Updated libOpenMPT to version 0.6.8

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
main
Christopher Snowhill 2023-02-04 22:13:01 -08:00
parent 4617654b57
commit 66338e2c83
No known key found for this signature in database
73 changed files with 475 additions and 280 deletions

View File

@ -1,4 +1,4 @@
Copyright (c) 2004-2022, OpenMPT Project Developers and Contributors
Copyright (c) 2004-2023, OpenMPT Project Developers and Contributors
Copyright (c) 1997-2003, Olivier Lapicque
All rights reserved.

View File

@ -215,8 +215,7 @@ LOCAL_SRC_FILES += \
sounddsp/DSP.cpp \
sounddsp/EQ.cpp \
sounddsp/Reverb.cpp \
test/TestToolsLib.cpp \
test/test.cpp
include $(BUILD_SHARED_LIBRARY)

View File

@ -1,4 +1,4 @@
MPT_SVNVERSION=17954
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.6.6
MPT_SVNDATE=2022-09-25T14:18:19.447172Z
MPT_SVNVERSION=18680
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.6.8
MPT_SVNDATE=2023-01-29T12:13:49.877060Z

View File

@ -80,15 +80,15 @@ CPPFLAGS += -D_WIN32_WINNT=0x0501
else ifeq ($(WINDOWS_VERSION),winxp64)
CPPFLAGS += -D_WIN32_WINNT=0x0502
else ifeq ($(WINDOWS_VERSION),winvista)
CPPFLAGS += -DNTDDI_VERSION=0x06000000
CPPFLAGS += -DNTDDI_VERSION=0x06000000 -D_WIN32_WINNT=0x0600
else ifeq ($(WINDOWS_VERSION),win7)
CPPFLAGS += -DNTDDI_VERSION=0x06010000
CPPFLAGS += -DNTDDI_VERSION=0x06010000 -D_WIN32_WINNT=0x0601
else ifeq ($(WINDOWS_VERSION),win8)
CPPFLAGS += -DNTDDI_VERSION=0x06020000
CPPFLAGS += -DNTDDI_VERSION=0x06020000 -D_WIN32_WINNT=0x0602
else ifeq ($(WINDOWS_VERSION),win8.1)
CPPFLAGS += -DNTDDI_VERSION=0x06030000
CPPFLAGS += -DNTDDI_VERSION=0x06030000 -D_WIN32_WINNT=0x0603
else ifeq ($(WINDOWS_VERSION),win10)
CPPFLAGS += -DNTDDI_VERSION=0x0A000000
CPPFLAGS += -DNTDDI_VERSION=0x0A000000 -D_WIN32_WINNT=0x0A00
else
$(error unknown WINDOWS_VERSION)
endif

View File

@ -21,6 +21,7 @@ CFLAGS_SILENT += -Wno-float-conversion
CFLAGS_SILENT += -Wno-implicit-fallthrough
CFLAGS_SILENT += -Wno-old-style-declaration
CFLAGS_SILENT += -Wno-sign-compare
CFLAGS_SILENT += -Wno-stringop-overflow
CFLAGS_SILENT += -Wno-type-limits
CFLAGS_SILENT += -Wno-unused-but-set-variable
CFLAGS_SILENT += -Wno-unused-function

View File

@ -1,10 +1,10 @@
#pragma once
#define OPENMPT_VERSION_SVNVERSION "17954"
#define OPENMPT_VERSION_REVISION 17954
#define OPENMPT_VERSION_SVNVERSION "18680"
#define OPENMPT_VERSION_REVISION 18680
#define OPENMPT_VERSION_DIRTY 0
#define OPENMPT_VERSION_MIXEDREVISIONS 0
#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.6.6"
#define OPENMPT_VERSION_DATE "2022-09-25T14:18:19.447172Z"
#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.6.8"
#define OPENMPT_VERSION_DATE "2023-01-29T12:13:49.877060Z"
#define OPENMPT_VERSION_IS_PACKAGE 1

View File

@ -516,14 +516,20 @@ CString ToCString(const std::wstring &str)
#ifdef UNICODE
return str.c_str();
#else
// cppcheck false-positive
// cppcheck-suppress returnDanglingLifetime
return ToCharset(Charset::Locale, str).c_str();
#endif
}
CString ToCString(Charset from, const std::string &str)
{
#ifdef UNICODE
// cppcheck false-positive
// cppcheck-suppress returnDanglingLifetime
return ToWide(from, str).c_str();
#else
// cppcheck false-positive
// cppcheck-suppress returnDanglingLifetime
return ToCharset(Charset::Locale, from, str).c_str();
#endif
}
@ -547,6 +553,8 @@ std::string ToCharset(Charset to, const CString &str)
CString ToCString(const mpt::lstring &str)
{
#ifdef UNICODE
// cppcheck false-positive
// cppcheck-suppress returnDanglingLifetime
return ToWide(str).c_str();
#else
return str.c_str();
@ -635,8 +643,12 @@ mpt::winstring ToWin(const mpt::ustring &str)
CString ToCString(const mpt::ustring &str)
{
#ifdef UNICODE
// cppcheck false-positive
// cppcheck-suppress returnDanglingLifetime
return String::DecodeImpl<mpt::ustring>(mpt::Charset::UTF8, str).c_str();
#else // !UNICODE
// cppcheck false-positive
// cppcheck-suppress returnDanglingLifetime
return String::ConvertImpl<std::string, mpt::ustring>(mpt::Charset::Locale, mpt::Charset::UTF8, str).c_str();
#endif // UNICODE
}
@ -810,7 +822,7 @@ mpt::ustring ToUpperCase(const mpt::ustring &s)
#endif // UNICODE
#else // !MPT_WITH_MFC
std::wstring ws = mpt::ToWide(s);
std::transform(ws.begin(), ws.end(), ws.begin(), &std::towlower);
std::transform(ws.begin(), ws.end(), ws.begin(), &std::towupper);
return mpt::ToUnicode(ws);
#endif // MPT_WITH_MFC
}

View File

