Index: common/mptString.cpp =================================================================== --- common/mptString.cpp (revision 12197) +++ common/mptString.cpp (working copy) @@ -1793,6 +1793,28 @@ return a.length() < b.length() ? -1 : 1; } +int CompareNoCaseAscii(std::string_view a, std::string_view b) +{ + for(std::size_t i = 0; i < std::min(a.length(), b.length()); ++i) + { + unsigned char ac = static_cast(mpt::ToLowerCaseAscii(a[i])); + unsigned char bc = static_cast(mpt::ToLowerCaseAscii(b[i])); + if(ac != bc) + { + return ac < bc ? -1 : 1; + } else if(!ac && !bc) + { + return 0; + } + } + if(a.length() == b.length()) + { + return 0; + } + return a.length() < b.length() ? -1 : 1; +} + + #if defined(MODPLUG_TRACKER) mpt::ustring ToLowerCase(const mpt::ustring &s) Index: common/mptString.h =================================================================== --- common/mptString.h (revision 12197) +++ common/mptString.h (working copy) @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -525,6 +526,7 @@ int CompareNoCaseAscii(const char *a, const char *b, std::size_t n); int CompareNoCaseAscii(const std::string &a, const std::string &b); +int CompareNoCaseAscii(std::string_view a, std::string_view b); #if defined(MODPLUG_TRACKER) Index: common/stdafx.h =================================================================== --- common/stdafx.h (revision 12197) +++ common/stdafx.h (working copy) @@ -115,6 +115,7 @@ // // // +// // // Index: libopenmpt/dox/changelog.md =================================================================== --- libopenmpt/dox/changelog.md (revision 12197) +++ libopenmpt/dox/changelog.md (working copy) @@ -15,9 +15,9 @@ * [**Regression**] foo_openmpt: foo_openmpt is discontinued. Please use Kode54's fork foo_openmpt54: . - * [**Regression**] Support for client code using C++11 has been removed. C++14 - is now required to build libopenmpt client applications. - * [**Regression**] Support for building with C++11 and C++14 has been removed. + * [**Regression**] Support for client code using C++11 or C++ 14 has been + removed. C++17 is now required to build libopenmpt client applications. + * [**Regression**] Support for building with C++11 or C++14 has been removed. C++17 is now required to build libopenmpt. * [**Regression**] Support for Visual Studio 2015 has been removed. * [**Regression**] Support for GCC 4.8, 4.9, 5, 6 has been removed. Index: libopenmpt/dox/dependencies.md =================================================================== --- libopenmpt/dox/dependencies.md (revision 12197) +++ libopenmpt/dox/dependencies.md (working copy) @@ -48,8 +48,7 @@ * Required compilers to use libopenmpt: * Any **C89** / **C99** / **C11** compatible compiler should work with the C API as long as a **C99** compatible **stdint.h** is available. - * Any **C++14** / **C++17** compatible compiler should work with the C++ - API. + * Any **C++17** compatible compiler should work with the C++ API. * **J2B** support requires an inflate (deflate decompression) implementation: * **zlib** * **miniz** can be used internally if no zlib is available. Index: libopenmpt/libopenmpt.h =================================================================== --- libopenmpt/libopenmpt.h (revision 12197) +++ libopenmpt/libopenmpt.h (working copy) @@ -1396,21 +1396,21 @@ * \param mod The module handle to work on. * \return A semicolon-separated list containing all supported ctl keys. * \remarks Currently supported ctl values are: - * - load.skip_samples: Set to "1" to avoid loading samples into memory - * - load.skip_patterns: Set to "1" to avoid loading patterns into memory - * - load.skip_plugins: Set to "1" to avoid loading plugins - * - load.skip_subsongs_init: Set to "1" to avoid pre-initializing sub-songs. Skipping results in faster module loading but slower seeking. - * - seek.sync_samples: Set to "1" to sync sample playback when using openmpt_module_set_position_seconds or openmpt_module_set_position_order_row. - * - subsong: The current subsong. Setting it has identical semantics as openmpt_module_select_subsong(), getting it returns the currently selected subsong. - * - play.at_end: Chooses the behaviour when the end of song is reached: + * - load.skip_samples (boolean): Set to "1" to avoid loading samples into memory + * - load.skip_patterns (boolean): Set to "1" to avoid loading patterns into memory + * - load.skip_plugins (boolean): Set to "1" to avoid loading plugins + * - load.skip_subsongs_init (boolean): Set to "1" to avoid pre-initializing sub-songs. Skipping results in faster module loading but slower seeking. + * - seek.sync_samples (boolean): Set to "1" to sync sample playback when using openmpt_module_set_position_seconds or openmpt_module_set_position_order_row. + * - subsong (integer): The current subsong. Setting it has identical semantics as openmpt_module_select_subsong(), getting it returns the currently selected subsong. + * - play.at_end (text): Chooses the behaviour when the end of song is reached: * - "fadeout": Fades the module out for a short while. Subsequent reads after the fadeout will return 0 rendered frames. * - "continue": Returns 0 rendered frames when the song end is reached. Subsequent reads will continue playing from the song start or loop start. * - "stop": Returns 0 rendered frames when the song end is reached. Subsequent reads will return 0 rendered frames. - * - play.tempo_factor: Set a floating point tempo factor. "1.0" is the default tempo. - * - play.pitch_factor: Set a floating point pitch factor. "1.0" is the default pitch. - * - render.resampler.emulate_amiga: Set to "1" to enable the Amiga resampler for Amiga modules. This emulates the sound characteristics of the Paula chip and overrides the selected interpolation filter. Non-Amiga module formats are not affected by this setting. - * - render.opl.volume_factor: Set volume factor applied to synthesized OPL sounds, relative to the default OPL volume. - * - dither: Set the dither algorithm that is used for the 16 bit versions of openmpt_module_read. Supported values are: + * - play.tempo_factor (floatingpoint): Set a floating point tempo factor. "1.0" is the default tempo. + * - play.pitch_factor (floatingpoint): Set a floating point pitch factor. "1.0" is the default pitch. + * - render.resampler.emulate_amiga (boolean): Set to "1" to enable the Amiga resampler for Amiga modules. This emulates the sound characteristics of the Paula chip and overrides the selected interpolation filter. Non-Amiga module formats are not affected by this setting. + * - render.opl.volume_factor (floatingpoint): Set volume factor applied to synthesized OPL sounds, relative to the default OPL volume. + * - dither (integer): Set the dither algorithm that is used for the 16 bit versions of openmpt_module_read. Supported values are: * - 0: No dithering. * - 1: Default mode. Chosen by OpenMPT code, might change. * - 2: Rectangular, 0.5 bit depth, no noise shaping (original ModPlug Tracker). @@ -1417,6 +1417,7 @@ * - 3: Rectangular, 1 bit depth, simple 1st order noise shaping */ LIBOPENMPT_API const char * openmpt_module_get_ctls( openmpt_module * mod ); + /*! \brief Get current ctl value * * \param mod The module handle to work on. @@ -1423,8 +1424,46 @@ * \param ctl The ctl key whose value should be retrieved. * \return The associated ctl value, or NULL on failure. * \sa openmpt_module_get_ctls + * \deprecated Please use openmpt_module_ctl_get_boolean(), openmpt_module_ctl_get_integer(), openmpt_module_ctl_get_floatingpoint(), or openmpt_module_ctl_get_text(). */ -LIBOPENMPT_API const char * openmpt_module_ctl_get( openmpt_module * mod, const char * ctl ); +LIBOPENMPT_API LIBOPENMPT_DEPRECATED const char * openmpt_module_ctl_get( openmpt_module * mod, const char * ctl ); +/*! \brief Get current ctl boolean value + * + * \param mod The module handle to work on. + * \param ctl The ctl key whose value should be retrieved. + * \return The associated ctl value, or NULL on failure. + * \sa openmpt_module_get_ctls + * \since 0.5.0 + */ +LIBOPENMPT_API int openmpt_module_ctl_get_boolean( openmpt_module * mod, const char * ctl ); +/*! \brief Get current ctl integer value + * + * \param mod The module handle to work on. + * \param ctl The ctl key whose value should be retrieved. + * \return The associated ctl value, or NULL on failure. + * \sa openmpt_module_get_ctls + * \since 0.5.0 + */ +LIBOPENMPT_API int64_t openmpt_module_ctl_get_integer( openmpt_module * mod, const char * ctl ); +/*! \brief Get current ctl floatingpoint value + * + * \param mod The module handle to work on. + * \param ctl The ctl key whose value should be retrieved. + * \return The associated ctl value, or NULL on failure. + * \sa openmpt_module_get_ctls + * \since 0.5.0 + */ +LIBOPENMPT_API double openmpt_module_ctl_get_floatingpoint( openmpt_module * mod, const char * ctl ); +/*! \brief Get current ctl string value + * + * \param mod The module handle to work on. + * \param ctl The ctl key whose value should be retrieved. + * \return The associated ctl value, or NULL on failure. + * \sa openmpt_module_get_ctls + * \since 0.5.0 + */ +LIBOPENMPT_API const char * openmpt_module_ctl_get_text( openmpt_module * mod, const char * ctl ); + /*! \brief Set ctl value * * \param mod The module handle to work on. @@ -1432,8 +1471,49 @@ * \param value The value that should be set. * \return 1 if successful, 0 in case the value is not sensible (e.g. negative tempo factor) or the ctl is not recognized. * \sa openmpt_module_get_ctls + * \deprecated Please use openmpt_module_ctl_set_boolean(), openmpt_module_ctl_set_integer(), openmpt_module_ctl_set_floatingpoint(), or openmpt_module_ctl_set_text(). */ -LIBOPENMPT_API int openmpt_module_ctl_set( openmpt_module * mod, const char * ctl, const char * value ); +LIBOPENMPT_API LIBOPENMPT_DEPRECATED int openmpt_module_ctl_set( openmpt_module * mod, const char * ctl, const char * value ); +/*! \brief Set ctl boolean value + * + * \param mod The module handle to work on. + * \param ctl The ctl key whose value should be set. + * \param value The value that should be set. + * \return 1 if successful, 0 in case the value is not sensible (e.g. negative tempo factor) or the ctl is not recognized. + * \sa openmpt_module_get_ctls + * \since 0.5.0 + */ +LIBOPENMPT_API int openmpt_module_ctl_set_boolean( openmpt_module * mod, const char * ctl, int value ); +/*! \brief Set ctl integer value + * + * \param mod The module handle to work on. + * \param ctl The ctl key whose value should be set. + * \param value The value that should be set. + * \return 1 if successful, 0 in case the value is not sensible (e.g. negative tempo factor) or the ctl is not recognized. + * \sa openmpt_module_get_ctls + * \since 0.5.0 + */ +LIBOPENMPT_API int openmpt_module_ctl_set_integer( openmpt_module * mod, const char * ctl, int64_t value ); +/*! \brief Set ctl floatingpoint value + * + * \param mod The module handle to work on. + * \param ctl The ctl key whose value should be set. + * \param value The value that should be set. + * \return 1 if successful, 0 in case the value is not sensible (e.g. negative tempo factor) or the ctl is not recognized. + * \sa openmpt_module_get_ctls + * \since 0.5.0 + */ +LIBOPENMPT_API int openmpt_module_ctl_set_floatingpoint( openmpt_module * mod, const char * ctl, double value ); +/*! \brief Set ctl string value + * + * \param mod The module handle to work on. + * \param ctl The ctl key whose value should be set. + * \param value The value that should be set. + * \return 1 if successful, 0 in case the value is not sensible (e.g. negative tempo factor) or the ctl is not recognized. + * \sa openmpt_module_get_ctls + * \since 0.5.0 + */ +LIBOPENMPT_API int openmpt_module_ctl_set_text( openmpt_module * mod, const char * ctl, const char * value ); /* remember to add new functions to both C and C++ interfaces and to increase OPENMPT_API_VERSION_MINOR */ Index: libopenmpt/libopenmpt.hpp =================================================================== --- libopenmpt/libopenmpt.hpp (revision 12197) +++ libopenmpt/libopenmpt.hpp (working copy) @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -231,8 +232,16 @@ /*! \param extension file extension to query without a leading dot. The case is ignored. \return true if the extension is supported by libopenmpt, false otherwise. + \deprecated Please use openmpt::is_extension_supported2(). */ -LIBOPENMPT_CXX_API bool is_extension_supported( const std::string & extension ); +LIBOPENMPT_ATTR_DEPRECATED LIBOPENMPT_CXX_API bool is_extension_supported( const std::string & extension ); +//! Query whether a file extension is supported +/*! + \param extension file extension to query without a leading dot. The case is ignored. + \return true if the extension is supported by libopenmpt, false otherwise. + \since 0.5.0 +*/ +LIBOPENMPT_CXX_API bool is_extension_supported2( std::string_view extension ); //! Roughly scan the input stream to find out whether libopenmpt might be able to open it /*! @@ -962,21 +971,21 @@ /*! \return A vector containing all supported ctl keys. \remarks Currently supported ctl values are: - - load.skip_samples: Set to "1" to avoid loading samples into memory - - load.skip_patterns: Set to "1" to avoid loading patterns into memory - - load.skip_plugins: Set to "1" to avoid loading plugins - - load.skip_subsongs_init: Set to "1" to avoid pre-initializing sub-songs. Skipping results in faster module loading but slower seeking. - - seek.sync_samples: Set to "1" to sync sample playback when using openmpt::module::set_position_seconds or openmpt::module::set_position_order_row. - - subsong: The current subsong. Setting it has identical semantics as openmpt::module::select_subsong(), getting it returns the currently selected subsong. - - play.at_end: Chooses the behaviour when the end of song is reached: + - load.skip_samples (boolean): Set to "1" to avoid loading samples into memory + - load.skip_patterns (boolean): Set to "1" to avoid loading patterns into memory + - load.skip_plugins (boolean): Set to "1" to avoid loading plugins + - load.skip_subsongs_init (boolean): Set to "1" to avoid pre-initializing sub-songs. Skipping results in faster module loading but slower seeking. + - seek.sync_samples (boolean): Set to "1" to sync sample playback when using openmpt::module::set_position_seconds or openmpt::module::set_position_order_row. + - subsong (integer): The current subsong. Setting it has identical semantics as openmpt::module::select_subsong(), getting it returns the currently selected subsong. + - play.at_end (text): Chooses the behaviour when the end of song is reached: - "fadeout": Fades the module out for a short while. Subsequent reads after the fadeout will return 0 rendered frames. - "continue": Returns 0 rendered frames when the song end is reached. Subsequent reads will continue playing from the song start or loop start. - "stop": Returns 0 rendered frames when the song end is reached. Subsequent reads will return 0 rendered frames. - - play.tempo_factor: Set a floating point tempo factor. "1.0" is the default tempo. - - play.pitch_factor: Set a floating point pitch factor. "1.0" is the default pitch. - - render.resampler.emulate_amiga: Set to "1" to enable the Amiga resampler for Amiga modules. This emulates the sound characteristics of the Paula chip and overrides the selected interpolation filter. Non-Amiga module formats are not affected by this setting. - - render.opl.volume_factor: Set volume factor applied to synthesized OPL sounds, relative to the default OPL volume. - - dither: Set the dither algorithm that is used for the 16 bit versions of openmpt::module::read. Supported values are: + - play.tempo_factor (floatingpoint): Set a floating point tempo factor. "1.0" is the default tempo. + - play.pitch_factor (floatingpoint): Set a floating point pitch factor. "1.0" is the default pitch. + - render.resampler.emulate_amiga (boolean): Set to "1" to enable the Amiga resampler for Amiga modules. This emulates the sound characteristics of the Paula chip and overrides the selected interpolation filter. Non-Amiga module formats are not affected by this setting. + - render.opl.volume_factor (floatingpoint): Set volume factor applied to synthesized OPL sounds, relative to the default OPL volume. + - dither (integer): Set the dither algorithm that is used for the 16 bit versions of openmpt::module::read. Supported values are: - 0: No dithering. - 1: Default mode. Chosen by OpenMPT code, might change. - 2: Rectangular, 0.5 bit depth, no noise shaping (original ModPlug Tracker). @@ -991,8 +1000,42 @@ \param ctl The ctl key whose value should be retrieved. \return The associated ctl value. \sa openmpt::module::get_ctls + \deprecated Please use openmpt::module::ctl_get_boolean(), openmpt::module::ctl_get_integer(), openmpt::module::ctl_get_floatingpoint(), or openmpt::module::ctl_get_text(). */ - std::string ctl_get( const std::string & ctl ) const; + LIBOPENMPT_ATTR_DEPRECATED std::string ctl_get( const std::string & ctl ) const; + //! Get current ctl boolean value + /*! + \param ctl The ctl key whose value should be retrieved. + \return The associated ctl value. + \sa openmpt::module::get_ctls + \since 0.5.0 + */ + bool ctl_get_boolean( std::string_view ctl ) const; + //! Get current ctl integer value + /*! + \param ctl The ctl key whose value should be retrieved. + \return The associated ctl value. + \sa openmpt::module::get_ctls + \since 0.5.0 + */ + std::int64_t ctl_get_integer( std::string_view ctl ) const; + //! Get current ctl floatingpoint value + /*! + \param ctl The ctl key whose value should be retrieved. + \return The associated ctl value. + \sa openmpt::module::get_ctls + \since 0.5.0 + */ + double ctl_get_floatingpoint( std::string_view ctl ) const; + //! Get current ctl text value + /*! + \param ctl The ctl key whose value should be retrieved. + \return The associated ctl value. + \sa openmpt::module::get_ctls + \since 0.5.0 + */ + std::string ctl_get_text( std::string_view ctl ) const; + //! Set ctl value /*! \param ctl The ctl key whose value should be set. @@ -999,8 +1042,45 @@ \param value The value that should be set. \throws openmpt::exception Throws an exception derived from openmpt::exception in case the value is not sensible (e.g. negative tempo factor) or under the circumstances outlined in openmpt::module::get_ctls. \sa openmpt::module::get_ctls + \deprecated Please use openmpt::module::ctl_set_bool(), openmpt::module::ctl_set_int(), openmpt::module::ctl_set_float(), or openmpt::module::ctl_set_string(). */ - void ctl_set( const std::string & ctl, const std::string & value ); + LIBOPENMPT_ATTR_DEPRECATED void ctl_set( const std::string & ctl, const std::string & value ); + //! Set ctl boolean value + /*! + \param ctl The ctl key whose value should be set. + \param value The value that should be set. + \throws openmpt::exception Throws an exception derived from openmpt::exception in case the value is not sensible (e.g. negative tempo factor) or under the circumstances outlined in openmpt::module::get_ctls. + \sa openmpt::module::get_ctls + \since 0.5.0 + */ + void ctl_set_boolean( std::string_view ctl, bool value ); + //! Set ctl integer value + /*! + \param ctl The ctl key whose value should be set. + \param value The value that should be set. + \throws openmpt::exception Throws an exception derived from openmpt::exception in case the value is not sensible (e.g. negative tempo factor) or under the circumstances outlined in openmpt::module::get_ctls. + \sa openmpt::module::get_ctls + \since 0.5.0 + */ + void ctl_set_integer( std::string_view ctl, std::int64_t value ); + //! Set ctl floatingpoint value + /*! + \param ctl The ctl key whose value should be set. + \param value The value that should be set. + \throws openmpt::exception Throws an exception derived from openmpt::exception in case the value is not sensible (e.g. negative tempo factor) or under the circumstances outlined in openmpt::module::get_ctls. + \sa openmpt::module::get_ctls + \since 0.5.0 + */ + void ctl_set_floatingpoint( std::string_view ctl, double value ); + //! Set ctl text value + /*! + \param ctl The ctl key whose value should be set. + \param value The value that should be set. + \throws openmpt::exception Throws an exception derived from openmpt::exception in case the value is not sensible (e.g. negative tempo factor) or under the circumstances outlined in openmpt::module::get_ctls. + \sa openmpt::module::get_ctls + \since 0.5.0 + */ + void ctl_set_text( std::string_view ctl, std::string_view value ); // remember to add new functions to both C and C++ interfaces and to increase OPENMPT_API_VERSION_MINOR Index: libopenmpt/libopenmpt_c.cpp =================================================================== --- libopenmpt/libopenmpt_c.cpp (revision 12197) +++ libopenmpt/libopenmpt_c.cpp (working copy) @@ -1278,6 +1278,46 @@ } return NULL; } +int openmpt_module_ctl_get_boolean( openmpt_module * mod, const char * ctl ) { + try { + openmpt::interface::check_soundfile( mod ); + openmpt::interface::check_pointer( ctl ); + return mod->impl->ctl_get_boolean( ctl ); + } catch ( ... ) { + openmpt::report_exception( __func__, mod ); + } + return 0; +} +int64_t openmpt_module_ctl_get_integer( openmpt_module * mod, const char * ctl ) { + try { + openmpt::interface::check_soundfile( mod ); + openmpt::interface::check_pointer( ctl ); + return mod->impl->ctl_get_integer( ctl ); + } catch ( ... ) { + openmpt::report_exception( __func__, mod ); + } + return 0; +} +double openmpt_module_ctl_get_floatingpoint( openmpt_module * mod, const char * ctl ) { + try { + openmpt::interface::check_soundfile( mod ); + openmpt::interface::check_pointer( ctl ); + return mod->impl->ctl_get_floatingpoint( ctl ); + } catch ( ... ) { + openmpt::report_exception( __func__, mod ); + } + return 0.0; +} +const char * openmpt_module_ctl_get_text( openmpt_module * mod, const char * ctl ) { + try { + openmpt::interface::check_soundfile( mod ); + openmpt::interface::check_pointer( ctl ); + return openmpt::strdup( mod->impl->ctl_get_text( ctl ).c_str() ); + } catch ( ... ) { + openmpt::report_exception( __func__, mod ); + } + return NULL; +} int openmpt_module_ctl_set( openmpt_module * mod, const char * ctl, const char * value ) { try { @@ -1291,8 +1331,52 @@ } return 0; } +int openmpt_module_ctl_set_boolean( openmpt_module * mod, const char * ctl, int value ) { + try { + openmpt::interface::check_soundfile( mod ); + openmpt::interface::check_pointer( ctl ); + mod->impl->ctl_set_boolean( ctl, value ); + return 1; + } catch ( ... ) { + openmpt::report_exception( __func__, mod ); + } + return 0; +} +int openmpt_module_ctl_set_integer( openmpt_module * mod, const char * ctl, int64_t value ) { + try { + openmpt::interface::check_soundfile( mod ); + openmpt::interface::check_pointer( ctl ); + mod->impl->ctl_set_integer( ctl, value ); + return 1; + } catch ( ... ) { + openmpt::report_exception( __func__, mod ); + } + return 0; +} +int openmpt_module_ctl_set_floatingpoint( openmpt_module * mod, const char * ctl, double value ) { + try { + openmpt::interface::check_soundfile( mod ); + openmpt::interface::check_pointer( ctl ); + mod->impl->ctl_set_floatingpoint( ctl, value ); + return 1; + } catch ( ... ) { + openmpt::report_exception( __func__, mod ); + } + return 0; +} +int openmpt_module_ctl_set_text( openmpt_module * mod, const char * ctl, const char * value ) { + try { + openmpt::interface::check_soundfile( mod ); + openmpt::interface::check_pointer( ctl ); + openmpt::interface::check_pointer( value ); + mod->impl->ctl_set_text( ctl, value ); + return 1; + } catch ( ... ) { + openmpt::report_exception( __func__, mod ); + } + return 0; +} - openmpt_module_ext * openmpt_module_ext_create( openmpt_stream_callbacks stream_callbacks, void * stream, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message, const openmpt_module_initial_ctl * ctls ) { try { openmpt_module_ext * mod_ext = (openmpt_module_ext*)std::calloc( 1, sizeof( openmpt_module_ext ) ); Index: libopenmpt/libopenmpt_cxx.cpp =================================================================== --- libopenmpt/libopenmpt_cxx.cpp (revision 12197) +++ libopenmpt/libopenmpt_cxx.cpp (working copy) @@ -126,6 +126,9 @@ bool is_extension_supported( const std::string & extension ) { return openmpt::module_impl::is_extension_supported( extension ); } +bool is_extension_supported( std::string_view extension ) { + return openmpt::module_impl::is_extension_supported( extension ); +} double could_open_probability( std::istream & stream, double effort, std::ostream & log ) { return openmpt::module_impl::could_open_probability( stream, effort, openmpt::helper::make_unique( log ) ); @@ -385,12 +388,38 @@ std::vector module::get_ctls() const { return impl->get_ctls(); } + std::string module::ctl_get( const std::string & ctl ) const { return impl->ctl_get( ctl ); } +bool module::ctl_get_boolean( std::string_view ctl ) const { + return impl->ctl_get_boolean( ctl ); +} +std::int64_t module::ctl_get_integer( std::string_view ctl ) const { + return impl->ctl_get_integer( ctl ); +} +double module::ctl_get_floatingpoint( std::string_view ctl ) const { + return impl->ctl_get_floatingpoint( ctl ); +} +std::string module::ctl_get_text( std::string_view ctl ) const { + return impl->ctl_get_text( ctl ); +} + void module::ctl_set( const std::string & ctl, const std::string & value ) { impl->ctl_set( ctl, value ); } +void module::ctl_set_boolean( std::string_view ctl, bool value ) { + impl->ctl_set_boolean( ctl, value ); +} +void module::ctl_set_integer( std::string_view ctl, std::int64_t value ) { + impl->ctl_set_integer( ctl, value ); +} +void module::ctl_set_floatingpoint( std::string_view ctl, double value ) { + impl->ctl_set_floatingpoint( ctl, value ); +} +void module::ctl_set_text( std::string_view ctl, std::string_view value ) { + impl->ctl_set_text( ctl, value ); +} module_ext::module_ext( std::istream & stream, std::ostream & log, const std::map< std::string, std::string > & ctls ) : ext_impl(0) { ext_impl = new module_ext_impl( stream, openmpt::helper::make_unique( log ), ctls ); Index: libopenmpt/libopenmpt_impl.cpp =================================================================== --- libopenmpt/libopenmpt_impl.cpp (revision 12197) +++ libopenmpt/libopenmpt_impl.cpp (working copy) @@ -593,12 +593,9 @@ std::copy( extensions.begin(), extensions.end(), std::back_insert_iterator >( retval ) ); return retval; } -bool module_impl::is_extension_supported( const char * extension ) { +bool module_impl::is_extension_supported( std::string_view extension ) { return CSoundFile::IsExtensionSupported( extension ); } -bool module_impl::is_extension_supported( const std::string & extension ) { - return CSoundFile::IsExtensionSupported( extension.c_str() ); -} double module_impl::could_open_probability( const OpenMPT::FileReader & file, double effort, std::unique_ptr log ) { try { if ( effort >= 0.8 ) { @@ -1527,6 +1524,7 @@ "dither", }; } + std::string module_impl::ctl_get( std::string ctl, bool throw_if_unknown ) const { if ( !ctl.empty() ) { // cppcheck false-positive @@ -1591,6 +1589,215 @@ } } } +bool module_impl::ctl_get_boolean( std::string_view ctl, bool throw_if_unknown ) const { + if ( !ctl.empty() ) { + // cppcheck false-positive + // cppcheck-suppress containerOutOfBounds + char rightmost = ctl.back(); + if ( rightmost == '!' || rightmost == '?' ) { + if ( rightmost == '!' ) { + throw_if_unknown = true; + } else if ( rightmost == '?' ) { + throw_if_unknown = false; + } + ctl = ctl.substr( 0, ctl.length() - 1 ); + } + } + if ( ctl == "" ) { + throw openmpt::exception("empty ctl"); + } else if ( ctl == "load.skip_samples" || ctl == "load_skip_samples" ) { + return m_ctl_load_skip_samples; + } else if ( ctl == "load.skip_patterns" || ctl == "load_skip_patterns" ) { + return m_ctl_load_skip_patterns; + } else if ( ctl == "load.skip_plugins" ) { + return m_ctl_load_skip_plugins; + } else if ( ctl == "load.skip_subsongs_init" ) { + return m_ctl_load_skip_subsongs_init; + } else if ( ctl == "seek.sync_samples" ) { + return m_ctl_seek_sync_samples; + } else if ( ctl == "subsong" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "play.at_end" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "play.tempo_factor" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "play.pitch_factor" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "render.resampler.emulate_amiga" ) { + return m_sndFile->m_Resampler.m_Settings.emulateAmiga; + } else if ( ctl == "render.opl.volume_factor" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "dither" ) { + throw openmpt::exception("wrong ctl value type"); + } else { + if ( throw_if_unknown ) { + throw openmpt::exception("unknown ctl: " + std::string(ctl)); + } else { + return false; + } + } +} +std::int64_t module_impl::ctl_get_integer( std::string_view ctl, bool throw_if_unknown ) const { + if ( !ctl.empty() ) { + // cppcheck false-positive + // cppcheck-suppress containerOutOfBounds + char rightmost = ctl.back(); + if ( rightmost == '!' || rightmost == '?' ) { + if ( rightmost == '!' ) { + throw_if_unknown = true; + } else if ( rightmost == '?' ) { + throw_if_unknown = false; + } + ctl = ctl.substr( 0, ctl.length() - 1 ); + } + } + if ( ctl == "" ) { + throw openmpt::exception("empty ctl"); + } else if ( ctl == "load.skip_samples" || ctl == "load_skip_samples" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "load.skip_patterns" || ctl == "load_skip_patterns" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "load.skip_plugins" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "load.skip_subsongs_init" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "seek.sync_samples" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "subsong" ) { + return get_selected_subsong(); + } else if ( ctl == "play.at_end" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "play.tempo_factor" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "play.pitch_factor" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "render.resampler.emulate_amiga" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "render.opl.volume_factor" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "dither" ) { + return static_cast( m_Dither->GetMode() ); + } else { + if ( throw_if_unknown ) { + throw openmpt::exception("unknown ctl: " + std::string(ctl)); + } else { + return 0; + } + } +} +double module_impl::ctl_get_floatingpoint( std::string_view ctl, bool throw_if_unknown ) const { + if ( !ctl.empty() ) { + // cppcheck false-positive + // cppcheck-suppress containerOutOfBounds + char rightmost = ctl.back(); + if ( rightmost == '!' || rightmost == '?' ) { + if ( rightmost == '!' ) { + throw_if_unknown = true; + } else if ( rightmost == '?' ) { + throw_if_unknown = false; + } + ctl = ctl.substr( 0, ctl.length() - 1 ); + } + } + if ( ctl == "" ) { + throw openmpt::exception("empty ctl"); + } else if ( ctl == "load.skip_samples" || ctl == "load_skip_samples" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "load.skip_patterns" || ctl == "load_skip_patterns" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "load.skip_plugins" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "load.skip_subsongs_init" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "seek.sync_samples" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "subsong" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "play.at_end" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "play.tempo_factor" ) { + if ( !is_loaded() ) { + return 1.0; + } + return 65536.0 / m_sndFile->m_nTempoFactor; + } else if ( ctl == "play.pitch_factor" ) { + if ( !is_loaded() ) { + return 1.0; + } + return m_sndFile->m_nFreqFactor / 65536.0; + } else if ( ctl == "render.resampler.emulate_amiga" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "render.opl.volume_factor" ) { + return static_cast( m_sndFile->m_OPLVolumeFactor ) / static_cast( m_sndFile->m_OPLVolumeFactorScale ); + } else if ( ctl == "dither" ) { + throw openmpt::exception("wrong ctl value type"); + } else { + if ( throw_if_unknown ) { + throw openmpt::exception("unknown ctl: " + std::string(ctl)); + } else { + return 0.0; + } + } +} +std::string module_impl::ctl_get_text( std::string_view ctl, bool throw_if_unknown ) const { + if ( !ctl.empty() ) { + // cppcheck false-positive + // cppcheck-suppress containerOutOfBounds + char rightmost = ctl.back(); + if ( rightmost == '!' || rightmost == '?' ) { + if ( rightmost == '!' ) { + throw_if_unknown = true; + } else if ( rightmost == '?' ) { + throw_if_unknown = false; + } + ctl = ctl.substr( 0, ctl.length() - 1 ); + } + } + if ( ctl == "" ) { + throw openmpt::exception("empty ctl"); + } else if ( ctl == "load.skip_samples" || ctl == "load_skip_samples" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "load.skip_patterns" || ctl == "load_skip_patterns" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "load.skip_plugins" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "load.skip_subsongs_init" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "seek.sync_samples" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "subsong" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "play.at_end" ) { + switch ( m_ctl_play_at_end ) + { + case song_end_action::fadeout_song: + return "fadeout"; + case song_end_action::continue_song: + return "continue"; + case song_end_action::stop_song: + return "stop"; + default: + return std::string(); + } + } else if ( ctl == "play.tempo_factor" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "play.pitch_factor" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "render.resampler.emulate_amiga" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "render.opl.volume_factor" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "dither" ) { + throw openmpt::exception("wrong ctl value type"); + } else { + if ( throw_if_unknown ) { + throw openmpt::exception("unknown ctl: " + std::string(ctl)); + } else { + return std::string(); + } + } +} + void module_impl::ctl_set( std::string ctl, const std::string & value, bool throw_if_unknown ) { if ( !ctl.empty() ) { // cppcheck false-positive @@ -1671,5 +1878,229 @@ } } } +void module_impl::ctl_set_boolean( std::string_view ctl, bool value, bool throw_if_unknown ) { + if ( !ctl.empty() ) { + // cppcheck false-positive + // cppcheck-suppress containerOutOfBounds + char rightmost = ctl.back(); + if ( rightmost == '!' || rightmost == '?' ) { + if ( rightmost == '!' ) { + throw_if_unknown = true; + } else if ( rightmost == '?' ) { + throw_if_unknown = false; + } + ctl = ctl.substr( 0, ctl.length() - 1 ); + } + } + if ( ctl == "" ) { + throw openmpt::exception("empty ctl: := " + mpt::fmt::val( value ) ); + } else if ( ctl == "load.skip_samples" || ctl == "load_skip_samples" ) { + m_ctl_load_skip_samples = value; + } else if ( ctl == "load.skip_patterns" || ctl == "load_skip_patterns" ) { + m_ctl_load_skip_patterns = value; + } else if ( ctl == "load.skip_plugins" ) { + m_ctl_load_skip_plugins = value; + } else if ( ctl == "load.skip_subsongs_init" ) { + m_ctl_load_skip_subsongs_init = value; + } else if ( ctl == "seek.sync_samples" ) { + m_ctl_seek_sync_samples = value; + } else if ( ctl == "subsong" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "play.at_end" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "play.tempo_factor" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "play.pitch_factor" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "render.resampler.emulate_amiga" ) { + CResamplerSettings newsettings = m_sndFile->m_Resampler.m_Settings; + newsettings.emulateAmiga = value; + if ( newsettings != m_sndFile->m_Resampler.m_Settings ) { + m_sndFile->SetResamplerSettings( newsettings ); + } + } else if ( ctl == "render.opl.volume_factor" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "dither" ) { + throw openmpt::exception("wrong ctl value type"); + } else { + if ( throw_if_unknown ) { + throw openmpt::exception("unknown ctl: " + std::string(ctl) + " := " + mpt::fmt::val(value)); + } else { + // ignore + } + } +} +void module_impl::ctl_set_integer( std::string_view ctl, std::int64_t value, bool throw_if_unknown ) { + if ( !ctl.empty() ) { + // cppcheck false-positive + // cppcheck-suppress containerOutOfBounds + char rightmost = ctl.back(); + if ( rightmost == '!' || rightmost == '?' ) { + if ( rightmost == '!' ) { + throw_if_unknown = true; + } else if ( rightmost == '?' ) { + throw_if_unknown = false; + } + ctl = ctl.substr( 0, ctl.length() - 1 ); + } + } + if ( ctl == "" ) { + throw openmpt::exception("empty ctl: := " + mpt::fmt::val( value ) ); + } else if ( ctl == "load.skip_samples" || ctl == "load_skip_samples" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "load.skip_patterns" || ctl == "load_skip_patterns" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "load.skip_plugins" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "load.skip_subsongs_init" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "seek.sync_samples" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "subsong" ) { + select_subsong( mpt::saturate_cast( value ) ); + } else if ( ctl == "play.at_end" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "play.tempo_factor" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "play.pitch_factor" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "render.resampler.emulate_amiga" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "render.opl.volume_factor" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "dither" ) { + int dither = mpt::saturate_cast( value ); + if ( dither < 0 || dither >= NumDitherModes ) { + dither = DitherDefault; + } + m_Dither->SetMode( static_cast( dither ) ); + } else { + if ( throw_if_unknown ) { + throw openmpt::exception("unknown ctl: " + std::string(ctl) + " := " + mpt::fmt::val(value)); + } else { + // ignore + } + } +} +void module_impl::ctl_set_floatingpoint( std::string_view ctl, double value, bool throw_if_unknown ) { + if ( !ctl.empty() ) { + // cppcheck false-positive + // cppcheck-suppress containerOutOfBounds + char rightmost = ctl.back(); + if ( rightmost == '!' || rightmost == '?' ) { + if ( rightmost == '!' ) { + throw_if_unknown = true; + } else if ( rightmost == '?' ) { + throw_if_unknown = false; + } + ctl = ctl.substr( 0, ctl.length() - 1 ); + } + } + if ( ctl == "" ) { + throw openmpt::exception("empty ctl: := " + mpt::fmt::val( value ) ); + } else if ( ctl == "load.skip_samples" || ctl == "load_skip_samples" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "load.skip_patterns" || ctl == "load_skip_patterns" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "load.skip_plugins" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "load.skip_subsongs_init" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "seek.sync_samples" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "subsong" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "play.at_end" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "play.tempo_factor" ) { + if ( !is_loaded() ) { + return; + } + double factor = value; + if ( factor <= 0.0 || factor > 4.0 ) { + throw openmpt::exception("invalid tempo factor"); + } + m_sndFile->m_nTempoFactor = mpt::saturate_round( 65536.0 / factor ); + m_sndFile->RecalculateSamplesPerTick(); + } else if ( ctl == "play.pitch_factor" ) { + if ( !is_loaded() ) { + return; + } + double factor = value; + if ( factor <= 0.0 || factor > 4.0 ) { + throw openmpt::exception("invalid pitch factor"); + } + m_sndFile->m_nFreqFactor = mpt::saturate_round( 65536.0 * factor ); + m_sndFile->RecalculateSamplesPerTick(); + } else if ( ctl == "render.resampler.emulate_amiga" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "render.opl.volume_factor" ) { + m_sndFile->m_OPLVolumeFactor = mpt::saturate_round( value * static_cast( m_sndFile->m_OPLVolumeFactorScale ) ); + } else if ( ctl == "dither" ) { + throw openmpt::exception("wrong ctl value type"); + } else { + if ( throw_if_unknown ) { + throw openmpt::exception("unknown ctl: " + std::string(ctl) + " := " + mpt::fmt::val(value)); + } else { + // ignore + } + } +} +void module_impl::ctl_set_text( std::string_view ctl, std::string_view value, bool throw_if_unknown ) { + if ( !ctl.empty() ) { + // cppcheck false-positive + // cppcheck-suppress containerOutOfBounds + char rightmost = ctl.back(); + if ( rightmost == '!' || rightmost == '?' ) { + if ( rightmost == '!' ) { + throw_if_unknown = true; + } else if ( rightmost == '?' ) { + throw_if_unknown = false; + } + ctl = ctl.substr( 0, ctl.length() - 1 ); + } + } + if ( ctl == "" ) { + throw openmpt::exception("empty ctl: := " + std::string( value ) ); + } else if ( ctl == "load.skip_samples" || ctl == "load_skip_samples" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "load.skip_patterns" || ctl == "load_skip_patterns" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "load.skip_plugins" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "load.skip_subsongs_init" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "seek.sync_samples" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "subsong" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "play.at_end" ) { + if ( value == "fadeout" ) { + m_ctl_play_at_end = song_end_action::fadeout_song; + } else if(value == "continue") { + m_ctl_play_at_end = song_end_action::continue_song; + } else if(value == "stop") { + m_ctl_play_at_end = song_end_action::stop_song; + } else { + throw openmpt::exception("unknown song end action:" + std::string(value)); + } + } else if ( ctl == "play.tempo_factor" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "play.pitch_factor" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "render.resampler.emulate_amiga" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "render.opl.volume_factor" ) { + throw openmpt::exception("wrong ctl value type"); + } else if ( ctl == "dither" ) { + throw openmpt::exception("wrong ctl value type"); + } else { + if ( throw_if_unknown ) { + throw openmpt::exception("unknown ctl: " + std::string(ctl) + " := " + std::string(value)); + } else { + // ignore + } + } +} } // namespace openmpt Index: libopenmpt/libopenmpt_impl.hpp =================================================================== --- libopenmpt/libopenmpt_impl.hpp (revision 12197) +++ libopenmpt/libopenmpt_impl.hpp (working copy) @@ -130,8 +130,7 @@ static double could_open_probability( const OpenMPT::FileReader & file, double effort, std::unique_ptr log ); public: static std::vector get_supported_extensions(); - static bool is_extension_supported( const char * extension ); - static bool is_extension_supported( const std::string & extension ); + static bool is_extension_supported( std::string_view extension ); static double could_open_probability( callback_stream_wrapper stream, double effort, std::unique_ptr log ); static double could_open_probability( std::istream & stream, double effort, std::unique_ptr log ); static std::size_t probe_file_header_get_recommended_size(); @@ -204,7 +203,15 @@ std::string highlight_pattern_row_channel( std::int32_t p, std::int32_t r, std::int32_t c, std::size_t width, bool pad ) const; std::vector get_ctls() const; std::string ctl_get( std::string ctl, bool throw_if_unknown = true ) const; + bool ctl_get_boolean( std::string_view ctl, bool throw_if_unknown = true ) const; + std::int64_t ctl_get_integer( std::string_view ctl, bool throw_if_unknown = true ) const; + double ctl_get_floatingpoint( std::string_view ctl, bool throw_if_unknown = true ) const; + std::string ctl_get_text( std::string_view ctl, bool throw_if_unknown = true ) const; void ctl_set( std::string ctl, const std::string & value, bool throw_if_unknown = true ); + void ctl_set_boolean( std::string_view ctl, bool value, bool throw_if_unknown = true ); + void ctl_set_integer( std::string_view ctl, std::int64_t value, bool throw_if_unknown = true ); + void ctl_set_floatingpoint( std::string_view ctl, double value, bool throw_if_unknown = true ); + void ctl_set_text( std::string_view ctl, std::string_view value, bool throw_if_unknown = true ); }; // class module_impl namespace helper { Index: openmpt123/openmpt123.cpp =================================================================== --- openmpt123/openmpt123.cpp (revision 12197) +++ openmpt123/openmpt123.cpp (working copy) @@ -711,33 +711,6 @@ } -template < typename T, typename Tmod > -T ctl_get( Tmod & mod, const std::string & ctl ) { - T result = T(); - try { - std::istringstream str; - str.imbue( std::locale::classic() ); - str.str( mod.ctl_get( ctl ) ); - str >> std::fixed >> std::setprecision(16) >> result; - } catch ( const openmpt::exception & ) { - // ignore - } - return result; -} - -template < typename T, typename Tmod > -void ctl_set( Tmod & mod, const std::string & ctl, const T & val ) { - try { - std::ostringstream str; - str.imbue( std::locale::classic() ); - str << std::fixed << std::setprecision(16) << val; - mod.ctl_set( ctl, str.str() ); - } catch ( const openmpt::exception & ) { - // ignore - } - return; -} - template < typename Tmod > static void apply_mod_settings( commandlineflags & flags, Tmod & mod ) { flags.separation = std::max( flags.separation, std::int32_t( 0 ) ); @@ -753,12 +726,17 @@ 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 ); - ctl_set( mod, "play.tempo_factor", tempo_flag_to_double( flags.tempo ) ); - ctl_set( mod, "play.pitch_factor", pitch_flag_to_double( flags.pitch ) ); - std::ostringstream dither_str; - dither_str.imbue( std::locale::classic() ); - dither_str << flags.dither; - mod.ctl_set( "dither", dither_str.str() ); + 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) { } }; Index: soundlib/Sndfile.h =================================================================== --- soundlib/Sndfile.h (revision 12197) +++ soundlib/Sndfile.h (working copy) @@ -823,7 +823,7 @@ bool ReadWAV(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); static std::vector GetSupportedExtensions(bool otherFormats); - static bool IsExtensionSupported(const char *ext); // UTF8, casing of ext is ignored + static bool IsExtensionSupported(std::string_view ext); // UTF8, casing of ext is ignored static mpt::ustring ModContainerTypeToString(MODCONTAINERTYPE containertype); static mpt::ustring ModContainerTypeToTracker(MODCONTAINERTYPE containertype); Index: soundlib/Tables.cpp =================================================================== --- soundlib/Tables.cpp (revision 12197) +++ soundlib/Tables.cpp (working copy) @@ -176,21 +176,19 @@ } -static bool IsEqualExtension(const char *a, const char *b) +static bool IsEqualExtension(std::string_view a, std::string_view b) { - std::size_t lena = std::strlen(a); - std::size_t lenb = std::strlen(b); - if(lena != lenb) + if(a.length() != b.length()) { return false; } - return mpt::CompareNoCaseAscii(a, b, lena) == 0; + return mpt::CompareNoCaseAscii(a, b) == 0; } -bool CSoundFile::IsExtensionSupported(const char *ext) +bool CSoundFile::IsExtensionSupported(std::string_view ext) { - if(ext == nullptr || ext[0] == 0) + if(ext.length() == 0) { return false; }