From 7e98a0398bd4a4043f537e9f5941493251ef8796 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Fri, 10 Jan 2025 14:38:44 -0800 Subject: [PATCH] Updated libOpenMPT to version 0.7.13 Signed-off-by: Christopher Snowhill --- Frameworks/OpenMPT/OpenMPT/LICENSE | 2 +- Frameworks/OpenMPT/OpenMPT/Makefile | 33 +++++- Frameworks/OpenMPT/OpenMPT/build/dist.mk | 6 +- .../OpenMPT/build/download_externals.sh | 2 +- .../OpenMPT/build/make/config-cygwin.mk | 84 ++++++++++++++ .../OpenMPT/build/make/config-defaults.mk | 4 + .../OpenMPT/build/make/config-mingw-w64.mk | 2 + .../OpenMPT/build/svn_version/svn_version.h | 8 +- .../ext/mpg123.xcodeproj/project.pbxproj | 4 +- .../ext/mpg123.xcodeproj/project.pbxproj | 4 +- Frameworks/OpenMPT/OpenMPT/common/mptString.h | 8 ++ Frameworks/OpenMPT/OpenMPT/common/version.cpp | 8 +- .../OpenMPT/OpenMPT/common/versionNumber.h | 2 +- .../contrib/libmodplug-0.8.8.5/LICENSE | 2 +- .../contrib/libmodplug-0.8.9.0/LICENSE | 2 +- .../examples/libopenmpt_example_c_unsafe.c | 3 + .../libopenmpt/in_openmpt/in_openmpt.cpp | 2 +- .../OpenMPT/OpenMPT/libopenmpt/libopenmpt.hpp | 22 ++-- .../OpenMPT/libopenmpt/libopenmpt_version.h | 2 +- .../OpenMPT/libopenmpt/libopenmpt_version.mk | 4 +- .../OpenMPT/libopenmpt/libopenmpt_version.rc | 2 +- .../libopenmpt/xmp-openmpt/xmp-openmpt.cpp | 19 +++- .../OpenMPT/OpenMPT/openmpt123/openmpt123.cpp | 6 +- .../OpenMPT/OpenMPT/soundlib/Dlsbank.cpp | 6 + .../OpenMPT/soundlib/ITCompression.cpp | 3 +- .../OpenMPT/soundlib/InstrumentExtensions.cpp | 103 ++++++++---------- .../OpenMPT/OpenMPT/soundlib/Load_itp.cpp | 10 +- .../OpenMPT/OpenMPT/soundlib/Load_mo3.cpp | 2 +- .../OpenMPT/OpenMPT/soundlib/Load_mod.cpp | 4 + .../OpenMPT/OpenMPT/soundlib/Load_xm.cpp | 11 +- .../OpenMPT/OpenMPT/soundlib/ModSample.h | 4 + .../OpenMPT/soundlib/SampleFormats.cpp | 6 +- .../OpenMPT/OpenMPT/soundlib/Snd_defs.h | 6 +- .../OpenMPT/OpenMPT/soundlib/Snd_fx.cpp | 33 ++++-- .../OpenMPT/OpenMPT/soundlib/Sndfile.cpp | 20 ++-- Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.h | 6 +- .../OpenMPT/OpenMPT/soundlib/Sndmix.cpp | 2 +- .../OpenMPT/OpenMPT/soundlib/XMTools.cpp | 62 +++++------ Frameworks/OpenMPT/OpenMPT/soundlib/XMTools.h | 24 ++-- .../OpenMPT/OpenMPT/soundlib/modsmp_ctrl.cpp | 3 +- .../OpenMPT/src/mpt/LICENSE.BSD-3-Clause.txt | 2 +- .../OpenMPT/src/mpt/base/arithmetic_shift.hpp | 2 - .../OpenMPT/src/mpt/base/detect_os.hpp | 7 ++ .../OpenMPT/src/mpt/base/detect_quirks.hpp | 30 +++++ .../OpenMPT/src/mpt/base/saturate_round.hpp | 2 +- .../OpenMPT/src/mpt/base/source_location.hpp | 6 +- .../OpenMPT/OpenMPT/src/mpt/check/libc.hpp | 11 ++ .../OpenMPT/OpenMPT/src/mpt/check/windows.hpp | 8 ++ .../src/mpt/io_file_adapter/fileadapter.hpp | 4 + .../src/mpt/string_transcode/transcode.hpp | 101 +++++++++++++++++ 50 files changed, 524 insertions(+), 185 deletions(-) create mode 100644 Frameworks/OpenMPT/OpenMPT/build/make/config-cygwin.mk diff --git a/Frameworks/OpenMPT/OpenMPT/LICENSE b/Frameworks/OpenMPT/OpenMPT/LICENSE index c9db5fcfc..d916fe2fc 100644 --- a/Frameworks/OpenMPT/OpenMPT/LICENSE +++ b/Frameworks/OpenMPT/OpenMPT/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2024, OpenMPT Project Developers and Contributors +Copyright (c) 2004-2025, OpenMPT Project Developers and Contributors Copyright (c) 1997-2003, Olivier Lapicque All rights reserved. diff --git a/Frameworks/OpenMPT/OpenMPT/Makefile b/Frameworks/OpenMPT/OpenMPT/Makefile index d8936835a..e2e82dad8 100644 --- a/Frameworks/OpenMPT/OpenMPT/Makefile +++ b/Frameworks/OpenMPT/OpenMPT/Makefile @@ -256,6 +256,27 @@ NUMTHREADS:=$(shell nproc) else ifeq ($(OS),Windows_NT) +ifeq ($(shell uname -o),Cygwin) + +HOST=unix +HOST_FLAVOUR=CYGWIN + +TOOLCHAIN_SUFFIX= + +CPPCHECK = cppcheck + +MKDIR_P = mkdir -p +RM = rm -f +RMTREE = rm -rf +INSTALL = install +INSTALL_MAKE_DIR = install -d +INSTALL_DIR = cp -r -v +FIXPATH = $1 + +NUMTHREADS:=$(NUMBER_OF_PROCESSORS) + +else + HOST=windows HOST_FLAVOUR= @@ -273,6 +294,8 @@ FIXPATH = $(subst /,\,$1) NUMTHREADS:=$(NUMBER_OF_PROCESSORS) +endif + else HOST=unix @@ -689,7 +712,7 @@ ifeq ($(LOCAL_MPG123),1) CPPFLAGS_MPG123 := -DMPT_WITH_MPG123 -DMPG123_NO_LARGENAME LDFLAGS_MPG123 := LDLIBS_MPG123 := -CPPFLAGS_MPG123 += -Iinclude/mpg123/src/include/ -Iinclude/mpg123/ports/makefile/ +CPPFLAGS_MPG123 += -Iinclude/mpg123/src/include/ -Iinclude/mpg123/ports/generic/ LOCAL_MPG123_SOURCES := LOCAL_MPG123_SOURCES += include/mpg123/src/compat/compat.c LOCAL_MPG123_SOURCES += include/mpg123/src/compat/compat_str.c @@ -721,10 +744,10 @@ include/mpg123/src/compat/%$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) -DOPT_GENER include/mpg123/src/compat/%.test$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) -DOPT_GENERIC include/mpg123/src/libmpg123/%$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) -DOPT_GENERIC include/mpg123/src/libmpg123/%.test$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) -DOPT_GENERIC -include/mpg123/src/compat/%$(FLAVOUR_O).o : CPPFLAGS:= -Iinclude/mpg123/src/include/ -Iinclude/mpg123/ports/makefile/ $(CPPFLAGS) -include/mpg123/src/compat/%.test$(FLAVOUR_O).o : CPPFLAGS:= -Iinclude/mpg123/src/include/ -Iinclude/mpg123/ports/makefile/ $(CPPFLAGS) -include/mpg123/src/libmpg123/%$(FLAVOUR_O).o : CPPFLAGS:= -Iinclude/mpg123/src/include/ -Iinclude/mpg123/ports/makefile/ $(CPPFLAGS) -include/mpg123/src/libmpg123/%.test$(FLAVOUR_O).o : CPPFLAGS:= -Iinclude/mpg123/src/include/ -Iinclude/mpg123/ports/makefile/ $(CPPFLAGS) +include/mpg123/src/compat/%$(FLAVOUR_O).o : CPPFLAGS:= -Iinclude/mpg123/src/include/ -Iinclude/mpg123/ports/generic/ $(CPPFLAGS) +include/mpg123/src/compat/%.test$(FLAVOUR_O).o : CPPFLAGS:= -Iinclude/mpg123/src/include/ -Iinclude/mpg123/ports/generic/ $(CPPFLAGS) +include/mpg123/src/libmpg123/%$(FLAVOUR_O).o : CPPFLAGS:= -Iinclude/mpg123/src/include/ -Iinclude/mpg123/ports/generic/ $(CPPFLAGS) +include/mpg123/src/libmpg123/%.test$(FLAVOUR_O).o : CPPFLAGS:= -Iinclude/mpg123/src/include/ -Iinclude/mpg123/ports/generic/ $(CPPFLAGS) else ifeq ($(NO_MPG123),1) else diff --git a/Frameworks/OpenMPT/OpenMPT/build/dist.mk b/Frameworks/OpenMPT/OpenMPT/build/dist.mk index a6bed4b06..c558fe7fc 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/dist.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/dist.mk @@ -1,4 +1,4 @@ -MPT_SVNVERSION=22406 -MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.7.12 -MPT_SVNDATE=2024-12-01T13:10:15.135688Z +MPT_SVNVERSION=22826 +MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.7.13 +MPT_SVNDATE=2025-01-06T13:49:43.586768Z diff --git a/Frameworks/OpenMPT/OpenMPT/build/download_externals.sh b/Frameworks/OpenMPT/OpenMPT/build/download_externals.sh index 22abc8605..1c8ac95cf 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/download_externals.sh +++ b/Frameworks/OpenMPT/OpenMPT/build/download_externals.sh @@ -99,7 +99,7 @@ download "build/externals/allegro-4.2.3.1-hg.8+r8500.zip" 3872466 46cd8d4d7138b7 download "build/externals/csdpmi7b.zip" 71339 58c24691d27cead1cec92d334af551f37a3ba31de25a687d99399c28d822ec9f6ffccc9332bfce35e65dae4dd1210b54e54b223a4de17f5adcb11e2da004b834 "https://lib.openmpt.org/files/libopenmpt/contrib/djgpp/cwsdpmi/csdpmi7b.zip https://djgpp.mirror.garr.it/current/v2misc/csdpmi7b.zip" download "build/externals/csdpmi7s.zip" 89872 ea5652d31850d8eb0d15a919de0b51849f58efea0d16ad2aa4687fac4abd223d0ca34a2d1b616b02fafe84651dbef3e506df9262cfb399eb6d9909bffc89bfd3 "https://lib.openmpt.org/files/libopenmpt/contrib/djgpp/cwsdpmi/csdpmi7s.zip https://djgpp.mirror.garr.it/current/v2misc/csdpmi7s.zip" download "build/externals/WA5.55_SDK.exe" 336166 394375db8a16bf155b5de9376f6290488ab339e503dbdfdc4e2f5bede967799e625c559cca363bc988324f1a8e86e5fd28a9f697422abd7bb3dcde4a766607b5 "http://download.nullsoft.com/winamp/plugin-dev/WA5.55_SDK.exe https://web.archive.org/web/20131217072017id_/http://download.nullsoft.com/winamp/plugin-dev/WA5.55_SDK.exe" -download "build/externals/xmp-sdk.zip" 322744 62c442d656d4bb380360368a0f5f01da11b4ed54333d7f54f875a9a5ec390b08921e00bd08e62cd7a0a5fe642e3377023f20a950cc2a42898ff4cda9ab88fc91 "https://www.un4seen.com/files/xmp-sdk.zip" +download "build/externals/xmp-sdk.zip" 322903 67b96c6e6aa794e9de4f446d23f969e3591457196fd100c5475f5df52308de861a0c411db54fcb2bf46a12e9136ddda9d2974a5167432a979a701ef2c4679ef9 "https://www.un4seen.com/files/xmp-sdk.zip" unpack "include/allegro42" "build/externals/allegro-4.2.3.1-hg.8+r8500.zip" "." unpack "include/cwsdpmi" "build/externals/csdpmi7b.zip" "." diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-cygwin.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-cygwin.mk new file mode 100644 index 000000000..9894887a5 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-cygwin.mk @@ -0,0 +1,84 @@ + +ifeq ($(origin CC),default) +CC = $(TOOLCHAIN_PREFIX)gcc$(TOOLCHAIN_SUFFIX) +endif +ifeq ($(origin CXX),default) +CXX = $(TOOLCHAIN_PREFIX)g++$(TOOLCHAIN_SUFFIX) +endif +ifeq ($(origin LD),default) +LD = $(CXX) +endif +ifeq ($(origin AR),default) +AR = $(TOOLCHAIN_PREFIX)ar$(TOOLCHAIN_SUFFIX) +endif + +ifneq ($(STDCXX),) +CXXFLAGS_STDCXX = -std=$(STDCXX) -fexceptions -frtti -pthread +else ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=c++20 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++20' ; fi ), c++20) +CXXFLAGS_STDCXX = -std=c++20 -fexceptions -frtti -pthread +else +CXXFLAGS_STDCXX = -std=c++17 -fexceptions -frtti -pthread +endif +ifneq ($(STDC),) +CFLAGS_STDC = -std=$(STDC) -pthread +else ifeq ($(shell printf '\n' > bin/empty.c ; if $(CC) -std=c18 -c bin/empty.c -o bin/empty.out > /dev/null 2>&1 ; then echo 'c18' ; fi ), c18) +CFLAGS_STDC = -std=c18 -pthread +else ifeq ($(shell printf '\n' > bin/empty.c ; if $(CC) -std=c17 -c bin/empty.c -o bin/empty.out > /dev/null 2>&1 ; then echo 'c17' ; fi ), c17) +CFLAGS_STDC = -std=c17 -pthread +else +CFLAGS_STDC = -std=c11 -pthread +endif +CXXFLAGS += $(CXXFLAGS_STDCXX) +CFLAGS += $(CFLAGS_STDC) +LDFLAGS += -pthread + +CPPFLAGS += +CXXFLAGS += -fPIC +CFLAGS += -fPIC +LDFLAGS += +LDLIBS += -lm +ARFLAGS := rcs + +ifeq ($(NATIVE),1) +CXXFLAGS += -march=native +CFLAGS += -march=native +endif + +ifeq ($(MODERN),1) +LDFLAGS += -fuse-ld=gold +endif + +ifeq ($(OPTIMIZE_LTO),1) +CXXFLAGS += -flto +CFLAGS += -flto +endif + +ifeq ($(ANALYZE),1) +CXXFLAGS += -fanalyzer -Wno-analyzer-malloc-leak -Wno-analyzer-null-dereference -Wno-analyzer-possible-null-argument -Wno-analyzer-possible-null-dereference +CFLAGS += -fanalyzer -Wno-analyzer-malloc-leak -Wno-analyzer-null-dereference -Wno-analyzer-possible-null-argument -Wno-analyzer-possible-null-dereference +endif + +ifeq ($(CHECKED_ADDRESS),1) +CXXFLAGS += -fsanitize=address +CFLAGS += -fsanitize=address +endif + +ifeq ($(CHECKED_UNDEFINED),1) +CXXFLAGS += -fsanitize=undefined +CFLAGS += -fsanitize=undefined +endif + +include build/make/warnings-gcc.mk + +EXESUFFIX=.exe +SOSUFFIX=.dll +SOSUFFIXWINDOWS=1 + +ALLOW_LGPL=0 + +DYNLINK=0 +SHARED_LIB=1 +STATIC_LIB=0 +SHARED_SONAME=0 + +ENABLE_DLL=1 diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-defaults.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-defaults.mk index b08533b6b..cc0a94132 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-defaults.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-defaults.mk @@ -25,6 +25,10 @@ WINDOWS_ARCH=x86 include build/make/config-mingw-w64.mk endif +else ifeq ($(HOST_FLAVOUR),CYGWIN) + +include build/make/config-cygwin.mk + else ifeq ($(HOST_FLAVOUR),LINUX) include build/make/config-gcc.mk diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw-w64.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw-w64.mk index 2e17c4f8c..46536c8e1 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw-w64.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw-w64.mk @@ -55,10 +55,12 @@ CFLAGS += $(CFLAGS_STDC) CPPFLAGS += -DNOMINMAX ifeq ($(MINGW_COMPILER),clang) +CPPFLAGS += -D_UNICODE CXXFLAGS += -municode CFLAGS += -municode LDFLAGS += -mconsole -mthreads else +CPPFLAGS += -D_UNICODE CXXFLAGS += -municode -mthreads CFLAGS += -municode -mthreads LDFLAGS += -mconsole diff --git a/Frameworks/OpenMPT/OpenMPT/build/svn_version/svn_version.h b/Frameworks/OpenMPT/OpenMPT/build/svn_version/svn_version.h index 55a863d78..fc930eb18 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 "22406" -#define OPENMPT_VERSION_REVISION 22406 +#define OPENMPT_VERSION_SVNVERSION "22826" +#define OPENMPT_VERSION_REVISION 22826 #define OPENMPT_VERSION_DIRTY 0 #define OPENMPT_VERSION_MIXEDREVISIONS 0 -#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.7.12" -#define OPENMPT_VERSION_DATE "2024-12-01T13:10:15.135688Z" +#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.7.13" +#define OPENMPT_VERSION_DATE "2025-01-06T13:49:43.586768Z" #define OPENMPT_VERSION_IS_PACKAGE 1 diff --git a/Frameworks/OpenMPT/OpenMPT/build/xcode-ios/ext/mpg123.xcodeproj/project.pbxproj b/Frameworks/OpenMPT/OpenMPT/build/xcode-ios/ext/mpg123.xcodeproj/project.pbxproj index b0051d8ad..038a6029a 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/xcode-ios/ext/mpg123.xcodeproj/project.pbxproj +++ b/Frameworks/OpenMPT/OpenMPT/build/xcode-ios/ext/mpg123.xcodeproj/project.pbxproj @@ -257,7 +257,7 @@ ONLY_ACTIVE_ARCH = YES; SYMROOT = "../../../bin/debug/xcode4-ios/all"; USER_HEADER_SEARCH_PATHS = ( - ../../../include/mpg123/ports/Xcode, + ../../../include/mpg123/ports/generic, ../../../include/mpg123/src/include, ); }; @@ -295,7 +295,7 @@ ONLY_ACTIVE_ARCH = NO; SYMROOT = "../../../bin/release/xcode4-ios/all"; USER_HEADER_SEARCH_PATHS = ( - ../../../include/mpg123/ports/Xcode, + ../../../include/mpg123/ports/generic, ../../../include/mpg123/src/include, ); }; diff --git a/Frameworks/OpenMPT/OpenMPT/build/xcode-macosx/ext/mpg123.xcodeproj/project.pbxproj b/Frameworks/OpenMPT/OpenMPT/build/xcode-macosx/ext/mpg123.xcodeproj/project.pbxproj index b1284dc20..3ad02f662 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/xcode-macosx/ext/mpg123.xcodeproj/project.pbxproj +++ b/Frameworks/OpenMPT/OpenMPT/build/xcode-macosx/ext/mpg123.xcodeproj/project.pbxproj @@ -257,7 +257,7 @@ ONLY_ACTIVE_ARCH = YES; SYMROOT = "../../../bin/debug/xcode4-macosx/all"; USER_HEADER_SEARCH_PATHS = ( - ../../../include/mpg123/ports/Xcode, + ../../../include/mpg123/ports/generic, ../../../include/mpg123/src/include, ); }; @@ -295,7 +295,7 @@ ONLY_ACTIVE_ARCH = NO; SYMROOT = "../../../bin/release/xcode4-macosx/all"; USER_HEADER_SEARCH_PATHS = ( - ../../../include/mpg123/ports/Xcode, + ../../../include/mpg123/ports/generic, ../../../include/mpg123/src/include, ); }; diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptString.h b/Frameworks/OpenMPT/OpenMPT/common/mptString.h index 16fc64c49..99b5f7e6c 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptString.h +++ b/Frameworks/OpenMPT/OpenMPT/common/mptString.h @@ -429,7 +429,11 @@ inline mpt::ustring ToUnicode(uint16 codepage, Tencoding &&fallback, Tsrc &&str) std::optional charset = mpt::optional_encoding_from_codepage(codepage); if(charset.has_value()) { +#if defined(MPT_LIBCXX_QUIRK_NO_OPTIONAL_VALUE) + result = mpt::transcode(*charset, std::forward(str)); +#else result = mpt::transcode(charset.value(), std::forward(str)); +#endif } else if(mpt::has_codepage(static_cast(codepage))) { result = mpt::transcode(static_cast(codepage), std::forward(str)); @@ -440,7 +444,11 @@ inline mpt::ustring ToUnicode(uint16 codepage, Tencoding &&fallback, Tsrc &&str) return result; #else // !MPT_OS_WINDOWS std::optional charset = mpt::optional_encoding_from_codepage(codepage); +#if defined(MPT_LIBCXX_QUIRK_NO_OPTIONAL_VALUE) return charset.has_value() ? mpt::transcode(charset.value(), std::forward(str)) : mpt::transcode(std::forward(fallback), std::forward(str)); +#else + return charset.has_value() ? mpt::transcode(*charset, std::forward(str)) : mpt::transcode(std::forward(fallback), std::forward(str)); +#endif #endif // MPT_OS_WINDOWS } diff --git a/Frameworks/OpenMPT/OpenMPT/common/version.cpp b/Frameworks/OpenMPT/OpenMPT/common/version.cpp index a8b444c47..8ecd9d42a 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/version.cpp +++ b/Frameworks/OpenMPT/OpenMPT/common/version.cpp @@ -600,12 +600,12 @@ mpt::ustring GetFullCreditsString() "libopenmpt (based on OpenMPT / Open ModPlug Tracker)\n" #endif "\n" - "Copyright \xC2\xA9 2004-2024 OpenMPT Project Developers and Contributors\n" + "Copyright \xC2\xA9 2004-2025 OpenMPT Project Developers and Contributors\n" "Copyright \xC2\xA9 1997-2003 Olivier Lapicque\n" "\n" "Developers:\n" - "Johannes Schultz (2008-2024)\n" - "J\xC3\xB6rn Heusipp (2012-2024)\n" + "Johannes Schultz (2008-2025)\n" + "J\xC3\xB6rn Heusipp (2012-2025)\n" "Ahti Lepp\xC3\xA4nen (2005-2011)\n" "Robin Fernandes (2004-2007)\n" "Sergiy Pylypenko (2007)\n" @@ -803,7 +803,7 @@ mpt::ustring GetFullCreditsString() mpt::ustring GetLicenseString() { return MPT_UTF8( - "Copyright (c) 2004-2024, OpenMPT Project Developers and Contributors" "\n" + "Copyright (c) 2004-2025, OpenMPT Project Developers and Contributors" "\n" "Copyright (c) 1997-2003, Olivier Lapicque" "\n" "All rights reserved." "\n" "" "\n" diff --git a/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h b/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h index 29f85967c..d0683a02d 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 13 +#define VER_MINOR 14 #define VER_MINORMINOR 00 OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/LICENSE b/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/LICENSE index c9db5fcfc..d916fe2fc 100644 --- a/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/LICENSE +++ b/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2024, OpenMPT Project Developers and Contributors +Copyright (c) 2004-2025, OpenMPT Project Developers and Contributors Copyright (c) 1997-2003, Olivier Lapicque All rights reserved. diff --git a/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/LICENSE b/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/LICENSE index c9db5fcfc..d916fe2fc 100644 --- a/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/LICENSE +++ b/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2024, OpenMPT Project Developers and Contributors +Copyright (c) 2004-2025, OpenMPT Project Developers and Contributors Copyright (c) 1997-2003, Olivier Lapicque All rights reserved. diff --git a/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_unsafe.c b/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_unsafe.c index 7677ba8af..78b460eda 100644 --- a/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_unsafe.c +++ b/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_unsafe.c @@ -83,6 +83,9 @@ int main( int argc, char * argv[] ) { file = fopen( argv[1], "rb" ); #endif mod = openmpt_module_create2( openmpt_stream_get_file_callbacks2(), file, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); +#if defined( __clang__ ) && defined( __clang_analyzer__ ) + [[clang::suppress]] +#endif fclose( file ); Pa_Initialize(); Pa_OpenDefaultStream( &stream, 0, 2, paInt16 | paNonInterleaved, SAMPLERATE, paFramesPerBufferUnspecified, NULL, NULL ); diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/in_openmpt/in_openmpt.cpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/in_openmpt/in_openmpt.cpp index 2af556c74..d697b9fd4 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/in_openmpt/in_openmpt.cpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/in_openmpt/in_openmpt.cpp @@ -223,7 +223,7 @@ static void config( HWND hwndParent ) { static void about( HWND hwndParent ) { std::ostringstream about; about << SHORT_TITLE << " version " << openmpt::string::get( "library_version" ) << " " << "(built " << openmpt::string::get( "build" ) << ")" << std::endl; - about << " Copyright (c) 2013-2024 OpenMPT Project Developers and Contributors (https://lib.openmpt.org/)" << std::endl; + about << " Copyright (c) 2013-2025 OpenMPT Project Developers and Contributors (https://lib.openmpt.org/)" << std::endl; about << " OpenMPT version " << openmpt::string::get( "core_version" ) << std::endl; about << std::endl; about << openmpt::string::get( "contact" ) << std::endl; diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.hpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.hpp index 66f24877d..8bcd47a6c 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.hpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.hpp @@ -49,25 +49,25 @@ * * libopenmpt can use 3 different strategies for file I/O. * - * - openmpt::module::module() with any kind of memory buffer as parameter will - * load the module from the provided memory buffer, which will require loading - * all data upfront by the library - * caller. * - openmpt::module::module() with a seekable std::istream as parameter will - * load the module via the stream interface. libopenmpt will not implement an - * additional buffering layer in this case whih means the callbacks are assumed - * to be performant even with small i/o sizes. + * load the module via the stream interface. This is the recommended strategy. * - openmpt::module::module() with an unseekable std::istream as parameter * will load the module via the stream interface. libopempt will make an * internal copy as it goes along, and sometimes have to pre-cache the whole * file in case it needs to know the complete file size. This strategy is * intended to be used if the file is located on a high latency network. + * - openmpt::module::module() with any kind of memory buffer as parameter will + * load the module from the provided memory buffer, which will require loading + * all data upfront by the library caller. This strategy has the disadvantage of + * requiring all data to be loaded even when the module loading happens to fail + * after that. It should only be used when the data has already been loaded into + * memory for other reasons. * - * | constructor | speed | memory consumption | - * | ----------------: | :----: | :----------------: | - * | memory buffer |

