aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/openmpt123/openmpt123.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/openmpt123/openmpt123.hpp')
-rw-r--r--Src/external_dependencies/openmpt-trunk/openmpt123/openmpt123.hpp726
1 files changed, 726 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/openmpt123/openmpt123.hpp b/Src/external_dependencies/openmpt-trunk/openmpt123/openmpt123.hpp
new file mode 100644
index 00000000..878359aa
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/openmpt123/openmpt123.hpp
@@ -0,0 +1,726 @@
+/*
+ * openmpt123.hpp
+ * --------------
+ * 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.
+ */
+
+#ifndef OPENMPT123_HPP
+#define OPENMPT123_HPP
+
+#include "openmpt123_config.hpp"
+
+#include "mpt/base/compiletime_warning.hpp"
+#include "mpt/base/floatingpoint.hpp"
+#include "mpt/base/preprocessor.hpp"
+#include "mpt/string_transcode/transcode.hpp"
+
+#include <string>
+
+namespace openmpt123 {
+
+struct exception : public openmpt::exception {
+ exception( const std::string & text ) : openmpt::exception(text) { }
+};
+
+struct show_help_exception {
+ std::string message;
+ bool longhelp;
+ show_help_exception( const std::string & msg = "", bool longhelp_ = true ) : message(msg), longhelp(longhelp_) { }
+};
+
+struct args_error_exception {
+ args_error_exception() { }
+};
+
+struct show_help_keyboard_exception { };
+
+#if defined(WIN32)
+bool IsConsole( DWORD stdHandle );
+#endif
+bool IsTerminal( int fd );
+
+
+
+struct field {
+ std::string key;
+ std::string val;
+ field( const std::string & key )
+ : key(key)
+ {
+ return;
+ }
+};
+
+class textout : public std::ostringstream {
+public:
+ textout() {
+ return;
+ }
+ virtual ~textout() {
+ return;
+ }
+protected:
+ std::string pop() {
+ std::string text = str();
+ str(std::string());
+ return text;
+ }
+public:
+ virtual void writeout() = 0;
+ virtual void cursor_up( std::size_t lines ) {
+ static_cast<void>( lines );
+ }
+};
+
+class textout_dummy : public textout {
+public:
+ textout_dummy() {
+ return;
+ }
+ virtual ~textout_dummy() {
+ return;
+ }
+public:
+ void writeout() override {
+ static_cast<void>( pop() );
+ }
+};
+
+class textout_ostream : public textout {
+private:
+ std::ostream & s;
+#if defined(__DJGPP__)
+ mpt::common_encoding codepage;
+#endif
+public:
+ textout_ostream( std::ostream & s_ )
+ : s(s_)
+#if defined(__DJGPP__)
+ , codepage(mpt::common_encoding::cp437)
+#endif
+ {
+ #if defined(__DJGPP__)
+ codepage = mpt::djgpp_get_locale_encoding();
+ #endif
+ return;
+ }
+ virtual ~textout_ostream() {
+ writeout_impl();
+ }
+private:
+ void writeout_impl() {
+ std::string text = pop();
+ if ( text.length() > 0 ) {
+ #if defined(__DJGPP__)
+ s << mpt::transcode<std::string>( codepage, mpt::common_encoding::utf8, text );
+ #elif defined(__EMSCRIPTEN__)
+ s << text;
+ #else
+ s << mpt::transcode<std::string>( mpt::logical_encoding::locale, mpt::common_encoding::utf8, text );
+ #endif
+ s.flush();
+ }
+ }
+public:
+ void writeout() override {
+ writeout_impl();
+ }
+ void cursor_up( std::size_t lines ) override {
+ s.flush();
+ for ( std::size_t line = 0; line < lines; ++line ) {
+ *this << "\x1b[1A";
+ }
+ }
+};
+
+#if defined(WIN32)
+
+class textout_ostream_console : public textout {
+private:
+#if defined(UNICODE)
+ std::wostream & s;
+#else
+ std::ostream & s;
+#endif
+ HANDLE handle;
+ bool console;
+public:
+#if defined(UNICODE)
+ textout_ostream_console( std::wostream & s_, DWORD stdHandle_ )
+#else
+ textout_ostream_console( std::ostream & s_, DWORD stdHandle_ )
+#endif
+ : s(s_)
+ , handle(GetStdHandle( stdHandle_ ))
+ , console(IsConsole( stdHandle_ ))
+ {
+ return;
+ }
+ virtual ~textout_ostream_console() {
+ writeout_impl();
+ }
+private:
+ void writeout_impl() {
+ std::string text = pop();
+ if ( text.length() > 0 ) {
+ if ( console ) {
+ #if defined(UNICODE)
+ std::wstring wtext = mpt::transcode<std::wstring>( mpt::common_encoding::utf8, text );
+ WriteConsole( handle, wtext.data(), static_cast<DWORD>( wtext.size() ), NULL, NULL );
+ #else
+ std::string ltext = mpt::transcode<std::string>( mpt::logical_encoding::locale, mpt::common_encoding::utf8, text );
+ WriteConsole( handle, ltext.data(), static_cast<DWORD>( ltext.size() ), NULL, NULL );
+ #endif
+ } else {
+ #if defined(UNICODE)
+ s << mpt::transcode<std::wstring>( mpt::common_encoding::utf8, text );
+ #else
+ s << mpt::transcode<std::string>( mpt::logical_encoding::locale, mpt::common_encoding::utf8, text );
+ #endif
+ s.flush();
+ }
+ }
+ }
+public:
+ void writeout() override {
+ writeout_impl();
+ }
+ void cursor_up( std::size_t lines ) override {
+ if ( console ) {
+ s.flush();
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ ZeroMemory( &csbi, sizeof( CONSOLE_SCREEN_BUFFER_INFO ) );
+ COORD coord_cursor = COORD();
+ if ( GetConsoleScreenBufferInfo( handle, &csbi ) != FALSE ) {
+ coord_cursor = csbi.dwCursorPosition;
+ coord_cursor.X = 1;
+ coord_cursor.Y -= static_cast<SHORT>( lines );
+ SetConsoleCursorPosition( handle, coord_cursor );
+ }
+ }
+ }
+};
+
+#endif // WIN32
+
+static inline float mpt_round( float val ) {
+ if ( val >= 0.0f ) {
+ return std::floor( val + 0.5f );
+ } else {
+ return std::ceil( val - 0.5f );
+ }
+}
+
+static inline long mpt_lround( float val ) {
+ return static_cast< long >( mpt_round( val ) );
+}
+
+static inline std::string append_software_tag( std::string software ) {
+ std::string openmpt123 = std::string() + "openmpt123 " + OPENMPT123_VERSION_STRING + " (libopenmpt " + openmpt::string::get( "library_version" ) + ", OpenMPT " + openmpt::string::get( "core_version" ) + ")";
+ if ( software.empty() ) {
+ software = openmpt123;
+ } else {
+ software += " (via " + openmpt123 + ")";
+ }
+ return software;
+}
+
+static inline std::string get_encoder_tag() {
+ return std::string() + "openmpt123 " + OPENMPT123_VERSION_STRING + " (libopenmpt " + openmpt::string::get( "library_version" ) + ", OpenMPT " + openmpt::string::get( "core_version" ) + ")";
+}
+
+static inline std::string get_extension( std::string filename ) {
+ if ( filename.find_last_of( "." ) != std::string::npos ) {
+ return filename.substr( filename.find_last_of( "." ) + 1 );
+ }
+ return "";
+}
+
+enum class Mode {
+ None,
+ Probe,
+ Info,
+ UI,
+ Batch,
+ Render
+};
+
+static inline std::string mode_to_string( Mode mode ) {
+ switch ( mode ) {
+ case Mode::None: return "none"; break;
+ case Mode::Probe: return "probe"; break;
+ case Mode::Info: return "info"; break;
+ case Mode::UI: return "ui"; break;
+ case Mode::Batch: return "batch"; break;
+ case Mode::Render: return "render"; break;
+ }
+ return "";
+}
+
+static const std::int32_t default_low = -2;
+static const std::int32_t default_high = -1;
+
+struct commandlineflags {
+ Mode mode;
+ bool canUI;
+ std::int32_t ui_redraw_interval;
+ bool canProgress;
+ std::string driver;
+ std::string device;
+ std::int32_t buffer;
+ std::int32_t period;
+ std::int32_t samplerate;
+ std::int32_t channels;
+ std::int32_t gain;
+ std::int32_t separation;
+ std::int32_t filtertaps;
+ std::int32_t ramping; // ramping strength : -1:default 0:off 1 2 3 4 5 // roughly milliseconds
+ std::int32_t tempo;
+ std::int32_t pitch;
+ std::int32_t dither;
+ std::int32_t repeatcount;
+ std::int32_t subsong;
+ std::map<std::string, std::string> ctls;
+ double seek_target;
+ double end_time;
+ bool quiet;
+ bool verbose;
+ int terminal_width;
+ int terminal_height;
+ bool show_details;
+ bool show_message;
+ bool show_ui;
+ bool show_progress;
+ bool show_meters;
+ bool show_channel_meters;
+ bool show_pattern;
+ bool use_float;
+ bool use_stdout;
+ bool randomize;
+ bool shuffle;
+ bool restart;
+ std::size_t playlist_index;
+ std::vector<std::string> filenames;
+ std::string output_filename;
+ std::string output_extension;
+ bool force_overwrite;
+ bool paused;
+ std::string warnings;
+ void apply_default_buffer_sizes() {
+ if ( ui_redraw_interval == default_high ) {
+ ui_redraw_interval = 50;
+ } else if ( ui_redraw_interval == default_low ) {
+ ui_redraw_interval = 10;
+ }
+ if ( buffer == default_high ) {
+ buffer = 250;
+ } else if ( buffer == default_low ) {
+ buffer = 50;
+ }
+ if ( period == default_high ) {
+ period = 50;
+ } else if ( period == default_low ) {
+ period = 10;
+ }
+ }
+ commandlineflags() {
+ mode = Mode::UI;
+ ui_redraw_interval = default_high;
+ driver = "";
+ device = "";
+ buffer = default_high;
+ period = default_high;
+#if defined(__DJGPP__)
+ samplerate = 44100;
+ channels = 2;
+ use_float = false;
+#else
+ samplerate = 48000;
+ channels = 2;
+ use_float = mpt::float_traits<float>::is_hard && mpt::float_traits<float>::is_ieee754_binary;
+#endif
+ gain = 0;
+ separation = 100;
+ filtertaps = 8;
+ ramping = -1;
+ tempo = 0;
+ pitch = 0;
+ dither = 1;
+ repeatcount = 0;
+ subsong = -1;
+ seek_target = 0.0;
+ end_time = 0.0;
+ quiet = false;
+ verbose = false;
+#if defined(__DJGPP__)
+ terminal_width = 80;
+ terminal_height = 25;
+#else
+ terminal_width = 72;
+ terminal_height = 23;
+#endif
+#if defined(WIN32)
+ terminal_width = 72;
+ terminal_height = 23;
+ HANDLE hStdOutput = GetStdHandle( STD_OUTPUT_HANDLE );
+ if ( ( hStdOutput != NULL ) && ( hStdOutput != INVALID_HANDLE_VALUE ) ) {
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ ZeroMemory( &csbi, sizeof( CONSOLE_SCREEN_BUFFER_INFO ) );
+ if ( GetConsoleScreenBufferInfo( hStdOutput, &csbi ) != FALSE ) {
+ terminal_width = std::min( static_cast<int>( 1 + csbi.srWindow.Right - csbi.srWindow.Left ), static_cast<int>( csbi.dwSize.X ) );
+ terminal_height = std::min( static_cast<int>( 1 + csbi.srWindow.Bottom - csbi.srWindow.Top ), static_cast<int>( csbi.dwSize.Y ) );
+ }
+ }
+#else // WIN32
+ if ( isatty( STDERR_FILENO ) ) {
+ const char * env_columns = std::getenv( "COLUMNS" );
+ if ( env_columns ) {
+ std::istringstream istr( env_columns );
+ int tmp = 0;
+ istr >> tmp;
+ if ( tmp > 0 ) {
+ terminal_width = tmp;
+ }
+ }
+ const char * env_rows = std::getenv( "ROWS" );
+ if ( env_rows ) {
+ std::istringstream istr( env_rows );
+ int tmp = 0;
+ istr >> tmp;
+ if ( tmp > 0 ) {
+ terminal_height = tmp;
+ }
+ }
+ #if defined(TIOCGWINSZ)
+ struct winsize ts;
+ if ( ioctl( STDERR_FILENO, TIOCGWINSZ, &ts ) >= 0 ) {
+ terminal_width = ts.ws_col;
+ terminal_height = ts.ws_row;
+ }
+ #elif defined(TIOCGSIZE)
+ struct ttysize ts;
+ if ( ioctl( STDERR_FILENO, TIOCGSIZE, &ts ) >= 0 ) {
+ terminal_width = ts.ts_cols;
+ terminal_height = ts.ts_rows;
+ }
+ #endif
+ }
+#endif
+ show_details = true;
+ show_message = false;
+#if defined(WIN32)
+ canUI = IsTerminal( 0 ) ? true : false;
+ canProgress = IsTerminal( 2 ) ? true : false;
+#else // !WIN32
+ canUI = isatty( STDIN_FILENO ) ? true : false;
+ canProgress = isatty( STDERR_FILENO ) ? true : false;
+#endif // WIN32
+ show_ui = canUI;
+ show_progress = canProgress;
+ show_meters = canUI && canProgress;
+ show_channel_meters = false;
+ show_pattern = false;
+ use_stdout = false;
+ randomize = false;
+ shuffle = false;
+ restart = false;
+ playlist_index = 0;
+ output_extension = "auto";
+ force_overwrite = false;
+ paused = false;
+ }
+ void check_and_sanitize() {
+ if ( filenames.size() == 0 ) {
+ throw args_error_exception();
+ }
+ if ( use_stdout && ( device != commandlineflags().device || !output_filename.empty() ) ) {
+ throw args_error_exception();
+ }
+ if ( !output_filename.empty() && ( device != commandlineflags().device || use_stdout ) ) {
+ throw args_error_exception();
+ }
+ for ( const auto & filename : filenames ) {
+ if ( filename == "-" ) {
+ canUI = false;
+ }
+ }
+ show_ui = canUI;
+ if ( mode == Mode::None ) {
+ if ( canUI ) {
+ mode = Mode::UI;
+ } else {
+ mode = Mode::Batch;
+ }
+ }
+ if ( mode == Mode::UI && !canUI ) {
+ throw args_error_exception();
+ }
+ if ( show_progress && !canProgress ) {
+ throw args_error_exception();
+ }
+ switch ( mode ) {
+ case Mode::None:
+ throw args_error_exception();
+ break;
+ case Mode::Probe:
+ show_ui = false;
+ show_progress = false;
+ show_meters = false;
+ show_channel_meters = false;
+ show_pattern = false;
+ break;
+ case Mode::Info:
+ show_ui = false;
+ show_progress = false;
+ show_meters = false;
+ show_channel_meters = false;
+ show_pattern = false;
+ break;
+ case Mode::UI:
+ break;
+ case Mode::Batch:
+ show_meters = false;
+ show_channel_meters = false;
+ show_pattern = false;
+ break;
+ case Mode::Render:
+ show_meters = false;
+ show_channel_meters = false;
+ show_pattern = false;
+ show_ui = false;
+ break;
+ }
+ if ( quiet ) {
+ verbose = false;
+ show_ui = false;
+ show_details = false;
+ show_progress = false;
+ show_channel_meters = false;
+ }
+ if ( verbose ) {
+ show_details = true;
+ }
+ if ( channels != 1 && channels != 2 && channels != 4 ) {
+ channels = commandlineflags().channels;
+ }
+ if ( samplerate < 0 ) {
+ samplerate = commandlineflags().samplerate;
+ }
+ if ( output_extension == "auto" ) {
+ output_extension = "";
+ }
+ if ( mode != Mode::Render && !output_extension.empty() ) {
+ throw args_error_exception();
+ }
+ if ( mode == Mode::Render && !output_filename.empty() ) {
+ throw args_error_exception();
+ }
+ if ( mode != Mode::Render && !output_filename.empty() ) {
+ output_extension = get_extension( output_filename );
+ }
+ if ( output_extension.empty() ) {
+ output_extension = "wav";
+ }
+ }
+};
+
+template < typename Tsample > Tsample convert_sample_to( float val );
+template < > float convert_sample_to( float val ) {
+ return val;
+}
+template < > std::int16_t convert_sample_to( float val ) {
+ std::int32_t tmp = static_cast<std::int32_t>( val * 32768.0f );
+ tmp = std::min( tmp, std::int32_t( 32767 ) );
+ tmp = std::max( tmp, std::int32_t( -32768 ) );
+ return static_cast<std::int16_t>( tmp );
+}
+
+class write_buffers_interface {
+protected:
+ virtual ~write_buffers_interface() {
+ return;
+ }
+public:
+ virtual void write_metadata( std::map<std::string,std::string> metadata ) {
+ (void)metadata;
+ return;
+ }
+ virtual void write_updated_metadata( std::map<std::string,std::string> metadata ) {
+ (void)metadata;
+ return;
+ }
+ 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;
+ virtual bool pause() {
+ return false;
+ }
+ virtual bool unpause() {
+ return false;
+ }
+ virtual bool sleep( int /*ms*/ ) {
+ return false;
+ }
+ virtual bool is_dummy() const {
+ return false;
+ }
+};
+
+class write_buffers_polling_wrapper : public write_buffers_interface {
+protected:
+ std::size_t channels;
+ std::size_t sampleQueueMaxFrames;
+ std::deque<float> sampleQueue;
+protected:
+ virtual ~write_buffers_polling_wrapper() {
+ return;
+ }
+protected:
+ write_buffers_polling_wrapper( const commandlineflags & flags )
+ : channels(flags.channels)
+ , sampleQueueMaxFrames(0)
+ {
+ return;
+ }
+ void set_queue_size_frames( std::size_t frames ) {
+ sampleQueueMaxFrames = frames;
+ }
+ template < typename Tsample >
+ Tsample pop_queue() {
+ float val = 0.0f;
+ if ( !sampleQueue.empty() ) {
+ val = sampleQueue.front();
+ sampleQueue.pop_front();
+ }
+ return convert_sample_to<Tsample>( val );
+ }
+public:
+ void write( const std::vector<float*> buffers, std::size_t frames ) override {
+ for ( std::size_t frame = 0; frame < frames; ++frame ) {
+ for ( std::size_t channel = 0; channel < channels; ++channel ) {
+ sampleQueue.push_back( buffers[channel][frame] );
+ }
+ while ( sampleQueue.size() >= sampleQueueMaxFrames * channels ) {
+ while ( !forward_queue() ) {
+ sleep( 1 );
+ }
+ }
+ }
+ }
+ void write( const std::vector<std::int16_t*> buffers, std::size_t frames ) override {
+ for ( std::size_t frame = 0; frame < frames; ++frame ) {
+ for ( std::size_t channel = 0; channel < channels; ++channel ) {
+ sampleQueue.push_back( buffers[channel][frame] * (1.0f/32768.0f) );
+ }
+ while ( sampleQueue.size() >= sampleQueueMaxFrames * channels ) {
+ while ( !forward_queue() ) {
+ sleep( 1 );
+ }
+ }
+ }
+ }
+ virtual bool forward_queue() = 0;
+ bool sleep( int ms ) override = 0;
+};
+
+class write_buffers_polling_wrapper_int : public write_buffers_interface {
+protected:
+ std::size_t channels;
+ std::size_t sampleQueueMaxFrames;
+ std::deque<std::int16_t> sampleQueue;
+protected:
+ virtual ~write_buffers_polling_wrapper_int() {
+ return;
+ }
+protected:
+ write_buffers_polling_wrapper_int( const commandlineflags & flags )
+ : channels(flags.channels)
+ , sampleQueueMaxFrames(0)
+ {
+ return;
+ }
+ void set_queue_size_frames( std::size_t frames ) {
+ sampleQueueMaxFrames = frames;
+ }
+ std::int16_t pop_queue() {
+ std::int16_t val = 0;
+ if ( !sampleQueue.empty() ) {
+ val = sampleQueue.front();
+ sampleQueue.pop_front();
+ }
+ return val;
+ }
+public:
+ void write( const std::vector<float*> buffers, std::size_t frames ) override {
+ for ( std::size_t frame = 0; frame < frames; ++frame ) {
+ for ( std::size_t channel = 0; channel < channels; ++channel ) {
+ sampleQueue.push_back( convert_sample_to<std::int16_t>( buffers[channel][frame] ) );
+ }
+ while ( sampleQueue.size() >= sampleQueueMaxFrames * channels ) {
+ while ( !forward_queue() ) {
+ sleep( 1 );
+ }
+ }
+ }
+ }
+ void write( const std::vector<std::int16_t*> buffers, std::size_t frames ) override {
+ for ( std::size_t frame = 0; frame < frames; ++frame ) {
+ for ( std::size_t channel = 0; channel < channels; ++channel ) {
+ sampleQueue.push_back( buffers[channel][frame] );
+ }
+ while ( sampleQueue.size() >= sampleQueueMaxFrames * channels ) {
+ while ( !forward_queue() ) {
+ sleep( 1 );
+ }
+ }
+ }
+ }
+ virtual bool forward_queue() = 0;
+ bool sleep( int ms ) override = 0;
+};
+
+class void_audio_stream : public write_buffers_interface {
+public:
+ virtual ~void_audio_stream() {
+ return;
+ }
+public:
+ void write( const std::vector<float*> buffers, std::size_t frames ) override {
+ (void)buffers;
+ (void)frames;
+ }
+ void write( const std::vector<std::int16_t*> buffers, std::size_t frames ) override {
+ (void)buffers;
+ (void)frames;
+ }
+ bool is_dummy() const override {
+ return true;
+ }
+};
+
+class file_audio_stream_base : public write_buffers_interface {
+protected:
+ file_audio_stream_base() {
+ return;
+ }
+public:
+ void write_metadata( std::map<std::string,std::string> metadata ) override {
+ (void)metadata;
+ return;
+ }
+ void write_updated_metadata( std::map<std::string,std::string> metadata ) override {
+ (void)metadata;
+ return;
+ }
+ void write( const std::vector<float*> buffers, std::size_t frames ) override = 0;
+ void write( const std::vector<std::int16_t*> buffers, std::size_t frames ) override = 0;
+ virtual ~file_audio_stream_base() {
+ return;
+ }
+};
+
+} // namespace openmpt123
+
+#endif // OPENMPT123_HPP