@ -592,12 +592,12 @@ mpt::ustring GetFullCreditsString()
"libopenmpt (based on OpenMPT / Open ModPlug Tracker)\n"
#endif
"\n"
"Copyright \xC2\xA9 2004-2022 OpenMPT Project Developers and Contributors\n"
"Copyright \xC2\xA9 2004-2023 OpenMPT Project Developers and Contributors\n"
"Copyright \xC2\xA9 1997-2003 Olivier Lapicque\n"
"\n"
"Developers:\n"
"Johannes Schultz (2008-2022)\n"
"J\xC3\xB6rn Heusipp (2012-2022)\n"
"Johannes Schultz (2008-2023)\n"
"J\xC3\xB6rn Heusipp (2012-2023)\n"
"Ahti Lepp\xC3\xA4nen (2005-2011)\n"
"Robin Fernandes (2004-2007)\n"
"Sergiy Pylypenko (2007)\n"
@ -792,7 +792,7 @@ mpt::ustring GetFullCreditsString()
mpt::ustring GetLicenseString()
{
return MPT_UTF8(
"Copyright (c) 2004-2022, OpenMPT Project Developers and Contributors" "\n"
"Copyright (c) 2004-2023, 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 30
#define VER_MINOR 07
#define VER_MINOR 10
#define VER_MINORMINOR 00
OPENMPT_NAMESPACE_END

View File

@ -1,4 +1,4 @@
Copyright (c) 2004-2022, OpenMPT Project Developers and Contributors
Copyright (c) 2004-2023, OpenMPT Project Developers and Contributors
Copyright (c) 1997-2003, Olivier Lapicque
All rights reserved.

View File

@ -1,4 +1,4 @@
Copyright (c) 2004-2022, OpenMPT Project Developers and Contributors
Copyright (c) 2004-2023, OpenMPT Project Developers and Contributors
Copyright (c) 1997-2003, Olivier Lapicque
All rights reserved.

View File

@ -5,6 +5,34 @@ Changelog {#changelog}
For fully detailed change log, please see the source repository directly. This
is just a high-level summary.
### libopenmpt 0.6.8 (2023-01-29)
* [**Bug**] DSYM: Loading DSYM files got broken in 0.6.7.
* When seeking around in a module, the tempo was sometimes incorrectly limited
to 255 BPM.
* Initial instrument cutoff was broken for OPL instruments in
libopenmnpt 0.6.7.
* mpg123: Update to v1.31.2 (2023-01-14).
### libopenmpt 0.6.7 (2023-01-08)
* [**Bug**] openmpt123: openmpt123 crashed on Windows 9x when showing any
console output.
* IT: In sample mode, portamento to a different sample turns off the filter if
cutoff / resonance was previously 127 / 0.
* S3M Detect files saved with Graoumf Tracker instead of claiming they were
made with OpenMPT 4.47.
* S3M: Pattern loop state was not propagated anymore since libopenmpt 0.6.0,
leading to wrong song length calculation and SB0 + SBx being located on
different channels not working properly anymore.
* mpg123: Update to v1.31.1 (2022-11-01).
* FLAC: Update to v1.4.2 (2022-10-22).
* pugixml: Update to v1.13 (2022-11-02).
### libopenmpt 0.6.6 (2022-09-25)
* [**Sec**] Possible crash when playing manipulated IT / MPTM files with a T00

View File

@ -262,7 +262,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-2022 OpenMPT Project Developers and Contributors (https://lib.openmpt.org/)" << std::endl;
about << " Copyright (c) 2013-2023 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

@ -1132,7 +1132,7 @@ public:
\param value The value that should be set.
\throws openmpt::exception Throws an exception derived from openmpt::exception in case the value is not sensible (e.g. negative tempo factor) or under the circumstances outlined in openmpt::module::get_ctls.
\sa openmpt::module::get_ctls
\deprecated Please use openmpt::module::ctl_set_bool(), openmpt::module::ctl_set_int(), openmpt::module::ctl_set_floatingpoint(), or openmpt::module::ctl_set_string().
\deprecated Please use openmpt::module::ctl_set_boolean(), openmpt::module::ctl_set_integer(), openmpt::module::ctl_set_floatingpoint(), or openmpt::module::ctl_set_text().
*/
LIBOPENMPT_ATTR_DEPRECATED void ctl_set( const std::string & ctl, const std::string & value );
//! Set ctl boolean value

View File

@ -21,7 +21,7 @@
/*! \brief libopenmpt minor version number */
#define OPENMPT_API_VERSION_MINOR 6
/*! \brief libopenmpt patch version number */
#define OPENMPT_API_VERSION_PATCH 6
#define OPENMPT_API_VERSION_PATCH 8
/*! \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=6
LIBOPENMPT_VERSION_PATCH=6
LIBOPENMPT_VERSION_PATCH=8
LIBOPENMPT_VERSION_PREREL=
LIBOPENMPT_LTVER_CURRENT=3
LIBOPENMPT_LTVER_REVISION=6
LIBOPENMPT_LTVER_REVISION=8
LIBOPENMPT_LTVER_AGE=3

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-2022 OpenMPT Project Developers and Contributors, Copyright © 1997-2003 Olivier Lapicque"
VALUE "LegalCopyright", "Copyright © 2004-2023 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

@ -519,7 +519,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-2022 OpenMPT Project Developers and Contributors (https://lib.openmpt.org/)" << std::endl;
about << " Copyright (c) 2013-2023 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;
@ -563,8 +563,8 @@ private:
xmplay_streambuf & operator = ( const xmplay_streambuf & );
private:
XMPFILE & file;
static const std::size_t put_back = 4096;
static const std::size_t buf_size = 65536;
static inline constexpr std::size_t put_back = 4096;
static inline constexpr std::size_t buf_size = 65536;
std::vector<char> buffer;
}; // class xmplay_streambuf

View File

@ -8,7 +8,7 @@
*/
static const char * const license =
"Copyright (c) 2004-2022, OpenMPT Project Developers and Contributors" "\n"
"Copyright (c) 2004-2023, OpenMPT Project Developers and Contributors" "\n"
"Copyright (c) 1997-2003, Olivier Lapicque" "\n"
"All rights reserved." "\n"
"" "\n"
@ -464,7 +464,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-2022 OpenMPT Project Developers and Contributors <https://lib.openmpt.org/>" << std::endl;
log << "Copyright (c) 2013-2023 OpenMPT Project Developers and Contributors <https://lib.openmpt.org/>" << std::endl;
if ( !verbose ) {
log << std::endl;
return;
@ -541,7 +541,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-2022 OpenMPT Project Developers and Contributors <https://lib.openmpt.org/>" << std::endl;
log << "Copyright (c) 2013-2023 OpenMPT Project Developers and Contributors <https://lib.openmpt.org/>" << std::endl;
}
static void show_short_version( textout & log ) {
@ -587,6 +587,34 @@ static std::string get_device_string( const std::string & device ) {
return device;
}
static void show_help_keyboard( textout & log, bool man_version = false ) {
if ( !man_version ) {
show_info( log, false );
}
log << "Keyboard hotkeys (use 'openmpt123 --ui'):" << std::endl;
log << std::endl;
log << " [q] quit" << std::endl;
log << " [ ] pause / unpause" << std::endl;
log << " [N] skip 10 files backward" << std::endl;
log << " [n] prev file" << std::endl;
log << " [m] next file" << std::endl;
log << " [M] skip 10 files forward" << std::endl;
log << " [h] seek 10 seconds backward" << std::endl;
log << " [j] seek 1 seconds backward" << std::endl;
log << " [k] seek 1 seconds forward" << std::endl;
log << " [l] seek 10 seconds forward" << std::endl;
log << " [u]|[i] +/- tempo" << std::endl;
log << " [o]|[p] +/- pitch" << std::endl;
log << " [3]|[4] +/- gain" << std::endl;
log << " [5]|[6] +/- stereo separation" << std::endl;
log << " [7]|[8] +/- filter taps" << std::endl;
log << " [9]|[0] +/- volume ramping" << std::endl;
log << std::endl;
if ( !man_version ) {
log.writeout();
}
}
static void show_help( textout & log, bool with_info = true, bool longhelp = false, bool man_version = false, const std::string & message = std::string() ) {
if ( with_info ) {
show_info( log, false );
@ -600,6 +628,7 @@ static void show_help( textout & log, bool with_info = true, bool longhelp = fal
}
if ( man_version ) {
log << "Options:" << std::endl;
log << std::endl;
}
log << " -h, --help Show help" << std::endl;
log << " --help-keyboard Show keyboard hotkeys in ui mode" << std::endl;
@ -685,6 +714,8 @@ static void show_help( textout & log, bool with_info = true, bool longhelp = fal
log << extension;
}
log << std::endl;
} else {
show_help_keyboard( log, true );
}
}
@ -697,30 +728,6 @@ static void show_help( textout & log, bool with_info = true, bool longhelp = fal
log.writeout();
}
static void show_help_keyboard( textout & log ) {
show_info( log, false );
log << "Keyboard hotkeys (use 'openmpt123 --ui'):" << std::endl;
log << std::endl;
log << " [q] quit" << std::endl;
log << " [ ] pause / unpause" << std::endl;
log << " [N] skip 10 files backward" << std::endl;
log << " [n] prev file" << std::endl;
log << " [m] next file" << std::endl;
log << " [M] skip 10 files forward" << std::endl;
log << " [h] seek 10 seconds backward" << std::endl;
log << " [j] seek 1 seconds backward" << std::endl;
log << " [k] seek 1 seconds forward" << std::endl;
log << " [l] seek 10 seconds forward" << std::endl;
log << " [u]|[i] +/- tempo" << std::endl;
log << " [o]|[p] +/- pitch" << std::endl;
log << " [3]|[4] +/- gain" << std::endl;
log << " [5]|[6] +/- stereo separation" << std::endl;
log << " [7]|[8] +/- filter taps" << std::endl;
log << " [9]|[0] +/- volume ramping" << std::endl;
log << std::endl;
log.writeout();
}
template < typename Tmod >
static void apply_mod_settings( commandlineflags & flags, Tmod & mod ) {

View File

@ -120,7 +120,7 @@ private:
s << text;
#else
s << mpt::transcode<std::string>( mpt::logical_encoding::locale, mpt::common_encoding::utf8, text );
#endif
#endif
s.flush();
}
}
@ -167,12 +167,13 @@ private:
std::string text = pop();
if ( text.length() > 0 ) {
if ( console ) {
DWORD chars_written = 0;
#if defined(UNICODE)
std::wstring wtext = mpt::transcode<std::wstring>( mpt::common_encoding::utf8, text );
WriteConsole( handle, wtext.data(), static_cast<DWORD>( wtext.size() ), NULL, NULL );
WriteConsole( handle, wtext.data(), static_cast<DWORD>( wtext.size() ), &chars_written, NULL );
#else
std::string ltext = mpt::transcode<std::string>( mpt::logical_encoding::locale, mpt::common_encoding::utf8, text );
WriteConsole( handle, ltext.data(), static_cast<DWORD>( ltext.size() ), NULL, NULL );
WriteConsole( handle, ltext.data(), static_cast<DWORD>( ltext.size() ), &chars_written, NULL );
#endif
} else {
#if defined(UNICODE)

View File

@ -98,6 +98,8 @@ static uint8 XPK_ReadTable(int32 index)
};
if(index < 0) throw XPK_error();
if(static_cast<std::size_t>(index) >= std::size(xpk_table)) throw XPK_error();
// cppcheck false-positive
// cppcheck-suppress arrayIndexOutOfBoundsCond
return xpk_table[index];
}

View File

@ -2010,9 +2010,9 @@ bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, ui
} else
{
SmpLength len = std::min(dwLen / 2u, sampleCopy.nLength);
const int16 *src = reinterpret_cast<int16 *>(pWaveForm.data());
const std::byte *src = mpt::byte_cast<const std::byte *>(pWaveForm.data());
int16 *dst = sampleCopy.sample16() + offsetNew;
CopySample<SC::ConversionChain<SC::Convert<int16, int16>, SC::DecodeIdentity<int16>>>(dst, len, 2, src, pWaveForm.size(), 1);
CopySample<SC::ConversionChain<SC::Convert<int16, int16>, SC::DecodeInt16<0, littleEndian16>>>(dst, len, 2, src, pWaveForm.size(), 1);
}
sample.FreeSample();
sample = sampleCopy;

View File

@ -129,7 +129,7 @@ public:
uint32 GetNumInstruments() const { return static_cast<uint32>(m_Instruments.size()); }
uint32 GetNumSamples() const { return static_cast<uint32>(m_WaveForms.size()); }
const DLSINSTRUMENT *GetInstrument(uint32 iIns) const { return iIns < m_Instruments.size() ? &m_Instruments[iIns] : nullptr; }
const DLSINSTRUMENT *FindInstrument(bool isDrum, uint32 bank = 0xFF, uint32 program = 0xFF, uint32 key = 0xFF, uint32 *pInsNo = nullptr) const;
[[nodiscard]] const DLSINSTRUMENT *FindInstrument(bool isDrum, uint32 bank = 0xFF, uint32 program = 0xFF, uint32 key = 0xFF, uint32 *pInsNo = nullptr) const;
bool FindAndExtract(CSoundFile &sndFile, const INSTRUMENTINDEX ins, const bool isDrum) const;
uint32 GetRegionFromKey(uint32 nIns, uint32 nKey) const;
bool ExtractWaveForm(uint32 nIns, uint32 nRgn, std::vector<uint8> &waveData, uint32 &length) const;

View File

@ -288,7 +288,7 @@ struct MixLoopState
#ifdef MPT_BUILD_DEBUG
{
SmpLength posDest = (nPos + nInc * (nSmpCount - 1)).GetUInt();
if (posDest < 0 || posDest > chn.nLength)
MPT_MAYBE_CONSTANT_IF(posDest < 0 || posDest > chn.nLength)
{
// We computed an invalid delta!
MPT_ASSERT_NOTREACHED();
@ -487,6 +487,17 @@ void CSoundFile::CreateStereoMix(int count)
{
// ProTracker compatibility: Instrument changes without a note do not happen instantly, but rather when the sample loop has finished playing.
// Test case: PTInstrSwap.mod, PTSwapNoLoop.mod
#ifdef MODPLUG_TRACKER
if(m_SamplePlayLengths != nullptr)
{
// Even if the sample was playing at zero volume, we need to retain its full length for correct sample swap timing
size_t smp = std::distance(static_cast<const ModSample *>(static_cast<std::decay<decltype(Samples)>::type>(Samples)), chn.pModSample);
if(smp < m_SamplePlayLengths->size())
{
(*m_SamplePlayLengths)[smp] = std::max((*m_SamplePlayLengths)[smp], std::min(chn.nLength, chn.position.GetUInt()));
}
}
#endif
const ModSample &smp = Samples[chn.nNewIns];
chn.pModSample = &smp;
chn.pCurrentSample = smp.samplev();

View File

@ -187,6 +187,8 @@ void ITCompression::CompressBlock(const typename Properties::sample_t *data, Smp
int8 ITCompression::GetWidthChangeSize(int8 w, bool is16)
{
MPT_ASSERT(w > 0 && static_cast<unsigned int>(w) <= std::size(ITWidthChangeSize));
// cppcheck false-positive
// cppcheck-suppress negativeIndex
int8 wcs = ITWidthChangeSize[w - 1];
if(w <= 6 && is16)
wcs++;

View File

@ -1034,27 +1034,27 @@ bool CSoundFile::ReadAMS2(FileReader &file, ModLoadingFlags loadFlags)
/////////////////////////////////////////////////////////////////////
// AMS Sample unpacking
void AMSUnpack(const int8 * const source, size_t sourceSize, void * const dest, const size_t destSize, char packCharacter)
void AMSUnpack(mpt::const_byte_span source, mpt::byte_span dest, int8 packCharacter)
{
std::vector<int8> tempBuf(destSize, 0);
size_t depackSize = destSize;
std::vector<int8> tempBuf(dest.size(), 0);
std::size_t depackSize = dest.size();
// Unpack Loop
{
const int8 *in = source;
const std::byte *in = source.data();
int8 *out = tempBuf.data();
size_t i = sourceSize, j = destSize;
size_t i = source.size(), j = dest.size();
while(i != 0 && j != 0)
{
int8 ch = *(in++);
int8 ch = mpt::byte_cast<int8>(*(in++));
if(--i != 0 && ch == packCharacter)
{
uint8 repCount = *(in++);
uint8 repCount = mpt::byte_cast<uint8>(*(in++));
repCount = static_cast<uint8>(std::min(static_cast<size_t>(repCount), j));
if(--i != 0 && repCount)
{
ch = *(in++);
ch = mpt::byte_cast<int8>(*(in++));
i--;
while(repCount-- != 0)
{
@ -1081,7 +1081,7 @@ void AMSUnpack(const int8 * const source, size_t sourceSize, void * const dest,
int8 *out = tempBuf.data();
uint16 bitcount = 0x80;
size_t k = 0;
uint8 *dst = static_cast<uint8 *>(dest);
uint8 *dst = mpt::byte_cast<uint8 *>(dest.data());
for(size_t i = 0; i < depackSize; i++)
{
uint8 al = *out++;
@ -1092,7 +1092,7 @@ void AMSUnpack(const int8 * const source, size_t sourceSize, void * const dest,
bl = ((bl | (bl << 8)) >> ((dh + 8 - count) & 7)) & 0xFF;
bitcount = ((bitcount | (bitcount << 8)) >> 1) & 0xFF;
dst[k++] |= bl;
if(k >= destSize)
if(k >= dest.size())
{
k = 0;
dh++;
@ -1105,16 +1105,16 @@ void AMSUnpack(const int8 * const source, size_t sourceSize, void * const dest,
// Delta Unpack
{
int8 old = 0;
int8 *out = static_cast<int8 *>(dest);
uint8 *out = mpt::byte_cast<uint8*>(dest.data());
for(size_t i = depackSize; i != 0; i--)
{
int pos = *reinterpret_cast<uint8 *>(out);
int pos = static_cast<uint8>(*out);
if(pos != 128 && (pos & 0x80) != 0)
{
pos = -(pos & 0x7F);
}
old -= static_cast<int8>(pos);
*(out++) = old;
*(out++) = static_cast<uint8>(old);
}
}
}

View File

@ -258,14 +258,16 @@ bool CSoundFile::ReadDSym(FileReader &file, ModLoadingFlags loadFlags)
const auto allowedCommands = file.ReadArray<uint8, 8>();
std::vector<std::byte> sequenceData;
std::vector<uint16le> sequence;
if(fileHeader.numOrders)
{
std::vector<std::byte> sequenceData;
const uint32 sequenceSize = fileHeader.numOrders * fileHeader.numChannels * 2u;
if(!ReadDSymChunk(file, sequenceData, sequenceSize))
return false;
FileReader sequenceChunk = FileReader(mpt::as_span(sequenceData));
sequenceChunk.ReadVector(sequence, sequenceData.size() / 2u);
}
const auto sequence = mpt::as_span(reinterpret_cast<uint16le *>(sequenceData.data()), sequenceData.size() / 2u);
std::vector<std::byte> trackData;
trackData.reserve(fileHeader.numTracks * 256u);

View File

@ -1317,15 +1317,15 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
musicChunk.ReadNullString(name);
m_szNames[smp] = name;
if(version >= 5)
{
musicChunk.ReadNullString(name);
sample.filename = name;
}
else
name.clear();
MO3Sample smpHeader;
if(!musicChunk.ReadStruct(smpHeader))
break;
smpHeader.ConvertToMPT(sample, m_nType, frequencyIsHertz);
sample.filename = name;
int16 sharedOggHeader = 0;
if(version >= 5 && (smpHeader.flags & MO3Sample::smpCompressionMask) == MO3Sample::smpSharedOgg)

View File

@ -1535,7 +1535,8 @@ bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
}
// Let's see if the file is too small (including some overhead for broken files like sll7.mod or ghostbus.mod)
if(file.BytesLeft() + 65536 < numPatterns * 64u * 4u * 4u + totalSampleLen)
std::size_t requiredRemainingDataSize = numPatterns * 64u * 4u * 4u + totalSampleLen;
if(!file.CanRead(requiredRemainingDataSize - std::min<std::size_t>(requiredRemainingDataSize, 65536u)))
return false;
if(loadFlags == onlyVerifyHeader)

View File

@ -325,12 +325,16 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
nonCompatTracker = true;
break;
case S3MFileHeader::trkOpenMPT:
if(fileHeader.cwtv != S3MFileHeader::trkGraoumfTracker)
{
uint32 mptVersion = (fileHeader.cwtv & S3MFileHeader::versionMask) << 16;
if(mptVersion >= 0x01'29'00'00)
mptVersion |= fileHeader.reserved2;
m_dwLastSavedWithVersion = Version(mptVersion);
madeWithTracker = U_("OpenMPT ") + mpt::ufmt::val(m_dwLastSavedWithVersion);
} else
{
madeWithTracker = U_("Graoumf Tracker");
}
break;
case S3MFileHeader::trkBeRoTracker:

View File

@ -31,12 +31,12 @@ void ModSample::Convert(MODTYPE fromType, MODTYPE toType)
nFineTune = 0;
// TransposeToFrequency assumes NTSC middle-C frequency like FT2, but we play MODs with PAL middle-C!
if(fromType == MOD_TYPE_MOD)
nC5Speed = Util::muldivr_unsigned(nC5Speed, 8272, 8363);
nC5Speed = Util::muldivr_unsigned(nC5Speed, 8287, 8363);
} else if((toType & (MOD_TYPE_MOD | MOD_TYPE_XM)) && (!(fromType & (MOD_TYPE_MOD | MOD_TYPE_XM))))
{
// FrequencyToTranspose assumes NTSC middle-C frequency like FT2, but we play MODs with PAL middle-C!
if(toType == MOD_TYPE_MOD)
nC5Speed = Util::muldivr_unsigned(nC5Speed, 8363, 8272);
nC5Speed = Util::muldivr_unsigned(nC5Speed, 8363, 8287);
FrequencyToTranspose();
}
@ -162,7 +162,7 @@ uint32 ModSample::GetSampleRate(const MODTYPE type) const
rate = nC5Speed;
// TransposeToFrequency assumes NTSC middle-C frequency like FT2, but we play MODs with PAL middle-C!
if(type == MOD_TYPE_MOD)
rate = Util::muldivr_unsigned(rate, 8272, 8363);
rate = Util::muldivr_unsigned(rate, 8287, 8363);
return (rate > 0) ? rate : 8363;
}

View File

@ -50,6 +50,7 @@ struct S3MFileHeader
trkIT2_07 = 0x3207,
trkIT2_14 = 0x3214,
trkBeRoTrackerOld = 0x4100, // Used from 2004 to 2012
trkGraoumfTracker = 0x5447,
trkCamoto = 0xCA00,
};

View File

@ -1140,6 +1140,18 @@ bool CSoundFile::ReadS3ISample(SAMPLEINDEX nSample, FileReader &file)
return false;
}
if(sampleHeader.sampleType >= S3MSampleHeader::typeAdMel)
{
if(SupportsOPL())
{
InitOPL();
} else
{
AddToLog(LogInformation, U_("OPL instruments are not supported by this format."));
return true;
}
}
DestroySampleThreadsafe(nSample);
ModSample &sample = Samples[nSample];
@ -1148,10 +1160,6 @@ bool CSoundFile::ReadS3ISample(SAMPLEINDEX nSample, FileReader &file)
if(sampleHeader.sampleType < S3MSampleHeader::typeAdMel)
sampleHeader.GetSampleFormat(false).ReadSample(sample, file);
else if(SupportsOPL())
InitOPL();
else
AddToLog(LogInformation, U_("OPL instruments are not supported by this format."));
sample.Convert(MOD_TYPE_S3M, GetType());
sample.PrecomputeLoops(*this, false);

View File

@ -179,7 +179,7 @@ size_t SampleIO::ReadSample(ModSample &sample, FileReader &file) const
LimitMax(sourceSize, mpt::saturate_cast<uint32>(packedDataView.size()));
bytesRead += sourceSize;
AMSUnpack(reinterpret_cast<const int8 *>(packedDataView.data()), packedDataView.size(), sample.samplev(), sample.GetSampleSizeInBytes(), packCharacter);
AMSUnpack(packedDataView.span(), mpt::as_span(sample.sampleb(), sample.GetSampleSizeInBytes()), packCharacter);
if(sample.uFlags[CHN_16BIT] && !mpt::endian_is_little())
{
auto p = sample.sample16();

View File

@ -544,6 +544,9 @@ enum PlayBehaviour
kApplyOffsetWithoutNote, // Offset commands even work when there's no note next to them (e.g. DMF, MDL, PLM formats)
kITPitchPanSeparation, // Pitch/Pan Separation can be overridden by panning commands (this also fixes a bug where any "special" notes affect PPS)
kImprecisePingPongLoops, // Use old (less precise) ping-pong overshoot calculation
kPluginIgnoreTonePortamento, // Use old tone portamento behaviour for plugins (XM: no plugin pitch slides with commands E1x/E2x/X1x/X2x)
kST3TonePortaWithAdlibNote, // Adlib note next to tone portamento is delayed until next row
kITResetFilterOnPortaSmpChange, // Filter is reset on portamento if sample is swapped
// Add new play behaviours here.

View File

@ -59,6 +59,37 @@ uint32 CSoundFile::CutOffToFrequency(uint32 nCutOff, int envModifier) const
}
// Update channels with instrument filter settings updated through tracker UI
void CSoundFile::UpdateInstrumentFilter(const ModInstrument *ins, bool updateMode, bool updateCutoff, bool updateResonance)
{
for(auto &chn : m_PlayState.Chn)
{
if(chn.pModInstrument != ins)
continue;
bool change = false;
if(updateMode && ins->filterMode != FilterMode::Unchanged && chn.nFilterMode != ins->filterMode)
{
chn.nFilterMode = ins->filterMode;
change = true;
}
if(updateCutoff)
{
chn.nCutOff = ins->IsCutoffEnabled() ? ins->GetCutoff() : 0x7F;
change |= (chn.nCutOff < 0x7F || chn.dwFlags[CHN_FILTER]);
}
if(updateResonance)
{
chn.nResonance = ins->IsResonanceEnabled() ? ins->GetResonance() : 0;
change |= (chn.nResonance > 0 || chn.dwFlags[CHN_FILTER]);
}
// If filter envelope is active, the filter will be updated in the next player tick anyway.
if(change && (!ins->PitchEnv.dwFlags[ENV_FILTER] || !IsEnvelopeProcessed(chn, ENV_PITCH)))
SetupChannelFilter(chn, false);
}
}
// Simple 2-poles resonant filter. Returns computed cutoff in range [0, 254] or -1 if filter is not applied.
int CSoundFile::SetupChannelFilter(ModChannel &chn, bool bReset, int envModifier) const
{
@ -82,10 +113,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.triggerNote)
if(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, FilterResetPatDelay.it
// Test cases: filter-reset.it, filter-reset-carry.it, filter-reset-envelope.it, filter-nna.it, FilterResetPatDelay.it, FilterPortaSmpChange.it, FilterPortaSmpChange-InsMode.it
chn.dwFlags.reset(CHN_FILTER);
}
return -1;

View File

@ -612,8 +612,17 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
if (tempo.GetInt()) chn.nOldTempo = static_cast<uint8>(tempo.GetInt()); else tempo.Set(chn.nOldTempo);
}
if (tempo.GetInt() >= 0x20) playState.m_nMusicTempo = tempo;
else
const auto &specs = GetModSpecifications();
if(tempo.GetInt() >= 0x20)
{
#if MPT_MSVC_BEFORE(2019, 0)
// Work-around for VS2017 /std:c++17 /permissive-
// which fails to find operator < for templated user types inside std::min.
playState.m_nMusicTempo.SetRaw(std::min(tempo.GetRaw(), specs.GetTempoMax().GetRaw()));
#else
playState.m_nMusicTempo = std::min(tempo, specs.GetTempoMax());
#endif
} else
{
// Tempo Slide
TEMPO tempoDiff((tempo.GetInt() & 0x0F) * nonRowTicks, 0);
@ -627,14 +636,14 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
else
playState.m_nMusicTempo.Set(0);
}
}
TEMPO tempoMin = GetModSpecifications().GetTempoMin(), tempoMax = GetModSpecifications().GetTempoMax();
if(m_playBehaviour[kTempoClamp]) // clamp tempo correctly in compatible mode
{
tempoMax.Set(255);
TEMPO tempoMin = specs.GetTempoMin(), tempoMax = specs.GetTempoMax();
if(m_playBehaviour[kTempoClamp]) // clamp tempo correctly in compatible mode
{
tempoMax.Set(255);
}
Limit(playState.m_nMusicTempo, tempoMin, tempoMax);
}
Limit(playState.m_nMusicTempo, tempoMin, tempoMax);
}
break;
@ -651,7 +660,7 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
break;
case 0xB0: // Pattern Loop
PatternLoop(playState, chn, param & 0x0F);
PatternLoop(playState, nChn, param & 0x0F);
break;
case 0xF0: // Active macro
@ -664,7 +673,7 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
switch(param & 0xF0)
{
case 0x60: // Pattern Loop
PatternLoop(playState, chn, param & 0x0F);
PatternLoop(playState, nChn, param & 0x0F);
break;
case 0xF0: // Active macro
@ -1107,7 +1116,7 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
case CMD_FINETUNE:
case CMD_FINETUNE_SMOOTH:
memory.RenderChannel(nChn, oldTickDuration); // Re-sync what we've got so far
SetFinetune(nChn, playState, false); // TODO should render each tick individually for CMD_FINETUNE_SMOOTH for higher sync accuracy
chn.microTuning = CalculateFinetuneTarget(playState.m_nPattern, playState.m_nRow, nChn); // TODO should render each tick individually for CMD_FINETUNE_SMOOTH for higher sync accuracy
break;
}
chn.isFirstTick = true;
@ -1349,6 +1358,10 @@ void CSoundFile::InstrumentChange(ModChannel &chn, uint32 instr, bool bPorta, bo
// but still uses the sample info from the old one (bug?)
returnAfterVolumeAdjust = true;
}
// IT compatbility: Reset filter if portamento results in sample change
// Test case: FilterPortaSmpChange.it, FilterPortaSmpChange-InsMode.it
if(m_playBehaviour[kITResetFilterOnPortaSmpChange] && !m_nInstruments)
chn.triggerNote = true;
}
// IT compatibility: A lone instrument number should only reset sample properties to those of the corresponding sample in instrument mode.
// C#5 01 ... <-- sample 1
@ -1951,6 +1964,7 @@ void CSoundFile::NoteChange(ModChannel &chn, int note, bool bPorta, bool bResetE
// Enable Ramping
if(!bPorta)
{
chn.triggerNote = true;
chn.nLeftVU = chn.nRightVU = 0xFF;
chn.dwFlags.reset(CHN_FILTER);
chn.dwFlags.set(CHN_FASTVOLRAMP);
@ -1972,35 +1986,6 @@ void CSoundFile::NoteChange(ModChannel &chn, int note, bool bPorta, bool bResetE
chn.nAutoVibPos = 0;
}
chn.rightVol = chn.leftVol = 0;
bool useFilter = !m_SongFlags[SONG_MPTFILTERMODE];
// Setup Initial Filter for this note
if(pIns)
{
if(pIns->IsResonanceEnabled())
{
chn.nResonance = pIns->GetResonance();
useFilter = true;
}
if(pIns->IsCutoffEnabled())
{
chn.nCutOff = pIns->GetCutoff();
useFilter = true;
}
if(useFilter && (pIns->filterMode != FilterMode::Unchanged))
{
chn.nFilterMode = pIns->filterMode;
}
} else
{
chn.nVolSwing = chn.nPanSwing = 0;
chn.nCutSwing = chn.nResSwing = 0;
}
if((chn.nCutOff < 0x7F || m_playBehaviour[kITFilterBehaviour]) && useFilter)
{
int cutoff = SetupChannelFilter(chn, true);
if(cutoff >= 0 && chn.dwFlags[CHN_ADLIB] && m_opl && channelHint != CHANNELINDEX_INVALID)
m_opl->Volume(channelHint, chn.nCutOff / 2u, true);
}
if(chn.dwFlags[CHN_ADLIB] && m_opl && channelHint != CHANNELINDEX_INVALID)
{
@ -2565,7 +2550,7 @@ bool CSoundFile::ProcessEffects()
{
chn.isFirstTick = tickCount == nStartTick;
}
chn.triggerNote = triggerNote;
chn.triggerNote = false;
// FT2 compatibility: Note + portamento + note delay = no portamento
// Test case: PortaDelay.xm
@ -3359,13 +3344,7 @@ bool CSoundFile::ProcessEffects()
case CMD_FINETUNE:
case CMD_FINETUNE_SMOOTH:
if(m_SongFlags[SONG_FIRSTTICK] || cmd == CMD_FINETUNE_SMOOTH)
{
SetFinetune(nChn, m_PlayState, cmd == CMD_FINETUNE_SMOOTH);
#ifndef NO_PLUGINS
if(IMixPlugin *plugin = GetChannelInstrumentPlugin(m_PlayState.Chn[nChn]); plugin != nullptr)
plugin->MidiPitchBendRaw(chn.GetMIDIPitchBend(), nChn);
#endif // NO_PLUGINS
}
SetFinetune(m_PlayState.m_nPattern, m_PlayState.m_nRow, nChn, m_PlayState, cmd == CMD_FINETUNE_SMOOTH);
break;
// Set Channel Global Volume
@ -3943,10 +3922,24 @@ void CSoundFile::ExtraFinePortamentoDown(ModChannel &chn, ModCommand::PARAM para
}
void CSoundFile::SetFinetune(CHANNELINDEX channel, PlayState &playState, bool isSmooth) const
// Process finetune command from pattern editor
void CSoundFile::ProcessFinetune(PATTERNINDEX pattern, ROWINDEX row, CHANNELINDEX channel, bool isSmooth)
{
SetFinetune(pattern, row, channel, m_PlayState, isSmooth);
// Also apply to notes played via CModDoc::PlayNote
for(CHANNELINDEX chn = GetNumChannels(); chn < MAX_CHANNELS; chn++)
{
auto &modChn = m_PlayState.Chn[chn];
if(modChn.nMasterChn == channel + 1 && modChn.isPreviewNote && !modChn.dwFlags[CHN_KEYOFF])
modChn.microTuning = m_PlayState.Chn[channel].microTuning;
}
}
void CSoundFile::SetFinetune(PATTERNINDEX pattern, ROWINDEX row, CHANNELINDEX channel, PlayState &playState, bool isSmooth) const
{
ModChannel &chn = playState.Chn[channel];
int16 newTuning = mpt::saturate_cast<int16>(static_cast<int32>(CalculateXParam(playState.m_nPattern, playState.m_nRow, channel, nullptr)) - 0x8000);
int16 newTuning = CalculateFinetuneTarget(pattern, row, channel);
if(isSmooth)
{
@ -3958,6 +3951,17 @@ void CSoundFile::SetFinetune(CHANNELINDEX channel, PlayState &playState, bool is
}
}
chn.microTuning = newTuning;
#ifndef NO_PLUGINS
if(IMixPlugin *plugin = GetChannelInstrumentPlugin(chn); plugin != nullptr)
plugin->MidiPitchBendRaw(chn.GetMIDIPitchBend(), channel);
#endif // NO_PLUGINS
}
int16 CSoundFile::CalculateFinetuneTarget(PATTERNINDEX pattern, ROWINDEX row, CHANNELINDEX channel) const
{
return mpt::saturate_cast<int16>(static_cast<int32>(CalculateXParam(pattern, row, channel, nullptr)) - 0x8000);
}
@ -4494,7 +4498,7 @@ void CSoundFile::ExtendedMODCommands(CHANNELINDEX nChn, ModCommand::PARAM param)
// E6x: Pattern Loop
case 0x60:
if(m_SongFlags[SONG_FIRSTTICK])
PatternLoop(m_PlayState, chn, param & 0x0F);
PatternLoop(m_PlayState, nChn, param & 0x0F);
break;
// E7x: Set Tremolo WaveForm
case 0x70: chn.nTremoloType = param & 0x07; break;
@ -4679,7 +4683,7 @@ void CSoundFile::ExtendedS3MCommands(CHANNELINDEX nChn, ModCommand::PARAM param)
// SBx: Pattern Loop
case 0xB0:
if(m_SongFlags[SONG_FIRSTTICK])
PatternLoop(m_PlayState, chn, param & 0x0F);
PatternLoop(m_PlayState, nChn, param & 0x0F);
break;
// SCx: Note Cut
case 0xC0:
@ -5831,11 +5835,14 @@ void CSoundFile::SetTempo(TEMPO param, bool setFromUI)
}
void CSoundFile::PatternLoop(PlayState &state, ModChannel &chn, ModCommand::PARAM param) const
void CSoundFile::PatternLoop(PlayState &state, CHANNELINDEX nChn, ModCommand::PARAM param) const
{
if(m_playBehaviour[kST3NoMutedChannels] && chn.dwFlags[CHN_MUTE | CHN_SYNCMUTE])
if(m_playBehaviour[kST3NoMutedChannels] && state.Chn[nChn].dwFlags[CHN_MUTE | CHN_SYNCMUTE])
return; // not even effects are processed on muted S3M channels
// ST3 doesn't have per-channel pattern loop memory.
ModChannel &chn = state.Chn[(GetType() == MOD_TYPE_S3M) ? 0 : nChn];
if(!param)
{
// Loop Start
@ -5890,17 +5897,6 @@ void CSoundFile::PatternLoop(PlayState &state, ModChannel &chn, ModCommand::PARA
if(m_playBehaviour[kITPatternLoopWithJumps])
state.m_posJump = ORDERINDEX_INVALID;
}
if(GetType() == MOD_TYPE_S3M)
{
// ST3 doesn't have per-channel pattern loop memory, so spam all changes to other channels as well.
for(CHANNELINDEX i = 0; i < GetNumChannels(); i++)
{
state.Chn[i].nPatternLoop = chn.nPatternLoop;
state.Chn[i].nPatternLoopCount = chn.nPatternLoopCount;
}
}
}

View File

@ -1074,6 +1074,7 @@ PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type)
playBehaviour.set(kITDoNotOverrideChannelPan);
playBehaviour.set(kITDCTBehaviour);
playBehaviour.set(kITPitchPanSeparation);
playBehaviour.set(kITResetFilterOnPortaSmpChange);
if(type == MOD_TYPE_MPT)
{
playBehaviour.set(kOPLFlexibleNoteOff);

View File

@ -77,7 +77,7 @@ bool ReadInstrumentHeaderField(ModInstrument * input, uint32 fcode, uint16 fsize
// Sample decompression routines in format-specific source files
void AMSUnpack(const int8 * const source, size_t sourceSize, void * const dest, const size_t destSize, char packCharacter);
void AMSUnpack(mpt::const_byte_span source, mpt::byte_span dest, int8 packCharacter);
uintptr_t DMFUnpack(FileReader &file, uint8 *psample, uint32 maxlen);
@ -998,6 +998,7 @@ public:
bool IsRenderingToDisc() const { return m_bIsRendering; }
void PrecomputeSampleLoops(bool updateChannels = false);
void UpdateInstrumentFilter(const ModInstrument *ins, bool updateMode, bool updateCutoff, bool updateResonance);
public:
// Mixer Config
@ -1031,6 +1032,8 @@ public:
void ProcessRamping(ModChannel &chn) const;
void ProcessFinetune(PATTERNINDEX pattern, ROWINDEX row, CHANNELINDEX channel, bool isSmooth);
protected:
// Global variable initializer for loader functions
void SetType(MODTYPE type);
@ -1084,7 +1087,8 @@ protected:
void PortamentoMPT(ModChannel &chn, int);
void PortamentoFineMPT(ModChannel &chn, int);
void PortamentoExtraFineMPT(ModChannel &chn, int);
void SetFinetune(CHANNELINDEX channel, PlayState &playState, bool isSmooth) const;
void SetFinetune(PATTERNINDEX pattern, ROWINDEX row, CHANNELINDEX channel, PlayState &playState, bool isSmooth) const;
int16 CalculateFinetuneTarget(PATTERNINDEX pattern, ROWINDEX row, CHANNELINDEX channel) const;
void NoteSlide(ModChannel &chn, uint32 param, bool slideUp, bool retrig) const;
std::pair<uint16, bool> GetVolCmdTonePorta(const ModCommand &m, uint32 startTick) const;
void TonePortamento(ModChannel &chn, uint16 param) const;
@ -1105,7 +1109,7 @@ protected:
void DigiBoosterSampleReverse(ModChannel &chn, ModCommand::PARAM param) const;
void HandleDigiSamplePlayDirection(PlayState &state, CHANNELINDEX chn) const;
void NoteCut(CHANNELINDEX nChn, uint32 nTick, bool cutSample);
void PatternLoop(PlayState &state, ModChannel &chn, ModCommand::PARAM param) const;
void PatternLoop(PlayState &state, CHANNELINDEX nChn, ModCommand::PARAM param) const;
bool HandleNextRow(PlayState &state, const ModSequence &order, bool honorPatternLoop) const;
void ExtendedMODCommands(CHANNELINDEX nChn, ModCommand::PARAM param);
void ExtendedS3MCommands(CHANNELINDEX nChn, ModCommand::PARAM param);

View File

@ -2250,20 +2250,55 @@ bool CSoundFile::ReadNote()
chn.nRealPan = 128;
}
// Setup Initial Filter for this note
int cutoff = -1;
if(chn.triggerNote)
{
bool useFilter = !m_SongFlags[SONG_MPTFILTERMODE];
if(pIns)
{
if(pIns->IsResonanceEnabled())
{
chn.nResonance = pIns->GetResonance();
useFilter = true;
}
if(pIns->IsCutoffEnabled())
{
chn.nCutOff = pIns->GetCutoff();
useFilter = true;
}
if(useFilter && (pIns->filterMode != FilterMode::Unchanged))
{
chn.nFilterMode = pIns->filterMode;
}
} else
{
chn.nVolSwing = chn.nPanSwing = 0;
chn.nCutSwing = chn.nResSwing = 0;
}
if((chn.nCutOff < 0x7F || m_playBehaviour[kITFilterBehaviour]) && useFilter)
{
cutoff = SetupChannelFilter(chn, true);
if(cutoff >= 0)
cutoff = chn.nCutOff / 2u;
}
}
// Now that all relevant envelopes etc. have been processed, we can parse the MIDI macro data.
ProcessMacroOnChannel(nChn);
// After MIDI macros have been processed, we can also process the pitch / filter envelope and other pitch-related things.
if(samplePlaying)
{
int cutoff = ProcessPitchFilterEnvelope(chn, period);
if(cutoff >= 0 && chn.dwFlags[CHN_ADLIB] && m_opl)
{
// Cutoff doubles as modulator intensity for FM instruments
m_opl->Volume(nChn, static_cast<uint8>(cutoff / 4), true);
}
int envCutoff = ProcessPitchFilterEnvelope(chn, period);
if(envCutoff >= 0)
cutoff = envCutoff / 4;
}
// Cutoff doubles as modulator intensity for FM instruments
if(cutoff >= 0 && chn.dwFlags[CHN_ADLIB] && m_opl)
m_opl->Volume(nChn, static_cast<uint8>(cutoff), true);
if(chn.rowCommand.volcmd == VOLCMD_VIBRATODEPTH &&
(chn.rowCommand.command == CMD_VIBRATO || chn.rowCommand.command == CMD_VIBRATOVOL || chn.rowCommand.command == CMD_FINEVIBRATO))
{
@ -2509,6 +2544,7 @@ bool CSoundFile::ReadNote()
}
chn.dwOldFlags = chn.dwFlags;
chn.triggerNote = false; // For SONG_PAUSED mode
}
// If there are more channels being mixed than allowed, order them by volume and discard the most quiet ones

View File

@ -577,6 +577,7 @@ void CSoundFile::UpgradeModule()
{ kITPatternLoopWithJumps, MPT_V("1.29.00.32") },
{ kITDCTBehaviour, MPT_V("1.29.00.57") },
{ kITPitchPanSeparation, MPT_V("1.30.00.53") },
{ kITResetFilterOnPortaSmpChange, MPT_V("1.30.08.02") },
};
for(const auto &b : behaviours)

View File

@ -79,7 +79,7 @@ void ModCommand::ExtendedMODtoS3MEffect()
case 0x20: command = CMD_PORTAMENTODOWN; param |= 0xF0; break;
case 0x30: param = (param & 0x0F) | 0x10; break;
case 0x40: param = (param & 0x03) | 0x30; break;
case 0x50: param = (param & 0x0F) | 0x20; break;
case 0x50: param = (param ^ 0x58) | 0x20; break;
case 0x60: param = (param & 0x0F) | 0xB0; break;
case 0x70: param = (param & 0x03) | 0x40; break;
case 0x90: command = CMD_RETRIG; param = (param & 0x0F); break;
@ -102,7 +102,7 @@ void ModCommand::ExtendedS3MtoMODEffect()
switch(param & 0xF0)
{
case 0x10: param = (param & 0x0F) | 0x30; break;
case 0x20: param = (param & 0x0F) | 0x50; break;
case 0x20: param = (param ^ 0x28) | 0x50; break;
case 0x30: param = (param & 0x0F) | 0x40; break;
case 0x40: param = (param & 0x0F) | 0x70; break;
case 0x50: command = CMD_XFINEPORTAUPDOWN; break; // map to unused X5x

View File

@ -38,7 +38,7 @@ void SymMODEcho::Process(float* pOutL, float* pOutR, uint32 numFrames)
float *outL = m_mixBuffer.GetOutputBuffer(0), *outR = m_mixBuffer.GetOutputBuffer(1);
const uint32 delayTime = m_SndFile.m_PlayState.m_nSamplesPerTick * m_chunk.param[kEchoDelay];
// SymMODs don't have a variable tempo so the tick duration should never change... but if someone loads a module into an MPTM file we have to account for this.
// SymMODs don't have a variable tempo so the tick duration should never change... but if someone loads an instance into an MPTM file we have to account for this.
if(m_delayLine.size() < delayTime * 2)
m_delayLine.resize(delayTime * 2);

View File

@ -186,7 +186,7 @@ void Distortion::RecalculateDistortionParams()
// Distortion
float edge = 2.0f + m_param[kDistEdge] * 29.0f;
m_edge = static_cast<uint8>(edge); // 2...31 shifted bits
m_shift = mpt::bit_width(m_edge);
m_shift = static_cast<uint8>(mpt::bit_width(m_edge));
static constexpr float LogNorm[32] =
{

View File

@ -1,4 +1,4 @@
Copyright (c) 2004-2022, OpenMPT Project Developers and Contributors
Copyright (c) 2004-2023, OpenMPT Project Developers and Contributors
Copyright (c) 1997-2003, Olivier Lapicque
All rights reserved.

View File

@ -6,8 +6,8 @@
#include "mpt/base/detect_compiler.hpp"
#include "mpt/base/macros.hpp"
#include "mpt/base/namespace.hpp"
#include "mpt/base/saturate_cast.hpp"
#include <algorithm>

View File

@ -168,6 +168,12 @@ public:
T & operator*() {
return *m_value;
}
const T * operator->() const {
return m_value.get();
}
T * operator->() {
return m_value.get();
}
};

View File

@ -263,10 +263,10 @@ constexpr T bit_floor(T x) noexcept {
}
template <typename T>
constexpr T bit_width(T x) noexcept {
constexpr int bit_width(T x) noexcept {
static_assert(std::numeric_limits<T>::is_integer);
static_assert(std::is_unsigned<T>::value);
T result = 0;
int result = 0;
while (x > 0) {
x >>= 1;
result += 1;
@ -371,7 +371,7 @@ constexpr T rotr(T x, int s) noexcept {
template <typename T>
constexpr int lower_bound_entropy_bits(T x_) {
typename std::make_unsigned<T>::type x = static_cast<typename std::make_unsigned<T>::type>(x_);
return mpt::bit_width(x) == static_cast<typename std::make_unsigned<T>::type>(mpt::popcount(x)) ? mpt::bit_width(x) : mpt::bit_width(x) - 1;
return (static_cast<unsigned int>(mpt::bit_width(x)) == static_cast<typename std::make_unsigned<T>::type>(mpt::popcount(x))) ? mpt::bit_width(x) : mpt::bit_width(x) - 1;
}

View File

@ -50,7 +50,9 @@
#elif defined(_MSC_VER)
#define MPT_COMPILER_MSVC 1
#if (_MSC_VER >= 1933)
#if (_MSC_VER >= 1934)
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 4)
#elif (_MSC_VER >= 1933)
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 3)
#elif (_MSC_VER >= 1932)
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 2)

View File

@ -108,21 +108,21 @@ MPT_TEST_GROUP_INLINE("mpt/base/bit")
MPT_TEST_EXPECT_EQUAL(mpt::bit_floor(uint32(0xfffffffeu)), 0x80000000u);
MPT_TEST_EXPECT_EQUAL(mpt::bit_floor(uint32(0xffffffffu)), 0x80000000u);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(0u), 0u);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(1u), 1u);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(2u), 2u);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(3u), 2u);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(4u), 3u);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(5u), 3u);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(6u), 3u);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(7u), 3u);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(8u), 4u);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(9u), 4u);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(uint32(0x7fffffffu)), 31u);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(uint32(0x80000000u)), 32u);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(uint32(0x80000001u)), 32u);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(uint32(0xfffffffeu)), 32u);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(uint32(0xffffffffu)), 32u);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(0u), 0);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(1u), 1);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(2u), 2);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(3u), 2);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(4u), 3);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(5u), 3);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(6u), 3);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(7u), 3);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(8u), 4);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(9u), 4);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(uint32(0x7fffffffu)), 31);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(uint32(0x80000000u)), 32);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(uint32(0x80000001u)), 32);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(uint32(0xfffffffeu)), 32);
MPT_TEST_EXPECT_EQUAL(mpt::bit_width(uint32(0xffffffffu)), 32);
MPT_TEST_EXPECT_EQUAL(mpt::countl_one(uint8(0b00000000)), 0);
MPT_TEST_EXPECT_EQUAL(mpt::countl_one(uint8(0b00000001)), 0);