fast

|

medium

| - * | seekable stream |

slow

|

low

| + * | constructor | speed | memory consumption | + * | ----------------: | :---: | :----------------: | + * | seekable stream |

medium

|

low

| * | unseekable stream |

medium

|

high

| + * | memory buffer |

fast

|

medium

| * * In all cases, the data or stream passed to the constructor is no longer * needed after the openmpt::module has been constructed and can be destroyed diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h index ac2640567..8f03baee2 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 12 +#define OPENMPT_API_VERSION_PATCH 13 /*! \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 a1b0f4e02..89eb7aaba 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=12 +LIBOPENMPT_VERSION_PATCH=13 LIBOPENMPT_VERSION_PREREL= LIBOPENMPT_LTVER_CURRENT=4 -LIBOPENMPT_LTVER_REVISION=12 +LIBOPENMPT_LTVER_REVISION=13 LIBOPENMPT_LTVER_AGE=4 diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.rc b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.rc index bd35f7ac4..37bc9ccdd 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.rc +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.rc @@ -192,7 +192,7 @@ BEGIN VALUE "FileDescription", VER_FILEDESC_STR VALUE "FileVersion", VER_FILEVERSION_STR VALUE "InternalName", VER_FILENAME_STR - VALUE "LegalCopyright", "Copyright © 2004-2024 OpenMPT Project Developers and Contributors, Copyright © 1997-2003 Olivier Lapicque" + VALUE "LegalCopyright", "Copyright © 2004-2025 OpenMPT Project Developers and Contributors, Copyright © 1997-2003 Olivier Lapicque" VALUE "OriginalFilename", VER_FILENAME_STR VALUE "ProductName", "libopenmpt" VALUE "ProductVersion", VER_FILEVERSION_STR diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt/xmp-openmpt.cpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt/xmp-openmpt.cpp index dd436bbcf..b2609a7f8 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt/xmp-openmpt.cpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt/xmp-openmpt.cpp @@ -46,7 +46,14 @@ static const char * xmp_openmpt_string = "OpenMPT (" OPENMPT_API_VERSION_STRING #define USE_XMPLAY_ISTREAM +// XMPLAY expects a WINAPI (which is __stdcall) function using an undecorated symbol name which conflicts with the provided declaration. +#if defined(__GNUC__) +#define XMPIN_GetInterface XMPIN_GetInterface_Dummy +#endif #include "xmplay/xmpin.h" +#if defined(__GNUC__) +#undef XMPIN_GetInterface +#endif // Shortcut block assigned to the OpenMPT plugin by un4seen. enum { @@ -107,7 +114,9 @@ static void apply_and_save_options(); static std::string convert_to_native( const std::string & str ); +#if !defined(UNICODE) static std::string StringEncode( const std::wstring &src, UINT codepage ); +#endif static std::wstring StringDecode( const std::string & src, UINT codepage ); @@ -187,6 +196,7 @@ static std::string convert_to_native( const std::string & str ) { return result; } +#if !defined(UNICODE) static std::string StringEncode( const std::wstring &src, UINT codepage ) { int required_size = WideCharToMultiByte( codepage, 0, src.c_str(), -1, nullptr, 0, nullptr, nullptr); @@ -198,6 +208,7 @@ static std::string StringEncode( const std::wstring &src, UINT codepage ) WideCharToMultiByte( codepage, 0, src.c_str(), -1, encoded_string.data(), encoded_string.size(), nullptr, nullptr); return encoded_string.data(); } +#endif static std::wstring StringDecode( const std::string & src, UINT codepage ) { @@ -489,7 +500,7 @@ static void clear_current_timeinfo() { static void WINAPI openmpt_About( HWND win ) { std::ostringstream about; about << SHORT_TITLE << " version " << openmpt::string::get( "library_version" ) << " " << "(built " << openmpt::string::get( "build" ) << ")" << std::endl; - about << " Copyright (c) 2013-2024 OpenMPT Project Developers and Contributors (https://lib.openmpt.org/)" << std::endl; + about << " Copyright (c) 2013-2025 OpenMPT Project Developers and Contributors (https://lib.openmpt.org/)" << std::endl; about << " OpenMPT version " << openmpt::string::get( "core_version" ) << std::endl; about << std::endl; about << openmpt::string::get( "contact" ) << std::endl; @@ -998,6 +1009,7 @@ static void WINAPI openmpt_SetFormat( XMPFORMAT * form ) { form->rate = 0; form->chan = 0; form->res = 0; + form->chanmask = 0; return; } if ( self->settings.samplerate != 0 ) { @@ -1026,6 +1038,7 @@ static void WINAPI openmpt_SetFormat( XMPFORMAT * form ) { } } form->res = 4; // float + form->chanmask = 0; } // get the tags @@ -1704,7 +1717,9 @@ static XMPIN xmpin = { nullptr, // reserved2 openmpt_GetConfig, - openmpt_SetConfig + openmpt_SetConfig, + + nullptr }; static const char * xmp_openmpt_default_exts = "OpenMPT\0mptm/mptmz"; diff --git a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.cpp b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.cpp index 610603d16..6981dd7d3 100644 --- a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.cpp +++ b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.cpp @@ -8,7 +8,7 @@ */ static const char * const license = -"Copyright (c) 2004-2024, OpenMPT Project Developers and Contributors" "\n" +"Copyright (c) 2004-2025, OpenMPT Project Developers and Contributors" "\n" "Copyright (c) 1997-2003, Olivier Lapicque" "\n" "All rights reserved." "\n" "" "\n" @@ -385,7 +385,7 @@ static void show_banner( concat_stream & log, verbosity banner ) { return; } log << MPT_USTRING("openmpt123") << MPT_USTRING(" v") << mpt::transcode( mpt::source_encoding, OPENMPT123_VERSION_STRING ) << MPT_USTRING(", libopenmpt ") << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "library_version" ) ) << MPT_USTRING(" (") << MPT_USTRING("OpenMPT ") << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "core_version" ) ) << MPT_USTRING(")") << lf; - log << MPT_USTRING("Copyright (c) 2013-2024 OpenMPT Project Developers and Contributors ") << lf; + log << MPT_USTRING("Copyright (c) 2013-2025 OpenMPT Project Developers and Contributors ") << lf; if ( banner == verbosity_normal ) { log << lf; return; @@ -462,7 +462,7 @@ static void show_banner( concat_stream & log, verbosity banner ) { static void show_man_version( textout & log ) { log << MPT_USTRING("openmpt123") << MPT_USTRING(" v") << mpt::transcode( mpt::source_encoding, OPENMPT123_VERSION_STRING ) << lf; log << lf; - log << MPT_USTRING("Copyright (c) 2013-2024 OpenMPT Project Developers and Contributors ") << lf; + log << MPT_USTRING("Copyright (c) 2013-2025 OpenMPT Project Developers and Contributors ") << lf; } static void show_short_version( textout & log ) { diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp index b0b08cf12..f865cfdda 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp @@ -1415,7 +1415,13 @@ bool CDLSBank::Open(FileReader file) uint32 nInsDef; if(file.GetOptionalFileName()) + { +#if defined(MPT_LIBCXX_QUIRK_NO_OPTIONAL_VALUE) + m_szFileName = *(file.GetOptionalFileName()); +#else m_szFileName = file.GetOptionalFileName().value(); +#endif + } file.Rewind(); if(!file.CanRead(256)) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ITCompression.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/ITCompression.cpp index b7ed19970..28ce870d9 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ITCompression.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ITCompression.cpp @@ -154,10 +154,11 @@ void ITCompression::CompressBlock(const typename Properties::sample_t *data, Smp { if(bwt[i] != width) { + MPT_ASSERT(width >= 0); if(width <= 6) { // Mode A: 1 to 6 bits - MPT_ASSERT(width); + MPT_ASSERT(width != 0); WriteBits(width, (1 << (width - 1))); WriteBits(Properties::fetchA, ConvertWidth(width, bwt[i])); } else if(width < Properties::defWidth) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/InstrumentExtensions.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/InstrumentExtensions.cpp index 8997a111a..b9c83f36f 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/InstrumentExtensions.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/InstrumentExtensions.cpp @@ -483,6 +483,42 @@ void CSoundFile::WriteInstrumentPropertyForAllInstruments(uint32 code, uint16 si #endif // !MODPLUG_NO_FILESAVE +// Convert instrument flags which were read from 'dF..' extension to proper internal representation. +static void ConvertInstrumentFlags(ModInstrument &ins, uint32 flags) +{ + ins.VolEnv.dwFlags.set(ENV_ENABLED, (flags & 0x0001) != 0); + ins.VolEnv.dwFlags.set(ENV_SUSTAIN, (flags & 0x0002) != 0); + ins.VolEnv.dwFlags.set(ENV_LOOP, (flags & 0x0004) != 0); + ins.VolEnv.dwFlags.set(ENV_CARRY, (flags & 0x0800) != 0); + + ins.PanEnv.dwFlags.set(ENV_ENABLED, (flags & 0x0008) != 0); + ins.PanEnv.dwFlags.set(ENV_SUSTAIN, (flags & 0x0010) != 0); + ins.PanEnv.dwFlags.set(ENV_LOOP, (flags & 0x0020) != 0); + ins.PanEnv.dwFlags.set(ENV_CARRY, (flags & 0x1000) != 0); + + ins.PitchEnv.dwFlags.set(ENV_ENABLED, (flags & 0x0040) != 0); + ins.PitchEnv.dwFlags.set(ENV_SUSTAIN, (flags & 0x0080) != 0); + ins.PitchEnv.dwFlags.set(ENV_LOOP, (flags & 0x0100) != 0); + ins.PitchEnv.dwFlags.set(ENV_CARRY, (flags & 0x2000) != 0); + ins.PitchEnv.dwFlags.set(ENV_FILTER, (flags & 0x0400) != 0); + + ins.dwFlags.set(INS_SETPANNING, (flags & 0x0200) != 0); + ins.dwFlags.set(INS_MUTE, (flags & 0x4000) != 0); +} + + +// Convert VFLG / PFLG / AFLG +static void ConvertEnvelopeFlags(ModInstrument &instr, uint32 flags, EnvelopeType envType) +{ + InstrumentEnvelope &env = instr.GetEnvelope(envType); + env.dwFlags.set(ENV_ENABLED, (flags & 0x01) != 0); + env.dwFlags.set(ENV_LOOP, (flags & 0x02) != 0); + env.dwFlags.set(ENV_SUSTAIN, (flags & 0x04) != 0); + env.dwFlags.set(ENV_CARRY, (flags & 0x08) != 0); + env.dwFlags.set(ENV_FILTER, (envType == ENV_PITCH) && (flags & 0x10) != 0); +} + + // -------------------------------------------------------------------------------------------- // Convenient macro to help GET_HEADER declaration for single type members ONLY (non-array) // -------------------------------------------------------------------------------------------- @@ -569,7 +605,6 @@ bool ReadInstrumentHeaderField(ModInstrument *input, uint32 fcode, uint16 fsize, { // clang-format off GET_MPTHEADER_sized_member( nFadeOut , uint32 , MagicBE("FO..") ) - GET_MPTHEADER_sized_member( dwFlags , uint8 , MagicBE("dF..") ) GET_MPTHEADER_sized_member( nGlobalVol , uint32 , MagicBE("GV..") ) GET_MPTHEADER_sized_member( nPan , uint32 , MagicBE("P...") ) GET_MPTHEADER_sized_member( VolEnv.nLoopStart , uint8 , MagicBE("VLS.") ) @@ -616,11 +651,20 @@ bool ReadInstrumentHeaderField(ModInstrument *input, uint32 fcode, uint16 fsize, GET_MPTHEADER_sized_member( PitchEnv.nReleaseNode , uint8 , MagicBE("PERN") ) GET_MPTHEADER_sized_member( PanEnv.nReleaseNode , uint8 , MagicBE("AERN") ) GET_MPTHEADER_sized_member( VolEnv.nReleaseNode , uint8 , MagicBE("VERN") ) - GET_MPTHEADER_sized_member( PitchEnv.dwFlags , uint8 , MagicBE("PFLG") ) - GET_MPTHEADER_sized_member( PanEnv.dwFlags , uint8 , MagicBE("AFLG") ) - GET_MPTHEADER_sized_member( VolEnv.dwFlags , uint8 , MagicBE("VFLG") ) GET_MPTHEADER_sized_member( midiPWD , int8 , MagicBE("MPWD") ) // clang-format on + case MagicBE("dF.."): + ConvertInstrumentFlags(*input, file.ReadSizedIntLE(fsize)); + return true; + case MagicBE("VFLG"): + ConvertEnvelopeFlags(*input, file.ReadSizedIntLE(fsize), ENV_VOLUME); + return true; + case MagicBE("AFLG"): + ConvertEnvelopeFlags(*input, file.ReadSizedIntLE(fsize), ENV_PANNING); + return true; + case MagicBE("PFLG"): + ConvertEnvelopeFlags(*input, file.ReadSizedIntLE(fsize), ENV_PITCH); + return true; case MagicBE("R..."): { // Resampling has been written as various sizes including uint16 and uint32 in the past @@ -660,54 +704,6 @@ bool ReadInstrumentHeaderField(ModInstrument *input, uint32 fcode, uint16 fsize, return result; } - -// Convert instrument flags which were read from 'dF..' extension to proper internal representation. -static void ConvertReadExtendedFlags(ModInstrument *pIns) -{ - // Flags of 'dF..' datafield in extended instrument properties. - enum - { - dFdd_VOLUME = 0x0001, - dFdd_VOLSUSTAIN = 0x0002, - dFdd_VOLLOOP = 0x0004, - dFdd_PANNING = 0x0008, - dFdd_PANSUSTAIN = 0x0010, - dFdd_PANLOOP = 0x0020, - dFdd_PITCH = 0x0040, - dFdd_PITCHSUSTAIN = 0x0080, - dFdd_PITCHLOOP = 0x0100, - dFdd_SETPANNING = 0x0200, - dFdd_FILTER = 0x0400, - dFdd_VOLCARRY = 0x0800, - dFdd_PANCARRY = 0x1000, - dFdd_PITCHCARRY = 0x2000, - dFdd_MUTE = 0x4000, - }; - - const uint32 dwOldFlags = pIns->dwFlags.GetRaw(); - - pIns->VolEnv.dwFlags.set(ENV_ENABLED, (dwOldFlags & dFdd_VOLUME) != 0); - pIns->VolEnv.dwFlags.set(ENV_SUSTAIN, (dwOldFlags & dFdd_VOLSUSTAIN) != 0); - pIns->VolEnv.dwFlags.set(ENV_LOOP, (dwOldFlags & dFdd_VOLLOOP) != 0); - pIns->VolEnv.dwFlags.set(ENV_CARRY, (dwOldFlags & dFdd_VOLCARRY) != 0); - - pIns->PanEnv.dwFlags.set(ENV_ENABLED, (dwOldFlags & dFdd_PANNING) != 0); - pIns->PanEnv.dwFlags.set(ENV_SUSTAIN, (dwOldFlags & dFdd_PANSUSTAIN) != 0); - pIns->PanEnv.dwFlags.set(ENV_LOOP, (dwOldFlags & dFdd_PANLOOP) != 0); - pIns->PanEnv.dwFlags.set(ENV_CARRY, (dwOldFlags & dFdd_PANCARRY) != 0); - - pIns->PitchEnv.dwFlags.set(ENV_ENABLED, (dwOldFlags & dFdd_PITCH) != 0); - pIns->PitchEnv.dwFlags.set(ENV_SUSTAIN, (dwOldFlags & dFdd_PITCHSUSTAIN) != 0); - pIns->PitchEnv.dwFlags.set(ENV_LOOP, (dwOldFlags & dFdd_PITCHLOOP) != 0); - pIns->PitchEnv.dwFlags.set(ENV_CARRY, (dwOldFlags & dFdd_PITCHCARRY) != 0); - pIns->PitchEnv.dwFlags.set(ENV_FILTER, (dwOldFlags & dFdd_FILTER) != 0); - - pIns->dwFlags.reset(); - pIns->dwFlags.set(INS_SETPANNING, (dwOldFlags & dFdd_SETPANNING) != 0); - pIns->dwFlags.set(INS_MUTE, (dwOldFlags & dFdd_MUTE) != 0); -} - - void ReadInstrumentExtensionField(ModInstrument* pIns, const uint32 code, const uint16 size, FileReader &file) { if(code == MagicBE("K[..")) @@ -724,9 +720,6 @@ void ReadInstrumentExtensionField(ModInstrument* pIns, const uint32 code, const file.Skip(size); return; } - - if(code == MagicBE("dF..")) // 'dF..' field requires additional processing. - ConvertReadExtendedFlags(pIns); } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_itp.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_itp.cpp index fe131fe58..ddea9c299 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_itp.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_itp.cpp @@ -261,7 +261,7 @@ bool CSoundFile::ReadITP(FileReader &file, ModLoadingFlags loadFlags) #ifdef MODPLUG_TRACKER if(const auto fileName = file.GetOptionalFileName(); fileName.has_value()) { - instrPaths[ins] = mpt::AbsolutePathToRelative(instrPaths[ins], fileName->GetDirectoryWithDrive()); + instrPaths[ins] = mpt::RelativePathToAbsolute(instrPaths[ins], fileName->GetDirectoryWithDrive()); } else if(GetpModDoc() != nullptr) { instrPaths[ins] = mpt::RelativePathToAbsolute(instrPaths[ins], GetpModDoc()->GetPathNameMpt().GetDirectoryWithDrive()); @@ -309,15 +309,13 @@ bool CSoundFile::ReadITP(FileReader &file, ModLoadingFlags loadFlags) // Pattern data size_t numCommands = GetNumChannels() * numRows; - if(patternChunk.CanRead(sizeof(ITPModCommand) * numCommands)) { - ModCommand *target = Patterns[pat].GetpModCommand(0, 0); - while(numCommands-- != 0) + for(ModCommand &m : Patterns[pat]) { ITPModCommand data; patternChunk.ReadStruct(data); - *(target++) = data; + m = data; } } } @@ -330,7 +328,7 @@ bool CSoundFile::ReadITP(FileReader &file, ModLoadingFlags loadFlags) // Read number of embedded samples - at most as many as there are real samples in a valid file uint32 embeddedSamples = file.ReadUint32LE(); - if(embeddedSamples > m_nSamples) + if(embeddedSamples > GetNumSamples()) { return false; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mo3.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mo3.cpp index b990fc7af..6e5104872 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mo3.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mo3.cpp @@ -1016,7 +1016,7 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags) CMD_PORTAMENTOUP, CMD_TREMOR, CMD_RETRIG, CMD_FINEVIBRATO, CMD_CHANNELVOLUME, CMD_CHANNELVOLSLIDE, CMD_PANNINGSLIDE, CMD_S3MCMDEX, CMD_TEMPO, CMD_GLOBALVOLSLIDE, CMD_PANBRELLO, CMD_MIDI, - CMD_NONE,/*FineVolSld*/ CMD_NONE,/*PortaDown*/ CMD_NONE, /*PortaUp*/ CMD_NONE, + CMD_NONE,/*FineVolSld*/ CMD_NONE,/*PortaDown*/ CMD_NONE, /*PortaUp*/ CMD_DUMMY, CMD_NONE,/*ITVolCol*/ CMD_XPARAM, CMD_SMOOTHMIDI, CMD_DELAYCUT, CMD_FINETUNE, CMD_FINETUNE_SMOOTH, }; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp index a53aa79d4..e5c562f7b 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp @@ -1286,7 +1286,11 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) FileReader amData; if(file.GetOptionalFileName()) { +#if defined(MPT_LIBCXX_QUIRK_NO_OPTIONAL_VALUE) + mpt::PathString filename = *(file.GetOptionalFileName()); +#else mpt::PathString filename = file.GetOptionalFileName().value(); +#endif // Find instrument definition file const mpt::PathString exts[] = {P_(".nt"), P_(".NT"), P_(".as"), P_(".AS")}; for(const auto &ext : exts) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_xm.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_xm.cpp index f8fbea5c4..761dd8e12 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_xm.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_xm.cpp @@ -679,9 +679,10 @@ bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags) m_playBehaviour.reset(kFT2ST3OffsetOutOfRange); // Fix arpeggios in KAPTENFL.XM m_playBehaviour.reset(kFT2Arpeggio); - } else if(!memcmp(fileHeader.trackerName, "*Converted ", 11)) + } else if(!memcmp(fileHeader.trackerName, "*Converted ", 11) && !memcmp(fileHeader.trackerName + 14, "-File*", 6)) { - madeWith = verDigiTrakker; + madeWith = verDigiTrakker | verConfirmed; + madeWithTracker = UL_("Digitrakker"); } } @@ -1389,9 +1390,11 @@ bool CSoundFile::SaveXM(std::ostream &f, bool compatibilityExport) if(Instruments[ins] != nullptr) { // Convert instrument - insHeader.ConvertToXM(*Instruments[ins], compatibilityExport); + auto sampleList = insHeader.ConvertToXM(*Instruments[ins], compatibilityExport); + samples = std::move(sampleList.samples); + if(sampleList.tooManySamples) + AddToLog(LogInformation, MPT_UFORMAT("Instrument {} references too many samples, only the first {} will be exported.")(ins, samples.size())); - samples = insHeader.instrument.GetSampleList(*Instruments[ins], compatibilityExport); if(samples.size() > 0 && samples[0] <= GetNumSamples()) { // Copy over auto-vibrato settings of first sample diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ModSample.h b/Frameworks/OpenMPT/OpenMPT/soundlib/ModSample.h index c250038ba..d13563e43 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ModSample.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ModSample.h @@ -144,6 +144,10 @@ struct ModSample void SetLoop(SmpLength start, SmpLength end, bool enable, bool pingpong, CSoundFile &sndFile); // Set sustain loop points and update loop wrap-around buffer void SetSustainLoop(SmpLength start, SmpLength end, bool enable, bool pingpong, CSoundFile &sndFile); + // Retrieve the normal loop points + std::pair GetLoop() const noexcept { return std::make_pair(nLoopStart, nLoopEnd); } + // Retrieve the sustain loop points + std::pair GetSustainLoop() const noexcept { return std::make_pair(nSustainStart, nSustainEnd); } // Update loop wrap-around buffer void PrecomputeLoops(CSoundFile &sndFile, bool updateChannels = true); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp index 1a02584b1..aefb74939 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp @@ -1360,9 +1360,11 @@ bool CSoundFile::SaveXIInstrument(INSTRUMENTINDEX nInstr, std::ostream &f) const // Create file header XIInstrumentHeader header; - header.ConvertToXM(*pIns, false); + const auto sampleList = header.ConvertToXM(*pIns, false); + const auto &samples = sampleList.samples; + if(sampleList.tooManySamples) + AddToLog(LogInformation, MPT_UFORMAT("This instrument references too many samples, only the first {} will be exported.")(samples.size())); - const std::vector samples = header.instrument.GetSampleList(*pIns, false); if(samples.size() > 0 && samples[0] <= GetNumSamples()) { // Copy over auto-vibrato settings of first sample diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_defs.h b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_defs.h index 61c767f9e..73d90ddd1 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_defs.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_defs.h @@ -42,8 +42,12 @@ using SmpLength = uint32; inline constexpr SmpLength MAX_SAMPLE_LENGTH = 0x10000000; // Sample length in frames. Sample size in bytes can be more than this (= 256 MB). +inline constexpr ROWINDEX MAX_ROWS_PER_MEASURE = 65536; +inline constexpr ROWINDEX MAX_ROWS_PER_BEAT = 65536; +inline constexpr ROWINDEX DEFAULT_ROWS_PER_BEAT = 4; +inline constexpr ROWINDEX DEFAULT_ROWS_PER_MEASURE = 16; + inline constexpr ROWINDEX MAX_PATTERN_ROWS = 1024; -inline constexpr ROWINDEX MAX_ROWS_PER_BEAT = 65536; inline constexpr ORDERINDEX MAX_ORDERS = ORDERINDEX_MAX + 1; inline constexpr PATTERNINDEX MAX_PATTERNS = 4000; inline constexpr SAMPLEINDEX MAX_SAMPLES = 4000; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp index effedbc1a..4937c6ca8 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp @@ -1391,7 +1391,10 @@ void CSoundFile::InstrumentChange(ModChannel &chn, uint32 instr, bool bPorta, bo if(pIns->NoteMap[note - NOTE_MIN] > NOTE_MAX) return; uint32 n = pIns->Keyboard[note - NOTE_MIN]; - pSmp = (n <= GetNumSamples()) ? &Samples[n] : &Samples[0]; + if(n) + pSmp = (n <= GetNumSamples()) ? &Samples[n] : &Samples[0]; + else + pSmp = nullptr; } else if(GetNumInstruments()) { // No valid instrument, or not a valid note. @@ -2129,19 +2132,22 @@ CHANNELINDEX CSoundFile::GetNNAChannel(CHANNELINDEX nChn) const for(CHANNELINDEX i = m_nChannels; i < MAX_CHANNELS; i++) { const ModChannel &c = m_PlayState.Chn[i]; - // No sample and no plugin playing - if(!c.nLength && !c.HasMIDIOutput()) + // Sample playing? + if(c.nLength) + continue; + // Can a plugin potentially be playing? + if(!c.HasMIDIOutput()) return i; - // Plugin channel with already released note - if(!c.nLength && c.dwFlags[CHN_KEYOFF | CHN_NOTEFADE]) + // Has the plugin note already been released? (note: lastMidiNoteWithoutArp is set from within IMixPlugin, so this implies that there is a valid plugin assignment) + if(c.dwFlags[CHN_KEYOFF | CHN_NOTEFADE] || c.lastMidiNoteWithoutArp == NOTE_NONE) return i; // Stopped OPL channel if(c.dwFlags[CHN_ADLIB] && (!m_opl || !m_opl->IsActive(i))) return i; } - uint32 vol = 0x800000; - if(nChn < MAX_CHANNELS) + int32 vol = 0x800100; + if(nChn < m_PlayState.Chn.size()) { const ModChannel &srcChn = m_PlayState.Chn[nChn]; if(!srcChn.nFadeOutVol && srcChn.nLength) @@ -2160,7 +2166,8 @@ CHANNELINDEX CSoundFile::GetNNAChannel(CHANNELINDEX nChn) const // Use a combination of real volume [14 bit] (which includes volume envelopes, but also potentially global volume) and note volume [9 bit]. // Rationale: We need volume envelopes in case e.g. all NNA channels are playing at full volume but are looping on a 0-volume envelope node. // But if global volume is not applied to master and the global volume temporarily drops to 0, we would kill arbitrary channels. Hence, add the note volume as well. - uint32 v = (c.nRealVolume << 9) | c.nVolume; + int32 v = (c.nRealVolume << 9) | c.nVolume; + // Less priority to looped samples if(c.dwFlags[CHN_LOOP]) v /= 2; if((v < vol) || ((v == vol) && (c.VolEnv.nEnvPosition > envpos))) @@ -5165,6 +5172,12 @@ void CSoundFile::ParseMIDIMacro(PlayState &playState, CHANNELINDEX nChn, bool is } else if(macro[pos] == 's') { // SysEx Checksum (not an original Impulse Tracker macro variable, but added for convenience) + if(!firstNibble) // From MIDI.TXT: '9n' is exactly the same as '09 n' or '9 n' -- so finish current byte first + { + outPos++; + firstNibble = true; + } + auto startPos = outPos; while(startPos > 0 && out[--startPos] != 0xF0) ; @@ -6063,7 +6076,7 @@ void CSoundFile::PatternLoop(PlayState &state, CHANNELINDEX nChn, ModCommand::PA // IT compatibility 10. Pattern loops (+ same fix for XM / MOD / S3M files) if(!m_playBehaviour[kITFT2PatternLoop] && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_S3M))) { - auto p = std::cbegin(state.Chn); + auto p = state.Chn.data(); for(CHANNELINDEX i = 0; i < GetNumChannels(); i++, p++) { // Loop on other channel @@ -6289,6 +6302,8 @@ uint32 CSoundFile::GetFreqFromPeriod(uint32 period, uint32 c5speed, int32 nPerio octave = ((14 - div) & 0x1F); } else { + if(period > 29 * 768) + return 0; octave = (period / 768) + 2; } return (XMLinearTable[period % 768] << (FREQ_FRACBITS + 2)) >> octave; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.cpp index 9901819bf..0a294479f 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.cpp @@ -136,11 +136,11 @@ CSoundFile::CSoundFile() : #ifdef MODPLUG_TRACKER m_bChannelMuteTogglePending.reset(); - m_nDefaultRowsPerBeat = m_PlayState.m_nCurrentRowsPerBeat = (TrackerSettings::Instance().m_nRowHighlightBeats) ? TrackerSettings::Instance().m_nRowHighlightBeats : 4; + m_nDefaultRowsPerBeat = m_PlayState.m_nCurrentRowsPerBeat = (TrackerSettings::Instance().m_nRowHighlightBeats) ? TrackerSettings::Instance().m_nRowHighlightBeats : DEFAULT_ROWS_PER_BEAT; m_nDefaultRowsPerMeasure = m_PlayState.m_nCurrentRowsPerMeasure = (TrackerSettings::Instance().m_nRowHighlightMeasures >= m_nDefaultRowsPerBeat) ? TrackerSettings::Instance().m_nRowHighlightMeasures : m_nDefaultRowsPerBeat * 4; #else - m_nDefaultRowsPerBeat = m_PlayState.m_nCurrentRowsPerBeat = 4; - m_nDefaultRowsPerMeasure = m_PlayState.m_nCurrentRowsPerMeasure = 16; + m_nDefaultRowsPerBeat = m_PlayState.m_nCurrentRowsPerBeat = DEFAULT_ROWS_PER_BEAT; + m_nDefaultRowsPerMeasure = m_PlayState.m_nCurrentRowsPerMeasure = DEFAULT_ROWS_PER_MEASURE; #endif // MODPLUG_TRACKER MemsetZero(Instruments); @@ -212,6 +212,7 @@ void CSoundFile::InitializeGlobals(MODTYPE type) m_nResampling = SRCMODE_DEFAULT; m_dwLastSavedWithVersion = Version(0); m_dwCreatedWithVersion = Version(0); + m_nTempoMode = TempoMode::Classic; SetMixLevels(MixLevels::Compatible); @@ -880,11 +881,12 @@ double CSoundFile::GetCurrentBPM() const bpm = m_PlayState.m_nMusicTempo.ToDouble(); } else { - //with other modes, we calculate it: - double ticksPerBeat = m_PlayState.m_nMusicSpeed * m_PlayState.m_nCurrentRowsPerBeat; //ticks/beat = ticks/row * rows/beat - double samplesPerBeat = m_PlayState.m_nSamplesPerTick * ticksPerBeat; //samps/beat = samps/tick * ticks/beat - bpm = m_MixerSettings.gdwMixingFreq / samplesPerBeat * 60; //beats/sec = samps/sec / samps/beat - } //beats/min = beats/sec * 60 + // With other modes, we calculate it: + ROWINDEX rowsPerBeat = m_PlayState.m_nCurrentRowsPerBeat ? m_PlayState.m_nCurrentRowsPerBeat : DEFAULT_ROWS_PER_BEAT; + double ticksPerBeat = m_PlayState.m_nMusicSpeed * rowsPerBeat; // Ticks/beat = ticks/row * rows/beat + double samplesPerBeat = m_PlayState.m_nSamplesPerTick * ticksPerBeat; // Samps/beat = samps/tick * ticks/beat + bpm = m_MixerSettings.gdwMixingFreq / samplesPerBeat * 60; // Beats/sec = samps/sec / samps/beat + } // Beats/min = beats/sec * 60 return bpm; } @@ -1043,7 +1045,7 @@ void CSoundFile::ResetChannels() chn.nLength = 0; if(chn.dwFlags[CHN_ADLIB] && m_opl) { - CHANNELINDEX c = static_cast(std::distance(std::begin(m_PlayState.Chn), &chn)); + CHANNELINDEX c = static_cast(std::distance(m_PlayState.Chn.data(), &chn)); m_opl->NoteCut(c); } } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.h b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.h index 8c928d537..3cc25cefe 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.h @@ -509,7 +509,7 @@ class CSoundFile ResamplingMode m_nResampling; // Resampling mode (if overriding the globally set resampling) int32 m_nRepeatCount = 0; // -1 means repeat infinitely. ORDERINDEX m_nMaxOrderPosition; - ModChannelSettings ChnSettings[MAX_BASECHANNELS]; // Initial channels settings + std::array ChnSettings; // Initial channels settings CPatternContainer Patterns; ModSequenceSet Order; // Pattern sequences (order lists) protected: @@ -589,8 +589,8 @@ class CSoundFile bool m_bPositionChanged = true; // Report to plugins that we jumped around in the module public: - CHANNELINDEX ChnMix[MAX_CHANNELS]; // Index of channels in Chn to be actually mixed - ModChannel Chn[MAX_CHANNELS]; // Mixing channels... First m_nChannels channels are master channels (i.e. they are never NNA channels)! + std::array ChnMix; // Index of channels in Chn to be actually mixed + std::array Chn; // Mixing channels... First m_nChannels channels are master channels (i.e. they are never NNA channels)! struct MIDIMacroEvaluationResults { diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp index 147d0c795..28549f81c 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp @@ -670,7 +670,7 @@ bool CSoundFile::ProcessRow() // Reset channel values ModCommand *m = Patterns[m_PlayState.m_nPattern].GetpModCommand(m_PlayState.m_nRow, 0); - for (ModChannel *pChn = m_PlayState.Chn, *pEnd = pChn + m_nChannels; pChn != pEnd; pChn++, m++) + for (ModChannel *pChn = m_PlayState.Chn.data(), *pEnd = pChn + m_nChannels; pChn != pEnd; pChn++, m++) { // First, handle some quirks that happen after the last tick of the previous row... if(m_playBehaviour[KST3PortaAfterArpeggio] diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/XMTools.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/XMTools.cpp index 4f0bdcd3e..66395a83b 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/XMTools.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/XMTools.cpp @@ -54,7 +54,7 @@ void XMInstrument::ConvertEnvelopeToXM(const InstrumentEnvelope &mptEnv, uint8le // Convert OpenMPT's internal sample representation to an XMInstrument. -uint16 XMInstrument::ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport) +XMInstrument::SampleList XMInstrument::ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport) { MemsetZero(*this); @@ -74,53 +74,49 @@ uint16 XMInstrument::ConvertToXM(const ModInstrument &mptIns, bool compatibility pitchWheelRange = std::min(mptIns.midiPWD, int8(36)); // Create sample assignment table - auto sampleList = GetSampleList(mptIns, compatibilityExport); + const auto sampleList = GetSampleList(mptIns, compatibilityExport); for(std::size_t i = 0; i < std::size(sampleMap); i++) { if(mptIns.Keyboard[i + 12] > 0) { - auto sample = std::find(sampleList.begin(), sampleList.end(), mptIns.Keyboard[i + 12]); - if(sample != sampleList.end()) + auto sample = std::find(sampleList.samples.begin(), sampleList.samples.end(), mptIns.Keyboard[i + 12]); + if(sample != sampleList.samples.end()) { // Yep, we want to export this sample. - sampleMap[i] = static_cast(sample - sampleList.begin()); + sampleMap[i] = static_cast(std::distance(sampleList.samples.begin(), sample)); } } } - return static_cast(sampleList.size()); + return sampleList; } // Get a list of samples that should be written to the file. -std::vector XMInstrument::GetSampleList(const ModInstrument &mptIns, bool compatibilityExport) const +XMInstrument::SampleList XMInstrument::GetSampleList(const ModInstrument &mptIns, bool compatibilityExport) const { - std::vector sampleList; // List of samples associated with this instrument - std::vector addedToList; // Which samples did we already add to the sample list? + SampleList sampleList; // List of samples associated with this instrument + std::vector addedToList; // Which samples did we already add to the sample list? - uint8 numSamples = 0; for(std::size_t i = 0; i < std::size(sampleMap); i++) { const SAMPLEINDEX smp = mptIns.Keyboard[i + 12]; - if(smp > 0) - { - if(smp > addedToList.size()) - { - addedToList.resize(smp, false); - } - - if(!addedToList[smp - 1] && numSamples < (compatibilityExport ? 16 : 32)) - { - // We haven't considered this sample yet. - addedToList[smp - 1] = true; - numSamples++; - sampleList.push_back(smp); - } - } + if(smp == 0) + continue; + if(smp > addedToList.size()) + addedToList.resize(smp, false); + if(addedToList[smp - 1]) + continue; + // We haven't considered this sample yet. + addedToList[smp - 1] = true; + if(sampleList.samples.size() < (compatibilityExport ? 16u : 32u)) + sampleList.samples.push_back(smp); + else + sampleList.tooManySamples = true; } // FT2 completely ignores MIDI settings (and also the less important stuff) if not at least one (empty) sample is assigned to this instrument! - if(sampleList.empty() && compatibilityExport && midiEnabled) - sampleList.assign(1, 0); + if(sampleList.samples.empty() && compatibilityExport && midiEnabled) + sampleList.samples.assign(1, 0); return sampleList; } @@ -247,12 +243,14 @@ void XMInstrumentHeader::Finalise() // Convert OpenMPT's internal sample representation to an XMInstrumentHeader. -void XMInstrumentHeader::ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport) +XMInstrument::SampleList XMInstrumentHeader::ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport) { - numSamples = instrument.ConvertToXM(mptIns, compatibilityExport); + const auto sampleList = instrument.ConvertToXM(mptIns, compatibilityExport); + numSamples = static_cast(sampleList.samples.size()); mpt::String::WriteBuf(mpt::String::spacePadded, name) = mptIns.name; type = mptIns.nMidiProgram; // If FT2 writes crap here, we can do so, too! (we probably shouldn't, though. This is just for backwards compatibility with old MPT versions.) + return sampleList; } @@ -284,9 +282,10 @@ void XMInstrumentHeader::ConvertToMPT(ModInstrument &mptIns) const // Convert OpenMPT's internal sample representation to an XIInstrumentHeader. -void XIInstrumentHeader::ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport) +XMInstrument::SampleList XIInstrumentHeader::ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport) { - numSamples = instrument.ConvertToXM(mptIns, compatibilityExport); + const auto sampleList = instrument.ConvertToXM(mptIns, compatibilityExport); + numSamples = static_cast(sampleList.samples.size()); memcpy(signature, "Extended Instrument: ", 21); mpt::String::WriteBuf(mpt::String::spacePadded, name) = mptIns.name; @@ -296,6 +295,7 @@ void XIInstrumentHeader::ConvertToXM(const ModInstrument &mptIns, bool compatibi mpt::String::WriteBuf(mpt::String::spacePadded, trackerName) = openMptTrackerName; version = 0x102; + return sampleList; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/XMTools.h b/Frameworks/OpenMPT/OpenMPT/soundlib/XMTools.h index d8a23d785..50c42add2 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/XMTools.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/XMTools.h @@ -28,7 +28,7 @@ struct XMFileHeader }; char signature[17]; // "Extended Module: " - char songName[20]; // Song Name, not null-terminated (any nulls are treated as spaces) + char songName[20]; // Song Name, space-padded uint8le eof; // DOS EOF Character (0x1A) char trackerName[20]; // Software that was used to create the XM file uint16le version; // File version (1.02 - 1.04 are supported) @@ -92,8 +92,14 @@ struct XMInstrument // Convert XM envelope data to an OpenMPT's internal envelope representation. void ConvertEnvelopeToMPT(InstrumentEnvelope &mptEnv, uint8 numPoints, uint8 flags, uint8 sustain, uint8 loopStart, uint8 loopEnd, EnvType env) const; + struct SampleList + { + std::vector samples; // The list of samples to write to the file + bool tooManySamples = false; // Does the source instrument contain more samples than what we can write? + }; + // Convert OpenMPT's internal sample representation to an XMInstrument. - uint16 ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport); + SampleList ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport); // Convert an XMInstrument to OpenMPT's internal instrument representation. void ConvertToMPT(ModInstrument &mptIns) const; // Apply auto-vibrato settings from sample to file. @@ -102,7 +108,7 @@ struct XMInstrument void ApplyAutoVibratoToMPT(ModSample &mptSmp) const; // Get a list of samples that should be written to the file. - std::vector GetSampleList(const ModInstrument &mptIns, bool compatibilityExport) const; + SampleList GetSampleList(const ModInstrument &mptIns, bool compatibilityExport) const; }; MPT_BINARY_STRUCT(XMInstrument, 230) @@ -112,8 +118,8 @@ MPT_BINARY_STRUCT(XMInstrument, 230) struct XMInstrumentHeader { uint32le size; // Size of XMInstrumentHeader + XMInstrument - char name[22]; // Instrument Name, not null-terminated (any nulls are treated as spaces) - uint8le type; // Instrument Type (Apparently FT2 writes some crap here, but it's the same crap for all instruments of the same module!) + char name[22]; // Instrument Name, space-padded + uint8le type; // Instrument Type (FT2 does not initialize this field properly, so it contains a random value, but it's the same random value for all instruments of the same module!) uint16le numSamples; // Number of Samples associated with instrument uint32le sampleHeaderSize; // Size of XMSample XMInstrument instrument; @@ -122,7 +128,7 @@ struct XMInstrumentHeader void Finalise(); // Convert OpenMPT's internal sample representation to an XMInstrument. - void ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport); + XMInstrument::SampleList ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport); // Convert an XMInstrument to OpenMPT's internal instrument representation. void ConvertToMPT(ModInstrument &mptIns) const; }; @@ -139,7 +145,7 @@ struct XIInstrumentHeader }; char signature[21]; // "Extended Instrument: " - char name[22]; // Instrument Name, not null-terminated (any nulls are treated as spaces) + char name[22]; // Instrument Name, space-padded uint8le eof; // DOS EOF Character (0x1A) char trackerName[20]; // Software that was used to create the XI file uint16le version; // File Version (1.02) @@ -147,7 +153,7 @@ struct XIInstrumentHeader uint16le numSamples; // Number of embedded sample headers + samples // Convert OpenMPT's internal sample representation to an XIInstrumentHeader. - void ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport); + XMInstrument::SampleList ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport); // Convert an XIInstrumentHeader to OpenMPT's internal instrument representation. void ConvertToMPT(ModInstrument &mptIns) const; }; @@ -176,7 +182,7 @@ struct XMSample uint8le pan; // Sample Panning int8le relnote; // Sample Transpose uint8le reserved; // Reserved (abused for ModPlug's ADPCM compression) - char name[22]; // Sample Name, not null-terminated (any nulls are treated as spaces) + char name[22]; // Sample Name, space-padded // Convert OpenMPT's internal sample representation to an XMSample. void ConvertToXM(const ModSample &mptSmp, MODTYPE fromType, bool compatibilityExport); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/modsmp_ctrl.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/modsmp_ctrl.cpp index 562d7fb69..31eea76ed 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/modsmp_ctrl.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/modsmp_ctrl.cpp @@ -177,8 +177,7 @@ static void XFadeSampleImpl(const T *srcIn, const T *srcOut, T *output, const Sm bool XFadeSample(ModSample &smp, SmpLength fadeLength, int fadeLaw, bool afterloopFade, bool useSustainLoop, CSoundFile &sndFile) { if(!smp.HasSampleData()) return false; - const SmpLength loopStart = useSustainLoop ? smp.nSustainStart : smp.nLoopStart; - const SmpLength loopEnd = useSustainLoop ? smp.nSustainEnd : smp.nLoopEnd; + const auto [loopStart, loopEnd] = useSustainLoop ? smp.GetSustainLoop() : smp.GetLoop(); if(loopEnd <= loopStart || loopEnd > smp.nLength) return false; if(loopStart < fadeLength) return false; diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/LICENSE.BSD-3-Clause.txt b/Frameworks/OpenMPT/OpenMPT/src/mpt/LICENSE.BSD-3-Clause.txt index f1628b1f8..07141c05b 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/LICENSE.BSD-3-Clause.txt +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/LICENSE.BSD-3-Clause.txt @@ -1,4 +1,4 @@ -Copyright (c) 2004-2024, OpenMPT Project Developers and Contributors +Copyright (c) 2004-2025, OpenMPT Project Developers and Contributors Copyright (c) 1997-2003, Olivier Lapicque All rights reserved. diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/arithmetic_shift.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/arithmetic_shift.hpp index 70308a259..48c79690b 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/arithmetic_shift.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/arithmetic_shift.hpp @@ -8,8 +8,6 @@ #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" -#include "mpt/base/saturate_cast.hpp" - namespace mpt { inline namespace MPT_INLINE_NS { diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_os.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_os.hpp index 789a3faef..630c518ba 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_os.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_os.hpp @@ -93,6 +93,10 @@ #endif +#elif defined(__CYGWIN__) +#define MPT_OS_CYGWIN 1 + + #elif defined(_WIN32) #define MPT_OS_WINDOWS 1 #if !defined(_WIN32_WINDOWS) && !defined(WINVER) @@ -379,6 +383,9 @@ static_assert(NTDDI_WIN11_GE == MPT_WIN_11_23H2); #ifndef MPT_OS_EMSCRIPTEN #define MPT_OS_EMSCRIPTEN 0 #endif +#ifndef MPT_OS_CYGWIN +#define MPT_OS_CYGWIN 0 +#endif #ifndef MPT_OS_WINDOWS #define MPT_OS_WINDOWS 0 #endif diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_quirks.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_quirks.hpp index 29e0ca4a2..7734642ff 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_quirks.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_quirks.hpp @@ -241,6 +241,16 @@ +#if MPT_OS_CYGWIN +#define MPT_LIBCXX_QUIRK_BROKEN_USER_LOCALE +#endif + + + +// #define MPT_LIBCXX_QUIRK_BROKEN_ACTIVE_LOCALE + + + #if MPT_CXX_AT_LEAST(20) // Clang 14 is incompatible with libstdc++ 13 in C++20 mode #if MPT_CLANG_BEFORE(15, 0, 0) && MPT_LIBCXX_GNU_AT_LEAST(13) @@ -291,12 +301,16 @@ #elif MPT_OS_MACOSX_OR_IOS #if defined(TARGET_OS_OSX) #if TARGET_OS_OSX +#if !defined(MAC_OS_X_VERSION_10_15) +#define MPT_LIBCXX_QUIRK_NO_TO_CHARS_INT +#else #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_15) #define MPT_LIBCXX_QUIRK_NO_TO_CHARS_INT #endif #endif #endif #endif +#endif @@ -318,4 +332,20 @@ +#if MPT_OS_MACOSX_OR_IOS +#if defined(TARGET_OS_OSX) +#if TARGET_OS_OSX +#if !defined(MAC_OS_X_VERSION_10_14) +#define MPT_LIBCXX_QUIRK_NO_OPTIONAL_VALUE +#else +#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_14) +#define MPT_LIBCXX_QUIRK_NO_OPTIONAL_VALUE +#endif +#endif +#endif +#endif +#endif + + + #endif // MPT_BASE_DETECT_QUIRKS_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/saturate_round.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/saturate_round.hpp index 7680608bd..167a4607e 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/saturate_round.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/saturate_round.hpp @@ -10,7 +10,7 @@ #include "mpt/base/math.hpp" #include "mpt/base/saturate_cast.hpp" -#include +#include diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/source_location.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/source_location.hpp index 90be04bc7..2a1333f58 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/source_location.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/source_location.hpp @@ -41,7 +41,11 @@ using std::source_location; #define MPT_SOURCE_LOCATION_LINE __builtin_LINE() #define MPT_SOURCE_LOCATION_COLUMN 0 -#elif MPT_COMPILER_CLANG && MPT_CLANG_AT_LEAST(9, 0, 0) +#elif MPT_COMPILER_CLANG && ((!MPT_OS_MACOSX_OR_IOS && MPT_CLANG_AT_LEAST(9, 0, 0)) || (MPT_OS_MACOSX_OR_IOS && MPT_CLANG_AT_LEAST(12, 0, 0))) + +// We do not know which Apple Clang version introduced __builtin_FILE(). +// It fails with 10.x (see ), +// and IRC dicussion decided on 12.x as a somewhat safe choice. #define MPT_SOURCE_LOCATION_FILE __builtin_FILE() #define MPT_SOURCE_LOCATION_FUNCTION __builtin_FUNCTION() diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/check/libc.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/check/libc.hpp index 8e3789991..78090b828 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/check/libc.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/check/libc.hpp @@ -4,6 +4,7 @@ #define MPT_CHECK_LIBC_HPP #include "mpt/base/detect_libc.hpp" +#include "mpt/base/detect_os.hpp" #include "mpt/base/detect_quirks.hpp" #include "mpt/base/compiletime_warning.hpp" @@ -30,4 +31,14 @@ MPT_WARNING("C stdlib is not multi-threaded.") #endif #endif +#ifndef MPT_CHECK_LIBC_IGNORE_WARNING_UNICODE_MISMATCH +#if MPT_OS_WINDOWS +#ifdef UNICODE +#ifndef _UNICODE +MPT_WARNING("UNICODE is defined but _UNICODE is not defined. Please #define _UNICODE.") +#endif +#endif +#endif // MPT_OS_WINDOWS +#endif + #endif // MPT_CHECK_LIBC_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/check/windows.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/check/windows.hpp index fea40114b..b97619ccf 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/check/windows.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/check/windows.hpp @@ -20,6 +20,14 @@ MPT_WARNING("Targeting Win9x but windows.h uses UNICODE TCHAR. Please do not #de #endif #endif +#ifndef MPT_CHECK_WINDOWS_IGNORE_WARNING_UNICODE_MISMATCH +#ifdef _UNICODE +#ifndef UNICODE +MPT_WARNING("_UNICODE is defined but UNICODE is not defined. Please enable UNICODE support in your compiler, or do not #define _UNICODE.") +#endif +#endif +#endif + #ifndef NOMINMAX #ifndef MPT_CHECK_WINDOWS_IGNORE_WARNING_NO_NOMINMAX MPT_WARNING("windows.h defines min and max which conflicts with C++. Please #define NOMINMAX.") diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file_adapter/fileadapter.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file_adapter/fileadapter.hpp index 4ec1c4a93..7ecfac16a 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file_adapter/fileadapter.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file_adapter/fileadapter.hpp @@ -135,7 +135,11 @@ class FileAdapter { m_Filename = tempName; m_IsTempFile = true; } else { +#if defined(MPT_LIBCXX_QUIRK_NO_OPTIONAL_VALUE) + m_Filename = *(file.GetOptionalFileName()); +#else m_Filename = file.GetOptionalFileName().value(); +#endif } } catch (const std::runtime_error &) { m_Filename = mpt::os_path{}; diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/string_transcode/transcode.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/string_transcode/transcode.hpp index 3e0d1891f..67d9c0c2d 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/string_transcode/transcode.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/string_transcode/transcode.hpp @@ -11,6 +11,7 @@ #include "mpt/base/namespace.hpp" #include "mpt/base/saturate_cast.hpp" #include "mpt/detect/mfc.hpp" +#include "mpt/out_of_memory/out_of_memory.hpp" #include "mpt/string/types.hpp" #include "mpt/string/utility.hpp" @@ -1664,10 +1665,60 @@ inline Tdststring encode(logical_encoding encoding, const mpt::widestring & src) #elif !defined(MPT_COMPILER_QUIRK_NO_WCHAR) switch (encoding) { case logical_encoding::locale: +#if defined(MPT_LIBCXX_QUIRK_BROKEN_USER_LOCALE) + try { + return encode_locale(std::locale(""), src); + } catch (mpt::out_of_memory e) { + mpt::rethrow_out_of_memory(e); + } catch (...) { + // nothing + } + try { + return encode_locale(std::locale(), src); + } catch (mpt::out_of_memory e) { + mpt::rethrow_out_of_memory(e); + } catch (...) { + // nothing + } + try { + return encode_locale(std::locale::classic(), src); + } catch (mpt::out_of_memory e) { + mpt::rethrow_out_of_memory(e); + } catch (...) { + // nothing + } + return encode_ascii(src); +#else return encode_locale(std::locale(""), src); +#endif break; case logical_encoding::active_locale: +#if defined(MPT_LIBCXX_QUIRK_BROKEN_ACTIVE_LOCALE) + try { + return encode_locale(std::locale(), src); + } catch (mpt::out_of_memory e) { + mpt::rethrow_out_of_memory(e); + } catch (...) { + // nothing + } + try { + return encode_locale(std::locale(""), src); + } catch (mpt::out_of_memory e) { + mpt::rethrow_out_of_memory(e); + } catch (...) { + // nothing + } + try { + return encode_locale(std::locale::classic(), src); + } catch (mpt::out_of_memory e) { + mpt::rethrow_out_of_memory(e); + } catch (...) { + // nothing + } + return encode_ascii(src); +#else return encode_locale(std::locale(), src); +#endif break; } throw std::domain_error("unsupported encoding"); @@ -1835,10 +1886,60 @@ inline mpt::widestring decode(logical_encoding encoding, const Tsrcstring & src) #elif !defined(MPT_COMPILER_QUIRK_NO_WCHAR) switch (encoding) { case logical_encoding::locale: +#if defined(MPT_LIBCXX_QUIRK_BROKEN_USER_LOCALE) + try { + return decode_locale(std::locale(""), src); + } catch (mpt::out_of_memory e) { + mpt::rethrow_out_of_memory(e); + } catch (...) { + // nothing + } + try { + return decode_locale(std::locale(), src); + } catch (mpt::out_of_memory e) { + mpt::rethrow_out_of_memory(e); + } catch (...) { + // nothing + } + try { + return decode_locale(std::locale::classic(), src); + } catch (mpt::out_of_memory e) { + mpt::rethrow_out_of_memory(e); + } catch (...) { + // nothing + } + return decode_ascii(src); +#else return decode_locale(std::locale(""), src); +#endif break; case logical_encoding::active_locale: +#if defined(MPT_LIBCXX_QUIRK_BROKEN_USER_LOCALE) + try { + return decode_locale(std::locale(), src); + } catch (mpt::out_of_memory e) { + mpt::rethrow_out_of_memory(e); + } catch (...) { + // nothing + } + try { + return decode_locale(std::locale(""), src); + } catch (mpt::out_of_memory e) { + mpt::rethrow_out_of_memory(e); + } catch (...) { + // nothing + } + try { + return decode_locale(std::locale::classic(), src); + } catch (mpt::out_of_memory e) { + mpt::rethrow_out_of_memory(e); + } catch (...) { + // nothing + } + return decode_ascii(src); +#else return decode_locale(std::locale(), src); +#endif break; } throw std::domain_error("unsupported encoding");