libOpenMPT Legacy: Updated to version 0.5.16

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
CQTexperiment
Christopher Snowhill 2022-01-30 15:19:36 -08:00
parent 9e42182928
commit ebb9c5b4f1
35 changed files with 246 additions and 112 deletions

View File

@ -1,4 +1,4 @@
Copyright (c) 2004-2021, OpenMPT contributors
Copyright (c) 2004-2022, OpenMPT contributors
Copyright (c) 1997-2003, Olivier Lapicque
All rights reserved.

View File

@ -74,6 +74,7 @@
# LOCAL_OGG=1 Build local copy of libogg, even if found
# LOCAL_VORBIS=1 Build local copy of libvorbis, even if found
#
# NO_MINIZ=1 Do not fallback to miniz
# NO_MINIMP3=1 Do not fallback to minimp3
# NO_STBVORBIS=1 Do not fallback to stb_vorbis
#
@ -867,11 +868,14 @@ LIBOPENMPT_C_SOURCES += $(LOCAL_ZLIB_SOURCES)
LIBOPENMPTTEST_C_SOURCES += $(LOCAL_ZLIB_SOURCES)
else
ifeq ($(NO_ZLIB),1)
ifeq ($(NO_MINIZ),1)
else
LIBOPENMPT_C_SOURCES += include/miniz/miniz.c
LIBOPENMPTTEST_C_SOURCES += include/miniz/miniz.c
CPPFLAGS += -DMPT_WITH_MINIZ
endif
endif
endif
include/minimp3/minimp3.o : CFLAGS+=$(CFLAGS_SILENT)
include/minimp3/minimp3.test.o : CFLAGS+=$(CFLAGS_SILENT)

View File

@ -1,4 +1,4 @@
MPT_SVNVERSION=16119
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.14
MPT_SVNDATE=2021-12-05T14:17:40.071493Z
MPT_SVNVERSION=16768
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.16
MPT_SVNDATE=2022-01-30T16:50:10.915999Z

View File

@ -40,11 +40,10 @@ LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
else ifeq ($(EMSCRIPTEN_TARGET),all)
# emits native wasm AND javascript with full wasm optimizations.
# as of emscripten 1.38, this is equivalent to default.
CPPFLAGS += -DMPT_BUILD_WASM
CXXFLAGS +=
CFLAGS +=
LDFLAGS += -s WASM=2 -s LEGACY_VM_SUPPORT=1
LDFLAGS += -s WASM=2 -s LEGACY_VM_SUPPORT=1 -Wno-transpile
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
@ -71,7 +70,7 @@ else ifeq ($(EMSCRIPTEN_TARGET),js)
CPPFLAGS += -DMPT_BUILD_ASMJS
CXXFLAGS +=
CFLAGS +=
LDFLAGS += -s WASM=0 -s LEGACY_VM_SUPPORT=1
LDFLAGS += -s WASM=0 -s LEGACY_VM_SUPPORT=1 -Wno-transpile
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1

View File

@ -1,10 +1,10 @@
#pragma once
#define OPENMPT_VERSION_SVNVERSION "16119"
#define OPENMPT_VERSION_REVISION 16119
#define OPENMPT_VERSION_SVNVERSION "16768"
#define OPENMPT_VERSION_REVISION 16768
#define OPENMPT_VERSION_DIRTY 0
#define OPENMPT_VERSION_MIXEDREVISIONS 0
#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.14"
#define OPENMPT_VERSION_DATE "2021-12-05T14:17:40.071493Z"
#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.16"
#define OPENMPT_VERSION_DATE "2022-01-30T16:50:10.915999Z"
#define OPENMPT_VERSION_IS_PACKAGE 1

View File

@ -418,6 +418,30 @@ inline T ExponentialGrow(const T &x)
} //namespace Util
namespace mpt
{
template <typename T>
inline T sanitize_nan(T val)
{
static_assert(std::is_floating_point<T>::value);
if(std::isnan(val))
{
return T(0.0);
}
return val;
}
template <typename T>
inline T safe_clamp(T v, T lo, T hi)
{
static_assert(std::is_floating_point<T>::value);
return std::clamp(mpt::sanitize_nan(v), lo, hi);
}
} // namespace mpt
// Limits 'val' to given range. If 'val' is less than 'lowerLimit', 'val' is set to value 'lowerLimit'.
// Similarly if 'val' is greater than 'upperLimit', 'val' is set to value 'upperLimit'.
// If 'lowerLimit' > 'upperLimit', 'val' won't be modified.

View File

