diff --git a/Frameworks/OpenMPT/OpenMPT/Makefile b/Frameworks/OpenMPT/OpenMPT/Makefile index cfb7576e4..a4923a821 100644 --- a/Frameworks/OpenMPT/OpenMPT/Makefile +++ b/Frameworks/OpenMPT/OpenMPT/Makefile @@ -733,6 +733,7 @@ CPPCHECK_FLAGS += --std=c99 --std=c++17 CPPCHECK_FLAGS += --quiet CPPCHECK_FLAGS += --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' CPPCHECK_FLAGS += --suppress=missingIncludeSystem +CPPCHECK_FLAGS += --suppress=uninitMemberVar CPPCHECK_FLAGS += $(CPPFLAGS) CPPFLAGS += $(CPPFLAGS_ZLIB) $(CPPFLAGS_MPG123) $(CPPFLAGS_OGG) $(CPPFLAGS_VORBIS) $(CPPFLAGS_VORBISFILE) diff --git a/Frameworks/OpenMPT/OpenMPT/build/dist.mk b/Frameworks/OpenMPT/OpenMPT/build/dist.mk index 5bb517aa0..3d617da48 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/dist.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/dist.mk @@ -1,4 +1,4 @@ -MPT_SVNVERSION=15019 -MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.9 -MPT_SVNDATE=2021-05-16T14:59:54.252327Z +MPT_SVNVERSION=15412 +MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.10 +MPT_SVNDATE=2021-07-04T16:30:04.479627Z diff --git a/Frameworks/OpenMPT/OpenMPT/build/svn_version/svn_version.h b/Frameworks/OpenMPT/OpenMPT/build/svn_version/svn_version.h index 828906e76..26f6b0302 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/svn_version/svn_version.h +++ b/Frameworks/OpenMPT/OpenMPT/build/svn_version/svn_version.h @@ -1,10 +1,10 @@ #pragma once -#define OPENMPT_VERSION_SVNVERSION "15019" -#define OPENMPT_VERSION_REVISION 15019 +#define OPENMPT_VERSION_SVNVERSION "15412" +#define OPENMPT_VERSION_REVISION 15412 #define OPENMPT_VERSION_DIRTY 0 #define OPENMPT_VERSION_MIXEDREVISIONS 0 -#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.9" -#define OPENMPT_VERSION_DATE "2021-05-16T14:59:54.252327Z" +#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.10" +#define OPENMPT_VERSION_DATE "2021-07-04T16:30:04.479627Z" #define OPENMPT_VERSION_IS_PACKAGE 1 diff --git a/Frameworks/OpenMPT/OpenMPT/common/BuildSettings.h b/Frameworks/OpenMPT/OpenMPT/common/BuildSettings.h index ea7fc264e..026c553d0 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/BuildSettings.h +++ b/Frameworks/OpenMPT/OpenMPT/common/BuildSettings.h @@ -79,7 +79,11 @@ #endif // MPT_OS_WINDOWS // OpenMPT-only dependencies +#if !MPT_MSVC_BEFORE(2019,0) +// disabled for VS2017 because of multiple initialization of inline variables +// https://developercommunity.visualstudio.com/t/static-inline-variable-gets-destroyed-multiple-tim/297876 #define MPT_WITH_ASIO +#endif #define MPT_WITH_DMO #define MPT_WITH_LAME #define MPT_WITH_LHASA diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptCPU.cpp b/Frameworks/OpenMPT/OpenMPT/common/mptCPU.cpp index 14a260e5e..842900d40 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptCPU.cpp +++ b/Frameworks/OpenMPT/OpenMPT/common/mptCPU.cpp @@ -284,12 +284,10 @@ int GetMinimumAVXVersion() { int minimumAVXVersion = 0; #if MPT_COMPILER_MSVC - #if defined(_M_IX86_FP) - #if defined(__AVX2__) - minimumAVXVersion = 2; - #elif defined(__AVX__) - minimumAVXVersion = 1; - #endif + #if defined(__AVX2__) + minimumAVXVersion = 2; + #elif defined(__AVX__) + minimumAVXVersion = 1; #endif #endif return minimumAVXVersion; diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptPathString.cpp b/Frameworks/OpenMPT/OpenMPT/common/mptPathString.cpp index fabc7bca5..3361c5440 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptPathString.cpp +++ b/Frameworks/OpenMPT/OpenMPT/common/mptPathString.cpp @@ -22,18 +22,6 @@ #include #endif -#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT -#if defined(__MINGW32__) || defined(__MINGW64__) -// MinGW-w64 headers do not declare this for WinRT, which is wrong. -extern "C" { -WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR *lpFilePart); -#ifndef GetFullPathName -#define GetFullPathName GetFullPathNameW -#endif -} -#endif -#endif - OPENMPT_NAMESPACE_BEGIN #if MPT_OS_WINDOWS @@ -44,7 +32,11 @@ namespace mpt RawPathString PathString::AsNativePrefixed() const { - if(path.length() <= MAX_PATH || path.substr(0, 4) == PL_("\\\\?\\")) +#if MPT_OS_WINDOWS_WINRT && (_WIN32_WINNT < 0x0a00) + // For WinRT on Windows 8, there is no official wy to determine an absolute path. + return path; +#else + if(path.length() < MAX_PATH || path.substr(0, 4) == PL_("\\\\?\\")) { // Path is short enough or already in prefixed form return path; @@ -59,6 +51,7 @@ RawPathString PathString::AsNativePrefixed() const // Regular file: C:\foo.bar -> \\?\C:\foo.bar return PL_("\\\\?\\") + absPath; } +#endif } @@ -442,6 +435,8 @@ bool PathIsAbsolute(const mpt::PathString &path) { #if MPT_OS_WINDOWS +#if !(MPT_OS_WINDOWS_WINRT && (_WIN32_WINNT < 0x0a00)) + mpt::PathString GetAbsolutePath(const mpt::PathString &path) { DWORD size = GetFullPathName(path.AsNative().c_str(), 0, nullptr, nullptr); @@ -457,6 +452,8 @@ mpt::PathString GetAbsolutePath(const mpt::PathString &path) return mpt::PathString::FromNative(fullPathName.data()); } +#endif + #ifdef MODPLUG_TRACKER bool DeleteWholeDirectoryTree(mpt::PathString path) diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptPathString.h b/Frameworks/OpenMPT/OpenMPT/common/mptPathString.h index f971e61cb..9d522b1f6 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptPathString.h +++ b/Frameworks/OpenMPT/OpenMPT/common/mptPathString.h @@ -321,9 +321,13 @@ bool PathIsAbsolute(const mpt::PathString &path); #if MPT_OS_WINDOWS +#if !(MPT_OS_WINDOWS_WINRT && (_WIN32_WINNT < 0x0a00)) + // Returns the absolute path for a potentially relative path and removes ".." or "." components. (same as GetFullPathNameW) mpt::PathString GetAbsolutePath(const mpt::PathString &path); +#endif + #ifdef MODPLUG_TRACKER // Deletes a complete directory tree. Handle with EXTREME care. diff --git a/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h b/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h index 4fa3570f2..82cb7a138 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h +++ b/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h @@ -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 29 -#define VER_MINOR 10 +#define VER_MINOR 11 #define VER_MINORMINOR 00 OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/OpenMPT.txt b/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/OpenMPT.txt index 2149fbab7..714bc017a 100644 --- a/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/OpenMPT.txt +++ b/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/OpenMPT.txt @@ -1,14 +1,12 @@ This folder contains the stb_vorbis library from -https://github.com/nothings/stb/blob/master/stb_vorbis.c v1.20 -commit b42009b3b9d4ca35bc703f5310eedc74f584be58 (2020-07-13) +https://github.com/nothings/stb/blob/master/stb_vorbis.c v1.21 +commit 8e51be04dc7dcee462e1f09e410faceab52cc6d2 (2021-07-02) Modifications: * Use of alloca has been replaced with malloc, as alloca is not in C99 and fails to compile. * Macro redefinition of alloca with mingw-w64 has been fixed. * Macro redefinition of STB_VORBIS_NO_STDIO has been fixed. - * Bugfix https://github.com/nothings/stb/pull/1064 has been applied. -Modifications are always additions and have been marked with // OpenMPT. For building, premake is used to generate Visual Studio project files. See ../build/premake/ for details. diff --git a/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/stb_vorbis.c b/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/stb_vorbis.c index 9e6fc3377..4bf24bec6 100644 --- a/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/stb_vorbis.c +++ b/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/stb_vorbis.c @@ -1,4 +1,4 @@ -// Ogg Vorbis audio decoder - v1.20 - public domain +// Ogg Vorbis audio decoder - v1.21 - public domain // http://nothings.org/stb_vorbis/ // // Original version written by Sean Barrett in 2007. @@ -33,8 +33,10 @@ // Timur Gagiev Maxwell Koo Peter Waller // github:audinowho Dougall Johnson David Reid // github:Clownacy Pedro J. Estebanez Remi Verschelde +// AnthoFoxo // // Partial history: +// 1.21 - 2021-07-02 - fix bug for files with no comments // 1.20 - 2020-07-11 - several small fixes // 1.19 - 2020-02-05 - warnings // 1.18 - 2020-02-02 - fix seek bugs; parse header comments; misc warnings etc. @@ -3651,13 +3653,12 @@ static int start_decoder(vorb *f) f->vendor[len] = (char)'\0'; //user comments f->comment_list_length = get32_packet(f); - f->comment_list = (char**)setup_malloc(f, sizeof(char*) * (f->comment_list_length)); -#if 0 // OpenMPT - if (f->comment_list == NULL) return error(f, VORBIS_outofmem); -#else // OpenMPT - // Bugfix from https://github.com/nothings/stb/pull/1064 // OpenMPT - if (f->comment_list_length > 0 && f->comment_list == NULL) return error(f, VORBIS_outofmem); // OpenMPT -#endif // OpenMPT + f->comment_list = NULL; + if (f->comment_list_length > 0) + { + f->comment_list = (char**) setup_malloc(f, sizeof(char*) * (f->comment_list_length)); + if (f->comment_list == NULL) return error(f, VORBIS_outofmem); + } for(i=0; i < f->comment_list_length; ++i) { len = get32_packet(f); diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/changelog.md b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/changelog.md index 474322de4..5f82a4b6a 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/changelog.md +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/changelog.md @@ -5,6 +5,29 @@ Changelog {#changelog} For fully detailed change log, please see the source repository directly. This is just a high-level summary. +### libopenmpt 0.5.10 (2021-07-04) + + * S3M: Honor the Stereo flag not being set. This improves the sound of some + tunes like Turbulence by Purple Motion. + * S3M: Detect MPT 1.0 alpha versions which didn't set the Stereo flag. In this + case, the unset Stereo flag is also ignored because MPT 1.0 alpha used the + default S3M channel panning anyway. + * S3M: Only for OPL instruments the high sample rate bits should be ignored; + for PCM instruments they are clamped to 65535 Hz. + * MOD: Do not apply ProTracker loop length quirk to MODs that could have been + made with Scream Tracker (fixes Soul-O-Matic by Purple Motion). + * AMF (DSMI): Format revisions 1 and 9, as well as early (technically + malformed) revision 10 files, are now supported. Surround panning commands + and instrument number without note are now converted correctly. + * AMF (DSMI): Patterns and samples were not read correctly in some files + (e.g. AVOID.AMF). + * GDM: Correctly import extra-fine portamentos. + + * mpg123: Update to v1.28.0 (2021-06-05). + * ogg: Update to v1.3.5 (2021-06-04). + * stb_vorbis: Update v1.21 commit 8e51be04dc7dcee462e1f09e410faceab52cc6d2 + (2021-07-02). + ### libopenmpt 0.5.9 (2021-05-16) * `Makefile` `CONFIG=emscripten` does not pass linker options to the compiler diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h index 37fbb63d3..ed1f4b729 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h @@ -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 9 +#define OPENMPT_API_VERSION_PATCH 10 /*! \brief libopenmpt pre-release tag */ #define OPENMPT_API_VERSION_PREREL "" /*! \brief libopenmpt pre-release flag */ diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.mk b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.mk index cac7acd43..de1bc97db 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.mk +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.mk @@ -1,8 +1,8 @@ LIBOPENMPT_VERSION_MAJOR=0 LIBOPENMPT_VERSION_MINOR=5 -LIBOPENMPT_VERSION_PATCH=9 +LIBOPENMPT_VERSION_PATCH=10 LIBOPENMPT_VERSION_PREREL= LIBOPENMPT_LTVER_CURRENT=2 -LIBOPENMPT_LTVER_REVISION=9 +LIBOPENMPT_LTVER_REVISION=10 LIBOPENMPT_LTVER_AGE=2 diff --git a/Frameworks/OpenMPT/OpenMPT/soundbase/Dither.h b/Frameworks/OpenMPT/OpenMPT/soundbase/Dither.h index 319f63671..acab6aa2c 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundbase/Dither.h +++ b/Frameworks/OpenMPT/OpenMPT/soundbase/Dither.h @@ -225,7 +225,7 @@ private: public: template DitherTemplate(Trd & rd) - : prng(rd) + : prng(mpt::make_prng(rd)) { return; } diff --git a/Frameworks/OpenMPT/OpenMPT/sounddsp/Reverb.cpp b/Frameworks/OpenMPT/OpenMPT/sounddsp/Reverb.cpp index 1cb5046d9..4a1d337a4 100644 --- a/Frameworks/OpenMPT/OpenMPT/sounddsp/Reverb.cpp +++ b/Frameworks/OpenMPT/OpenMPT/sounddsp/Reverb.cpp @@ -433,7 +433,7 @@ void CReverb::Process(MixSampleInt *MixSoundBuffer, uint32 nSamples) if (nIn > 0) ProcessPreDelay(&g_RefDelay, MixReverbBuffer, nIn); // Process Reverb Reflections and Late Reverberation int32 *pRvbOut = MixReverbBuffer; - uint32 nRvbSamples = nOut, nCount = 0; + uint32 nRvbSamples = nOut; while (nRvbSamples > 0) { uint32 nPosRef = g_RefDelay.nRefOutPos & SNDMIX_REVERB_DELAY_MASK; @@ -451,7 +451,6 @@ void CReverb::Process(MixSampleInt *MixSoundBuffer, uint32 nSamples) // Update delay positions g_RefDelay.nRefOutPos = (g_RefDelay.nRefOutPos + n) & SNDMIX_REVERB_DELAY_MASK; g_RefDelay.nDelayPos = (g_RefDelay.nDelayPos + n) & SNDMIX_REFLECTIONS_DELAY_MASK; - nCount += n*2; pRvbOut += n*2; nRvbSamples -= n; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp index a7e99770d..a38efee02 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp @@ -22,8 +22,6 @@ #include "SampleIO.h" #include "modsmp_ctrl.h" -#include - OPENMPT_NAMESPACE_BEGIN #ifdef MODPLUG_TRACKER @@ -1877,7 +1875,7 @@ bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, ui { // Try to combine stereo samples uint8 pan1 = GetPanning(nIns, nRgn), pan2 = GetPanning(nIns, iDup); - if((pan1 == 0 || pan1 == 255) && (pan2 == 0 || pan2 == 255)) + if((pan1 < 16 && pan2 >= 240) || (pan2 < 16 && pan1 >= 240)) { ModSample &sample = sndFile.GetSample(nSmp); ctrlSmp::ConvertToStereo(sample, sndFile); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_amf.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_amf.cpp index f986ca2b8..7d2c903c3 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_amf.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_amf.cpp @@ -65,21 +65,6 @@ struct AsylumSampleHeader MPT_BINARY_STRUCT(AsylumSampleHeader, 37) -// DSMI AMF File Header -struct AMFFileHeader -{ - char amf[3]; - uint8le version; - char title[32]; - uint8le numSamples; - uint8le numOrders; - uint16le numTracks; - uint8le numChannels; -}; - -MPT_BINARY_STRUCT(AMFFileHeader, 41) - - static bool ValidateHeader(const AsylumFileHeader &fileHeader) { if(std::memcmp(fileHeader.signature, "ASYLUM Music Format V1.0\0", 25) @@ -216,11 +201,95 @@ bool CSoundFile::ReadAMF_Asylum(FileReader &file, ModLoadingFlags loadFlags) } +// DSMI AMF File Header +struct AMFFileHeader +{ + char amf[3]; + uint8le version; + char title[32]; + uint8le numSamples; + uint8le numOrders; + uint16le numTracks; + uint8le numChannels; +}; + +MPT_BINARY_STRUCT(AMFFileHeader, 41) + + +// DSMI AMF Sample Header (v1-v9) +struct AMFSampleHeaderOld +{ + uint8le type; + char name[32]; + char filename[13]; + uint32le index; + uint16le length; + uint16le sampleRate; + uint8le volume; + uint16le loopStart; + uint16le loopEnd; + + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.Initialize(); + mptSmp.filename = mpt::String::ReadBuf(mpt::String::nullTerminated, filename); + mptSmp.nLength = length; + mptSmp.nC5Speed = sampleRate; + mptSmp.nVolume = std::min(volume.get(), uint8(64)) * 4u; + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = loopEnd; + if(mptSmp.nLoopEnd == uint16_max) + mptSmp.nLoopStart = mptSmp.nLoopEnd = 0; + else if(type != 0 && mptSmp.nLoopEnd > mptSmp.nLoopStart + 2 && mptSmp.nLoopEnd <= mptSmp.nLength) + mptSmp.uFlags.set(CHN_LOOP); + } +}; + +MPT_BINARY_STRUCT(AMFSampleHeaderOld, 59) + + +// DSMI AMF Sample Header (v10+) +struct AMFSampleHeaderNew +{ + uint8le type; + char name[32]; + char filename[13]; + uint32le index; + uint32le length; + uint16le sampleRate; + uint8le volume; + uint32le loopStart; + uint32le loopEnd; + + void ConvertToMPT(ModSample &mptSmp, bool truncated) const + { + mptSmp.Initialize(); + mptSmp.filename = mpt::String::ReadBuf(mpt::String::nullTerminated, filename); + mptSmp.nLength = length; + mptSmp.nC5Speed = sampleRate; + mptSmp.nVolume = std::min(volume.get(), uint8(64)) * 4u; + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = loopEnd; + if(truncated && mptSmp.nLoopStart > 0) + mptSmp.nLoopEnd = mptSmp.nLength; + if(type != 0 && mptSmp.nLoopEnd > mptSmp.nLoopStart + 2 && mptSmp.nLoopEnd <= mptSmp.nLength) + mptSmp.uFlags.set(CHN_LOOP); + } + + // Check if sample headers might be truncated + bool IsValid(uint8 numSamples) const + { + return type <= 1 && index <= numSamples && length <= 0x100000 && volume <= 64 && loopStart <= length && loopEnd <= length; + } +}; + +MPT_BINARY_STRUCT(AMFSampleHeaderNew, 65) + + // Read a single AMF track (channel) into a pattern. static void AMFReadPattern(CPattern &pattern, CHANNELINDEX chn, FileReader &fileChunk) { fileChunk.Rewind(); - ModCommand::INSTR lastInstr = 0; while(fileChunk.CanRead(3)) { const auto [row, command, value] = fileChunk.ReadArray(); @@ -241,25 +310,17 @@ static void AMFReadPattern(CPattern &pattern, CHANNELINDEX chn, FileReader &file m.note = command + NOTE_MIN; if(value != 0xFF) { - if(!m.instr) m.instr = lastInstr; m.volcmd = VOLCMD_VOLUME; m.vol = value; } } } else if(command == 0x7F) { - // Duplicate row - int8 rowDelta = static_cast(value); - int16 copyRow = static_cast(row) + rowDelta; - if(copyRow >= 0 && copyRow < static_cast(pattern.GetNumRows())) - { - m = *pattern.GetpModCommand(copyRow, chn); - } + // Instrument without note retrigger in MOD (no need to do anything here, should be preceded by 0x80 command) } else if(command == 0x80) { // Instrument m.instr = value + 1; - lastInstr = m.instr; } else { // Effect @@ -277,12 +338,9 @@ static void AMFReadPattern(CPattern &pattern, CHANNELINDEX chn, FileReader &file uint8 param = value; if(cmd < CountOf(effTrans)) - { cmd = effTrans[cmd]; - } else - { + else cmd = CMD_NONE; - } // Fix some commands... switch(command & 0x7F) @@ -362,15 +420,25 @@ static void AMFReadPattern(CPattern &pattern, CHANNELINDEX chn, FileReader &file // 17: Panning case 0x17: - param = (param + 64) & 0x7F; - if(m.command != CMD_NONE) + if(param == 100) { - if(m.volcmd == VOLCMD_NONE || m.volcmd == VOLCMD_PANNING) + // History lesson intermission: According to Otto Chrons, he remembers that he added support + // for 8A4 / XA4 "surround" panning in DMP for MOD and S3M files before any other trackers did, + // So DSMI / DMP are most likely the original source of these 7-bit panning + surround commands! + param = 0xA4; + } else + { + param = static_cast(std::clamp(static_cast(param) + 64, 0, 128)); + if(m.command != CMD_NONE) { - m.volcmd = VOLCMD_PANNING; - m.vol = param / 2; + // Move to volume column if required + if(m.volcmd == VOLCMD_NONE || m.volcmd == VOLCMD_PANNING) + { + m.volcmd = VOLCMD_PANNING; + m.vol = param / 2; + } + cmd = CMD_NONE; } - cmd = CMD_NONE; } break; } @@ -388,9 +456,8 @@ static void AMFReadPattern(CPattern &pattern, CHANNELINDEX chn, FileReader &file static bool ValidateHeader(const AMFFileHeader &fileHeader) { if(std::memcmp(fileHeader.amf, "AMF", 3) - || fileHeader.version < 8 || fileHeader.version > 14 - || ((fileHeader.numChannels < 1 || fileHeader.numChannels > 32) && fileHeader.version >= 10) - ) + || (fileHeader.version < 8 && fileHeader.version != 1) || fileHeader.version > 14 + || ((fileHeader.numChannels < 1 || fileHeader.numChannels > 32) && fileHeader.version >= 9)) { return false; } @@ -444,7 +511,7 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags) m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.title); - if(fileHeader.version < 10) + if(fileHeader.version < 9) { // Old format revisions are fixed to 4 channels m_nChannels = 4; @@ -458,16 +525,13 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags) const CHANNELINDEX readChannels = fileHeader.version >= 12 ? 32 : 16; for(CHANNELINDEX chn = 0; chn < readChannels; chn++) { - int16 pan = (file.ReadInt8() + 64) * 2; - if(pan < 0) pan = 0; - if(pan > 256) - { - pan = 128; + int8 pan = file.ReadInt8(); + if(pan == 100) ChnSettings[chn].dwFlags = CHN_SURROUND; - } - ChnSettings[chn].nPan = static_cast(pan); + else + ChnSettings[chn].nPan = static_cast(std::clamp((pan + 64) * 2, 0, 256)); } - } else if(fileHeader.version == 10) + } else if(fileHeader.version >= 9) { uint8 panPos[16]; file.ReadArray(panPos); @@ -476,14 +540,13 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags) ChnSettings[chn].nPan = (panPos[chn] & 1) ? 0x40 : 0xC0; } } - // To check: Was the channel table introduced in revision 1.0 or 0.9? I only have 0.8 files, in which it is missing... - MPT_ASSERT(fileHeader.version != 9); // Get Tempo/Speed if(fileHeader.version >= 13) { auto [tempo, speed] = file.ReadArray(); - if(tempo < 32) tempo = 125; + if(tempo < 32) + tempo = 125; m_nDefaultTempo.Set(tempo); m_nDefaultSpeed = speed; } else @@ -513,60 +576,40 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags) } // Read Sample Headers - std::vector samplePos(GetNumSamples(), 0); - uint32 maxSamplePos = 0; + bool truncatedSampleHeaders = false; + if(fileHeader.version == 10) + { + // M2AMF 1.3 included with DMP 2.32 wrote new (v10+) sample headers, but using the old struct length. + const auto startPos = file.GetPosition(); + for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) + { + AMFSampleHeaderNew sample; + if(file.ReadStruct(sample) && !sample.IsValid(fileHeader.numSamples)) + { + truncatedSampleHeaders = true; + break; + } + } + file.Seek(startPos); + } + std::vector sampleMap(GetNumSamples(), 0); for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { - ModSample &sample = Samples[smp]; - sample.Initialize(); - - uint8 type = file.ReadUint8(); - file.ReadString(m_szNames[smp], 32); - file.ReadString(sample.filename, 13); - samplePos[smp - 1] = file.ReadUint32LE(); if(fileHeader.version < 10) { - sample.nLength = file.ReadUint16LE(); + AMFSampleHeaderOld sample; + file.ReadStruct(sample); + sample.ConvertToMPT(Samples[smp]); + m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sample.name); + sampleMap[smp - 1] = sample.index; } else { - sample.nLength = file.ReadUint32LE(); - } - - sample.nC5Speed = file.ReadUint16LE(); - sample.nVolume = std::min(file.ReadUint8(), uint8(64)) * 4u; - - if(fileHeader.version < 10) - { - // Various sources (Miodrag Vallat's amf.txt, old ModPlug code) suggest that the loop information - // format revision 1.0 should only consist of a 16-bit value for the loop start (loop end would - // automatically equal sample length), but the only v1.0 files I have ("the tribal zone" and - // "the way its gonna b" by Maelcum) do not confirm this - the sample headers are laid out exactly - // as in the newer revisions in these two files. Even in format revision 0.8 (output by MOD2AMF v1.02) - // There are loop start and loop end values (although they are 16-Bit). Maybe this only applies to - // even older revision of the format? - sample.nLoopStart = file.ReadUint16LE(); - sample.nLoopEnd = file.ReadUint16LE(); - } else - { - sample.nLoopStart = file.ReadUint32LE(); - sample.nLoopEnd = file.ReadUint32LE(); - } - - // Length of v1.0+ sample header: 65 bytes - // Length of old sample header: 59 bytes - - if(type != 0) - { - if(sample.nLoopEnd > sample.nLoopStart + 2 && sample.nLoopEnd <= sample.nLength) - { - sample.uFlags.set(CHN_LOOP); - } else - { - sample.nLoopStart = sample.nLoopEnd = 0; - } - - maxSamplePos = std::max(maxSamplePos, samplePos[smp - 1]); + AMFSampleHeaderNew sample; + file.ReadStructPartial(sample, truncatedSampleHeaders ? sizeof(AMFSampleHeaderOld) : sizeof(AMFSampleHeaderNew)); + sample.ConvertToMPT(Samples[smp], truncatedSampleHeaders); + m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sample.name); + sampleMap[smp - 1] = sample.index; } } @@ -584,10 +627,11 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags) std::vector trackData(trackCount); for(uint16 i = 0; i < trackCount; i++) { - // Track size is a 24-Bit value describing the number of byte triplets in this track. - uint8 trackSize[3]; - file.ReadArray(trackSize); - trackData[i] = file.ReadChunk((trackSize[0] | (trackSize[1] << 8) | (trackSize[2] << 16)) * 3); + // Track size is a 16-Bit value describing the number of byte triplets in this track, followed by a track type byte. + uint16 numEvents = file.ReadUint16LE(); + file.Skip(1); + if(numEvents) + trackData[i] = file.ReadChunk(numEvents * 3 + (fileHeader.version == 1 ? 3 : 0)); } if(loadFlags & loadSampleData) @@ -599,24 +643,18 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags) SampleIO::littleEndian, SampleIO::unsignedPCM); - // Why is all of this sample loading business so weird in AMF? - // Surely there must be some great idea behind it which isn't handled here or used in the wild - // (re-using the same sample data for different sample slots maybe?) - - // First, try compacting the sample indices so that the loop won't have 2^32 iterations in the worst case. - std::vector samplePosCompact = samplePos; - std::sort(samplePosCompact.begin(), samplePosCompact.end()); - auto end = std::unique(samplePosCompact.begin(), samplePosCompact.end()); - - for(auto pos = samplePosCompact.begin(); pos != end && file.CanRead(1); pos++) + // Note: in theory a sample can be reused by several instruments and appear in a different order in the file + // However, M2AMF doesn't take advantage of this and just writes instruments in the order they appear, + // without de-duplicating identical sample data. + for(SAMPLEINDEX smp = 1; smp <= GetNumSamples() && file.CanRead(1); smp++) { - for(SAMPLEINDEX smp = 0; smp < GetNumSamples() && file.CanRead(1); smp++) + auto startPos = file.GetPosition(); + for(SAMPLEINDEX target = 0; target < GetNumSamples(); target++) { - if(*pos == samplePos[smp]) - { - sampleIO.ReadSample(Samples[smp + 1], file); - break; - } + if(sampleMap[target] != smp) + continue; + file.Seek(startPos); + sampleIO.ReadSample(Samples[target + 1], file); } } } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_gdm.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_gdm.cpp index b722efab3..c3f10a7e3 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_gdm.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_gdm.cpp @@ -442,9 +442,20 @@ bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags) break; case CMD_MODCMDEX: - if(!modSpecs.HasCommand(CMD_MODCMDEX)) + switch(m.param >> 4) { - m.ExtendedMODtoS3MEffect(); + case 0x8: + m.command = CMD_PORTAMENTOUP; + m.param = 0xE0 | (m.param & 0x0F); + break; + case 0x9: + m.command = CMD_PORTAMENTODOWN; + m.param = 0xE0 | (m.param & 0x0F); + break; + default: + if(!modSpecs.HasCommand(CMD_MODCMDEX)) + m.ExtendedMODtoS3MEffect(); + break; } break; @@ -459,54 +470,21 @@ bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags) case CMD_S3MCMDEX: // Some really special commands - switch(m.param >> 4) + if(m.param == 0x01) { - case 0x0: - switch(m.param & 0x0F) - { - case 0x0: // Surround Off - case 0x1: // Surround On - m.param += 0x90; - break; - case 0x2: // Set normal loop - not implemented in BWSB or 2GDM. - case 0x3: // Set bidi loop - ditto - m.command = CMD_NONE; - break; - case 0x4: // Play sample forwards - m.command = CMD_S3MCMDEX; - m.param = 0x9E; - break; - case 0x5: // Play sample backwards - m.command = CMD_S3MCMDEX; - m.param = 0x9F; - break; - case 0x6: // Monaural sample - also not implemented. - case 0x7: // Stereo sample - ditto - case 0x8: // Stop sample on end - ditto - case 0x9: // Loop sample on end - ditto - default: - m.command = CMD_NONE; - break; - } - break; - - case 0x8: // 4-Bit Panning - if(!modSpecs.HasCommand(CMD_S3MCMDEX)) - { + // Surround (implemented in 2GDM but not in BWSB itself) + m.param = 0x91; + } else if((m.param & 0xF0) == 0x80) + { + // 4-Bit Panning + if (!modSpecs.HasCommand(CMD_S3MCMDEX)) m.command = CMD_MODCMDEX; - } - break; - - case 0xD: // Adjust frequency (increment in hz) - also not implemented. - default: + } else + { + // All other effects are implemented neither in 2GDM nor in BWSB. m.command = CMD_NONE; - break; } break; - - case 0x1F: - m.command = CMD_TEMPO; - break; } // Move pannings to volume column - should never happen @@ -520,9 +498,7 @@ bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags) if(!(effByte & effectDone)) break; // no other effect follows } - } - } } } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp index f327c5041..00fc811b2 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp @@ -833,6 +833,8 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) bool isInconexia = IsMagic(magic, "M\0\0\0") || IsMagic(magic, "8\0\0\0"); // A loop length of zero will freeze ProTracker, so assume that modules having such a value were not meant to be played on Amiga. Fixes LHS_MI.MOD bool hasRepLen0 = false; + // Empty sample slots typically should have a default volume of 0 in ProTracker + bool hasEmptySampleWithVolume = false; if(modMagicResult.setMODVBlankTiming) { m_playBehaviour.set(kMODVBlankTiming); @@ -867,7 +869,9 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) if(sampleHeader.length && !sampleHeader.loopLength) hasRepLen0 = true; - + else if(!sampleHeader.length && sampleHeader.volume == 64) + hasEmptySampleWithVolume = true; + if(maybeWOW) { // Some WOW files rely on sample length 1 being counted as well @@ -1193,8 +1197,11 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) // Fix sample 6 in MOD.shorttune2, which has a replen longer than the sample itself. // ProTracker reads beyond the end of the sample when playing. Normally samples are // adjacent in PT's memory, so we simply read into the next sample in the file. + // On the other hand, the loop points in Purple Motions's SOUL-O-M.MOD are completely broken and shouldn't be treated like this. + // As it was most likely written in Scream Tracker, it has empty sample slots with a default volume of 64, which we use for + // rejecting this quirk for that file. FileReader::off_t nextSample = file.GetPosition() + sampleIO.CalculateEncodedSize(sample.nLength); - if(isMdKd && onlyAmigaNotes) + if(isMdKd && onlyAmigaNotes && !hasEmptySampleWithVolume) sample.nLength = std::max(sample.nLength, sample.nLoopEnd); sampleIO.ReadSample(sample, file); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp index 4620637cf..dcb2a703e 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp @@ -244,9 +244,17 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) case S3MFileHeader::trkScreamTracker: if(fileHeader.cwtv == S3MFileHeader::trkST3_20 && fileHeader.special == 0 && (fileHeader.ordNum & 0x0F) == 0 && fileHeader.ultraClicks == 0 && (fileHeader.flags & ~0x50) == 0) { - // MPT 1.16 and older versions of OpenMPT - Simply keep default (filter) MIDI macros - m_dwLastSavedWithVersion = MPT_V("1.16.00.00"); - madeWithTracker = U_("ModPlug Tracker / OpenMPT"); + // MPT and OpenMPT before 1.17.03.02 - Simply keep default (filter) MIDI macros + if((fileHeader.masterVolume & 0x80) != 0) + { + m_dwLastSavedWithVersion = MPT_V("1.16.00.00"); + madeWithTracker = U_("ModPlug Tracker / OpenMPT 1.17"); + } else + { + // MPT 1.0 alpha5 doesn't set the stereo flag, but MPT 1.0 beta1 does. + m_dwLastSavedWithVersion = MPT_V("1.00.00.00"); + madeWithTracker = U_("ModPlug Tracker 1.0 alpha"); + } keepMidiMacros = true; nonCompatTracker = true; m_playBehaviour.set(kST3LimitPeriod); @@ -255,6 +263,9 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) madeWithTracker = U_("Velvet Studio"); } else { + // ST3.20 should only ever write ultra-click values 16, 24 and 32 (corresponding to 8, 12 and 16 in the GUI), ST3.01/3.03 should only write 0. + // However, we won't fingerprint these values here as it's unlikely that there is any other tracker out there disguising as ST3 and using a strange ultra-click value. + // Also, re-saving a file with a strange ultra-click value in ST3 doesn't fix this value unless the user manually changes it, or if it's below 16. madeWithTracker = U_("Scream Tracker"); formatTrackerStr = true; isST3 = true; @@ -276,7 +287,7 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) } if(fileHeader.cwtv >= S3MFileHeader::trkIT2_07 && fileHeader.reserved3 != 0) { - // Starting from version 2.07, IT stores the total edit time of a module in the "reserved" field + // Starting from version 2.07, IT stores the total edit time of a module in the "reserved" field uint32 editTime = DecodeITEditTimer(fileHeader.cwtv, fileHeader.reserved3); FileHistory hist; @@ -402,9 +413,15 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) // However, this version check is missing in ST3, so any mono file with a master volume of 18 will be converted to a stereo file with master volume 32. else if(fileHeader.masterVolume == 2 || fileHeader.masterVolume == (2 | 0x10)) m_nSamplePreAmp = 0x20; + else if(!(fileHeader.masterVolume & 0x7F)) + m_nSamplePreAmp = 48; else m_nSamplePreAmp = std::max(fileHeader.masterVolume & 0x7F, 0x10); // Bit 7 = Stereo (we always use stereo) + const bool isStereo = (fileHeader.masterVolume & 0x80) != 0 || m_dwLastSavedWithVersion; + if(!isStereo) + m_nSamplePreAmp = Util::muldivr_unsigned(m_nSamplePreAmp, 8, 11); + // Approximately as loud as in DOSBox and a real SoundBlaster 16 m_nVSTiVolume = 36; if(isSchism && fileHeader.cwtv < SchismVersionFromDate<2018, 11, 12>::Version(S3MFileHeader::trkSchismTracker)) @@ -421,7 +438,8 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) if(fileHeader.channels[i] != 0xFF) { m_nChannels = i + 1; - ChnSettings[i].nPan = (ctype & 8) ? 0xCC : 0x33; // 200 : 56 + if(isStereo) + ChnSettings[i].nPan = (ctype & 8) ? 0xCC : 0x33; // 200 : 56 } if(fileHeader.channels[i] & 0x80) { @@ -695,7 +713,7 @@ bool CSoundFile::SaveS3M(std::ostream &f) const fileHeader.speed = static_cast(Clamp(m_nDefaultSpeed, 1u, 254u)); fileHeader.tempo = static_cast(Clamp(m_nDefaultTempo.GetInt(), 33u, 255u)); fileHeader.masterVolume = static_cast(Clamp(m_nSamplePreAmp, 16u, 127u) | 0x80); - fileHeader.ultraClicks = 8; + fileHeader.ultraClicks = 16; fileHeader.usePanningTable = S3MFileHeader::idPanning; mpt::IO::Write(f, fileHeader); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/OggStream.h b/Frameworks/OpenMPT/OpenMPT/soundlib/OggStream.h index c11b4b92d..54d678500 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/OggStream.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/OggStream.h @@ -31,7 +31,7 @@ struct PageHeader uint8le header_type; uint64le granule_position; uint32le bitstream_serial_number; - uint32le page_seqauence_number; + uint32le page_sequence_number; uint32le CRC_checksum; uint8le page_segments; }; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/S3MTools.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/S3MTools.cpp index 5245e2506..a41470bf6 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/S3MTools.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/S3MTools.cpp @@ -52,9 +52,14 @@ void S3MSampleHeader::ConvertToMPT(ModSample &mptSmp, bool isST3) const // C-5 frequency mptSmp.nC5Speed = c5speed; - // ST3 ignores the high 16 bits if(isST3) - mptSmp.nC5Speed &= 0xFFFF; + { + // ST3 ignores or clamps the high 16 bits depending on the instrument type + if(sampleType == typeAdMel) + mptSmp.nC5Speed &= 0xFFFF; + else + LimitMax(mptSmp.nC5Speed, uint16_max); + } if(mptSmp.nC5Speed == 0) mptSmp.nC5Speed = 8363; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatMP3.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatMP3.cpp index b33e3f8e6..aacc2cdc1 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatMP3.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatMP3.cpp @@ -53,7 +53,14 @@ typedef off_t mpg123_off_t; typedef size_t mpg123_size_t; +// Check for exactly _MSC_VER as libmpg123 does, in order to also catch clang-cl. +#ifdef _MSC_VER +// ssize_t definition in libmpg123.h.in should never have existed at all. +// It got removed from libmpg23.h.in after 1.28.0 and before 1.28.1. +typedef ptrdiff_t mpg123_ssize_t; +#else typedef ssize_t mpg123_ssize_t; +#endif class ComponentMPG123 : public ComponentBuiltin diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp index e65c5bb30..898b1e264 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp @@ -1928,8 +1928,7 @@ bool CSoundFile::ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file, bool mayN // Read SSND chunk FileReader soundChunk(chunks.GetChunk(AIFFChunk::idSSND)); AIFFSoundChunk sampleHeader; - if(!soundChunk.ReadStruct(sampleHeader) - || !soundChunk.CanRead(sampleHeader.offset)) + if(!soundChunk.ReadStruct(sampleHeader)) { return false; } @@ -1950,7 +1949,7 @@ bool CSoundFile::ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file, bool mayN endian, SampleIO::signedPCM); - if(!memcmp(compression, "fl32", 4) || !memcmp(compression, "FL32", 4) || !memcmp(compression, "fl64", 4)) + if(!memcmp(compression, "fl32", 4) || !memcmp(compression, "FL32", 4) || !memcmp(compression, "fl64", 4) || !memcmp(compression, "FL64", 4)) { sampleIO |= SampleIO::floatPCM; } else if(!memcmp(compression, "alaw", 4) || !memcmp(compression, "ALAW", 4)) @@ -1961,6 +1960,9 @@ bool CSoundFile::ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file, bool mayN { sampleIO |= SampleIO::uLaw; sampleIO |= SampleIO::_16bit; + } else if(!memcmp(compression, "raw ", 4)) + { + sampleIO |= SampleIO::unsignedPCM; } if(mayNormalize) @@ -1968,7 +1970,10 @@ bool CSoundFile::ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file, bool mayN sampleIO.MayNormalize(); } - soundChunk.Skip(sampleHeader.offset); + if(soundChunk.CanRead(sampleHeader.offset)) + { + soundChunk.Skip(sampleHeader.offset); + } ModSample &mptSample = Samples[nSample]; DestroySampleThreadsafe(nSample); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp index 8d7875798..7d6d8d480 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp @@ -279,11 +279,6 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod forbiddenCommands.set(CMD_NOTESLIDEDOWN); forbiddenCommands.set(CMD_NOTESLIDEDOWNRETRIG); forbiddenVolCommands.set(VOLCMD_PORTAUP); forbiddenVolCommands.set(VOLCMD_PORTADOWN); - // Optimize away channels for which it's pointless to adjust sample positions - for(CHANNELINDEX i = 0; i < GetNumChannels(); i++) - { - if(ChnSettings[i].dwFlags[CHN_MUTE]) memory.chnSettings[i].ticksToRender = GetLengthMemory::IGNORE_CHANNEL; - } if(target.mode == GetLengthTarget::SeekPosition && target.pos.order < orderList.size()) { // If we know where to seek, we can directly rule out any channels on which a new note would be triggered right at the start. diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.h b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.h index b3cf850cd..60710701d 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.h @@ -954,6 +954,8 @@ public: void SetSpeed(PlayState &playState, uint32 param) const; static TEMPO ConvertST2Tempo(uint8 tempo); + void ProcessRamping(ModChannel &chn) const; + protected: // Global variable initializer for loader functions void SetType(MODTYPE type); @@ -985,8 +987,6 @@ protected: void ProcessVibrato(CHANNELINDEX nChn, int &period, Tuning::RATIOTYPE &vibratoFactor); void ProcessSampleAutoVibrato(ModChannel &chn, int &period, Tuning::RATIOTYPE &vibratoFactor, int &nPeriodFrac) const; - void ProcessRamping(ModChannel &chn) const; - SamplePosition GetChannelIncrement(const ModChannel &chn, uint32 period, int periodFrac) const; protected: diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.cpp index f404772cd..bfb3b66f5 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.cpp @@ -292,7 +292,7 @@ void LFOPlugin::SaveAllParameters() return; m_pMixStruct->defaultProgram = -1; - m_pMixStruct->pluginData.assign(chunk.cbegin(), chunk.cend()); + m_pMixStruct->pluginData.assign(chunk.begin(), chunk.end()); } diff --git a/Frameworks/OpenMPT/OpenMPT/test/test.cpp b/Frameworks/OpenMPT/OpenMPT/test/test.cpp index bc92fdb51..7ecc733a2 100644 --- a/Frameworks/OpenMPT/OpenMPT/test/test.cpp +++ b/Frameworks/OpenMPT/OpenMPT/test/test.cpp @@ -2154,6 +2154,61 @@ static MPT_NOINLINE void TestMisc2() VERIFY_EQUAL(uri.query, U_("")); VERIFY_EQUAL(uri.fragment, U_("")); } + { + URI uri = ParseURI(U_("scheme://host")); + VERIFY_EQUAL(uri.scheme, U_("scheme")); + VERIFY_EQUAL(uri.username, U_("")); + VERIFY_EQUAL(uri.password, U_("")); + VERIFY_EQUAL(uri.host, U_("host")); + VERIFY_EQUAL(uri.port, U_("")); + VERIFY_EQUAL(uri.path, U_("")); + VERIFY_EQUAL(uri.query, U_("")); + VERIFY_EQUAL(uri.fragment, U_("")); + } + { + URI uri = ParseURI(U_("scheme://host?query")); + VERIFY_EQUAL(uri.scheme, U_("scheme")); + VERIFY_EQUAL(uri.username, U_("")); + VERIFY_EQUAL(uri.password, U_("")); + VERIFY_EQUAL(uri.host, U_("host")); + VERIFY_EQUAL(uri.port, U_("")); + VERIFY_EQUAL(uri.path, U_("")); + VERIFY_EQUAL(uri.query, U_("query")); + VERIFY_EQUAL(uri.fragment, U_("")); + } + { + URI uri = ParseURI(U_("scheme://host#fragment")); + VERIFY_EQUAL(uri.scheme, U_("scheme")); + VERIFY_EQUAL(uri.username, U_("")); + VERIFY_EQUAL(uri.password, U_("")); + VERIFY_EQUAL(uri.host, U_("host")); + VERIFY_EQUAL(uri.port, U_("")); + VERIFY_EQUAL(uri.path, U_("")); + VERIFY_EQUAL(uri.query, U_("")); + VERIFY_EQUAL(uri.fragment, U_("fragment")); + } + { + URI uri = ParseURI(U_("scheme://host?#")); + VERIFY_EQUAL(uri.scheme, U_("scheme")); + VERIFY_EQUAL(uri.username, U_("")); + VERIFY_EQUAL(uri.password, U_("")); + VERIFY_EQUAL(uri.host, U_("host")); + VERIFY_EQUAL(uri.port, U_("")); + VERIFY_EQUAL(uri.path, U_("")); + VERIFY_EQUAL(uri.query, U_("")); + VERIFY_EQUAL(uri.fragment, U_("")); + } + { + URI uri = ParseURI(U_("scheme://host#?")); + VERIFY_EQUAL(uri.scheme, U_("scheme")); + VERIFY_EQUAL(uri.username, U_("")); + VERIFY_EQUAL(uri.password, U_("")); + VERIFY_EQUAL(uri.host, U_("host")); + VERIFY_EQUAL(uri.port, U_("")); + VERIFY_EQUAL(uri.path, U_("")); + VERIFY_EQUAL(uri.query, U_("")); + VERIFY_EQUAL(uri.fragment, U_("?")); + } { URI uri = ParseURI(U_("scheme://username:password@[2001:db8::1]:port/path?query#fragment")); VERIFY_EQUAL(uri.scheme, U_("scheme"));