123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544 |
- /*
- * openmpt123.cpp
- * --------------
- * Purpose: libopenmpt command line player
- * Notes : (currently none)
- * Authors: OpenMPT Devs
- * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
- */
- static const char * const license =
- "Copyright (c) 2004-2022, OpenMPT Project Developers and Contributors" "\n"
- "Copyright (c) 1997-2003, Olivier Lapicque" "\n"
- "All rights reserved." "\n"
- "" "\n"
- "Redistribution and use in source and binary forms, with or without" "\n"
- "modification, are permitted provided that the following conditions are met:" "\n"
- " * Redistributions of source code must retain the above copyright" "\n"
- " notice, this list of conditions and the following disclaimer." "\n"
- " * Redistributions in binary form must reproduce the above copyright" "\n"
- " notice, this list of conditions and the following disclaimer in the" "\n"
- " documentation and/or other materials provided with the distribution." "\n"
- " * Neither the name of the OpenMPT project nor the" "\n"
- " names of its contributors may be used to endorse or promote products" "\n"
- " derived from this software without specific prior written permission." "\n"
- "" "\n"
- "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"" "\n"
- "AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE" "\n"
- "IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" "\n"
- "DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE" "\n"
- "FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL" "\n"
- "DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR" "\n"
- "SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER" "\n"
- "CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY," "\n"
- "OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" "\n"
- "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." "\n"
- ;
- #include "openmpt123_config.hpp"
- #include <algorithm>
- #include <deque>
- #include <fstream>
- #include <iomanip>
- #include <iostream>
- #include <iterator>
- #include <limits>
- #include <locale>
- #include <map>
- #include <memory>
- #include <random>
- #include <set>
- #include <sstream>
- #include <stdexcept>
- #include <string>
- #include <vector>
- #include <cassert>
- #include <cmath>
- #include <cstdint>
- #include <cstdio>
- #include <cstdlib>
- #include <cstring>
- #include <ctime>
- #if defined(__DJGPP__)
- #include <conio.h>
- #include <dpmi.h>
- #include <fcntl.h>
- #include <io.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <termios.h>
- #include <unistd.h>
- #elif defined(WIN32)
- #include <conio.h>
- #include <fcntl.h>
- #include <io.h>
- #include <stdio.h>
- #if defined(__MINGW32__) && !defined(__MINGW64__)
- #include <string.h>
- #endif
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <windows.h>
- #include <mmsystem.h>
- #include <mmreg.h>
- #else
- #include <termios.h>
- #include <unistd.h>
- #include <sys/ioctl.h>
- #include <sys/poll.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #endif
- #include <libopenmpt/libopenmpt.hpp>
- #include "openmpt123.hpp"
- #include "openmpt123_flac.hpp"
- #include "openmpt123_mmio.hpp"
- #include "openmpt123_sndfile.hpp"
- #include "openmpt123_raw.hpp"
- #include "openmpt123_stdout.hpp"
- #include "openmpt123_allegro42.hpp"
- #include "openmpt123_portaudio.hpp"
- #include "openmpt123_pulseaudio.hpp"
- #include "openmpt123_sdl2.hpp"
- #include "openmpt123_waveout.hpp"
- namespace openmpt123 {
- struct silent_exit_exception : public std::exception {
- };
- struct show_license_exception : public std::exception {
- };
- struct show_credits_exception : public std::exception {
- };
- struct show_man_version_exception : public std::exception {
- };
- struct show_man_help_exception : public std::exception {
- };
- struct show_short_version_number_exception : public std::exception {
- };
- struct show_version_number_exception : public std::exception {
- };
- struct show_long_version_number_exception : public std::exception {
- };
- #if defined( WIN32 )
- bool IsConsole( DWORD stdHandle ) {
- HANDLE hStd = GetStdHandle( stdHandle );
- if ( ( hStd != NULL ) && ( hStd != INVALID_HANDLE_VALUE ) ) {
- DWORD mode = 0;
- if ( GetConsoleMode( hStd, &mode ) != FALSE ) {
- return true;
- }
- }
- return false;
- }
- #endif
- bool IsTerminal( int fd ) {
- #if defined( WIN32 )
- if ( !_isatty( fd ) ) {
- return false;
- }
- DWORD stdHandle = 0;
- if ( fd == 0 ) {
- stdHandle = STD_INPUT_HANDLE;
- } else if ( fd == 1 ) {
- stdHandle = STD_OUTPUT_HANDLE;
- } else if ( fd == 2 ) {
- stdHandle = STD_ERROR_HANDLE;
- }
- return IsConsole( stdHandle );
- #else
- return isatty( fd ) ? true : false;
- #endif
- }
- #if !defined( WIN32 )
- static termios saved_attributes;
- static void reset_input_mode() {
- tcsetattr( STDIN_FILENO, TCSANOW, &saved_attributes );
- }
- static void set_input_mode() {
- termios tattr;
- if ( !isatty( STDIN_FILENO ) ) {
- return;
- }
- tcgetattr( STDIN_FILENO, &saved_attributes );
- atexit( reset_input_mode );
- tcgetattr( STDIN_FILENO, &tattr );
- tattr.c_lflag &= ~( ICANON | ECHO );
- tattr.c_cc[VMIN] = 1;
- tattr.c_cc[VTIME] = 0;
- tcsetattr( STDIN_FILENO, TCSAFLUSH, &tattr );
- }
- #endif
- class file_audio_stream_raii : public file_audio_stream_base {
- private:
- std::unique_ptr<file_audio_stream_base> impl;
- public:
- file_audio_stream_raii( const commandlineflags & flags, const std::string & filename, std::ostream & log )
- : impl(nullptr)
- {
- if ( !flags.force_overwrite ) {
- std::ifstream testfile( filename, std::ios::binary );
- if ( testfile ) {
- throw exception( "file already exists" );
- }
- }
- if ( false ) {
- // nothing
- } else if ( flags.output_extension == "raw" ) {
- impl = std::make_unique<raw_stream_raii>( filename, flags, log );
- #ifdef MPT_WITH_MMIO
- } else if ( flags.output_extension == "wav" ) {
- impl = std::make_unique<mmio_stream_raii>( filename, flags, log );
- #endif
- #ifdef MPT_WITH_FLAC
- } else if ( flags.output_extension == "flac" ) {
- impl = std::make_unique<flac_stream_raii>( filename, flags, log );
- #endif
- #ifdef MPT_WITH_SNDFILE
- } else {
- impl = std::make_unique<sndfile_stream_raii>( filename, flags, log );
- #endif
- }
- if ( !impl ) {
- throw exception( "file format handler '" + flags.output_extension + "' not found" );
- }
- }
- virtual ~file_audio_stream_raii() {
- return;
- }
- void write_metadata( std::map<std::string,std::string> metadata ) override {
- impl->write_metadata( metadata );
- }
- void write_updated_metadata( std::map<std::string,std::string> metadata ) override {
- impl->write_updated_metadata( metadata );
- }
- void write( const std::vector<float*> buffers, std::size_t frames ) override {
- impl->write( buffers, frames );
- }
- void write( const std::vector<std::int16_t*> buffers, std::size_t frames ) override {
- impl->write( buffers, frames );
- }
- };
- static std::string ctls_to_string( const std::map<std::string, std::string> & ctls ) {
- std::string result;
- for ( const auto & ctl : ctls ) {
- if ( !result.empty() ) {
- result += "; ";
- }
- result += ctl.first + "=" + ctl.second;
- }
- return result;
- }
- static double tempo_flag_to_double( std::int32_t tempo ) {
- return std::pow( 2.0, tempo / 24.0 );
- }
- static double pitch_flag_to_double( std::int32_t pitch ) {
- return std::pow( 2.0, pitch / 24.0 );
- }
- static double my_round( double val ) {
- if ( val >= 0.0 ) {
- return std::floor( val + 0.5 );
- } else {
- return std::ceil( val - 0.5 );
- }
- }
- static std::int32_t double_to_tempo_flag( double factor ) {
- return static_cast<std::int32_t>( my_round( std::log( factor ) / std::log( 2.0 ) * 24.0 ) );
- }
- static std::int32_t double_to_pitch_flag( double factor ) {
- return static_cast<std::int32_t>( my_round( std::log( factor ) / std::log( 2.0 ) * 24.0 ) );
- }
- static std::ostream & operator << ( std::ostream & s, const commandlineflags & flags ) {
- s << "Quiet: " << flags.quiet << std::endl;
- s << "Verbose: " << flags.verbose << std::endl;
- s << "Mode : " << mode_to_string( flags.mode ) << std::endl;
- s << "Show progress: " << flags.show_progress << std::endl;
- s << "Show peak meters: " << flags.show_meters << std::endl;
- s << "Show channel peak meters: " << flags.show_channel_meters << std::endl;
- s << "Show details: " << flags.show_details << std::endl;
- s << "Show message: " << flags.show_message << std::endl;
- s << "Update: " << flags.ui_redraw_interval << "ms" << std::endl;
- s << "Device: " << flags.device << std::endl;
- s << "Buffer: " << flags.buffer << "ms" << std::endl;
- s << "Period: " << flags.period << "ms" << std::endl;
- s << "Samplerate: " << flags.samplerate << std::endl;
- s << "Channels: " << flags.channels << std::endl;
- s << "Float: " << flags.use_float << std::endl;
- s << "Gain: " << flags.gain / 100.0 << std::endl;
- s << "Stereo separation: " << flags.separation << std::endl;
- s << "Interpolation filter taps: " << flags.filtertaps << std::endl;
- s << "Volume ramping strength: " << flags.ramping << std::endl;
- s << "Tempo: " << tempo_flag_to_double( flags.tempo ) << std::endl;
- s << "Pitch: " << pitch_flag_to_double( flags.pitch ) << std::endl;
- s << "Output dithering: " << flags.dither << std::endl;
- s << "Repeat count: " << flags.repeatcount << std::endl;
- s << "Seek target: " << flags.seek_target << std::endl;
- s << "End time: " << flags.end_time << std::endl;
- s << "Standard output: " << flags.use_stdout << std::endl;
- s << "Output filename: " << flags.output_filename << std::endl;
- s << "Force overwrite output file: " << flags.force_overwrite << std::endl;
- s << "Ctls: " << ctls_to_string( flags.ctls ) << std::endl;
- s << std::endl;
- s << "Files: " << std::endl;
- for ( const auto & filename : flags.filenames ) {
- s << " " << filename << std::endl;
- }
- s << std::endl;
- return s;
- }
- static std::string replace( std::string str, const std::string & oldstr, const std::string & newstr ) {
- std::size_t pos = 0;
- while ( ( pos = str.find( oldstr, pos ) ) != std::string::npos ) {
- str.replace( pos, oldstr.length(), newstr );
- pos += newstr.length();
- }
- return str;
- }
- static bool begins_with( const std::string & str, const std::string & match ) {
- return ( str.find( match ) == 0 );
- }
- static bool ends_with( const std::string & str, const std::string & match ) {
- return ( str.rfind( match ) == ( str.length() - match.length() ) );
- }
- static std::string trim_left(std::string str, const std::string &whitespace = std::string()) {
- std::string::size_type pos = str.find_first_not_of(whitespace);
- if(pos != std::string::npos) {
- str.erase(str.begin(), str.begin() + pos);
- } else if(pos == std::string::npos && str.length() > 0 && str.find_last_of(whitespace) == str.length() - 1) {
- return std::string();
- }
- return str;
- }
- static std::string trim_right(std::string str, const std::string &whitespace = std::string()) {
- std::string::size_type pos = str.find_last_not_of(whitespace);
- if(pos != std::string::npos) {
- str.erase(str.begin() + pos + 1, str.end());
- } else if(pos == std::string::npos && str.length() > 0 && str.find_first_of(whitespace) == 0) {
- return std::string();
- }
- return str;
- }
- static std::string trim(std::string str, const std::string &whitespace = std::string()) {
- return trim_right(trim_left(str, whitespace), whitespace);
- }
- static std::string trim_eol( const std::string & str ) {
- return trim( str, "\r\n" );
- }
- static std::string default_path_separator() {
- #if defined(WIN32)
- return "\\";
- #else
- return "/";
- #endif
- }
- static std::string path_separators() {
- #if defined(WIN32)
- return "\\/";
- #else
- return "/";
- #endif
- }
- static bool is_path_separator( char c ) {
- #if defined(WIN32)
- return ( c == '\\' ) || ( c == '/' );
- #else
- return c == '/';
- #endif
- }
- static std::string get_basepath( std::string filename ) {
- std::string::size_type pos = filename.find_last_of( path_separators() );
- if ( pos == std::string::npos ) {
- return std::string();
- }
- return filename.substr( 0, pos ) + default_path_separator();
- }
- static bool is_absolute( std::string filename ) {
- #if defined(WIN32)
- if ( begins_with( filename, "\\\\?\\UNC\\" ) ) {
- return true;
- }
- if ( begins_with( filename, "\\\\?\\" ) ) {
- return true;
- }
- if ( begins_with( filename, "\\\\" ) ) {
- return true; // UNC
- }
- if ( begins_with( filename, "//" ) ) {
- return true; // UNC
- }
- return ( filename.length() ) >= 3 && ( filename[1] == ':' ) && is_path_separator( filename[2] );
- #else
- return ( filename.length() >= 1 ) && is_path_separator( filename[0] );
- #endif
- }
- static std::string get_filename( const std::string & filepath ) {
- if ( filepath.find_last_of( path_separators() ) == std::string::npos ) {
- return filepath;
- }
- return filepath.substr( filepath.find_last_of( path_separators() ) + 1 );
- }
- static std::string prepend_lines( std::string str, const std::string & prefix ) {
- if ( str.empty() ) {
- return str;
- }
- if ( str.substr( str.length() - 1, 1 ) == std::string("\n") ) {
- str = str.substr( 0, str.length() - 1 );
- }
- return replace( str, std::string("\n"), std::string("\n") + prefix );
- }
- static std::string bytes_to_string( std::uint64_t bytes ) {
- static const char * const suffixes[] = { "B", "kB", "MB", "GB", "TB", "PB" };
- int offset = 0;
- while ( bytes > 9999 ) {
- bytes /= 1000;
- offset += 1;
- if ( offset == 5 ) {
- break;
- }
- }
- std::ostringstream result;
- result << bytes << suffixes[offset];
- return result.str();
- }
- 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 ) ) % 60;
- std::int64_t hours = ( time_ms / ( 1000 * 60 * 60 ) );
- 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();
- }
- static void show_info( std::ostream & log, bool verbose ) {
- log << "openmpt123" << " v" << OPENMPT123_VERSION_STRING << ", libopenmpt " << openmpt::string::get( "library_version" ) << " (" << "OpenMPT " << openmpt::string::get( "core_version" ) << ")" << std::endl;
- log << "Copyright (c) 2013-2022 OpenMPT Project Developers and Contributors <https://lib.openmpt.org/>" << std::endl;
- if ( !verbose ) {
- log << std::endl;
- return;
- }
- log << " libopenmpt source..: " << openmpt::string::get( "source_url" ) << std::endl;
- log << " libopenmpt date....: " << openmpt::string::get( "source_date" ) << std::endl;
- log << " libopenmpt srcinfo.: ";
- {
- std::vector<std::string> fields;
- if ( openmpt::string::get( "source_is_package" ) == "1" ) {
- fields.push_back( "package" );
- }
- if ( openmpt::string::get( "source_is_release" ) == "1" ) {
- fields.push_back( "release" );
- }
- if ( ( !openmpt::string::get( "source_revision" ).empty() ) && ( openmpt::string::get( "source_revision" ) != "0" ) ) {
- std::string field = "rev" + openmpt::string::get( "source_revision" );
- if ( openmpt::string::get( "source_has_mixed_revisions" ) == "1" ) {
- field += "+mixed";
- }
- if ( openmpt::string::get( "source_is_modified" ) == "1" ) {
- field += "+modified";
- }
- fields.push_back( field );
- }
- bool first = true;
- for ( const auto & field : fields ) {
- if ( first ) {
- first = false;
- } else {
- log << ", ";
- }
- log << field;
- }
- }
- log << std::endl;
- log << " libopenmpt compiler: " << openmpt::string::get( "build_compiler" ) << std::endl;
- log << " libopenmpt features: " << openmpt::string::get( "library_features" ) << std::endl;
- #ifdef MPT_WITH_SDL2
- log << " libSDL2 ";
- SDL_version sdlver;
- std::memset( &sdlver, 0, sizeof( SDL_version ) );
- SDL_GetVersion( &sdlver );
- log << static_cast<int>( sdlver.major ) << "." << static_cast<int>( sdlver.minor ) << "." << static_cast<int>( sdlver.patch );
- const char * revision = SDL_GetRevision();
- if ( revision ) {
- log << " (" << revision << ")";
- }
- log << ", ";
- std::memset( &sdlver, 0, sizeof( SDL_version ) );
- SDL_VERSION( &sdlver );
- log << "API: " << static_cast<int>( sdlver.major ) << "." << static_cast<int>( sdlver.minor ) << "." << static_cast<int>( sdlver.patch ) << "";
- log << " <https://libsdl.org/>" << std::endl;
- #endif
- #ifdef MPT_WITH_PULSEAUDIO
- log << " " << "libpulse, libpulse-simple" << " (headers " << pa_get_headers_version() << ", API " << PA_API_VERSION << ", PROTOCOL " << PA_PROTOCOL_VERSION << ", library " << ( pa_get_library_version() ? pa_get_library_version() : "unknown" ) << ") <https://www.freedesktop.org/wiki/Software/PulseAudio/>" << std::endl;
- #endif
- #ifdef MPT_WITH_PORTAUDIO
- log << " " << Pa_GetVersionText() << " (" << Pa_GetVersion() << ") <http://portaudio.com/>" << std::endl;
- #endif
- #ifdef MPT_WITH_FLAC
- log << " FLAC " << FLAC__VERSION_STRING << ", " << FLAC__VENDOR_STRING << ", API " << FLAC_API_VERSION_CURRENT << "." << FLAC_API_VERSION_REVISION << "." << FLAC_API_VERSION_AGE << " <https://xiph.org/flac/>" << std::endl;
- #endif
- #ifdef MPT_WITH_SNDFILE
- char sndfile_info[128];
- std::memset( sndfile_info, 0, sizeof( sndfile_info ) );
- sf_command( 0, SFC_GET_LIB_VERSION, sndfile_info, sizeof( sndfile_info ) );
- sndfile_info[127] = '\0';
- log << " libsndfile " << sndfile_info << " <http://mega-nerd.com/libsndfile/>" << std::endl;
- #endif
- log << std::endl;
- }
- static void show_man_version( textout & log ) {
- log << "openmpt123" << " v" << OPENMPT123_VERSION_STRING << std::endl;
- log << std::endl;
- log << "Copyright (c) 2013-2022 OpenMPT Project Developers and Contributors <https://lib.openmpt.org/>" << std::endl;
- }
- static void show_short_version( textout & log ) {
- log << OPENMPT123_VERSION_STRING << " / " << openmpt::string::get( "library_version" ) << " / " << openmpt::string::get( "core_version" ) << std::endl;
- log.writeout();
- }
- static void show_version( textout & log ) {
- show_info( log, false );
- log.writeout();
- }
- static void show_long_version( textout & log ) {
- show_info( log, true );
- log.writeout();
- }
- static void show_credits( textout & log ) {
- show_info( log, false );
- log << openmpt::string::get( "contact" ) << std::endl;
- log << std::endl;
- log << openmpt::string::get( "credits" ) << std::endl;
- log.writeout();
- }
- static void show_license( textout & log ) {
- show_info( log, false );
- log << license << std::endl;
- log.writeout();
- }
- static std::string get_driver_string( const std::string & driver ) {
- if ( driver.empty() ) {
- return "default";
- }
- return driver;
- }
- static std::string get_device_string( const std::string & device ) {
- if ( device.empty() ) {
- return "default";
- }
- return device;
- }
- static void show_help( textout & log, bool with_info = true, bool longhelp = false, bool man_version = false, const std::string & message = std::string() ) {
- if ( with_info ) {
- show_info( log, false );
- }
- {
- log << "Usage: openmpt123 [options] [--] file1 [file2] ..." << std::endl;
- log << std::endl;
- if ( man_version ) {
- log << "openmpt123 plays module music files." << std::endl;
- log << std::endl;
- }
- if ( man_version ) {
- log << "Options:" << std::endl;
- }
- log << " -h, --help Show help" << std::endl;
- log << " --help-keyboard Show keyboard hotkeys in ui mode" << std::endl;
- log << " -q, --quiet Suppress non-error screen output" << std::endl;
- log << " -v, --verbose Show more screen output" << std::endl;
- log << " --version Show version information and exit" << std::endl;
- log << " --short-version Show version number and nothing else" << std::endl;
- log << " --long-version Show long version information and exit" << std::endl;
- log << " --credits Show elaborate contributors list" << std::endl;
- log << " --license Show license" << std::endl;
- log << std::endl;
- log << " --probe Probe each file whether it is a supported file format" << std::endl;
- log << " --info Display information about each file" << std::endl;
- log << " --ui Interactively play each file" << std::endl;
- log << " --batch Play each file" << std::endl;
- log << " --render Render each file to individual PCM data files" << std::endl;
- if ( !longhelp ) {
- log << std::endl;
- log.writeout();
- return;
- }
- log << std::endl;
- log << " --terminal-width n Assume terminal is n characters wide [default: " << commandlineflags().terminal_width << "]" << std::endl;
- log << " --terminal-height n Assume terminal is n characters high [default: " << commandlineflags().terminal_height << "]" << std::endl;
- log << std::endl;
- log << " --[no-]progress Show playback progress [default: " << commandlineflags().show_progress << "]" << std::endl;
- log << " --[no-]meters Show peak meters [default: " << commandlineflags().show_meters << "]" << std::endl;
- log << " --[no-]channel-meters Show channel peak meters (EXPERIMENTAL) [default: " << commandlineflags().show_channel_meters << "]" << std::endl;
- log << " --[no-]pattern Show pattern (EXPERIMENTAL) [default: " << commandlineflags().show_pattern << "]" << std::endl;
- log << std::endl;
- log << " --[no-]details Show song details [default: " << commandlineflags().show_details << "]" << std::endl;
- log << " --[no-]message Show song message [default: " << commandlineflags().show_message << "]" << std::endl;
- log << std::endl;
- log << " --update n Set output update interval to n ms [default: " << commandlineflags().ui_redraw_interval << "]" << std::endl;
- log << std::endl;
- log << " --samplerate n Set samplerate to n Hz [default: " << commandlineflags().samplerate << "]" << std::endl;
- log << " --channels n use n [1,2,4] output channels [default: " << commandlineflags().channels << "]" << std::endl;
- log << " --[no-]float Output 32bit floating point instead of 16bit integer [default: " << commandlineflags().use_float << "]" << std::endl;
- log << std::endl;
- log << " --gain n Set output gain to n dB [default: " << commandlineflags().gain / 100.0 << "]" << std::endl;
- log << " --stereo n Set stereo separation to n % [default: " << commandlineflags().separation << "]" << std::endl;
- log << " --filter n Set interpolation filter taps to n [1,2,4,8] [default: " << commandlineflags().filtertaps << "]" << std::endl;
- log << " --ramping n Set volume ramping strength n [0..5] [default: " << commandlineflags().ramping << "]" << std::endl;
- log << " --tempo f Set tempo factor f [default: " << tempo_flag_to_double( commandlineflags().tempo ) << "]" << std::endl;
- log << " --pitch f Set pitch factor f [default: " << pitch_flag_to_double( commandlineflags().pitch ) << "]" << std::endl;
- log << " --dither n Dither type to use (if applicable for selected output format): [0=off,1=auto,2=0.5bit,3=1bit] [default: " << commandlineflags().dither << "]" << std::endl;
- log << std::endl;
- log << " --playlist file Load playlist from file" << std::endl;
- log << " --[no-]randomize Randomize playlist [default: " << commandlineflags().randomize << "]" << std::endl;
- log << " --[no-]shuffle Shuffle through playlist [default: " << commandlineflags().shuffle << "]" << std::endl;
- log << " --[no-]restart Restart playlist when finished [default: " << commandlineflags().restart << "]" << std::endl;
- log << std::endl;
- log << " --subsong n Select subsong n (-1 means play all subsongs consecutively) [default: " << commandlineflags().subsong << "]" << std::endl;
- log << " --repeat n Repeat song n times (-1 means forever) [default: " << commandlineflags().repeatcount << "]" << std::endl;
- log << " --seek n Seek to n seconds on start [default: " << commandlineflags().seek_target << "]" << std::endl;
- log << " --end-time n Play until position is n seconds (0 means until the end) [default: " << commandlineflags().end_time << "]" << std::endl;
- log << std::endl;
- log << " --ctl c=v Set libopenmpt ctl c to value v" << std::endl;
- log << std::endl;
- log << " --driver n Set output driver [default: " << get_driver_string( commandlineflags().driver ) << "]," << std::endl;
- log << " --device n Set output device [default: " << get_device_string( commandlineflags().device ) << "]," << std::endl;
- log << " use --device help to show available devices" << std::endl;
- log << " --buffer n Set output buffer size to n ms [default: " << commandlineflags().buffer << "]" << std::endl;
- log << " --period n Set output period size to n ms [default: " << commandlineflags().period << "]" << std::endl;
- log << " --stdout Write raw audio data to stdout [default: " << commandlineflags().use_stdout << "]" << std::endl;
- log << " --output-type t Use output format t when writing to a individual PCM files (only applies to --render mode) [default: " << commandlineflags().output_extension << "]" << std::endl;
- log << " -o, --output f Write PCM output to file f instead of streaming to audio device (only applies to --ui and --batch modes) [default: " << commandlineflags().output_filename << "]" << std::endl;
- log << " --force Force overwriting of output file [default: " << commandlineflags().force_overwrite << "]" << std::endl;
- log << std::endl;
- log << " -- Interpret further arguments as filenames" << std::endl;
- log << std::endl;
- if ( !man_version ) {
- log << " Supported file formats: " << std::endl;
- log << " ";
- std::vector<std::string> extensions = openmpt::get_supported_extensions();
- bool first = true;
- for ( const auto & extension : extensions ) {
- if ( first ) {
- first = false;
- } else {
- log << ", ";
- }
- log << extension;
- }
- log << std::endl;
- }
- }
- log << std::endl;
- if ( message.size() > 0 ) {
- log << message;
- log << std::endl;
- }
- log.writeout();
- }
- static void show_help_keyboard( textout & log ) {
- show_info( log, false );
- log << "Keyboard hotkeys (use 'openmpt123 --ui'):" << std::endl;
- log << std::endl;
- log << " [q] quit" << std::endl;
- log << " [ ] pause / unpause" << std::endl;
- log << " [N] skip 10 files backward" << std::endl;
- log << " [n] prev file" << std::endl;
- log << " [m] next file" << std::endl;
- log << " [M] skip 10 files forward" << std::endl;
- log << " [h] seek 10 seconds backward" << std::endl;
- log << " [j] seek 1 seconds backward" << std::endl;
- log << " [k] seek 1 seconds forward" << std::endl;
- log << " [l] seek 10 seconds forward" << std::endl;
- log << " [u]|[i] +/- tempo" << std::endl;
- log << " [o]|[p] +/- pitch" << std::endl;
- log << " [3]|[4] +/- gain" << std::endl;
- log << " [5]|[6] +/- stereo separation" << std::endl;
- log << " [7]|[8] +/- filter taps" << std::endl;
- log << " [9]|[0] +/- volume ramping" << std::endl;
- log << std::endl;
- log.writeout();
- }
- template < typename Tmod >
- static void apply_mod_settings( commandlineflags & flags, Tmod & mod ) {
- flags.separation = std::max( flags.separation, std::int32_t( 0 ) );
- flags.filtertaps = std::max( flags.filtertaps, std::int32_t( 1 ) );
- flags.filtertaps = std::min( flags.filtertaps, std::int32_t( 8 ) );
- flags.ramping = std::max( flags.ramping, std::int32_t( -1 ) );
- flags.ramping = std::min( flags.ramping, std::int32_t( 10 ) );
- flags.tempo = std::max( flags.tempo, std::int32_t( -48 ) );
- flags.tempo = std::min( flags.tempo, std::int32_t( 48 ) );
- flags.pitch = std::max( flags.pitch, std::int32_t( -48 ) );
- flags.pitch = std::min( flags.pitch, std::int32_t( 48 ) );
- mod.set_render_param( openmpt::module::RENDER_MASTERGAIN_MILLIBEL, flags.gain );
- mod.set_render_param( openmpt::module::RENDER_STEREOSEPARATION_PERCENT, flags.separation );
- mod.set_render_param( openmpt::module::RENDER_INTERPOLATIONFILTER_LENGTH, flags.filtertaps );
- mod.set_render_param( openmpt::module::RENDER_VOLUMERAMPING_STRENGTH, flags.ramping );
- try {
- mod.ctl_set_floatingpoint( "play.tempo_factor", tempo_flag_to_double( flags.tempo ) );
- } catch ( const openmpt::exception & ) {
- // ignore
- }
- try {
- mod.ctl_set_floatingpoint( "play.pitch_factor", pitch_flag_to_double( flags.pitch ) );
- } catch ( const openmpt::exception & ) {
- // ignore
- }
- mod.ctl_set_integer( "dither", flags.dither );
- }
- struct prev_file { int count; prev_file( int c ) : count(c) { } };
- struct next_file { int count; next_file( int c ) : count(c) { } };
- template < typename Tmod >
- static bool handle_keypress( int c, commandlineflags & flags, Tmod & mod, write_buffers_interface & audio_stream ) {
- switch ( c ) {
- case 'q': throw silent_exit_exception(); break;
- case 'N': throw prev_file(10); break;
- case 'n': throw prev_file(1); break;
- case ' ': if ( !flags.paused ) { flags.paused = audio_stream.pause(); } else { flags.paused = false; audio_stream.unpause(); } break;
- case 'h': mod.set_position_seconds( mod.get_position_seconds() - 10.0 ); break;
- case 'j': mod.set_position_seconds( mod.get_position_seconds() - 1.0 ); break;
- case 'k': mod.set_position_seconds( mod.get_position_seconds() + 1.0 ); break;
- case 'l': mod.set_position_seconds( mod.get_position_seconds() + 10.0 ); break;
- case 'H': mod.set_position_order_row( mod.get_current_order() - 1, 0 ); break;
- case 'J': mod.set_position_order_row( mod.get_current_order(), mod.get_current_row() - 1 ); break;
- case 'K': mod.set_position_order_row( mod.get_current_order(), mod.get_current_row() + 1 ); break;
- case 'L': mod.set_position_order_row( mod.get_current_order() + 1, 0 ); break;
- case 'm': throw next_file(1); break;
- case 'M': throw next_file(10); break;
- case 'u': flags.tempo -= 1; apply_mod_settings( flags, mod ); break;
- case 'i': flags.tempo += 1; apply_mod_settings( flags, mod ); break;
- case 'o': flags.pitch -= 1; apply_mod_settings( flags, mod ); break;
- case 'p': flags.pitch += 1; apply_mod_settings( flags, mod ); break;
- case '3': flags.gain -=100; apply_mod_settings( flags, mod ); break;
- case '4': flags.gain +=100; apply_mod_settings( flags, mod ); break;
- case '5': flags.separation -= 5; apply_mod_settings( flags, mod ); break;
- case '6': flags.separation += 5; apply_mod_settings( flags, mod ); break;
- case '7': flags.filtertaps /= 2; apply_mod_settings( flags, mod ); break;
- case '8': flags.filtertaps *= 2; apply_mod_settings( flags, mod ); break;
- case '9': flags.ramping -= 1; apply_mod_settings( flags, mod ); break;
- case '0': flags.ramping += 1; apply_mod_settings( flags, mod ); break;
- }
- return true;
- }
- struct meter_channel {
- float peak;
- float clip;
- float hold;
- float hold_age;
- meter_channel()
- : peak(0.0f)
- , clip(0.0f)
- , hold(0.0f)
- , hold_age(0.0f)
- {
- return;
- }
- };
- struct meter_type {
- meter_channel channels[4];
- };
- static const float falloff_rate = 20.0f / 1.7f;
- static void update_meter( meter_type & meter, const commandlineflags & flags, std::size_t count, const std::int16_t * const * buffers ) {
- float falloff_factor = std::pow( 10.0f, -falloff_rate / flags.samplerate / 20.0f );
- for ( int channel = 0; channel < flags.channels; ++channel ) {
- meter.channels[channel].peak = 0.0f;
- for ( std::size_t frame = 0; frame < count; ++frame ) {
- if ( meter.channels[channel].clip != 0.0f ) {
- meter.channels[channel].clip -= ( 1.0f / 2.0f ) * 1.0f / static_cast<float>( flags.samplerate );
- if ( meter.channels[channel].clip <= 0.0f ) {
- meter.channels[channel].clip = 0.0f;
- }
- }
- float val = std::fabs( buffers[channel][frame] / 32768.0f );
- if ( val >= 1.0f ) {
- meter.channels[channel].clip = 1.0f;
- }
- if ( val > meter.channels[channel].peak ) {
- meter.channels[channel].peak = val;
- }
- meter.channels[channel].hold *= falloff_factor;
- if ( val > meter.channels[channel].hold ) {
- meter.channels[channel].hold = val;
- meter.channels[channel].hold_age = 0.0f;
- } else {
- meter.channels[channel].hold_age += 1.0f / static_cast<float>( flags.samplerate );
- }
- }
- }
- }
- static void update_meter( meter_type & meter, const commandlineflags & flags, std::size_t count, const float * const * buffers ) {
- float falloff_factor = std::pow( 10.0f, -falloff_rate / flags.samplerate / 20.0f );
- for ( int channel = 0; channel < flags.channels; ++channel ) {
- if ( !count ) {
- meter = meter_type();
- }
- meter.channels[channel].peak = 0.0f;
- for ( std::size_t frame = 0; frame < count; ++frame ) {
- if ( meter.channels[channel].clip != 0.0f ) {
- meter.channels[channel].clip -= ( 1.0f / 2.0f ) * 1.0f / static_cast<float>( flags.samplerate );
- if ( meter.channels[channel].clip <= 0.0f ) {
- meter.channels[channel].clip = 0.0f;
- }
- }
- float val = std::fabs( buffers[channel][frame] );
- if ( val >= 1.0f ) {
- meter.channels[channel].clip = 1.0f;
- }
- if ( val > meter.channels[channel].peak ) {
- meter.channels[channel].peak = val;
- }
- meter.channels[channel].hold *= falloff_factor;
- if ( val > meter.channels[channel].hold ) {
- meter.channels[channel].hold = val;
- meter.channels[channel].hold_age = 0.0f;
- } else {
- meter.channels[channel].hold_age += 1.0f / static_cast<float>( flags.samplerate );
- }
- }
- }
- }
- static const char * const channel_tags[4][4] = {
- { " C", " ", " ", " " },
- { " L", " R", " ", " " },
- { "FL", "FR", "RC", " " },
- { "FL", "FR", "RL", "RR" },
- };
- static std::string channel_to_string( int channels, int channel, const meter_channel & meter, bool tiny = false ) {
- int val = std::numeric_limits<int>::min();
- int hold_pos = std::numeric_limits<int>::min();
- if ( meter.peak > 0.0f ) {
- float db = 20.0f * std::log10( meter.peak );
- val = static_cast<int>( db + 48.0f );
- }
- if ( meter.hold > 0.0f ) {
- float db_hold = 20.0f * std::log10( meter.hold );
- hold_pos = static_cast<int>( db_hold + 48.0f );
- }
- if ( val < 0 ) {
- val = 0;
- }
- int headroom = val;
- if ( val > 48 ) {
- val = 48;
- }
- headroom -= val;
- if ( headroom < 0 ) {
- headroom = 0;
- }
- if ( headroom > 12 ) {
- headroom = 12;
- }
- headroom -= 1; // clip indicator
- if ( headroom < 0 ) {
- headroom = 0;
- }
- if ( tiny ) {
- if ( meter.clip != 0.0f || meter.peak >= 1.0f ) {
- return "#";
- } else if ( meter.peak > std::pow( 10.0f, -6.0f / 20.0f ) ) {
- return "O";
- } else if ( meter.peak > std::pow( 10.0f, -12.0f / 20.0f ) ) {
- return "o";
- } else if ( meter.peak > std::pow( 10.0f, -18.0f / 20.0f ) ) {
- return ".";
- } else {
- return " ";
- }
- } else {
- std::ostringstream res1;
- std::ostringstream res2;
- res1
- << " "
- << channel_tags[channels-1][channel]
- << " : "
- ;
- res2
- << std::string(val,'>') << std::string(std::size_t{48}-val,' ')
- << ( ( meter.clip != 0.0f ) ? "#" : ":" )
- << std::string(headroom,'>') << std::string(std::size_t{12}-headroom,' ')
- ;
- std::string tmp = res2.str();
- if ( 0 <= hold_pos && hold_pos <= 60 ) {
- if ( hold_pos == 48 ) {
- tmp[hold_pos] = '#';
- } else {
- tmp[hold_pos] = ':';
- }
- }
- return res1.str() + tmp;
- }
- }
- static char peak_to_char( float peak ) {
- if ( peak >= 1.0f ) {
- return '#';
- } else if ( peak >= 0.5f ) {
- return 'O';
- } else if ( peak >= 0.25f ) {
- return 'o';
- } else if ( peak >= 0.125f ) {
- return '.';
- } else {
- return ' ';
- }
- }
- static std::string peak_to_string_left( float peak, int width ) {
- std::string result;
- float thresh = 1.0f;
- while ( width-- ) {
- if ( peak >= thresh ) {
- if ( thresh == 1.0f ) {
- result.push_back( '#' );
- } else {
- result.push_back( '<' );
- }
- } else {
- result.push_back( ' ' );
- }
- thresh *= 0.5f;
- }
- return result;
- }
- static std::string peak_to_string_right( float peak, int width ) {
- std::string result;
- float thresh = 1.0f;
- while ( width-- ) {
- if ( peak >= thresh ) {
- if ( thresh == 1.0f ) {
- result.push_back( '#' );
- } else {
- result.push_back( '>' );
- }
- } else {
- result.push_back( ' ' );
- }
- thresh *= 0.5f;
- }
- std::reverse( result.begin(), result.end() );
- return result;
- }
- static void draw_meters( std::ostream & log, const meter_type & meter, const commandlineflags & flags ) {
- for ( int channel = 0; channel < flags.channels; ++channel ) {
- log << channel_to_string( flags.channels, channel, meter.channels[channel] ) << std::endl;
- }
- }
- static void draw_meters_tiny( std::ostream & log, const meter_type & meter, const commandlineflags & flags ) {
- for ( int channel = 0; channel < flags.channels; ++channel ) {
- log << channel_to_string( flags.channels, channel, meter.channels[channel], true );
- }
- }
- static void draw_channel_meters_tiny( std::ostream & log, float peak ) {
- log << peak_to_char( peak );
- }
- static void draw_channel_meters_tiny( std::ostream & log, float peak_left, float peak_right ) {
- log << peak_to_char( peak_left ) << peak_to_char( peak_right );
- }
- static void draw_channel_meters( std::ostream & log, float peak_left, float peak_right, int width ) {
- if ( width >= 8 + 1 + 8 ) {
- width = 8 + 1 + 8;
- }
- log << peak_to_string_left( peak_left, width / 2 ) << ( width % 2 == 1 ? ":" : "" ) << peak_to_string_right( peak_right, width / 2 );
- }
- template < typename Tsample, typename Tmod >
- void render_loop( commandlineflags & flags, Tmod & mod, double & duration, textout & log, write_buffers_interface & audio_stream ) {
- log.writeout();
- std::size_t bufsize;
- if ( flags.mode == Mode::UI ) {
- bufsize = std::min( flags.ui_redraw_interval, flags.period ) * flags.samplerate / 1000;
- } else if ( flags.mode == Mode::Batch ) {
- bufsize = flags.period * flags.samplerate / 1000;
- } else {
- bufsize = 1024;
- }
- std::int64_t last_redraw_frame = std::int64_t{0} - flags.ui_redraw_interval;
- std::int64_t rendered_frames = 0;
- std::vector<Tsample> left( bufsize );
- std::vector<Tsample> right( bufsize );
- std::vector<Tsample> rear_left( bufsize );
- std::vector<Tsample> rear_right( bufsize );
- std::vector<Tsample*> buffers( 4 ) ;
- buffers[0] = left.data();
- buffers[1] = right.data();
- buffers[2] = rear_left.data();
- buffers[3] = rear_right.data();
- buffers.resize( flags.channels );
-
- meter_type meter;
-
- const bool multiline = flags.show_ui;
-
- int lines = 0;
- int pattern_lines = 0;
-
- if ( multiline ) {
- lines += 1;
- // cppcheck-suppress identicalInnerCondition
- if ( flags.show_ui ) {
- lines += 1;
- }
- if ( flags.show_meters ) {
- for ( int channel = 0; channel < flags.channels; ++channel ) {
- lines += 1;
- }
- }
- if ( flags.show_channel_meters ) {
- lines += 1;
- }
- if ( flags.show_details ) {
- lines += 1;
- if ( flags.show_progress ) {
- lines += 1;
- }
- }
- if ( flags.show_progress ) {
- lines += 1;
- }
- if ( flags.show_pattern ) {
- pattern_lines = flags.terminal_height - lines - 1;
- lines = flags.terminal_height - 1;
- }
- } else if ( flags.show_ui || flags.show_details || flags.show_progress ) {
- log << std::endl;
- }
- for ( int line = 0; line < lines; ++line ) {
- log << std::endl;
- }
- log.writeout();
- double cpu_smooth = 0.0;
- while ( true ) {
- if ( flags.mode == Mode::UI ) {
- #if defined( __DJGPP__ )
- while ( kbhit() ) {
- int c = getch();
- if ( !handle_keypress( c, flags, mod, audio_stream ) ) {
- return;
- }
- }
- #elif defined( WIN32 ) && defined( UNICODE )
- while ( _kbhit() ) {
- wint_t c = _getwch();
- if ( !handle_keypress( c, flags, mod, audio_stream ) ) {
- return;
- }
- }
- #elif defined( WIN32 )
- while ( _kbhit() ) {
- int c = _getch();
- if ( !handle_keypress( c, flags, mod, audio_stream ) ) {
- return;
- }
- }
- #else
- while ( true ) {
- pollfd pollfds;
- pollfds.fd = STDIN_FILENO;
- pollfds.events = POLLIN;
- poll(&pollfds, 1, 0);
- if ( !( pollfds.revents & POLLIN ) ) {
- break;
- }
- char c = 0;
- if ( read( STDIN_FILENO, &c, 1 ) != 1 ) {
- break;
- }
- if ( !handle_keypress( c, flags, mod, audio_stream ) ) {
- return;
- }
- }
- #endif
- if ( flags.paused ) {
- audio_stream.sleep( flags.ui_redraw_interval );
- continue;
- }
- }
-
- std::clock_t cpu_beg = 0;
- std::clock_t cpu_end = 0;
- if ( flags.show_details ) {
- cpu_beg = std::clock();
- }
- 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(), rear_left.data(), rear_right.data() ); break;
- }
-
- char cpu_str[64] = "";
- if ( flags.show_details ) {
- cpu_end = std::clock();
- if ( count > 0 ) {
- double cpu = 1.0;
- cpu *= ( static_cast<double>( cpu_end ) - static_cast<double>( cpu_beg ) ) / static_cast<double>( CLOCKS_PER_SEC );
- cpu /= ( static_cast<double>( count ) ) / static_cast<double>( flags.samplerate );
- double mix = ( static_cast<double>( count ) ) / static_cast<double>( flags.samplerate );
- cpu_smooth = ( 1.0 - mix ) * cpu_smooth + mix * cpu;
- std::snprintf( cpu_str, 64, "%.2f%%", cpu_smooth * 100.0 );
- }
- }
- if ( flags.show_meters ) {
- update_meter( meter, flags, count, buffers.data() );
- }
- if ( count > 0 ) {
- audio_stream.write( buffers, count );
- }
- if ( count > 0 ) {
- rendered_frames += count;
- if ( rendered_frames >= last_redraw_frame + ( flags.ui_redraw_interval * flags.samplerate / 1000 ) ) {
- last_redraw_frame = rendered_frames;
- } else {
- continue;
- }
- }
- if ( multiline ) {
- log.cursor_up( lines );
- log << std::endl;
- if ( flags.show_meters ) {
- draw_meters( log, meter, flags );
- }
- if ( flags.show_channel_meters ) {
- int width = ( flags.terminal_width - 3 ) / mod.get_num_channels();
- if ( width > 11 ) {
- width = 11;
- }
- log << " ";
- for ( std::int32_t channel = 0; channel < mod.get_num_channels(); ++channel ) {
- if ( width >= 3 ) {
- log << ":";
- }
- if ( width == 1 ) {
- draw_channel_meters_tiny( log, ( mod.get_current_channel_vu_left( channel ) + mod.get_current_channel_vu_right( channel ) ) * (1.0f/std::sqrt(2.0f)) );
- } else if ( width <= 4 ) {
- draw_channel_meters_tiny( log, mod.get_current_channel_vu_left( channel ), mod.get_current_channel_vu_right( channel ) );
- } else {
- draw_channel_meters( log, mod.get_current_channel_vu_left( channel ), mod.get_current_channel_vu_right( channel ), width - 1 );
- }
- }
- if ( width >= 3 ) {
- log << ":";
- }
- log << std::endl;
- }
- if ( flags.show_pattern ) {
- int width = ( flags.terminal_width - 3 ) / mod.get_num_channels();
- if ( width > 13 + 1 ) {
- width = 13 + 1;
- }
- for ( std::int32_t line = 0; line < pattern_lines; ++line ) {
- std::int32_t row = mod.get_current_row() - ( pattern_lines / 2 ) + line;
- if ( row == mod.get_current_row() ) {
- log << ">";
- } else {
- log << " ";
- }
- if ( row < 0 || row >= mod.get_pattern_num_rows( mod.get_current_pattern() ) ) {
- for ( std::int32_t channel = 0; channel < mod.get_num_channels(); ++channel ) {
- if ( width >= 3 ) {
- log << ":";
- }
- log << std::string( width >= 3 ? width - 1 : width, ' ' );
- }
- } else {
- for ( std::int32_t channel = 0; channel < mod.get_num_channels(); ++channel ) {
- if ( width >= 3 ) {
- if ( row == mod.get_current_row() ) {
- log << "+";
- } else {
- log << ":";
- }
- }
- log << mod.format_pattern_row_channel( mod.get_current_pattern(), row, channel, width >= 3 ? width - 1 : width );
- }
- }
- if ( width >= 3 ) {
- log << ":";
- }
- log << std::endl;
- }
- }
- if ( flags.show_ui ) {
- log << "Settings...: ";
- log << "Gain: " << flags.gain * 0.01f << " dB" << " ";
- log << "Stereo: " << flags.separation << " %" << " ";
- log << "Filter: " << flags.filtertaps << " taps" << " ";
- log << "Ramping: " << flags.ramping << " ";
- log << std::endl;
- }
- if ( flags.show_details ) {
- log << "Mixer......: ";
- log << "CPU:" << std::setw(6) << std::setfill(':') << cpu_str;
- log << " ";
- log << "Chn:" << std::setw(3) << std::setfill(':') << mod.get_current_playing_channels();
- log << " ";
- log << std::endl;
- if ( flags.show_progress ) {
- log << "Player.....: ";
- log << "Ord:" << std::setw(3) << std::setfill(':') << mod.get_current_order() << "/" << std::setw(3) << std::setfill(':') << mod.get_num_orders();
- log << " ";
- log << "Pat:" << std::setw(3) << std::setfill(':') << mod.get_current_pattern();
- log << " ";
- log << "Row:" << std::setw(3) << std::setfill(':') << mod.get_current_row();
- log << " ";
- log << "Spd:" << std::setw(2) << std::setfill(':') << mod.get_current_speed();
- log << " ";
- log << "Tmp:" << std::setw(3) << std::setfill(':') << mod.get_current_tempo();
- log << " ";
- log << std::endl;
- }
- }
- if ( flags.show_progress ) {
- log << "Position...: " << seconds_to_string( mod.get_position_seconds() ) << " / " << seconds_to_string( duration ) << " " << std::endl;
- }
- } else if ( flags.show_channel_meters ) {
- if ( flags.show_ui || flags.show_details || flags.show_progress ) {
- int width = ( flags.terminal_width - 3 ) / mod.get_num_channels();
- log << " ";
- for ( std::int32_t channel = 0; channel < mod.get_num_channels(); ++channel ) {
- if ( width >= 3 ) {
- log << ":";
- }
- if ( width == 1 ) {
- draw_channel_meters_tiny( log, ( mod.get_current_channel_vu_left( channel ) + mod.get_current_channel_vu_right( channel ) ) * (1.0f/std::sqrt(2.0f)) );
- } else if ( width <= 4 ) {
- draw_channel_meters_tiny( log, mod.get_current_channel_vu_left( channel ), mod.get_current_channel_vu_right( channel ) );
- } else {
- draw_channel_meters( log, mod.get_current_channel_vu_left( channel ), mod.get_current_channel_vu_right( channel ), width - 1 );
- }
- }
- if ( width >= 3 ) {
- log << ":";
- }
- }
- log << " " << "\r";
- } else {
- if ( flags.show_ui ) {
- log << " ";
- log << std::setw(3) << std::setfill(':') << flags.gain * 0.01f << "dB";
- log << "|";
- log << std::setw(3) << std::setfill(':') << flags.separation << "%";
- log << "|";
- log << std::setw(2) << std::setfill(':') << flags.filtertaps << "taps";
- log << "|";
- log << std::setw(3) << std::setfill(':') << flags.ramping;
- }
- if ( flags.show_meters ) {
- log << " ";
- draw_meters_tiny( log, meter, flags );
- }
- if ( flags.show_details && flags.show_ui ) {
- log << " ";
- log << "CPU:" << std::setw(6) << std::setfill(':') << cpu_str;
- log << "|";
- log << "Chn:" << std::setw(3) << std::setfill(':') << mod.get_current_playing_channels();
- }
- if ( flags.show_details && !flags.show_ui ) {
- if ( flags.show_progress ) {
- log << " ";
- log << "Ord:" << std::setw(3) << std::setfill(':') << mod.get_current_order() << "/" << std::setw(3) << std::setfill(':') << mod.get_num_orders();
- log << "|";
- log << "Pat:" << std::setw(3) << std::setfill(':') << mod.get_current_pattern();
- log << "|";
- log << "Row:" << std::setw(3) << std::setfill(':') << mod.get_current_row();
- log << " ";
- log << "Spd:" << std::setw(2) << std::setfill(':') << mod.get_current_speed();
- log << "|";
- log << "Tmp:" << std::setw(3) << std::setfill(':') << mod.get_current_tempo();
- }
- }
- if ( flags.show_progress ) {
- log << " ";
- log << seconds_to_string( mod.get_position_seconds() );
- log << "/";
- log << seconds_to_string( duration );
- }
- if ( flags.show_ui || flags.show_details || flags.show_progress ) {
- log << " " << "\r";
- }
- }
- log.writeout();
- if ( count == 0 ) {
- break;
- }
-
- if ( flags.end_time > 0 && mod.get_position_seconds() >= flags.end_time ) {
- break;
- }
- }
- log.writeout();
- }
- template < typename Tmod >
- std::map<std::string,std::string> get_metadata( const Tmod & mod ) {
- std::map<std::string,std::string> result;
- const std::vector<std::string> metadata_keys = mod.get_metadata_keys();
- for ( const auto & key : metadata_keys ) {
- result[ key ] = mod.get_metadata( key );
- }
- return result;
- }
- class set_field : private std::ostringstream {
- private:
- std::vector<openmpt123::field> & fields;
- public:
- set_field( std::vector<openmpt123::field> & fields, const std::string & name )
- : fields(fields)
- {
- fields.push_back( name );
- }
- std::ostream & ostream() {
- return *this;
- }
- ~set_field() {
- fields.back().val = str();
- }
- };
- static void show_fields( textout & log, const std::vector<field> & fields ) {
- const std::size_t fw = 11;
- for ( const auto & field :fields ) {
- std::string key = field.key;
- std::string val = field.val;
- if ( key.length() < fw ) {
- key += std::string( fw - key.length(), '.' );
- }
- if ( key.length() > fw ) {
- key = key.substr( 0, fw );
- }
- key += ": ";
- val = prepend_lines( val, std::string( fw, ' ' ) + ": " );
- log << key << val << std::endl;
- }
- }
- static void probe_mod_file( commandlineflags & flags, const std::string & filename, std::uint64_t filesize, std::istream & data_stream, textout & log ) {
- log.writeout();
- std::vector<field> fields;
- if ( flags.filenames.size() > 1 ) {
- set_field( fields, "Playlist" ).ostream() << flags.playlist_index + 1 << "/" << flags.filenames.size();
- set_field( fields, "Prev/Next" ).ostream()
- << "'"
- << ( flags.playlist_index > 0 ? get_filename( flags.filenames[ flags.playlist_index - 1 ] ) : std::string() )
- << "'"
- << " / "
- << "['" << get_filename( filename ) << "']"
- << " / "
- << "'"
- << ( flags.playlist_index + 1 < flags.filenames.size() ? get_filename( flags.filenames[ flags.playlist_index + 1 ] ) : std::string() )
- << "'"
- ;
- }
- if ( flags.verbose ) {
- set_field( fields, "Path" ).ostream() << filename;
- }
- if ( flags.show_details ) {
- set_field( fields, "Filename" ).ostream() << get_filename( filename );
- set_field( fields, "Size" ).ostream() << bytes_to_string( filesize );
- }
-
- int probe_result = openmpt::probe_file_header( openmpt::probe_file_header_flags_default2, data_stream );
- std::string probe_result_string;
- switch ( probe_result ) {
- case openmpt::probe_file_header_result_success:
- probe_result_string = "Success";
- break;
- case openmpt::probe_file_header_result_failure:
- probe_result_string = "Failure";
- break;
- case openmpt::probe_file_header_result_wantmoredata:
- probe_result_string = "Insufficient Data";
- break;
- default:
- probe_result_string = "Internal Error";
- break;
- }
- set_field( fields, "Probe" ).ostream() << probe_result_string;
- show_fields( log, fields );
- log.writeout();
- }
- template < typename Tmod >
- void render_mod_file( commandlineflags & flags, const std::string & filename, std::uint64_t filesize, Tmod & mod, textout & log, write_buffers_interface & audio_stream ) {
- log.writeout();
- if ( flags.mode != Mode::Probe && flags.mode != Mode::Info ) {
- mod.set_repeat_count( flags.repeatcount );
- apply_mod_settings( flags, mod );
- }
-
- double duration = mod.get_duration_seconds();
- std::vector<field> fields;
- if ( flags.filenames.size() > 1 ) {
- set_field( fields, "Playlist" ).ostream() << flags.playlist_index + 1 << "/" << flags.filenames.size();
- set_field( fields, "Prev/Next" ).ostream()
- << "'"
- << ( flags.playlist_index > 0 ? get_filename( flags.filenames[ flags.playlist_index - 1 ] ) : std::string() )
- << "'"
- << " / "
- << "['" << get_filename( filename ) << "']"
- << " / "
- << "'"
- << ( flags.playlist_index + 1 < flags.filenames.size() ? get_filename( flags.filenames[ flags.playlist_index + 1 ] ) : std::string() )
- << "'"
- ;
- }
- if ( flags.verbose ) {
- set_field( fields, "Path" ).ostream() << filename;
- }
- if ( flags.show_details ) {
- set_field( fields, "Filename" ).ostream() << get_filename( filename );
- set_field( fields, "Size" ).ostream() << bytes_to_string( filesize );
- if ( !mod.get_metadata( "warnings" ).empty() ) {
- set_field( fields, "Warnings" ).ostream() << mod.get_metadata( "warnings" );
- }
- if ( !mod.get_metadata( "container" ).empty() ) {
- set_field( fields, "Container" ).ostream() << mod.get_metadata( "container" ) << " (" << mod.get_metadata( "container_long" ) << ")";
- }
- set_field( fields, "Type" ).ostream() << mod.get_metadata( "type" ) << " (" << mod.get_metadata( "type_long" ) << ")";
- if ( !mod.get_metadata( "originaltype" ).empty() ) {
- set_field( fields, "Orig. Type" ).ostream() << mod.get_metadata( "originaltype" ) << " (" << mod.get_metadata( "originaltype_long" ) << ")";
- }
- if ( ( mod.get_num_subsongs() > 1 ) && ( flags.subsong != -1 ) ) {
- set_field( fields, "Subsong" ).ostream() << flags.subsong;
- }
- set_field( fields, "Tracker" ).ostream() << mod.get_metadata( "tracker" );
- if ( !mod.get_metadata( "date" ).empty() ) {
- set_field( fields, "Date" ).ostream() << mod.get_metadata( "date" );
- }
- if ( !mod.get_metadata( "artist" ).empty() ) {
- set_field( fields, "Artist" ).ostream() << mod.get_metadata( "artist" );
- }
- }
- if ( true ) {
- set_field( fields, "Title" ).ostream() << mod.get_metadata( "title" );
- set_field( fields, "Duration" ).ostream() << seconds_to_string( duration );
- }
- if ( flags.show_details ) {
- set_field( fields, "Subsongs" ).ostream() << mod.get_num_subsongs();
- set_field( fields, "Channels" ).ostream() << mod.get_num_channels();
- set_field( fields, "Orders" ).ostream() << mod.get_num_orders();
- set_field( fields, "Patterns" ).ostream() << mod.get_num_patterns();
- set_field( fields, "Instruments" ).ostream() << mod.get_num_instruments();
- set_field( fields, "Samples" ).ostream() << mod.get_num_samples();
- }
- if ( flags.show_message ) {
- set_field( fields, "Message" ).ostream() << mod.get_metadata( "message" );
- }
- show_fields( log, fields );
- log.writeout();
- if ( flags.filenames.size() == 1 || flags.mode == Mode::Render ) {
- audio_stream.write_metadata( get_metadata( mod ) );
- } else {
- audio_stream.write_updated_metadata( get_metadata( mod ) );
- }
- if ( flags.mode == Mode::Probe || flags.mode == Mode::Info ) {
- return;
- }
- if ( flags.seek_target > 0.0 ) {
- mod.set_position_seconds( flags.seek_target );
- }
- try {
- 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 ( ... ) {
- if ( flags.show_progress ) {
- log << std::endl;
- }
- throw;
- }
- log.writeout();
- }
- static void probe_file( commandlineflags & flags, const std::string & filename, textout & log ) {
- log.writeout();
- std::ostringstream silentlog;
- try {
- #if defined(WIN32) && defined(UNICODE) && !defined(_MSC_VER)
- std::istringstream file_stream;
- #else
- std::ifstream file_stream;
- #endif
- std::uint64_t filesize = 0;
- bool use_stdin = ( filename == "-" );
- if ( !use_stdin ) {
- #if defined(WIN32) && defined(UNICODE) && !defined(_MSC_VER)
- // Only MSVC has std::ifstream::ifstream(std::wstring).
- // Fake it for other compilers using _wfopen().
- std::string data;
- FILE * f = _wfopen( mpt::transcode<std::wstring>( mpt::common_encoding::utf8, filename ).c_str(), L"rb" );
- if ( f ) {
- while ( !feof( f ) ) {
- static const std::size_t BUFFER_SIZE = 4096;
- char buffer[BUFFER_SIZE];
- size_t data_read = fread( buffer, 1, BUFFER_SIZE, f );
- std::copy( buffer, buffer + data_read, std::back_inserter( data ) );
- }
- fclose( f );
- f = NULL;
- }
- file_stream.str( data );
- filesize = data.length();
- #elif defined(_MSC_VER) && defined(UNICODE)
- file_stream.open( mpt::transcode<std::wstring>( mpt::common_encoding::utf8, filename ), std::ios::binary );
- file_stream.seekg( 0, std::ios::end );
- filesize = file_stream.tellg();
- file_stream.seekg( 0, std::ios::beg );
- #else
- file_stream.open( filename, std::ios::binary );
- file_stream.seekg( 0, std::ios::end );
- filesize = file_stream.tellg();
- file_stream.seekg( 0, std::ios::beg );
- #endif
- }
- std::istream & data_stream = use_stdin ? std::cin : file_stream;
- if ( data_stream.fail() ) {
- throw exception( "file open error" );
- }
-
- probe_mod_file( flags, filename, filesize, data_stream, log );
- } catch ( silent_exit_exception & ) {
- throw;
- } catch ( std::exception & e ) {
- if ( !silentlog.str().empty() ) {
- log << "errors probing '" << filename << "': " << silentlog.str() << std::endl;
- } else {
- log << "errors probing '" << filename << "'" << std::endl;
- }
- log << "error probing '" << filename << "': " << e.what() << std::endl;
- } catch ( ... ) {
- if ( !silentlog.str().empty() ) {
- log << "errors probing '" << filename << "': " << silentlog.str() << std::endl;
- } else {
- log << "errors probing '" << filename << "'" << std::endl;
- }
- log << "unknown error probing '" << filename << "'" << std::endl;
- }
- log << std::endl;
- log.writeout();
- }
- static void render_file( commandlineflags & flags, const std::string & filename, textout & log, write_buffers_interface & audio_stream ) {
- log.writeout();
- std::ostringstream silentlog;
- try {
- #if defined(WIN32) && defined(UNICODE) && !defined(_MSC_VER)
- std::istringstream file_stream;
- #else
- std::ifstream file_stream;
- #endif
- std::uint64_t filesize = 0;
- bool use_stdin = ( filename == "-" );
- if ( !use_stdin ) {
- #if defined(WIN32) && defined(UNICODE) && !defined(_MSC_VER)
- // Only MSVC has std::ifstream::ifstream(std::wstring).
- // Fake it for other compilers using _wfopen().
- std::string data;
- FILE * f = _wfopen( mpt::transcode<std::wstring>( mpt::common_encoding::utf8, filename ).c_str(), L"rb" );
- if ( f ) {
- while ( !feof( f ) ) {
- static const std::size_t BUFFER_SIZE = 4096;
- char buffer[BUFFER_SIZE];
- size_t data_read = fread( buffer, 1, BUFFER_SIZE, f );
- std::copy( buffer, buffer + data_read, std::back_inserter( data ) );
- }
- fclose( f );
- f = NULL;
- }
- file_stream.str( data );
- filesize = data.length();
- #elif defined(_MSC_VER) && defined(UNICODE)
- file_stream.open( mpt::transcode<std::wstring>( mpt::common_encoding::utf8, filename ), std::ios::binary );
- file_stream.seekg( 0, std::ios::end );
- filesize = file_stream.tellg();
- file_stream.seekg( 0, std::ios::beg );
- #else
- file_stream.open( filename, std::ios::binary );
- file_stream.seekg( 0, std::ios::end );
- filesize = file_stream.tellg();
- file_stream.seekg( 0, std::ios::beg );
- #endif
- }
- std::istream & data_stream = use_stdin ? std::cin : file_stream;
- if ( data_stream.fail() ) {
- throw exception( "file open error" );
- }
- {
- openmpt::module mod( data_stream, silentlog, flags.ctls );
- mod.select_subsong( flags.subsong );
- silentlog.str( std::string() ); // clear, loader messages get stored to get_metadata( "warnings" ) by libopenmpt internally
- render_mod_file( flags, filename, filesize, mod, log, audio_stream );
- }
- } catch ( prev_file & ) {
- throw;
- } catch ( next_file & ) {
- throw;
- } catch ( silent_exit_exception & ) {
- throw;
- } catch ( std::exception & e ) {
- if ( !silentlog.str().empty() ) {
- log << "errors loading '" << filename << "': " << silentlog.str() << std::endl;
- } else {
- log << "errors loading '" << filename << "'" << std::endl;
- }
- log << "error playing '" << filename << "': " << e.what() << std::endl;
- } catch ( ... ) {
- if ( !silentlog.str().empty() ) {
- log << "errors loading '" << filename << "': " << silentlog.str() << std::endl;
- } else {
- log << "errors loading '" << filename << "'" << std::endl;
- }
- log << "unknown error playing '" << filename << "'" << std::endl;
- }
- log << std::endl;
- log.writeout();
- }
- static std::string get_random_filename( std::set<std::string> & filenames, std::default_random_engine & prng ) {
- std::size_t index = std::uniform_int_distribution<std::size_t>( 0, filenames.size() - 1 )( prng );
- std::set<std::string>::iterator it = filenames.begin();
- std::advance( it, index );
- return *it;
- }
- static void render_files( commandlineflags & flags, textout & log, write_buffers_interface & audio_stream, std::default_random_engine & prng ) {
- if ( flags.randomize ) {
- std::shuffle( flags.filenames.begin(), flags.filenames.end(), prng );
- }
- try {
- while ( true ) {
- if ( flags.shuffle ) {
- // TODO: improve prev/next logic
- std::set<std::string> shuffle_set;
- shuffle_set.insert( flags.filenames.begin(), flags.filenames.end() );
- while ( true ) {
- if ( shuffle_set.empty() ) {
- break;
- }
- std::string filename = get_random_filename( shuffle_set, prng );
- try {
- flags.playlist_index = std::find( flags.filenames.begin(), flags.filenames.end(), filename ) - flags.filenames.begin();
- render_file( flags, filename, log, audio_stream );
- shuffle_set.erase( filename );
- continue;
- } catch ( prev_file & ) {
- shuffle_set.erase( filename );
- continue;
- } catch ( next_file & ) {
- shuffle_set.erase( filename );
- continue;
- } catch ( ... ) {
- throw;
- }
- }
- } else {
- std::vector<std::string>::iterator filename = flags.filenames.begin();
- while ( true ) {
- if ( filename == flags.filenames.end() ) {
- break;
- }
- try {
- flags.playlist_index = filename - flags.filenames.begin();
- render_file( flags, *filename, log, audio_stream );
- filename++;
- continue;
- } catch ( prev_file & e ) {
- while ( filename != flags.filenames.begin() && e.count ) {
- e.count--;
- --filename;
- }
- continue;
- } catch ( next_file & e ) {
- while ( filename != flags.filenames.end() && e.count ) {
- e.count--;
- ++filename;
- }
- continue;
- } catch ( ... ) {
- throw;
- }
- }
- }
- if ( !flags.restart ) {
- break;
- }
- }
- } catch ( ... ) {
- throw;
- }
- }
- static bool parse_playlist( commandlineflags & flags, std::string filename, std::ostream & log ) {
- log.flush();
- bool is_playlist = false;
- bool m3u8 = false;
- if ( ends_with( filename, ".m3u") || ends_with( filename, ".m3U") || ends_with( filename, ".M3u") || ends_with( filename, ".M3U") ) {
- is_playlist = true;
- }
- if ( ends_with( filename, ".m3u8") || ends_with( filename, ".m3U8") || ends_with( filename, ".M3u8") || ends_with( filename, ".M3U8") ) {
- is_playlist = true;
- m3u8 = true;
- }
- if ( ends_with( filename, ".pls") || ends_with( filename, ".plS") || ends_with( filename, ".pLs") || ends_with( filename, ".pLS") || ends_with( filename, ".Pls") || ends_with( filename, ".PlS") || ends_with( filename, ".PLs") || ends_with( filename, ".PLS") ) {
- is_playlist = true;
- }
- std::string basepath = get_basepath( filename );
- try {
- #if defined(WIN32) && defined(UNICODE) && !defined(_MSC_VER)
- std::istringstream file_stream;
- #else
- std::ifstream file_stream;
- #endif
- #if defined(WIN32) && defined(UNICODE) && !defined(_MSC_VER)
- // Only MSVC has std::ifstream::ifstream(std::wstring).
- // Fake it for other compilers using _wfopen().
- std::string data;
- FILE * f = _wfopen( mpt::transcode<std::wstring>( mpt::common_encoding::utf8, filename ).c_str(), L"rb" );
- if ( f ) {
- while ( !feof( f ) ) {
- static const std::size_t BUFFER_SIZE = 4096;
- char buffer[BUFFER_SIZE];
- size_t data_read = fread( buffer, 1, BUFFER_SIZE, f );
- std::copy( buffer, buffer + data_read, std::back_inserter( data ) );
- }
- fclose( f );
- f = NULL;
- }
- file_stream.str( data );
- #elif defined(_MSC_VER) && defined(UNICODE)
- file_stream.open( mpt::transcode<std::wstring>( mpt::common_encoding::utf8, filename ), std::ios::binary );
- #else
- file_stream.open( filename, std::ios::binary );
- #endif
- std::string line;
- bool first = true;
- bool extm3u = false;
- bool pls = false;
- while ( std::getline( file_stream, line ) ) {
- std::string newfile;
- line = trim_eol( line );
- if ( first ) {
- first = false;
- if ( line == "#EXTM3U" ) {
- extm3u = true;
- continue;
- } else if ( line == "[playlist]" ) {
- pls = true;
- }
- }
- if ( line.empty() ) {
- continue;
- }
- if ( pls ) {
- if ( begins_with( line, "File" ) ) {
- if ( line.find( "=" ) != std::string::npos ) {
- flags.filenames.push_back( line.substr( line.find( "=" ) + 1 ) );
- }
- } else if ( begins_with( line, "Title" ) ) {
- continue;
- } else if ( begins_with( line, "Length" ) ) {
- continue;
- } else if ( begins_with( line, "NumberOfEntries" ) ) {
- continue;
- } else if ( begins_with( line, "Version" ) ) {
- continue;
- } else {
- continue;
- }
- } else if ( extm3u ) {
- if ( begins_with( line, "#EXTINF" ) ) {
- continue;
- } else if ( begins_with( line, "#" ) ) {
- continue;
- }
- if ( m3u8 ) {
- newfile = line;
- } else {
- #if defined(WIN32)
- newfile = mpt::transcode<std::string>( mpt::common_encoding::utf8, mpt::logical_encoding::locale, line );
- #else
- newfile = line;
- #endif
- }
- } else {
- if ( m3u8 ) {
- newfile = line;
- } else {
- #if defined(WIN32)
- newfile = mpt::transcode<std::string>( mpt::common_encoding::utf8, mpt::logical_encoding::locale, line );
- #else
- newfile = line;
- #endif
- }
- }
- if ( !newfile.empty() ) {
- if ( !is_absolute( newfile ) ) {
- newfile = basepath + newfile;
- }
- flags.filenames.push_back( newfile );
- }
- }
- } catch ( std::exception & e ) {
- log << "error loading '" << filename << "': " << e.what() << std::endl;
- } catch ( ... ) {
- log << "unknown error loading '" << filename << "'" << std::endl;
- }
- log.flush();
- return is_playlist;
- }
- static commandlineflags parse_openmpt123( const std::vector<std::string> & args, std::ostream & log ) {
- log.flush();
- if ( args.size() <= 1 ) {
- throw args_error_exception();
- }
- commandlineflags flags;
- bool files_only = false;
- // cppcheck false-positive
- // cppcheck-suppress StlMissingComparison
- for ( auto 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 == "--help-keyboard" ) {
- throw show_help_keyboard_exception();
- } else if ( arg == "-q" || arg == "--quiet" ) {
- flags.quiet = true;
- } else if ( arg == "-v" || arg == "--verbose" ) {
- flags.verbose = true;
- } else if ( arg == "--man-version" ) {
- throw show_man_version_exception();
- } else if ( arg == "--man-help" ) {
- throw show_man_help_exception();
- } else if ( arg == "--version" ) {
- throw show_version_number_exception();
- } else if ( arg == "--short-version" ) {
- throw show_short_version_number_exception();
- } else if ( arg == "--long-version" ) {
- throw show_long_version_number_exception();
- } else if ( arg == "--credits" ) {
- throw show_credits_exception();
- } else if ( arg == "--license" ) {
- throw show_license_exception();
- } else if ( arg == "--probe" ) {
- flags.mode = Mode::Probe;
- } else if ( arg == "--info" ) {
- flags.mode = Mode::Info;
- } else if ( arg == "--ui" ) {
- flags.mode = Mode::UI;
- } else if ( arg == "--batch" ) {
- flags.mode = Mode::Batch;
- } else if ( arg == "--render" ) {
- flags.mode = Mode::Render;
- } else if ( arg == "--terminal-width" && nextarg != "" ) {
- std::istringstream istr( nextarg );
- istr >> flags.terminal_width;
- ++i;
- } else if ( arg == "--terminal-height" && nextarg != "" ) {
- std::istringstream istr( nextarg );
- istr >> flags.terminal_height;
- ++i;
- } else if ( arg == "--progress" ) {
- flags.show_progress = true;
- } else if ( arg == "--no-progress" ) {
- flags.show_progress = false;
- } else if ( arg == "--meters" ) {
- flags.show_meters = true;
- } else if ( arg == "--no-meters" ) {
- flags.show_meters = false;
- } else if ( arg == "--channel-meters" ) {
- flags.show_channel_meters = true;
- } else if ( arg == "--no-channel-meters" ) {
- flags.show_channel_meters = false;
- } else if ( arg == "--pattern" ) {
- flags.show_pattern = true;
- } else if ( arg == "--no-pattern" ) {
- flags.show_pattern = false;
- } else if ( arg == "--details" ) {
- flags.show_details = true;
- } else if ( arg == "--no-details" ) {
- flags.show_details = false;
- } else if ( arg == "--message" ) {
- flags.show_message = true;
- } else if ( arg == "--no-message" ) {
- flags.show_message = false;
- } else if ( arg == "--driver" && nextarg != "" ) {
- if ( false ) {
- // nothing
- } else if ( nextarg == "help" ) {
- std::ostringstream drivers;
- drivers << " Available drivers:" << std::endl;
- drivers << " " << "default" << std::endl;
- #if defined( MPT_WITH_PULSEAUDIO )
- drivers << " " << "pulseaudio" << std::endl;
- #endif
- #if defined( MPT_WITH_SDL2 )
- drivers << " " << "sdl2" << std::endl;
- #endif
- #if defined( MPT_WITH_PORTAUDIO )
- drivers << " " << "portaudio" << std::endl;
- #endif
- #if defined( WIN32 )
- drivers << " " << "waveout" << std::endl;
- #endif
- #if defined( MPT_WITH_ALLEGRO42 )
- drivers << " " << "allegro42" << std::endl;
- #endif
- throw show_help_exception( drivers.str() );
- } else if ( nextarg == "default" ) {
- flags.driver = "";
- } else {
- flags.driver = nextarg;
- }
- ++i;
- } else if ( arg == "--device" && nextarg != "" ) {
- if ( false ) {
- // nothing
- } else if ( nextarg == "help" ) {
- std::ostringstream devices;
- devices << " Available devices:" << std::endl;
- devices << " " << "default" << ": " << "default" << std::endl;
- #if defined( MPT_WITH_PULSEAUDIO )
- devices << show_pulseaudio_devices( log );
- #endif
- #if defined( MPT_WITH_SDL2 )
- devices << show_sdl2_devices( log );
- #endif
- #if defined( MPT_WITH_PORTAUDIO )
- devices << show_portaudio_devices( log );
- #endif
- #if defined( WIN32 )
- devices << show_waveout_devices( log );
- #endif
- #if defined( MPT_WITH_ALLEGRO42 )
- devices << show_allegro42_devices( log );
- #endif
- throw show_help_exception( devices.str() );
- } else if ( nextarg == "default" ) {
- flags.device = "";
- } else {
- flags.device = nextarg;
- }
- ++i;
- } else if ( arg == "--buffer" && nextarg != "" ) {
- std::istringstream istr( nextarg );
- istr >> flags.buffer;
- ++i;
- } else if ( arg == "--period" && nextarg != "" ) {
- std::istringstream istr( nextarg );
- istr >> flags.period;
- ++i;
- } else if ( arg == "--update" && nextarg != "" ) {
- std::istringstream istr( nextarg );
- istr >> flags.ui_redraw_interval;
- ++i;
- } else if ( arg == "--stdout" ) {
- flags.use_stdout = true;
- } else if ( ( arg == "-o" || arg == "--output" ) && nextarg != "" ) {
- flags.output_filename = nextarg;
- ++i;
- } else if ( arg == "--force" ) {
- flags.force_overwrite = true;
- } else if ( arg == "--output-type" && nextarg != "" ) {
- flags.output_extension = nextarg;
- ++i;
- } else if ( arg == "--samplerate" && nextarg != "" ) {
- std::istringstream istr( nextarg );
- istr >> flags.samplerate;
- ++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 == "--gain" && nextarg != "" ) {
- std::istringstream istr( nextarg );
- double gain = 0.0;
- istr >> gain;
- flags.gain = static_cast<std::int32_t>( gain * 100.0 );
- ++i;
- } else if ( arg == "--stereo" && nextarg != "" ) {
- std::istringstream istr( nextarg );
- istr >> flags.separation;
- ++i;
- } else if ( arg == "--filter" && nextarg != "" ) {
- std::istringstream istr( nextarg );
- istr >> flags.filtertaps;
- ++i;
- } else if ( arg == "--ramping" && nextarg != "" ) {
- std::istringstream istr( nextarg );
- istr >> flags.ramping;
- ++i;
- } else if ( arg == "--tempo" && nextarg != "" ) {
- std::istringstream istr( nextarg );
- double tmp = 1.0;
- istr >> tmp;
- flags.tempo = double_to_tempo_flag( tmp );
- ++i;
- } else if ( arg == "--pitch" && nextarg != "" ) {
- std::istringstream istr( nextarg );
- double tmp = 1.0;
- istr >> tmp;
- flags.pitch = double_to_pitch_flag( tmp );
- ++i;
- } else if ( arg == "--dither" && nextarg != "" ) {
- std::istringstream istr( nextarg );
- istr >> flags.dither;
- ++i;
- } else if ( arg == "--playlist" && nextarg != "" ) {
- parse_playlist( flags, nextarg, log );
- ++i;
- } else if ( arg == "--randomize" ) {
- flags.randomize = true;
- } else if ( arg == "--no-randomize" ) {
- flags.randomize = false;
- } else if ( arg == "--shuffle" ) {
- flags.shuffle = true;
- } else if ( arg == "--no-shuffle" ) {
- flags.shuffle = false;
- } else if ( arg == "--restart" ) {
- flags.restart = true;
- } else if ( arg == "--no-restart" ) {
- flags.restart = false;
- } else if ( arg == "--subsong" && nextarg != "" ) {
- std::istringstream istr( nextarg );
- istr >> flags.subsong;
- ++i;
- } else if ( arg == "--repeat" && nextarg != "" ) {
- std::istringstream istr( nextarg );
- istr >> flags.repeatcount;
- ++i;
- } else if ( arg == "--ctl" && nextarg != "" ) {
- std::istringstream istr( nextarg );
- std::string ctl_c_v;
- istr >> ctl_c_v;
- if ( ctl_c_v.find( "=" ) == std::string::npos ) {
- throw args_error_exception();
- }
- std::string ctl = ctl_c_v.substr( 0, ctl_c_v.find( "=" ) );
- std::string val = ctl_c_v.substr( ctl_c_v.find( "=" ) + std::string("=").length(), std::string::npos );
- if ( ctl.empty() ) {
- throw args_error_exception();
- }
- flags.ctls[ ctl ] = val;
- ++i;
- } else if ( arg == "--seek" && nextarg != "" ) {
- std::istringstream istr( nextarg );
- istr >> flags.seek_target;
- ++i;
- } else if ( arg == "--end-time" && nextarg != "" ) {
- std::istringstream istr( nextarg );
- istr >> flags.end_time;
- ++i;
- } else if ( arg.size() > 0 && arg.substr( 0, 1 ) == "-" ) {
- throw args_error_exception();
- }
- }
- }
- return flags;
- }
- #if defined(WIN32)
- class FD_utf8_raii {
- private:
- FILE * file;
- int old_mode;
- public:
- FD_utf8_raii( FILE * file, bool set_utf8 )
- : file(file)
- , old_mode(-1)
- {
- if ( set_utf8 ) {
- fflush( file );
- #if defined(UNICODE)
- old_mode = _setmode( _fileno( file ), _O_U8TEXT );
- #else
- old_mode = _setmode( _fileno( file ), _O_TEXT );
- #endif
- if ( old_mode == -1 ) {
- throw exception( "failed to set TEXT mode on file descriptor" );
- }
- }
- }
- ~FD_utf8_raii()
- {
- if ( old_mode != -1 ) {
- fflush( file );
- old_mode = _setmode( _fileno( file ), old_mode );
- }
- }
- };
- class FD_binary_raii {
- private:
- FILE * file;
- int old_mode;
- public:
- FD_binary_raii( FILE * file, bool set_binary )
- : file(file)
- , old_mode(-1)
- {
- if ( set_binary ) {
- fflush( file );
- old_mode = _setmode( _fileno( file ), _O_BINARY );
- if ( old_mode == -1 ) {
- throw exception( "failed to set binary mode on file descriptor" );
- }
- }
- }
- ~FD_binary_raii()
- {
- if ( old_mode != -1 ) {
- fflush( file );
- old_mode = _setmode( _fileno( file ), old_mode );
- }
- }
- };
- #endif
- #if defined(WIN32) && defined(UNICODE)
- static int wmain( int wargc, wchar_t * wargv [] ) {
- #else
- static int main( int argc, char * argv [] ) {
- #endif
- std::vector<std::string> args;
- #if defined(WIN32) && defined(UNICODE)
- for ( int arg = 0; arg < wargc; ++arg ) {
- args.push_back( mpt::transcode<std::string>( mpt::common_encoding::utf8, wargv[arg] ) );
- }
- #else
- args = std::vector<std::string>( argv, argv + argc );
- #endif
- #if defined(WIN32)
- FD_utf8_raii stdin_utf8_guard( stdin, true );
- FD_utf8_raii stdout_utf8_guard( stdout, true );
- FD_utf8_raii stderr_utf8_guard( stderr, true );
- #endif
- textout_dummy dummy_log;
- #if defined(WIN32)
- #if defined(UNICODE)
- textout_ostream_console std_out( std::wcout, STD_OUTPUT_HANDLE );
- textout_ostream_console std_err( std::wclog, STD_ERROR_HANDLE );
- #else
- textout_ostream_console std_out( std::cout, STD_OUTPUT_HANDLE );
- textout_ostream_console std_err( std::clog, STD_ERROR_HANDLE );
- #endif
- #else
- textout_ostream std_out( std::cout );
- textout_ostream std_err( std::clog );
- #endif
- commandlineflags flags;
- try {
- flags = parse_openmpt123( args, std::cerr );
- flags.check_and_sanitize();
- } catch ( args_error_exception & ) {
- show_help( std_out );
- return 1;
- } catch ( show_man_help_exception & ) {
- show_help( std_out, false, true, true );
- return 0;
- } catch ( show_man_version_exception & ) {
- show_man_version( std_out );
- return 0;
- } catch ( show_help_exception & e ) {
- show_help( std_out, true, e.longhelp, false, e.message );
- if ( flags.verbose ) {
- show_credits( std_out );
- }
- return 0;
- } catch ( show_help_keyboard_exception & ) {
- show_help_keyboard( std_out );
- return 0;
- } catch ( show_long_version_number_exception & ) {
- show_long_version( std_out );
- return 0;
- } catch ( show_version_number_exception & ) {
- show_version( std_out );
- return 0;
- } catch ( show_short_version_number_exception & ) {
- show_short_version( std_out );
- return 0;
- } catch ( show_credits_exception & ) {
- show_credits( std_out );
- return 0;
- } catch ( show_license_exception & ) {
- show_license( std_out );
- return 0;
- } catch ( silent_exit_exception & ) {
- return 0;
- } catch ( std::exception & e ) {
- std_err << "error: " << e.what() << std::endl;
- std_err.writeout();
- return 1;
- } catch ( ... ) {
- std_err << "unknown error" << std::endl;
- std_err.writeout();
- return 1;
- }
- try {
- bool stdin_can_ui = true;
- for ( const auto & filename : flags.filenames ) {
- if ( filename == "-" ) {
- stdin_can_ui = false;
- break;
- }
- }
- bool stdout_can_ui = true;
- if ( flags.use_stdout ) {
- stdout_can_ui = false;
- }
- // set stdin binary
- #if defined(WIN32)
- FD_binary_raii stdin_guard( stdin, !stdin_can_ui );
- #endif
- // set stdout binary
- #if defined(WIN32)
- FD_binary_raii stdout_guard( stdout, !stdout_can_ui );
- #endif
- // setup terminal
- #if !defined(WIN32)
- if ( stdin_can_ui ) {
- if ( flags.mode == Mode::UI ) {
- set_input_mode();
- }
- }
- #endif
-
- textout & log = flags.quiet ? static_cast<textout&>( dummy_log ) : static_cast<textout&>( stdout_can_ui ? std_out : std_err );
- show_info( log, flags.verbose );
- if ( !flags.warnings.empty() ) {
- log << flags.warnings << std::endl;
- }
- if ( flags.verbose ) {
- log << flags;
- }
- log.writeout();
- std::default_random_engine prng;
- try {
- std::random_device rd;
- std::seed_seq seq{ rd(), static_cast<unsigned int>( std::time( NULL ) ) };
- prng = std::default_random_engine{ seq };
- } catch ( const std::exception & ) {
- std::seed_seq seq{ static_cast<unsigned int>( std::time( NULL ) ) };
- prng = std::default_random_engine{ seq };
- }
- std::srand( std::uniform_int_distribution<unsigned int>()( prng ) );
- switch ( flags.mode ) {
- case Mode::Probe: {
- for ( const auto & filename : flags.filenames ) {
- probe_file( flags, filename, log );
- flags.playlist_index++;
- }
- } break;
- case Mode::Info: {
- void_audio_stream dummy;
- render_files( flags, log, dummy, prng );
- } break;
- case Mode::UI:
- case Mode::Batch: {
- if ( flags.use_stdout ) {
- flags.apply_default_buffer_sizes();
- stdout_stream_raii stdout_audio_stream;
- render_files( flags, log, stdout_audio_stream, prng );
- } else if ( !flags.output_filename.empty() ) {
- flags.apply_default_buffer_sizes();
- file_audio_stream_raii file_audio_stream( flags, flags.output_filename, log );
- render_files( flags, log, file_audio_stream, prng );
- #if defined( MPT_WITH_PULSEAUDIO )
- } else if ( flags.driver == "pulseaudio" || flags.driver.empty() ) {
- pulseaudio_stream_raii pulseaudio_stream( flags, log );
- render_files( flags, log, pulseaudio_stream, prng );
- #endif
- #if defined( MPT_WITH_SDL2 )
- } else if ( flags.driver == "sdl2" || flags.driver.empty() ) {
- sdl2_stream_raii sdl2_stream( flags, log );
- render_files( flags, log, sdl2_stream, prng );
- #endif
- #if defined( MPT_WITH_PORTAUDIO )
- } else if ( flags.driver == "portaudio" || flags.driver.empty() ) {
- portaudio_stream_raii portaudio_stream( flags, log );
- render_files( flags, log, portaudio_stream, prng );
- #endif
- #if defined( WIN32 )
- } else if ( flags.driver == "waveout" || flags.driver.empty() ) {
- waveout_stream_raii waveout_stream( flags );
- render_files( flags, log, waveout_stream, prng );
- #endif
- #if defined( MPT_WITH_ALLEGRO42 )
- } else if ( flags.driver == "allegro42" || flags.driver.empty() ) {
- allegro42_stream_raii allegro42_stream( flags, log );
- render_files( flags, log, allegro42_stream, prng );
- #endif
- } else {
- if ( flags.driver.empty() ) {
- throw exception( "openmpt123 is compiled without any audio driver" );
- } else {
- throw exception( "audio driver '" + flags.driver + "' not found" );
- }
- }
- } break;
- case Mode::Render: {
- for ( const auto & filename : flags.filenames ) {
- flags.apply_default_buffer_sizes();
- file_audio_stream_raii file_audio_stream( flags, filename + std::string(".") + flags.output_extension, log );
- render_file( flags, filename, log, file_audio_stream );
- flags.playlist_index++;
- }
- } break;
- case Mode::None:
- break;
- }
- } catch ( args_error_exception & ) {
- show_help( std_out );
- return 1;
- #ifdef MPT_WITH_ALLEGRO42
- } catch ( allegro42_exception & e ) {
- std_err << "Allegro-4.2 error: " << e.what() << std::endl;
- std_err.writeout();
- return 1;
- #endif
- #ifdef MPT_WITH_PULSEAUDIO
- } catch ( pulseaudio_exception & e ) {
- std_err << "PulseAudio error: " << e.what() << std::endl;
- std_err.writeout();
- return 1;
- #endif
- #ifdef MPT_WITH_PORTAUDIO
- } catch ( portaudio_exception & e ) {
- std_err << "PortAudio error: " << e.what() << std::endl;
- std_err.writeout();
- return 1;
- #endif
- #ifdef MPT_WITH_SDL2
- } catch ( sdl2_exception & e ) {
- std_err << "SDL2 error: " << e.what() << std::endl;
- std_err.writeout();
- return 1;
- #endif
- } catch ( silent_exit_exception & ) {
- return 0;
- } catch ( std::exception & e ) {
- std_err << "error: " << e.what() << std::endl;
- std_err.writeout();
- return 1;
- } catch ( ... ) {
- std_err << "unknown error" << std::endl;
- std_err.writeout();
- return 1;
- }
- return 0;
- }
- } // namespace openmpt123
- #if defined(WIN32) && defined(UNICODE)
- #if defined(__GNUC__) || (defined(__clang__) && !defined(_MSC_VER))
- // mingw64 does only default to special C linkage for "main", but not for "wmain".
- extern "C" int wmain( int wargc, wchar_t * wargv [] );
- extern "C"
- #endif
- int wmain( int wargc, wchar_t * wargv [] ) {
- return openmpt123::wmain( wargc, wargv );
- }
- #else
- int main( int argc, char * argv [] ) {
- return openmpt123::main( argc, argv );
- }
- #endif
|