@ -565,12 +565,12 @@ mpt::ustring GetFullCreditsString()
"libopenmpt (based on OpenMPT / ModPlug Tracker)\n"
#endif
"\n"
"Copyright \xC2\xA9 2004-2021 Contributors\n"
"Copyright \xC2\xA9 2004-2022 Contributors\n"
"Copyright \xC2\xA9 1997-2003 Olivier Lapicque\n"
"\n"
"Contributors:\n"
"Johannes Schultz (2008-2021)\n"
"J\xC3\xB6rn Heusipp (2012-2021)\n"
"Johannes Schultz (2008-2022)\n"
"J\xC3\xB6rn Heusipp (2012-2022)\n"
"Ahti Lepp\xC3\xA4nen (2005-2011)\n"
"Robin Fernandes (2004-2007)\n"
"Sergiy Pylypenko (2007)\n"
@ -760,7 +760,7 @@ mpt::ustring GetFullCreditsString()
mpt::ustring GetLicenseString()
{
return MPT_UTF8(
"Copyright (c) 2004-2021, OpenMPT contributors" "\n"
"Copyright (c) 2004-2022, OpenMPT contributors" "\n"
"Copyright (c) 1997-2003, Olivier Lapicque" "\n"
"All rights reserved." "\n"
"" "\n"

View File

@ -18,6 +18,6 @@ OPENMPT_NAMESPACE_BEGIN
#define VER_MAJORMAJOR 1
#define VER_MAJOR 29
#define VER_MINOR 15
#define VER_MINORMINOR 00
#define VER_MINORMINOR 04
OPENMPT_NAMESPACE_END

View File

@ -1,4 +1,4 @@
Copyright (c) 2004-2021, OpenMPT contributors
Copyright (c) 2004-2022, OpenMPT contributors
Copyright (c) 1997-2003, Olivier Lapicque
All rights reserved.

View File

@ -1,4 +1,4 @@
Copyright (c) 2004-2021, OpenMPT contributors
Copyright (c) 2004-2022, OpenMPT contributors
Copyright (c) 1997-2003, Olivier Lapicque
All rights reserved.

View File

@ -5,6 +5,39 @@ Changelog {#changelog}
For fully detailed change log, please see the source repository directly. This
is just a high-level summary.
### libopenmpt 0.5.16 (2022-01-30)
* [**Bug**] Possible hang with malformed DMF, DSM, MED and OKT files
containing 65536 or more patterns when destroying the module.
* [**Bug**] Avoid NaNs and infinite values with custom tunings.
* The letter "z" is now evaluated in fixed MIDI macros (Z80...ZFF) the same
way as in Impulse Tracker.
* MOD: Loosened VBlank timing heuristics so that "frame of mind" by Dascon
plays correctly.
* MOD: Validate the contents of "hidden" patterns beyond the end of the order
list when the file size matches the expected size when only taken "official"
patterns into account. This fixes Shofixti Ditty.mod from Star Control 2
while keeping other (partly broken) modules working.
* MED: Command 20 (reverse sample) is now only applied when it's next to a
note.
### libopenmpt 0.5.15 (2021-12-23)
* [**Sec**] Possible out-of-bounds read of stack-allocated array in malformed
AMS files. (r16243)
* [**Bug**] Fixed various undefined behaviour found with ubsan.
* IT: Even after libopenmpt 0.5.14 the filter reset logic was still not 100%
identical to Impulse Tracker: A note triggered on tick 0 of a row with a
Pattern Delay effect still caused the filter to be reset on repetitions of
that row even though the note wasn't retriggered.
* MOD: Loosened VBlank timing heuristics so that the original copy of
Guitar Slinger from Dizzy Tunes II plays correctly.
* mpg123: Update to v1.29.3 (2021-12-11).
### libopenmpt 0.5.14 (2021-12-05)
* [**Sec**] Possible out-of-bounds read in Chorus plugin with NaN plugin

View File

@ -214,7 +214,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-2021 OpenMPT developers (https://lib.openmpt.org/)" << std::endl;
about << " Copyright (c) 2013-2022 OpenMPT developers (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

@ -159,6 +159,8 @@ LIBOPENMPT_DEPRECATED static const int LIBOPENMPT_DEPRECATED_STRING_CONSTANT = 0
#else
#define LIBOPENMPT_DEPRECATED_STRING( str ) str
#endif
#else
#define LIBOPENMPT_DEPRECATED_STRING( str ) str
#endif

View File

@ -19,7 +19,7 @@
/*! \brief libopenmpt minor version number */
#define OPENMPT_API_VERSION_MINOR 5
/*! \brief libopenmpt patch version number */
#define OPENMPT_API_VERSION_PATCH 14
#define OPENMPT_API_VERSION_PATCH 16
/*! \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=5
LIBOPENMPT_VERSION_PATCH=14
LIBOPENMPT_VERSION_PATCH=16
LIBOPENMPT_VERSION_PREREL=
LIBOPENMPT_LTVER_CURRENT=2
LIBOPENMPT_LTVER_REVISION=14
LIBOPENMPT_LTVER_REVISION=16
LIBOPENMPT_LTVER_AGE=2

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-2020 OpenMPT contributors, Copyright © 1997-2003 Olivier Lapicque"
VALUE "LegalCopyright", "Copyright © 2004-2022 OpenMPT contributors, Copyright © 1997-2003 Olivier Lapicque"
VALUE "OriginalFilename", VER_FILENAME_STR
VALUE "ProductName", "libopenmpt"
VALUE "ProductVersion", VER_FILEVERSION_STR

View File

@ -468,7 +468,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-2021 OpenMPT developers (https://lib.openmpt.org/)" << std::endl;
about << " Copyright (c) 2013-2022 OpenMPT developers (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

@ -8,7 +8,7 @@
*/
static const char * const license =
"Copyright (c) 2004-2021, OpenMPT contributors" "\n"
"Copyright (c) 2004-2022, OpenMPT contributors" "\n"
"Copyright (c) 1997-2003, Olivier Lapicque" "\n"
"All rights reserved." "\n"
"" "\n"
@ -461,7 +461,7 @@ static std::string seconds_to_string( double time ) {
static void show_info( std::ostream & log, bool verbose ) {
log << "openmpt123" << " v" << OPENMPT123_VERSION_STRING << ", libopenmpt " << openmpt::string::get( "library_version" ) << " (" << "OpenMPT " << openmpt::string::get( "core_version" ) << ")" << std::endl;
log << "Copyright (c) 2013-2021 OpenMPT developers <https://lib.openmpt.org/>" << std::endl;
log << "Copyright (c) 2013-2022 OpenMPT developers <https://lib.openmpt.org/>" << std::endl;
if ( !verbose ) {
log << std::endl;
return;
@ -538,7 +538,7 @@ static void show_info( std::ostream & log, bool verbose ) {
static void show_man_version( textout & log ) {
log << "openmpt123" << " v" << OPENMPT123_VERSION_STRING << std::endl;
log << std::endl;
log << "Copyright (c) 2013-2021 OpenMPT developers <https://lib.openmpt.org/>" << std::endl;
log << "Copyright (c) 2013-2022 OpenMPT developers <https://lib.openmpt.org/>" << std::endl;
}
static void show_short_version( textout & log ) {

View File

@ -213,7 +213,19 @@ struct DecodeFloat32
static constexpr std::size_t input_inc = 4;
MPT_FORCEINLINE output_t operator() (const input_t *inBuf)
{
return IEEE754binary32LE(inBuf[loLoByteIndex], inBuf[loHiByteIndex], inBuf[hiLoByteIndex], inBuf[hiHiByteIndex]);
float32 val = IEEE754binary32LE(inBuf[loLoByteIndex], inBuf[loHiByteIndex], inBuf[hiLoByteIndex], inBuf[hiHiByteIndex]);
val = mpt::sanitize_nan(val);
if(std::isinf(val))
{
if(val >= 0.0f)
{
val = 1.0f;
} else
{
val = -1.0f;
}
}
return val;
}
};
@ -226,7 +238,20 @@ struct DecodeScaledFloat32
float factor;
MPT_FORCEINLINE output_t operator() (const input_t *inBuf)
{
return factor * IEEE754binary32LE(inBuf[loLoByteIndex], inBuf[loHiByteIndex], inBuf[hiLoByteIndex], inBuf[hiHiByteIndex]);
float32 val = IEEE754binary32LE(inBuf[loLoByteIndex], inBuf[loHiByteIndex], inBuf[hiLoByteIndex], inBuf[hiHiByteIndex]);
val = mpt::sanitize_nan(val);
if(std::isinf(val))
{
if(val >= 0.0f)
{
val = 1.0f;
} else
{
val = -1.0f;
}
}
return factor * val;
}
MPT_FORCEINLINE DecodeScaledFloat32(float scaleFactor)
: factor(scaleFactor)
@ -243,7 +268,19 @@ struct DecodeFloat64
static constexpr std::size_t input_inc = 8;
MPT_FORCEINLINE output_t operator() (const input_t *inBuf)
{
return IEEE754binary64LE(inBuf[b0], inBuf[b1], inBuf[b2], inBuf[b3], inBuf[b4], inBuf[b5], inBuf[b6], inBuf[b7]);
float64 val = IEEE754binary64LE(inBuf[b0], inBuf[b1], inBuf[b2], inBuf[b3], inBuf[b4], inBuf[b5], inBuf[b6], inBuf[b7]);
val = mpt::sanitize_nan(val);
if(std::isinf(val))
{
if(val >= 0.0)
{
val = 1.0;
} else
{
val = -1.0;
}
}
return val;
}
};
@ -371,7 +408,7 @@ struct Convert<uint8, float32>
typedef uint8 output_t;
MPT_FORCEINLINE output_t operator() (input_t val)
{
Limit(val, -1.0f, 1.0f);
val = mpt::safe_clamp(val, -1.0f, 1.0f);
val *= 128.0f;
return static_cast<uint8>(mpt::saturate_cast<int8>(static_cast<int>(MPT_SC_FASTROUND(val)))+0x80);
}
@ -384,7 +421,7 @@ struct Convert<uint8, double>
typedef uint8 output_t;
MPT_FORCEINLINE output_t operator() (input_t val)
{
Limit(val, -1.0, 1.0);
val = mpt::safe_clamp(val, -1.0, 1.0);
val *= 128.0;
return static_cast<uint8>(mpt::saturate_cast<int8>(static_cast<int>(MPT_SC_FASTROUND(val)))+0x80);
}
@ -452,7 +489,7 @@ struct Convert<int8, float32>
typedef int8 output_t;
MPT_FORCEINLINE output_t operator() (input_t val)
{
Limit(val, -1.0f, 1.0f);
val = mpt::safe_clamp(val, -1.0f, 1.0f);
val *= 128.0f;
return mpt::saturate_cast<int8>(static_cast<int>(MPT_SC_FASTROUND(val)));
}
@ -465,7 +502,7 @@ struct Convert<int8, double>
typedef int8 output_t;
MPT_FORCEINLINE output_t operator() (input_t val)
{
Limit(val, -1.0, 1.0);
val = mpt::safe_clamp(val, -1.0, 1.0);
val *= 128.0;
return mpt::saturate_cast<int8>(static_cast<int>(MPT_SC_FASTROUND(val)));
}
@ -533,7 +570,7 @@ struct Convert<int16, float32>
typedef int16 output_t;
MPT_FORCEINLINE output_t operator() (input_t val)
{
Limit(val, -1.0f, 1.0f);
val = mpt::safe_clamp(val, -1.0f, 1.0f);
val *= 32768.0f;
return mpt::saturate_cast<int16>(static_cast<int>(MPT_SC_FASTROUND(val)));
}
@ -546,7 +583,7 @@ struct Convert<int16, double>
typedef int16 output_t;
MPT_FORCEINLINE output_t operator() (input_t val)
{
Limit(val, -1.0, 1.0);
val = mpt::safe_clamp(val, -1.0, 1.0);
val *= 32768.0;
return mpt::saturate_cast<int16>(static_cast<int>(MPT_SC_FASTROUND(val)));
}
@ -614,7 +651,7 @@ struct Convert<int24, float32>
typedef int24 output_t;
MPT_FORCEINLINE output_t operator() (input_t val)
{
Limit(val, -1.0f, 1.0f);
val = mpt::safe_clamp(val, -1.0f, 1.0f);
val *= 2147483648.0f;
return static_cast<int24>(MPT_SC_RSHIFT_SIGNED(mpt::saturate_cast<int32>(static_cast<int64>(MPT_SC_FASTROUND(val))), 8));
}
@ -627,7 +664,7 @@ struct Convert<int24, double>
typedef int24 output_t;
MPT_FORCEINLINE output_t operator() (input_t val)
{
Limit(val, -1.0, 1.0);
val = mpt::safe_clamp(val, -1.0, 1.0);
val *= 2147483648.0;
return static_cast<int24>(MPT_SC_RSHIFT_SIGNED(mpt::saturate_cast<int32>(static_cast<int64>(MPT_SC_FASTROUND(val))), 8));
}
@ -695,7 +732,7 @@ struct Convert<int32, float32>
typedef int32 output_t;
MPT_FORCEINLINE output_t operator() (input_t val)
{
Limit(val, -1.0f, 1.0f);
val = mpt::safe_clamp(val, -1.0f, 1.0f);
val *= 2147483648.0f;
return mpt::saturate_cast<int32>(static_cast<int64>(MPT_SC_FASTROUND(val)));
}
@ -708,7 +745,7 @@ struct Convert<int32, double>
typedef int32 output_t;
MPT_FORCEINLINE output_t operator() (input_t val)
{
Limit(val, -1.0, 1.0);
val = mpt::safe_clamp(val, -1.0, 1.0);
val *= 2147483648.0;
return mpt::saturate_cast<int32>(static_cast<int64>(MPT_SC_FASTROUND(val)));
}
@ -776,7 +813,7 @@ struct Convert<int64, float32>
typedef int64 output_t;
MPT_FORCEINLINE output_t operator() (input_t val)
{
Limit(val, -1.0f, 1.0f);
val = mpt::safe_clamp(val, -1.0f, 1.0f);
val *= static_cast<float>(uint64(1)<<63);
return mpt::saturate_cast<int64>(MPT_SC_FASTROUND(val));
}
@ -789,7 +826,7 @@ struct Convert<int64, double>
typedef int64 output_t;
MPT_FORCEINLINE output_t operator() (input_t val)
{
Limit(val, -1.0, 1.0);
val = mpt::safe_clamp(val, -1.0, 1.0);
val *= static_cast<double>(uint64(1)<<63);
return mpt::saturate_cast<int64>(MPT_SC_FASTROUND(val));
}
@ -1155,6 +1192,7 @@ struct ConvertToFixedPoint<int32, float32, fractionalBits>
MPT_FORCEINLINE output_t operator() (input_t val)
{
static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t)*8-1);
val = mpt::sanitize_nan(val);
return mpt::saturate_cast<output_t>(MPT_SC_FASTROUND(val * factor));
}
};
@ -1173,6 +1211,7 @@ struct ConvertToFixedPoint<int32, float64, fractionalBits>
MPT_FORCEINLINE output_t operator() (input_t val)
{
static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t)*8-1);
val = mpt::sanitize_nan(val);
return mpt::saturate_cast<output_t>(MPT_SC_FASTROUND(val * factor));
}
};

View File

@ -58,7 +58,7 @@ struct XPK_BufferBounds
static int32 bfextu(std::size_t p, int32 bo, int32 bc, XPK_BufferBounds &bufs)
{
int32 r;
uint32 r;
p += bo / 8;
r = bufs.SrcRead(p); p++;
@ -75,7 +75,7 @@ static int32 bfextu(std::size_t p, int32 bo, int32 bc, XPK_BufferBounds &bufs)
static int32 bfexts(std::size_t p, int32 bo, int32 bc, XPK_BufferBounds &bufs)
{
int32 r;
uint32 r;
p += bo / 8;
r = bufs.SrcRead(p); p++;
@ -84,9 +84,7 @@ static int32 bfexts(std::size_t p, int32 bo, int32 bc, XPK_BufferBounds &bufs)
r <<= 8;
r |= bufs.SrcRead(p);
r <<= (bo % 8) + 8;
r >>= 32 - bc;
return r;
return mpt::rshift_signed(static_cast<int32>(r), 32 - bc);
}

View File

@ -438,14 +438,14 @@ bool CSoundFile::ReadAMS(FileReader &file, ModLoadingFlags loadFlags)
file.ReadSizedString<uint8le, mpt::String::spacePadded>(ChnSettings[chn].szName);
}
// Read pattern names
// Read pattern names and create patterns
Patterns.ResizeArray(fileHeader.numPats);
for(PATTERNINDEX pat = 0; pat < fileHeader.numPats; pat++)
{
char name[11];
file.ReadSizedString<uint8le, mpt::String::spacePadded>(name);
const bool ok = file.ReadSizedString<uint8le, mpt::String::spacePadded>(name);
// Create pattern now, so name won't be reset later.
if(Patterns.Insert(pat, 64))
if(Patterns.Insert(pat, 64) && ok)
{
Patterns[pat].SetName(name);
}
@ -973,8 +973,8 @@ bool CSoundFile::ReadAMS2(FileReader &file, ModLoadingFlags loadFlags)
}
char patternName[11];
patternChunk.ReadSizedString<uint8le, mpt::String::spacePadded>(patternName);
Patterns[pat].SetName(patternName);
if(patternChunk.ReadSizedString<uint8le, mpt::String::spacePadded>(patternName))
Patterns[pat].SetName(patternName);
ReadAMSPattern(Patterns[pat], true, patternChunk);
}

