libOpenMPT: Updated to version 0.8.2

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
Christopher Snowhill 2025-08-04 17:31:38 -07:00
parent b9ced57d5f
commit ecfbee6f53
35 changed files with 348 additions and 99 deletions

View file

@ -360,6 +360,9 @@ endif
ifeq ($(UNAME_S),OpenBSD) ifeq ($(UNAME_S),OpenBSD)
HOST_FLAVOUR=OPENBSD HOST_FLAVOUR=OPENBSD
endif endif
ifeq ($(UNAME_S),DragonFly)
HOST_FLAVOUR=DRAGONFLY
endif
ifeq ($(UNAME_S),Haiku) ifeq ($(UNAME_S),Haiku)
HOST_FLAVOUR=HAIKU HOST_FLAVOUR=HAIKU
endif endif
@ -408,6 +411,8 @@ TAR_C=tar -c -N
else else
TAR_C=tar -c -F pax -N TAR_C=tar -c -F pax -N
endif endif
else ifeq ($(findstring DragonFly,$(UNAME_S)),DragonFly)
TAR_C=tar -c --format pax --numeric-owner --uname "" --gname "" --uid 0 --gid 0
else ifeq ($(findstring BSD,$(UNAME_S)),BSD) else ifeq ($(findstring BSD,$(UNAME_S)),BSD)
TAR_C=tar -c --format pax --numeric-owner --uname "" --gname "" --uid 0 --gid 0 TAR_C=tar -c --format pax --numeric-owner --uname "" --gname "" --uid 0 --gid 0
else else

View file

@ -1,4 +1,4 @@
MPT_SVNVERSION=23497 MPT_SVNVERSION=23826
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.8.1 MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.8.2
MPT_SVNDATE=2025-06-14T13:04:39.042416Z MPT_SVNDATE=2025-07-19T10:45:24.126020Z

View file

@ -53,6 +53,13 @@ LDLIBS_PLATFORM=-lc++ -lc
include build/make/config-clang.mk include build/make/config-clang.mk
MPT_COMPILER_NOALLOCAH=1 MPT_COMPILER_NOALLOCAH=1
else ifeq ($(HOST_FLAVOUR),DRAGONFLY)
NO_PORTAUDIOCPP?=1
NO_PULSEAUDIO?=1
include build/make/config-gcc.mk
MPT_COMPILER_NOALLOCAH=1
else ifeq ($(HOST_FLAVOUR),HAIKU) else ifeq ($(HOST_FLAVOUR),HAIKU)
NO_PULSEAUDIO?=1 NO_PULSEAUDIO?=1

View file

@ -1,10 +1,10 @@
#pragma once #pragma once
#define OPENMPT_VERSION_SVNVERSION "23497" #define OPENMPT_VERSION_SVNVERSION "23826"
#define OPENMPT_VERSION_REVISION 23497 #define OPENMPT_VERSION_REVISION 23826
#define OPENMPT_VERSION_DIRTY 0 #define OPENMPT_VERSION_DIRTY 0
#define OPENMPT_VERSION_MIXEDREVISIONS 0 #define OPENMPT_VERSION_MIXEDREVISIONS 0
#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.8.1" #define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.8.2"
#define OPENMPT_VERSION_DATE "2025-06-14T13:04:39.042416Z" #define OPENMPT_VERSION_DATE "2025-07-19T10:45:24.126020Z"
#define OPENMPT_VERSION_IS_PACKAGE 1 #define OPENMPT_VERSION_IS_PACKAGE 1

View file

@ -364,6 +364,7 @@
54F2D0191B80C78B8982EE59 /* algorithm.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = algorithm.hpp; path = ../../src/mpt/base/algorithm.hpp; sourceTree = "<group>"; }; 54F2D0191B80C78B8982EE59 /* algorithm.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = algorithm.hpp; path = ../../src/mpt/base/algorithm.hpp; sourceTree = "<group>"; };
55356226EAAC215859487866 /* span.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = span.hpp; path = ../../src/mpt/audio/span.hpp; sourceTree = "<group>"; }; 55356226EAAC215859487866 /* span.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = span.hpp; path = ../../src/mpt/audio/span.hpp; sourceTree = "<group>"; };
55C6E46D9A1589DFDC3CC2AD /* Dlsbank.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Dlsbank.cpp; path = ../../soundlib/Dlsbank.cpp; sourceTree = "<group>"; }; 55C6E46D9A1589DFDC3CC2AD /* Dlsbank.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Dlsbank.cpp; path = ../../soundlib/Dlsbank.cpp; sourceTree = "<group>"; };
55E9D1C649E91B38CED43006 /* feature_fence.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = feature_fence.hpp; path = ../../src/mpt/arch/feature_fence.hpp; sourceTree = "<group>"; };
55EF6B83EC187D75AD7ED9C3 /* tests_endian_int24.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_endian_int24.hpp; path = ../../src/mpt/endian/tests/tests_endian_int24.hpp; sourceTree = "<group>"; }; 55EF6B83EC187D75AD7ED9C3 /* tests_endian_int24.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_endian_int24.hpp; path = ../../src/mpt/endian/tests/tests_endian_int24.hpp; sourceTree = "<group>"; };
5609DBF3C331EA65C4C4DA33 /* utility.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = utility.hpp; path = ../../src/mpt/base/utility.hpp; sourceTree = "<group>"; }; 5609DBF3C331EA65C4C4DA33 /* utility.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = utility.hpp; path = ../../src/mpt/base/utility.hpp; sourceTree = "<group>"; };
567D9E616834DE53DDA2CCA1 /* InstrumentExtensions.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = InstrumentExtensions.cpp; path = ../../soundlib/InstrumentExtensions.cpp; sourceTree = "<group>"; }; 567D9E616834DE53DDA2CCA1 /* InstrumentExtensions.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = InstrumentExtensions.cpp; path = ../../soundlib/InstrumentExtensions.cpp; sourceTree = "<group>"; };
@ -1517,6 +1518,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
09573FAA7A79E09C30408DEA /* arch.hpp */, 09573FAA7A79E09C30408DEA /* arch.hpp */,
55E9D1C649E91B38CED43006 /* feature_fence.hpp */,
1197459E05968F108A81A3DE /* feature_flags.hpp */, 1197459E05968F108A81A3DE /* feature_flags.hpp */,
473316F00DC10E627BC33530 /* x86_amd64.hpp */, 473316F00DC10E627BC33530 /* x86_amd64.hpp */,
); );

View file

@ -364,6 +364,7 @@
54F2D0191B80C78B8982EE59 /* algorithm.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = algorithm.hpp; path = ../../src/mpt/base/algorithm.hpp; sourceTree = "<group>"; }; 54F2D0191B80C78B8982EE59 /* algorithm.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = algorithm.hpp; path = ../../src/mpt/base/algorithm.hpp; sourceTree = "<group>"; };
55356226EAAC215859487866 /* span.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = span.hpp; path = ../../src/mpt/audio/span.hpp; sourceTree = "<group>"; }; 55356226EAAC215859487866 /* span.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = span.hpp; path = ../../src/mpt/audio/span.hpp; sourceTree = "<group>"; };
55C6E46D9A1589DFDC3CC2AD /* Dlsbank.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Dlsbank.cpp; path = ../../soundlib/Dlsbank.cpp; sourceTree = "<group>"; }; 55C6E46D9A1589DFDC3CC2AD /* Dlsbank.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Dlsbank.cpp; path = ../../soundlib/Dlsbank.cpp; sourceTree = "<group>"; };
55E9D1C649E91B38CED43006 /* feature_fence.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = feature_fence.hpp; path = ../../src/mpt/arch/feature_fence.hpp; sourceTree = "<group>"; };
55EF6B83EC187D75AD7ED9C3 /* tests_endian_int24.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_endian_int24.hpp; path = ../../src/mpt/endian/tests/tests_endian_int24.hpp; sourceTree = "<group>"; }; 55EF6B83EC187D75AD7ED9C3 /* tests_endian_int24.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_endian_int24.hpp; path = ../../src/mpt/endian/tests/tests_endian_int24.hpp; sourceTree = "<group>"; };
5609DBF3C331EA65C4C4DA33 /* utility.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = utility.hpp; path = ../../src/mpt/base/utility.hpp; sourceTree = "<group>"; }; 5609DBF3C331EA65C4C4DA33 /* utility.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = utility.hpp; path = ../../src/mpt/base/utility.hpp; sourceTree = "<group>"; };
567D9E616834DE53DDA2CCA1 /* InstrumentExtensions.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = InstrumentExtensions.cpp; path = ../../soundlib/InstrumentExtensions.cpp; sourceTree = "<group>"; }; 567D9E616834DE53DDA2CCA1 /* InstrumentExtensions.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = InstrumentExtensions.cpp; path = ../../soundlib/InstrumentExtensions.cpp; sourceTree = "<group>"; };
@ -1517,6 +1518,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
09573FAA7A79E09C30408DEA /* arch.hpp */, 09573FAA7A79E09C30408DEA /* arch.hpp */,
55E9D1C649E91B38CED43006 /* feature_fence.hpp */,
1197459E05968F108A81A3DE /* feature_flags.hpp */, 1197459E05968F108A81A3DE /* feature_flags.hpp */,
473316F00DC10E627BC33530 /* x86_amd64.hpp */, 473316F00DC10E627BC33530 /* x86_amd64.hpp */,
); );

