Updated libOpenMPT to version 0.7.13
Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
parent
4b19c15354
commit
9ed4e4e8d9
50 changed files with 524 additions and 185 deletions
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" "."
|
||||
|
|
84
Frameworks/OpenMPT/OpenMPT/build/make/config-cygwin.mk
Normal file
84
Frameworks/OpenMPT/OpenMPT/build/make/config-cygwin.mk
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
};
|
||||
|
|
|
@ -429,7 +429,11 @@ inline mpt::ustring ToUnicode(uint16 codepage, Tencoding &&fallback, Tsrc &&str)
|
|||
std::optional<mpt::common_encoding> charset = mpt::optional_encoding_from_codepage(codepage);
|
||||
if(charset.has_value())
|
||||
{
|
||||
#if defined(MPT_LIBCXX_QUIRK_NO_OPTIONAL_VALUE)
|
||||
result = mpt::transcode<mpt::ustring>(*charset, std::forward<Tsrc>(str));
|
||||
#else
|
||||
result = mpt::transcode<mpt::ustring>(charset.value(), std::forward<Tsrc>(str));
|
||||
#endif
|
||||
} else if(mpt::has_codepage(static_cast<UINT>(codepage)))
|
||||
{
|
||||
result = mpt::transcode<mpt::ustring>(static_cast<UINT>(codepage), std::forward<Tsrc>(str));
|
||||
|
@ -440,7 +444,11 @@ inline mpt::ustring ToUnicode(uint16 codepage, Tencoding &&fallback, Tsrc &&str)
|
|||
return result;
|
||||
#else // !MPT_OS_WINDOWS
|
||||
std::optional<mpt::common_encoding> charset = mpt::optional_encoding_from_codepage(codepage);
|
||||
#if defined(MPT_LIBCXX_QUIRK_NO_OPTIONAL_VALUE)
|
||||
return charset.has_value() ? mpt::transcode<mpt::ustring>(charset.value(), std::forward<Tsrc>(str)) : mpt::transcode<mpt::ustring>(std::forward<Tencoding>(fallback), std::forward<Tsrc>(str));
|
||||
#else
|
||||
return charset.has_value() ? mpt::transcode<mpt::ustring>(*charset, std::forward<Tsrc>(str)) : mpt::transcode<mpt::ustring>(std::forward<Tencoding>(fallback), std::forward<Tsrc>(str));
|
||||
#endif
|
||||
#endif // MPT_OS_WINDOWS
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 | <p style="background-color:green" >fast </p> | <p style="background-color:yellow">medium</p> |
|
||||
* | seekable stream | <p style="background-color:red" >slow </p> | <p style="background-color:green" >low </p> |
|
||||
* | constructor | speed | memory consumption |
|
||||
* | ----------------: | :---: | :----------------: |
|
||||
* | seekable stream | <p style="background-color:yellow">medium</p> | <p style="background-color:green" >low </p> |
|
||||
* | unseekable stream | <p style="background-color:yellow">medium</p> | <p style="background-color:red" >high </p> |
|
||||
* | memory buffer | <p style="background-color:green" >fast </p> | <p style="background-color:yellow">medium</p> |
|
||||
*
|
||||
* 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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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<mpt::ustring> & log, verbosity banner ) {
|
|||
return;
|
||||
}
|
||||
log << MPT_USTRING("openmpt123") << MPT_USTRING(" v") << mpt::transcode<mpt::ustring>( mpt::source_encoding, OPENMPT123_VERSION_STRING ) << MPT_USTRING(", libopenmpt ") << mpt::transcode<mpt::ustring>( libopenmpt_encoding, openmpt::string::get( "library_version" ) ) << MPT_USTRING(" (") << MPT_USTRING("OpenMPT ") << mpt::transcode<mpt::ustring>( libopenmpt_encoding, openmpt::string::get( "core_version" ) ) << MPT_USTRING(")") << lf;
|
||||
log << MPT_USTRING("Copyright (c) 2013-2024 OpenMPT Project Developers and Contributors <https://lib.openmpt.org/>") << lf;
|
||||
log << MPT_USTRING("Copyright (c) 2013-2025 OpenMPT Project Developers and Contributors <https://lib.openmpt.org/>") << lf;
|
||||
if ( banner == verbosity_normal ) {
|
||||
log << lf;
|
||||
return;
|
||||
|
@ -462,7 +462,7 @@ static void show_banner( concat_stream<mpt::ustring> & log, verbosity banner ) {
|
|||
static void show_man_version( textout & log ) {
|
||||
log << MPT_USTRING("openmpt123") << MPT_USTRING(" v") << mpt::transcode<mpt::ustring>( mpt::source_encoding, OPENMPT123_VERSION_STRING ) << lf;
|
||||
log << lf;
|
||||
log << MPT_USTRING("Copyright (c) 2013-2024 OpenMPT Project Developers and Contributors <https://lib.openmpt.org/>") << lf;
|
||||
log << MPT_USTRING("Copyright (c) 2013-2025 OpenMPT Project Developers and Contributors <https://lib.openmpt.org/>") << lf;
|
||||
}
|
||||
|
||||
static void show_short_version( textout & log ) {
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<uint32>(fsize));
|
||||
return true;
|
||||
case MagicBE("VFLG"):
|
||||
ConvertEnvelopeFlags(*input, file.ReadSizedIntLE<uint32>(fsize), ENV_VOLUME);
|
||||
return true;
|
||||
case MagicBE("AFLG"):
|
||||
ConvertEnvelopeFlags(*input, file.ReadSizedIntLE<uint32>(fsize), ENV_PANNING);
|
||||
return true;
|
||||
case MagicBE("PFLG"):
|
||||
ConvertEnvelopeFlags(*input, file.ReadSizedIntLE<uint32>(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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<SmpLength, SmpLength> GetLoop() const noexcept { return std::make_pair(nLoopStart, nLoopEnd); }
|
||||
// Retrieve the sustain loop points
|
||||
std::pair<SmpLength, SmpLength> GetSustainLoop() const noexcept { return std::make_pair(nSustainStart, nSustainEnd); }
|
||||
// Update loop wrap-around buffer
|
||||
void PrecomputeLoops(CSoundFile &sndFile, bool updateChannels = true);
|
||||
|
||||
|
|
|
@ -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<SAMPLEINDEX> samples = header.instrument.GetSampleList(*pIns, false);
|
||||
if(samples.size() > 0 && samples[0] <= GetNumSamples())
|
||||
{
|
||||
// Copy over auto-vibrato settings of first sample
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<CHANNELINDEX>(std::distance(std::begin(m_PlayState.Chn), &chn));
|
||||
CHANNELINDEX c = static_cast<CHANNELINDEX>(std::distance(m_PlayState.Chn.data(), &chn));
|
||||
m_opl->NoteCut(c);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -509,7 +509,7 @@ public:
|
|||
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<ModChannelSettings, MAX_BASECHANNELS> ChnSettings; // Initial channels settings
|
||||
CPatternContainer Patterns;
|
||||
ModSequenceSet Order; // Pattern sequences (order lists)
|
||||
protected:
|
||||
|
@ -589,8 +589,8 @@ public:
|
|||
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<CHANNELINDEX, MAX_CHANNELS> ChnMix; // Index of channels in Chn to be actually mixed
|
||||
std::array<ModChannel, MAX_CHANNELS> Chn; // Mixing channels... First m_nChannels channels are master channels (i.e. they are never NNA channels)!
|
||||
|
||||
struct MIDIMacroEvaluationResults
|
||||
{
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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<uint8>(sample - sampleList.begin());
|
||||
sampleMap[i] = static_cast<uint8>(std::distance(sampleList.samples.begin(), sample));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<uint16>(sampleList.size());
|
||||
return sampleList;
|
||||
}
|
||||
|
||||
|
||||
// Get a list of samples that should be written to the file.
|
||||
std::vector<SAMPLEINDEX> XMInstrument::GetSampleList(const ModInstrument &mptIns, bool compatibilityExport) const
|
||||
XMInstrument::SampleList XMInstrument::GetSampleList(const ModInstrument &mptIns, bool compatibilityExport) const
|
||||
{
|
||||
std::vector<SAMPLEINDEX> sampleList; // List of samples associated with this instrument
|
||||
std::vector<bool> addedToList; // Which samples did we already add to the sample list?
|
||||
SampleList sampleList; // List of samples associated with this instrument
|
||||
std::vector<bool> 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<uint16>(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<uint16>(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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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<SAMPLEINDEX> 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<SAMPLEINDEX> 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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "mpt/base/math.hpp"
|
||||
#include "mpt/base/saturate_cast.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
#include <limits>
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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 <https://github.com/fink/fink-distributions/issues/1202>),
|
||||
// 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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.")
|
||||
|
|
|
@ -135,7 +135,11 @@ public:
|
|||
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{};
|
||||
|
|
|
@ -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<Tdststring>(std::locale(""), src);
|
||||
} catch (mpt::out_of_memory e) {
|
||||
mpt::rethrow_out_of_memory(e);
|
||||
} catch (...) {
|
||||
// nothing
|
||||
}
|
||||
try {
|
||||
return encode_locale<Tdststring>(std::locale(), src);
|
||||
} catch (mpt::out_of_memory e) {
|
||||
mpt::rethrow_out_of_memory(e);
|
||||
} catch (...) {
|
||||
// nothing
|
||||
}
|
||||
try {
|
||||
return encode_locale<Tdststring>(std::locale::classic(), src);
|
||||
} catch (mpt::out_of_memory e) {
|
||||
mpt::rethrow_out_of_memory(e);
|
||||
} catch (...) {
|
||||
// nothing
|
||||
}
|
||||
return encode_ascii<Tdststring>(src);
|
||||
#else
|
||||
return encode_locale<Tdststring>(std::locale(""), src);
|
||||
#endif
|
||||
break;
|
||||
case logical_encoding::active_locale:
|
||||
#if defined(MPT_LIBCXX_QUIRK_BROKEN_ACTIVE_LOCALE)
|
||||
try {
|
||||
return encode_locale<Tdststring>(std::locale(), src);
|
||||
} catch (mpt::out_of_memory e) {
|
||||
mpt::rethrow_out_of_memory(e);
|
||||
} catch (...) {
|
||||
// nothing
|
||||
}
|
||||
try {
|
||||
return encode_locale<Tdststring>(std::locale(""), src);
|
||||
} catch (mpt::out_of_memory e) {
|
||||
mpt::rethrow_out_of_memory(e);
|
||||
} catch (...) {
|
||||
// nothing
|
||||
}
|
||||
try {
|
||||
return encode_locale<Tdststring>(std::locale::classic(), src);
|
||||
} catch (mpt::out_of_memory e) {
|
||||
mpt::rethrow_out_of_memory(e);
|
||||
} catch (...) {
|
||||
// nothing
|
||||
}
|
||||
return encode_ascii<Tdststring>(src);
|
||||
#else
|
||||
return encode_locale<Tdststring>(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");
|
||||
|
|
Loading…
Reference in a new issue