View File

@ -543,8 +543,11 @@ static void ConvertMEDEffect(ModCommand &m, bool is8ch, bool bpmMode, uint8 rows
case 0x20: // Reverse sample + skip samples
if(m.param == 0 && m.vol == 0)
{
m.command = CMD_S3MCMDEX;
m.param = 0x9F;
if(m.IsNote())
{
m.command = CMD_S3MCMDEX;
m.param = 0x9F;
}
} else
{
// Skip given number of samples

View File

@ -279,7 +279,7 @@ struct MO3Sample
smpCompressionMask = 0x1000 | 0x2000 | 0x4000 | 0x8000
};
int32le freqFinetune; // Frequency in S3M and IT, finetune (0...255) in MOD, MTM, XM
uint32le freqFinetune; // Frequency in S3M and IT, finetune (0...255) in MOD, MTM, XM
int8le transpose;
uint8le defaultVolume; // 0...64
uint16le panning; // 0...256 if enabled, 0xFFFF otherwise
@ -304,9 +304,9 @@ struct MO3Sample
if(type & (MOD_TYPE_IT | MOD_TYPE_S3M))
{
if(frequencyIsHertz)
mptSmp.nC5Speed = static_cast<uint32>(freqFinetune);
mptSmp.nC5Speed = freqFinetune;
else
mptSmp.nC5Speed = mpt::saturate_round<uint32>(8363.0 * std::pow(2.0, (freqFinetune + 1408) / 1536.0));
mptSmp.nC5Speed = mpt::saturate_round<uint32>(8363.0 * std::pow(2.0, static_cast<int32>(freqFinetune + 1408) / 1536.0));
} else
{
mptSmp.nFineTune = static_cast<int8>(freqFinetune);
@ -394,7 +394,7 @@ struct MO3SampleChunk
do \
{ \
READ_CTRL_BIT; \
strLen = (strLen << 1) + carry; \
strLen = mpt::lshift_signed(strLen, 1) + carry; \
READ_CTRL_BIT; \
} while(carry); \
}
@ -441,7 +441,7 @@ static bool UnpackMO3Data(FileReader &file, std::vector<uint8> &uncompressed, co
{
// LZ ptr in ctrl stream
if(uint8 b; file.Read(b))
strOffset = (strLen << 8) | b; // read less significant offset byte from stream
strOffset = mpt::lshift_signed(strLen, 8) | b; // read less significant offset byte from stream
else
break;
strLen = 0;
@ -456,9 +456,9 @@ static bool UnpackMO3Data(FileReader &file, std::vector<uint8> &uncompressed, co
// read the next 2 bits as part of strLen
READ_CTRL_BIT;
strLen = (strLen << 1) + carry;
strLen = mpt::lshift_signed(strLen, 1) + carry;
READ_CTRL_BIT;
strLen = (strLen << 1) + carry;
strLen = mpt::lshift_signed(strLen, 1) + carry;
if(strLen == 0)
{
// length does not fit in 2 bits

View File

@ -54,7 +54,7 @@ void CSoundFile::ConvertModCommand(ModCommand &m)
break;
// Extension for XM extended effects
case 'G' - 55: m.command = CMD_GLOBALVOLUME; break; //16
case 'G' - 55: m.command = CMD_GLOBALVOLUME; break; //16
case 'H' - 55: m.command = CMD_GLOBALVOLSLIDE; break;
case 'K' - 55: m.command = CMD_KEYOFF; break;
case 'L' - 55: m.command = CMD_SETENVPOSITION; break;
@ -63,11 +63,11 @@ void CSoundFile::ConvertModCommand(ModCommand &m)
case 'T' - 55: m.command = CMD_TREMOR; break;
case 'W' - 55: m.command = CMD_DUMMY; break;
case 'X' - 55: m.command = CMD_XFINEPORTAUPDOWN; break;
case 'Y' - 55: m.command = CMD_PANBRELLO; break; //34
case 'Z' - 55: m.command = CMD_MIDI; break; //35
case '\\' - 56: m.command = CMD_SMOOTHMIDI; break; //rewbs.smoothVST: 36 - note: this is actually displayed as "-" in FT2, but seems to be doing nothing.
//case ':' - 21: m.command = CMD_DELAYCUT; break; //37
case '#' + 3: m.command = CMD_XPARAM; break; //rewbs.XMfixes - Xm.param is 38
case 'Y' - 55: m.command = CMD_PANBRELLO; break; // 34
case 'Z' - 55: m.command = CMD_MIDI; break; // 35
case '\\' - 56: m.command = CMD_SMOOTHMIDI; break; // 36 - note: this is actually displayed as "-" in FT2, but seems to be doing nothing.
case 37: m.command = CMD_SMOOTHMIDI; break; // BeRoTracker uses this for smooth MIDI macros for some reason; in old OpenMPT versions this was reserved for the unimplemented "velocity" command
case '#' + 3: m.command = CMD_XPARAM; break; // 38
default: m.command = CMD_NONE;
}
}
@ -206,7 +206,7 @@ void CSoundFile::ModSaveCommand(uint8 &command, uint8 &param, bool toXM, bool co
struct MODFileHeader
{
uint8be numOrders;
uint8be restartPos;
uint8be restartPos; // Tempo (early SoundTracker) or restart position (only PC trackers?)
uint8be orderList[128];
};
@ -582,6 +582,7 @@ static PATTERNINDEX GetNumPatterns(FileReader &file, ModSequence &Order, ORDERIN
const size_t patternStartOffset = file.GetPosition();
const size_t sizeWithoutPatterns = totalSampleLen + patternStartOffset;
const size_t sizeWithOfficialPatterns = sizeWithoutPatterns + officialPatterns * numChannels * 256;
if(wowSampleLen && (wowSampleLen + patternStartOffset) + numPatterns * 8 * 256 == (file.GetLength() & ~1))
{
@ -592,8 +593,9 @@ static PATTERNINDEX GetNumPatterns(FileReader &file, ModSequence &Order, ORDERIN
if(ValidateMODPatternData(file, 16, true))
numChannels = 8;
file.Seek(patternStartOffset);
} else if(numPatterns != officialPatterns && validateHiddenPatterns)
} else if(numPatterns != officialPatterns && (validateHiddenPatterns || sizeWithOfficialPatterns == file.GetLength()))
{
// 15-sample SoundTracker specifics:
// Fix SoundTracker modules where "hidden" patterns should be ignored.
// razor-1911.mod (MD5 b75f0f471b0ae400185585ca05bf7fe8, SHA1 4de31af234229faec00f1e85e1e8f78f405d454b)
// and captain_fizz.mod (MD5 55bd89fe5a8e345df65438dbfc2df94e, SHA1 9e0e8b7dc67939885435ea8d3ff4be7704207a43)
@ -606,28 +608,21 @@ static PATTERNINDEX GetNumPatterns(FileReader &file, ModSequence &Order, ORDERIN
// only play correctly if we ignore the hidden patterns.
// Hence, we have a peek at the first hidden pattern and check if it contains a lot of illegal data.
// If that is the case, we assume it's part of the sample data and only consider the "official" patterns.
file.Seek(patternStartOffset + officialPatterns * 1024);
// 31-sample NoiseTracker / ProTracker specifics:
// Interestingly, (broken) variants of the ProTracker modules
// "killing butterfly" (MD5 bd676358b1dbb40d40f25435e845cf6b, SHA1 9df4ae21214ff753802756b616a0cafaeced8021),
// "quartex" by Reflex (MD5 35526bef0fb21cb96394838d94c14bab, SHA1 116756c68c7b6598dcfbad75a043477fcc54c96c),
// seem to have the "correct" file size when only taking the "official" patterns into account, but they only play
// correctly when also loading the inofficial patterns.
// On the other hand, "Shofixti Ditty.mod" from Star Control 2 (MD5 62b7b0819123400e4d5a7813eef7fc7d, SHA1 8330cd595c61f51c37a3b6f2a8559cf3fcaaa6e8)
// doesn't sound correct when taking the second "inofficial" pattern into account.
file.Seek(patternStartOffset + officialPatterns * numChannels * 256);
if(!ValidateMODPatternData(file, 64, true))
numPatterns = officialPatterns;
file.Seek(patternStartOffset);
}
#ifdef MPT_BUILD_DEBUG
// Check if the "hidden" patterns in the order list are actually real, i.e. if they are saved in the file.
// OpenMPT did this check in the past, but no other tracker appears to do this.
// Interestingly, (broken) variants of the ProTracker modules
// "killing butterfly" (MD5 bd676358b1dbb40d40f25435e845cf6b, SHA1 9df4ae21214ff753802756b616a0cafaeced8021),
// "quartex" by Reflex (MD5 35526bef0fb21cb96394838d94c14bab, SHA1 116756c68c7b6598dcfbad75a043477fcc54c96c),
// seem to have the "correct" file size when only taking the "official" patterns into account, but they only play
// correctly when also loading the inofficial patterns.
// See also the above check for ambiguities with SoundTracker modules.
// Keep this assertion in the code to find potential other broken MODs.
if(numPatterns != officialPatterns && sizeWithoutPatterns + officialPatterns * numChannels * 256 == file.GetLength())
{
MPT_ASSERT(false);
//numPatterns = officialPatterns;
} else
#endif
if(numPatternsIllegal > numPatterns && sizeWithoutPatterns + numPatternsIllegal * numChannels * 256 == file.GetLength())
{
// Even those illegal pattern indexes (> 128) appear to be valid... What a weird file!
@ -776,7 +771,7 @@ static bool CheckMODMagic(const char magic[4], MODMagicResult &result)
CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMOD(MemoryFileReader file, const uint64 *pfilesize)
{
if(!file.CanRead(1080 + 4))
if(!file.LengthIsAtLeast(1080 + 4))
{
return ProbeWantMoreData;
}
@ -1283,7 +1278,7 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags)
}
#endif // MPT_EXTERNAL_SAMPLES || MPT_BUILD_FUZZER
// Fix VBlank MODs. Arbitrary threshold: 10 minutes.
// Fix VBlank MODs. Arbitrary threshold: 8 minutes (enough for "frame of mind" by Dascon...).
// Basically, this just converts all tempo commands into speed commands
// for MODs which are supposed to have VBlank timing (instead of CIA timing).
// There is no perfect way to do this, since both MOD types look the same,
@ -1296,12 +1291,12 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags)
if(isMdKd && hasTempoCommands && !definitelyCIA)
{
const double songTime = GetLength(eNoAdjust).front().duration;
if(songTime >= 600.0)
if(songTime >= 480.0)
{
m_playBehaviour.set(kMODVBlankTiming);
if(GetLength(eNoAdjust, GetLengthTarget(songTime)).front().targetReached)
{
// This just makes things worse, song is at least as long as in CIA mode (e.g. in "Stary Hallway" by Neurodancer)
// This just makes things worse, song is at least as long as in CIA mode
// Obviously we should keep using CIA timing then...
m_playBehaviour.reset(kMODVBlankTiming);
} else

View File

@ -59,6 +59,9 @@ void CSoundFile::S3MConvert(ModCommand &m, bool fromIT)
// Chars under 0x40 don't save properly, so map : to ] and # to [.
case ']': m.command = CMD_DELAYCUT; break;
case '[': m.command = CMD_XPARAM; break;
// BeRoTracker extensions
case '1' + 0x41: m.command = fromIT ? CMD_KEYOFF : CMD_NONE; break;
case '2' + 0x41: m.command = fromIT ? CMD_SETENVPOSITION : CMD_NONE; break;
default: m.command = CMD_NONE;
}
}

View File

@ -41,6 +41,7 @@ void ModChannel::Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELI
prevNoteOffset = 0;
lastZxxParam = 0xFF;
isFirstTick = false;
triggerNote = false;
isPreviewNote = false;
rowCommand.Clear();
}

View File

@ -71,7 +71,7 @@ struct ModChannel
int32 newLeftVol, newRightVol;
int32 nRealVolume, nRealPan;
int32 nVolume, nPan, nFadeOutVol;
int32 nPeriod; // Frequency in Hz if !CSoundFile::PeriodsAreFrequencies() or using custom tuning, 4x Amiga periods otherwise
int32 nPeriod; // Frequency in Hz if CSoundFile::PeriodsAreFrequencies() or using custom tuning, 4x Amiga periods otherwise
int32 nC5Speed, nPortamentoDest;
int32 cachedPeriod, glissandoPeriod;
int32 nCalcVolume; // Calculated channel volume, 14-Bit (without global volume, pre-amp etc applied) - for MIDI macros
@ -116,9 +116,10 @@ struct ModChannel
FilterMode nFilterMode;
uint8 nEFxSpeed, nEFxDelay; // memory for Invert Loop (EFx, .MOD only)
uint8 nNoteSlideCounter, nNoteSlideSpeed, nNoteSlideStep; // IMF / PTM Note Slide
uint8 lastZxxParam; // Memory for \xx slides
bool isFirstTick : 1;
bool isPreviewNote : 1;
uint8 lastZxxParam; // Memory for \xx slides
bool isFirstTick : 1; // Execute tick-0 effects on this channel? (condition differs between formats due to Pattern Delay commands)
bool triggerNote : 1; // Trigger note on this tick on this channel if there is one?
bool isPreviewNote : 1; // Notes preview in editor
//-->Variables used to make user-definable tuning modes work with pattern effects.
//If true, freq should be recalculated in ReadNote() on first tick.

View File

@ -649,8 +649,8 @@ public:
MPT_CONSTEXPR11_FUN FPInt() : v(0) { }
MPT_CONSTEXPR11_FUN FPInt(T intPart, T fractPart) : v((intPart * fractFact) + (fractPart % fractFact)) { }
explicit MPT_CONSTEXPR11_FUN FPInt(float f) : v(static_cast<T>(f * float(fractFact))) { }
explicit MPT_CONSTEXPR11_FUN FPInt(double f) : v(static_cast<T>(f * double(fractFact))) { }
explicit MPT_CONSTEXPR11_FUN FPInt(float f) : v(mpt::saturate_round<T>(f * float(fractFact))) { }
explicit MPT_CONSTEXPR11_FUN FPInt(double f) : v(mpt::saturate_round<T>(f * double(fractFact))) { }
// Set integer and fractional part
MPT_CONSTEXPR14_FUN FPInt<fractFact, T> &Set(T intPart, T fractPart = 0) { v = (intPart * fractFact) + (fractPart % fractFact); return *this; }

View File

@ -81,10 +81,10 @@ int CSoundFile::SetupChannelFilter(ModChannel &chn, bool bReset, int envModifier
// Filtering is only ever done in IT if either cutoff is not full or if resonance is set.
if(m_playBehaviour[kITFilterBehaviour] && resonance == 0 && computedCutoff >= 254)
{
if(chn.rowCommand.IsNote() && !chn.rowCommand.IsPortamento() && !chn.nMasterChn && chn.isFirstTick)
if(chn.rowCommand.IsNote() && !chn.rowCommand.IsPortamento() && !chn.nMasterChn && chn.triggerNote)
{
// Z7F next to a note disables the filter, however in other cases this should not happen.
// Test cases: filter-reset.it, filter-reset-carry.it, filter-reset-envelope.it, filter-nna.it
// Test cases: filter-reset.it, filter-reset-carry.it, filter-reset-envelope.it, filter-nna.it, FilterResetPatDelay.it
chn.dwFlags.reset(CHN_FILTER);
}
return -1;
@ -148,7 +148,7 @@ int CSoundFile::SetupChannelFilter(ModChannel &chn, bool bReset, int envModifier
#endif // MPT_INTMIXER
break;
}
#undef FILTER_CONVERT
#undef MPT_FILTER_CONVERT
if (bReset)
{

View File

@ -2659,6 +2659,7 @@ bool CSoundFile::ProcessEffects()
{
chn.isFirstTick = tickCount == nStartTick;
}
chn.triggerNote = triggerNote;
// FT2 compatibility: Note + portamento + note delay = no portamento
// Test case: PortaDelay.xm
@ -5082,7 +5083,7 @@ void CSoundFile::ProcessMIDIMacro(CHANNELINDEX nChn, bool isSmooth, const char *
} else if(macro[pos] == 'z')
{
// Zxx parameter
data = param & 0x7F;
data = param;
if(isSmooth && chn.lastZxxParam < 0x80
&& (outPos < 3 || out[outPos - 3] != 0xF0 || out[outPos - 2] < 0xF0))
{

View File

@ -1908,6 +1908,8 @@ void CSoundFile::ProcessSampleAutoVibrato(ModChannel &chn, int &period, Tuning::
void CSoundFile::ProcessRamping(ModChannel &chn) const
{
chn.leftRamp = chn.rightRamp = 0;
LimitMax(chn.newLeftVol, int32_max >> VOLUMERAMPPRECISION);
LimitMax(chn.newRightVol, int32_max >> VOLUMERAMPPRECISION);
if(chn.dwFlags[CHN_VOLUMERAMP] && (chn.leftVol != chn.newLeftVol || chn.rightVol != chn.newRightVol))
{
const bool rampUp = (chn.newLeftVol > chn.leftVol) || (chn.newRightVol > chn.rightVol);
@ -2509,7 +2511,7 @@ void CSoundFile::ProcessMacroOnChannel(CHANNELINDEX nChn)
if(chn.rowCommand.param < 0x80)
ProcessMIDIMacro(nChn, (chn.rowCommand.command == CMD_SMOOTHMIDI), m_MidiCfg.szMidiSFXExt[chn.nActiveMacro], chn.rowCommand.param);
else
ProcessMIDIMacro(nChn, (chn.rowCommand.command == CMD_SMOOTHMIDI), m_MidiCfg.szMidiZXXExt[(chn.rowCommand.param & 0x7F)], 0);
ProcessMIDIMacro(nChn, (chn.rowCommand.command == CMD_SMOOTHMIDI), m_MidiCfg.szMidiZXXExt[(chn.rowCommand.param & 0x7F)], chn.rowCommand.param);
}
}
}

View File

@ -262,7 +262,8 @@ bool CPattern::SetName(const char *newName, size_t maxChars)
{
return false;
}
m_PatternName = mpt::truncate(newName, maxChars);
const auto nameEnd = std::find(newName, newName + maxChars, '\0');
m_PatternName.assign(newName, nameEnd);
return true;
}

View File

@ -28,10 +28,7 @@ void CPatternContainer::ClearPatterns()
void CPatternContainer::DestroyPatterns()
{
for(PATTERNINDEX i = 0; i < m_Patterns.size(); i++)
{
Remove(i);
}
m_Patterns.clear();
}
@ -67,7 +64,7 @@ PATTERNINDEX CPatternContainer::InsertAny(const ROWINDEX rows, bool respectQtyLi
bool CPatternContainer::Insert(const PATTERNINDEX index, const ROWINDEX rows)
{
if(rows > MAX_PATTERN_ROWS || rows == 0)
if(rows > MAX_PATTERN_ROWS || rows == 0 || index >= PATTERNINDEX_INVALID)
return false;
if(IsValidPat(index))
return false;

View File

@ -616,10 +616,11 @@ float I3DL2Reverb::CalcDecayCoeffs(int32 index)
float c2 = 0.0f;
float c21 = (std::pow(c1, 2.0f - 2.0f / decayHFRatio) - 1.0f) / (1.0f - std::cos(hfRef));
if(c21 != 0)
if(c21 != 0 && std::isfinite(c21))
{
float c22 = -2.0f * c21 - 2.0f;
float c23 = std::sqrt(c22 * c22 - c21 * c21 * 4.0f);
float c23sq = c22 * c22 - c21 * c21 * 4.0f;
float c23 = c23sq > 0.0f ? std::sqrt(c23sq) : 0.0f;
c2 = (c23 - c22) / (c21 + c21);
if(std::abs(c2) > 1.0f)
c2 = (-c22 - c23) / (c21 + c21);

View File

@ -23,6 +23,10 @@ OPENMPT_NAMESPACE_BEGIN
namespace Tuning {
static RATIOTYPE SanitizeGroupRatio(RATIOTYPE ratio)
{
return std::clamp(std::abs(ratio), 1e-15f, 1e+07f);
}
namespace CTuningS11n
{
@ -256,7 +260,12 @@ RATIOTYPE CTuning::GetRatio(const NOTEINDEXTYPE note) const
{
return s_DefaultFallbackRatio;
}
return m_RatioTable[note - m_NoteMin];
const auto ratio = m_RatioTable[note - m_NoteMin];
if(ratio <= 1e-15f)
{
return s_DefaultFallbackRatio;
}
return ratio;
}
@ -479,6 +488,17 @@ SerializationResult CTuning::InitDeserialize(std::istream &iStrm, mpt::Charset d
UNOTEINDEXTYPE ratiotableSize = 0;
ssb.ReadItem(ratiotableSize, "RTI4");
m_GroupRatio = SanitizeGroupRatio(m_GroupRatio);
if(!std::isfinite(m_GroupRatio))
{
return SerializationResult::Failure;
}
for(auto ratio : m_RatioTable)
{
if(!std::isfinite(ratio))
return SerializationResult::Failure;
}
// If reader status is ok and m_NoteMin is somewhat reasonable, process data.
if(!((ssb.GetStatus() & srlztn::SNT_FAILURE) == 0 && m_NoteMin >= -300 && m_NoteMin <= 300))
{
@ -682,6 +702,11 @@ SerializationResult CTuning::InitDeserializeOLD(std::istream &inStrm, mpt::Chars
return SerializationResult::Failure;
}
}
for(auto ratio : m_RatioTable)
{
if(!std::isfinite(ratio))
return SerializationResult::Failure;
}
//Fineratios
if(version <= 2)
@ -697,6 +722,11 @@ SerializationResult CTuning::InitDeserializeOLD(std::istream &inStrm, mpt::Chars
return SerializationResult::Failure;
}
}
for(auto ratio : m_RatioTableFine)
{
if(!std::isfinite(ratio))
return SerializationResult::Failure;
}
m_FineStepCount = mpt::saturate_cast<USTEPINDEXTYPE>(m_RatioTableFine.size());
// m_NoteMin
@ -720,8 +750,8 @@ SerializationResult CTuning::InitDeserializeOLD(std::istream &inStrm, mpt::Chars
//m_GroupRatio
IEEE754binary32LE groupratio = IEEE754binary32LE(0.0f);
mpt::IO::Read(inStrm, groupratio);
m_GroupRatio = groupratio;
if(m_GroupRatio < 0)
m_GroupRatio = SanitizeGroupRatio(groupratio);
if(!std::isfinite(m_GroupRatio))
{
return SerializationResult::Failure;
}