View file

@ -12,12 +12,15 @@
#include "openmpt/all/BuildSettings.hpp" #include "openmpt/all/BuildSettings.hpp"
#include "mptString.h"
#include "mpt/io/io.hpp" #include "mpt/io/io.hpp"
#include "mpt/io/io_stdstream.hpp" #include "mpt/io/io_stdstream.hpp"
#include "mptString.h"
#ifdef MPT_WITH_ZLIB #ifdef MPT_WITH_ZLIB
#include <ctime>
#include <zlib.h> #include <zlib.h>
OPENMPT_NAMESPACE_BEGIN OPENMPT_NAMESPACE_BEGIN
@ -25,15 +28,31 @@ OPENMPT_NAMESPACE_BEGIN
inline void WriteGzip(std::ostream &output, std::string &outData, const mpt::ustring &fileName) inline void WriteGzip(std::ostream &output, std::string &outData, const mpt::ustring &fileName)
{ {
z_stream strm{}; z_stream strm{};
int zlib_errc = Z_OK;
strm.avail_in = static_cast<uInt>(outData.size()); strm.avail_in = static_cast<uInt>(outData.size());
strm.next_in = reinterpret_cast<Bytef *>(outData.data()); strm.next_in = reinterpret_cast<Bytef *>(outData.data());
if(deflateInit2(&strm, Z_BEST_COMPRESSION, Z_DEFLATED, 15 | 16, 9, Z_DEFAULT_STRATEGY) != Z_OK) zlib_errc = deflateInit2(&strm, Z_BEST_COMPRESSION, Z_DEFLATED, 15 | 16, 9, Z_DEFAULT_STRATEGY);
throw std::runtime_error{"zlib init failed"}; if(zlib_errc == Z_MEM_ERROR)
{
mpt::throw_out_of_memory();
} else if(zlib_errc < Z_OK)
{
throw std::runtime_error{"zlib: deflateInit2() failed"};
}
gz_header gzHeader{}; gz_header gzHeader{};
gzHeader.time = static_cast<uLong>(time(nullptr)); gzHeader.time = static_cast<uLong>(std::time(nullptr));
std::string filenameISO = mpt::ToCharset(mpt::Charset::ISO8859_1, fileName); std::string filenameISO = mpt::ToCharset(mpt::Charset::ISO8859_1, fileName);
gzHeader.name = reinterpret_cast<Bytef *>(filenameISO.data()); gzHeader.name = reinterpret_cast<Bytef *>(filenameISO.data());
deflateSetHeader(&strm, &gzHeader); zlib_errc = deflateSetHeader(&strm, &gzHeader);
if(zlib_errc == Z_MEM_ERROR)
{
deflateEnd(&strm);
mpt::throw_out_of_memory();
} else if(zlib_errc < Z_OK)
{
deflateEnd(&strm);
throw std::runtime_error{"zlib: deflateSetHeader() failed"};
}
try try
{ {
do do
@ -41,15 +60,33 @@ inline void WriteGzip(std::ostream &output, std::string &outData, const mpt::ust
std::array<Bytef, mpt::IO::BUFFERSIZE_TINY> buffer; std::array<Bytef, mpt::IO::BUFFERSIZE_TINY> buffer;
strm.avail_out = static_cast<uInt>(buffer.size()); strm.avail_out = static_cast<uInt>(buffer.size());
strm.next_out = buffer.data(); strm.next_out = buffer.data();
deflate(&strm, Z_FINISH); zlib_errc = deflate(&strm, Z_FINISH);
if(zlib_errc == Z_BUF_ERROR)
{
// expected
} else if(zlib_errc == Z_MEM_ERROR)
{
mpt::throw_out_of_memory();
} else if(zlib_errc < Z_OK)
{
throw std::runtime_error{"zlib: deflate() failed"};
}
mpt::IO::WritePartial(output, buffer, buffer.size() - strm.avail_out); mpt::IO::WritePartial(output, buffer, buffer.size() - strm.avail_out);
} while(strm.avail_out == 0); } while(strm.avail_out == 0);
} catch(mpt::out_of_memory e)
{
deflateEnd(&strm); deflateEnd(&strm);
mpt::rethrow_out_of_memory(e);
} catch(const std::exception &) } catch(const std::exception &)
{
deflateEnd(&strm);
throw;
} catch(...)
{ {
deflateEnd(&strm); deflateEnd(&strm);
throw; throw;
} }
deflateEnd(&strm);
} }
OPENMPT_NAMESPACE_END OPENMPT_NAMESPACE_END

View file

@ -42,7 +42,7 @@ OPENMPT_NAMESPACE_BEGIN
#ifdef SSB_LOGGING #ifdef SSB_LOGGING
#define SSB_LOG(x) MPT_LOG_GLOBAL(LogDebug, "serialization", x) #define SSB_LOG(x) MPT_LOG_GLOBAL(LogDebug, "serialization", (x))
#else #else
#define SSB_LOG(x) do { } while(0) #define SSB_LOG(x) do { } while(0)
#endif #endif

View file

@ -15,5 +15,5 @@
// Version definitions. The only thing that needs to be changed when changing version number. // Version definitions. The only thing that needs to be changed when changing version number.
#define VER_MAJORMAJOR 1 #define VER_MAJORMAJOR 1
#define VER_MAJOR 32 #define VER_MAJOR 32
#define VER_MINOR 01 #define VER_MINOR 03
#define VER_MINORMINOR 04 #define VER_MINORMINOR 00

View file

@ -21,7 +21,7 @@
/*! \brief libopenmpt minor version number */ /*! \brief libopenmpt minor version number */
#define OPENMPT_API_VERSION_MINOR 8 #define OPENMPT_API_VERSION_MINOR 8
/*! \brief libopenmpt patch version number */ /*! \brief libopenmpt patch version number */
#define OPENMPT_API_VERSION_PATCH 1 #define OPENMPT_API_VERSION_PATCH 2
/*! \brief libopenmpt pre-release tag */ /*! \brief libopenmpt pre-release tag */
#define OPENMPT_API_VERSION_PREREL "" #define OPENMPT_API_VERSION_PREREL ""
/*! \brief libopenmpt pre-release flag */ /*! \brief libopenmpt pre-release flag */

View file

@ -1,8 +1,8 @@
LIBOPENMPT_VERSION_MAJOR=0 LIBOPENMPT_VERSION_MAJOR=0
LIBOPENMPT_VERSION_MINOR=8 LIBOPENMPT_VERSION_MINOR=8
LIBOPENMPT_VERSION_PATCH=1 LIBOPENMPT_VERSION_PATCH=2
LIBOPENMPT_VERSION_PREREL= LIBOPENMPT_VERSION_PREREL=
LIBOPENMPT_LTVER_CURRENT=5 LIBOPENMPT_LTVER_CURRENT=5
LIBOPENMPT_LTVER_REVISION=1 LIBOPENMPT_LTVER_REVISION=2
LIBOPENMPT_LTVER_AGE=5 LIBOPENMPT_LTVER_AGE=5

View file