View File

@ -5,6 +5,7 @@
#include "mpt/base/alloc.hpp"
#include "mpt/base/detect_compiler.hpp"
#include "mpt/base/memory.hpp"
#include "mpt/base/namespace.hpp"

View File

@ -10,8 +10,6 @@
#include "mpt/format/default_integer.hpp"
#include "mpt/format/default_string.hpp"
#include <type_traits>
namespace mpt {

View File

@ -14,6 +14,7 @@
#include "mpt/test/test_macros.hpp"
#include <limits>
#include <string>

View File

@ -6,6 +6,7 @@
#include "mpt/base/integer.hpp"
#include "mpt/base/memory.hpp"
#include "mpt/base/namespace.hpp"
#include <cstddef>

View File

@ -8,6 +8,7 @@
#include "mpt/base/macros.hpp"
#include "mpt/base/memory.hpp"
#include "mpt/base/namespace.hpp"
#include "mpt/base/saturate_cast.hpp"
#include "mpt/base/utility.hpp"
#include "mpt/io/base.hpp"

View File

@ -5,6 +5,7 @@
#include "mpt/base/alloc.hpp"
#include "mpt/base/integer.hpp"
#include "mpt/base/namespace.hpp"
#include "mpt/base/utility.hpp"
@ -354,7 +355,7 @@ MPT_TEST_GROUP_INLINE("mpt/io")
// Run-time in case some weird compiler gets confused by our templates
// and only writes the first array element.
std::ostringstream f;
uint16be data[2];
mpt::uint16be data[2];
mpt::reset(data);
data[0] = 0x1234;
data[1] = 0x5678;
@ -363,7 +364,7 @@ MPT_TEST_GROUP_INLINE("mpt/io")
}
{
std::ostringstream f;
std::vector<int16be> data;
std::vector<mpt::int16be> data;
data.resize(3);
data[0] = 0x1234;
data[1] = 0x5678;
@ -373,7 +374,7 @@ MPT_TEST_GROUP_INLINE("mpt/io")
}
{
std::ostringstream f;
int16be data[3];
mpt::int16be data[3];
mpt::reset(data);
data[0] = 0x1234;
data[1] = 0x5678;

View File

@ -130,7 +130,7 @@ public:
streamPos = position;
return true;
}
if (position <= DataContainer().GetLength()) {
if (DataContainer().CanRead(0, position)) {
streamPos = position;
return true;
} else {
@ -212,8 +212,7 @@ public:
protected:
FileCursor CreateChunk(pos_type position, pos_type length) const {
pos_type readableLength = DataContainer().GetReadableLength(position, length);
if (readableLength == 0)
{
if (readableLength == 0) {
return FileCursor();
}
return FileCursor(CreateChunkImpl(SharedDataContainer(), position, std::min(length, DataContainer().GetLength() - position)));

View File

@ -43,7 +43,7 @@ public:
virtual pos_type GetLength() const = 0;
virtual mpt::byte_span Read(pos_type pos, mpt::byte_span dst) const = 0;
virtual bool CanRead(pos_type pos, std::size_t length) const {
virtual bool CanRead(pos_type pos, pos_type length) const {
pos_type dataLength = GetLength();
if ((pos == dataLength) && (length == 0)) {
return true;
@ -54,7 +54,7 @@ public:
return length <= dataLength - pos;
}
virtual std::size_t GetReadableLength(pos_type pos, std::size_t length) const {
virtual pos_type GetReadableLength(pos_type pos, pos_type length) const {
pos_type dataLength = GetLength();
if (pos >= dataLength) {
return 0;

View File

@ -88,7 +88,7 @@ public:
}
return data->Read(dataOffset + pos, dst.first(std::min(dst.size(), dataLength - pos)));
}
bool CanRead(pos_type pos, std::size_t length) const override {
bool CanRead(pos_type pos, pos_type length) const override {
if ((pos == dataLength) && (length == 0)) {
return true;
}
@ -97,7 +97,7 @@ public:
}
return (length <= dataLength - pos);
}
pos_type GetReadableLength(pos_type pos, std::size_t length) const override {
pos_type GetReadableLength(pos_type pos, pos_type length) const override {
if (pos >= dataLength) {
return 0;
}

View File

@ -5,8 +5,10 @@
#include "mpt/base/alloc.hpp"
#include "mpt/base/memory.hpp"
#include "mpt/base/namespace.hpp"
#include "mpt/base/span.hpp"
#include "mpt/io_read/filedata.hpp"
#include <algorithm>

View File

@ -136,7 +136,7 @@ public:
return dst.subspan(0, cache_avail);
}
bool CanRead(pos_type pos, std::size_t length) const override {
bool CanRead(pos_type pos, pos_type length) const override {
CacheStreamUpTo(pos, length);
if ((pos == IFileData::pos_type(cachesize)) && (length == 0)) {
return true;
@ -147,7 +147,7 @@ public:
return length <= IFileData::pos_type(cachesize) - pos;
}
std::size_t GetReadableLength(pos_type pos, std::size_t length) const override {
pos_type GetReadableLength(pos_type pos, pos_type length) const override {
CacheStreamUpTo(pos, length);
if (pos >= cachesize) {
return 0;

View File

@ -69,7 +69,7 @@ public:
return dst.first(avail);
}
bool CanRead(pos_type pos, std::size_t length) const override {
bool CanRead(pos_type pos, pos_type length) const override {
if ((pos == streamLength) && (length == 0)) {
return true;
}
@ -79,7 +79,7 @@ public:
return (length <= streamLength - pos);
}
std::size_t GetReadableLength(pos_type pos, std::size_t length) const override {
pos_type GetReadableLength(pos_type pos, pos_type length) const override {
if (pos >= streamLength) {
return 0;
}

View File

@ -8,6 +8,7 @@
#include "mpt/base/memory.hpp"
#include "mpt/base/namespace.hpp"
#include "mpt/base/integer.hpp"
#include "mpt/base/span.hpp"
#include "mpt/io/base.hpp"
#include <cstddef>

View File

@ -111,6 +111,12 @@ public:
return Version();
}
static constexpr Version AnyWindows() noexcept {
Version result = Version();
result.m_SystemIsWindows = true;
return result;
}
constexpr Version(mpt::osinfo::windows::Version::System system, mpt::osinfo::windows::Version::ServicePack servicePack, mpt::osinfo::windows::Version::Build build, mpt::osinfo::windows::Version::TypeId type) noexcept
: m_SystemIsWindows(true)
, m_System(system)
@ -125,13 +131,17 @@ public:
static mpt::osinfo::windows::Version FromSDK() noexcept {
// Initialize to used SDK version
#if defined(NTDDI_VERSION)
#if NTDDI_VERSION >= 0x0A00000B // NTDDI_WIN10_CO Win11
#if NTDDI_VERSION >= 0x0A00000C // NTDDI_WIN10_NI Win11 22H2
return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 22621, 0);
#elif NTDDI_VERSION >= 0x0A00000B // NTDDI_WIN10_CO Win11 21H2
return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 22000, 0);
//#elif // 22H2
// return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19045, 0);
#elif NTDDI_VERSION >= 0x0A00000A // NTDDI_WIN10_FE 21H2
return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19044, 0);
//#elif // NTDDI_WIN10_FE 21H1
//#elif // 21H1
// return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19043, 0);
//#elif // NTDDI_WIN10_FE 20H2
//#elif // 20H2
// return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19042, 0);
#elif NTDDI_VERSION >= 0x0A000009 // NTDDI_WIN10_MN 2004/20H1
return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19041, 0);

View File

@ -51,7 +51,13 @@ inline T ConvertStringTo(const Tstring & str) {
std::basic_istringstream<typename decltype(mpt::parse_as_internal_string_type(mpt::as_string(str)))::value_type> stream(mpt::parse_as_internal_string_type(mpt::as_string(str)));
stream.imbue(std::locale::classic());
T value;
if constexpr (std::is_same<T, signed char>::value) {
if constexpr (std::is_same<T, bool>::value) {
int tmp;
if (!(stream >> tmp)) {
return T{};
}
value = tmp ? true : false;
} else if constexpr (std::is_same<T, signed char>::value) {
signed int tmp;
if (!(stream >> tmp)) {
return T{};

View File

@ -35,6 +35,13 @@ MPT_TEST_GROUP_INLINE("mpt/parse")
#pragma clang diagnostic pop
#endif
{
MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo<bool>("1"), true);
MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo<bool>("0"), false);
MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo<bool>("2"), true);
MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo<bool>("-0"), false);
MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo<bool>("-1"), true);
MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo<uint32>("586"), 586u);
MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo<uint32>("586"), 586u);
MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo<uint32>("2147483647"), (uint32)std::numeric_limits<int32>::max());
MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo<uint32>("4294967295"), std::numeric_limits<uint32>::max());

View File

@ -7,6 +7,7 @@
#include "mpt/base/detect.hpp"
#include "mpt/base/namespace.hpp"
#include "mpt/base/saturate_cast.hpp"
#include "mpt/detect/mfc.hpp"
#include "mpt/string/types.hpp"

View File

@ -8,6 +8,7 @@
#include "mpt/base/detect.hpp"
#include "mpt/base/namespace.hpp"
#include "mpt/detect/mfc.hpp"
#include "mpt/string/types.hpp"
#include <string>
#include <vector>

View File

@ -7,11 +7,14 @@
#include "mpt/base/detect.hpp"
#include "mpt/base/namespace.hpp"
#include "mpt/string/types.hpp"
#include "mpt/string_transcode/macros.hpp"
#include "mpt/string_transcode/transcode.hpp"
#include "mpt/test/test.hpp"
#include "mpt/test/test_macros.hpp"
#include <string>
namespace mpt {

View File

@ -260,7 +260,7 @@ public:
}
return mpt::UUID::UUIDFromWin32(uuid);
#else
return RFC4122Random(rng);
return mpt::UUID::RFC4122Random(rng);
#endif
}
// Create a UUID that contains local, traceable information.

View File

@ -35,11 +35,11 @@ public:
{
if constexpr(targetbits == 0)
{
MPT_UNREFERENCED_PARAMETER(rng);
MPT_UNUSED(rng);
return sample;
} else if constexpr(targetbits + MixSampleIntTraits::mix_headroom_bits + 1 >= 32)
{
MPT_UNREFERENCED_PARAMETER(rng);
MPT_UNUSED(rng);
return sample;
} else
{

View File

@ -38,7 +38,7 @@ public:
{
if constexpr(targetbits == 0)
{
MPT_UNREFERENCED_PARAMETER(prng);
MPT_UNUSED(prng);
return sample;
} else
{
@ -46,7 +46,7 @@ public:
constexpr int rshift = (32 - targetbits) - MixSampleIntTraits::mix_headroom_bits;
if constexpr(rshift <= 1)
{
MPT_UNREFERENCED_PARAMETER(prng);
MPT_UNUSED(prng);
// nothing to dither
return sample;
} else

View File

@ -653,6 +653,12 @@ static MPT_NOINLINE void TestStringFormatting()
VERIFY_EQUAL(mpt::cfmt::center(4, CString(_T("a"))), CString(_T(" a ")));
#endif // MPT_WITH_MFC
VERIFY_EQUAL(ConvertStrTo<bool>("1"), true);
VERIFY_EQUAL(ConvertStrTo<bool>("0"), false);
VERIFY_EQUAL(ConvertStrTo<bool>("2"), true);
VERIFY_EQUAL(ConvertStrTo<bool>("-0"), false);
VERIFY_EQUAL(ConvertStrTo<bool>("-1"), true);
VERIFY_EQUAL(ConvertStrTo<uint32>("586"), 586u);
VERIFY_EQUAL(ConvertStrTo<uint32>("2147483647"), (uint32)int32_max);
VERIFY_EQUAL(ConvertStrTo<uint32>("4294967295"), uint32_max);
@ -3534,35 +3540,29 @@ static MPT_NOINLINE void TestStringIO()
static MPT_NOINLINE void TestSampleConversion()
{
std::vector<uint8> sourceBufContainer(65536 * 4);
std::vector<uint8> targetBufContainer(65536 * 6);
uint8 *sourceBuf = &(sourceBufContainer[0]);
void *targetBuf = &(targetBufContainer[0]);
// Signed 8-Bit Integer PCM
// Unsigned 8-Bit Integer PCM
// Delta 8-Bit Integer PCM
{
uint8 *source8 = sourceBuf;
for(size_t i = 0; i < 256; i++)
std::vector<std::byte> source8(256);
for(std::size_t i = 0; i < 256; i++)
{
source8[i] = static_cast<uint8>(i);
source8[i] = mpt::byte_cast<std::byte>(static_cast<uint8>(i));
}
int8 *signed8 = static_cast<int8 *>(targetBuf);
uint8 *unsigned8 = static_cast<uint8 *>(targetBuf) + 256;
int8 *delta8 = static_cast<int8 *>(targetBuf) + 512;
std::vector<int8> signed8(256);
std::vector<int8> unsigned8(256);
std::vector<int8> delta8(256);
int8 delta = 0;
CopySample<SC::DecodeInt8>(signed8, 256, 1, mpt::byte_cast<const std::byte *>(source8), 256, 1);
CopySample<SC::DecodeUint8>(reinterpret_cast<int8 *>(unsigned8), 256, 1, mpt::byte_cast<const std::byte *>(source8), 256, 1);
CopySample<SC::DecodeInt8Delta>(delta8, 256, 1, mpt::byte_cast<const std::byte *>(source8), 256, 1);
CopySample<SC::DecodeInt8>(signed8.data(), 256, 1, source8.data(), 256, 1);
CopySample<SC::DecodeUint8>(unsigned8.data(), 256, 1, source8.data(), 256, 1);
CopySample<SC::DecodeInt8Delta>(delta8.data(), 256, 1, source8.data(), 256, 1);
for(size_t i = 0; i < 256; i++)
for(std::size_t i = 0; i < 256; i++)
{
delta += static_cast<int8>(i);
VERIFY_EQUAL_QUIET_NONCONT(signed8[i], static_cast<int8>(i));
VERIFY_EQUAL_QUIET_NONCONT(unsigned8[i], static_cast<uint8>(i + 0x80u));
VERIFY_EQUAL_QUIET_NONCONT(unsigned8[i], static_cast<int8>(static_cast<int>(i) - 0x80));
VERIFY_EQUAL_QUIET_NONCONT(delta8[i], static_cast<int8>(delta));
}
}
@ -3573,47 +3573,47 @@ static MPT_NOINLINE void TestSampleConversion()
{
// Little Endian
uint8 *source16 = sourceBuf;
for(size_t i = 0; i < 65536; i++)
std::vector<std::byte> source16(65536 * 2);
for(std::size_t i = 0; i < 65536; i++)
{
source16[i * 2 + 0] = static_cast<uint8>(i & 0xFF);
source16[i * 2 + 1] = static_cast<uint8>(i >> 8);
source16[i * 2 + 0] = mpt::byte_cast<std::byte>(static_cast<uint8>(i & 0xFF));
source16[i * 2 + 1] = mpt::byte_cast<std::byte>(static_cast<uint8>(i >> 8));
}
int16 *signed16 = static_cast<int16 *>(targetBuf);
uint16 *unsigned16 = static_cast<uint16 *>(targetBuf) + 65536;
int16 *delta16 = static_cast<int16 *>(targetBuf) + 65536 * 2;
std::vector<int16> signed16(65536);
std::vector<int16> unsigned16(65536);
std::vector<int16> delta16(65536);
int16 delta = 0;
CopySample<SC::DecodeInt16<0, littleEndian16> >(signed16, 65536, 1, mpt::byte_cast<const std::byte *>(source16), 65536 * 2, 1);
CopySample<SC::DecodeInt16<0x8000u, littleEndian16> >(reinterpret_cast<int16*>(unsigned16), 65536, 1, mpt::byte_cast<const std::byte *>(source16), 65536 * 2, 1);
CopySample<SC::DecodeInt16Delta<littleEndian16> >(delta16, 65536, 1, mpt::byte_cast<const std::byte *>(source16), 65536 * 2, 1);
CopySample<SC::DecodeInt16<0, littleEndian16> >(signed16.data(), 65536, 1, source16.data(), 65536 * 2, 1);
CopySample<SC::DecodeInt16<0x8000u, littleEndian16> >(unsigned16.data(), 65536, 1, source16.data(), 65536 * 2, 1);
CopySample<SC::DecodeInt16Delta<littleEndian16> >(delta16.data(), 65536, 1, source16.data(), 65536 * 2, 1);
for(size_t i = 0; i < 65536; i++)
for(std::size_t i = 0; i < 65536; i++)
{
delta += static_cast<int16>(i);
VERIFY_EQUAL_QUIET_NONCONT(signed16[i], static_cast<int16>(i));
VERIFY_EQUAL_QUIET_NONCONT(unsigned16[i], static_cast<uint16>(i + 0x8000u));
VERIFY_EQUAL_QUIET_NONCONT(unsigned16[i], static_cast<int16>(static_cast<int>(i) - 0x8000));
VERIFY_EQUAL_QUIET_NONCONT(delta16[i], static_cast<int16>(delta));
}
// Big Endian
for(size_t i = 0; i < 65536; i++)
for(std::size_t i = 0; i < 65536; i++)
{
source16[i * 2 + 0] = static_cast<uint8>(i >> 8);
source16[i * 2 + 1] = static_cast<uint8>(i & 0xFF);
source16[i * 2 + 0] = mpt::byte_cast<std::byte>(static_cast<uint8>(i >> 8));
source16[i * 2 + 1] = mpt::byte_cast<std::byte>(static_cast<uint8>(i & 0xFF));
}
CopySample<SC::DecodeInt16<0, bigEndian16> >(signed16, 65536, 1, mpt::byte_cast<const std::byte *>(source16), 65536 * 2, 1);
CopySample<SC::DecodeInt16<0x8000u, bigEndian16> >(reinterpret_cast<int16*>(unsigned16), 65536, 1, mpt::byte_cast<const std::byte *>(source16), 65536 * 2, 1);
CopySample<SC::DecodeInt16Delta<bigEndian16> >(delta16, 65536, 1, mpt::byte_cast<const std::byte *>(source16), 65536 * 2, 1);
CopySample<SC::DecodeInt16<0, bigEndian16> >(signed16.data(), 65536, 1, source16.data(), 65536 * 2, 1);
CopySample<SC::DecodeInt16<0x8000u, bigEndian16> >(unsigned16.data(), 65536, 1, source16.data(), 65536 * 2, 1);
CopySample<SC::DecodeInt16Delta<bigEndian16> >(delta16.data(), 65536, 1, source16.data(), 65536 * 2, 1);
delta = 0;
for(size_t i = 0; i < 65536; i++)
{
delta += static_cast<int16>(i);
VERIFY_EQUAL_QUIET_NONCONT(signed16[i], static_cast<int16>(i));
VERIFY_EQUAL_QUIET_NONCONT(unsigned16[i], static_cast<uint16>(i + 0x8000u));
VERIFY_EQUAL_QUIET_NONCONT(unsigned16[i], static_cast<int16>(static_cast<int>(i) - 0x8000));
VERIFY_EQUAL_QUIET_NONCONT(delta16[i], static_cast<int16>(delta));
}
@ -3621,24 +3621,25 @@ static MPT_NOINLINE void TestSampleConversion()
// Signed 24-Bit Integer PCM
{
uint8 *source24 = sourceBuf;
for(size_t i = 0; i < 65536; i++)
std::vector<std::byte> source24(65536 * 3);
for(std::size_t i = 0; i < 65536; i++)
{
source24[i * 3 + 0] = 0;
source24[i * 3 + 1] = static_cast<uint8>(i & 0xFF);
source24[i * 3 + 2] = static_cast<uint8>(i >> 8);
source24[i * 3 + 0] = mpt::byte_cast<std::byte>(static_cast<uint8>(0));
source24[i * 3 + 1] = mpt::byte_cast<std::byte>(static_cast<uint8>(i & 0xFF));
source24[i * 3 + 2] = mpt::byte_cast<std::byte>(static_cast<uint8>(i >> 8));
}
int16 *truncated16 = static_cast<int16 *>(targetBuf);
std::vector<int16> truncated16(65536);
std::vector<int16> sampleBuf(65536);
ModSample sample;
sample.Initialize();
sample.nLength = 65536;
sample.uFlags.set(CHN_16BIT);
sample.pData.pSample = (static_cast<int16 *>(targetBuf) + 65536);
CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(sample, mpt::byte_cast<const std::byte *>(source24), 3*65536);
CopySample<SC::ConversionChain<SC::ConvertShift<int16, int32, 16>, SC::DecodeInt24<0, littleEndian24> > >(truncated16, 65536, 1, mpt::byte_cast<const std::byte *>(source24), 65536 * 3, 1);
sample.pData.pSample = sampleBuf.data();
CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(sample, source24.data(), 3*65536);
CopySample<SC::ConversionChain<SC::ConvertShift<int16, int32, 16>, SC::DecodeInt24<0, littleEndian24> > >(truncated16.data(), 65536, 1, source24.data(), 65536 * 3, 1);
for(size_t i = 0; i < 65536; i++)
for(std::size_t i = 0; i < 65536; i++)
{
VERIFY_EQUAL_QUIET_NONCONT(sample.sample16()[i], static_cast<int16>(i));
VERIFY_EQUAL_QUIET_NONCONT(truncated16[i], static_cast<int16>(i));
@ -3647,26 +3648,27 @@ static MPT_NOINLINE void TestSampleConversion()
// Float 32-Bit
{
uint8 *source32 = sourceBuf;
for(size_t i = 0; i < 65536; i++)
std::vector<std::byte> source32(65536 * 4);
for(std::size_t i = 0; i < 65536; i++)
{
IEEE754binary32BE floatbits = IEEE754binary32BE((static_cast<float>(i) / 65536.0f) - 0.5f);
source32[i * 4 + 0] = mpt::byte_cast<uint8>(floatbits.GetByte(0));
source32[i * 4 + 1] = mpt::byte_cast<uint8>(floatbits.GetByte(1));
source32[i * 4 + 2] = mpt::byte_cast<uint8>(floatbits.GetByte(2));
source32[i * 4 + 3] = mpt::byte_cast<uint8>(floatbits.GetByte(3));
source32[i * 4 + 0] = mpt::byte_cast<std::byte>(floatbits.GetByte(0));
source32[i * 4 + 1] = mpt::byte_cast<std::byte>(floatbits.GetByte(1));
source32[i * 4 + 2] = mpt::byte_cast<std::byte>(floatbits.GetByte(2));
source32[i * 4 + 3] = mpt::byte_cast<std::byte>(floatbits.GetByte(3));
}
int16 *truncated16 = static_cast<int16 *>(targetBuf);
std::vector<int16> truncated16(65536);
std::vector<int16> sampleBuf(65536);
ModSample sample;
sample.Initialize();
sample.nLength = 65536;
sample.uFlags.set(CHN_16BIT);
sample.pData.pSample = static_cast<int16 *>(targetBuf) + 65536;
CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, float32>, SC::DecodeFloat32<bigEndian32> > >(sample, mpt::byte_cast<const std::byte *>(source32), 4*65536);
CopySample<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<bigEndian32> > >(truncated16, 65536, 1, mpt::byte_cast<const std::byte *>(source32), 65536 * 4, 1);
sample.pData.pSample = sampleBuf.data();
CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, float32>, SC::DecodeFloat32<bigEndian32> > >(sample, source32.data(), 4*65536);
CopySample<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<bigEndian32> > >(truncated16.data(), 65536, 1, source32.data(), 65536 * 4, 1);
for(size_t i = 0; i < 65536; i++)
for(std::size_t i = 0; i < 65536; i++)
{
VERIFY_EQUAL_QUIET_NONCONT(sample.sample16()[i], static_cast<int16>(i - 0x8000u));
VERIFY_EQUAL_QUIET_NONCONT(std::abs(truncated16[i] - static_cast<int16>((i - 0x8000u) / 2)) <= 1, true);
@ -3740,10 +3742,11 @@ static MPT_NOINLINE void TestSampleConversion()
// Range checks
{
int8 oneSample = 1;
char *signed8 = reinterpret_cast<char *>(targetBuf);
memset(signed8, 0, 4);
CopySample<SC::DecodeInt8>(reinterpret_cast<int8*>(targetBuf), 4, 1, reinterpret_cast<const std::byte*>(&oneSample), sizeof(oneSample), 1);
std::byte oneSample = mpt::byte_cast<std::byte>(static_cast<int8>(1));
int8 targetBuf4[4];
int8 *signed8 = targetBuf4;
std::memset(signed8, 0, 4);
CopySample<SC::DecodeInt8>(targetBuf4, 4, 1, &oneSample, sizeof(oneSample), 1);
VERIFY_EQUAL_NONCONT(signed8[0], 1);
VERIFY_EQUAL_NONCONT(signed8[1], 0);
VERIFY_EQUAL_NONCONT(signed8[2], 0);