From 9a427cf03c2d34718123abfcf37fd899a3a4a62f Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Sun, 14 Mar 2021 14:55:49 -0700 Subject: [PATCH] Update libopenmpt to version 0.5.6 --- Frameworks/OpenMPT/OpenMPT/LICENSE | 2 +- Frameworks/OpenMPT/OpenMPT/README.md | 32 +++----- Frameworks/OpenMPT/OpenMPT/build/dist.mk | 6 +- .../OpenMPT/build/make/config-emscripten.mk | 9 +++ .../OpenMPT/build/svn_version/svn_version.h | 8 +- .../OpenMPT/OpenMPT/common/CompilerDetect.h | 6 ++ .../OpenMPT/OpenMPT/common/mptRandom.cpp | 16 ++++ Frameworks/OpenMPT/OpenMPT/common/mptRandom.h | 2 + Frameworks/OpenMPT/OpenMPT/common/version.cpp | 8 +- .../OpenMPT/OpenMPT/common/versionNumber.h | 2 +- .../contrib/libmodplug-0.8.8.5/LICENSE | 2 +- .../contrib/libmodplug-0.8.9.0/LICENSE | 2 +- .../OpenMPT/include/stb_vorbis/OpenMPT.txt | 1 + .../OpenMPT/include/stb_vorbis/stb_vorbis.c | 5 ++ .../bindings/freebasic/libopenmpt.bi | 4 +- .../OpenMPT/libopenmpt/dox/changelog.md | 30 ++++++++ .../OpenMPT/OpenMPT/libopenmpt/in_openmpt.cpp | 2 +- .../OpenMPT/OpenMPT/libopenmpt/libopenmpt.h | 4 +- .../OpenMPT/OpenMPT/libopenmpt/libopenmpt.hpp | 6 +- .../OpenMPT/libopenmpt/libopenmpt_c.cpp | 6 +- .../OpenMPT/libopenmpt/libopenmpt_impl.cpp | 8 +- .../OpenMPT/libopenmpt/libopenmpt_version.h | 2 +- .../OpenMPT/libopenmpt/libopenmpt_version.mk | 4 +- .../OpenMPT/libopenmpt/xmp-openmpt.cpp | 2 +- .../OpenMPT/OpenMPT/openmpt123/openmpt123.cpp | 12 ++- .../OpenMPT/OpenMPT/openmpt123/openmpt123.hpp | 8 ++ .../OpenMPT/OpenMPT/soundlib/Dlsbank.cpp | 1 + .../OpenMPT/OpenMPT/soundlib/Load_ams.cpp | 13 ++-- .../OpenMPT/OpenMPT/soundlib/Load_dmf.cpp | 25 +++++-- .../OpenMPT/OpenMPT/soundlib/Load_mod.cpp | 4 + .../OpenMPT/OpenMPT/soundlib/Load_s3m.cpp | 10 +-- .../OpenMPT/OpenMPT/soundlib/Load_wav.cpp | 36 ++++----- .../OpenMPT/OpenMPT/soundlib/ModSampleCopy.h | 6 +- .../OpenMPT/OpenMPT/soundlib/ModSequence.cpp | 11 +-- .../OpenMPT/OpenMPT/soundlib/S3MTools.cpp | 13 ++-- .../OpenMPT/OpenMPT/soundlib/S3MTools.h | 2 +- .../OpenMPT/soundlib/SampleFormats.cpp | 19 +++-- .../OpenMPT/OpenMPT/soundlib/SampleIO.cpp | 2 +- .../OpenMPT/OpenMPT/soundlib/Snd_defs.h | 2 +- .../OpenMPT/OpenMPT/soundlib/Snd_fx.cpp | 27 ++++--- .../OpenMPT/OpenMPT/soundlib/Sndfile.cpp | 14 +++- .../OpenMPT/OpenMPT/soundlib/Sndmix.cpp | 7 +- .../OpenMPT/soundlib/UpgradeModule.cpp | 2 +- .../OpenMPT/OpenMPT/soundlib/modsmp_ctrl.cpp | 74 +++++++++++++++++-- .../OpenMPT/OpenMPT/soundlib/modsmp_ctrl.h | 4 + .../OpenMPT/soundlib/plugins/LFOPlugin.cpp | 2 +- .../OpenMPT/soundlib/plugins/LFOPlugin.h | 2 +- .../soundlib/plugins/PlugInterface.cpp | 5 +- .../OpenMPT/soundlib/plugins/PlugInterface.h | 4 +- .../OpenMPT/OpenMPT/soundlib/tuning.cpp | 5 +- 50 files changed, 331 insertions(+), 148 deletions(-) diff --git a/Frameworks/OpenMPT/OpenMPT/LICENSE b/Frameworks/OpenMPT/OpenMPT/LICENSE index e81fc3ff8..ae92400c3 100644 --- a/Frameworks/OpenMPT/OpenMPT/LICENSE +++ b/Frameworks/OpenMPT/OpenMPT/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2020, OpenMPT contributors +Copyright (c) 2004-2021, OpenMPT contributors Copyright (c) 1997-2003, Olivier Lapicque All rights reserved. diff --git a/Frameworks/OpenMPT/OpenMPT/README.md b/Frameworks/OpenMPT/OpenMPT/README.md index 94c32e0fb..1d9de2b90 100644 --- a/Frameworks/OpenMPT/OpenMPT/README.md +++ b/Frameworks/OpenMPT/OpenMPT/README.md @@ -170,36 +170,24 @@ For detailed requirements, see `libopenmpt/dox/quickstart.md`. - emscripten (on Unix-like systems): - libopenmpt has been tested and verified to work with emscripten 1.38.5 - or later. Earlier versions are not supported. - Run: - # generates WebAssembly with dynamic heap growth + # generates WebAssembly with JavaScript fallback + make CONFIG=emscripten EMSCRIPTEN_TARGET=all + + or + + # generates WebAssembly make CONFIG=emscripten EMSCRIPTEN_TARGET=wasm or - # generates asm.js with a fixed size 128MB heap - make CONFIG=emscripten EMSCRIPTEN_TARGET=asmjs128m - - or - - # generates asm.js with a fixed default size heap (as of Emscripten - # 1.38.11, this amounts to 16MB) - make CONFIG=emscripten EMSCRIPTEN_TARGET=asmjs - - or - - # generates JavaScript with dynamic heap growth and with - # compatibility for older VMs + # generates JavaScript with compatibility for older VMs make CONFIG=emscripten EMSCRIPTEN_TARGET=js Running the test suite on the command line is also supported by using - node.js. Version 8.9.1 or greater has been tested. Earlier versions - might or might not work. Depending on how your distribution calls the - `node.js` binary, you might have to edit - `build/make/config-emscripten.mk`. + node.js. Depending on how your distribution calls the `node.js` binary, + you might have to edit `build/make/config-emscripten.mk`. - DJGPP / DOS @@ -229,7 +217,7 @@ For detailed requirements, see `libopenmpt/dox/quickstart.md`. - other compilers: - To compile libopenmpt with other C++14 compliant compilers, run: + To compile libopenmpt with other C++17 compliant compilers, run: make CONFIG=generic diff --git a/Frameworks/OpenMPT/OpenMPT/build/dist.mk b/Frameworks/OpenMPT/OpenMPT/build/dist.mk index 231c97f64..79714a6dc 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/dist.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/dist.mk @@ -1,4 +1,4 @@ -MPT_SVNVERSION=13932 -MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.4 -MPT_SVNDATE=2020-11-29T15:01:39.790705Z +MPT_SVNVERSION=14311 +MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.6 +MPT_SVNDATE=2021-03-14T15:27:41.476009Z diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-emscripten.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-emscripten.mk index 3a9670d78..69488d0b0 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-emscripten.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-emscripten.mk @@ -48,6 +48,15 @@ LDFLAGS += -s WASM=2 -s LEGACY_VM_SUPPORT=1 LDFLAGS += -s ALLOW_MEMORY_GROWTH=1 +else ifeq ($(EMSCRIPTEN_TARGET),audioworkletprocessor) +# emits an es6 module in a single file suitable for use in an AudioWorkletProcessor +CPPFLAGS += -DMPT_BUILD_WASM -DMPT_BUILD_AUDIOWORKLETPROCESSOR +CXXFLAGS += -s WASM=1 -s WASM_ASYNC_COMPILATION=0 -s MODULARIZE=1 -s EXPORT_ES6=1 -s SINGLE_FILE=1 +CFLAGS += -s WASM=1 -s WASM_ASYNC_COMPILATION=0 -s MODULARIZE=1 -s EXPORT_ES6=1 -s SINGLE_FILE=1 +LDFLAGS += -s WASM=1 -s WASM_ASYNC_COMPILATION=0 -s MODULARIZE=1 -s EXPORT_ES6=1 -s SINGLE_FILE=1 + +LDFLAGS += -s ALLOW_MEMORY_GROWTH=1 + else ifeq ($(EMSCRIPTEN_TARGET),wasm) # emits native wasm. CPPFLAGS += -DMPT_BUILD_WASM diff --git a/Frameworks/OpenMPT/OpenMPT/build/svn_version/svn_version.h b/Frameworks/OpenMPT/OpenMPT/build/svn_version/svn_version.h index e000ef227..e43987fee 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/svn_version/svn_version.h +++ b/Frameworks/OpenMPT/OpenMPT/build/svn_version/svn_version.h @@ -1,10 +1,10 @@ #pragma once -#define OPENMPT_VERSION_SVNVERSION "13932" -#define OPENMPT_VERSION_REVISION 13932 +#define OPENMPT_VERSION_SVNVERSION "14311" +#define OPENMPT_VERSION_REVISION 14311 #define OPENMPT_VERSION_DIRTY 0 #define OPENMPT_VERSION_MIXEDREVISIONS 0 -#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.4" -#define OPENMPT_VERSION_DATE "2020-11-29T15:01:39.790705Z" +#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.6" +#define OPENMPT_VERSION_DATE "2021-03-14T15:27:41.476009Z" #define OPENMPT_VERSION_IS_PACKAGE 1 diff --git a/Frameworks/OpenMPT/OpenMPT/common/CompilerDetect.h b/Frameworks/OpenMPT/OpenMPT/common/CompilerDetect.h index 3b1d75951..6a5217fd4 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/CompilerDetect.h +++ b/Frameworks/OpenMPT/OpenMPT/common/CompilerDetect.h @@ -309,6 +309,12 @@ #endif +#if MPT_OS_EMSCRIPTEN && defined(MPT_BUILD_AUDIOWORKLETPROCESSOR) +#define MPT_COMPILER_QUIRK_CHRONO_NO_HIGH_RESOLUTION_CLOCK +#define MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE +#endif + + #if MPT_OS_DJGPP #define MPT_COMPILER_QUIRK_NO_WCHAR #endif diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptRandom.cpp b/Frameworks/OpenMPT/OpenMPT/common/mptRandom.cpp index 84e0db941..1cf4e7e4e 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptRandom.cpp +++ b/Frameworks/OpenMPT/OpenMPT/common/mptRandom.cpp @@ -27,6 +27,8 @@ namespace mpt { +#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE) + template static T log2(T x) { @@ -58,6 +60,8 @@ static MPT_CONSTEXPR14_FUN bool is_mask(T x) return false; } +#endif // !MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE + namespace { template struct default_hash { }; @@ -91,6 +95,7 @@ static T generate_timeseed() hash(std::begin(bytes), std::end(bytes)); } +#if !defined(MPT_COMPILER_QUIRK_CHRONO_NO_HIGH_RESOLUTION_CLOCK) { uint64be time; time = std::chrono::duration_cast(std::chrono::high_resolution_clock().now().time_since_epoch()).count(); @@ -98,6 +103,7 @@ static T generate_timeseed() std::memcpy(bytes, &time, sizeof(time)); hash(std::begin(bytes), std::end(bytes)); } +#endif // !MPT_COMPILER_QUIRK_CHRONO_NO_HIGH_RESOLUTION_CLOCK return static_cast(hash.result()); @@ -126,8 +132,11 @@ crand::result_type crand::operator()() #endif // MODPLUG_TRACKER sane_random_device::sane_random_device() +#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE) : rd_reliable(false) +#endif // MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE { +#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE) try { prd = std::make_unique(); @@ -140,6 +149,7 @@ sane_random_device::sane_random_device() rd_reliable = false; } if(!rd_reliable) +#endif // MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE { init_fallback(); } @@ -147,8 +157,11 @@ sane_random_device::sane_random_device() sane_random_device::sane_random_device(const std::string & token_) : token(token_) +#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE) , rd_reliable(false) +#endif // MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE { +#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE) try { prd = std::make_unique(token); @@ -161,6 +174,7 @@ sane_random_device::sane_random_device(const std::string & token_) rd_reliable = false; } if(!rd_reliable) +#endif // MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE { init_fallback(); } @@ -198,6 +212,7 @@ sane_random_device::result_type sane_random_device::operator()() { mpt::lock_guard l(m); result_type result = 0; +#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE) if(prd) { try @@ -244,6 +259,7 @@ sane_random_device::result_type sane_random_device::operator()() rd_reliable = false; } if(!rd_reliable) +#endif // MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE { // std::random_device is unreliable // XOR the generated random number with more entropy from the time-seeded // PRNG. diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptRandom.h b/Frameworks/OpenMPT/OpenMPT/common/mptRandom.h index 84a7c029b..972ce623b 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptRandom.h +++ b/Frameworks/OpenMPT/OpenMPT/common/mptRandom.h @@ -449,8 +449,10 @@ class sane_random_device private: mpt::mutex m; std::string token; +#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE) std::unique_ptr prd; bool rd_reliable; +#endif // !MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE std::unique_ptr rd_fallback; public: typedef unsigned int result_type; diff --git a/Frameworks/OpenMPT/OpenMPT/common/version.cpp b/Frameworks/OpenMPT/OpenMPT/common/version.cpp index 40efdaf40..8489288f7 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/version.cpp +++ b/Frameworks/OpenMPT/OpenMPT/common/version.cpp @@ -582,12 +582,12 @@ mpt::ustring GetFullCreditsString() "libopenmpt (based on OpenMPT / ModPlug Tracker)\n" #endif "\n" - "Copyright \xC2\xA9 2004-2020 Contributors\n" + "Copyright \xC2\xA9 2004-2021 Contributors\n" "Copyright \xC2\xA9 1997-2003 Olivier Lapicque\n" "\n" "Contributors:\n" - "Johannes Schultz (2008-2020)\n" - "J\xC3\xB6rn Heusipp (2012-2020)\n" + "Johannes Schultz (2008-2021)\n" + "J\xC3\xB6rn Heusipp (2012-2021)\n" "Ahti Lepp\xC3\xA4nen (2005-2011)\n" "Robin Fernandes (2004-2007)\n" "Sergiy Pylypenko (2007)\n" @@ -777,7 +777,7 @@ mpt::ustring GetFullCreditsString() mpt::ustring GetLicenseString() { return MPT_UTF8( - "Copyright (c) 2004-2020, OpenMPT contributors" "\n" + "Copyright (c) 2004-2021, OpenMPT contributors" "\n" "Copyright (c) 1997-2003, Olivier Lapicque" "\n" "All rights reserved." "\n" "" "\n" diff --git a/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h b/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h index 3b2a02f09..47c02bb5b 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h +++ b/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h @@ -17,7 +17,7 @@ OPENMPT_NAMESPACE_BEGIN // Version definitions. The only thing that needs to be changed when changing version number. #define VER_MAJORMAJOR 1 #define VER_MAJOR 29 -#define VER_MINOR 06 +#define VER_MINOR 08 #define VER_MINORMINOR 00 OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/LICENSE b/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/LICENSE index e81fc3ff8..ae92400c3 100644 --- a/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/LICENSE +++ b/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2020, OpenMPT contributors +Copyright (c) 2004-2021, OpenMPT contributors Copyright (c) 1997-2003, Olivier Lapicque All rights reserved. diff --git a/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/LICENSE b/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/LICENSE index e81fc3ff8..ae92400c3 100644 --- a/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/LICENSE +++ b/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2020, OpenMPT contributors +Copyright (c) 2004-2021, OpenMPT contributors Copyright (c) 1997-2003, Olivier Lapicque All rights reserved. diff --git a/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/OpenMPT.txt b/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/OpenMPT.txt index 6d32ad581..2149fbab7 100644 --- a/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/OpenMPT.txt +++ b/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/OpenMPT.txt @@ -7,6 +7,7 @@ Modifications: fails to compile. * Macro redefinition of alloca with mingw-w64 has been fixed. * Macro redefinition of STB_VORBIS_NO_STDIO has been fixed. + * Bugfix https://github.com/nothings/stb/pull/1064 has been applied. Modifications are always additions and have been marked with // OpenMPT. For building, premake is used to generate Visual Studio project files. diff --git a/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/stb_vorbis.c b/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/stb_vorbis.c index 75fabf7d6..9e6fc3377 100644 --- a/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/stb_vorbis.c +++ b/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/stb_vorbis.c @@ -3652,7 +3652,12 @@ static int start_decoder(vorb *f) //user comments f->comment_list_length = get32_packet(f); f->comment_list = (char**)setup_malloc(f, sizeof(char*) * (f->comment_list_length)); +#if 0 // OpenMPT if (f->comment_list == NULL) return error(f, VORBIS_outofmem); +#else // OpenMPT + // Bugfix from https://github.com/nothings/stb/pull/1064 // OpenMPT + if (f->comment_list_length > 0 && f->comment_list == NULL) return error(f, VORBIS_outofmem); // OpenMPT +#endif // OpenMPT for(i=0; i < f->comment_list_length; ++i) { len = get32_packet(f); diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/bindings/freebasic/libopenmpt.bi b/Frameworks/OpenMPT/OpenMPT/libopenmpt/bindings/freebasic/libopenmpt.bi index 6e83441b9..b346a0ca4 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/bindings/freebasic/libopenmpt.bi +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/bindings/freebasic/libopenmpt.bi @@ -981,7 +981,7 @@ Declare Function openmpt_module_read_interleaved_stereo(ByVal module As openmpt_ \param module The module handle to work on. \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. - \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved suad surround output in the order (L,R,RL,RR). + \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR). \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. @@ -1011,7 +1011,7 @@ Declare Function openmpt_module_read_interleaved_float_stereo(ByVal module As op \param module The module handle to work on. \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. - \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved suad surround output in the order (L,R,RL,RR). + \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR). \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/changelog.md b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/changelog.md index bfcc2a96f..0cdc38114 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/changelog.md +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/changelog.md @@ -5,6 +5,36 @@ Changelog {#changelog} For fully detailed change log, please see the source repository directly. This is just a high-level summary. +### libopenmpt 0.5.6 (2021-03-14) + + * AMS: Avoid allocating excessive amount of memory for compressed song message + in malformed files. + * S3M: Some samples or OPL patches were imported with a too high sample rate + if module was saved with Scream Tracker 3. + + * vorbis: Update to v1.3.7 (2020-07-04). + +### libopenmpt 0.5.5 (2021-01-31) + + * [**New**] `Makefile` `CONFIG=emscripten` now supports + `EMSCRIPTEN_TARGET=audioworkletprocessor` which builds an ES6 module in + a single file with reduced dependencies suitable to be used in an + AudioWorkletProcessor. + + * [**Bug**] stb_vorbis: Fix decoding of Vorbis streams without comments which + affected most Vorbis samples since stb_vorbis v1.20. + + * `openmpt::ext::interactive::set_pitch_factor` wasn't applied to OPL voices. + * OPL channel state (in particular current patch) is now updated when seeking. + * The FT2 tremolo quirk is now also applied to MOD files. FT2 just copied the + quirky code from ProTracker! + * DMF: Preserve effects better in some situations where there is more than one + effect in a pattern cell. + * DMF: Improve import of finetune effect with parameters larger than +/-15. + + * mpg123: Update to v1.26.4 (2020-12-24). + * pugixml: Update to v1.11.4 (2020-12-22). + ### libopenmpt 0.5.4 (2020-11-29) * AMS: An upper bound for uncompressed sample size is now established to diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/in_openmpt.cpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/in_openmpt.cpp index 1b752106c..5066242ff 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/in_openmpt.cpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/in_openmpt.cpp @@ -210,7 +210,7 @@ static void config( HWND hwndParent ) { static void about( HWND hwndParent ) { std::ostringstream about; about << SHORT_TITLE << " version " << openmpt::string::get( "library_version" ) << " " << "(built " << openmpt::string::get( "build" ) << ")" << std::endl; - about << " Copyright (c) 2013-2020 OpenMPT developers (https://lib.openmpt.org/)" << std::endl; + about << " Copyright (c) 2013-2021 OpenMPT developers (https://lib.openmpt.org/)" << std::endl; about << " OpenMPT version " << openmpt::string::get( "core_version" ) << std::endl; about << std::endl; about << openmpt::string::get( "contact" ) << std::endl; diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.h b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.h index 5451483e9..8aa69b5e3 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.h +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.h @@ -1071,7 +1071,7 @@ LIBOPENMPT_API size_t openmpt_module_read_interleaved_stereo( openmpt_module * m * \param mod The module handle to work on. * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. * \param count Number of audio frames to render per channel. - * \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved suad surround output in the order (L,R,RL,RR). + * \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR). * \return The number of frames actually rendered. * \retval 0 The end of song has been reached. * \remarks The output buffers are only written to up to the returned number of elements. @@ -1099,7 +1099,7 @@ LIBOPENMPT_API size_t openmpt_module_read_interleaved_float_stereo( openmpt_modu * \param mod The module handle to work on. * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. * \param count Number of audio frames to render per channel. - * \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved suad surround output in the order (L,R,RL,RR). + * \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR). * \return The number of frames actually rendered. * \retval 0 The end of song has been reached. * \remarks The output buffers are only written to up to the returned number of elements. diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.hpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.hpp index 0e5bff0b1..7215baf9b 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.hpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.hpp @@ -750,7 +750,7 @@ public: /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. - \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved suad surround output in the order (L,R,RL,RR). + \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR). \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. @@ -776,7 +776,7 @@ public: /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. \param count Number of audio frames to render per channel. - \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved suad surround output in the order (L,R,RL,RR). + \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR). \return The number of frames actually rendered. \retval 0 The end of song has been reached. \remarks The output buffers are only written to up to the returned number of elements. @@ -1119,7 +1119,7 @@ public: \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(). + \deprecated Please use openmpt::module::ctl_set_bool(), openmpt::module::ctl_set_int(), openmpt::module::ctl_set_floatingpoint(), or openmpt::module::ctl_set_string(). */ LIBOPENMPT_ATTR_DEPRECATED void ctl_set( const std::string & ctl, const std::string & value ); //! Set ctl boolean value diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_c.cpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_c.cpp index fff8a59fb..0ae46be2d 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_c.cpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_c.cpp @@ -1734,12 +1734,12 @@ int openmpt_module_ext_get_interface( openmpt_module_ext * mod_ext, const char * openmpt::interface::check_pointer( interface ); std::memset( interface, 0, interface_size ); int result = 0; - if ( !strcmp( interface_id, "" ) ) { + if ( !std::strcmp( interface_id, "" ) ) { result = 0; - } else if ( !strcmp( interface_id, LIBOPENMPT_EXT_C_INTERFACE_PATTERN_VIS ) && ( interface_size == sizeof( openmpt_module_ext_interface_pattern_vis ) ) ) { + } else if ( !std::strcmp( interface_id, LIBOPENMPT_EXT_C_INTERFACE_PATTERN_VIS ) && ( interface_size == sizeof( openmpt_module_ext_interface_pattern_vis ) ) ) { openmpt_module_ext_interface_pattern_vis * i = static_cast< openmpt_module_ext_interface_pattern_vis * >( interface ); i->get_pattern_row_channel_volume_effect_type = &get_pattern_row_channel_volume_effect_type; i->get_pattern_row_channel_effect_type = &get_pattern_row_channel_effect_type; @@ -1747,7 +1747,7 @@ int openmpt_module_ext_get_interface( openmpt_module_ext * mod_ext, const char * - } else if ( !strcmp( interface_id, LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE ) && ( interface_size == sizeof( openmpt_module_ext_interface_interactive ) ) ) { + } else if ( !std::strcmp( interface_id, LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE ) && ( interface_size == sizeof( openmpt_module_ext_interface_interactive ) ) ) { openmpt_module_ext_interface_interactive * i = static_cast< openmpt_module_ext_interface_interactive * >( interface ); i->set_current_speed = &set_current_speed; i->set_current_tempo = &set_current_tempo; diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_impl.cpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_impl.cpp index 74f407a31..71cd67b60 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_impl.cpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_impl.cpp @@ -66,8 +66,8 @@ MPT_WARNING("Warning: libopenmpt built in non thread-safe mode because mutexes a MPT_WARNING("Warning: Building libopenmpt with MinGW-w64 without std::thread support is not recommended and is deprecated. Please use MinGW-w64 with posix threading model (as opposed to win32 threading model), or build with mingw-std-threads.") #endif // MINGW -#if MPT_CLANG_AT_LEAST(5,0,0) && defined(__powerpc__) && !defined(__powerpc64__) -MPT_WARNING("Warning: libopenmpt is known to trigger bad code generation with Clang 5 or later on powerpc (32bit) when using -O3. See .") +#if MPT_CLANG_AT_LEAST(5,0,0) && MPT_CLANG_BEFORE(11,0,0) && defined(__powerpc__) && !defined(__powerpc64__) +MPT_WARNING("Warning: libopenmpt is known to trigger bad code generation with Clang 5..10 on powerpc (32bit) when using -O3. See .") #endif #endif // !MPT_BUILD_SILENCE_LIBOPENMPT_CONFIGURATION_WARNINGS @@ -1106,9 +1106,9 @@ double module_impl::set_position_seconds( double seconds ) { } else { subsong = &subsongs[m_current_subsong]; } + m_sndFile->SetCurrentOrder( static_cast( subsong->start_order ) ); GetLengthType t = m_sndFile->GetLength( m_ctl_seek_sync_samples ? eAdjustSamplePositions : eAdjust, GetLengthTarget( seconds ).StartPos( static_cast( subsong->sequence ), static_cast( subsong->start_order ), static_cast( subsong->start_row ) ) ).back(); - m_sndFile->m_PlayState.m_nCurrentOrder = t.lastOrder; - m_sndFile->SetCurrentOrder( t.lastOrder ); + m_sndFile->m_PlayState.m_nNextOrder = m_sndFile->m_PlayState.m_nCurrentOrder = t.lastOrder; m_sndFile->m_PlayState.m_nNextRow = t.lastRow; m_currentPositionSeconds = base_seconds + t.duration; return m_currentPositionSeconds; diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h index 5736522fd..edf57fc6d 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h @@ -19,7 +19,7 @@ /*! \brief libopenmpt minor version number */ #define OPENMPT_API_VERSION_MINOR 5 /*! \brief libopenmpt patch version number */ -#define OPENMPT_API_VERSION_PATCH 4 +#define OPENMPT_API_VERSION_PATCH 6 /*! \brief libopenmpt pre-release tag */ #define OPENMPT_API_VERSION_PREREL "" /*! \brief libopenmpt pre-release flag */ diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.mk b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.mk index 9627719c5..5192b424f 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.mk +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.mk @@ -1,8 +1,8 @@ LIBOPENMPT_VERSION_MAJOR=0 LIBOPENMPT_VERSION_MINOR=5 -LIBOPENMPT_VERSION_PATCH=4 +LIBOPENMPT_VERSION_PATCH=6 LIBOPENMPT_VERSION_PREREL= LIBOPENMPT_LTVER_CURRENT=2 -LIBOPENMPT_LTVER_REVISION=4 +LIBOPENMPT_LTVER_REVISION=6 LIBOPENMPT_LTVER_AGE=2 diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt.cpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt.cpp index 56334e4bc..2664dda00 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt.cpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt.cpp @@ -465,7 +465,7 @@ static void clear_current_timeinfo() { static void WINAPI openmpt_About( HWND win ) { std::ostringstream about; about << SHORT_TITLE << " version " << openmpt::string::get( "library_version" ) << " " << "(built " << openmpt::string::get( "build" ) << ")" << std::endl; - about << " Copyright (c) 2013-2020 OpenMPT developers (https://lib.openmpt.org/)" << std::endl; + about << " Copyright (c) 2013-2021 OpenMPT developers (https://lib.openmpt.org/)" << std::endl; about << " OpenMPT version " << openmpt::string::get( "core_version" ) << std::endl; about << std::endl; about << openmpt::string::get( "contact" ) << std::endl; diff --git a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.cpp b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.cpp index faae040d1..c85908d1a 100644 --- a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.cpp +++ b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.cpp @@ -8,7 +8,7 @@ */ static const char * const license = -"Copyright (c) 2004-2020, OpenMPT contributors" "\n" +"Copyright (c) 2004-2021, OpenMPT contributors" "\n" "Copyright (c) 1997-2003, Olivier Lapicque" "\n" "All rights reserved." "\n" "" "\n" @@ -74,6 +74,7 @@ static const char * const license = #include #include #include +#include #include #include #include @@ -459,7 +460,7 @@ static std::string seconds_to_string( double time ) { 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-2020 OpenMPT developers " << std::endl; + log << "Copyright (c) 2013-2021 OpenMPT developers " << std::endl; if ( !verbose ) { log << std::endl; return; @@ -536,7 +537,7 @@ static void show_info( std::ostream & log, bool verbose ) { static void show_man_version( textout & log ) { log << "openmpt123" << " v" << OPENMPT123_VERSION_STRING << std::endl; log << std::endl; - log << "Copyright (c) 2013-2020 OpenMPT developers " << std::endl; + log << "Copyright (c) 2013-2021 OpenMPT developers " << std::endl; } static void show_short_version( textout & log ) { @@ -2288,8 +2289,13 @@ static int main( int argc, char * argv [] ) { #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 ); diff --git a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.hpp b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.hpp index 89a28bf67..d3041d12a 100644 --- a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.hpp +++ b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.hpp @@ -890,11 +890,19 @@ public: 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_ )) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp index 4f849747a..a7e99770d 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp @@ -1698,6 +1698,7 @@ bool CDLSBank::ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nI if (usUnityNote > 0x7F) usUnityNote = 60; int steps = (60 + transpose - usUnityNote) * 128 + sFineTune; sample.Transpose(steps * (1.0 / (12.0 * 128.0))); + sample.RelativeTone = 0; Limit(lVolume, 16, 256); sample.nGlobalVol = (uint8)(lVolume / 4); // 0-64 diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ams.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ams.cpp index c9b31a54a..e9e1b302b 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ams.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ams.cpp @@ -903,12 +903,9 @@ bool CSoundFile::ReadAMS2(FileReader &file, ModLoadingFlags loadFlags) // Text // Read composer name - uint8 composerLength = file.ReadUint8(); - if(composerLength) + if(std::string composer; file.ReadSizedString(composer)) { - std::string str; - file.ReadString(str, composerLength); - m_songArtist = mpt::ToUnicode(mpt::Charset::CP437AMS2, str); + m_songArtist = mpt::ToUnicode(mpt::Charset::CP437AMS2, composer); } // Channel names @@ -926,11 +923,13 @@ bool CSoundFile::ReadAMS2(FileReader &file, ModLoadingFlags loadFlags) } if(descriptionHeader.packedLen > sizeof(descriptionHeader) && file.CanRead(descriptionHeader.packedLen - sizeof(descriptionHeader))) { - const size_t textLength = descriptionHeader.packedLen - sizeof(descriptionHeader); + const uint32 textLength = descriptionHeader.packedLen - static_cast(sizeof(descriptionHeader)); std::vector textIn; file.ReadVector(textIn, textLength); + // In the best case, every byte triplet can decode to 255 bytes, which is a ratio of exactly 1:85 + const uint32 maxLength = std::min(textLength, Util::MaxValueOfType(textLength) / 85u) * 85u; std::string textOut; - textOut.reserve(descriptionHeader.unpackedLen); + textOut.reserve(std::min(maxLength, descriptionHeader.unpackedLen.get())); size_t readLen = 0; while(readLen < textLength) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dmf.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dmf.cpp index 3e6f1e373..68a1a6231 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dmf.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dmf.cpp @@ -630,10 +630,19 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, const uint8 fileVersion, switch(effect2) { - case 1: // Note Finetune - effect2 = static_cast(effectParam2 < 128 ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN); - if(effectParam2 > 128) effectParam2 = 255 - effectParam2 + 1; - effectParam2 = 0xF0 | std::min(uint8(0x0F), effectParam2); // Well, this is not too accurate... + case 1: // Note Finetune (1/16th of a semitone signed 8-bit value, not 1/128th as the interface claims) + effect2 = (effectParam2 < 128) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN; + if(effectParam2 >= 128) + effectParam2 = ~effectParam2 + 1; + if(effectParam2 >= 16 && m->IsNote()) + { + if(effect2 == CMD_PORTAMENTOUP) + m->note = static_cast(std::min(m->note + effectParam2 / 16, static_cast(NOTE_MAX))); + else + m->note = static_cast(std::max(m->note - effectParam2 / 16, static_cast(NOTE_MIN))); + effectParam2 %= 16u; + } + effectParam2 = 0xF0 | std::min(uint8(0x0F), effectParam2); break; case 2: // Note Delay (wtf is the difference to Sample Delay?) effectParam2 = DMFdelay2MPT(effectParam2, settings.internalTicks); @@ -654,7 +663,7 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, const uint8 fileVersion, case 4: // Portamento Up case 5: // Portamento Down effectParam2 = DMFporta2MPT(effectParam2, settings.internalTicks, true); - effect2 = static_cast(effect2 == 4 ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN); + effect2 = (effect2 == 4) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN; useMem2 = true; break; case 6: // Portamento to Note @@ -811,6 +820,12 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, const uint8 fileVersion, // Prefer instrument effects over any other effects if(effect1 != CMD_NONE) { + ModCommand::TwoRegularCommandsToMPT(effect3, effectParam3, effect1, effectParam1); + if(m->volcmd == VOLCMD_NONE && effect3 != VOLCMD_NONE) + { + m->volcmd = effect3; + m->vol = effectParam3; + } m->command = effect1; m->param = effectParam1; } else if(effect3 != CMD_NONE) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp index 79e318c8f..ebd124fe5 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp @@ -1160,6 +1160,10 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) { m_SongFlags.set(SONG_ISAMIGA); } + if(isGenericMultiChannel || isMdKd) + { + m_playBehaviour.set(kFT2MODTremoloRampWaveform); + } if(isInconexia) { m_playBehaviour.set(kMODIgnorePanning); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp index c0f3a5151..6f07e14e9 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp @@ -84,6 +84,7 @@ void CSoundFile::S3MSaveConvert(uint8 &command, uint8 ¶m, bool toIT, bool co case CMD_TONEPORTAVOL: command = 'L'; break; case CMD_CHANNELVOLUME: command = 'M'; break; case CMD_CHANNELVOLSLIDE: command = 'N'; break; + case CMD_OFFSETPERCENTAGE: case CMD_OFFSET: command = 'O'; break; case CMD_PANNINGSLIDE: command = 'P'; break; case CMD_RETRIG: command = 'Q'; break; @@ -465,7 +466,7 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) continue; } - sampleHeader.ConvertToMPT(Samples[smp + 1]); + sampleHeader.ConvertToMPT(Samples[smp + 1], isST3); m_szNames[smp + 1] = mpt::String::ReadBuf(mpt::String::nullTerminated, sampleHeader.name); if(sampleHeader.sampleType < S3MSampleHeader::typeAdMel) @@ -527,7 +528,7 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) } CHANNELINDEX channel = (info & s3mChannelMask); - ModCommand dummy = ModCommand::Empty(); + ModCommand dummy; ModCommand &m = (channel < GetNumChannels()) ? rowBase[channel] : dummy; if(info & s3mNotePresent) @@ -577,12 +578,9 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) } else { if(m.param < 0x08) - { zxxCountLeft++; - } else if(m.param > 0x08) - { + else if(m.param > 0x08) zxxCountRight++; - } } } } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_wav.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_wav.cpp index a71f0bdf8..424ace0a5 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_wav.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_wav.cpp @@ -64,11 +64,13 @@ bool CSoundFile::ReadWAV(FileReader &file, ModLoadingFlags loadFlags) WAVReader wavFile(file); if(!wavFile.IsValid() - || wavFile.GetNumChannels() == 0 - || wavFile.GetNumChannels() > MAX_BASECHANNELS - || wavFile.GetBitsPerSample() == 0 - || wavFile.GetBitsPerSample() > 32 - || (wavFile.GetSampleFormat() != WAVFormatChunk::fmtPCM && wavFile.GetSampleFormat() != WAVFormatChunk::fmtFloat)) + || wavFile.GetNumChannels() == 0 + || wavFile.GetNumChannels() > MAX_BASECHANNELS + || wavFile.GetNumChannels() >= MAX_SAMPLES + || wavFile.GetBitsPerSample() == 0 + || wavFile.GetBitsPerSample() > 64 + || (wavFile.GetBitsPerSample() < 32 && wavFile.GetSampleFormat() == WAVFormatChunk::fmtFloat) + || (wavFile.GetSampleFormat() != WAVFormatChunk::fmtPCM && wavFile.GetSampleFormat() != WAVFormatChunk::fmtFloat)) { return false; } else if(loadFlags == onlyVerifyHeader) @@ -173,22 +175,22 @@ bool CSoundFile::ReadWAV(FileReader &file, ModLoadingFlags loadFlags) if(wavFile.GetSampleFormat() == WAVFormatChunk::fmtFloat) { - CopyWavChannel, SC::DecodeFloat32 > >(sample, sampleChunk, channel, wavFile.GetNumChannels()); + if(wavFile.GetBitsPerSample() <= 32) + CopyWavChannel, SC::DecodeFloat32>>(sample, sampleChunk, channel, wavFile.GetNumChannels()); + else + CopyWavChannel, SC::DecodeFloat64>>(sample, sampleChunk, channel, wavFile.GetNumChannels()); } else { if(wavFile.GetBitsPerSample() <= 8) - { CopyWavChannel(sample, sampleChunk, channel, wavFile.GetNumChannels()); - } else if(wavFile.GetBitsPerSample() <= 16) - { - CopyWavChannel >(sample, sampleChunk, channel, wavFile.GetNumChannels()); - } else if(wavFile.GetBitsPerSample() <= 24) - { - CopyWavChannel, SC::DecodeInt24<0, littleEndian24> > >(sample, sampleChunk, channel, wavFile.GetNumChannels()); - } else if(wavFile.GetBitsPerSample() <= 32) - { - CopyWavChannel, SC::DecodeInt32<0, littleEndian32> > >(sample, sampleChunk, channel, wavFile.GetNumChannels()); - } + else if(wavFile.GetBitsPerSample() <= 16) + CopyWavChannel>(sample, sampleChunk, channel, wavFile.GetNumChannels()); + else if(wavFile.GetBitsPerSample() <= 24) + CopyWavChannel, SC::DecodeInt24<0, littleEndian24>>>(sample, sampleChunk, channel, wavFile.GetNumChannels()); + else if(wavFile.GetBitsPerSample() <= 32) + CopyWavChannel, SC::DecodeInt32<0, littleEndian32>>>(sample, sampleChunk, channel, wavFile.GetNumChannels()); + else if(wavFile.GetBitsPerSample() <= 64) + CopyWavChannel, SC::DecodeInt64<0, littleEndian64>>>(sample, sampleChunk, channel, wavFile.GetNumChannels()); } sample.PrecomputeLoops(*this, false); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ModSampleCopy.h b/Frameworks/OpenMPT/OpenMPT/soundlib/ModSampleCopy.h index ce20e79ce..3d4ec2a13 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ModSampleCopy.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ModSampleCopy.h @@ -114,12 +114,12 @@ size_t CopyStereoSplitSample(ModSample &sample, const Tbyte *sourceBuffer, size_ template size_t CopyAndNormalizeSample(ModSample &sample, const Tbyte *sourceBuffer, size_t sourceSize, typename SampleConversion::peak_t *srcPeak = nullptr, SampleConversion conv = SampleConversion()) { - const size_t inSize = sizeof(typename SampleConversion::input_t); + const size_t sampleSize = SampleConversion::input_inc; MPT_ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t)); size_t numSamples = sample.nLength * sample.GetNumChannels(); - LimitMax(numSamples, sourceSize / inSize); + LimitMax(numSamples, sourceSize / sampleSize); const std::byte * inBuf = mpt::byte_cast(sourceBuffer); // Finding max value @@ -150,7 +150,7 @@ size_t CopyAndNormalizeSample(ModSample &sample, const Tbyte *sourceBuffer, size *srcPeak = sampleConv.GetSrcPeak(); } - return numSamples * inSize; + return numSamples * sampleSize; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ModSequence.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/ModSequence.cpp index b7638a21d..1c5d2cf46 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ModSequence.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ModSequence.cpp @@ -180,18 +180,19 @@ void ModSequence::assign(ORDERINDEX newSize, PATTERNINDEX pat) ORDERINDEX ModSequence::insert(ORDERINDEX pos, ORDERINDEX count, PATTERNINDEX fill) { - if (pos >= m_sndFile.GetModSpecifications().ordersMax || count == 0) + const auto ordersMax = m_sndFile.GetModSpecifications().ordersMax; + if(pos >= ordersMax || GetLengthTailTrimmed() >= ordersMax || count == 0) return 0; // Limit number of orders to be inserted so that we don't exceed the format limit. - LimitMax(count, ORDERINDEX(m_sndFile.GetModSpecifications().ordersMax - pos)); - reserve(pos + count); + LimitMax(count, static_cast(ordersMax - pos)); + reserve(std::max(pos, GetLength()) + count); // Inserting past the end of the container? if(pos > size()) resize(pos); std::vector::insert(begin() + pos, count, fill); // Did we overgrow? Remove patterns at end. - if(size() > m_sndFile.GetModSpecifications().ordersMax) - resize(m_sndFile.GetModSpecifications().ordersMax); + if(size() > ordersMax) + resize(ordersMax); return count; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/S3MTools.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/S3MTools.cpp index d7305412d..5245e2506 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/S3MTools.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/S3MTools.cpp @@ -17,7 +17,7 @@ OPENMPT_NAMESPACE_BEGIN // Convert an S3M sample header to OpenMPT's internal sample header. -void S3MSampleHeader::ConvertToMPT(ModSample &mptSmp) const +void S3MSampleHeader::ConvertToMPT(ModSample &mptSmp, bool isST3) const { mptSmp.Initialize(MOD_TYPE_S3M); mptSmp.filename = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, filename); @@ -48,17 +48,18 @@ void S3MSampleHeader::ConvertToMPT(ModSample &mptSmp) const } // Volume / Panning - mptSmp.nVolume = std::min(static_cast(defaultVolume), uint8(64)) * 4; + mptSmp.nVolume = std::min(defaultVolume.get(), uint8(64)) * 4; // C-5 frequency mptSmp.nC5Speed = c5speed; + // ST3 ignores the high 16 bits + if(isST3) + mptSmp.nC5Speed &= 0xFFFF; + if(mptSmp.nC5Speed == 0) - { mptSmp.nC5Speed = 8363; - } else if(mptSmp.nC5Speed < 1024) - { + else if(mptSmp.nC5Speed < 1024) mptSmp.nC5Speed = 1024; - } } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/S3MTools.h b/Frameworks/OpenMPT/OpenMPT/soundlib/S3MTools.h index a78ad2281..4c0e5885d 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/S3MTools.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/S3MTools.h @@ -134,7 +134,7 @@ struct S3MSampleHeader char magic[4]; // "SCRS" magic bytes ("SCRI" for Adlib instruments) // Convert an S3M sample header to OpenMPT's internal sample header. - void ConvertToMPT(ModSample &mptSmp) const; + void ConvertToMPT(ModSample &mptSmp, bool isST3 = false) const; // Convert OpenMPT's internal sample header to an S3M sample header. SmpLength ConvertToS3M(const ModSample &mptSmp); // Retrieve the internal sample format flags for this sample. diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp index 3bd949b5e..e65c5bb30 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp @@ -20,6 +20,7 @@ #include "../common/mptFileIO.h" #endif // !MODPLUG_NO_FILESAVE #include "../common/misc_util.h" +#include "../common/Endianness.h" #include "Tagging.h" #include "ITTools.h" #include "XMTools.h" @@ -421,11 +422,12 @@ bool CSoundFile::ReadWAVSample(SAMPLEINDEX nSample, FileReader &file, bool mayNo WAVReader wavFile(file); if(!wavFile.IsValid() - || wavFile.GetNumChannels() == 0 - || wavFile.GetNumChannels() > 2 - || (wavFile.GetBitsPerSample() == 0 && wavFile.GetSampleFormat() != WAVFormatChunk::fmtMP3) - || (wavFile.GetBitsPerSample() > 64) - || (wavFile.GetSampleFormat() != WAVFormatChunk::fmtPCM && wavFile.GetSampleFormat() != WAVFormatChunk::fmtFloat && wavFile.GetSampleFormat() != WAVFormatChunk::fmtIMA_ADPCM && wavFile.GetSampleFormat() != WAVFormatChunk::fmtMP3 && wavFile.GetSampleFormat() != WAVFormatChunk::fmtALaw && wavFile.GetSampleFormat() != WAVFormatChunk::fmtULaw)) + || wavFile.GetNumChannels() == 0 + || wavFile.GetNumChannels() > 2 + || (wavFile.GetBitsPerSample() == 0 && wavFile.GetSampleFormat() != WAVFormatChunk::fmtMP3) + || (wavFile.GetBitsPerSample() < 32 && wavFile.GetSampleFormat() == WAVFormatChunk::fmtFloat) + || (wavFile.GetBitsPerSample() > 64) + || (wavFile.GetSampleFormat() != WAVFormatChunk::fmtPCM && wavFile.GetSampleFormat() != WAVFormatChunk::fmtFloat && wavFile.GetSampleFormat() != WAVFormatChunk::fmtIMA_ADPCM && wavFile.GetSampleFormat() != WAVFormatChunk::fmtMP3 && wavFile.GetSampleFormat() != WAVFormatChunk::fmtALaw && wavFile.GetSampleFormat() != WAVFormatChunk::fmtULaw)) { return false; } @@ -2486,6 +2488,7 @@ struct IFFChunk idVHDR = MagicBE("VHDR"), idBODY = MagicBE("BODY"), idNAME = MagicBE("NAME"), + idCHAN = MagicBE("CHAN"), }; uint32be id; // See ChunkIdentifiers @@ -2538,6 +2541,7 @@ bool CSoundFile::ReadIFFSample(SAMPLEINDEX nSample, FileReader &file) FileReader vhdrChunk = chunks.GetChunk(IFFChunk::idVHDR); FileReader bodyChunk = chunks.GetChunk(IFFChunk::idBODY); + FileReader chanChunk = chunks.GetChunk(IFFChunk::idCHAN); IFFSampleHeader sampleHeader; if(!bodyChunk.IsValid() || !vhdrChunk.IsValid() @@ -2549,6 +2553,7 @@ bool CSoundFile::ReadIFFSample(SAMPLEINDEX nSample, FileReader &file) DestroySampleThreadsafe(nSample); // Default values const uint8 bytesPerSample = memcmp(fileHeader.magic, "8SVX", 4) ? 2 : 1; + const uint8 channels = chanChunk.ReadUint32BE() == 6 ? 2 : 1; ModSample &sample = Samples[nSample]; sample.Initialize(); sample.nLoopStart = sampleHeader.oneShotHiSamples / bytesPerSample; @@ -2569,13 +2574,13 @@ bool CSoundFile::ReadIFFSample(SAMPLEINDEX nSample, FileReader &file) m_szNames[nSample] = ""; } - sample.nLength = mpt::saturate_cast(bodyChunk.GetLength() / bytesPerSample); + sample.nLength = mpt::saturate_cast(bodyChunk.GetLength() / (bytesPerSample * channels)); if((sample.nLoopStart + 4 < sample.nLoopEnd) && (sample.nLoopEnd <= sample.nLength)) sample.uFlags.set(CHN_LOOP); // While this is an Amiga format, the 16SV version appears to be only used on PC, and only with little-endian sample data. SampleIO( (bytesPerSample == 2) ? SampleIO::_16bit : SampleIO::_8bit, - SampleIO::mono, + (channels == 2) ? SampleIO::stereoSplit : SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM) .ReadSample(sample, bodyChunk); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleIO.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleIO.cpp index cf26f1cf9..6a131c438 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleIO.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleIO.cpp @@ -327,7 +327,7 @@ size_t SampleIO::ReadSample(ModSample &sample, FileReader &file) const const auto &lut = GetEncoding() == uLaw ? uLawTable : aLawTable; SmpLength readLength = sample.nLength * GetNumChannels(); - LimitMax(readLength, mpt::saturate_cast(file.BytesLeft())); + LimitMax(readLength, mpt::saturate_cast(fileSize)); bytesRead = readLength; const uint8 *inBuf = mpt::byte_cast(sourceBuf); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_defs.h b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_defs.h index 0dbb9db52..98870cdec 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_defs.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_defs.h @@ -512,7 +512,7 @@ enum PlayBehaviour kFT2NoteOffFlags, // Set and reset the correct fade/key-off flags with note-off and instrument number after note-off kITMultiSampleInstrumentNumber, // After portamento to different sample within multi-sampled instrument, lone instrument numbers in patterns always recall the new sample's default settings kRowDelayWithNoteDelay, // Retrigger note delays on every reptition of a row - kFT2TremoloRampWaveform, // FT2-compatible tremolo ramp down / triangle waveform + kFT2MODTremoloRampWaveform, // FT2-/ProTracker-compatible tremolo ramp down / triangle waveform kFT2PortaUpDownMemory, // Portamento up and down have separate memory kMODOutOfRangeNoteDelay, // ProTracker behaviour for out-of-range note delays diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp index 922f07b21..17cca1cb4 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp @@ -154,6 +154,9 @@ public: int vol = 0; sndFile.ProcessInstrumentFade(chn, vol); + if(chn.dwFlags[CHN_ADLIB]) + continue; + if(updateInc || chnSettings[channel].incChanged) { if(chn.m_CalculateFreq || chn.m_ReCalculateFreqOnFirstTick) @@ -568,11 +571,6 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod { if(Samples[smp].uFlags[CHN_PANNING]) chn.SetInstrumentPan(Samples[smp].nPan, *this); - if(Samples[smp].uFlags[CHN_ADLIB]) - { - memory.state->Chn[nChn].Stop(); - memory.chnSettings[nChn].ticksToRender = 0; - } } } @@ -1301,18 +1299,25 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod m_PlayState.m_nFrameDelay = m_PlayState.m_nPatternDelay = 0; m_PlayState.m_nTickCount = Util::MaxValueOfType(m_PlayState.m_nTickCount) - 1; m_PlayState.m_bPositionChanged = true; + if(m_opl != nullptr) + m_opl->Reset(); for(CHANNELINDEX n = 0; n < GetNumChannels(); n++) { - if(m_PlayState.Chn[n].nLastNote != NOTE_NONE) + auto &chn = m_PlayState.Chn[n]; + if(chn.nLastNote != NOTE_NONE) { - m_PlayState.Chn[n].nNewNote = m_PlayState.Chn[n].nLastNote; + chn.nNewNote = chn.nLastNote; } if(memory.chnSettings[n].vol != 0xFF && !adjustSamplePos) { - m_PlayState.Chn[n].nVolume = std::min(memory.chnSettings[n].vol, uint8(64)) * 4; + chn.nVolume = std::min(memory.chnSettings[n].vol, uint8(64)) * 4; + } + if(chn.pModSample != nullptr && chn.pModSample->uFlags[CHN_ADLIB] && m_opl) + { + m_opl->Patch(n, chn.pModSample->adlib); + m_opl->NoteCut(n); } } - if(m_opl != nullptr) m_opl->Reset(); #ifndef NO_PLUGINS // If there were any PC events, update plugin parameters to their latest value. @@ -1694,7 +1699,7 @@ void CSoundFile::InstrumentChange(ModChannel &chn, uint32 instr, bool bPorta, bo chn.nFineTune = pSmp->nFineTune; } - chn.nTranspose = pSmp->RelativeTone; + chn.nTranspose = UseFinetuneAndTranspose() ? pSmp->RelativeTone : 0; // FT2 compatibility: Don't reset portamento target with new instrument numbers. // Test case: Porta-Pickup.xm @@ -4984,6 +4989,7 @@ void CSoundFile::ProcessMIDIMacro(CHANNELINDEX nChn, bool isSmooth, const char * // MIDI channel isNibble = true; data = 0xFF; +#ifndef NO_PLUGINS const PLUGINDEX plug = (plugin != 0) ? plugin : GetBestPlugin(nChn, PrioritiseChannel, EvenIfMuted); if(plug > 0 && plug <= MAX_MIXPLUGINS) { @@ -4991,6 +4997,7 @@ void CSoundFile::ProcessMIDIMacro(CHANNELINDEX nChn, bool isSmooth, const char * if(midiPlug) data = midiPlug->GetMidiChannel(nChn); } +#endif // NO_PLUGINS if(data == 0xFF) { // Fallback if no plugin was found diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.cpp index 89f3db9b1..19d084f8a 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.cpp @@ -537,9 +537,14 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags) m_nInstruments = maxInstr; // Set default play state values - if (!m_nDefaultTempo.GetInt()) m_nDefaultTempo.Set(125); - if (!m_nDefaultSpeed) m_nDefaultSpeed = 6; - if (m_nDefaultRowsPerMeasure < m_nDefaultRowsPerBeat) m_nDefaultRowsPerMeasure = m_nDefaultRowsPerBeat; + if(!m_nDefaultTempo.GetInt()) + m_nDefaultTempo.Set(125); + else + LimitMax(m_nDefaultTempo, TEMPO(uint16_max, 0)); + if(!m_nDefaultSpeed) + m_nDefaultSpeed = 6; + if(m_nDefaultRowsPerMeasure < m_nDefaultRowsPerBeat) + m_nDefaultRowsPerMeasure = m_nDefaultRowsPerBeat; m_PlayState.m_nMusicSpeed = m_nDefaultSpeed; m_PlayState.m_nMusicTempo = m_nDefaultTempo; m_PlayState.m_nCurrentRowsPerBeat = m_nDefaultRowsPerBeat; @@ -1085,7 +1090,7 @@ PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type) playBehaviour.set(kFT2FinetunePrecision); playBehaviour.set(kFT2NoteOffFlags); playBehaviour.set(kRowDelayWithNoteDelay); - playBehaviour.set(kFT2TremoloRampWaveform); + playBehaviour.set(kFT2MODTremoloRampWaveform); playBehaviour.set(kFT2PortaUpDownMemory); playBehaviour.set(kFT2PanSustainRelease); playBehaviour.set(kFT2NoteDelayWithoutInstr); @@ -1116,6 +1121,7 @@ PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type) playBehaviour.set(kMODOutOfRangeNoteDelay); playBehaviour.set(kMODTempoOnSecondTick); playBehaviour.set(kRowDelayWithNoteDelay); + playBehaviour.set(kFT2MODTremoloRampWaveform); break; default: diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp index e41b46ea4..499ff1e98 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp @@ -889,7 +889,7 @@ void CSoundFile::ProcessTremolo(ModChannel &chn, int &vol) const const uint8 attenuation = ((GetType() & (MOD_TYPE_XM | MOD_TYPE_MOD)) || m_playBehaviour[kITVibratoTremoloPanbrello]) ? 5 : 6; int delta = GetVibratoDelta(chn.nTremoloType, chn.nTremoloPos); - if((chn.nTremoloType & 0x03) == 1 && m_playBehaviour[kFT2TremoloRampWaveform]) + if((chn.nTremoloType & 0x03) == 1 && m_playBehaviour[kFT2MODTremoloRampWaveform]) { // FT2 compatibility: Tremolo ramp down / triangle implementation is weird and affected by vibrato position (copypaste bug) // Test case: TremoloWaveforms.xm, TremoloVibrato.xm @@ -2295,7 +2295,10 @@ bool CSoundFile::ReadNote() // In ST3, a sample rate of 8363 Hz is mapped to middle-C, which is 261.625 Hz in a tempered scale at A4 = 440. // Hence, we have to translate our "sample rate" into pitch. const auto freq = hasTuning ? chn.nPeriod : GetFreqFromPeriod(period, chn.nC5Speed, nPeriodFrac); - const auto milliHertz = Util::muldivr_unsigned(freq, 261625, 8363 << FREQ_FRACBITS); + auto milliHertz = Util::muldivr_unsigned(freq, 261625, 8363 << FREQ_FRACBITS); +#ifndef MODPLUG_TRACKER + milliHertz = Util::muldivr_unsigned(milliHertz, m_nFreqFactor, 65536); +#endif // !MODPLUG_TRACKER const bool keyOff = chn.dwFlags[CHN_KEYOFF] || (chn.dwFlags[CHN_NOTEFADE] && chn.nFadeOutVol == 0); m_opl->Frequency(nChn, milliHertz, keyOff, m_playBehaviour[kOPLBeatingOscillators]); } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/UpgradeModule.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/UpgradeModule.cpp index 2b95d6182..527abc700 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/UpgradeModule.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/UpgradeModule.cpp @@ -565,7 +565,7 @@ void CSoundFile::UpgradeModule() { { kFT2NoteOffFlags, MPT_V("1.27.00.27") }, { kRowDelayWithNoteDelay, MPT_V("1.27.00.37") }, - { kFT2TremoloRampWaveform, MPT_V("1.27.00.37") }, + { kFT2MODTremoloRampWaveform, MPT_V("1.27.00.37") }, { kFT2PortaUpDownMemory, MPT_V("1.27.00.37") }, { kFT2PanSustainRelease, MPT_V("1.28.00.09") }, { kFT2NoteDelayWithoutInstr, MPT_V("1.28.00.44") }, diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/modsmp_ctrl.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/modsmp_ctrl.cpp index 27760f6fe..1ad2d59ee 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/modsmp_ctrl.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/modsmp_ctrl.cpp @@ -187,10 +187,9 @@ static void ConvertStereoToMonoMixImpl(T *pDest, const SmpLength length) template -static void ConvertStereoToMonoOneChannelImpl(T *pDest, const SmpLength length) +static void ConvertStereoToMonoOneChannelImpl(T *pDest, const T *pSource, const SmpLength length) { - const T *pEnd = pDest + length; - for(T *pSource = pDest; pDest != pEnd; pDest++, pSource += 2) + for(const T *pEnd = pDest + length; pDest != pEnd; pDest++, pSource += 2) { *pDest = *pSource; } @@ -218,9 +217,9 @@ bool ConvertToMono(ModSample &smp, CSoundFile &sndFile, StereoToMonoMode convers conversionMode = onlyLeft; } if(smp.GetElementarySampleSize() == 2) - ConvertStereoToMonoOneChannelImpl(smp.sample16() + (conversionMode == onlyLeft ? 0 : 1), smp.nLength); + ConvertStereoToMonoOneChannelImpl(smp.sample16(), smp.sample16() + (conversionMode == onlyLeft ? 0 : 1), smp.nLength); else if(smp.GetElementarySampleSize() == 1) - ConvertStereoToMonoOneChannelImpl(smp.sample8() + (conversionMode == onlyLeft ? 0 : 1), smp.nLength); + ConvertStereoToMonoOneChannelImpl(smp.sample8(), smp.sample8() + (conversionMode == onlyLeft ? 0 : 1), smp.nLength); else return false; } @@ -241,7 +240,70 @@ bool ConvertToMono(ModSample &smp, CSoundFile &sndFile, StereoToMonoMode convers template -static void ConvertMonoToStereoImpl(const T * MPT_RESTRICT src, T * MPT_RESTRICT dst, SmpLength length) +static void SplitStereoImpl(void *destL, void *destR, const T *source, SmpLength length) +{ + T *l = static_cast(destL), *r = static_cast(destR); + while(length--) + { + *(l++) = source[0]; + *(r++) = source[1]; + source += 2; + } +} + + +// Converts a stereo sample into two mono samples. Source sample will not be deleted. +bool SplitStereo(const ModSample &source, ModSample &left, ModSample &right, CSoundFile &sndFile) +{ + if(!source.HasSampleData() || source.GetNumChannels() != 2 || &left == &right) + return false; + const bool sourceIsLeft = &left == &source, sourceIsRight = &right == &source; + if(left.HasSampleData() && !sourceIsLeft) + return false; + if(right.HasSampleData() && !sourceIsRight) + return false; + + void *leftData = sourceIsLeft ? left.samplev() : ModSample::AllocateSample(source.nLength, source.GetElementarySampleSize()); + void *rightData = sourceIsRight ? right.samplev() : ModSample::AllocateSample(source.nLength, source.GetElementarySampleSize()); + if(!leftData || !rightData) + { + if(!sourceIsLeft) + ModSample::FreeSample(leftData); + if(!sourceIsRight) + ModSample::FreeSample(rightData); + return false; + } + + if(source.GetElementarySampleSize() == 2) + SplitStereoImpl(leftData, rightData, source.sample16(), source.nLength); + else if(source.GetElementarySampleSize() == 1) + SplitStereoImpl(leftData, rightData, source.sample8(), source.nLength); + else + MPT_ASSERT_NOTREACHED(); + + CriticalSection cs; + left = source; + left.uFlags.reset(CHN_STEREO); + left.pData.pSample = leftData; + + right = source; + right.uFlags.reset(CHN_STEREO); + right.pData.pSample = rightData; + + for(auto &chn : sndFile.m_PlayState.Chn) + { + if(chn.pModSample == &left || chn.pModSample == &right) + chn.dwFlags.reset(CHN_STEREO); + } + + left.PrecomputeLoops(sndFile, false); + right.PrecomputeLoops(sndFile, false); + return true; +} + + +template +static void ConvertMonoToStereoImpl(const T *MPT_RESTRICT src, T *MPT_RESTRICT dst, SmpLength length) { while(length--) { diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/modsmp_ctrl.h b/Frameworks/OpenMPT/OpenMPT/soundlib/modsmp_ctrl.h index 366aa20e3..8ac23c51f 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/modsmp_ctrl.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/modsmp_ctrl.h @@ -46,6 +46,10 @@ enum StereoToMonoMode // Convert a sample with any number of channels to mono bool ConvertToMono(ModSample &smp, CSoundFile &sndFile, StereoToMonoMode conversionMode); +// Converts a stereo sample into two mono samples. Source sample will not be deleted. +// Either of the two target samples may be identical to the source sample. +bool SplitStereo(const ModSample &source, ModSample &left, ModSample &right, CSoundFile &sndFile); + // Convert a mono sample to stereo bool ConvertToStereo(ModSample &smp, CSoundFile &sndFile); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.cpp index 6e789fe4f..3a359c57e 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.cpp @@ -276,7 +276,7 @@ void LFOPlugin::HardAllNotesOff() } -bool LFOPlugin::IsNotePlaying(uint32 note, CHANNELINDEX trackerChn) +bool LFOPlugin::IsNotePlaying(uint8 note, CHANNELINDEX trackerChn) { if(IMixPlugin *plugin = GetOutputPlugin()) return plugin->IsNotePlaying(note, trackerChn); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.h b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.h index 030753554..d8ab3fd5c 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.h @@ -91,7 +91,7 @@ public: void MidiVibrato(int32 depth, int8 pwd, CHANNELINDEX trackChannel) override; void MidiCommand(const ModInstrument &instr, uint16 note, uint16 vol, CHANNELINDEX trackChannel) override; void HardAllNotesOff() override; - bool IsNotePlaying(uint32 note, CHANNELINDEX trackerChn) override; + bool IsNotePlaying(uint8 note, CHANNELINDEX trackerChn) override; int32 GetNumPrograms() const override { return 0; } int32 GetCurrentProgram() override { return 0; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.cpp index 43c323e62..d8e3a390b 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.cpp @@ -947,8 +947,11 @@ void IMidiPlugin::MidiCommand(const ModInstrument &instr, uint16 note, uint16 vo } -bool IMidiPlugin::IsNotePlaying(uint32 note, CHANNELINDEX trackerChn) +bool IMidiPlugin::IsNotePlaying(uint8 note, CHANNELINDEX trackerChn) { + if(!ModCommand::IsNote(note) || trackerChn >= std::size(m_MidiCh[GetMidiChannel(trackerChn)].noteOnMap[note])) + return false; + note -= NOTE_MIN; return (m_MidiCh[GetMidiChannel(trackerChn)].noteOnMap[note][trackerChn] != 0); } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.h b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.h index 42b4abe06..efa8aa976 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.h @@ -147,7 +147,7 @@ public: virtual void MidiVibrato(int32 /*depth*/, int8 /*pwd*/, CHANNELINDEX /*trackerChn*/) { } virtual void MidiCommand(const ModInstrument &/*instr*/, uint16 /*note*/, uint16 /*vol*/, CHANNELINDEX /*trackChannel*/) { } virtual void HardAllNotesOff() { } - virtual bool IsNotePlaying(uint32 /*note*/, CHANNELINDEX /*trackerChn*/) { return false; } + virtual bool IsNotePlaying(uint8 /*note*/, CHANNELINDEX /*trackerChn*/) { return false; } // Modify parameter by given amount. Only needs to be re-implemented if plugin architecture allows this to be performed atomically. virtual void ModifyParameter(PlugParamIndex nIndex, PlugParamValue diff); @@ -264,7 +264,7 @@ public: void MidiPitchBend(int32 increment, int8 pwd, CHANNELINDEX trackerChn) override; void MidiVibrato(int32 depth, int8 pwd, CHANNELINDEX trackerChn) override; void MidiCommand(const ModInstrument &instr, uint16 note, uint16 vol, CHANNELINDEX trackChannel) override; - bool IsNotePlaying(uint32 note, CHANNELINDEX trackerChn) override; + bool IsNotePlaying(uint8 note, CHANNELINDEX trackerChn) override; // Get the MIDI channel currently associated with a given tracker channel virtual uint8 GetMidiChannel(CHANNELINDEX trackChannel) const; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/tuning.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/tuning.cpp index 3f60d8ae1..a9d4a9952 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/tuning.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/tuning.cpp @@ -234,12 +234,13 @@ mpt::ustring CTuning::GetNoteName(const NOTEINDEXTYPE &x, bool addOctave) const void CTuning::SetNoteName(const NOTEINDEXTYPE &n, const mpt::ustring &str) { + const NOTEINDEXTYPE pos = (GetGroupSize() < 1) ? n : static_cast(mpt::wrapping_modulo(n, m_GroupSize)); if(!str.empty()) { - m_NoteNameMap[n] = str; + m_NoteNameMap[pos] = str; } else { - const auto iter = m_NoteNameMap.find(n); + const auto iter = m_NoteNameMap.find(pos); if(iter != m_NoteNameMap.end()) { m_NoteNameMap.erase(iter);