@ -38,6 +38,25 @@ static const char * const license =
#include "openmpt123_config.hpp" #include "openmpt123_config.hpp"
#include "mpt/base/detect_compiler.hpp" #include "mpt/base/detect_compiler.hpp"
#if MPT_COMPILER_GCC
#ifdef MPT_COMPILER_SETTING_QUIRK_GCC_BROKEN_IPA
// See <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115049>.
#if MPT_GCC_BEFORE(9, 0, 0)
// Earlier GCC get confused about setting a global function attribute.
// We need to check for 9.0 instead of 9.1 because of
// <https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1028580>.
// It also gets confused when setting global optimization -O1,
// so we have no way of fixing GCC 8 or earlier.
//#pragma GCC optimize("O1")
#else
#pragma GCC optimize("no-ipa-ra")
#endif
#endif // MPT_COMPILER_SETTING_QUIRK_GCC_BROKEN_IPA
#endif // MPT_COMPILER_GCC
#include "mpt/base/detect_os.hpp" #include "mpt/base/detect_os.hpp"
#include "mpt/base/detect_quirks.hpp" #include "mpt/base/detect_quirks.hpp"

View file

@ -19,7 +19,7 @@
#include "mpt/base/saturate_round.hpp" #include "mpt/base/saturate_round.hpp"
#include <algorithm> #include <algorithm>
#if MPT_PLATFORM_MULTITHREADED && !defined(MPT_COMPILER_QUIRK_NO_STDCPP_THREADS) #if MPT_PLATFORM_MULTITHREADED && !defined(MPT_LIBCXX_QUIRK_NO_STD_THREAD)
#include <thread> #include <thread>
#endif #endif
@ -71,7 +71,7 @@ public:
FLAC__stream_encoder_set_bits_per_sample( encoder, flags.use_float ? 24 : 16 ); FLAC__stream_encoder_set_bits_per_sample( encoder, flags.use_float ? 24 : 16 );
FLAC__stream_encoder_set_sample_rate( encoder, flags.samplerate ); FLAC__stream_encoder_set_sample_rate( encoder, flags.samplerate );
FLAC__stream_encoder_set_compression_level( encoder, 8 ); FLAC__stream_encoder_set_compression_level( encoder, 8 );
#if (FLAC_API_VERSION_CURRENT >= 14) && MPT_PLATFORM_MULTITHREADED && !defined(MPT_COMPILER_QUIRK_NO_STDCPP_THREADS) #if (FLAC_API_VERSION_CURRENT >= 14) && MPT_PLATFORM_MULTITHREADED && !defined(MPT_LIBCXX_QUIRK_NO_STD_THREAD)
std::uint32_t threads = static_cast<std::uint32_t>(std::max(std::thread::hardware_concurrency(), static_cast<unsigned int>(1))); std::uint32_t threads = static_cast<std::uint32_t>(std::max(std::thread::hardware_concurrency(), static_cast<unsigned int>(1)));
// Work-around <https://github.com/xiph/flac/issues/823>. // Work-around <https://github.com/xiph/flac/issues/823>.
//FLAC__stream_encoder_set_num_threads( encoder, threads ); //FLAC__stream_encoder_set_num_threads( encoder, threads );

View file

