From: <man...@us...> - 2013-05-11 14:54:54
|
Revision: 2016 http://sourceforge.net/p/modplug/code/2016 Author: manxorist Date: 2013-05-11 14:54:46 +0000 (Sat, 11 May 2013) Log Message: ----------- [New] Add openmpt123, a command line module player using libopenmpt. [New] Add modplug123, a modplug123 command line interface for openmpt123. [Mod] Build portaudio with VS2010 also with winmm support for openmpt123. Use of this API via portaudio is disabled in the tracker by default to not confuse users, but can be enabled via a hidden setting: [Sound Settings]MorePortaudio. Modified Paths: -------------- trunk/OpenMPT/include/portaudio/OpenMPT.txt trunk/OpenMPT/include/portaudio/build/msvc/portaudio_openmpt_vs2010.vcxproj trunk/OpenMPT/mptrack/Mpdlgs.cpp trunk/OpenMPT/mptrack/TrackerSettings.cpp trunk/OpenMPT/mptrack/TrackerSettings.h Added Paths: ----------- trunk/OpenMPT/openmpt123/ trunk/OpenMPT/openmpt123/bin/ trunk/OpenMPT/openmpt123/openmpt123.cpp trunk/OpenMPT/openmpt123/openmpt123.sln trunk/OpenMPT/openmpt123/openmpt123.vcxproj trunk/OpenMPT/openmpt123/openmpt123.vcxproj.filters Modified: trunk/OpenMPT/include/portaudio/OpenMPT.txt =================================================================== --- trunk/OpenMPT/include/portaudio/OpenMPT.txt 2013-05-11 14:53:38 UTC (rev 2015) +++ trunk/OpenMPT/include/portaudio/OpenMPT.txt 2013-05-11 14:54:46 UTC (rev 2016) @@ -4,4 +4,5 @@ - Change the Runtime library [C/C++/Code Generation/Runtime Library] to static linking in both Release and Debug configurations (/MT and /MTd instead of /MD and /MDd). - Change the [General/Confguration Type] to Static Library. - Exclude hostapi/ASIO/ASIOSDK/asio.cpp hostapi/ASIO/ASIOSDK/asiodrivers.cpp hostapi/ASIO/ASIOSDK/asiolist.cpp and hostapi/ASIO/pa_asio.cpp from the build. -- Change the following preprocessor definitions in [C/C++/Preprocessor]: PA_USE_ASIO=0;PA_USE_DS=0;PA_USE_WMME=0;PA_USE_WASAPI=1;PA_USE_WDMKS=0; to only build portaudio with wasapi support. +- For VS2008, change the following preprocessor definitions in [C/C++/Preprocessor]: PA_USE_ASIO=0;PA_USE_DS=0;PA_USE_WMME=0;PA_USE_WASAPI=1;PA_USE_WDMKS=0; to only build portaudio with wasapi support. +- For VS2010, change the following preprocessor definitions in [C/C++/Preprocessor]: PA_USE_ASIO=0;PA_USE_DS=0;PA_USE_WMME=1;PA_USE_WASAPI=1;PA_USE_WDMKS=0; to only build portaudio with winmm and wasapi support (winmm being used for openmpt123). Modified: trunk/OpenMPT/include/portaudio/build/msvc/portaudio_openmpt_vs2010.vcxproj =================================================================== --- trunk/OpenMPT/include/portaudio/build/msvc/portaudio_openmpt_vs2010.vcxproj 2013-05-11 14:53:38 UTC (rev 2015) +++ trunk/OpenMPT/include/portaudio/build/msvc/portaudio_openmpt_vs2010.vcxproj 2013-05-11 14:54:46 UTC (rev 2016) @@ -139,7 +139,7 @@ <IntrinsicFunctions>true</IntrinsicFunctions> <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> <AdditionalIncludeDirectories>..\..\src\common;..\..\include;.\;..\..\src\os\win;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <PreprocessorDefinitions>WIN32;NDEBUG;_USRDLL;PA_ENABLE_DEBUG_OUTPUT;_CRT_SECURE_NO_DEPRECATE;PAWIN_USE_WDMKS_DEVICE_INFO;PA_USE_ASIO=0;PA_USE_DS=0;PA_USE_WMME=0;PA_USE_WASAPI=1;PA_USE_WDMKS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;NDEBUG;_USRDLL;PA_ENABLE_DEBUG_OUTPUT;_CRT_SECURE_NO_DEPRECATE;PAWIN_USE_WDMKS_DEVICE_INFO;PA_USE_ASIO=0;PA_USE_DS=0;PA_USE_WMME=1;PA_USE_WASAPI=1;PA_USE_WDMKS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <FunctionLevelLinking>true</FunctionLevelLinking> @@ -229,7 +229,7 @@ <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>..\..\src\common;..\..\include;.\;..\..\src\os\win;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <PreprocessorDefinitions>WIN32;_DEBUG;_USRDLL;PA_ENABLE_DEBUG_OUTPUT;_CRT_SECURE_NO_DEPRECATE;PAWIN_USE_WDMKS_DEVICE_INFO;PA_USE_ASIO=0;PA_USE_DS=0;PA_USE_WMME=0;PA_USE_WASAPI=1;PA_USE_WDMKS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;_DEBUG;_USRDLL;PA_ENABLE_DEBUG_OUTPUT;_CRT_SECURE_NO_DEPRECATE;PAWIN_USE_WDMKS_DEVICE_INFO;PA_USE_ASIO=0;PA_USE_DS=0;PA_USE_WMME=1;PA_USE_WASAPI=1;PA_USE_WDMKS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MinimalRebuild>true</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> Modified: trunk/OpenMPT/mptrack/Mpdlgs.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mpdlgs.cpp 2013-05-11 14:53:38 UTC (rev 2015) +++ trunk/OpenMPT/mptrack/Mpdlgs.cpp 2013-05-11 14:54:46 UTC (rev 2016) @@ -213,8 +213,18 @@ } COMBOBOXEXITEM cbi; UINT iItem = 0; + for (UINT nDevType = 0; nDevType < SNDDEV_NUM_DEVTYPES; nDevType++) { + if(!TrackerSettings::Instance().m_MorePortaudio) + { + if(nDevType == SNDDEV_PORTAUDIO_ASIO || nDevType == SNDDEV_PORTAUDIO_DS || nDevType == SNDDEV_PORTAUDIO_WMME) + { + // skip those portaudio apis that are already implemented via our own ISoundDevice class + // can be overwritten via [Sound Settings]MorePortaudio=1 + continue; + } + } UINT nDev = 0; while (EnumerateSoundDevices(nDevType, nDev, s, CountOf(s))) @@ -225,9 +235,11 @@ switch(nDevType) { case SNDDEV_DSOUND: + case SNDDEV_PORTAUDIO_DS: cbi.iImage = IMAGE_DIRECTX; break; case SNDDEV_ASIO: + case SNDDEV_PORTAUDIO_ASIO: bAsio = TRUE; cbi.iImage = IMAGE_ASIO; break; Modified: trunk/OpenMPT/mptrack/TrackerSettings.cpp =================================================================== --- trunk/OpenMPT/mptrack/TrackerSettings.cpp 2013-05-11 14:53:38 UTC (rev 2015) +++ trunk/OpenMPT/mptrack/TrackerSettings.cpp 2013-05-11 14:54:46 UTC (rev 2016) @@ -68,6 +68,7 @@ // Audio device gbLoopSong = TRUE; + m_MorePortaudio = false; m_nWaveDevice = SNDDEV_BUILD_ID(0, SNDDEV_WAVEOUT); // Default value will be overridden m_LatencyMS = SNDDEV_DEFAULT_LATENCY_MS; m_UpdateIntervalMS = SNDDEV_DEFAULT_UPDATEINTERVAL_MS; @@ -327,6 +328,7 @@ rgbCustomColors[ncol] = CMainFrame::GetPrivateProfileDWord("Display", s, rgbCustomColors[ncol], iniFile); } + m_MorePortaudio = CMainFrame::GetPrivateProfileBool("Sound Settings", "MorePortaudio", m_MorePortaudio, iniFile); DWORD defaultDevice = SNDDEV_BUILD_ID(0, SNDDEV_WAVEOUT); // first WaveOut device #ifndef NO_ASIO // If there's an ASIO device available, prefer it over DirectSound Modified: trunk/OpenMPT/mptrack/TrackerSettings.h =================================================================== --- trunk/OpenMPT/mptrack/TrackerSettings.h 2013-05-11 14:53:38 UTC (rev 2015) +++ trunk/OpenMPT/mptrack/TrackerSettings.h 2013-05-11 14:54:46 UTC (rev 2016) @@ -177,6 +177,7 @@ // Audio Setup DWORD gbLoopSong; + bool m_MorePortaudio; LONG m_nWaveDevice; // use the SNDDEV_GET_NUMBER and SNDDEV_GET_TYPE macros to decode DWORD m_LatencyMS; DWORD m_UpdateIntervalMS; Index: trunk/OpenMPT/openmpt123 =================================================================== --- trunk/OpenMPT/openmpt123 2013-05-11 14:53:38 UTC (rev 2015) +++ trunk/OpenMPT/openmpt123 2013-05-11 14:54:46 UTC (rev 2016) Property changes on: trunk/OpenMPT/openmpt123 ___________________________________________________________________ Added: svn:ignore ## -0,0 +1,9 ## +Debug +Release +ReleaseStatic +openmpt123.sdf +openmpt123.suo +openmpt123.vcxproj.user +openmpt123.opensdf +ipch +DebugStatic Added: tsvn:logminsize ## -0,0 +1 ## +10 \ No newline at end of property Index: trunk/OpenMPT/openmpt123/bin =================================================================== --- trunk/OpenMPT/openmpt123/bin 2013-05-11 14:53:38 UTC (rev 2015) +++ trunk/OpenMPT/openmpt123/bin 2013-05-11 14:54:46 UTC (rev 2016) Property changes on: trunk/OpenMPT/openmpt123/bin ___________________________________________________________________ Added: svn:ignore ## -0,0 +1 ## +* Added: tsvn:logminsize ## -0,0 +1 ## +10 \ No newline at end of property Added: trunk/OpenMPT/openmpt123/openmpt123.cpp =================================================================== --- trunk/OpenMPT/openmpt123/openmpt123.cpp (rev 0) +++ trunk/OpenMPT/openmpt123/openmpt123.cpp 2013-05-11 14:54:46 UTC (rev 2016) @@ -0,0 +1,766 @@ +/* + * openmpt123.cpp + * -------------- + * Purpose: libopenmpt command line example player + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#define LIBOPENMPT_ALPHA_WARNING_SEEN_AND_I_KNOW_WHAT_I_AM_DOING + +#define OPENMPT123_VERSION_STRING "0.1" + +#include <algorithm> +#include <fstream> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <string> +#include <vector> + +#include <cstdint> + +#if defined(_MSC_VER) +#include <fcntl.h> +#include <io.h> +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> +#endif + +#include <libopenmpt/libopenmpt.hpp> + +#include <portaudio.h> + +struct show_help_exception : public std::exception { + std::string message; + show_help_exception( const std::string & msg = "" ) : message(msg) { } +}; + +struct openmpt123_exception : public std::exception { + openmpt123_exception( const char * text ) : std::exception( text ) { } +}; + +struct silent_exit_exception : public std::exception { + silent_exit_exception() { } +}; + +struct show_version_number_exception : public std::exception { + show_version_number_exception() { } +}; + +struct portaudio_exception : public std::exception { + portaudio_exception( PaError code ) : std::exception( Pa_GetErrorText( code ) ) { } +}; + +struct openmpt123_flags { + bool modplug123; + int device; + std::int32_t channels; + std::int32_t buffer; + std::int32_t repeatcount; + std::int32_t samplerate; + std::int32_t gain; + std::int32_t quality; + std::int32_t rampinsamples; + std::int32_t rampoutsamples; + bool quiet; + bool verbose; + bool show_message; + bool show_progress; + double seek_target; + bool use_float; + bool use_stdout; + std::vector<std::string> filenames; + openmpt123_flags() { + modplug123 = false; + device = -1; + channels = 2; + buffer = 250; + repeatcount = 0; + samplerate = 48000; + gain = 0; + quality = 100; + rampinsamples = 16; + rampoutsamples = 42; + quiet = false; + verbose = false; + show_message = false; + show_progress = false; + seek_target = 0.0; + use_float = false; + use_stdout = false; + } + void check_and_sanitize() { + if ( filenames.size() == 0 ) { + throw show_help_exception(); + } + if ( quiet ) { + verbose = false; + show_progress = false; + } + if ( channels != 1 && channels != 2 && channels != 4 ) { + channels = openmpt123_flags().channels; + } + if ( samplerate < 0 ) { + samplerate = openmpt123_flags().samplerate; + } + } +}; + +std::ostream & operator << ( std::ostream & s, const openmpt123_flags & flags ) { + s << "Quiet: " << flags.quiet << std::endl; + s << "Verbose: " << flags.verbose << std::endl; + s << "Show message: " << flags.show_message << std::endl; + s << "Show progress: " << flags.show_progress << std::endl; + s << "Device: " << flags.device << std::endl; + s << "Channels: " << flags.channels << std::endl; + s << "Buffer: " << flags.buffer << std::endl; + s << "Repeat count: " << flags.repeatcount << std::endl; + s << "Sample rate: " << flags.samplerate << std::endl; + s << "Gain: " << flags.gain << std::endl; + s << "Quality: " << flags.quality << std::endl; + s << "Seek target: " << flags.seek_target << std::endl; + s << "Float: " << flags.use_float << std::endl; + s << "Standard output: " << flags.use_stdout << std::endl; + s << std::endl; + s << "Files: " << std::endl; + for ( std::vector<std::string>::const_iterator filename = flags.filenames.begin(); filename != flags.filenames.end(); ++filename ) { + s << " " << *filename << std::endl; + } + s << std::endl; + return s; +} + +static std::string seconds_to_string( double time ) { + std::int64_t time_ms = static_cast<std::int64_t>( time * 1000 ); + std::int64_t milliseconds = time_ms % 1000; + std::int64_t seconds = ( time_ms / 1000 ) % 60; + std::int64_t minutes = ( time_ms / ( 1000 * 60 ) ) % 24; + std::int64_t hours = ( time_ms / ( 1000 * 60 * 24 ) ); + std::ostringstream str; + if ( hours > 0 ) { + str << hours << ":"; + } + str << std::setfill('0') << std::setw(2) << minutes; + str << ":"; + str << std::setfill('0') << std::setw(2) << seconds; + str << "."; + str << std::setfill('0') << std::setw(3) << milliseconds; + return str.str(); +} + +template < typename T > +std::string bytes_to_string( T bytes ) { + std::ostringstream str; + if ( bytes >= std::uint64_t(10) * 1024 * 1024 * 1024 ) { + str << bytes / 1024 / 1024 / 1024 << "GiB"; + } else if ( bytes >= std::uint64_t(10) * 1024 * 1024 ) { + str << bytes / 1024 / 1024 << "MiB"; + } else if ( bytes >= std::uint64_t(10) * 1024 ) { + str << bytes / 1024 << "KiB"; + } else { + str << bytes << "B"; + } + return str.str(); +} + +typedef void (*PaUtilLogCallback ) (const char *log); +extern "C" void PaUtil_SetDebugPrintFunction(PaUtilLogCallback cb); + +class portaudio_raii { +private: + bool log_set; + bool portaudio_initialized; + static std::ostream * portaudio_log_stream; +private: + static void portaudio_log_function( const char * log ) { + if ( portaudio_log_stream ) { + *portaudio_log_stream << "PortAudio: " << log; + } + } +protected: + void check_portaudio_error( PaError e, std::ostream & log = std::cerr ) { + if ( e == paNoError ) { + return; + } + if ( e == paOutputUnderflowed ) { + log << "PortAudio warning: " << Pa_GetErrorText( e ) << std::endl; + return; + } + throw portaudio_exception( e ); + } +public: + portaudio_raii( bool verbose, std::ostream & log = std::cerr ) : log_set(false), portaudio_initialized(false) { + if ( verbose ) { + portaudio_log_stream = &log; + } else { + portaudio_log_stream = nullptr; + } + PaUtil_SetDebugPrintFunction( portaudio_log_function ); + log_set = true; + check_portaudio_error( Pa_Initialize() ); + portaudio_initialized = true; + if ( verbose ) { + *portaudio_log_stream << std::endl; + } + } + ~portaudio_raii() { + if ( portaudio_initialized ) { + check_portaudio_error( Pa_Terminate() ); + portaudio_initialized = false; + } + if ( log_set ) { + PaUtil_SetDebugPrintFunction( NULL ); + portaudio_log_stream = nullptr; + log_set = false; + } + } +}; + +std::ostream * portaudio_raii::portaudio_log_stream = nullptr; + +class write_buffers_interface { +public: + virtual void write( const std::vector<float*> buffers, std::size_t frames ) = 0; + virtual void write( const std::vector<std::int16_t*> buffers, std::size_t frames ) = 0; +}; + +class portaudio_stream_raii : public portaudio_raii, public write_buffers_interface { +private: + PaStream * stream; +public: + portaudio_stream_raii( const openmpt123_flags & flags, std::ostream & log = std::cerr ) : portaudio_raii(flags.verbose, log), stream(NULL) { + PaStreamParameters streamparameters; + std::memset( &streamparameters, 0, sizeof(PaStreamParameters) ); + streamparameters.device = ( flags.device == -1 ) ? Pa_GetDefaultOutputDevice() : flags.device; + streamparameters.channelCount = flags.channels; + streamparameters.sampleFormat = ( flags.use_float ? paFloat32 : paInt16 ) | paNonInterleaved; + streamparameters.suggestedLatency = flags.buffer * 0.001; + check_portaudio_error( Pa_OpenStream( &stream, NULL, &streamparameters, flags.samplerate, paFramesPerBufferUnspecified, 0, NULL, NULL ) ); + check_portaudio_error( Pa_StartStream( stream ) ); + if ( flags.verbose ) { + log << "PortAudio:" << std::endl; + log << " device: " + << streamparameters.device + << " [ " << Pa_GetHostApiInfo( Pa_GetDeviceInfo( streamparameters.device )->hostApi )->name << " / " << Pa_GetDeviceInfo( streamparameters.device )->name << " ] " + << std::endl; + log << " channels: " << streamparameters.channelCount << std::endl; + log << " sampleformat: " << ( ( streamparameters.sampleFormat == ( paFloat32 | paNonInterleaved ) ) ? "paFloat32" : "paInt16" ) << std::endl; + log << " latency: " << streamparameters.suggestedLatency << std::endl; + log << " samplerate: " << flags.samplerate << std::endl; + log << std::endl; + } + } + ~portaudio_stream_raii() { + if ( stream ) { + check_portaudio_error( Pa_StopStream( stream ) ); + check_portaudio_error( Pa_CloseStream( stream ) ); + stream = NULL; + } + } +public: + void write( const std::vector<float*> buffers, std::size_t frames ) { + check_portaudio_error( Pa_WriteStream( stream, buffers.data(), frames ) ); + } + void write( const std::vector<std::int16_t*> buffers, std::size_t frames ) { + check_portaudio_error( Pa_WriteStream( stream, buffers.data(), frames ) ); + } +}; + +class stdout_stream_raii : public write_buffers_interface { +private: + std::vector<float> interleaved_float_buffer; + std::vector<std::int16_t> interleaved_int_buffer; +public: + stdout_stream_raii() { + #if defined(_MSC_VER) + _setmode( _fileno( stdout ), _O_BINARY ); + #endif + } +public: + void write( const std::vector<float*> buffers, std::size_t frames ) { + interleaved_float_buffer.clear(); + for ( std::size_t frame = 0; frame < frames; frame++ ) { + for ( std::size_t channel = 0; channel < buffers.size(); channel++ ) { + interleaved_float_buffer.push_back( buffers[channel][frame] ); + } + } + std::cout.write( (const char*)( interleaved_float_buffer.data() ), interleaved_float_buffer.size() * sizeof( float ) ); + } + void write( const std::vector<std::int16_t*> buffers, std::size_t frames ) { + interleaved_int_buffer.clear(); + for ( std::size_t frame = 0; frame < frames; frame++ ) { + for ( std::size_t channel = 0; channel < buffers.size(); channel++ ) { + interleaved_int_buffer.push_back( buffers[channel][frame] ); + } + } + std::cout.write( (const char*)( interleaved_int_buffer.data() ), interleaved_int_buffer.size() * sizeof( std::int32_t ) ); + } +}; + +static void show_info( std::ostream & log, bool modplug123 = false ) { + log << ( modplug123 ? "modplug123 emulated by " : "" ) << "openmpt123" << " version " << OPENMPT123_VERSION_STRING << std::endl; + log << " Copyright (c) 2013 OpenMPT developers (http://openmpt.org/)" << std::endl; + log << " libopenmpt version " << openmpt::string::get( openmpt::string::library_version ) << " " << "(built " << openmpt::string::get( openmpt::string::build ) << ")" << std::endl; + log << " OpenMPT version " << openmpt::string::get( openmpt::string::core_version ) << std::endl; + log << " " << Pa_GetVersionText() << " (http://portaudio.com/)" << std::endl; + log << std::endl; +} + +static void show_version() { + std::clog << OPENMPT123_VERSION_STRING << std::endl; +} + +static std::string get_device_string( int device ) { + if ( device == -1 ) { + return "default"; + } + std::ostringstream str; + str << device; + return str.str(); +} + +static void show_help( show_help_exception & e, bool modplug123 ) { + show_info( std::clog, modplug123 ); + if ( modplug123 ) { + std::clog << "Usage: modplug123 [options] file1 [file2] ..." << std::endl; + std::clog << std::endl; + std::clog << " -h, --help Show help" << std::endl; + std::clog << " -v, --version Show version number and nothing else" << std::endl; + std::clog << " -l Loop song [default: " << openmpt123_flags().repeatcount << "]" << std::endl; + std::clog << " -ao n Set output device [default: " << openmpt123_flags().device << "]," << std::endl; + std::clog << " use -ao help to show available devices" << std::endl; + } else { + std::clog << "Usage: openmpt123 [options] [--] file1 [file2] ..." << std::endl; + std::clog << std::endl; + std::clog << " -h, --help Show help" << std::endl; + std::clog << " -q, --quiet Suppress non-error screen output" << std::endl; + std::clog << " -v, --verbose Show more screen output" << std::endl; + std::clog << " --version Show version number and nothing else" << std::endl; + std::clog << " --[no-]message Show song message [default: " << openmpt123_flags().show_message << "]" << std::endl; + std::clog << " --[no-]progress Show playback progress [default: " << openmpt123_flags().show_progress << "]" << std::endl; + std::clog << " --device n Set output device [default: " << get_device_string( openmpt123_flags().device ) << "]," << std::endl; + std::clog << " use --device help to show available devices" << std::endl; + std::clog << " --channels n use n [1,2,4] output channels [default: " << openmpt123_flags().channels << "]" << std::endl; + std::clog << " --[no]-float Output 32bit floating point instead of 16bit integer [default: " << openmpt123_flags().use_float << "]" << std::endl; + std::clog << " --buffer n Set output buffer size to n ms [default: " << openmpt123_flags().buffer << "]," << std::endl; + std::clog << " --samplerate n Set samplerate to n Hz [default: " << openmpt123_flags().samplerate << "]" << std::endl; + std::clog << " --gain n Set output gain to n dB [default: " << openmpt123_flags().gain << "]" << std::endl; + std::clog << " --repeat n Repeat song n times (-1 means forever) [default: " << openmpt123_flags().repeatcount << "]" << std::endl; + std::clog << " --quality n Set rendering quality to n % [default: " << openmpt123_flags().quality << "]" << std::endl; + std::clog << " --seek n Seek to n seconds on start [default: " << openmpt123_flags().seek_target << "]" << std::endl; + std::clog << " --volrampin n Use n samples volume ramping on sample begin [default: " << openmpt123_flags().rampinsamples << "]" << std::endl; + std::clog << " --volrampout n Use n samples volume ramping on sample end [default: " << openmpt123_flags().rampoutsamples << "]" << std::endl; + std::clog << std::endl; + std::clog << " -- Interpret further arguments as filenames" << std::endl; + std::clog << std::endl; + std::clog << " Supported file formats: " << std::endl; + std::clog << " "; + std::vector<std::string> extensions = openmpt::get_supported_extensions(); + bool first = true; + for ( std::vector<std::string>::iterator i = extensions.begin(); i != extensions.end(); ++i ) { + if ( first ) { + first = false; + } else { + std::clog << ", "; + } + std::clog << *i; + } + std::clog << std::endl; + } + + std::clog << std::endl; + + if ( e.message.size() > 0 ) { + std::clog << e.message; + std::clog << std::endl; + } +} + +static void show_audio_devices() { + std::ostringstream devices; + devices << " Available devices:" << std::endl; + portaudio_raii portaudio( false ); + devices << " " << "stdout" << ": " << "use standard output" << std::endl; + devices << " " << "default" << ": " << "default" << std::endl; + for ( PaDeviceIndex i = 0; i < Pa_GetDeviceCount(); ++i ) { + if ( Pa_GetDeviceInfo( i ) && Pa_GetDeviceInfo( i )->maxOutputChannels > 0 ) { + devices << " " << i << ": " << Pa_GetDeviceInfo( i )->name << std::endl; + } + } + throw show_help_exception( devices.str() ); +} + +template < typename Tsample > +void render_loop( const openmpt123_flags & flags, openmpt::module & mod, double & duration, std::ostream & log, write_buffers_interface & audio_stream ) { + + const std::size_t bufsize = 1024; + + std::vector<Tsample> left( bufsize ); + std::vector<Tsample> right( bufsize ); + std::vector<Tsample> back_left( bufsize ); + std::vector<Tsample> back_right( bufsize ); + std::vector<Tsample*> buffers( 4 ) ; + buffers[0] = left.data(); + buffers[1] = right.data(); + buffers[2] = back_left.data(); + buffers[3] = back_right.data(); + buffers.resize( flags.channels ); + + while ( true ) { + + std::size_t count = 0; + + switch ( flags.channels ) { + case 1: count = mod.read( flags.samplerate, bufsize, left.data() ); break; + case 2: count = mod.read( flags.samplerate, bufsize, left.data(), right.data() ); break; + case 4: count = mod.read( flags.samplerate, bufsize, left.data(), right.data(), back_left.data(), back_right.data() ); break; + } + + if ( count == 0 ) { + break; + } + + audio_stream.write( buffers, count ); + + if ( flags.show_progress ) { + log + << " " + << seconds_to_string( mod.get_current_position_seconds() ) + << " / " + << seconds_to_string( duration ) + << " " + << "Ord:" << mod.get_current_order() << "/" << mod.get_num_orders() << " Pat:" << mod.get_current_pattern() << " Row:" << mod.get_current_row() + << " " + << "Spd:" << mod.get_current_speed() << " Tmp:" << mod.get_current_tempo() + << " " + << "Chn:" << mod.get_current_playing_channels() + << " " + << "\r"; + } + + } + +} + +static void render_file( const openmpt123_flags & flags, const std::string & filename, std::ostream & log, write_buffers_interface & audio_stream ) { + + try { + + std::ifstream file_stream; + std::istream & stdin_stream = std::cin; + bool use_stdin = ( filename == "-" ); + if ( !use_stdin ) { + file_stream.open( filename, std::ios::binary ); + } else { + stdin_stream.setf( std::ios::binary ); + } + std::istream & data_stream = use_stdin ? stdin_stream : file_stream; + if ( data_stream.fail() ) { + throw openmpt123_exception( "file open error" ); + } + + openmpt::module mod( data_stream ); + + if ( !use_stdin ) { + file_stream.close(); + } + + double duration = mod.get_duration_seconds(); + log << "File: " << filename << std::endl; + log << "Type: " << mod.get_metadata( "type" ) << " (" << mod.get_metadata( "type_long" ) << ")" << std::endl; + log << "Tracker: " << mod.get_metadata( "tracker" ) << std::endl; + log << "Title: " << mod.get_metadata( "title" ) << std::endl; + log << "Duration: " << seconds_to_string( duration ) << std::endl; + log << "Channels: " << mod.get_num_channels() << std::endl; + log << "Orders: " << mod.get_num_orders() << std::endl; + log << "Patterns: " << mod.get_num_patterns() << std::endl; + log << "Instruments: " << mod.get_num_instruments() << std::endl; + log << "Samples: " << mod.get_num_samples() << std::endl; + + if ( flags.show_message ) { + log << "Message: " << std::endl; + log << mod.get_metadata( "message" ) << std::endl; + log << std::endl; + } + + mod.set_render_param( openmpt::module::RENDER_REPEATCOUNT, flags.repeatcount ); + mod.set_render_param( openmpt::module::RENDER_QUALITY_PERCENT, flags.quality ); + mod.set_render_param( openmpt::module::RENDER_MASTERGAIN_DB, flags.gain ); + mod.set_render_param( openmpt::module::RENDER_VOLUMERAMP_IN_SAMPLES, flags.rampinsamples ); + mod.set_render_param( openmpt::module::RENDER_VOLUMERAMP_OUT_SAMPLES, flags.rampoutsamples ); + + if ( flags.seek_target > 0.0 ) { + mod.seek_seconds( flags.seek_target ); + } + + if ( flags.use_float ) { + render_loop<float>( flags, mod, duration, log, audio_stream ); + } else { + render_loop<std::int16_t>( flags, mod, duration, log, audio_stream ); + } + + if ( flags.show_progress ) { + log << std::endl; + } + + } catch ( std::exception & e ) { + std::cerr << "error playing '" << filename << "': " << e.what() << std::endl; + } catch ( ... ) { + std::cerr << "unknown error playing '" << filename << "'" << std::endl; + } + + log << std::endl; + +} + +static openmpt123_flags parse_modplug123( const std::vector<std::string> & args ) { + + openmpt123_flags flags; + + flags.modplug123 = true; + + bool files_only = false; + for ( std::vector<std::string>::const_iterator i = args.begin(); i != args.end(); ++i ) { + if ( i == args.begin() ) { + // skip program name + continue; + } + std::string arg = *i; + std::string nextarg = ( i+1 != args.end() ) ? *(i+1) : ""; + if ( files_only ) { + flags.filenames.push_back( arg ); + } else if ( arg.substr( 0, 1 ) != "-" ) { + flags.filenames.push_back( arg ); + } else if ( arg == "-h" || arg == "--help" ) { + throw show_help_exception(); + } else if ( arg == "-v" || arg == "--version" ) { + show_info( std::clog, true ); + throw silent_exit_exception(); + } else if ( arg == "-l" ) { + flags.repeatcount = -1; + } else if ( arg == "-ao" && nextarg != "" ) { + if ( nextarg == "help" ) { + show_audio_devices(); + } else if ( nextarg == "stdout" ) { + flags.use_stdout = true; + } else if ( nextarg == "default" ) { + flags.device = -1; + } else { + std::istringstream istr( nextarg ); + istr >> flags.device; + } + ++i; + } + } + + return flags; + +} + +static openmpt123_flags parse_openmpt123( const std::vector<std::string> & args ) { + + openmpt123_flags flags; + + bool files_only = false; + for ( std::vector<std::string>::const_iterator i = args.begin(); i != args.end(); ++i ) { + if ( i == args.begin() ) { + // skip program name + continue; + } + std::string arg = *i; + std::string nextarg = ( i+1 != args.end() ) ? *(i+1) : ""; + if ( files_only ) { + flags.filenames.push_back( arg ); + } else if ( arg.substr( 0, 1 ) != "-" ) { + flags.filenames.push_back( arg ); + } else { + if ( arg == "--" ) { + files_only = true; + } else if ( arg == "-h" || arg == "--help" ) { + throw show_help_exception(); + } else if ( arg == "-q" || arg == "--quiet" ) { + flags.quiet = true; + } else if ( arg == "-v" || arg == "--verbose" ) { + flags.verbose = true; + } else if ( arg == "--version" ) { + throw show_version_number_exception(); + } else if ( arg == "--message" ) { + flags.show_message = true; + } else if ( arg == "--no-message" ) { + flags.show_message = false; + } else if ( arg == "--progress" ) { + flags.show_progress = true; + } else if ( arg == "--no-progress" ) { + flags.show_progress = false; + } else if ( arg == "--device" && nextarg != "" ) { + if ( nextarg == "help" ) { + show_audio_devices(); + } else if ( nextarg == "stdout" ) { + flags.use_stdout = true; + } else if ( nextarg == "default" ) { + flags.device = -1; + } else { + std::istringstream istr( nextarg ); + istr >> flags.device; + } + ++i; + } else if ( arg == "--channels" && nextarg != "" ) { + std::istringstream istr( nextarg ); + istr >> flags.channels; + ++i; + } else if ( arg == "--float" ) { + flags.use_float = true; + } else if ( arg == "--no-float" ) { + flags.use_float = false; + } else if ( arg == "--buffer" && nextarg != "" ) { + std::istringstream istr( nextarg ); + istr >> flags.buffer; + ++i; + } else if ( arg == "--samplerate" && nextarg != "" ) { + std::istringstream istr( nextarg ); + istr >> flags.samplerate; + ++i; + } else if ( arg == "--gain" && nextarg != "" ) { + std::istringstream istr( nextarg ); + istr >> flags.gain; + ++i; + } else if ( arg == "--repeat" && nextarg != "" ) { + std::istringstream istr( nextarg ); + istr >> flags.repeatcount; + ++i; + } else if ( arg == "--quality" && nextarg != "" ) { + std::istringstream istr( nextarg ); + istr >> flags.quality; + ++i; + } else if ( arg == "--seek" && nextarg != "" ) { + std::istringstream istr( nextarg ); + istr >> flags.seek_target; + ++i; + } else if ( arg == "--volrampin" && nextarg != "" ) { + std::istringstream istr( nextarg ); + istr >> flags.rampinsamples; + ++i; + } else if ( arg == "--volrampout" && nextarg != "" ) { + std::istringstream istr( nextarg ); + istr >> flags.rampoutsamples; + ++i; + } else if ( arg.size() > 0 && arg.substr( 0, 1 ) == "-" ) { + throw show_help_exception(); + } + } + } + + return flags; + +} + +static bool equal_end( const std::string & str1, const std::string & str2 ) { + std::size_t minlength = std::min( str1.length(), str2.length() ); + return str1.substr( str1.length() - minlength ) == str2.substr( str2.length() - minlength ); +} + +static bool is_modplug123_binary_name( std::string name ) { + std::transform( name.begin(), name.end(), name.begin(), tolower ); + if ( equal_end( name, "modplug123" ) ) { + return true; + } + if ( equal_end( name, "modplug123.exe" ) ) { + return true; + } + return false; +} + +static void show_credits( std::ostream & s ) { + s << openmpt::string::get( openmpt::string::contact ) << std::endl; + s << std::endl; + s << openmpt::string::get( openmpt::string::credits ); +} + +int main( int argc, char * argv [] ) { + + openmpt123_flags flags; + + try { + + std::vector<std::string> args( argv, argv + argc ); + + if ( args.size() > 0 && is_modplug123_binary_name( args[0] ) ) { + + flags = parse_modplug123( args ); + + } else { + + flags = parse_openmpt123( args ); + + } + + flags.check_and_sanitize(); + + std::ostringstream dummy_log; + std::ostream & log = flags.quiet ? dummy_log : std::clog; + + show_info( log, flags.modplug123 ); + + if ( flags.verbose ) { + + show_credits( log ); + + log << flags; + + } + + #if defined(_MSC_VER) + + for ( std::vector<std::string>::iterator filename = flags.filenames.begin(); filename != flags.filenames.end(); ++filename ) { + if ( *filename == "-" ) { + _setmode( _fileno( stdin ), _O_BINARY ); + break; + } + } + + #endif + + if ( flags.use_stdout ) { + + stdout_stream_raii stdout_audio_stream; + + for ( std::vector<std::string>::iterator filename = flags.filenames.begin(); filename != flags.filenames.end(); ++filename ) { + render_file( flags, *filename, log, stdout_audio_stream ); + } + + } else { + + portaudio_stream_raii portaudio_stream( flags, log ); + + for ( std::vector<std::string>::iterator filename = flags.filenames.begin(); filename != flags.filenames.end(); ++filename ) { + render_file( flags, *filename, log, portaudio_stream ); + } + + } + + } catch ( show_help_exception & e ) { + show_help( e, flags.modplug123 ); + if ( flags.verbose ) { + show_credits( std::clog ); + } + return 1; + } catch ( show_version_number_exception & ) { + show_version(); + return 0; + } catch ( portaudio_exception & e ) { + std::cerr << "PortAudio error: " << e.what() << std::endl; + } catch ( silent_exit_exception & ) { + return 0; + } catch ( std::exception & e ) { + std::cerr << "error: " << e.what() << std::endl; + return 1; + } catch ( ... ) { + std::cerr << "unknown error" << std::endl; + return 1; + } + + return 0; +} Property changes on: trunk/OpenMPT/openmpt123/openmpt123.cpp ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/x-c++src \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: trunk/OpenMPT/openmpt123/openmpt123.sln =================================================================== --- trunk/OpenMPT/openmpt123/openmpt123.sln (rev 0) +++ trunk/OpenMPT/openmpt123/openmpt123.sln 2013-05-11 14:54:46 UTC (rev 2016) @@ -0,0 +1,38 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openmpt123", "openmpt123.vcxproj", "{29E00E3B-C33B-4DC1-B44F-64597A3701DE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libopenmpt", "..\libopenmpt\libopenmpt.vcxproj", "{812A654D-99BE-4D13-B97F-86332AD3E363}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portaudio", "..\include\portaudio\build\msvc\portaudio_openmpt_vs2010.vcxproj", "{0A18A071-125E-442F-AFF7-A3F68ABECF99}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibstat", "..\include\zlib\contrib\vstudio\vc10\zlibstat.vcxproj", "{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {29E00E3B-C33B-4DC1-B44F-64597A3701DE}.Debug|Win32.ActiveCfg = Debug|Win32 + {29E00E3B-C33B-4DC1-B44F-64597A3701DE}.Debug|Win32.Build.0 = Debug|Win32 + {29E00E3B-C33B-4DC1-B44F-64597A3701DE}.Release|Win32.ActiveCfg = Release|Win32 + {29E00E3B-C33B-4DC1-B44F-64597A3701DE}.Release|Win32.Build.0 = Release|Win32 + {812A654D-99BE-4D13-B97F-86332AD3E363}.Debug|Win32.ActiveCfg = DebugStatic|Win32 + {812A654D-99BE-4D13-B97F-86332AD3E363}.Debug|Win32.Build.0 = DebugStatic|Win32 + {812A654D-99BE-4D13-B97F-86332AD3E363}.Release|Win32.ActiveCfg = ReleaseStatic|Win32 + {812A654D-99BE-4D13-B97F-86332AD3E363}.Release|Win32.Build.0 = ReleaseStatic|Win32 + {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|Win32.ActiveCfg = Debug|Win32 + {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|Win32.Build.0 = Debug|Win32 + {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|Win32.ActiveCfg = Release|Win32 + {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|Win32.Build.0 = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.ActiveCfg = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.Build.0 = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.Build.0 = ReleaseWithoutAsm|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal Property changes on: trunk/OpenMPT/openmpt123/openmpt123.sln ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/x-ms-sln \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +CRLF \ No newline at end of property Added: trunk/OpenMPT/openmpt123/openmpt123.vcxproj =================================================================== --- trunk/OpenMPT/openmpt123/openmpt123.vcxproj (rev 0) +++ trunk/OpenMPT/openmpt123/openmpt123.vcxproj 2013-05-11 14:54:46 UTC (rev 2016) @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{29E00E3B-C33B-4DC1-B44F-64597A3701DE}</ProjectGuid> + <RootNamespace>openmpt123</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <CharacterSet>NotSet</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <WholeProgramOptimization>false</WholeProgramOptimization> + <CharacterSet>NotSet</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <OutDir>bin\</OutDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..;../common;../include/portaudio/include;../common/svn_version;../common/svn_version_default</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + </ClCompile> + <Link> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Console</SubSystem> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <FloatingPointModel>Fast</FloatingPointModel> + <AdditionalIncludeDirectories>..;../common;../include/portaudio/include;../common/svn_version;../common/svn_version_default</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <SubSystem>Console</SubSystem> + </Link> + <PostBuildEvent> + <Command>copy /y bin\openmpt123.exe bin\modplug123.exe</Command> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="openmpt123.cpp" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\include\portaudio\build\msvc\portaudio_openmpt_vs2010.vcxproj"> + <Project>{0a18a071-125e-442f-aff7-a3f68abecf99}</Project> + </ProjectReference> + <ProjectReference Include="..\include\zlib\contrib\vstudio\vc10\zlibstat.vcxproj"> + <Project>{745dec58-ebb3-47a9-a9b8-4c6627c01bf8}</Project> + </ProjectReference> + <ProjectReference Include="..\libopenmpt\libopenmpt.vcxproj"> + <Project>{812a654d-99be-4d13-b97f-86332ad3e363}</Project> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file Added: trunk/OpenMPT/openmpt123/openmpt123.vcxproj.filters =================================================================== --- trunk/OpenMPT/openmpt123/openmpt123.vcxproj.filters (rev 0) +++ trunk/OpenMPT/openmpt123/openmpt123.vcxproj.filters 2013-05-11 14:54:46 UTC (rev 2016) @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="openmpt123.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project> \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |