Updated libOpenMPT to version 0.7.13

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
Christopher Snowhill 2025-01-10 14:38:44 -08:00
parent 4b19c15354
commit 9ed4e4e8d9
50 changed files with 524 additions and 185 deletions

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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" "."

View 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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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,
);
};

View file

@ -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,
);
};

View file

@ -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
}

View file

@ -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"

View file

@ -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

View file

@ -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.

View file

@ -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.

View file

@ -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 );

View file

@ -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;

View file

@ -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

View file

@ -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 */

View file

@ -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

View file

@ -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

View file

@ -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";

View file

@ -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 ) {

View file

@ -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))

View file

@ -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)

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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,
};

View file

@ -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)

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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
{

View file

@ -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]

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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.

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -10,7 +10,7 @@
#include "mpt/base/math.hpp"
#include "mpt/base/saturate_cast.hpp"
#include <type_traits>
#include <limits>

View file

@ -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()

View file

@ -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

View file

@ -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.")

View file

@ -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{};

View file

@ -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");