@ -90,7 +90,7 @@ public:
switch (new_mode) { switch (new_mode) {
case FILE_mode::text: case FILE_mode::text:
fflush( file ); fflush( file );
#if defined(UNICODE) #if defined(UNICODE) && MPT_LIBC_MS_AT_LEAST(MPT_LIBC_MS_VER_UCRT)
old_mode = _setmode( _fileno( file ), _O_U8TEXT ); old_mode = _setmode( _fileno( file ), _O_U8TEXT );
#else #else
old_mode = _setmode( _fileno( file ), _O_TEXT ); old_mode = _setmode( _fileno( file ), _O_TEXT );

View file

@ -102,6 +102,7 @@ void CEQ::ProcessTemplate(TMixSample *frontBuffer, TMixSample *rearBuffer, std::
unsigned int old_csr = 0; unsigned int old_csr = 0;
if(CPU::HasFeatureSet(CPU::feature::sse) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) if(CPU::HasFeatureSet(CPU::feature::sse) && CPU::HasModesEnabled(CPU::mode::xmm128sse))
{ {
mpt::arch::feature_fence_aquire();
old_csr = _mm_getcsr(); old_csr = _mm_getcsr();
_mm_setcsr((old_csr & ~(_MM_DENORMALS_ZERO_MASK | _MM_FLUSH_ZERO_MASK)) | _MM_DENORMALS_ZERO_ON | _MM_FLUSH_ZERO_ON); _mm_setcsr((old_csr & ~(_MM_DENORMALS_ZERO_MASK | _MM_FLUSH_ZERO_MASK)) | _MM_DENORMALS_ZERO_ON | _MM_FLUSH_ZERO_ON);
} }
@ -124,6 +125,7 @@ void CEQ::ProcessTemplate(TMixSample *frontBuffer, TMixSample *rearBuffer, std::
if(CPU::HasFeatureSet(CPU::feature::sse) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) if(CPU::HasFeatureSet(CPU::feature::sse) && CPU::HasModesEnabled(CPU::mode::xmm128sse))
{ {
_mm_setcsr(old_csr); _mm_setcsr(old_csr);
mpt::arch::feature_fence_release();
} }
#endif #endif
} }

View file

@ -159,7 +159,7 @@ const REFLECTIONPRESET gReflectionsPreset[ENVIRONMENT_NUMREFLECTIONS] =
// Implementation // Implementation
// //
MPT_FORCEINLINE int32 ftol(float f) { return static_cast<int32>(f); } static MPT_FORCEINLINE int32 ftol(float f) { return static_cast<int32>(f); }
static void I3dl2_to_Generic( static void I3dl2_to_Generic(
const SNDMIX_REVERB_PROPERTIES *pReverb, const SNDMIX_REVERB_PROPERTIES *pReverb,
@ -597,6 +597,7 @@ void CReverb::ReverbProcessPostFiltering1x(const int32 * MPT_RESTRICT pRvb, int3
#if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE2) && defined(MPT_ARCH_INTRINSICS_X86_SSE2) #if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE2) && defined(MPT_ARCH_INTRINSICS_X86_SSE2)
if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse))
{ {
mpt::arch::feature_fence_guard arch_feature_guard;
__m128i nDCRRvb_Y1 = Load64SSE(gnDCRRvb_Y1); __m128i nDCRRvb_Y1 = Load64SSE(gnDCRRvb_Y1);
__m128i nDCRRvb_X1 = Load64SSE(gnDCRRvb_X1); __m128i nDCRRvb_X1 = Load64SSE(gnDCRRvb_X1);
__m128i in = _mm_set1_epi32(0); __m128i in = _mm_set1_epi32(0);
@ -659,6 +660,7 @@ void CReverb::ReverbDCRemoval(int32 * MPT_RESTRICT pBuffer, uint32 nSamples)
#if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE2) && defined(MPT_ARCH_INTRINSICS_X86_SSE2) #if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE2) && defined(MPT_ARCH_INTRINSICS_X86_SSE2)
if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse))
{ {
mpt::arch::feature_fence_guard arch_feature_guard;
__m128i nDCRRvb_Y1 = Load64SSE(gnDCRRvb_Y1); __m128i nDCRRvb_Y1 = Load64SSE(gnDCRRvb_Y1);
__m128i nDCRRvb_X1 = Load64SSE(gnDCRRvb_X1); __m128i nDCRRvb_X1 = Load64SSE(gnDCRRvb_X1);
while(nSamples--) while(nSamples--)
@ -724,6 +726,7 @@ void CReverb::ProcessPreDelay(SWRvbRefDelay * MPT_RESTRICT pPreDelay, const int3
#if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE2) && defined(MPT_ARCH_INTRINSICS_X86_SSE2) #if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE2) && defined(MPT_ARCH_INTRINSICS_X86_SSE2)
if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse))
{ {
mpt::arch::feature_fence_guard arch_feature_guard;
__m128i coeffs = _mm_cvtsi32_si128(pPreDelay->nCoeffs.lr); __m128i coeffs = _mm_cvtsi32_si128(pPreDelay->nCoeffs.lr);
__m128i history = _mm_cvtsi32_si128(pPreDelay->History.lr); __m128i history = _mm_cvtsi32_si128(pPreDelay->History.lr);
__m128i preDifCoeffs = _mm_cvtsi32_si128(pPreDelay->nPreDifCoeffs.lr); __m128i preDifCoeffs = _mm_cvtsi32_si128(pPreDelay->nPreDifCoeffs.lr);
@ -796,6 +799,7 @@ void CReverb::ProcessReflections(SWRvbRefDelay * MPT_RESTRICT pPreDelay, LR16 *
#if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE2) && defined(MPT_ARCH_INTRINSICS_X86_SSE2) #if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE2) && defined(MPT_ARCH_INTRINSICS_X86_SSE2)
if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse))
{ {
mpt::arch::feature_fence_guard arch_feature_guard;
union union
{ {
__m128i xmm; __m128i xmm;
@ -891,6 +895,7 @@ void CReverb::ProcessLateReverb(SWLateReverb * MPT_RESTRICT pReverb, LR16 * MPT_
#if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE2) && defined(MPT_ARCH_INTRINSICS_X86_SSE2) #if defined(MPT_WANT_ARCH_INTRINSICS_X86_SSE2) && defined(MPT_ARCH_INTRINSICS_X86_SSE2)
if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse))
{ {
mpt::arch::feature_fence_guard arch_feature_guard;
int delayPos = pReverb->nDelayPos & RVBDLY_MASK; int delayPos = pReverb->nDelayPos & RVBDLY_MASK;
__m128i rvbOutGains = Load64SSE(pReverb->RvbOutGains); __m128i rvbOutGains = Load64SSE(pReverb->RvbOutGains);
__m128i difCoeffs = Load64SSE(pReverb->nDifCoeffs); __m128i difCoeffs = Load64SSE(pReverb->nDifCoeffs);

View file

@ -97,7 +97,7 @@ struct MixLoopState
// Check how many samples can be rendered without encountering loop or sample end, and also update loop position / direction // Check how many samples can be rendered without encountering loop or sample end, and also update loop position / direction
MPT_FORCEINLINE uint32 GetSampleCount(ModChannel &chn, uint32 nSamples) const MPT_FORCEINLINE uint32 GetSampleCount(ModChannel &chn, uint32 nSamples) const
{ {
int32 nLoopStart = chn.dwFlags[CHN_LOOP] ? chn.nLoopStart : 0; const int32 nLoopStart = chn.dwFlags[CHN_LOOP] ? chn.nLoopStart : 0;
SamplePosition nInc = chn.increment; SamplePosition nInc = chn.increment;
if(nSamples <= 0 || nInc.IsZero() || !chn.nLength || !samplePointer) if(nSamples <= 0 || nInc.IsZero() || !chn.nLength || !samplePointer)
@ -227,35 +227,24 @@ struct MixLoopState
{ {
if(nPosInt >= lookaheadStart) if(nPosInt >= lookaheadStart)
{ {
#if 0 if(nInc.IsNegative())
const uint32 oldCount = nSmpCount;
// When going backwards - we can only go back up to lookaheadStart.
// When going forwards - read through the whole pre-computed wrap-around buffer if possible.
// TODO: ProTracker sample swapping needs hard cut at sample end.
int32 samplesToRead = nInc.IsNegative()
? (nPosInt - lookaheadStart)
//: 2 * InterpolationMaxLookahead - (nPosInt - mixLoopState.lookaheadStart);
: (chn.nLoopEnd - nPosInt);
//LimitMax(samplesToRead, chn.nLoopEnd - chn.nLoopStart);
nSmpCount = SamplesToBufferLength(samplesToRead, chn);
Limit(nSmpCount, 1u, oldCount);
#else
if (nInc.IsNegative())
{ {
nSmpCount = DistanceToBufferLength(SamplePosition(lookaheadStart, 0), nPos, nInv); nSmpCount = DistanceToBufferLength(SamplePosition(lookaheadStart, 0), nPos, nInv);
} else chn.pCurrentSample = lookaheadPointer;
} else if(nPosInt <= chn.nLoopEnd)
{ {
nSmpCount = DistanceToBufferLength(nPos, SamplePosition(chn.nLoopEnd, 0), nInv); nSmpCount = DistanceToBufferLength(nPos, SamplePosition(chn.nLoopEnd, 0), nInv);
}
#endif
chn.pCurrentSample = lookaheadPointer; chn.pCurrentSample = lookaheadPointer;
} else
{
nSmpCount = DistanceToBufferLength(nPos, SamplePosition(chn.nLength, 0), nInv);
}
checkDest = false; checkDest = false;
} else if(chn.dwFlags[CHN_WRAPPED_LOOP] && isAtLoopStart) } else if(chn.dwFlags[CHN_WRAPPED_LOOP] && isAtLoopStart)
{ {
// We just restarted the loop, so interpolate correctly after wrapping around // We just restarted the loop, so interpolate correctly after wrapping around
nSmpCount = DistanceToBufferLength(nPos, SamplePosition(nLoopStart + InterpolationLookaheadBufferSize, 0), nInv); nSmpCount = DistanceToBufferLength(nPos, SamplePosition(nLoopStart + InterpolationLookaheadBufferSize, 0), nInv);
chn.pCurrentSample = lookaheadPointer + (chn.nLoopEnd - nLoopStart) * chn.pModSample->GetBytesPerSample(); chn.pCurrentSample = lookaheadPointer + (chn.nLength - nLoopStart) * chn.pModSample->GetBytesPerSample();
checkDest = false; checkDest = false;
} else if(nInc.IsPositive() && static_cast<SmpLength>(nPosDest) >= lookaheadStart && nSmpCount > 1) } else if(nInc.IsPositive() && static_cast<SmpLength>(nPosDest) >= lookaheadStart && nSmpCount > 1)
{ {
@ -325,12 +314,45 @@ void CSoundFile::CreateStereoMix(int count)
} }
std::pair<mixsample_t *, mixsample_t *> CSoundFile::GetChannelOffsets(const ModChannel &chn, CHANNELINDEX channel)
{
mixsample_t *pOfsR = &m_dryROfsVol;
mixsample_t *pOfsL = &m_dryLOfsVol;
#ifndef NO_REVERB
if(((m_MixerSettings.DSPMask & SNDDSP_REVERB) && !chn.dwFlags[CHN_NOREVERB]) || chn.dwFlags[CHN_REVERB])
{
pOfsR = &m_RvbROfsVol;
pOfsL = &m_RvbLOfsVol;
}
#endif
if(chn.dwFlags[CHN_SURROUND] && m_MixerSettings.gnChannels > 2)
{
pOfsR = &m_surroundROfsVol;
pOfsL = &m_surroundLOfsVol;
}
// Look for plugins associated with this implicit tracker channel.
#ifndef NO_PLUGINS
const PLUGINDEX mixPlugin = GetBestPlugin(chn, channel, PrioritiseInstrument, RespectMutes);
if((mixPlugin > 0) && (mixPlugin <= MAX_MIXPLUGINS) && m_MixPlugins[mixPlugin - 1].pMixPlugin != nullptr)
{
// Render into plugin buffer instead of global buffer
SNDMIXPLUGINSTATE &mixState = m_MixPlugins[mixPlugin - 1].pMixPlugin->m_MixState;
if(mixState.pMixBuffer)
{
pOfsR = &mixState.nVolDecayR;
pOfsL = &mixState.nVolDecayL;
}
}
#endif // NO_PLUGINS
return std::make_pair(pOfsL, pOfsR);
}
bool CSoundFile::MixChannel(int count, ModChannel &chn, CHANNELINDEX channel, bool doMix) bool CSoundFile::MixChannel(int count, ModChannel &chn, CHANNELINDEX channel, bool doMix)
{ {
if(chn.pCurrentSample || chn.nLOfs || chn.nROfs) if(chn.pCurrentSample || chn.nLOfs || chn.nROfs)
{ {
mixsample_t *pOfsR = &m_dryROfsVol; auto [pOfsL, pOfsR] = GetChannelOffsets(chn, channel);
mixsample_t *pOfsL = &m_dryLOfsVol;
uint32 functionNdx = MixFuncTable::ResamplingModeToMixFlags(static_cast<ResamplingMode>(chn.resamplingMode)); uint32 functionNdx = MixFuncTable::ResamplingModeToMixFlags(static_cast<ResamplingMode>(chn.resamplingMode));
if(chn.dwFlags[CHN_16BIT]) functionNdx |= MixFuncTable::ndx16Bit; if(chn.dwFlags[CHN_16BIT]) functionNdx |= MixFuncTable::ndx16Bit;
@ -345,15 +367,11 @@ bool CSoundFile::MixChannel(int count, ModChannel &chn, CHANNELINDEX channel, bo
{ {
m_Reverb.TouchReverbSendBuffer(ReverbSendBuffer, m_RvbROfsVol, m_RvbLOfsVol, count); m_Reverb.TouchReverbSendBuffer(ReverbSendBuffer, m_RvbROfsVol, m_RvbLOfsVol, count);
pbuffer = ReverbSendBuffer; pbuffer = ReverbSendBuffer;
pOfsR = &m_RvbROfsVol;
pOfsL = &m_RvbLOfsVol;
} }
#endif #endif
if(chn.dwFlags[CHN_SURROUND] && m_MixerSettings.gnChannels > 2) if(chn.dwFlags[CHN_SURROUND] && m_MixerSettings.gnChannels > 2)
{ {
pbuffer = MixRearBuffer; pbuffer = MixRearBuffer;
pOfsR = &m_surroundROfsVol;
pOfsL = &m_surroundLOfsVol;
} }
// Look for plugins associated with this implicit tracker channel. // Look for plugins associated with this implicit tracker channel.
@ -366,8 +384,6 @@ bool CSoundFile::MixChannel(int count, ModChannel &chn, CHANNELINDEX channel, bo
if (mixState.pMixBuffer) if (mixState.pMixBuffer)
{ {
pbuffer = mixState.pMixBuffer; pbuffer = mixState.pMixBuffer;
pOfsR = &mixState.nVolDecayR;
pOfsL = &mixState.nVolDecayL;
if (!(mixState.dwFlags & SNDMIXPLUGINSTATE::psfMixReady)) if (!(mixState.dwFlags & SNDMIXPLUGINSTATE::psfMixReady))
{ {
StereoFill(pbuffer, count, *pOfsR, *pOfsL); StereoFill(pbuffer, count, *pOfsR, *pOfsL);

View file

@ -83,8 +83,9 @@ struct FCFileHeader
return false; return false;
static constexpr uint32 MAX_FC_SIZE = 0x8'0000; // According to manual: Sample memory allocated = 100,000 bytes static constexpr uint32 MAX_FC_SIZE = 0x8'0000; // According to manual: Sample memory allocated = 100,000 bytes
if(sequenceSize % sizeof(FCPlaylistEntry) > 1 // Some files have a mysterious extra byte const uint32 seqSize = SequenceSize();
|| sequenceSize < sizeof(FCPlaylistEntry) || sequenceSize > 256 * 13 if(seqSize % sizeof(FCPlaylistEntry) > 1 // Some files have a mysterious extra byte
|| seqSize < sizeof(FCPlaylistEntry) || seqSize > 256 * 13
|| patternsSize % 64u || !patternsSize || patternsSize > 64 * 256 || patternsOffset > MAX_FC_SIZE || patternsSize % 64u || !patternsSize || patternsSize > 64 * 256 || patternsOffset > MAX_FC_SIZE
|| freqSequenceSize % 64u || !freqSequenceSize || freqSequenceSize > 64 * 256 || freqSequenceOffset > MAX_FC_SIZE || freqSequenceSize % 64u || !freqSequenceSize || freqSequenceSize > 64 * 256 || freqSequenceOffset > MAX_FC_SIZE
|| volSequenceSize % 64u || !volSequenceSize || volSequenceSize > 64 * 256 || volSequenceOffset > MAX_FC_SIZE || volSequenceSize % 64u || !volSequenceSize || volSequenceSize > 64 * 256 || volSequenceOffset > MAX_FC_SIZE
@ -102,12 +103,22 @@ struct FCFileHeader
ORDERINDEX NumOrders() const ORDERINDEX NumOrders() const
{ {
return static_cast<ORDERINDEX>(sequenceSize / sizeof(FCPlaylistEntry)); return static_cast<ORDERINDEX>(SequenceSize() / sizeof(FCPlaylistEntry));
} }
uint32 GetHeaderMinimumAdditionalSize() const uint32 GetHeaderMinimumAdditionalSize() const
{ {
return sequenceSize + (IsFC14() ? 80 : 0); return SequenceSize() + (IsFC14() ? 80 : 0);
}
uint32 SequenceSize() const
{
// A broken copy of cult.smod has a sequence size of 0 but the sequence data is actually in the place where it's supposed to be
if(sequenceSize > 0)
return sequenceSize;
if(const uint32 headerSize = IsFC14() ? 180 : 100; patternsOffset > headerSize)
return patternsOffset - headerSize;
return 0;
} }
}; };

View file

@ -357,8 +357,8 @@ std::string MIDIMacroConfig::Macro::NormalizedString() const
{ {
std::string sanitizedMacro = *this; std::string sanitizedMacro = *this;
std::string::size_type pos; std::string::size_type pos = 0;
while((pos = sanitizedMacro.find_first_not_of("0123456789ABCDEFabchmnopsuvxyz")) != std::string::npos) while((pos = sanitizedMacro.find_first_not_of("0123456789ABCDEFabchmnopsuvxyz", pos)) != std::string::npos)
{ {
sanitizedMacro.erase(pos, 1); sanitizedMacro.erase(pos, 1);
} }

View file

@ -21,7 +21,7 @@ OPENMPT_NAMESPACE_BEGIN
ModSequence::ModSequence(CSoundFile &sndFile) ModSequence::ModSequence(CSoundFile &sndFile)
: m_sndFile(sndFile) : m_sndFile{sndFile}
{ {
} }
@ -33,6 +33,8 @@ ModSequence& ModSequence::operator=(const ModSequence &other)
std::vector<PATTERNINDEX>::assign(other.begin(), other.end()); std::vector<PATTERNINDEX>::assign(other.begin(), other.end());
m_name = other.m_name; m_name = other.m_name;
m_restartPos = other.m_restartPos; m_restartPos = other.m_restartPos;
m_defaultTempo = other.m_defaultTempo;
m_defaultSpeed = other.m_defaultSpeed;
return *this; return *this;
} }
@ -41,7 +43,9 @@ bool ModSequence::operator== (const ModSequence &other) const noexcept
{ {
return static_cast<const std::vector<PATTERNINDEX> &>(*this) == other return static_cast<const std::vector<PATTERNINDEX> &>(*this) == other
&& m_name == other.m_name && m_name == other.m_name
&& m_restartPos == other.m_restartPos; && m_restartPos == other.m_restartPos
&& m_defaultTempo == other.m_defaultTempo
&& m_defaultSpeed == other.m_defaultSpeed;
} }

View file

@ -35,9 +35,11 @@
//#include "mpt/crc/crc.hpp" //#include "mpt/crc/crc.hpp"
#include "OggStream.h" #include "OggStream.h"
#include <algorithm> #include <algorithm>
#if MPT_PLATFORM_MULTITHREADED && !defined(MPT_COMPILER_QUIRK_NO_STDCPP_THREADS) #ifdef MPT_WITH_FLAC
#if MPT_PLATFORM_MULTITHREADED && !defined(MPT_LIBCXX_QUIRK_NO_STD_THREAD)
#include <thread> #include <thread>
#endif #endif
#endif
#ifdef MPT_WITH_OGG #ifdef MPT_WITH_OGG
#if MPT_COMPILER_CLANG #if MPT_COMPILER_CLANG
#pragma clang diagnostic push #pragma clang diagnostic push
@ -698,7 +700,7 @@ bool CSoundFile::SaveFLACSample(SAMPLEINDEX nSample, std::ostream &f) const
FLAC__stream_encoder_set_metadata(encoder, metadata.data(), numBlocks); FLAC__stream_encoder_set_metadata(encoder, metadata.data(), numBlocks);
#ifdef MODPLUG_TRACKER #ifdef MODPLUG_TRACKER
FLAC__stream_encoder_set_compression_level(encoder, TrackerSettings::Instance().m_FLACCompressionLevel); FLAC__stream_encoder_set_compression_level(encoder, TrackerSettings::Instance().m_FLACCompressionLevel);
#if (FLAC_API_VERSION_CURRENT >= 14) && MPT_PLATFORM_MULTITHREADED && !defined(MPT_COMPILER_QUIRK_NO_STDCPP_THREADS) #if (FLAC_API_VERSION_CURRENT >= 14) && MPT_PLATFORM_MULTITHREADED && !defined(MPT_LIBCXX_QUIRK_NO_STD_THREAD)
uint32 threads = TrackerSettings::Instance().m_FLACMultithreading ? static_cast<uint32>(std::max(std::thread::hardware_concurrency(), static_cast<unsigned int>(1))) : static_cast<uint32>(1); uint32 threads = TrackerSettings::Instance().m_FLACMultithreading ? static_cast<uint32>(std::max(std::thread::hardware_concurrency(), static_cast<unsigned int>(1))) : static_cast<uint32>(1);
// Work-around <https://github.com/xiph/flac/issues/823>. // Work-around <https://github.com/xiph/flac/issues/823>.
//FLAC__stream_encoder_set_num_threads(encoder, threads); //FLAC__stream_encoder_set_num_threads(encoder, threads);

View file

@ -618,6 +618,7 @@ enum PlayBehaviour
kITCarryAfterNoteOff, // Envelope Carry continues to function as normal even after note-off kITCarryAfterNoteOff, // Envelope Carry continues to function as normal even after note-off
kFT2OffsetMemoryRequiresNote, // Offset memory is only updated when offset command is next to a note kFT2OffsetMemoryRequiresNote, // Offset memory is only updated when offset command is next to a note
kITNoteCutWithPorta, // Note Cut (SCx) resets note frequency and interacts with tone portamento with row delay kITNoteCutWithPorta, // Note Cut (SCx) resets note frequency and interacts with tone portamento with row delay
kITVolColNoSlidePropagation, // Don't propagate volume command c/d parameter to regular command D memory
// Add new play behaviours here. // Add new play behaviours here.

View file

@ -1312,7 +1312,9 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
for(uint32 i = 0; i < numTicks; i++) for(uint32 i = 0; i < numTicks; i++)
{ {
chn.isFirstTick = (i == 0); chn.isFirstTick = (i == 0);
VolumeSlide(chn, vol); // IT Compatibility: Volume column volume slides must not propagate their memory to the regular effect column
// Test case: VolColNoSlideMemoryPropagation.it
VolumeSlide(chn, vol, m_playBehaviour[kITVolColNoSlidePropagation]);
} }
} }
break; break;
@ -3077,6 +3079,8 @@ bool CSoundFile::ProcessEffects()
// Instrument Change ? // Instrument Change ?
if(instr) if(instr)
{ {
auto [oldChnOfsL, oldChnOfsR] = GetChannelOffsets(chn, nChn);
const ModSample *oldSample = chn.pModSample; const ModSample *oldSample = chn.pModSample;
//const ModInstrument *oldInstrument = chn.pModInstrument; //const ModInstrument *oldInstrument = chn.pModInstrument;
@ -3101,8 +3105,8 @@ bool CSoundFile::ProcessEffects()
// When swapping samples without explicit note change (e.g. during portamento), avoid clicks at end of sample (as there won't be an NNA channel to fade the sample out) // When swapping samples without explicit note change (e.g. during portamento), avoid clicks at end of sample (as there won't be an NNA channel to fade the sample out)
if(oldSample != nullptr && oldSample != chn.pModSample) if(oldSample != nullptr && oldSample != chn.pModSample)
{ {
m_dryLOfsVol += chn.nLOfs; *oldChnOfsL += chn.nLOfs;
m_dryROfsVol += chn.nROfs; *oldChnOfsR += chn.nROfs;
chn.nLOfs = 0; chn.nLOfs = 0;
chn.nROfs = 0; chn.nROfs = 0;
} }
@ -3296,7 +3300,9 @@ bool CSoundFile::ProcessEffects()
{ {
chn.nOldVolParam = vol; chn.nOldVolParam = vol;
} }
VolumeSlide(chn, static_cast<ModCommand::PARAM>(volcmd == VOLCMD_VOLSLIDEUP ? (vol << 4) : vol)); // IT Compatibility: Volume column volume slides must not propagate their memory to the regular effect column
// Test case: VolColNoSlideMemoryPropagation.it
VolumeSlide(chn, static_cast<ModCommand::PARAM>(volcmd == VOLCMD_VOLSLIDEUP ? (vol << 4) : vol), m_playBehaviour[kITVolColNoSlidePropagation]);
break; break;
case VOLCMD_FINEVOLUP: case VOLCMD_FINEVOLUP:
@ -4833,12 +4839,15 @@ void CSoundFile::VolumeDownETX(const PlayState &playState, ModChannel &chn, ModC
} }
void CSoundFile::VolumeSlide(ModChannel &chn, ModCommand::PARAM param) const void CSoundFile::VolumeSlide(ModChannel &chn, ModCommand::PARAM param, bool volCol) const
{ {
if (param) if(!volCol)
{
if(param)
chn.nOldVolumeSlide = param; chn.nOldVolumeSlide = param;
else else
param = chn.nOldVolumeSlide; param = chn.nOldVolumeSlide;
}
if((GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_DIGI | MOD_TYPE_STP | MOD_TYPE_DTM))) if((GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_DIGI | MOD_TYPE_STP | MOD_TYPE_DTM)))
{ {
@ -5689,6 +5698,8 @@ void CSoundFile::ProcessSampleOffset(ModChannel &chn, CHANNELINDEX nChn, const P
void CSoundFile::SampleOffset(ModChannel &chn, SmpLength param) const void CSoundFile::SampleOffset(ModChannel &chn, SmpLength param) const
{ {
LimitMax(param, MAX_SAMPLE_LENGTH);
// ST3 compatibility: Instrument-less note recalls previous note's offset // ST3 compatibility: Instrument-less note recalls previous note's offset
// Test case: OxxMemory.s3m // Test case: OxxMemory.s3m
if(m_playBehaviour[kST3OffsetWithoutInstrument] || GetType() == MOD_TYPE_MED) if(m_playBehaviour[kST3OffsetWithoutInstrument] || GetType() == MOD_TYPE_MED)
@ -6285,6 +6296,9 @@ void CSoundFile::SetTempo(PlayState &playState, TEMPO param, bool setFromUI) con
} else if(param < minTempo && !playState.m_flags[SONG_FIRSTTICK]) } else if(param < minTempo && !playState.m_flags[SONG_FIRSTTICK])
{ {
// Tempo Slide // Tempo Slide
// Very old MPT versions (last confirmed version: 1.09.066) add/subtract the param only on the first tick.
// Newer MPT versions (first confirmed version: 1.09.090), add/subtract the param multiplied by 2 only on the first tick.
// In SVN r26, the behaviour was adjusted to match Impulse Tracker. This change is part of OpenMPT 1.17 RC1 but not the MPT Wild pre-beta.
TEMPO tempDiff(param.GetInt() & 0x0F, 0); TEMPO tempDiff(param.GetInt() & 0x0F, 0);
if((param.GetInt() & 0xF0) == 0x10) if((param.GetInt() & 0xF0) == 0x10)
playState.m_nMusicTempo += tempDiff; playState.m_nMusicTempo += tempDiff;

View file

@ -1228,6 +1228,7 @@ PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type)
playBehaviour.set(kITDoublePortamentoSlides); playBehaviour.set(kITDoublePortamentoSlides);
playBehaviour.set(kITCarryAfterNoteOff); playBehaviour.set(kITCarryAfterNoteOff);
playBehaviour.set(kITNoteCutWithPorta); playBehaviour.set(kITNoteCutWithPorta);
playBehaviour.set(kITVolColNoSlidePropagation);
break; break;
case MOD_TYPE_XM: case MOD_TYPE_XM:

View file

@ -989,6 +989,7 @@ public:
private: private:
void CreateStereoMix(int count); void CreateStereoMix(int count);
bool MixChannel(int count, ModChannel &chn, CHANNELINDEX channel, bool doMix); bool MixChannel(int count, ModChannel &chn, CHANNELINDEX channel, bool doMix);
std::pair<mixsample_t *, mixsample_t *> GetChannelOffsets(const ModChannel &chn, CHANNELINDEX channel);
public: public:
bool FadeSong(uint32 msec); bool FadeSong(uint32 msec);
private: private:
@ -1109,7 +1110,7 @@ protected:
void FineVibrato(ModChannel &chn, uint32 param) const; void FineVibrato(ModChannel &chn, uint32 param) const;
void AutoVolumeSlide(ModChannel &chn, ModCommand::PARAM param) const; void AutoVolumeSlide(ModChannel &chn, ModCommand::PARAM param) const;
void VolumeDownETX(const PlayState &playState, ModChannel &chn, ModCommand::PARAM param) const; void VolumeDownETX(const PlayState &playState, ModChannel &chn, ModCommand::PARAM param) const;
void VolumeSlide(ModChannel &chn, ModCommand::PARAM param) const; void VolumeSlide(ModChannel &chn, ModCommand::PARAM param, bool volCol = false) const;
void PanningSlide(ModChannel &chn, ModCommand::PARAM param, bool memory = true) const; void PanningSlide(ModChannel &chn, ModCommand::PARAM param, bool memory = true) const;
void ChannelVolSlide(ModChannel &chn, ModCommand::PARAM param) const; void ChannelVolSlide(ModChannel &chn, ModCommand::PARAM param) const;
void ChannelVolumeDownWithDuration(ModChannel &chn, uint16 param = uint16_max) const; void ChannelVolumeDownWithDuration(ModChannel &chn, uint16 param = uint16_max) const;

View file

@ -604,6 +604,7 @@ void CSoundFile::UpgradeModule()
{ kITDoublePortamentoSlides, MPT_V("1.32.00.27") }, { kITDoublePortamentoSlides, MPT_V("1.32.00.27") },
{ kITCarryAfterNoteOff, MPT_V("1.32.00.40") }, { kITCarryAfterNoteOff, MPT_V("1.32.00.40") },
{ kITNoteCutWithPorta, MPT_V("1.32.01.02") }, { kITNoteCutWithPorta, MPT_V("1.32.01.02") },
{ kITVolColNoSlidePropagation, MPT_V("1.32.02.03") },
}; };
for(const auto &b : behaviours) for(const auto &b : behaviours)

View file

@ -1017,13 +1017,23 @@ bool CSoundFile::ReadJ2B(FileReader &file, ModLoadingFlags loadFlags)
// Header is valid, now unpack the RIFF AM file using inflate // Header is valid, now unpack the RIFF AM file using inflate
z_stream strm{}; z_stream strm{};
if(inflateInit(&strm) != Z_OK) int zlib_errc = Z_OK;
zlib_errc = inflateInit(&strm);
if(zlib_errc == Z_MEM_ERROR)
{
mpt::throw_out_of_memory();
} else if(zlib_errc < Z_OK)
{
return false; return false;
}
uint32 remainRead = fileHeader.packedLength, remainWrite = fileHeader.unpackedLength, totalWritten = 0; uint32 remainRead = fileHeader.packedLength, remainWrite = fileHeader.unpackedLength, totalWritten = 0;
uint32 crc = 0; uint32 crc = 0;
std::vector<Bytef> amFileData(remainWrite); std::vector<Bytef> amFileData;
int retVal = Z_OK; int retVal = Z_OK;
try
{
amFileData.resize(remainWrite);
while(remainRead && remainWrite && retVal != Z_STREAM_END) while(remainRead && remainWrite && retVal != Z_STREAM_END)
{ {
Bytef buffer[mpt::IO::BUFFERSIZE_TINY]; Bytef buffer[mpt::IO::BUFFERSIZE_TINY];
@ -1037,7 +1047,19 @@ bool CSoundFile::ReadJ2B(FileReader &file, ModLoadingFlags loadFlags)
{ {
strm.avail_out = remainWrite; strm.avail_out = remainWrite;
strm.next_out = amFileData.data() + totalWritten; strm.next_out = amFileData.data() + totalWritten;
retVal = inflate(&strm, Z_NO_FLUSH); zlib_errc = inflate(&strm, Z_NO_FLUSH);
if(zlib_errc == Z_BUF_ERROR)
{
// expected
} else if(zlib_errc == Z_MEM_ERROR)
{
mpt::throw_out_of_memory();
} else if(zlib_errc < Z_OK)
{
inflateEnd(&strm);
return false;
}
retVal = zlib_errc;
uint32 written = remainWrite - strm.avail_out; uint32 written = remainWrite - strm.avail_out;
totalWritten += written; totalWritten += written;
remainWrite -= written; remainWrite -= written;
@ -1045,6 +1067,19 @@ bool CSoundFile::ReadJ2B(FileReader &file, ModLoadingFlags loadFlags)
remainRead -= readSize; remainRead -= readSize;
} }
} catch(mpt::out_of_memory e)
{
inflateEnd(&strm);
mpt::rethrow_out_of_memory(e);
} catch(const std::exception &)
{
inflateEnd(&strm);
return false;
} catch(...)
{
inflateEnd(&strm);
return false;
}
inflateEnd(&strm); inflateEnd(&strm);
bool result = false; bool result = false;

View file

@ -4,6 +4,7 @@
#define MPT_ARCH_ARCH_HPP #define MPT_ARCH_ARCH_HPP
#include "mpt/arch/feature_fence.hpp"
#include "mpt/arch/feature_flags.hpp" #include "mpt/arch/feature_flags.hpp"
#include "mpt/arch/x86_amd64.hpp" #include "mpt/arch/x86_amd64.hpp"
#include "mpt/base/detect.hpp" #include "mpt/base/detect.hpp"

View file

@ -0,0 +1,57 @@
/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */
#ifndef MPT_ARCH_FEATURE_FENCE_HPP
#define MPT_ARCH_FEATURE_FENCE_HPP
#include "mpt/base/detect.hpp"
#include "mpt/base/macros.hpp"
#include "mpt/base/namespace.hpp"
#include <atomic>
namespace mpt {
inline namespace MPT_INLINE_NS {
namespace arch {
MPT_FORCEINLINE void feature_fence_aquire() noexcept {
std::atomic_signal_fence(std::memory_order_acquire);
}
MPT_FORCEINLINE void feature_fence_release() noexcept {
std::atomic_signal_fence(std::memory_order_release);
}
class feature_fence_guard {
public:
MPT_FORCEINLINE feature_fence_guard() noexcept {
mpt::arch::feature_fence_aquire();
}
MPT_FORCEINLINE ~feature_fence_guard() noexcept {
mpt::arch::feature_fence_release();
}
feature_fence_guard(feature_fence_guard &&) = delete;
feature_fence_guard(const feature_fence_guard &) = delete;
feature_fence_guard & operator=(feature_fence_guard &&) = delete;
feature_fence_guard & operator=(const feature_fence_guard &) = delete;
};
} // namespace arch
} // namespace MPT_INLINE_NS
} // namespace mpt
#endif // MPT_ARCH_FEATURE_FENCE_HPP

View file

@ -103,9 +103,17 @@
#if !MPT_PLATFORM_MULTITHREADED
#define MPT_LIBCXX_QUIRK_NO_STD_THREAD
#elif !MPT_COMPILER_GENERIC && MPT_OS_WINDOWS && MPT_LIBCXX_GNU && !defined(_GLIBCXX_HAS_GTHREADS)
#define MPT_LIBCXX_QUIRK_NO_STD_THREAD
#endif
#if MPT_OS_WINDOWS && MPT_COMPILER_MSVC #if MPT_OS_WINDOWS && MPT_COMPILER_MSVC
#if MPT_WINNT_AT_LEAST(MPT_WIN_VISTA) #if MPT_WINNT_AT_LEAST(MPT_WIN_VISTA)
#define MPT_COMPILER_QUIRK_COMPLEX_STD_MUTEX #define MPT_LIBCXX_QUIRK_COMPLEX_STD_MUTEX
#endif #endif
#endif #endif
@ -348,6 +356,10 @@
#if MPT_LIBCXX_GNU_BEFORE(13) #if MPT_LIBCXX_GNU_BEFORE(13)
#define MPT_LIBCXX_QUIRK_CHRONO_DATE_NO_ZONED_TIME #define MPT_LIBCXX_QUIRK_CHRONO_DATE_NO_ZONED_TIME
#endif #endif
#if MPT_LIBCXX_LLVM
// See <https://github.com/llvm/llvm-project/issues/99982>
#define MPT_LIBCXX_QUIRK_CHRONO_DATE_NO_ZONED_TIME
#endif
#if MPT_MSVC_AT_LEAST(2022, 6) && MPT_MSVC_BEFORE(2022, 7) #if MPT_MSVC_AT_LEAST(2022, 6) && MPT_MSVC_BEFORE(2022, 7)
// std::chrono triggers ICE in VS2022 17.6.0, see <https://developercommunity.visualstudio.com/t/INTERNAL-COMPILER-ERROR-when-compiling-s/10366948>. // std::chrono triggers ICE in VS2022 17.6.0, see <https://developercommunity.visualstudio.com/t/INTERNAL-COMPILER-ERROR-when-compiling-s/10366948>.
#define MPT_LIBCXX_QUIRK_CHRONO_DATE_BROKEN_ZONED_TIME #define MPT_LIBCXX_QUIRK_CHRONO_DATE_BROKEN_ZONED_TIME

View file

@ -7,10 +7,9 @@
#include "mpt/base/array.hpp" #include "mpt/base/array.hpp"
#include "mpt/base/detect.hpp" #include "mpt/base/detect.hpp"
#include "mpt/base/namespace.hpp"
#include "mpt/base/integer.hpp" #include "mpt/base/integer.hpp"
#include "mpt/base/memory.hpp" #include "mpt/base/memory.hpp"
#include "mpt/base/namespace.hpp"
#include <array> #include <array>

View file

@ -5,6 +5,7 @@
#include "mpt/base/detect.hpp"
#include "mpt/base/memory.hpp" #include "mpt/base/memory.hpp"
#include "mpt/base/namespace.hpp" #include "mpt/base/namespace.hpp"
#include "mpt/io_read/filedata.hpp" #include "mpt/io_read/filedata.hpp"
@ -12,6 +13,9 @@
#include <algorithm> #include <algorithm>
#include <cstddef> #include <cstddef>
#if MPT_GCC_AT_LEAST(12, 0, 0)
#include <cstring>
#endif
@ -65,7 +69,15 @@ public:
return dst.first(0); return dst.first(0);
} }
pos_type avail = std::min(streamLength - pos, static_cast<pos_type>(dst.size())); pos_type avail = std::min(streamLength - pos, static_cast<pos_type>(dst.size()));
std::copy(streamData + pos, streamData + static_cast<std::size_t>(pos + avail), dst.data()); const std::byte * src = streamData + pos;
#if MPT_GCC_AT_LEAST(12, 0, 0)
// work-around bogus -Warray-bounds
// work-around bogus -Wstringop-overflow
// See <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121165>.
std::memcpy(dst.data(), src, avail);
#else
std::copy(src, src + avail, dst.data());
#endif
return dst.first(static_cast<std::size_t>(avail)); return dst.first(static_cast<std::size_t>(avail));
} }

View file

@ -11,9 +11,7 @@
#if !MPT_PLATFORM_MULTITHREADED #if !MPT_PLATFORM_MULTITHREADED
#define MPT_MUTEX_NONE 1 #define MPT_MUTEX_NONE 1
#elif MPT_COMPILER_GENERIC #elif defined(MPT_LIBCXX_QUIRK_NO_STD_THREAD)
#define MPT_MUTEX_STD 1
#elif MPT_OS_WINDOWS && MPT_LIBCXX_GNU && !defined(_GLIBCXX_HAS_GTHREADS)
#define MPT_MUTEX_WIN32 1 #define MPT_MUTEX_WIN32 1
#else #else
#define MPT_MUTEX_STD 1 #define MPT_MUTEX_STD 1
@ -31,7 +29,7 @@
#if MPT_MUTEX_STD #if MPT_MUTEX_STD
#include <mutex> #include <mutex>
#ifdef MPT_COMPILER_QUIRK_COMPLEX_STD_MUTEX #ifdef MPT_LIBCXX_QUIRK_COMPLEX_STD_MUTEX
#include <shared_mutex> #include <shared_mutex>
#include <type_traits> #include <type_traits>
#endif #endif
@ -48,7 +46,7 @@ inline namespace MPT_INLINE_NS {
#if MPT_MUTEX_STD #if MPT_MUTEX_STD
#ifdef MPT_COMPILER_QUIRK_COMPLEX_STD_MUTEX #ifdef MPT_LIBCXX_QUIRK_COMPLEX_STD_MUTEX
using mutex = std::conditional<sizeof(std::shared_mutex) < sizeof(std::mutex), std::shared_mutex, std::mutex>::type; using mutex = std::conditional<sizeof(std::shared_mutex) < sizeof(std::mutex), std::shared_mutex, std::mutex>::type;
#else #else
using mutex = std::mutex; using mutex = std::mutex;

View file

@ -27,6 +27,7 @@
#include <memory> #include <memory>
#include <random> #include <random>
#include <string> #include <string>
#include <vector>
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>

View file

@ -256,6 +256,7 @@
83BB83FD2DF2BE22002077FC /* wav.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83BB83F72DF2BE22002077FC /* wav.hpp */; }; 83BB83FD2DF2BE22002077FC /* wav.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83BB83F72DF2BE22002077FC /* wav.hpp */; };
83BB83FE2DF2BE22002077FC /* wav_write.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83BB83F92DF2BE22002077FC /* wav_write.hpp */; }; 83BB83FE2DF2BE22002077FC /* wav_write.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83BB83F92DF2BE22002077FC /* wav_write.hpp */; };
83BB83FF2DF2BE22002077FC /* tags.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83BB83F62DF2BE22002077FC /* tags.hpp */; }; 83BB83FF2DF2BE22002077FC /* tags.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83BB83F62DF2BE22002077FC /* tags.hpp */; };
83BDCD912E418723003FC007 /* feature_fence.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83BDCD902E418723003FC007 /* feature_fence.hpp */; };
83E5EFD01FFEF9D200659F0F /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 83E5EFCE1FFEF9D200659F0F /* config.h */; }; 83E5EFD01FFEF9D200659F0F /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 83E5EFCE1FFEF9D200659F0F /* config.h */; };
83E5FC661FFEFA0D00659F0F /* version.h in Headers */ = {isa = PBXBuildFile; fileRef = 83E5FC2D1FFEFA0D00659F0F /* version.h */; }; 83E5FC661FFEFA0D00659F0F /* version.h in Headers */ = {isa = PBXBuildFile; fileRef = 83E5FC2D1FFEFA0D00659F0F /* version.h */; };
83E5FC681FFEFA0D00659F0F /* stdafx.h in Headers */ = {isa = PBXBuildFile; fileRef = 83E5FC2F1FFEFA0D00659F0F /* stdafx.h */; }; 83E5FC681FFEFA0D00659F0F /* stdafx.h in Headers */ = {isa = PBXBuildFile; fileRef = 83E5FC2F1FFEFA0D00659F0F /* stdafx.h */; };
@ -734,6 +735,7 @@
83BB83F72DF2BE22002077FC /* wav.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = wav.hpp; sourceTree = "<group>"; }; 83BB83F72DF2BE22002077FC /* wav.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = wav.hpp; sourceTree = "<group>"; };
83BB83F92DF2BE22002077FC /* wav_write.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = wav_write.hpp; sourceTree = "<group>"; }; 83BB83F92DF2BE22002077FC /* wav_write.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = wav_write.hpp; sourceTree = "<group>"; };
83BB83FA2DF2BE22002077FC /* wav_write.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = wav_write.cpp; sourceTree = "<group>"; }; 83BB83FA2DF2BE22002077FC /* wav_write.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = wav_write.cpp; sourceTree = "<group>"; };
83BDCD902E418723003FC007 /* feature_fence.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = feature_fence.hpp; sourceTree = "<group>"; };
83E5EFBD1FFEF7CC00659F0F /* libOpenMPT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = libOpenMPT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 83E5EFBD1FFEF7CC00659F0F /* libOpenMPT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = libOpenMPT.framework; sourceTree = BUILT_PRODUCTS_DIR; };
83E5EFCE1FFEF9D200659F0F /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = SOURCE_ROOT; }; 83E5EFCE1FFEF9D200659F0F /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = SOURCE_ROOT; };
83E5EFCF1FFEF9D200659F0F /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; 83E5EFCF1FFEF9D200659F0F /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; };
@ -1487,6 +1489,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
83649BA62A03418500CD0580 /* arch.hpp */, 83649BA62A03418500CD0580 /* arch.hpp */,
83BDCD902E418723003FC007 /* feature_fence.hpp */,
83649BA52A03418500CD0580 /* feature_flags.hpp */, 83649BA52A03418500CD0580 /* feature_flags.hpp */,
83649BA72A03418500CD0580 /* x86_amd64.hpp */, 83649BA72A03418500CD0580 /* x86_amd64.hpp */,
); );
@ -2113,6 +2116,7 @@
83E5FCDB1FFEFA1A00659F0F /* libopenmpt_stream_callbacks_file.h in Headers */, 83E5FCDB1FFEFA1A00659F0F /* libopenmpt_stream_callbacks_file.h in Headers */,
830996BA27787E9A00857684 /* base.hpp in Headers */, 830996BA27787E9A00857684 /* base.hpp in Headers */,
83E5FDC31FFEFA8500659F0F /* MIDIEvents.h in Headers */, 83E5FDC31FFEFA8500659F0F /* MIDIEvents.h in Headers */,
83BDCD912E418723003FC007 /* feature_fence.hpp in Headers */,
83E5FDF81FFEFA8500659F0F /* Compressor.h in Headers */, 83E5FDF81FFEFA8500659F0F /* Compressor.h in Headers */,
8309970C27787E9A00857684 /* detect_compiler.hpp in Headers */, 8309970C27787E9A00857684 /* detect_compiler.hpp in Headers */,
830996C227787E9A00857684 /* simple_integer.hpp in Headers */, 830996C227787E9A00857684 /* simple_integer.hpp in Headers */,