From db5b4e68c223843dcdc8362e15598a78d5c8f8f4 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Wed, 30 Oct 2024 23:57:33 -0700 Subject: [PATCH] Updated libOpenMPT to version 0.7.11 Signed-off-by: Christopher Snowhill --- Frameworks/OpenMPT/OpenMPT/Makefile | 14 +- .../OpenMPT/build/android_ndk/Android.mk | 39 ++++- .../OpenMPT/build/android_ndk/Application.mk | 36 +++++ Frameworks/OpenMPT/OpenMPT/build/dist.mk | 6 +- .../OpenMPT/build/make/config-emscripten.mk | 4 +- .../OpenMPT/build/make/warnings-clang.mk | 13 +- .../OpenMPT/build/svn_version/svn_version.h | 8 +- .../OpenMPT/OpenMPT/common/BuildSettings.h | 5 +- .../OpenMPT/OpenMPT/common/mptBaseUtils.h | 6 +- Frameworks/OpenMPT/OpenMPT/common/version.cpp | 2 + .../OpenMPT/OpenMPT/common/versionNumber.h | 2 +- .../OpenMPT/include/minimp3/OpenMPT.txt | 10 +- .../OpenMPT/OpenMPT/include/minimp3/minimp3.h | 42 +++-- .../OpenMPT/libopenmpt/libopenmpt_version.h | 2 +- .../OpenMPT/libopenmpt/libopenmpt_version.mk | 4 +- .../OpenMPT/OpenMPT/openmpt123/openmpt123.cpp | 10 +- .../OpenMPT/OpenMPT/openmpt123/openmpt123.hpp | 2 + .../OpenMPT/openmpt123/openmpt123_sndfile.hpp | 6 +- Frameworks/OpenMPT/OpenMPT/sounddsp/EQ.cpp | 3 + .../OpenMPT/OpenMPT/sounddsp/Reverb.cpp | 3 + .../OpenMPT/OpenMPT/soundlib/Dlsbank.cpp | 149 +++++++++--------- Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.h | 9 +- .../OpenMPT/OpenMPT/soundlib/Load_669.cpp | 8 + .../OpenMPT/OpenMPT/soundlib/Load_dmf.cpp | 2 +- .../OpenMPT/OpenMPT/soundlib/Load_dsym.cpp | 2 + .../OpenMPT/OpenMPT/soundlib/Load_it.cpp | 81 +++++++--- .../OpenMPT/OpenMPT/soundlib/Load_med.cpp | 20 +-- .../OpenMPT/OpenMPT/soundlib/Load_mid.cpp | 8 +- .../OpenMPT/OpenMPT/soundlib/Load_mod.cpp | 6 + .../OpenMPT/OpenMPT/soundlib/Load_okt.cpp | 128 ++++++++------- .../OpenMPT/OpenMPT/soundlib/Load_ptm.cpp | 14 +- .../OpenMPT/OpenMPT/soundlib/Load_s3m.cpp | 34 ++-- .../OpenMPT/OpenMPT/soundlib/Load_sfx.cpp | 12 +- .../OpenMPT/OpenMPT/soundlib/Load_stm.cpp | 17 +- .../OpenMPT/OpenMPT/soundlib/Load_symmod.cpp | 40 ++++- .../OpenMPT/OpenMPT/soundlib/Load_ult.cpp | 24 +-- .../OpenMPT/OpenMPT/soundlib/Load_xm.cpp | 6 +- .../OpenMPT/soundlib/ModInstrument.cpp | 19 ++- .../OpenMPT/OpenMPT/soundlib/ModInstrument.h | 2 + .../OpenMPT/soundlib/SampleFormatMP3.cpp | 4 +- .../OpenMPT/soundlib/SampleFormatSFZ.cpp | 15 ++ .../OpenMPT/OpenMPT/soundlib/Snd_fx.cpp | 19 ++- Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.h | 1 + .../OpenMPT/OpenMPT/soundlib/Sndmix.cpp | 37 ++--- .../OpenMPT/OpenMPT/soundlib/Tables.cpp | 1 + .../OpenMPT/soundlib/mod_specifications.cpp | 2 +- .../OpenMPT/OpenMPT/soundlib/pattern.cpp | 19 ++- Frameworks/OpenMPT/OpenMPT/soundlib/pattern.h | 2 + .../soundlib/plugins/PluginManager.cpp | 23 +-- .../OpenMPT/src/mpt/base/detect_arch.hpp | 2 +- .../OpenMPT/src/mpt/base/detect_compiler.hpp | 14 +- .../OpenMPT/src/mpt/base/detect_os.hpp | 31 ++-- .../OpenMPT/src/mpt/base/detect_quirks.hpp | 6 + .../OpenMPT/OpenMPT/src/mpt/base/math.hpp | 6 +- .../OpenMPT/OpenMPT/src/mpt/base/numbers.hpp | 5 +- .../src/mpt/osinfo/windows_version.hpp | 16 +- .../OpenMPT/OpenMPT/src/mpt/random/device.hpp | 1 + .../OpenMPT/OpenMPT/src/mpt/random/engine.hpp | 13 +- .../OpenMPT/OpenMPT/src/mpt/random/random.hpp | 3 + .../OpenMPT/OpenMPT/src/mpt/string/buffer.hpp | 1 + Info.plist.template | 1 + 61 files changed, 684 insertions(+), 336 deletions(-) diff --git a/Frameworks/OpenMPT/OpenMPT/Makefile b/Frameworks/OpenMPT/OpenMPT/Makefile index 72ba8a0f5..d8936835a 100644 --- a/Frameworks/OpenMPT/OpenMPT/Makefile +++ b/Frameworks/OpenMPT/OpenMPT/Makefile @@ -66,6 +66,7 @@ # ONLY_TEST=0 Only build the test suite. # STRICT=0 Treat warnings as errors. # MODERN=0 Pass more modern compiler options. +# ANCIENT=0 Pass compiler options compatible with older versions. # NATIVE=0 Optimize for system CPU. # STDCXX=c++17 C++ standard version (default depends on compiler) # STDC=c17 C standard version (default depends on compiler) @@ -975,6 +976,7 @@ endif CPPCHECK_FLAGS += -j $(NUMTHREADS) CPPCHECK_FLAGS += --std=c11 --std=c++17 +CPPCHECK_FLAGS += --library=build/cppcheck/glibc-workarounds.cfg CPPCHECK_FLAGS += --quiet CPPCHECK_FLAGS += --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' CPPCHECK_FLAGS += --check-level=exhaustive @@ -1083,11 +1085,15 @@ CPPFLAGS += -DLIBOPENMPT_BUILD COMMON_CXX_SOURCES += \ + $(sort $(wildcard src/openmpt/all/*.cpp)) \ + $(sort $(wildcard src/openmpt/base/*.cpp)) \ + $(sort $(wildcard src/openmpt/logging/*.cpp)) \ + $(sort $(wildcard src/openmpt/random/*.cpp)) \ $(sort $(wildcard common/*.cpp)) \ - $(sort $(wildcard src/mpt/src/*.cpp)) \ SOUNDLIB_CXX_SOURCES += \ $(COMMON_CXX_SOURCES) \ + $(sort $(wildcard src/openmpt/soundbase/*.cpp)) \ $(sort $(wildcard soundlib/*.cpp)) \ $(sort $(wildcard soundlib/plugins/*.cpp)) \ $(sort $(wildcard soundlib/plugins/dmo/*.cpp)) \ @@ -1731,6 +1737,7 @@ bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION).msvc.zip: bin/$ svn export ./build/scriptlib bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/scriptlib --native-eol CRLF svn export ./build/svn_version bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/svn_version --native-eol CRLF svn export ./build/vs bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs --native-eol CRLF + svn export ./build/vs2017winxpansi bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2017winxpansi --native-eol CRLF svn export ./build/vs2017winxp bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2017winxp --native-eol CRLF svn export ./build/vs2019win7 bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2019win7 --native-eol CRLF svn export ./build/vs2019win81 bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2019win81 --native-eol CRLF @@ -1866,6 +1873,11 @@ else svn export ./include/miniz/miniz.c bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/MINIZ.TXT --native-eol CRLF svn export ./include/stb_vorbis/stb_vorbis.c bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/STBVORB.TXT --native-eol CRLF endif + mkdir -p bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/DJGPP + cp $(shell dirname $(shell which i386-pc-msdosdjgpp-gcc))/../license/copying bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/DJGPP/COPYING + cp $(shell dirname $(shell which i386-pc-msdosdjgpp-gcc))/../license/copying.dj bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/DJGPP/COPYING.DJ + cp $(shell dirname $(shell which i386-pc-msdosdjgpp-gcc))/../license/copying.lib bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/DJGPP/COPYING.LIB + cp $(shell dirname $(shell which i386-pc-msdosdjgpp-gcc))/../license/source.txt bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/DJGPP/SOURCE.TXT mkdir -p bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/SRC cp build/externals/csdpmi7s.zip bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/SRC/CSDPMI7S.ZIP mkdir -p bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN diff --git a/Frameworks/OpenMPT/OpenMPT/build/android_ndk/Android.mk b/Frameworks/OpenMPT/OpenMPT/build/android_ndk/Android.mk index debfb4a53..bdbd8a535 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/android_ndk/Android.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/android_ndk/Android.mk @@ -6,8 +6,45 @@ include $(CLEAR_VARS) LOCAL_MODULE := openmpt +ifeq ($(NDK_MAJOR),) LOCAL_CFLAGS += -std=c17 -LOCAL_CPPFLAGS += -std=c++17 -fexceptions -frtti +LOCAL_CPPFLAGS += -std=c++17 +else +ifeq ($(NDK_MAJOR),21) +# clang 9 +LOCAL_CFLAGS += -std=c17 +LOCAL_CPPFLAGS += -std=c++17 +else ifeq ($(NDK_MAJOR),22) +# clang 11 +LOCAL_CFLAGS += -std=c17 +LOCAL_CPPFLAGS += -std=c++20 +else ifeq ($(NDK_MAJOR),23) +# clang 12 +LOCAL_CFLAGS += -std=c17 +LOCAL_CPPFLAGS += -std=c++20 +else ifeq ($(NDK_MAJOR),24) +# clang 14 +LOCAL_CFLAGS += -std=c17 +LOCAL_CPPFLAGS += -std=c++20 +else ifeq ($(NDK_MAJOR),25) +# clang 14 +LOCAL_CFLAGS += -std=c17 +LOCAL_CPPFLAGS += -std=c++20 +else ifeq ($(NDK_MAJOR),26) +# clang 17 +LOCAL_CFLAGS += -std=c17 +LOCAL_CPPFLAGS += -std=c++20 +else ifeq ($(NDK_MAJOR),27) +# clang 18 +LOCAL_CFLAGS += -std=c17 +LOCAL_CPPFLAGS += -std=c++20 +else +LOCAL_CFLAGS += -std=c17 +LOCAL_CPPFLAGS += -std=c++20 +endif +endif + +LOCAL_CPPFLAGS += -fexceptions -frtti LOCAL_CPP_FEATURES += exceptions rtti diff --git a/Frameworks/OpenMPT/OpenMPT/build/android_ndk/Application.mk b/Frameworks/OpenMPT/OpenMPT/build/android_ndk/Application.mk index cf1ba4256..d0f0e2418 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/android_ndk/Application.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/android_ndk/Application.mk @@ -1,6 +1,42 @@ +ifeq ($(NDK_MAJOR),) APP_CFLAGS := -std=c17 APP_CPPFLAGS := -std=c++17 -fexceptions -frtti +else +ifeq ($(NDK_MAJOR),21) +# clang 9 +APP_CFLAGS := -std=c17 +APP_CPPFLAGS := -std=c++17 -fexceptions -frtti +else ifeq ($(NDK_MAJOR),22) +# clang 11 +APP_CFLAGS := -std=c17 +APP_CPPFLAGS := -std=c++20 -fexceptions -frtti +else ifeq ($(NDK_MAJOR),23) +# clang 12 +APP_CFLAGS := -std=c17 +APP_CPPFLAGS := -std=c++20 -fexceptions -frtti +else ifeq ($(NDK_MAJOR),24) +# clang 14 +APP_CFLAGS := -std=c17 +APP_CPPFLAGS := -std=c++20 -fexceptions -frtti +else ifeq ($(NDK_MAJOR),25) +# clang 14 +APP_CFLAGS := -std=c17 +APP_CPPFLAGS := -std=c++20 -fexceptions -frtti +else ifeq ($(NDK_MAJOR),26) +# clang 17 +APP_CFLAGS := -std=c17 +APP_CPPFLAGS := -std=c++20 -fexceptions -frtti +else ifeq ($(NDK_MAJOR),27) +# clang 18 +APP_CFLAGS := -std=c17 +APP_CPPFLAGS := -std=c++20 -fexceptions -frtti +else +APP_CFLAGS := -std=c17 +APP_CPPFLAGS := -std=c++20 -fexceptions -frtti +endif +endif + APP_LDFLAGS := APP_STL := c++_shared diff --git a/Frameworks/OpenMPT/OpenMPT/build/dist.mk b/Frameworks/OpenMPT/OpenMPT/build/dist.mk index 22d18d1aa..9a8f1c9f4 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/dist.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/dist.mk @@ -1,4 +1,4 @@ -MPT_SVNVERSION=21223 -MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.7.9 -MPT_SVNDATE=2024-07-21T12:01:13.335584Z +MPT_SVNVERSION=21953 +MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.7.11 +MPT_SVNDATE=2024-10-26T13:09:27.804941Z diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-emscripten.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-emscripten.mk index 5adb9fb82..6f04c7522 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-emscripten.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-emscripten.mk @@ -1,9 +1,9 @@ ifeq ($(origin CC),default) -CC = emcc -c +CC = emcc endif ifeq ($(origin CXX),default) -CXX = em++ -c +CXX = em++ endif ifeq ($(origin LD),default) LD = em++ diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/warnings-clang.mk b/Frameworks/OpenMPT/OpenMPT/build/make/warnings-clang.mk index 10694a72a..7954bdec8 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/warnings-clang.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/warnings-clang.mk @@ -2,8 +2,13 @@ CXXFLAGS_WARNINGS += -Wcast-align -Wcast-qual -Wdouble-promotion -Wfloat-conversion -Wmissing-prototypes -Wshift-count-negative -Wshift-count-overflow -Wshift-op-parentheses -Wshift-overflow -Wshift-sign-overflow -Wundef CFLAGS_WARNINGS += -Wcast-align -Wcast-qual -Wdouble-promotion -Wfloat-conversion -Wmissing-prototypes -Wshift-count-negative -Wshift-count-overflow -Wshift-op-parentheses -Wshift-overflow -Wshift-sign-overflow -Wundef -CXXFLAGS_WARNINGS += -Wdeprecated -Wextra-semi -Wframe-larger-than=16000 -Wglobal-constructors -Wimplicit-fallthrough -Wmissing-declarations -Wnon-virtual-dtor -Wreserved-id-macro -CFLAGS_WARNINGS += -Wframe-larger-than=4000 +CXXFLAGS_WARNINGS += -Wdeprecated -Wextra-semi -Wglobal-constructors -Wimplicit-fallthrough -Wmissing-declarations -Wnon-virtual-dtor -Wreserved-id-macro +CFLAGS_WARNINGS += + +ifneq ($(ANCIENT),1) +CXXFLAGS_WARNINGS += -Wframe-larger-than=16000 +CFLAGS_WARNINGS += -Wframe-larger-than=4000 +endif #CXXFLAGS_WARNINGS += -Wfloat-equal #CXXFLAGS_WARNINGS += -Wdocumentation @@ -21,10 +26,14 @@ CFLAGS_SILENT += -Wno-cast-align CFLAGS_SILENT += -Wno-cast-qual CFLAGS_SILENT += -Wno-double-promotion CFLAGS_SILENT += -Wno-float-conversion +ifneq ($(ANCIENT),1) CFLAGS_SILENT += -Wno-frame-larger-than +endif CFLAGS_SILENT += -Wno-missing-prototypes CFLAGS_SILENT += -Wno-sign-compare +ifneq ($(ANCIENT),1) CFLAGS_SILENT += -Wno-unused-but-set-variable +endif CFLAGS_SILENT += -Wno-unused-function CFLAGS_SILENT += -Wno-unused-parameter CFLAGS_SILENT += -Wno-unused-variable diff --git a/Frameworks/OpenMPT/OpenMPT/build/svn_version/svn_version.h b/Frameworks/OpenMPT/OpenMPT/build/svn_version/svn_version.h index 5be42958a..6990a182d 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 "21223" -#define OPENMPT_VERSION_REVISION 21223 +#define OPENMPT_VERSION_SVNVERSION "21953" +#define OPENMPT_VERSION_REVISION 21953 #define OPENMPT_VERSION_DIRTY 0 #define OPENMPT_VERSION_MIXEDREVISIONS 0 -#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.7.9" -#define OPENMPT_VERSION_DATE "2024-07-21T12:01:13.335584Z" +#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.7.11" +#define OPENMPT_VERSION_DATE "2024-10-26T13:09:27.804941Z" #define OPENMPT_VERSION_IS_PACKAGE 1 diff --git a/Frameworks/OpenMPT/OpenMPT/common/BuildSettings.h b/Frameworks/OpenMPT/OpenMPT/common/BuildSettings.h index 385ad28dc..0e38ab298 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/BuildSettings.h +++ b/Frameworks/OpenMPT/OpenMPT/common/BuildSettings.h @@ -20,6 +20,7 @@ +#include "mpt/base/detect_arch.hpp" #include "mpt/base/detect_compiler.hpp" #include "mpt/base/detect_os.hpp" #include "mpt/base/detect_quirks.hpp" @@ -229,14 +230,14 @@ #endif #if defined(MPT_ENABLE_ARCH_INTRINSICS) -#if MPT_COMPILER_MSVC && defined(_M_IX86) +#if MPT_COMPILER_MSVC && MPT_ARCH_X86 #define MPT_ENABLE_ARCH_X86 #define MPT_ENABLE_ARCH_INTRINSICS_SSE #define MPT_ENABLE_ARCH_INTRINSICS_SSE2 -#elif MPT_COMPILER_MSVC && defined(_M_X64) +#elif MPT_COMPILER_MSVC && MPT_ARCH_AMD64 #define MPT_ENABLE_ARCH_AMD64 diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptBaseUtils.h b/Frameworks/OpenMPT/OpenMPT/common/mptBaseUtils.h index 2f4409950..f1ea48896 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptBaseUtils.h +++ b/Frameworks/OpenMPT/OpenMPT/common/mptBaseUtils.h @@ -18,6 +18,8 @@ #include "mpt/base/array.hpp" #include "mpt/base/bit.hpp" #include "mpt/base/constexpr_throw.hpp" +#include "mpt/base/detect_arch.hpp" +#include "mpt/base/detect_compiler.hpp" #include "mpt/base/math.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/numeric.hpp" @@ -115,7 +117,7 @@ namespace Util { // MSVC generates unnecessarily complicated code for the unoptimized variant using _allmul. MPT_CONSTEXPR20_FUN int64 mul32to64(int32 a, int32 b) { - #if MPT_COMPILER_MSVC && (defined(_M_IX86) || defined(_M_X64)) + #if MPT_COMPILER_MSVC && (MPT_ARCH_X86 || MPT_ARCH_AMD64) MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return static_cast(a) * b; @@ -130,7 +132,7 @@ namespace Util { MPT_CONSTEXPR20_FUN uint64 mul32to64_unsigned(uint32 a, uint32 b) { - #if MPT_COMPILER_MSVC && (defined(_M_IX86) || defined(_M_X64)) + #if MPT_COMPILER_MSVC && (MPT_ARCH_X86 || MPT_ARCH_AMD64) MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return static_cast(a) * b; diff --git a/Frameworks/OpenMPT/OpenMPT/common/version.cpp b/Frameworks/OpenMPT/OpenMPT/common/version.cpp index ee4f0e8f1..6e47945bd 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/version.cpp +++ b/Frameworks/OpenMPT/OpenMPT/common/version.cpp @@ -615,9 +615,11 @@ mpt::ustring GetFullCreditsString() "\n" "Additional contributors:\n" "coda (https://coda.s3m.us/)\n" + "cs127 (https://cs127.github.io/)\n" "Jo\xC3\xA3o Baptista de Paula e Silva (https://joaobapt.com/)\n" "kode54 (https://kode54.net/)\n" "Revenant (https://revenant1.net/)\n" + "SYRiNX\n" "xaimus (http://xaimus.com/)\n" "\n" "Thanks to:\n" diff --git a/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h b/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h index ca83290bc..bc351c444 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 31 -#define VER_MINOR 09 +#define VER_MINOR 11 #define VER_MINORMINOR 00 OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/include/minimp3/OpenMPT.txt b/Frameworks/OpenMPT/OpenMPT/include/minimp3/OpenMPT.txt index ff728e876..e2b1ad6de 100644 --- a/Frameworks/OpenMPT/OpenMPT/include/minimp3/OpenMPT.txt +++ b/Frameworks/OpenMPT/OpenMPT/include/minimp3/OpenMPT.txt @@ -1,6 +1,12 @@ minimp3 library from https://github.com/lieff/minimp3 -commit 50d2aaf360a53653b718fead8e258d654c3a7e41 (2021-11-27) +Fork https://github.com/manxorist/minimp3/releases/tag/openmpt-2024-08-15-v4 +commit 2116754771b79347ad2f39127abace2a093c383e (2024-08-15) The following changes have been made: * minimp3.c has been added - * some warnings have been fixed + * The following pull rquests have been merged: + * https://github.com/lieff/minimp3/pull/126 + * https://github.com/lieff/minimp3/pull/96 + * https://github.com/lieff/minimp3/pull/97 + * https://github.com/lieff/minimp3/pull/125 + * https://github.com/lieff/minimp3/pull/127 * all modifications are marked by /* OpenMPT */ diff --git a/Frameworks/OpenMPT/OpenMPT/include/minimp3/minimp3.h b/Frameworks/OpenMPT/OpenMPT/include/minimp3/minimp3.h index 0ed72088f..620797b87 100644 --- a/Frameworks/OpenMPT/OpenMPT/include/minimp3/minimp3.h +++ b/Frameworks/OpenMPT/OpenMPT/include/minimp3/minimp3.h @@ -8,6 +8,10 @@ */ #include +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + #define MINIMP3_MAX_SAMPLES_PER_FRAME (1152*2) typedef struct @@ -22,10 +26,6 @@ typedef struct unsigned char header[4], reserv_buf[511]; } mp3dec_t; -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - void mp3dec_init(mp3dec_t *dec); #ifndef MINIMP3_FLOAT_OUTPUT typedef int16_t mp3d_sample_t; @@ -176,11 +176,7 @@ end: #define VMUL_S(x, s) vmulq_f32(x, vmovq_n_f32(s)) #define VREV(x) vcombine_f32(vget_high_f32(vrev64q_f32(x)), vget_low_f32(vrev64q_f32(x))) typedef float32x4_t f4; -#if 1 /* OpenMPT */ static int have_simd(void) -#else /* OpenMPT */ -static int have_simd() -#endif /* OpenMPT */ { /* TODO: detect neon for !MINIMP3_ONLY_SIMD */ return 1; } @@ -195,7 +191,7 @@ static int have_simd() #define HAVE_SIMD 0 #endif /* !defined(MINIMP3_NO_SIMD) */ -#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) +#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) && !defined(__ARM_ARCH_6M__) #define HAVE_ARMV6 1 static __inline__ __attribute__((always_inline)) int32_t minimp3_clip_int16_arm(int32_t a) { @@ -945,7 +941,8 @@ static void L3_stereo_top_band(const float *right, const uint8_t *sfb, int nband static void L3_stereo_process(float *left, const uint8_t *ist_pos, const uint8_t *sfb, const uint8_t *hdr, int max_band[3], int mpeg2_sh) { static const float g_pan[7*2] = { 0,1,0.21132487f,0.78867513f,0.36602540f,0.63397460f,0.5f,0.5f,0.63397460f,0.36602540f,0.78867513f,0.21132487f,1,0 }; - unsigned i, max_pos = HDR_TEST_MPEG1(hdr) ? 7 : 64; + const uint8_t mpeg1 = HDR_TEST_MPEG1(hdr); + unsigned i, max_pos = mpeg1 ? 7 : 64; for (i = 0; sfb[i]; i++) { @@ -953,7 +950,7 @@ static void L3_stereo_process(float *left, const uint8_t *ist_pos, const uint8_t if ((int)i > max_band[i % 3] && ipos < max_pos) { float kl, kr, s = HDR_TEST_MS_STEREO(hdr) ? 1.41421356f : 1; - if (HDR_TEST_MPEG1(hdr)) + if (mpeg1) { kl = g_pan[2*ipos]; kr = g_pan[2*ipos + 1]; @@ -1658,6 +1655,21 @@ static void mp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int n } } +static int hdr_is_tag(const uint8_t* hdr) +{ + return hdr[0] == 'T' && hdr[1] == 'A' && hdr[2] == 'G' && hdr[3] == '\0'; +} + +static int hdr_is_null(const uint8_t* hdr) +{ + return hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\0' && hdr[3] == '\0'; +} + +static int hdr_is_null_or_tag(const uint8_t* hdr) +{ + return hdr_is_tag(hdr) > 0 || hdr_is_null(hdr) > 0; +} + static int mp3d_match_frame(const uint8_t *hdr, int mp3_bytes, int frame_bytes) { int i, nmatch; @@ -1666,6 +1678,8 @@ static int mp3d_match_frame(const uint8_t *hdr, int mp3_bytes, int frame_bytes) i += hdr_frame_bytes(hdr + i, frame_bytes) + hdr_padding(hdr + i); if (i + HDR_SIZE > mp3_bytes) return nmatch > 0; + if (hdr_is_null_or_tag(hdr + i)) + return nmatch > 0; if (!hdr_compare(hdr, hdr + i)) return 0; } @@ -1773,7 +1787,7 @@ int mp3dec_decode_frame(mp3dec_t *dec, const uint8_t *mp3, int mp3_bytes, mp3d_s { for (igr = 0; igr < (HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm += 576*info->channels) { - memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + memset(scratch.grbuf, 0, sizeof(scratch.grbuf)); L3_decode(dec, &scratch, scratch.gr_info + igr*info->channels, info->channels); mp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, pcm, scratch.syn[0]); } @@ -1787,7 +1801,7 @@ int mp3dec_decode_frame(mp3dec_t *dec, const uint8_t *mp3, int mp3_bytes, mp3d_s L12_scale_info sci[1]; L12_read_scale_info(hdr, bs_frame, sci); - memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + memset(scratch.grbuf, 0, sizeof(scratch.grbuf)); for (i = 0, igr = 0; igr < 3; igr++) { if (12 == (i += L12_dequantize_granule(scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1))) @@ -1795,7 +1809,7 @@ int mp3dec_decode_frame(mp3dec_t *dec, const uint8_t *mp3, int mp3_bytes, mp3d_s i = 0; L12_apply_scf_384(sci, sci->scf + igr, scratch.grbuf[0]); mp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, pcm, scratch.syn[0]); - memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + memset(scratch.grbuf, 0, sizeof(scratch.grbuf)); pcm += 384*info->channels; } if (bs_frame->pos > bs_frame->limit) diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h index 0d5cb867b..f64a0f7dc 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h @@ -21,7 +21,7 @@ /*! \brief libopenmpt minor version number */ #define OPENMPT_API_VERSION_MINOR 7 /*! \brief libopenmpt patch version number */ -#define OPENMPT_API_VERSION_PATCH 9 +#define OPENMPT_API_VERSION_PATCH 11 /*! \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 4c43a00ce..81742762e 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=7 -LIBOPENMPT_VERSION_PATCH=9 +LIBOPENMPT_VERSION_PATCH=11 LIBOPENMPT_VERSION_PREREL= LIBOPENMPT_LTVER_CURRENT=4 -LIBOPENMPT_LTVER_REVISION=9 +LIBOPENMPT_LTVER_REVISION=11 LIBOPENMPT_LTVER_AGE=4 diff --git a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.cpp b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.cpp index c81da2745..610603d16 100644 --- a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.cpp +++ b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.cpp @@ -2203,8 +2203,8 @@ static int wmain( int wargc, wchar_t * wargv [] ) { static int main( int argc, char * argv [] ) { #endif #if MPT_OS_DJGPP - _crt0_startup_flags &= ~_CRT0_FLAG_LOCK_MEMORY; /* disable automatic locking for all further memory allocations */ assert(mpt::platform::libc().is_ok()); + _crt0_startup_flags &= ~_CRT0_FLAG_LOCK_MEMORY; /* disable automatic locking for all further memory allocations */ #endif /* MPT_OS_DJGPP */ std::vector args; #if MPT_OS_WINDOWS && defined(UNICODE) @@ -2301,6 +2301,10 @@ static int main( int argc, char * argv [] ) { return 0; } catch ( silent_exit_exception & ) { return 0; + } catch ( exception & e ) { + std_err << MPT_USTRING("error: ") << mpt::get_exception_text( e ) << lf; + std_err.writeout(); + return 1; } catch ( std::exception & e ) { std_err << MPT_USTRING("error: ") << mpt::get_exception_text( e ) << lf; std_err.writeout(); @@ -2468,6 +2472,10 @@ static int main( int argc, char * argv [] ) { #endif } catch ( silent_exit_exception & ) { return 0; + } catch ( exception & e ) { + std_err << MPT_USTRING("error: ") << mpt::get_exception_text( e ) << lf; + std_err.writeout(); + return 1; } catch ( std::exception & e ) { std_err << MPT_USTRING("error: ") << mpt::get_exception_text( e ) << lf; std_err.writeout(); diff --git a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.hpp b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.hpp index f585915d8..92542821e 100644 --- a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.hpp +++ b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.hpp @@ -33,6 +33,8 @@ #include +#include + namespace mpt { inline namespace MPT_INLINE_NS { diff --git a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_sndfile.hpp b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_sndfile.hpp index 550c83d49..d4efb31fc 100644 --- a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_sndfile.hpp +++ b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_sndfile.hpp @@ -117,7 +117,7 @@ private: case match_recurse: break; case match_exact: - if ( mpt::transcode( mpt::common_encoding::utf8, extension ) == format_info.extension ) { + if ( mpt::transcode( sndfile_encoding, extension ) == format_info.extension ) { if ( flags.use_float && ( subformat_info.format == SF_FORMAT_FLOAT ) ) { return matched_result( format, format_info, subformat_info, match_mode ); } else if ( !flags.use_float && ( subformat_info.format == SF_FORMAT_PCM_16 ) ) { @@ -126,7 +126,7 @@ private: } break; case match_better: - if ( mpt::transcode( mpt::common_encoding::utf8, extension ) == format_info.extension ) { + if ( mpt::transcode( sndfile_encoding, extension ) == format_info.extension ) { if ( flags.use_float && ( subformat_info.format == SF_FORMAT_FLOAT || subformat_info.format == SF_FORMAT_DOUBLE ) ) { return matched_result( format, format_info, subformat_info, match_mode ); } else if ( !flags.use_float && ( subformat_info.format & ( subformat_info.format == SF_FORMAT_PCM_16 || subformat_info.format == SF_FORMAT_PCM_24 || subformat_info.format == SF_FORMAT_PCM_32 ) ) ) { @@ -135,7 +135,7 @@ private: } break; case match_any: - if ( mpt::transcode( mpt::common_encoding::utf8, extension ) == format_info.extension ) { + if ( mpt::transcode( sndfile_encoding, extension ) == format_info.extension ) { return matched_result( format, format_info, subformat_info, match_mode ); } break; diff --git a/Frameworks/OpenMPT/OpenMPT/sounddsp/EQ.cpp b/Frameworks/OpenMPT/OpenMPT/sounddsp/EQ.cpp index 7ecb7e83b..abf308c38 100644 --- a/Frameworks/OpenMPT/OpenMPT/sounddsp/EQ.cpp +++ b/Frameworks/OpenMPT/OpenMPT/sounddsp/EQ.cpp @@ -31,6 +31,9 @@ #include #if defined(MPT_ENABLE_ARCH_INTRINSICS_SSE) +#if MPT_COMPILER_MSVC +#include +#endif #include #endif diff --git a/Frameworks/OpenMPT/OpenMPT/sounddsp/Reverb.cpp b/Frameworks/OpenMPT/OpenMPT/sounddsp/Reverb.cpp index 36b47a180..bf2cae4ff 100644 --- a/Frameworks/OpenMPT/OpenMPT/sounddsp/Reverb.cpp +++ b/Frameworks/OpenMPT/OpenMPT/sounddsp/Reverb.cpp @@ -20,6 +20,9 @@ #include "mpt/base/numbers.hpp" #if defined(MPT_ENABLE_ARCH_INTRINSICS_SSE2) +#if MPT_COMPILER_MSVC +#include +#endif #include #endif diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp index cf411a787..8a4eca312 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp @@ -616,15 +616,22 @@ CDLSBank::CDLSBank() bool CDLSBank::IsDLSBank(const mpt::PathString &filename) { - RIFFChunkID riff; - if(filename.empty()) return false; - mpt::ifstream f(filename, std::ios::binary); - if(!f) - { + if(filename.empty()) return false; - } - MemsetZero(riff); - mpt::IO::Read(f, riff); + mpt::IO::InputFile f(filename, false); + if(!f.IsValid()) + return false; + return IsDLSBank(GetFileReader(f)); +} + + +bool CDLSBank::IsDLSBank(FileReader file) +{ + file.Rewind(); + RIFFChunkID riff; + if(!file.ReadStruct(riff)) + return false; + // Check for embedded DLS sections if(riff.id_RIFF == IFFID_FORM) { @@ -632,28 +639,31 @@ bool CDLSBank::IsDLSBank(const mpt::PathString &filename) do { uint32 len = mpt::bit_cast(riff.riff_len); - if (len <= 4) break; - if (riff.id_DLS == IFFID_XDLS) + if(len <= 4) break; + if(riff.id_DLS == IFFID_XDLS) { - mpt::IO::Read(f, riff); - break; + if(!file.ReadStruct(riff)) + return false; + break; // found it } if((len % 2u) != 0) len++; - if (!mpt::IO::SeekRelative(f, len-4)) break; - } while (mpt::IO::Read(f, riff)); + if(!file.Skip(len - 4)) + return false; + } while(file.ReadStruct(riff)); } else if(riff.id_RIFF == IFFID_RIFF && riff.id_DLS == IFFID_RMID) { for (;;) { - if(!mpt::IO::Read(f, riff)) - break; - if (riff.id_DLS == IFFID_DLS) - break; // found it + if(!file.ReadStruct(riff)) + return false; + if(riff.id_DLS == IFFID_DLS || riff.id_DLS == IFFID_sfbk) + break; // found it int len = riff.riff_len; if((len % 2u) != 0) len++; - if ((len <= 4) || !mpt::IO::SeekRelative(f, len-4)) break; + if((len <= 4) || !file.Skip(len - 4)) + return false; } } return ((riff.id_RIFF == IFFID_RIFF) @@ -733,7 +743,7 @@ const DLSINSTRUMENT *CDLSBank::FindInstrument(bool isDrum, uint32 bank, uint32 p } -bool CDLSBank::FindAndExtract(CSoundFile &sndFile, const INSTRUMENTINDEX ins, const bool isDrum) const +bool CDLSBank::FindAndExtract(CSoundFile &sndFile, const INSTRUMENTINDEX ins, const bool isDrum, FileReader *file) const { ModInstrument *pIns = sndFile.Instruments[ins]; if(pIns == nullptr) @@ -747,7 +757,7 @@ bool CDLSBank::FindAndExtract(CSoundFile &sndFile, const INSTRUMENTINDEX ins, co || FindInstrument(isDrum, 0xFFFF, isDrum ? 0xFF : program, key, &dlsIns)) { if(key < 0x80) drumRgn = GetRegionFromKey(dlsIns, key); - if(ExtractInstrument(sndFile, ins, dlsIns, drumRgn)) + if(ExtractInstrument(sndFile, ins, dlsIns, drumRgn, file)) { pIns = sndFile.Instruments[ins]; // Reset pointer because ExtractInstrument may delete the previous value. if((key >= 24) && (key < 24 + std::size(szMidiPercussionNames))) @@ -1394,7 +1404,7 @@ bool CDLSBank::Open(const mpt::PathString &filename) { if(filename.empty()) return false; m_szFileName = filename; - mpt::IO::InputFile f(filename, SettingCacheCompleteFileBeforeLoading()); + mpt::IO::InputFile f(filename, false); if(!f.IsValid()) return false; return Open(GetFileReader(f)); } @@ -1408,12 +1418,8 @@ bool CDLSBank::Open(FileReader file) m_szFileName = file.GetOptionalFileName().value(); file.Rewind(); - size_t dwMemLength = file.GetLength(); - size_t dwMemPos = 0; if(!file.CanRead(256)) - { return false; - } RIFFChunkID riff; file.ReadStruct(riff); @@ -1422,11 +1428,9 @@ bool CDLSBank::Open(FileReader file) { while(file.ReadStruct(riff)) { - if(riff.id_RIFF == IFFID_RIFF && riff.id_DLS == IFFID_DLS) - { - file.SkipBack(sizeof(riff)); + if(riff.id_RIFF == IFFID_RIFF && (riff.id_DLS == IFFID_DLS || riff.id_DLS == IFFID_sfbk)) break; - } + uint32 len = riff.riff_len; if((len % 2u) != 0) len++; @@ -1469,13 +1473,12 @@ bool CDLSBank::Open(FileReader file) m_WaveForms.clear(); m_Envelopes.clear(); nInsDef = 0; - if (dwMemLength > 8 + riff.riff_len + dwMemPos) dwMemLength = 8 + riff.riff_len + dwMemPos; bool applyPaddingToSampleChunk = true; while(file.CanRead(sizeof(IFFCHUNK))) { IFFCHUNK chunkHeader; file.ReadStruct(chunkHeader); - dwMemPos = file.GetPosition(); + const auto chunkStartPos = file.GetPosition(); FileReader chunk = file.ReadChunk(chunkHeader.len); bool applyPadding = (chunkHeader.len % 2u) != 0; @@ -1531,7 +1534,7 @@ bool CDLSBank::Open(FileReader file) if (((listid == IFFID_wvpl) && (m_nType & SOUNDBANK_TYPE_DLS)) || ((listid == IFFID_sdta) && (m_nType & SOUNDBANK_TYPE_SF2))) { - m_dwWavePoolOffset = dwMemPos + 4; + m_dwWavePoolOffset = chunkStartPos + 4; #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", MPT_UFORMAT("Wave Pool offset: {}")(m_dwWavePoolOffset)); #endif @@ -1686,17 +1689,16 @@ uint32 CDLSBank::GetRegionFromKey(uint32 nIns, uint32 nKey) const } -bool CDLSBank::ExtractWaveForm(uint32 nIns, uint32 nRgn, std::vector &waveData, uint32 &length) const +std::vector CDLSBank::ExtractWaveForm(uint32 nIns, uint32 nRgn, FileReader *file) const { - waveData.clear(); - length = 0; + std::vector waveData; if (nIns >= m_Instruments.size() || !m_dwWavePoolOffset) { #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", MPT_UFORMAT("ExtractWaveForm({}) failed: m_Instruments.size()={} m_dwWavePoolOffset={} m_WaveForms.size()={}")(nIns, m_Instruments.size(), m_dwWavePoolOffset, m_WaveForms.size())); #endif - return false; + return waveData; } const DLSINSTRUMENT &dlsIns = m_Instruments[nIns]; if(nRgn >= dlsIns.Regions.size()) @@ -1704,7 +1706,7 @@ bool CDLSBank::ExtractWaveForm(uint32 nIns, uint32 nRgn, std::vector &wav #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", MPT_UFORMAT("invalid waveform region: nIns={} nRgn={} pSmp->nRegions={}")(nIns, nRgn, dlsIns.Regions.size())); #endif - return false; + return waveData; } uint32 nWaveLink = dlsIns.Regions[nRgn].nWaveLink; if(nWaveLink >= m_WaveForms.size()) @@ -1712,29 +1714,34 @@ bool CDLSBank::ExtractWaveForm(uint32 nIns, uint32 nRgn, std::vector &wav #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", MPT_UFORMAT("Invalid wavelink id: nWaveLink={} nWaveForms={}")(nWaveLink, m_WaveForms.size())); #endif - return false; + return waveData; } - mpt::ifstream f(m_szFileName, std::ios::binary); - if(!f) + std::unique_ptr inputFile; + FileReader f; + if(file) { - return false; + f = *file; + } else + { + inputFile = std::make_unique(m_szFileName, false); + if(!inputFile->IsValid()) + return waveData; + f = GetFileReader(*inputFile); } - mpt::IO::Offset sampleOffset = mpt::saturate_cast(m_WaveForms[nWaveLink] + m_dwWavePoolOffset); - if(mpt::IO::SeekAbsolute(f, sampleOffset)) + auto sampleOffset = mpt::saturate_cast(m_WaveForms[nWaveLink] + m_dwWavePoolOffset); + if(f.Seek(sampleOffset)) { if (m_nType & SOUNDBANK_TYPE_SF2) { if (m_SamplesEx[nWaveLink].dwLen) { - if (mpt::IO::SeekRelative(f, 8)) + if (f.Skip(8)) { - length = m_SamplesEx[nWaveLink].dwLen; try { - waveData.assign(length + 8, 0); - mpt::IO::ReadRaw(f, waveData.data(), length); + f.ReadVector(waveData, m_SamplesEx[nWaveLink].dwLen); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); @@ -1744,16 +1751,14 @@ bool CDLSBank::ExtractWaveForm(uint32 nIns, uint32 nRgn, std::vector &wav } else { LISTChunk chunk; - if(mpt::IO::Read(f, chunk)) + if(f.ReadStruct(chunk)) { if((chunk.id == IFFID_LIST) && (chunk.listid == IFFID_wave) && (chunk.len > 4)) { - length = chunk.len + 8; try { - waveData.assign(chunk.len + sizeof(IFFCHUNK), 0); - memcpy(waveData.data(), &chunk, sizeof(chunk)); - mpt::IO::ReadRaw(f, waveData.data() + sizeof(chunk), length - sizeof(chunk)); + f.SkipBack(sizeof(chunk)); + f.ReadVector(waveData, chunk.len + sizeof(IFFCHUNK)); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); @@ -1762,14 +1767,12 @@ bool CDLSBank::ExtractWaveForm(uint32 nIns, uint32 nRgn, std::vector &wav } } } - return !waveData.empty(); + return waveData; } -bool CDLSBank::ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nIns, uint32 nRgn, int transpose) const +bool CDLSBank::ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nIns, uint32 nRgn, int transpose, FileReader *file) const { - std::vector pWaveForm; - uint32 dwLen = 0; bool ok, hasWaveform; if(nIns >= m_Instruments.size()) @@ -1777,9 +1780,8 @@ bool CDLSBank::ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nI const DLSINSTRUMENT &dlsIns = m_Instruments[nIns]; if(nRgn >= dlsIns.Regions.size()) return false; - if(!ExtractWaveForm(nIns, nRgn, pWaveForm, dwLen)) - return false; - if(dwLen < 16) + const std::vector waveData = ExtractWaveForm(nIns, nRgn, file); + if(waveData.size() < 16) return false; ok = false; @@ -1798,10 +1800,10 @@ bool CDLSBank::ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nI #endif sample.Initialize(); - FileReader chunk{mpt::as_span(pWaveForm.data(), dwLen)}; + FileReader chunk{mpt::as_span(waveData)}; if(!p.compressed || !sndFile.ReadSampleFromFile(nSample, chunk, false, false)) { - sample.nLength = dwLen / 2; + sample.nLength = mpt::saturate_cast(waveData.size() / 2); SampleIO( SampleIO::_16bit, SampleIO::mono, @@ -1822,8 +1824,8 @@ bool CDLSBank::ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nI hasWaveform = sample.HasSampleData(); } else { - FileReader file(mpt::as_span(pWaveForm.data(), dwLen)); - hasWaveform = sndFile.ReadWAVSample(nSample, file, false, &wsmpChunk); + FileReader wavChunk(mpt::as_span(waveData)); + hasWaveform = sndFile.ReadWAVSample(nSample, wavChunk, false, &wsmpChunk); if(dlsIns.szName[0]) sndFile.m_szNames[nSample] = mpt::String::ReadAutoBuf(dlsIns.szName); } @@ -2033,7 +2035,7 @@ uint32 DLSENVELOPE::Envelope::ConvertToMPT(InstrumentEnvelope &mptEnv, const Env } -bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, uint32 nIns, uint32 nDrumRgn) const +bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, uint32 nIns, uint32 nDrumRgn, FileReader *file) const { uint32 minRegion, maxRegion, nEnv; @@ -2194,7 +2196,7 @@ bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, ui // Load the sample if(!duplicateRegion || !sndFile.GetSample(nSmp).HasSampleData()) { - ExtractSample(sndFile, nSmp, nIns, nRgn, transpose); + ExtractSample(sndFile, nSmp, nIns, nRgn, transpose, file); extractedSamples.insert(rgn.nWaveLink); } } else if(duplicateRegion && sndFile.GetSample(RgnToSmp[dupRegion]).GetNumChannels() == 1) @@ -2213,9 +2215,8 @@ bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, ui const uint8 offsetOrig = (pan1 < pan2) ? 1 : 0; const uint8 offsetNew = (pan1 < pan2) ? 0 : 1; - std::vector pWaveForm; - uint32 dwLen = 0; - if(!ExtractWaveForm(nIns, nRgn, pWaveForm, dwLen)) + const std::vector waveData = ExtractWaveForm(nIns, nRgn, file); + if(waveData.empty()) continue; extractedSamples.insert(rgn.nWaveLink); @@ -2230,8 +2231,8 @@ bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, ui // Now read the other channel if(m_SamplesEx[m_Instruments[nIns].Regions[nRgn].nWaveLink].compressed) { - FileReader file{mpt::as_span(pWaveForm)}; - if(sndFile.ReadSampleFromFile(nSmp, file, false, false)) + FileReader smpChunk{mpt::as_span(waveData)}; + if(sndFile.ReadSampleFromFile(nSmp, smpChunk, false, false)) { pDest = sampleCopy.sample16() + offsetNew; const SmpLength copyLength = std::min(sample.nLength, sampleCopy.nLength); @@ -2242,10 +2243,10 @@ bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, ui } } else { - SmpLength len = std::min(dwLen / 2u, sampleCopy.nLength); - const std::byte *src = mpt::byte_cast(pWaveForm.data()); + SmpLength len = std::min(mpt::saturate_cast(waveData.size() / 2u), sampleCopy.nLength); + const std::byte *src = mpt::byte_cast(waveData.data()); int16 *dst = sampleCopy.sample16() + offsetNew; - CopySample, SC::DecodeInt16<0, littleEndian16>>>(dst, len, 2, src, pWaveForm.size(), 1); + CopySample, SC::DecodeInt16<0, littleEndian16>>>(dst, len, 2, src, waveData.size(), 1); } sample.FreeSample(); sample = sampleCopy; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.h b/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.h index 3f953df33..9dbaca583 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.h @@ -129,6 +129,7 @@ public: bool operator==(const CDLSBank &other) const noexcept { return !mpt::PathCompareNoCase(m_szFileName, other.m_szFileName); } static bool IsDLSBank(const mpt::PathString &filename); + static bool IsDLSBank(FileReader file); static uint32 MakeMelodicCode(uint32 bank, uint32 instr) { return ((bank << 16) | (instr));} static uint32 MakeDrumCode(uint32 rgn, uint32 instr) { return (0x80000000 | (rgn << 16) | (instr));} @@ -144,16 +145,16 @@ public: uint32 GetNumSamples() const { return static_cast(m_WaveForms.size()); } const DLSINSTRUMENT *GetInstrument(uint32 iIns) const { return iIns < m_Instruments.size() ? &m_Instruments[iIns] : nullptr; } [[nodiscard]] const DLSINSTRUMENT *FindInstrument(bool isDrum, uint32 bank = 0xFF, uint32 program = 0xFF, uint32 key = 0xFF, uint32 *pInsNo = nullptr) const; - bool FindAndExtract(CSoundFile &sndFile, const INSTRUMENTINDEX ins, const bool isDrum) const; + bool FindAndExtract(CSoundFile &sndFile, const INSTRUMENTINDEX ins, const bool isDrum, FileReader *file = nullptr) const; uint32 GetRegionFromKey(uint32 nIns, uint32 nKey) const; - bool ExtractWaveForm(uint32 nIns, uint32 nRgn, std::vector &waveData, uint32 &length) const; - bool ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nIns, uint32 nRgn, int transpose = 0) const; - bool ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, uint32 nIns, uint32 nDrumRgn) const; + bool ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nIns, uint32 nRgn, int transpose = 0, FileReader *file = nullptr) const; + bool ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, uint32 nIns, uint32 nDrumRgn, FileReader *file = nullptr) const; const char *GetRegionName(uint32 nIns, uint32 nRgn) const; uint16 GetPanning(uint32 ins, uint32 region) const; // Internal Loader Functions protected: + std::vector ExtractWaveForm(uint32 nIns, uint32 nRgn, FileReader *file) const; bool UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, FileReader chunk); bool UpdateSF2PresetData(SF2LoaderInfo &sf2info, const IFFCHUNK &header, FileReader &chunk); bool ConvertSF2ToDLS(SF2LoaderInfo &sf2info); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_669.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_669.cpp index 402e11c49..5f88b23d6 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_669.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_669.cpp @@ -248,7 +248,15 @@ bool CSoundFile::Read669(FileReader &file, ModLoadingFlags loadFlags) uint8 command = effect[chn] >> 4; if(command < static_cast(std::size(effTrans))) { +#if MPT_COMPILER_MSVC +#pragma warning(push) +// false-positive +#pragma warning(disable:6385) // Reading invalid data from 'effTrans'. +#endif m->command = effTrans[command]; +#if MPT_COMPILER_MSVC +#pragma warning(pop) +#endif } else { m->command = CMD_NONE; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dmf.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dmf.cpp index d783007af..bb537ba9a 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dmf.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dmf.cpp @@ -24,7 +24,7 @@ struct DMFFileHeader { char signature[4]; // "DDMF" uint8 version; // 1 - 7 are beta versions, 8 is the official thing, 10 is xtracker32 - char tracker[8]; // "XTRACKER" + char tracker[8]; // "XTRACKER", or "SCREAM 3" when converting from S3M, etc. char songname[30]; char composer[20]; uint8 creationDay; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dsym.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dsym.cpp index 7d8e3a18d..7bd3c422b 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dsym.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dsym.cpp @@ -126,6 +126,8 @@ static std::vector DecompressDSymLZW(FileReader &file, uint32 size) // Align length to 4 bytes file.Seek(startPos + ((bitFile.GetPosition() - startPos + 3u) & ~FileReader::off_t(3))); + // cppcheck false-positive + // cppcheck-suppress returnDanglingLifetime return output; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_it.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_it.cpp index 359eb3c25..277d11743 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_it.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_it.cpp @@ -341,6 +341,26 @@ static void CopyPatternName(CPattern &pattern, FileReader &file) } +// Get version of Impulse Tracker that was used to create an IT/S3M file. +mpt::ustring CSoundFile::GetImpulseTrackerVersion(uint16 cwtv, uint16 cmwt) +{ + mpt::ustring version; + cwtv &= 0xFFF; + if(cmwt > 0x0214) + { + version = UL_("Impulse Tracker 2.15"); + } else if(cwtv >= 0x0215 && cwtv <= 0x0217) + { + const mpt::uchar *versions[] = {UL_("1-2"), UL_("3"), UL_("4-5")}; + version = MPT_UFORMAT("Impulse Tracker 2.14p{}")(mpt::ustring_view(versions[cwtv - 0x0215])); + } else + { + version = MPT_UFORMAT("Impulse Tracker {}.{}")((cwtv & 0x0F00) >> 8, mpt::ufmt::hex0<2>((cwtv & 0xFF))); + } + return version; +} + + // Get version of Schism Tracker that was used to create an IT/S3M file. mpt::ustring CSoundFile::GetSchismTrackerVersion(uint16 cwtv, uint32 reserved) { @@ -1027,6 +1047,7 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) auto patData = Patterns[pat].begin(); ROWINDEX row = 0; + ModCommand dummy{}; while(row < numRows && patternData.CanRead(1)) { uint8 b = patternData.ReadUint8(); @@ -1057,7 +1078,6 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) } // Now we grab the data for this particular row/channel. - ModCommand dummy{}; ModCommand &m = ch < m_nChannels ? patData[ch] : dummy; if(chnMask[ch] & 0x10) @@ -1138,8 +1158,18 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) { const auto [command, param] = patternData.ReadArray(); S3MConvert(m, command, param, true); + + // IT 1.xx does not support high offset command + if(m.command == CMD_S3MCMDEX && (m.param & 0xF0) == 0xA0 && fileHeader.cwtv < 0x0200) + m.command = CMD_DUMMY; + // Fix handling of commands V81-VFF in ITs made with old Schism Tracker versions + // (fixed in https://github.com/schismtracker/schismtracker/commit/ab5517d4730d4c717f7ebffb401445679bd30888 - one of the last versions to identify as v0.50) + else if(m.command == CMD_GLOBALVOLUME && m.param > 0x80 && fileHeader.cwtv >= 0x1000 && fileHeader.cwtv <= 0x1050) + m.param = 0x80; + // In some IT-compatible trackers, it is possible to input a parameter without a command. - // In this case, we still need to update the last value memory. OpenMPT didn't do this until v1.25.01.07. + // In this case, we still need to update the last value memory (so that we don't reuse a previous non-empty effect). + // OpenMPT didn't do this until v1.25.01.07. // Example: ckbounce.it lastValue[ch].command = m.command; lastValue[ch].param = m.param; @@ -1229,19 +1259,7 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) madeWithTracker = U_("Unknown"); } else if(fileHeader.cmwt < 0x0300 && madeWithTracker.empty()) { - if(fileHeader.cmwt > 0x0214) - { - madeWithTracker = U_("Impulse Tracker 2.15"); - } else if(fileHeader.cwtv > 0x0214) - { - // Patched update of IT 2.14 (0x0215 - 0x0217 == p1 - p3) - // p4 (as found on modland) adds the ITVSOUND driver, but doesn't seem to change - // anything as far as file saving is concerned. - madeWithTracker = MPT_UFORMAT("Impulse Tracker 2.14p{}")(fileHeader.cwtv - 0x0214); - } else - { - madeWithTracker = MPT_UFORMAT("Impulse Tracker {}.{}")((fileHeader.cwtv & 0x0F00) >> 8, mpt::ufmt::hex0<2>((fileHeader.cwtv & 0xFF))); - } + madeWithTracker = GetImpulseTrackerVersion(fileHeader.cwtv, fileHeader.cmwt); if(m_FileHistory.empty() && fileHeader.reserved != 0) { // Starting from version 2.07, IT stores the total edit time of a module in the "reserved" field @@ -1739,6 +1757,10 @@ bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool c // Write pattern header ROWINDEX writeRows = mpt::saturate_cast(Patterns[pat].GetNumRows()); + if(compatibilityExport) + writeRows = std::clamp(writeRows, ROWINDEX(32), ROWINDEX(200)); + if(writeRows != Patterns[pat].GetNumRows()) + AddToLog(LogWarning, MPT_UFORMAT("Warning: Pattern {} was resized from {} to {} rows.")(pat, Patterns[pat].GetNumRows(), writeRows)); uint16 writeSize = 0; uint16le patinfo[4]; patinfo[0] = 0; @@ -1755,11 +1777,12 @@ bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool c // Maximum 7 bytes per cell, plus end of row marker, so this buffer is always large enough to cover one row. std::vector buf(7 * maxChannels + 1); - for(ROWINDEX row = 0; row < writeRows; row++) + const ROWINDEX readRows = std::min(writeRows, Patterns[pat].GetNumRows()); + for(ROWINDEX row = 0; row < readRows; row++) { uint32 len = 0; const ModCommand *m = Patterns[pat].GetpModCommand(row, 0); - + bool writePatternBreak = (readRows < writeRows && row + 1 == readRows && !Patterns[pat].RowHasJump(row)); for(CHANNELINDEX ch = 0; ch < maxChannels; ch++, m++) { // Skip mptm-specific notes. @@ -1813,6 +1836,12 @@ bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool c S3MSaveConvert(*m, command, param, true, compatibilityExport); if (command) b |= 8; } + if(writePatternBreak && !(b & 8)) + { + b |= 8; + command = 'C' ^ 0x40; + writePatternBreak = false; + } // Packing information if (b) { @@ -1895,11 +1924,25 @@ bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool c break; } else { - dwPos += len; - writeSize += (uint16)len; + writeSize += static_cast(len); mpt::IO::WriteRaw(f, buf.data(), len); } + if(writePatternBreak) + { + // Didn't manage to put a pattern break, so put it on the next row instead. + const uint8 patternBreak[] = {1 | IT_bitmask_patternChanEnabled_c, 8, 'C' ^ 0x40, 0}; + mpt::IO::Write(f, patternBreak); + writeSize += sizeof(patternBreak); + } } + if(readRows < writeRows) + { + // Invent empty rows at end (if we end up here, the pattern is very short and we don't have to care about writeSize overflowing the 16-bit limit) + writeSize += static_cast(writeRows - readRows); + buf.assign(writeRows - readRows, 0); + mpt::IO::Write(f, buf); + } + dwPos += writeSize; mpt::IO::SeekAbsolute(f, dwPatPos); patinfo[0] = writeSize; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_med.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_med.cpp index 2abb1607c..9abf61a86 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_med.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_med.cpp @@ -411,12 +411,12 @@ static std::pair ConvertMEDEffect(ModCommand & switch(command) { case 0x04: // Vibrato (twice as deep as in ProTracker) - m.SetEffectCommand(CMD_VIBRATO, (std::min(param >> 3, 0x0F) << 4) | std::min((param & 0x0F) * 2, 0x0F)); + m.SetEffectCommand(CMD_VIBRATO, (param & 0xF0) | std::min((param & 0x0F) * 2, 0x0F)); break; case 0x08: // Hold and decay break; case 0x09: // Set secondary speed - if(param > 0 && param <= 20) + if(param > 0 && param <= 0x20) m.SetEffectCommand(CMD_SPEED, param); break; case 0x0C: // Set Volume (note: parameters >= 0x80 (only in hex mode?) should set the default instrument volume, which we don't support) @@ -456,10 +456,6 @@ static std::pair ConvertMEDEffect(ModCommand & return {CMD_XPARAM, static_cast(tempo & 0xFF)}; } } -#ifdef MODPLUG_TRACKER - if(m.param < 0x20) - m.param = 0x20; -#endif // MODPLUG_TRACKER } else switch(param) { case 0xF1: // Play note twice @@ -495,7 +491,7 @@ static std::pair ConvertMEDEffect(ModCommand & m.SetEffectCommand(CMD_MODCMDEX, 0x20 | nibbleLo); break; case 0x14: // Vibrato (ProTracker compatible depth, but faster) - m.SetEffectCommand(CMD_VIBRATO, (std::min((param >> 4) + 1, 0x0F) << 4) | (param & 0x0F)); + m.SetEffectCommand(CMD_VIBRATO, param); break; case 0x15: // Set finetune m.SetEffectCommand(CMD_MODCMDEX, 0x50 | (param & 0x0F)); @@ -1143,7 +1139,7 @@ bool CSoundFile::ReadMED(FileReader &file, ModLoadingFlags loadFlags) if(header.numTracks < 1 || header.numTracks > 64 || m_nChannels > 64) return false; - const bool freePan = (header.flags3 & MMD2Song::FLAG3_FREEPAN); + const bool freePan = !hardwareMixSamples && (header.flags3 & MMD2Song::FLAG3_FREEPAN); if(header.volAdjust) preamp = Util::muldivr_unsigned(preamp, std::min(header.volAdjust, 800), 100); if (freePan) @@ -1470,8 +1466,8 @@ bool CSoundFile::ReadMED(FileReader &file, ModLoadingFlags loadFlags) order[from] = pat; } Patterns[pat].WriteEffect(EffectWriter(CMD_POSITIONJUMP, mpt::saturate_cast(to)).Row(Patterns[pat].GetNumRows() - 1).RetryPreviousRow()); - if(pat >= numPatterns) - numPatterns = pat + 1; + if(pat >= basePattern && (pat - basePattern) >= numPatterns) + numPatterns = static_cast(pat - basePattern + 1); } if(numSongs > 1) @@ -1484,8 +1480,8 @@ bool CSoundFile::ReadMED(FileReader &file, ModLoadingFlags loadFlags) Patterns[firstPat].WriteEffect(EffectWriter(CMD_CHANNELVOLUME, static_cast(ChnSettings[chn].nVolume)).Channel(chn).RetryNextRow()); Patterns[firstPat].WriteEffect(EffectWriter(CMD_PANNING8, mpt::saturate_cast(ChnSettings[chn].nPan)).Channel(chn).RetryNextRow()); } - if(firstPat >= numPatterns) - numPatterns = firstPat + 1; + if(firstPat >= basePattern && (firstPat - basePattern) >= numPatterns) + numPatterns = static_cast(firstPat - basePattern + 1); } } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mid.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mid.cpp index 5c27d319c..696ae785c 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mid.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mid.cpp @@ -1320,12 +1320,14 @@ bool CSoundFile::ReadMID(FileReader &file, ModLoadingFlags loadFlags) } std::unique_ptr cachedBank, embeddedBank; + FileReader *bankFile = nullptr; - if(CDLSBank::IsDLSBank(file.GetOptionalFileName().value_or(P_("")))) + if(CDLSBank::IsDLSBank(file)) { // Soundfont embedded in MIDI file embeddedBank = std::make_unique(); - embeddedBank->Open(file.GetOptionalFileName().value_or(P_(""))); + embeddedBank->Open(file); + bankFile = &file; } else { // Soundfont with same name as MIDI file @@ -1353,7 +1355,7 @@ bool CSoundFile::ReadMID(FileReader &file, ModLoadingFlags loadFlags) else if(pIns->nMidiProgram) midiCode = (pIns->nMidiProgram - 1) & 0x7F; - if(embeddedBank && embeddedBank->FindAndExtract(*this, ins, midiCode >= 0x80)) + if(embeddedBank && embeddedBank->FindAndExtract(*this, ins, midiCode >= 0x80, bankFile)) { continue; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp index 7a06394e2..b592573df 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp @@ -2451,6 +2451,7 @@ bool CSoundFile::SaveMod(std::ostream &f) const continue; } const auto rowBase = Patterns[pat].GetRow(row); + bool writePatternBreak = (Patterns[pat].GetNumRows() < 64 && row + 1 == Patterns[pat].GetNumRows() && !Patterns[pat].RowHasJump(row)); events.resize(writeChannels * 4); size_t eventByte = 0; @@ -2466,6 +2467,11 @@ bool CSoundFile::SaveMod(std::ostream &f) const command = 0x0C; param = std::min(m.vol, uint8(64)); } + if(writePatternBreak && !command && !param) + { + command = 0x0D; + writePatternBreak = false; + } uint16 period = 0; // Convert note to period diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_okt.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_okt.cpp index fc94e7ae7..bd08449ce 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_okt.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_okt.cpp @@ -30,7 +30,7 @@ struct OktIffChunk }; uint32be signature; // IFF chunk name - uint32be chunksize; // chunk size without header + uint32be chunkSize; // Chunk size without header }; MPT_BINARY_STRUCT(OktIffChunk, 8) @@ -38,11 +38,11 @@ MPT_BINARY_STRUCT(OktIffChunk, 8) struct OktSample { char name[20]; - uint32be length; // length in bytes + uint32be length; // Length in bytes uint16be loopStart; // *2 for real value uint16be loopLength; // ditto - uint16be volume; // default volume - uint16be type; // 7-/8-bit sample + uint16be volume; // Default volume + uint16be type; // 7-/8-bit sample (0: 7-bit, only usable on paired channels ["8" in GUI], 1: 8-bit, only usable on unpaired channels ["4" in GUI], 2: 7-bit, usable on all channels ["B" in GUI]) }; MPT_BINARY_STRUCT(OktSample, 32) @@ -51,7 +51,8 @@ MPT_BINARY_STRUCT(OktSample, 32) // Parse the sample header block static void ReadOKTSamples(FileReader &chunk, CSoundFile &sndFile) { - sndFile.m_nSamples = std::min(static_cast(chunk.BytesLeft() / sizeof(OktSample)), static_cast(MAX_SAMPLES - 1)); + static_assert(MAX_SAMPLES >= 72); // For copies of type "B" samples + sndFile.m_nSamples = std::min(static_cast(chunk.BytesLeft() / sizeof(OktSample)), SAMPLEINDEX(36)); for(SAMPLEINDEX smp = 1; smp <= sndFile.GetNumSamples(); smp++) { @@ -66,6 +67,7 @@ static void ReadOKTSamples(FileReader &chunk, CSoundFile &sndFile) mptSmp.nVolume = std::min(oktSmp.volume.get(), uint16(64)) * 4u; mptSmp.nLength = oktSmp.length & ~1; mptSmp.cues[0] = oktSmp.type; // Temporary storage for pattern reader, will be reset later + mptSmp.cues[1] = 0; // Parse loops const SmpLength loopStart = oktSmp.loopStart * 2; const SmpLength loopLength = oktSmp.loopLength * 2; @@ -124,20 +126,26 @@ static void ReadOKTPattern(FileReader &chunk, PATTERNINDEX pat, CSoundFile &sndF if(note > 0 && note <= 36) { m.note = note + (NOTE_MIDDLEC - 13); + if(pairedChn[chn] && m.note >= NOTE_MIDDLEC + 22) + m.note = NOTE_MIDDLEC + 21; + m.instr = instr + 1; if(m.instr > 0 && m.instr <= sndFile.GetNumSamples()) { - const auto &sample = sndFile.GetSample(m.instr); + auto &sample = sndFile.GetSample(m.instr); // Default volume only works on raw Paula channels if(pairedChn[chn] && sample.nVolume < 256) - { - m.volcmd = VOLCMD_VOLUME; - m.vol = 64; - } + m.SetVolumeCommand(VOLCMD_VOLUME, 64); + // If channel and sample type don't match, stop this channel (add 100 to the instrument number to make it understandable what happened during import) if((sample.cues[0] == 1 && pairedChn[chn] != 0) || (sample.cues[0] == 0 && pairedChn[chn] == 0)) { m.instr += 100; + } else if(sample.cues[0] == 2 && pairedChn[chn] && sample.uFlags[CHN_SUSTAINLOOP]) + { + // Type "B" sample: Loops only work on raw Paula channels + sample.cues[1] = 1; + m.instr += 36; } } } @@ -150,105 +158,72 @@ static void ReadOKTPattern(FileReader &chunk, PATTERNINDEX pat, CSoundFile &sndF case 1: // 1 Portamento Down (Period) if(param) { - m.command = CMD_PORTAMENTOUP; - m.param = param; + m.SetEffectCommand(CMD_PORTAMENTOUP, param); } break; case 2: // 2 Portamento Up (Period) if(param) - { - m.command = CMD_PORTAMENTODOWN; - m.param = param; - } + m.SetEffectCommand(CMD_PORTAMENTODOWN, param); break; case 10: // A Arpeggio 1 (down, orig, up) if(param) - { - m.command = CMD_ARPEGGIO; - m.param = (param & 0x0F) | (InvertArpeggioParam(param >> 4) << 4); - } + m.SetEffectCommand(CMD_ARPEGGIO, (param & 0x0F) | (InvertArpeggioParam(param >> 4) << 4)); break; case 11: // B Arpeggio 2 (orig, up, orig, down) if(param) - { - m.command = CMD_ARPEGGIO; - m.param = (param & 0xF0) | InvertArpeggioParam(param & 0x0F); - } + m.SetEffectCommand(CMD_ARPEGGIO, (param & 0xF0) | InvertArpeggioParam(param & 0x0F)); break; // This one is close enough to "standard" arpeggio -- I think! case 12: // C Arpeggio 3 (up, up, orig) if(param) - { - m.command = CMD_ARPEGGIO; - m.param = param; - } + m.SetEffectCommand(CMD_ARPEGGIO, param); break; case 13: // D Slide Down (Notes) if(param) - { - m.command = CMD_NOTESLIDEDOWN; - m.param = 0x10 | std::min(uint8(0x0F), param); - } + m.SetEffectCommand(CMD_NOTESLIDEDOWN, 0x10 | std::min(uint8(0x0F), param)); break; case 30: // U Slide Up (Notes) if(param) - { - m.command = CMD_NOTESLIDEUP; - m.param = 0x10 | std::min(uint8(0x0F), param); - } + m.SetEffectCommand(CMD_NOTESLIDEUP, 0x10 | std::min(uint8(0x0F), param)); break; // Fine Slides are only implemented for libopenmpt. For OpenMPT, // sliding every 5 (non-note) ticks kind of works (at least at // speed 6), but implementing separate (format-agnostic) fine slide commands would of course be better. case 21: // L Slide Down Once (Notes) if(param) - { - m.command = CMD_NOTESLIDEDOWN; - m.param = 0x50 | std::min(uint8(0x0F), param); - } + m.SetEffectCommand(CMD_NOTESLIDEDOWN, 0x50 | std::min(uint8(0x0F), param)); break; case 17: // H Slide Up Once (Notes) if(param) - { - m.command = CMD_NOTESLIDEUP; - m.param = 0x50 | std::min(uint8(0x0F), param); - } + m.SetEffectCommand(CMD_NOTESLIDEUP, 0x50 | std::min(uint8(0x0F), param)); break; case 15: // F Set Filter <>00:ON - m.command = CMD_MODCMDEX; - m.param = !!param; + m.SetEffectCommand(CMD_MODCMDEX, !!param); break; case 25: // P Pos Jump - m.command = CMD_POSITIONJUMP; - m.param = param; + m.SetEffectCommand(CMD_POSITIONJUMP, param); break; case 27: // R Release sample (apparently not listed in the help!) - m.Clear(); m.note = NOTE_KEYOFF; + m.instr = 0; break; case 28: // S Speed if(param < 0x20) - { - m.command = CMD_SPEED; - m.param = param; - } + m.SetEffectCommand(CMD_SPEED, param); break; case 31: // V Volume // Volume on mixed channels is permanent, on hardware channels it behaves like in regular MODs if(param & 0x0F) - { - m.command = pairedChn[chn] ? CMD_CHANNELVOLSLIDE : CMD_VOLUMESLIDE; - m.param = param & 0x0F; - } + m.SetEffectCommand(pairedChn[chn] ? CMD_CHANNELVOLSLIDE : CMD_VOLUMESLIDE, param & 0x0F); switch(param >> 4) { @@ -260,13 +235,11 @@ static void ReadOKTPattern(FileReader &chunk, PATTERNINDEX pat, CSoundFile &sndF case 0: case 1: case 2: case 3: if(pairedChn[chn]) { - m.command = CMD_CHANNELVOLUME; - m.param = param; + m.SetEffectCommand(CMD_CHANNELVOLUME, param); } else { - m.volcmd = VOLCMD_VOLUME; - m.vol = param; - m.command = CMD_NONE; + m.SetVolumeCommand(VOLCMD_VOLUME, param); + m.SetEffectCommand(oldCmd, oldParam); } break; case 5: // Normal slide up @@ -280,7 +253,7 @@ static void ReadOKTPattern(FileReader &chunk, PATTERNINDEX pat, CSoundFile &sndF break; default: // Junk. - m.command = CMD_NONE; + m.SetEffectCommand(oldCmd, oldParam); break; } @@ -293,7 +266,14 @@ static void ReadOKTPattern(FileReader &chunk, PATTERNINDEX pat, CSoundFile &sndF { other.SetVolumeCommand(volCmd); } - other.SetEffectCommand(m); + if(ModCommand::GetEffectWeight(other.command) < ModCommand::GetEffectWeight(m.command)) + { + other.SetEffectCommand(m); + } else if(row < rows - 1) + { + // Retry on next row + sndFile.Patterns[pat].GetpModCommand(row + 1, static_cast(chn + pairedChn[chn]))->SetEffectCommand(m); + } } break; @@ -359,7 +339,7 @@ bool CSoundFile::ReadOKT(FileReader &file, ModLoadingFlags loadFlags) if(!file.ReadStruct(iffHead)) break; - FileReader chunk = file.ReadChunk(iffHead.chunksize); + FileReader chunk = file.ReadChunk(iffHead.chunkSize); if(!chunk.IsValid()) continue; @@ -467,12 +447,14 @@ bool CSoundFile::ReadOKT(FileReader &file, ModLoadingFlags loadFlags) // Read samples size_t fileSmp = 0; - for(SAMPLEINDEX smp = 1; smp < m_nSamples; smp++) + const SAMPLEINDEX origSamples = m_nSamples; + for(SAMPLEINDEX smp = 1; smp <= origSamples; smp++) { if(fileSmp >= sampleChunks.size() || !(loadFlags & loadSampleData)) break; ModSample &mptSample = Samples[smp]; + const bool needCopy = mptSample.cues[1] != 0; mptSample.SetDefaultCuePoints(); if(mptSample.nLength == 0) continue; @@ -487,6 +469,20 @@ bool CSoundFile::ReadOKT(FileReader &file, ModLoadingFlags loadFlags) SampleIO::signedPCM) .ReadSample(mptSample, sampleChunks[fileSmp]); + if(needCopy) + { + // Type "B" samples (can play on both paired and unpaired channels) can have loop information, + // which can only be used on unpaired channels. So we need a looped and unlooped copy of the sample. + m_nSamples = std::max(m_nSamples, static_cast(smp + 36)); + ModSample ©Sample = Samples[smp + 36]; + copySample.Initialize(); + copySample.nC5Speed = mptSample.nC5Speed; + copySample.nVolume = mptSample.nVolume; + copySample.nLength = mptSample.nLength; + copySample.CopyWaveform(mptSample); + m_szNames[smp + 36] = m_szNames[smp]; + } + fileSmp++; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ptm.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ptm.cpp index 2c7c2ebbe..cbb92daa9 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ptm.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ptm.cpp @@ -175,6 +175,7 @@ bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags) m_modFormat.madeWithTracker = MPT_UFORMAT("PolyTracker {}.{}")(fileHeader.versionHi.get(), mpt::ufmt::hex0<2>(fileHeader.versionLo.get())); m_modFormat.charset = mpt::Charset::CP437; + SetMixLevels(MixLevels::CompatibleFT2); m_SongFlags = SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS; m_nChannels = fileHeader.numChannels; m_nSamples = std::min(static_cast(fileHeader.numSamples), static_cast(MAX_SAMPLES - 1)); @@ -267,20 +268,25 @@ bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags) { case CMD_PANNING8: // Don't be surprised about the strange formula, this is directly translated from original disassembly... - m.command = CMD_S3MCMDEX; - m.param = 0x80 | ((std::max(m.param >> 3, 1u) - 1u) & 0x0F); + m.SetEffectCommand(CMD_S3MCMDEX, static_cast(0x80 | ((std::max(m.param >> 3, 1u) - 1u) & 0x0F))); break; case CMD_GLOBALVOLUME: m.param = std::min(m.param, uint8(0x40)) * 2u; break; +#ifdef MODPLUG_TRACKER + case CMD_OFFSET: + case CMD_REVERSEOFFSET: + if(m.instr && m.instr <= GetNumSamples() && Samples[m.instr].uFlags[CHN_16BIT]) + m.param /= 2; + break; +#endif // MODPLUG_TRACKER default: break; } } if(b & 0x80) { - m.volcmd = VOLCMD_VOLUME; - m.vol = file.ReadUint8(); + m.SetVolumeCommand(VOLCMD_VOLUME, file.ReadUint8()); } } } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp index 9b0914950..3b912b64b 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp @@ -283,9 +283,16 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) // though several ST3.01/3.03 files with ultra-click values of 16 have been found as well. // However, we won't fingerprint these values here as it's unlikely that there is any other tracker out there disguising as ST3 and using a strange ultra-click value. // Also, re-saving a file with a strange ultra-click value in ST3 doesn't fix this value unless the user manually changes it, or if it's below 16. - madeWithTracker = UL_("Scream Tracker"); - formatTrackerStr = true; isST3 = true; + if(fileHeader.cwtv == S3MFileHeader::trkST3_20) + { + // 3.21 writes the version number as 3.20. There is no known way to differentiate between the two. + madeWithTracker = UL_("Scream Tracker 3.20 - 3.21"); + } else + { + madeWithTracker = UL_("Scream Tracker"); + formatTrackerStr = true; + } } break; case S3MFileHeader::trkImagoOrpheus: @@ -297,17 +304,11 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) nonCompatTracker = true; break; case S3MFileHeader::trkImpulseTracker: - if(fileHeader.cwtv <= S3MFileHeader::trkIT2_14) - { - madeWithTracker = UL_("Impulse Tracker"); - formatTrackerStr = true; - } else if(fileHeader.cwtv == S3MFileHeader::trkIT1_old) - { + if(fileHeader.cwtv == S3MFileHeader::trkIT1_old) madeWithTracker = UL_("Impulse Tracker 1.03"); // Could also be 1.02, maybe? I don't have that one - } else - { - madeWithTracker = MPT_UFORMAT("Impulse Tracker 2.14p{}")(fileHeader.cwtv - S3MFileHeader::trkIT2_14); - } + else + madeWithTracker = GetImpulseTrackerVersion(fileHeader.cwtv, 0); + if(fileHeader.cwtv >= S3MFileHeader::trkIT2_07 && fileHeader.reserved3 != 0) { // Starting from version 2.07, IT stores the total edit time of a module in the "reserved" field @@ -724,7 +725,7 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) else if(m.param > 0x08) zxxCountRight++; } - } else if(m.command == CMD_OFFSET && m.param == 0 && fileHeader.cwtv <= S3MFileHeader::trkST3_01) + } else if(m.command == CMD_OFFSET && m.param == 0 && isST3 && fileHeader.cwtv <= S3MFileHeader::trkST3_01) { // Offset command didn't have effect memory in ST3.01; fixed in ST3.03 m.command = CMD_DUMMY; @@ -930,6 +931,7 @@ bool CSoundFile::SaveS3M(std::ostream &f) const const auto rowBase = Patterns[pat].GetRow(row); CHANNELINDEX writeChannels = std::min(CHANNELINDEX(32), GetNumChannels()); + bool writePatternBreak = (Patterns[pat].GetNumRows() < 64 && row + 1 == Patterns[pat].GetNumRows() && !Patterns[pat].RowHasJump(row)); for(CHANNELINDEX chn = 0; chn < writeChannels; chn++) { const ModCommand &m = rowBase[chn]; @@ -995,6 +997,12 @@ bool CSoundFile::SaveS3M(std::ostream &f) const } } } + if(writePatternBreak && !(info & s3mEffectPresent)) + { + info |= s3mEffectPresent; + command = 'C' ^ 0x40; + writePatternBreak = false; + } if(info & s3mAnyPresent) { diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_sfx.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_sfx.cpp index 36e4faa12..2a20edd68 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_sfx.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_sfx.cpp @@ -54,7 +54,7 @@ MPT_BINARY_STRUCT(SFXOrderHeader, 130) struct SFXSampleHeader { char name[22]; - char dummy[2]; // Supposedly sample length, but almost always incorrect + uint16be oneshotLength; // For unlooped samples, this is quite frequently 2 bytes shorter than the sample data length (and the last two samples would cause a click to be heard) uint8be finetune; uint8be volume; uint16be loopStart; @@ -64,7 +64,7 @@ struct SFXSampleHeader void ConvertToMPT(ModSample &mptSmp, uint32 length) const { mptSmp.Initialize(MOD_TYPE_MOD); - mptSmp.nLength = length; + mptSmp.nLength = (loopLength > 1) ? length : (oneshotLength * 2u); mptSmp.nFineTune = MOD2XMFineTune(finetune); mptSmp.nVolume = 4u * std::min(volume.get(), uint8(64)); @@ -434,14 +434,18 @@ bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags) // Reading samples if(loadFlags & loadSampleData) { - for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) if(Samples[smp].nLength) + for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { + if(!sampleLen[smp - 1]) + continue; + + FileReader chunk = file.ReadChunk(sampleLen[smp - 1]); SampleIO( SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM) - .ReadSample(Samples[smp], file); + .ReadSample(Samples[smp], chunk); } } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_stm.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_stm.cpp index 4947e15f5..b6bf9dc1a 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_stm.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_stm.cpp @@ -236,9 +236,24 @@ bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags) m_modFormat.formatName = U_("Scream Tracker 2"); m_modFormat.type = U_("stm"); - m_modFormat.madeWithTracker = MPT_UFORMAT("Scream Tracker {}.{}")(fileHeader.verMajor, mpt::ufmt::dec0<2>(fileHeader.verMinor)); m_modFormat.charset = mpt::Charset::CP437; + if(!std::memcmp(fileHeader.trackerName, "!Scream!", 8)) + { + if(fileHeader.verMinor >= 21) + m_modFormat.madeWithTracker = UL_("Scream Tracker 2.2 - 2.3 or compatible"); + else + m_modFormat.madeWithTracker = MPT_UFORMAT("Scream Tracker {}.{} or compatible")(fileHeader.verMajor, mpt::ufmt::dec0<2>(fileHeader.verMinor)); + } + else if(!std::memcmp(fileHeader.trackerName, "BMOD2STM", 8)) + m_modFormat.madeWithTracker = UL_("BMOD2STM"); + else if(!std::memcmp(fileHeader.trackerName, "WUZAMOD!", 8)) + m_modFormat.madeWithTracker = UL_("Wuzamod"); + else if(!std::memcmp(fileHeader.trackerName, "SWavePro", 8)) + m_modFormat.madeWithTracker = UL_("SoundWave Pro"); + else + m_modFormat.madeWithTracker = UL_("Unknown"); + m_playBehaviour.set(kST3SampleSwap); m_nSamples = 31; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_symmod.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_symmod.cpp index 2bfe5019b..bd0d4621b 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_symmod.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_symmod.cpp @@ -980,6 +980,30 @@ static bool ConvertDSP(const SymEvent event, MIDIMacroConfigData::Macro ¯o, } +static uint8 MapToClosestMidiMacro(const SymEvent event, std::map ¯oMap) +{ + if(event.command == SymEvent::DSPDelay) + return 0; + uint8 bestMatch = 0; + uint32 bestDistance = uint32_max; + for(const auto &m : macroMap) + { + const auto &mapEvent = m.first; + if(event.command != mapEvent.command || event.note != mapEvent.note) + continue; + const uint32 diff1 = static_cast(event.param) - mapEvent.param, diff2 = static_cast(event.inst) - mapEvent.inst; + const uint32 distance = diff1 * diff1 + diff2 * diff2; + if(distance >= bestDistance) + continue; + + bestMatch = m.second; + bestDistance = distance; + } + macroMap[event] = bestMatch; + return bestMatch; +} + + CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSymMOD(MemoryFileReader file, const uint64 *pfilesize) { MPT_UNREFERENCED_PARAMETER(pfilesize); @@ -1044,6 +1068,7 @@ bool CSoundFile::ReadSymMOD(FileReader &file, ModLoadingFlags loadFlags) uint16 sampleBoost = 2500; bool isSymphoniePro = false; bool externalSamples = false; + bool unknownHunks = false; std::vector positions; std::vector sequences; std::vector patternData; @@ -1202,9 +1227,10 @@ bool CSoundFile::ReadSymMOD(FileReader &file, ModLoadingFlags loadFlags) file.Skip(file.ReadUint32BE()); break; - // Unrecognized chunk/value type + // Unrecognized chunk/value type (e.g. garbage at the end of Natsh1.SymMOD) default: - return false; + unknownHunks = true; + break; } } @@ -1212,6 +1238,8 @@ bool CSoundFile::ReadSymMOD(FileReader &file, ModLoadingFlags loadFlags) return false; if((loadFlags & loadPatternData) && (positions.empty() || patternData.empty() || sequences.empty())) return false; + if(unknownHunks) + AddToLog(LogWarning, U_("Unknown hunks were found and ignored.")); // Let's hope noone is going to use the 256th instrument ;) if(instruments.size() >= MAX_INSTRUMENTS) @@ -1641,10 +1669,9 @@ bool CSoundFile::ReadSymMOD(FileReader &file, ModLoadingFlags loadFlags) case SymEvent::DSPEcho: case SymEvent::DSPDelay: #endif - if(macroMap.count(event)) + if(auto it = macroMap.find(event); it != macroMap.end() && it->second != 0) { - m.command = CMD_MIDI; - m.param = macroMap[event]; + m.SetEffectCommand(CMD_MIDI, it->second); } else if(macroMap.size() < m_MidiCfg.Zxx.size()) { uint8 param = static_cast(macroMap.size()); @@ -1656,6 +1683,9 @@ bool CSoundFile::ReadSymMOD(FileReader &file, ModLoadingFlags loadFlags) if(event.command == SymEvent::DSPEcho || event.command == SymEvent::DSPDelay) useDSP = true; } + } else if(uint8 param = MapToClosestMidiMacro(event, macroMap)) + { + m.SetEffectCommand(CMD_MIDI, param); } break; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ult.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ult.cpp index 3d86fcb69..34f8f09af 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ult.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ult.cpp @@ -197,7 +197,9 @@ static std::pair TranslateULTCommands(const uint8 e, uint8 } -static int ReadULTEvent(ModCommand &m, FileReader &file, uint8 version) +struct ULTEventResult { uint8 repeat = 0; ModCommand::COMMAND lostCommand = CMD_NONE; ModCommand::PARAM lostParam = 0; }; + +static ULTEventResult ReadULTEvent(ModCommand &m, FileReader &file, uint8 version) { uint8 repeat = 1; uint8 b = file.ReadUint8(); @@ -222,7 +224,7 @@ static int ReadULTEvent(ModCommand &m, FileReader &file, uint8 version) m.SetEffectCommand(CMD_OFFSET, static_cast(offset)); if(offset > 0xFF) m.SetVolumeCommand(VOLCMD_OFFSET, static_cast(offset >> 8)); - return repeat; + return {repeat}; } else if(cmd1 == CMD_OFFSET) { uint32 offset = param1 * 4; @@ -231,7 +233,7 @@ static int ReadULTEvent(ModCommand &m, FileReader &file, uint8 version) { m.SetEffectCommand(CMD_OFFSET, static_cast(offset)); m.SetVolumeCommand(VOLCMD_OFFSET, static_cast(offset >> 8)); - return repeat; + return {repeat}; } } else if(cmd2 == CMD_OFFSET) { @@ -241,7 +243,7 @@ static int ReadULTEvent(ModCommand &m, FileReader &file, uint8 version) { m.SetEffectCommand(CMD_OFFSET, static_cast(offset)); m.SetVolumeCommand(VOLCMD_OFFSET, static_cast(offset >> 8)); - return repeat; + return {repeat}; } } else if(cmd1 == cmd2) { @@ -257,9 +259,8 @@ static int ReadULTEvent(ModCommand &m, FileReader &file, uint8 version) // Combine slide commands, if possible ModCommand::CombineEffects(cmd2, param2, cmd1, param1); - m.FillInTwoCommands(cmd1, param1, cmd2, param2); - - return repeat; + const auto lostCommand = m.FillInTwoCommands(cmd1, param1, cmd2, param2); + return {repeat, lostCommand.first, lostCommand.second}; } @@ -388,8 +389,8 @@ bool CSoundFile::ReadULT(FileReader &file, ModLoadingFlags loadFlags) m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.songName); const mpt::uchar *versions[] = {UL_("<1.4"), UL_("1.4"), UL_("1.5"), UL_("1.6")}; - m_modFormat.formatName = U_("UltraTracker"); - m_modFormat.type = U_("ult"); + m_modFormat.formatName = UL_("UltraTracker"); + m_modFormat.type = UL_("ult"); m_modFormat.madeWithTracker = U_("UltraTracker ") + versions[fileHeader.version - '1']; m_modFormat.charset = mpt::Charset::CP437; @@ -456,7 +457,10 @@ bool CSoundFile::ReadULT(FileReader &file, ModLoadingFlags loadFlags) ROWINDEX row = 0; while(row < 64) { - int repeat = ReadULTEvent(evnote, file, fileHeader.version); + const ULTEventResult eventResult = ReadULTEvent(evnote, file, fileHeader.version); + if(eventResult.lostCommand != CMD_NONE && ModCommand::IsGlobalCommand(eventResult.lostCommand, eventResult.lostParam)) + Patterns[pat].WriteEffect(EffectWriter(eventResult.lostCommand, eventResult.lostParam).Row(row).RetryNextRow()); + int repeat = eventResult.repeat; if(repeat + row > 64) repeat = 64 - row; if(repeat == 0) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_xm.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_xm.cpp index 9acb080a0..f8fbea5c4 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_xm.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_xm.cpp @@ -1135,8 +1135,8 @@ bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags) #ifndef MODPLUG_NO_FILESAVE -#if MPT_GCC_AT_LEAST(13, 0, 0) && MPT_GCC_BEFORE(14, 1, 0) -// work-around massively confused GCC 13 optimizer: +#if MPT_GCC_AT_LEAST(13, 0, 0) && MPT_GCC_BEFORE(15, 1, 0) +// work-around massively confused GCC 13/14 optimizer: // /usr/include/c++/13/bits/stl_algobase.h:437:30: warning: 'void* __builtin_memcpy(void*, const void*, long unsigned int)' writing between 3 and 9223372036854775806 bytes into a region of size 0 overflows the destination [-Wstringop-overflow=] template static MPT_NOINLINE Tcont1 & gcc_append(Tcont1 & cont1, const Tcont2 & cont2) { @@ -1417,7 +1417,7 @@ bool CSoundFile::SaveXM(std::ostream &f, bool compatibilityExport) } } -#if MPT_GCC_AT_LEAST(13, 0, 0) && MPT_GCC_BEFORE(14, 1, 0) +#if MPT_GCC_AT_LEAST(13, 0, 0) && MPT_GCC_BEFORE(15, 1, 0) gcc_append(samples, additionalSamples); #else mpt::append(samples, additionalSamples); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ModInstrument.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/ModInstrument.cpp index e508e4b7b..d6d405848 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ModInstrument.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ModInstrument.cpp @@ -41,6 +41,12 @@ void InstrumentEnvelope::Convert(MODTYPE fromType, MODTYPE toType) // So we have to disable the sustain loop if it was behind the normal loop. dwFlags.reset(ENV_SUSTAIN); } + if(!dwFlags[ENV_LOOP | ENV_SUSTAIN]) + { + // XM has no automatic fade-out behaviour at the end of the envelope. + dwFlags.set(ENV_SUSTAIN); + nSustainStart = nSustainEnd = LastPoint(); + } // XM -> IT / MPTM: Shorten loop by one tick by inserting bogus point if(nLoopEnd > nLoopStart && dwFlags[ENV_LOOP] && nLoopEnd < size()) @@ -73,11 +79,11 @@ int32 InstrumentEnvelope::GetValueFromPosition(int position, int32 rangeOut, int if(empty()) return 0; - uint32 pt = size() - 1u; + uint32 pt = LastPoint(); const int32 ENV_PRECISION = 1 << 16; // Checking where current 'tick' is relative to the envelope points. - for(uint32 i = 0; i < size() - 1u; i++) + for(uint32 i = 0; i < LastPoint(); i++) { if (position <= at(i).tick) { @@ -129,12 +135,12 @@ void InstrumentEnvelope::Sanitize(uint8 maxValue) it->tick = std::max(it->tick, (it - 1)->tick); LimitMax(it->value, maxValue); } - LimitMax(nLoopEnd, static_cast(size() - 1)); + LimitMax(nLoopEnd, LastPoint()); LimitMax(nLoopStart, nLoopEnd); - LimitMax(nSustainEnd, static_cast(size() - 1)); + LimitMax(nSustainEnd, LastPoint()); LimitMax(nSustainStart, nSustainEnd); if(nReleaseNode != ENV_RELEASE_NODE_UNSET) - LimitMax(nReleaseNode, static_cast(size() - 1)); + LimitMax(nReleaseNode, LastPoint()); } else { nLoopStart = 0; @@ -220,10 +226,11 @@ void ModInstrument::Convert(MODTYPE fromType, MODTYPE toType) } } - // Limit fadeout length for IT + // Limit fadeout length and precision for IT if(toType & MOD_TYPE_IT) { LimitMax(nFadeOut, 8192u); + nFadeOut = ((nFadeOut + 16) / 32) * 32; } // MPT-specific features - remove instrument tunings, Pitch/Tempo Lock, cutoff / resonance swing and filter mode for other formats diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ModInstrument.h b/Frameworks/OpenMPT/OpenMPT/soundlib/ModInstrument.h index 2c04fa769..f28e84121 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ModInstrument.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ModInstrument.h @@ -61,6 +61,8 @@ struct InstrumentEnvelope : public std::vector uint32 size() const { return static_cast(std::vector::size()); } + uint8 LastPoint() const { return static_cast(std::max(size(), uint32(1)) - 1); } + using std::vector::push_back; void push_back(EnvelopeNode::tick_t tick, EnvelopeNode::value_t value) { emplace_back(tick, value); } }; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatMP3.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatMP3.cpp index efeccd090..aed530749 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatMP3.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatMP3.cpp @@ -172,7 +172,7 @@ static mpt::ustring ReadMPG123String(const char (&str)[N]) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wframe-larger-than=16000" #endif // MPT_COMPILER_GCC -#if MPT_CLANG_AT_LEAST(13,0,0) +#if (MPT_CLANG_AT_LEAST(13,0,0) && !defined(MPT_COMPILER_QUIRK_APPLE_CLANG)) || MPT_CLANG_AT_LEAST(13,1,0) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wframe-larger-than" #endif // MPT_COMPILER_CLANG @@ -180,7 +180,7 @@ static MPT_NOINLINE int mp3dec_decode_frame_no_inline(mp3dec_t *dec, const uint8 { return mp3dec_decode_frame(dec, mp3, mp3_bytes, pcm, info); } -#if MPT_CLANG_AT_LEAST(13,0,0) +#if (MPT_CLANG_AT_LEAST(13,0,0) && !defined(MPT_COMPILER_QUIRK_APPLE_CLANG)) || MPT_CLANG_AT_LEAST(13,1,0) #pragma clang diagnostic pop #endif // MPT_COMPILER_CLANG #if MPT_COMPILER_GCC diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatSFZ.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatSFZ.cpp index dc75ec3fd..1e9f96fe8 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatSFZ.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatSFZ.cpp @@ -988,6 +988,8 @@ bool CSoundFile::ReadSFZInstrument(INSTRUMENTINDEX nInstr, FileReader &file) filenameModifier += P_(" (cross-fade)"); } + const SmpLength origSampleLength = sample.nLength; + // Sample offset if(region.offset && region.offset < sample.nLength) { @@ -1003,6 +1005,19 @@ bool CSoundFile::ReadSFZInstrument(INSTRUMENTINDEX nInstr, FileReader &file) } LimitMax(sample.nLength, region.end); + if(sample.nLength < origSampleLength && (origSampleLength - sample.nLength) >= 128 * 1024) + { + // If the sample was trimmed excessively, re-allocate to save memory. + // This is crucial for SFZs like those generated by Sforzando's SF2 conversion process, + // as the whole SF2 sample data chunk ends up in a single WAV file that is then referenced by each region and sliced accordingly. + if(auto newData = ModSample::AllocateSample(sample.nLength, sample.GetBytesPerSample())) + { + memcpy(newData, sample.samplev(), sample.nLength * sample.GetBytesPerSample()); + sample.FreeSample(); + sample.pData.pSample = newData; + } + } + if(region.invertPhase) { ctrlSmp::InvertSample(sample, 0, sample.nLength, *this); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp index 1ae69f59a..25455fb2f 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp @@ -44,6 +44,12 @@ static uint32 GetLinearSlideUpTable (const CSoundFile *sndFile, uint32 i) { static uint32 GetFineLinearSlideDownTable(const CSoundFile *sndFile, uint32 i) { MPT_ASSERT(i < std::size(FineLinearSlideDownTable)); return sndFile->m_playBehaviour[kPeriodsAreHertz] ? FineLinearSlideDownTable[i] : FineLinearSlideUpTable[i]; } static uint32 GetFineLinearSlideUpTable (const CSoundFile *sndFile, uint32 i) { MPT_ASSERT(i < std::size(FineLinearSlideDownTable)); return sndFile->m_playBehaviour[kPeriodsAreHertz] ? FineLinearSlideUpTable[i] : FineLinearSlideDownTable[i]; } +// Minimum parameter of tempo command that is considered to be a BPM rather than a tempo slide +static constexpr TEMPO GetMinimumTempoParam(MODTYPE modType) +{ + return (modType & (MOD_TYPE_MDL | MOD_TYPE_MED | MOD_TYPE_XM | MOD_TYPE_MOD)) ? TEMPO(1, 0) : TEMPO(32, 0); +} + //////////////////////////////////////////////////////////// // Length @@ -678,7 +684,7 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod } const auto &specs = GetModSpecifications(); - if(tempo.GetInt() >= 0x20) + if(tempo >= GetMinimumTempoParam(GetType())) { #if MPT_MSVC_BEFORE(2019, 0) // Work-around for VS2017 /std:c++17 /permissive- @@ -5445,9 +5451,9 @@ void CSoundFile::SampleOffset(ModChannel &chn, SmpLength param) const param = (param - chn.nLoopStart) % (chn.nLoopEnd - chn.nLoopStart) + chn.nLoopStart; } - if(GetType() == MOD_TYPE_MDL && chn.dwFlags[CHN_16BIT]) + if((GetType() & (MOD_TYPE_MDL | MOD_TYPE_PTM)) && chn.dwFlags[CHN_16BIT]) { - // Digitrakker really uses byte offsets, not sample offsets. WTF! + // Digitrakker and Polytracker use byte offsets, not sample offsets. param /= 2u; } @@ -5520,7 +5526,10 @@ void CSoundFile::ReverseSampleOffset(ModChannel &chn, ModCommand::PARAM param) c chn.dwFlags.set(CHN_PINGPONGFLAG); chn.dwFlags.reset(CHN_LOOP); chn.nLength = chn.pModSample->nLength; // If there was a loop, extend sample to whole length. - chn.position.Set((chn.nLength - 1) - std::min(SmpLength(param) << 8, chn.nLength - SmpLength(1)), 0); + SmpLength offset = param << 8; + if(GetType() == MOD_TYPE_PTM && chn.dwFlags[CHN_16BIT]) + offset /= 2; + chn.position.Set((chn.nLength - 1) - std::min(offset, chn.nLength - SmpLength(1)), 0); } } @@ -5971,7 +5980,7 @@ void CSoundFile::SetTempo(TEMPO param, bool setFromUI) const CModSpecifications &specs = GetModSpecifications(); // Anything lower than the minimum tempo is considered to be a tempo slide - const TEMPO minTempo = (GetType() & (MOD_TYPE_MDL | MOD_TYPE_MED | MOD_TYPE_MOD)) ? TEMPO(1, 0) : TEMPO(32, 0); + const TEMPO minTempo = GetMinimumTempoParam(GetType()); if(setFromUI) { diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.h b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.h index 2da1b8f7e..8c928d537 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.h @@ -978,6 +978,7 @@ public: bool LoadExtendedSongProperties(FileReader &file, bool ignoreChannelCount, bool* pInterpretMptMade = nullptr); void LoadMPTMProperties(FileReader &file, uint16 cwtv); + static mpt::ustring GetImpulseTrackerVersion(uint16 cwtv, uint16 cmwt); static mpt::ustring GetSchismTrackerVersion(uint16 cwtv, uint32 reserved); // Reads extended instrument properties(XM/IT/MPTM). diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp index 79eee6a20..29f8f4a1e 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp @@ -1592,6 +1592,11 @@ void CSoundFile::ProcessArpeggio(CHANNELINDEX nChn, int32 &period, Tuning::NOTEI uint8 note = (GetType() != MOD_TYPE_MOD) ? chn.nNote : static_cast(GetNoteFromPeriod(period, chn.nFineTune, chn.nC5Speed)); if(GetType() & (MOD_TYPE_DBM | MOD_TYPE_DIGI)) tick += 2; + + // SFX uses a 0-1-2-0-2-1 pattern (fixed at 6 ticks per row) + if(GetType() == MOD_TYPE_SFX && tick > 3) + tick ^= 3; + switch(tick % 3) { case 1: note += (chn.nArpeggio >> 4); break; @@ -1614,7 +1619,7 @@ void CSoundFile::ProcessArpeggio(CHANNELINDEX nChn, int32 &period, Tuning::NOTEI } period = GetPeriodFromNote(note, chn.nFineTune, chn.nC5Speed); - if(GetType() & (MOD_TYPE_DBM | MOD_TYPE_DIGI | MOD_TYPE_PSM | MOD_TYPE_STM | MOD_TYPE_OKT)) + if(GetType() & (MOD_TYPE_DBM | MOD_TYPE_DIGI | MOD_TYPE_PSM | MOD_TYPE_STM | MOD_TYPE_OKT | MOD_TYPE_SFX)) { // The arpeggio note offset remains effective after the end of the current row in ScreamTracker 2. // This fixes the flute lead in MORPH.STM by Skaven, pattern 27. @@ -1638,7 +1643,7 @@ void CSoundFile::ProcessVibrato(CHANNELINDEX nChn, int32 &period, Tuning::RATIOT if(chn.dwFlags[CHN_VIBRATO]) { - const bool advancePosition = !m_SongFlags[SONG_FIRSTTICK] || ((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !(m_SongFlags[SONG_ITOLDEFFECTS])); + const bool advancePosition = !m_SongFlags[SONG_FIRSTTICK] || ((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_MED)) && !(m_SongFlags[SONG_ITOLDEFFECTS])); if(GetType() == MOD_TYPE_669) { @@ -2472,15 +2477,10 @@ bool CSoundFile::ReadNote() { int32 pan = (m_MixerSettings.gnChannels >= 2) ? Clamp(chn.nRealPan, 0, 256) : 128; - int32 realvol; - if(m_PlayConfig.getUseGlobalPreAmp()) - { - realvol = (chn.nRealVolume * kChnMasterVol) / 128; - } else - { - // Extra attenuation required here if we're bypassing pre-amp. - realvol = (chn.nRealVolume * kChnMasterVol) / 256; - } + int32 realvol = (chn.nRealVolume * kChnMasterVol) / 128; + // Extra attenuation required here if we're bypassing pre-amp. + if(!m_PlayConfig.getUseGlobalPreAmp()) + realvol /= 2; const PanningMode panningMode = m_PlayConfig.getPanningMode(); if(panningMode == PanningMode::SoftPanning || (panningMode == PanningMode::Undetermined && (m_MixerSettings.MixerFlags & SNDMIX_SOFTPANNING))) @@ -2501,6 +2501,7 @@ bool CSoundFile::ReadNote() // you can never truly achieve 100% right panning in FT2, only 100% left. // Test case: FT2PanLaw.xm LimitMax(pan, 255); + const int panL = pan > 0 ? XMPanningTable[256 - pan] : 65536; const int panR = XMPanningTable[pan]; chn.newLeftVol = (realvol * panL) / 65536; @@ -2636,11 +2637,11 @@ void CSoundFile::ProcessMidiOut(CHANNELINDEX nChn) // Check for volume commands uint8 vol = 0xFF; if(chn.rowCommand.volcmd == VOLCMD_VOLUME) - vol = std::min(chn.rowCommand.vol, uint8(64)); + vol = std::min(chn.rowCommand.vol, uint8(64)) * 2u; else if(chn.rowCommand.command == CMD_VOLUME) - vol = std::min(chn.rowCommand.param, uint8(64)); + vol = std::min(chn.rowCommand.param, uint8(64)) * 2u; else if(chn.rowCommand.command == CMD_VOLUME8) - vol = static_cast((chn.rowCommand.param + 3u) / 4u); + vol = static_cast((chn.rowCommand.param + 1u) / 2u); const bool hasVolCommand = (vol != 0xFF); @@ -2654,7 +2655,7 @@ void CSoundFile::ProcessMidiOut(CHANNELINDEX nChn) SendMIDINote(nChn, realNote, static_cast(chn.nVolume)); } else if(hasVolCommand) { - pPlugin->MidiCC(MIDIEvents::MIDICC_Volume_Fine, vol, nChn); + pPlugin->MidiCC(MIDIEvents::MIDICC_Volume_Fine, vol / 2u, nChn); } return; } @@ -2668,7 +2669,7 @@ void CSoundFile::ProcessMidiOut(CHANNELINDEX nChn) switch(pIns->pluginVelocityHandling) { case PLUGIN_VELOCITYHANDLING_CHANNEL: - velocity = chn.nVolume; + velocity = hasVolCommand ? vol * 2 : chn.nVolume; break; default: break; @@ -2696,11 +2697,11 @@ void CSoundFile::ProcessMidiOut(CHANNELINDEX nChn) switch(pIns->pluginVolumeHandling) { case PLUGIN_VOLUMEHANDLING_DRYWET: - if(hasVolCommand) pPlugin->SetDryRatio(1.0f - (2 * vol) / 127.0f); + if(hasVolCommand) pPlugin->SetDryRatio(1.0f - vol / 127.0f); else pPlugin->SetDryRatio(1.0f - (2 * defaultVolume) / 127.0f); break; case PLUGIN_VOLUMEHANDLING_MIDI: - if(hasVolCommand) pPlugin->MidiCC(MIDIEvents::MIDICC_Volume_Coarse, std::min(uint8(127), static_cast(2 * vol)), nChn); + if(hasVolCommand) pPlugin->MidiCC(MIDIEvents::MIDICC_Volume_Coarse, std::min(uint8(127), vol), nChn); else pPlugin->MidiCC(MIDIEvents::MIDICC_Volume_Coarse, static_cast(std::min(uint32(127), static_cast(2 * defaultVolume))), nChn); break; default: diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Tables.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Tables.cpp index d1d1d470c..d8110f4e6 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Tables.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Tables.cpp @@ -72,6 +72,7 @@ static constexpr ModFormatInfo modFormatInfo[] = { UL_("Digital Tracker"), "dtm" }, { UL_("Farandole Composer"), "far" }, { UL_("FM Tracker"), "fmt" }, + { UL_("ProTracker"), "fst" }, { UL_("Imago Orpheus"), "imf" }, { UL_("Ice Tracker"), "ice" }, #ifdef MPT_EXTERNAL_SAMPLES diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/mod_specifications.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/mod_specifications.cpp index e6016da25..bfff37238 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/mod_specifications.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/mod_specifications.cpp @@ -327,7 +327,7 @@ constexpr CModSpecifications it_ = 255, // Max tempo 1, // Min Speed 255, // Max Speed - 1, // Min pattern rows + 32, // Min pattern rows 200, // Max pattern rows 25, // Max mod name length 25, // Max sample name length diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/pattern.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/pattern.cpp index 68f155bda..96dd326ec 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/pattern.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/pattern.cpp @@ -37,21 +37,32 @@ CHANNELINDEX CPattern::GetNumChannels() const noexcept bool CPattern::IsEmptyRow(ROWINDEX row) const noexcept { if(m_ModCommands.empty() || !IsValidRow(row)) - { return true; - } for(const auto &m : GetRow(row)) { if(!m.IsEmpty()) - { return false; - } } return true; } +// Check if the row contains any position jumps or pattern breaks. +bool CPattern::RowHasJump(ROWINDEX row) const noexcept +{ + if(m_ModCommands.empty() || !IsValidRow(row)) + return false; + + for(const auto &m : GetRow(row)) + { + if(m.command == CMD_PATTERNBREAK || m.command == CMD_POSITIONJUMP) + return true; + } + return false; +} + + bool CPattern::SetSignature(const ROWINDEX rowsPerBeat, const ROWINDEX rowsPerMeasure) noexcept { if(rowsPerBeat < 1 diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/pattern.h b/Frameworks/OpenMPT/OpenMPT/soundlib/pattern.h index 8e24191ad..bc75ac683 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/pattern.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/pattern.h @@ -60,6 +60,8 @@ public: // Check if there is any note data on a given row. bool IsEmptyRow(ROWINDEX row) const noexcept; + // Check if the row contains any position jumps or pattern breaks. + bool RowHasJump(ROWINDEX row) const noexcept; // Allocate new pattern memory and replace old pattern data. bool AllocatePattern(ROWINDEX rows); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PluginManager.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PluginManager.cpp index 1da7cf85a..80280a153 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PluginManager.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PluginManager.cpp @@ -238,7 +238,7 @@ void VSTPluginLib::WriteToCache() const const std::string crcName = dllPath.ToUTF8(); const mpt::crc32 crc(crcName); - const mpt::ustring IDs = mpt::ufmt::HEX0<8>(pluginId1) + mpt::ufmt::HEX0<8>(pluginId2) + mpt::ufmt::HEX0<8>(crc.result()); + const mpt::ustring IDs = mpt::ufmt::HEX0<8>(static_cast(pluginId1)) + mpt::ufmt::HEX0<8>(static_cast(pluginId2)) + mpt::ufmt::HEX0<8>(crc.result()); mpt::PathString writePath = dllPath; if(theApp.IsPortableMode()) @@ -570,19 +570,20 @@ VSTPluginLib *CVstPluginManager::AddPlugin(const mpt::PathString &dllPath, bool pluginList.push_back(plug); // Extract plugin IDs - for (int i = 0; i < 16; i++) + uint32 id1 = 0, id2 = 0; + for(int i = 0; i < 16; i++) { - int32 n = IDs[i] - '0'; - if (n > 9) n = IDs[i] + 10 - 'A'; - n &= 0x0f; + uint32 n = IDs[i] - '0'; + if(n > 9) + n = IDs[i] + 10 - 'A'; + n &= 0x0F; if (i < 8) - { - plug->pluginId1 = (plug->pluginId1 << 4) | n; - } else - { - plug->pluginId2 = (plug->pluginId2 << 4) | n; - } + id1 = (id1 << 4) | n; + else + id2 = (id2 << 4) | n; } + plug->pluginId1 = id1; + plug->pluginId2 = id2; const mpt::ustring flagKey = IDs + U_(".Flags"); plug->DecodeCacheFlags(cacheFile.Read(cacheSection, flagKey, 0)); diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_arch.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_arch.hpp index d066593df..f4192a4ba 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_arch.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_arch.hpp @@ -25,7 +25,7 @@ -#if defined(_M_ARM64) +#if defined(_M_ARM64) || defined(_M_ARM64EC) #define MPT_ARCH_AARCH64 1 #elif defined(_M_ARM) diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_compiler.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_compiler.hpp index fc11d160d..ef1b73af5 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_compiler.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_compiler.hpp @@ -50,7 +50,9 @@ #elif defined(_MSC_VER) #define MPT_COMPILER_MSVC 1 -#if (_MSC_VER >= 1940) +#if (_MSC_VER >= 1941) +#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 11) +#elif (_MSC_VER >= 1940) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 10) #elif (_MSC_VER >= 1939) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 9) @@ -204,6 +206,16 @@ +// detect compiler quirks + +#if MPT_COMPILER_CLANG +#if defined(__APPLE__) +#define MPT_COMPILER_QUIRK_APPLE_CLANG +#endif +#endif + + + // detect compiler setting quirks #if MPT_COMPILER_GCC diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_os.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_os.hpp index cb9d60b38..789a3faef 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_os.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_os.hpp @@ -52,13 +52,14 @@ #define MPT_WIN_10_1903 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x07) // NTDDI_WIN10_19H1 1903/19H1 #define MPT_WIN_10_1909 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x08) // NTDDI_WIN10_VB 1909/19H2 #define MPT_WIN_10_2004 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x09) // NTDDI_WIN10_MN 2004/20H1 - // 20H2 - // 21H1 -#define MPT_WIN_10_21H2 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x0a) // NTDDI_WIN10_FE 21H2 - // 22H2 +#define MPT_WIN_10_20H2 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x0a) // NTDDI_WIN10_FE 20H2 +#define MPT_WIN_10_21H1 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x0b) // NTDDI_WIN10_CO 21H1 +#define MPT_WIN_10_21H2 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x0c) // NTDDI_WIN10_NI 21H2 +#define MPT_WIN_10_22H2 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x0d) // NTDDI_WIN10_CU 22H2 -#define MPT_WIN_11 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x0b) // NTDDI_WIN10_CO 21H2 -#define MPT_WIN_11_22H2 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x0c) // NTDDI_WIN10_NI 22H2 +#define MPT_WIN_11 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x0e) // NTDDI_WIN11_ZN 21H2 +#define MPT_WIN_11_22H2 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x0f) // NTDDI_WIN11_GA 22H2 +#define MPT_WIN_11_23H2 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x10) // NTDDI_WIN11_GE 23H2 // MPT_WIN_API_DESKTOP : Windows 8/10 Desktop Application (Win32) // MPT_WIN_API_UNIVERSAL : Windows 10 Store App / Universal App @@ -227,13 +228,25 @@ static_assert(NTDDI_WIN10_VB == MPT_WIN_10_1909); static_assert(NTDDI_WIN10_MN == MPT_WIN_10_2004); #endif #ifdef NTDDI_WIN10_FE -static_assert(NTDDI_WIN10_FE == MPT_WIN_10_21H2); +static_assert(NTDDI_WIN10_FE == MPT_WIN_10_20H2); #endif #ifdef NTDDI_WIN10_CO -static_assert(NTDDI_WIN10_CO == MPT_WIN_11); +static_assert(NTDDI_WIN10_CO == MPT_WIN_10_21H1); #endif #ifdef NTDDI_WIN10_NI -static_assert(NTDDI_WIN10_NI == MPT_WIN_11_22H2); +static_assert(NTDDI_WIN10_NI == MPT_WIN_10_21H2); +#endif +#ifdef NTDDI_WIN10_CU +static_assert(NTDDI_WIN10_CU == MPT_WIN_10_22H2); +#endif +#ifdef NTDDI_WIN11_ZN +static_assert(NTDDI_WIN11_ZN == MPT_WIN_11); +#endif +#ifdef NTDDI_WIN11_GA +static_assert(NTDDI_WIN11_GA == MPT_WIN_11_22H2); +#endif +#ifdef NTDDI_WIN11_GE +static_assert(NTDDI_WIN11_GE == MPT_WIN_11_23H2); #endif #endif #if defined(WINAPI_FAMILY) diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_quirks.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_quirks.hpp index 8112a6712..29e0ca4a2 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_quirks.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_quirks.hpp @@ -312,4 +312,10 @@ +#if MPT_OS_ANDROID && MPT_LIBCXX_LLVM_BEFORE(17000) +#define MPT_LIBCXX_QUIRK_NO_NUMBERS +#endif + + + #endif // MPT_BASE_DETECT_QUIRKS_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/math.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/math.hpp index 23e50d73b..a158ad4f7 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/math.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/math.hpp @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ -#ifndef MPT_BASE_EMPTY_HPP -#define MPT_BASE_EMPTY_HPP +#ifndef MPT_BASE_MATH_HPP +#define MPT_BASE_MATH_HPP @@ -85,4 +85,4 @@ inline T safe_clamp(T v, T lo, T hi) { -#endif // MPT_BASE_EMPTY_HPP +#endif // MPT_BASE_MATH_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/numbers.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/numbers.hpp index a69f10ee4..f6248b99d 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/numbers.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/numbers.hpp @@ -6,9 +6,10 @@ #include "mpt/base/detect_compiler.hpp" +#include "mpt/base/detect_quirks.hpp" #include "mpt/base/namespace.hpp" -#if MPT_CXX_AT_LEAST(20) +#if MPT_CXX_AT_LEAST(20) && !defined(MPT_LIBCXX_QUIRK_NO_NUMBERS) #include #else #include @@ -25,7 +26,7 @@ inline namespace MPT_INLINE_NS { namespace numbers { -#if MPT_CXX_AT_LEAST(20) +#if MPT_CXX_AT_LEAST(20) && !defined(MPT_LIBCXX_QUIRK_NO_NUMBERS) template inline constexpr T e_v = std::numbers::e_v; diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/windows_version.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/windows_version.hpp index d84776e66..79c4d3dd3 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/windows_version.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/windows_version.hpp @@ -131,18 +131,20 @@ public: static mpt::osinfo::windows::Version FromSDK() noexcept { // Initialize to used SDK version -#if MPT_WINNT_AT_LEAST(MPT_WIN_11_22H2) +#if MPT_WINNT_AT_LEAST(MPT_WIN_11_23H2) + return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 22631, 0); +#elif MPT_WINNT_AT_LEAST(MPT_WIN_11_22H2) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 22621, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_11) // 21H2 return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 22000, 0); -//#elif // 22H2 -// return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19045, 0); +#elif MPT_WINNT_AT_LEAST(MPT_WIN_10_22H2) + return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19045, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_10_21H2) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19044, 0); -//#elif // 21H1 -// return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19043, 0); -//#elif // 20H2 -// return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19042, 0); +#elif MPT_WINNT_AT_LEAST(MPT_WIN_10_21H1) + return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19043, 0); +#elif MPT_WINNT_AT_LEAST(MPT_WIN_10_20H2) + return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19042, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_10_2004) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19041, 0); #elif MPT_WINNT_AT_LEAST(MPT_WIN_10_1909) diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/random/device.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/random/device.hpp index 4c306c363..213b48cea 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/random/device.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/random/device.hpp @@ -22,6 +22,7 @@ #if !defined(MPT_LIBCXX_QUIRK_NO_CHRONO) #include #endif // !MPT_LIBCXX_QUIRK_NO_CHRONO +#include #include #include #include diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/random/engine.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/random/engine.hpp index 1fc36e159..a7ef27193 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/random/engine.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/random/engine.hpp @@ -7,6 +7,7 @@ #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" +#include "mpt/base/numeric.hpp" #include "mpt/random/seed.hpp" #include @@ -47,7 +48,7 @@ struct engine_traits { } template static inline rng_type make(Trd & rd) { - std::unique_ptr> values = std::make_unique>(rd); + std::unique_ptr(seed_bits, sizeof(unsigned int) * 8) / (sizeof(unsigned int) * 8)>> values = std::make_unique(seed_bits, sizeof(unsigned int) * 8) / (sizeof(unsigned int) * 8)>>(rd); std::seed_seq seed(values->begin(), values->end()); return rng_type(seed); } @@ -65,7 +66,7 @@ struct engine_traits { } template static inline rng_type make(Trd & rd) { - std::unique_ptr> values = std::make_unique>(rd); + std::unique_ptr(seed_bits, sizeof(unsigned int) * 8) / (sizeof(unsigned int) * 8)>> values = std::make_unique(seed_bits, sizeof(unsigned int) * 8) / (sizeof(unsigned int) * 8)>>(rd); std::seed_seq seed(values->begin(), values->end()); return rng_type(seed); } @@ -83,7 +84,7 @@ struct engine_traits { } template static inline rng_type make(Trd & rd) { - mpt::seed_seq_values values(rd); + mpt::seed_seq_values(seed_bits, sizeof(unsigned int) * 8) / (sizeof(unsigned int) * 8)> values(rd); std::seed_seq seed(values.begin(), values.end()); return rng_type(seed); } @@ -101,7 +102,7 @@ struct engine_traits { } template static inline rng_type make(Trd & rd) { - mpt::seed_seq_values values(rd); + mpt::seed_seq_values(seed_bits, sizeof(unsigned int) * 8) / (sizeof(unsigned int) * 8)> values(rd); std::seed_seq seed(values.begin(), values.end()); return rng_type(seed); } @@ -119,7 +120,7 @@ struct engine_traits { } template static inline rng_type make(Trd & rd) { - mpt::seed_seq_values values(rd); + mpt::seed_seq_values(seed_bits, sizeof(unsigned int) * 8) / (sizeof(unsigned int) * 8)> values(rd); std::seed_seq seed(values.begin(), values.end()); return rng_type(seed); } @@ -137,7 +138,7 @@ struct engine_traits { } template static inline rng_type make(Trd & rd) { - mpt::seed_seq_values values(rd); + mpt::seed_seq_values(seed_bits, sizeof(unsigned int) * 8) / (sizeof(unsigned int) * 8)> values(rd); std::seed_seq seed(values.begin(), values.end()); return rng_type(seed); } diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/random/random.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/random/random.hpp index 2f4a30c42..a0a9fdfa4 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/random/random.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/random/random.hpp @@ -8,8 +8,11 @@ #include "mpt/base/namespace.hpp" #include "mpt/random/engine.hpp" +#include #include +#include + namespace mpt { inline namespace MPT_INLINE_NS { diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/string/buffer.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/string/buffer.hpp index eafa65c76..f36f3e6cb 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/string/buffer.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/string/buffer.hpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include diff --git a/Info.plist.template b/Info.plist.template index bb2cd6593..10fcf2455 100644 --- a/Info.plist.template +++ b/Info.plist.template @@ -1537,6 +1537,7 @@ dtm far fmt + fst imf ice j2b