From baace3fea97662ecc5c4b579a4b9dd85a9f1fc67 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Mon, 9 Apr 2018 15:54:31 -0700 Subject: [PATCH] Updated libopenmpt to version 0.3.8. --- .../OpenMPT/OpenMPT/common/BuildSettings.h | 2 +- .../OpenMPT/OpenMPT/common/FileReader.h | 3 +- Frameworks/OpenMPT/OpenMPT/common/mptString.h | 26 ++-- .../OpenMPT/OpenMPT/common/versionNumber.h | 4 +- .../OpenMPT/include/minimp3/OpenMPT.txt | 1 + .../OpenMPT/OpenMPT/include/minimp3/libc.h | 2 +- .../OpenMPT/include/stb_vorbis/OpenMPT.txt | 6 +- .../OpenMPT/include/stb_vorbis/stb_vorbis.c | 83 +++++++----- .../OpenMPT/libopenmpt/dox/changelog.md | 33 +++++ .../OpenMPT/libopenmpt/dox/dependencies.md | 1 + .../OpenMPT/libopenmpt/libopenmpt_version.h | 2 +- .../OpenMPT/libopenmpt/libopenmpt_version.mk | 4 +- .../OpenMPT/libopenmpt/xmp-openmpt.cpp | 15 ++- .../soundbase/SampleFormatConverters.h | 14 +- .../OpenMPT/OpenMPT/soundlib/Dlsbank.cpp | 5 +- .../OpenMPT/OpenMPT/soundlib/Load_dbm.cpp | 21 +-- .../OpenMPT/OpenMPT/soundlib/Load_dsm.cpp | 28 ++-- .../OpenMPT/OpenMPT/soundlib/Load_dtm.cpp | 24 +++- .../OpenMPT/OpenMPT/soundlib/Load_imf.cpp | 10 +- .../OpenMPT/OpenMPT/soundlib/Load_it.cpp | 7 +- .../OpenMPT/OpenMPT/soundlib/Load_med.cpp | 9 +- .../OpenMPT/OpenMPT/soundlib/Load_mid.cpp | 2 +- .../OpenMPT/OpenMPT/soundlib/Load_mod.cpp | 2 +- .../OpenMPT/OpenMPT/soundlib/Load_s3m.cpp | 2 +- .../OpenMPT/OpenMPT/soundlib/Load_stm.cpp | 9 +- .../OpenMPT/OpenMPT/soundlib/MixerLoops.cpp | 10 ++ .../OpenMPT/soundlib/ModInstrument.cpp | 5 + .../OpenMPT/soundlib/SampleFormats.cpp | 17 ++- .../OpenMPT/OpenMPT/soundlib/Snd_flt.cpp | 14 +- .../OpenMPT/OpenMPT/soundlib/Snd_fx.cpp | 125 ++++++++---------- .../OpenMPT/OpenMPT/soundlib/Sndfile.cpp | 11 +- .../OpenMPT/OpenMPT/soundlib/Sndmix.cpp | 6 +- .../soundlib/plugins/PlugInterface.cpp | 4 +- 33 files changed, 313 insertions(+), 194 deletions(-) diff --git a/Frameworks/OpenMPT/OpenMPT/common/BuildSettings.h b/Frameworks/OpenMPT/OpenMPT/common/BuildSettings.h index 82631e0b3..d6b64fbbe 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/BuildSettings.h +++ b/Frameworks/OpenMPT/OpenMPT/common/BuildSettings.h @@ -473,7 +473,7 @@ #endif // arch #endif // ENABLE_ASM -#if defined(MPT_WITH_MPG123) && defined(MPT_BUILD_MSVC) && defined(MPT_BUILD_MSVC_STATIC) && !MPT_OS_WINDOWS_WINRT +#if defined(MPT_WITH_MPG123) && defined(MPT_BUILD_MSVC) && defined(MPT_BUILD_MSVC_STATIC) && !defined(LIBOPENMPT_NODELAYLOAD) && !MPT_OS_WINDOWS_WINRT #define MPT_ENABLE_MPG123_DELAYLOAD #endif diff --git a/Frameworks/OpenMPT/OpenMPT/common/FileReader.h b/Frameworks/OpenMPT/OpenMPT/common/FileReader.h index 200fcd21c..188c32a05 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/FileReader.h +++ b/Frameworks/OpenMPT/OpenMPT/common/FileReader.h @@ -349,8 +349,9 @@ public: } public: PinnedRawDataView() + : size_(0) + , pinnedData(nullptr) { - return; } PinnedRawDataView(const FileReader &file) { diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptString.h b/Frameworks/OpenMPT/OpenMPT/common/mptString.h index 157a0e49b..ea7bbaad7 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptString.h +++ b/Frameworks/OpenMPT/OpenMPT/common/mptString.h @@ -559,25 +559,33 @@ private: static mpt::ustring From8bit(const std::string &str) { - if(charset == mpt::CharsetUTF8) - { - return mpt::ToUnicode(mpt::CharsetUTF8, str); - } - // auto utf8 detection - if(tryUTF8 && mpt::IsUTF8(str)) + MPT_CONSTANT_IF(charset == mpt::CharsetUTF8) { return mpt::ToUnicode(mpt::CharsetUTF8, str); } else { - return mpt::ToUnicode(charset, str); + // auto utf8 detection + MPT_CONSTANT_IF(tryUTF8) + { + if(mpt::IsUTF8(str)) + { + return mpt::ToUnicode(mpt::CharsetUTF8, str); + } else + { + return mpt::ToUnicode(charset, str); + } + } else + { + return mpt::ToUnicode(charset, str); + } } } public: // 8 bit - BasicAnyString(const char *str) : mpt::ustring(str ? mpt::ToUnicode(charset, str) : mpt::ustring()) { } - BasicAnyString(const std::string str) : mpt::ustring(mpt::ToUnicode(charset, str)) { } + BasicAnyString(const char *str) : mpt::ustring(From8bit(str ? str : std::string())) { } + BasicAnyString(const std::string str) : mpt::ustring(From8bit(str)) { } // unicode BasicAnyString(const mpt::ustring &str) : mpt::ustring(str) { } diff --git a/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h b/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h index 58a40b787..797811e72 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h +++ b/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h @@ -18,8 +18,8 @@ OPENMPT_NAMESPACE_BEGIN //Version definitions. The only thing that needs to be changed when changing version number. #define VER_MAJORMAJOR 1 #define VER_MAJOR 27 -#define VER_MINOR 04 -#define VER_MINORMINOR 02 +#define VER_MINOR 07 +#define VER_MINORMINOR 00 //Version string. For example "1.17.02.28" #define MPT_VERSION_STR VER_STRINGIZE(VER_MAJORMAJOR) "." VER_STRINGIZE(VER_MAJOR) "." VER_STRINGIZE(VER_MINOR) "." VER_STRINGIZE(VER_MINORMINOR) diff --git a/Frameworks/OpenMPT/OpenMPT/include/minimp3/OpenMPT.txt b/Frameworks/OpenMPT/OpenMPT/include/minimp3/OpenMPT.txt index 4d536900e..04488f866 100644 --- a/Frameworks/OpenMPT/OpenMPT/include/minimp3/OpenMPT.txt +++ b/Frameworks/OpenMPT/OpenMPT/include/minimp3/OpenMPT.txt @@ -4,6 +4,7 @@ The following changes have been made: - mp3_create() declaration has been fixed. - GET_DATA() has been rewritten to avoid unaligned access warnings. - Signed/unsigned comparison warnings have been fixed. +- Detection of stdint types has been fixed to work on *BSD. - Modifications have been marked with // OpenMPT - Obviously, unnecessary folders and files have been removed. - For building, premake is used to generate Visual Studio project files. diff --git a/Frameworks/OpenMPT/OpenMPT/include/minimp3/libc.h b/Frameworks/OpenMPT/OpenMPT/include/minimp3/libc.h index 45fca6092..0426f0e73 100644 --- a/Frameworks/OpenMPT/OpenMPT/include/minimp3/libc.h +++ b/Frameworks/OpenMPT/OpenMPT/include/minimp3/libc.h @@ -42,7 +42,7 @@ #endif #include -#ifndef __int8_t_defined +#if !defined(__int8_t_defined) && !defined(_INT8_T_DECLARED) /* OpenMPT */ #define __int8_t_defined typedef unsigned char uint8_t; typedef signed char int8_t; diff --git a/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/OpenMPT.txt b/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/OpenMPT.txt index d8319f644..12c993dc0 100644 --- a/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/OpenMPT.txt +++ b/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/OpenMPT.txt @@ -1,6 +1,6 @@ -This folder contains the stb_vorbis library from -https://github.com/nothings/stb/blob/master/stb_vorbis.c -(commit 9d9f75eb682dd98b34de08bb5c489c6c561c9fa6) +This folder contains the stb_vorbis library from +https://github.com/nothings/stb/blob/master/stb_vorbis.c v1.14 +commit e6afb9cbae4064da8c3e69af3ff5c4629579c1d2 (2018-02-11) Modifications: * Use of alloca has been replaced with malloc, as alloca is not in C99 and diff --git a/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/stb_vorbis.c b/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/stb_vorbis.c index 43f343b5b..5c5df6154 100644 --- a/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/stb_vorbis.c +++ b/Frameworks/OpenMPT/OpenMPT/include/stb_vorbis/stb_vorbis.c @@ -1,11 +1,11 @@ -// Ogg Vorbis audio decoder - v1.11 - public domain +// Ogg Vorbis audio decoder - v1.14 - public domain // http://nothings.org/stb_vorbis/ // // Original version written by Sean Barrett in 2007. // -// Originally sponsored by RAD Game Tools. Seeking sponsored -// by Phillip Bennefall, Marc Andersen, Aaron Baker, Elias Software, -// Aras Pranckevicius, and Sean Barrett. +// Originally sponsored by RAD Game Tools. Seeking implementation +// sponsored by Phillip Bennefall, Marc Andersen, Aaron Baker, +// Elias Software, Aras Pranckevicius, and Sean Barrett. // // LICENSE // @@ -30,22 +30,26 @@ // Tom Beaumont Ingo Leitgeb Nicolas Guillemot // Phillip Bennefall Rohit Thiago Goulart // manxorist@github saga musix github:infatum +// Timur Gagiev // // Partial history: -// 1.11 - 2017/07/23 - fix MinGW compilation -// 1.10 - 2017/03/03 - more robust seeking; fix negative ilog(); clear error in open_memory -// 1.09 - 2016/04/04 - back out 'truncation of last frame' fix from previous version -// 1.08 - 2016/04/02 - warnings; setup memory leaks; truncation of last frame -// 1.07 - 2015/01/16 - fixes for crashes on invalid files; warning fixes; const -// 1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson) +// 1.14 - 2018-02-11 - delete bogus dealloca usage +// 1.13 - 2018-01-29 - fix truncation of last frame (hopefully) +// 1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files +// 1.11 - 2017-07-23 - fix MinGW compilation +// 1.10 - 2017-03-03 - more robust seeking; fix negative ilog(); clear error in open_memory +// 1.09 - 2016-04-04 - back out 'truncation of last frame' fix from previous version +// 1.08 - 2016-04-02 - warnings; setup memory leaks; truncation of last frame +// 1.07 - 2015-01-16 - fixes for crashes on invalid files; warning fixes; const +// 1.06 - 2015-08-31 - full, correct support for seeking API (Dougall Johnson) // some crash fixes when out of memory or with corrupt files // fix some inappropriately signed shifts -// 1.05 - 2015/04/19 - don't define __forceinline if it's redundant -// 1.04 - 2014/08/27 - fix missing const-correct case in API -// 1.03 - 2014/08/07 - warning fixes -// 1.02 - 2014/07/09 - declare qsort comparison as explicitly _cdecl in Windows -// 1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float (interleaved was correct) -// 1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in >2-channel; +// 1.05 - 2015-04-19 - don't define __forceinline if it's redundant +// 1.04 - 2014-08-27 - fix missing const-correct case in API +// 1.03 - 2014-08-07 - warning fixes +// 1.02 - 2014-07-09 - declare qsort comparison as explicitly _cdecl in Windows +// 1.01 - 2014-06-18 - fix stb_vorbis_get_samples_float (interleaved was correct) +// 1.0 - 2014-05-26 - fix memory leaks; fix warnings; fix bugs in >2-channel; // (API change) report sample rate for decode-full-file funcs // // See end of file for full version history. @@ -885,11 +889,7 @@ static int error(vorb *f, enum STBVorbisError e) #if 0 // OpenMPT #define temp_alloc(f,size) (f->alloc.alloc_buffer ? setup_temp_malloc(f,size) : alloca(size)) -#ifdef dealloca -#define temp_free(f,p) (f->alloc.alloc_buffer ? 0 : dealloca(size)) -#else #define temp_free(f,p) 0 -#endif #else // OpenMPT #define temp_alloc(f,size) (f->alloc.alloc_buffer ? setup_temp_malloc(f,size) : malloc(size)) // OpenMPT #define temp_free(f,p) (f->alloc.alloc_buffer ? 0 : free(p)) // OpenMPT @@ -2051,6 +2051,8 @@ static int residue_decode(vorb *f, Codebook *book, float *target, int offset, in return TRUE; } +// n is 1/2 of the blocksize -- +// specification: "Correct per-vector decode length is [n]/2" static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode) { int i,j,pass; @@ -2058,7 +2060,10 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int int rtype = f->residue_types[rn]; int c = r->classbook; int classwords = f->codebooks[c].dimensions; - int n_read = r->end - r->begin; + unsigned int actual_size = rtype == 2 ? n*2 : n; + unsigned int limit_r_begin = (r->begin < actual_size ? r->begin : actual_size); + unsigned int limit_r_end = (r->end < actual_size ? r->end : actual_size); + int n_read = limit_r_end - limit_r_begin; int part_read = n_read / r->part_size; int temp_alloc_point = temp_alloc_save(f); #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE @@ -3400,7 +3405,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, if (f->last_seg_which == f->end_seg_with_known_loc) { // if we have a valid current loc, and this is final: if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) { - uint32 current_end = f->known_loc_for_packet - (n-right_end); + uint32 current_end = f->known_loc_for_packet; // then let's infer the size of the (probably) short final frame if (current_end < f->current_loc + (right_end-left_start)) { if (current_end < f->current_loc) { @@ -3409,7 +3414,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, } else { *len = current_end - f->current_loc; } - *len += left_start; + *len += left_start; // this doesn't seem right, but has no ill effect on my test files if (*len > right_end) *len = right_end; // this should never happen f->current_loc += *len; return TRUE; @@ -4064,6 +4069,7 @@ static int start_decoder(vorb *f) f->previous_window[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2); f->finalY[i] = (int16 *) setup_malloc(f, sizeof(int16) * longest_floorlist); if (f->channel_buffers[i] == NULL || f->previous_window[i] == NULL || f->finalY[i] == NULL) return error(f, VORBIS_outofmem); + memset(f->channel_buffers[i], 0, sizeof(float) * f->blocksize_1); #ifdef STB_VORBIS_NO_DEFER_FLOOR f->floor_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2); if (f->floor_buffers[i] == NULL) return error(f, VORBIS_outofmem); @@ -4091,7 +4097,10 @@ static int start_decoder(vorb *f) int i,max_part_read=0; for (i=0; i < f->residue_count; ++i) { Residue *r = f->residue_config + i; - int n_read = r->end - r->begin; + unsigned int actual_size = f->blocksize_1 / 2; + unsigned int limit_r_begin = r->begin < actual_size ? r->begin : actual_size; + unsigned int limit_r_end = r->end < actual_size ? r->end : actual_size; + int n_read = limit_r_end - limit_r_begin; int part_read = n_read / r->part_size; if (part_read > max_part_read) max_part_read = part_read; @@ -4102,6 +4111,8 @@ static int start_decoder(vorb *f) classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *)); #endif + // maximum reasonable partition size is f->blocksize_1 + f->temp_memory_required = classify_mem; if (imdct_mem > f->temp_memory_required) f->temp_memory_required = imdct_mem; @@ -5365,20 +5376,22 @@ int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, in #endif // STB_VORBIS_NO_PULLDATA_API /* Version history - 1.10 - 2017/03/03 - more robust seeking; fix negative ilog(); clear error in open_memory - 1.09 - 2016/04/04 - back out 'avoid discarding last frame' fix from previous version - 1.08 - 2016/04/02 - fixed multiple warnings; fix setup memory leaks; + 1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files + 1.11 - 2017-07-23 - fix MinGW compilation + 1.10 - 2017-03-03 - more robust seeking; fix negative ilog(); clear error in open_memory + 1.09 - 2016-04-04 - back out 'avoid discarding last frame' fix from previous version + 1.08 - 2016-04-02 - fixed multiple warnings; fix setup memory leaks; avoid discarding last frame of audio data - 1.07 - 2015/01/16 - fixed some warnings, fix mingw, const-correct API + 1.07 - 2015-01-16 - fixed some warnings, fix mingw, const-correct API some more crash fixes when out of memory or with corrupt files - 1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson) + 1.06 - 2015-08-31 - full, correct support for seeking API (Dougall Johnson) some crash fixes when out of memory or with corrupt files - 1.05 - 2015/04/19 - don't define __forceinline if it's redundant - 1.04 - 2014/08/27 - fix missing const-correct case in API - 1.03 - 2014/08/07 - Warning fixes - 1.02 - 2014/07/09 - Declare qsort compare function _cdecl on windows - 1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float - 1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in multichannel + 1.05 - 2015-04-19 - don't define __forceinline if it's redundant + 1.04 - 2014-08-27 - fix missing const-correct case in API + 1.03 - 2014-08-07 - Warning fixes + 1.02 - 2014-07-09 - Declare qsort compare function _cdecl on windows + 1.01 - 2014-06-18 - fix stb_vorbis_get_samples_float + 1.0 - 2014-05-26 - fix memory leaks; fix warnings; fix bugs in multichannel (API change) report sample rate for decode-full-file funcs 0.99996 - bracket #include for macintosh compilation by Laurent Gomila 0.99995 - use union instead of pointer-cast for fast-float-to-int to avoid alias-optimization problem diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/changelog.md b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/changelog.md index 1dda37ac2..e37bd70ad 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/changelog.md +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/changelog.md @@ -5,6 +5,39 @@ Changelog {#changelog} For fully detailed change log, please see the source repository directly. This is just a high-level summary. +### libopenmpt 0.3.8 (2018-04-08) + + * [**Sec**] Possible out-of-bounds memory read with IT / ITP / MO3 files + containing pattern loops (r10028). + + * Keep track of active SFx macro during seeking. + * The "note cut" duplicate note action did not volume-ramp the previously + playing sample. + * A song starting with non-existing patterns could not be played. + * DSM: Support restart position and 16-bit samples. + * DTM: Import global volume. + +### libopenmpt 0.3.7 (2018-03-11) + + * [**Bug**] libopenmpt did not build with NDK r13b on armeabi due to missing + `-latomic`. + * [**Bug**] xmp-openmpt: Sample rate and number of output channels were not + applied correctly when using per-file settings. + + * [**Change**] foo_openmpt: foo_openmpt is now packaged as a fb2k-component + package for easier installation. + + * IT: More accurate song length calculation for pattern loops that have no + start command and are following another pattern loop. + * IMF: Filter cutoff was upside down and the cutoff range was too small. + * MED: Correctly import patterns with less channels than the maximum used + amount. Import "STP" note stop command. + * DBM: Key Off and Set Envelope Position were imported incorrectly. + High sample offset (E7x) is now supported. + * DIGI / DBM: Arpeggio should not return to base note at end of row. + * Some filter changes through MIDI macros were not applied if the note volume + was set to 0 on the same row. + ### libopenmpt 0.3.6 (2018-02-03) * [**Sec**] Possible out-of-bounds memory read with malformed STP files. diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/dependencies.md b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/dependencies.md index d68956202..c06634bbd 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/dependencies.md +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/dependencies.md @@ -38,6 +38,7 @@ Dependencies particular: * `char` can be `signed` or `unsigned` * shifting signed values is implementation defined + * `signed` integer overflow is undefined * `float` and `double` can be non-IEEE754 * Required compilers to use libopenmpt: diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h index dbc1afe35..833258a94 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 3 /*! \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 */ diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.mk b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.mk index a3d74c71f..70e881fd0 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=3 -LIBOPENMPT_VERSION_PATCH=6 +LIBOPENMPT_VERSION_PATCH=8 LIBOPENMPT_VERSION_PREREL= LIBOPENMPT_LTVER_CURRENT=1 -LIBOPENMPT_LTVER_REVISION=6 +LIBOPENMPT_LTVER_REVISION=8 LIBOPENMPT_LTVER_AGE=1 diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt.cpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt.cpp index 0787fdc3b..1bf010804 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt.cpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt.cpp @@ -163,6 +163,7 @@ struct self_xmplay_t { std::size_t num_channels; xmp_openmpt_settings settings; openmpt::module_ext * mod; + bool set_format_called; openmpt::ext::pattern_vis * pattern_vis; std::int32_t tempo_factor, pitch_factor; bool single_subsong_mode; @@ -171,6 +172,7 @@ struct self_xmplay_t { , num_channels(2) , settings() , mod(0) + , set_format_called(false) , pattern_vis(0) , tempo_factor(0) , pitch_factor(0) @@ -179,11 +181,13 @@ struct self_xmplay_t { settings.changed = apply_and_save_options; } void on_new_mod() { + set_format_called = false; self->pattern_vis = static_cast( self->mod->get_interface( openmpt::ext::pattern_vis_id ) ); } void delete_mod() { if ( mod ) { pattern_vis = 0; + set_format_called = false; delete mod; mod = 0; } @@ -310,6 +314,12 @@ static void save_settings_to_xml( std::string & xml, const libopenmpt::plugin::s static void apply_options() { if ( self->mod ) { + if ( !self->set_format_called ) { + // SetFormat will only be called once after loading a file. + // We cannot apply samplerate or numchannels changes afterwards during playback. + self->samplerate = self->settings.samplerate; + self->num_channels = self->settings.channels; + } self->mod->set_repeat_count( self->settings.repeatcount ); self->mod->set_render_param( openmpt::module::RENDER_MASTERGAIN_MILLIBEL, self->settings.mastergain_millibel ); self->mod->set_render_param( openmpt::module::RENDER_STEREOSEPARATION_PERCENT, self->settings.stereoseparation ); @@ -893,8 +903,6 @@ static DWORD WINAPI openmpt_Open( const char * filename, XMPFILE file ) { clear_current_timeinfo(); reset_timeinfos(); apply_options(); - self->samplerate = self->settings.samplerate; - self->num_channels = self->settings.channels; std::int32_t num_subsongs = self->mod->get_num_subsongs(); self->subsong_lengths.resize( num_subsongs ); @@ -926,6 +934,9 @@ static void WINAPI openmpt_SetFormat( XMPFORMAT * form ) { if ( !form ) { return; } + // SetFormat will only be called once after loading a file. + // We cannot apply samplerate or numchannels changes afterwards during playback. + self->set_format_called = true; if ( !self->mod ) { form->rate = 0; form->chan = 0; diff --git a/Frameworks/OpenMPT/OpenMPT/soundbase/SampleFormatConverters.h b/Frameworks/OpenMPT/OpenMPT/soundbase/SampleFormatConverters.h index f6a9bba13..a10e54652 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundbase/SampleFormatConverters.h +++ b/Frameworks/OpenMPT/OpenMPT/soundbase/SampleFormatConverters.h @@ -675,12 +675,7 @@ struct Convert { Limit(val, -1.0f, 1.0f); val *= static_cast(uint64(1)<<63); -#if MPT_SC_AVOID_FLOOR - // MSVC with x87 floating point math calls floor for the more intuitive version - return mpt::saturate_cast(MPT_SC_RSHIFT_SIGNED(static_cast(val * 2.0f + 1.0f), 1)); -#else - return mpt::saturate_cast(static_cast(std::floor(val + 0.5f))); -#endif + return mpt::saturate_cast(std::floor(val + 0.5f)); } }; @@ -693,12 +688,7 @@ struct Convert { Limit(val, -1.0, 1.0); val *= static_cast(uint64(1)<<63); -#if MPT_SC_AVOID_FLOOR - // MSVC with x87 floating point math calls floor for the more intuitive version - return mpt::saturate_cast(MPT_SC_RSHIFT_SIGNED(static_cast(val * 2.0 + 1.0), 1)); -#else - return mpt::saturate_cast(static_cast(std::floor(val + 0.5))); -#endif + return mpt::saturate_cast(std::floor(val + 0.5)); } }; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp index d1841cd7d..5a8d17226 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp @@ -446,7 +446,7 @@ static uint8 DLSSustainLevelToLinear(int32 sustain) if(sustain >= 0) { int32 l = sustain / (1000 * 512); - if(l >= 0 || l <= 128) + if(l >= 0 && l <= 128) return static_cast(l); } return 128; @@ -1885,6 +1885,8 @@ bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, ui int32 lSusLevel = - DLS32BitRelativeLinearToGain(lStartFactor << 10) / 65536; int32 lDecayEndTime = (lReleaseTime * lSusLevel) / 960; lReleaseTime -= lDecayEndTime; + if(pIns->VolEnv.nSustainEnd > 0) + pIns->VolEnv.nReleaseNode = pIns->VolEnv.nSustainEnd; for (uint32 i=0; i<5; i++) { int32 lFactor = 1 + ((lStartFactor * 3) >> (i+2)); @@ -1930,6 +1932,7 @@ bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, ui pIns->VolEnv[3] = EnvelopeNode(pIns->VolEnv[2].tick * 2u, ENVELOPE_MIN); // 1 second max. for drums } } + pIns->Convert(MOD_TYPE_MPT, sndFile.GetType()); return true; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dbm.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dbm.cpp index 890a8eb7a..1b86cb1b2 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dbm.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dbm.cpp @@ -133,8 +133,8 @@ static const ModCommand::COMMAND dbmEffects[] = CMD_VIBRATO, CMD_TONEPORTAVOL, CMD_VIBRATOVOL, CMD_TREMOLO, CMD_PANNING8, CMD_OFFSET, CMD_VOLUMESLIDE, CMD_POSITIONJUMP, CMD_VOLUME, CMD_PATTERNBREAK, CMD_MODCMDEX, CMD_TEMPO, - CMD_GLOBALVOLUME, CMD_GLOBALVOLSLIDE, CMD_KEYOFF, CMD_SETENVPOSITION, - CMD_CHANNELVOLUME, CMD_CHANNELVOLSLIDE, CMD_NONE, CMD_NONE, + CMD_GLOBALVOLUME, CMD_GLOBALVOLSLIDE, CMD_NONE, CMD_NONE, + CMD_KEYOFF, CMD_SETENVPOSITION, CMD_NONE, CMD_NONE, CMD_NONE, CMD_PANNINGSLIDE, CMD_NONE, CMD_NONE, CMD_NONE, CMD_NONE, CMD_NONE, #ifndef NO_PLUGINS @@ -215,11 +215,11 @@ static void ConvertDBMEffect(uint8 &command, uint8 ¶m) param = (param == 0x50) ? 0x00 : 0x40; } break; - case 0x60: // set loop begin / loop - // TODO + case 0x60: // Pattern loop break; - case 0x70: // set offset - // TODO + case 0x70: // Coarse offset + command = CMD_S3MCMDEX; + param = 0xA0 | (param & 0x0F); break; default: // Rest will be converted later from CMD_MODCMDEX to CMD_S3MCMDEX. @@ -355,6 +355,7 @@ bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags) m_madeWithTracker = mpt::format(MPT_USTRING("DigiBooster Pro %1.%2"))(mpt::ufmt::hex(fileHeader.trkVerHi), mpt::ufmt::hex(fileHeader.trkVerLo)); m_playBehaviour.set(kSlidesAtSpeed1); m_playBehaviour.reset(kITVibratoTremoloPanbrello); + m_playBehaviour.reset(kITArpeggio); // Name chunk FileReader nameChunk = chunks.GetChunk(DBMChunk::idNAME); @@ -493,7 +494,7 @@ bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags) continue; } - ModCommand dummy; + ModCommand dummy = ModCommand::Empty(); ModCommand &m = ch <= GetNumChannels() ? patRow[ch - 1] : dummy; const uint8 b = chunk.ReadUint8(); @@ -668,7 +669,8 @@ bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags) { ModSample &srcSample = Samples[0]; const int8 *smpData = srcSample.pSample8; - uint32 predelay = Util::muldiv_unsigned(20116, srcSample.nC5Speed, 100000); + SmpLength predelay = Util::muldiv_unsigned(20116, srcSample.nC5Speed, 100000); + LimitMax(predelay, srcSample.nLength); smpData += predelay * srcSample.GetBytesPerSample(); srcSample.nLength -= predelay; @@ -683,7 +685,8 @@ bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags) memcpy(sample.pSample, smpData, sample.GetSampleSizeInBytes()); smpData += sample.GetSampleSizeInBytes(); srcSample.nLength -= sample.nLength; - uint32 gap = Util::muldiv_unsigned(454, srcSample.nC5Speed, 10000); + SmpLength gap = Util::muldiv_unsigned(454, srcSample.nC5Speed, 10000); + LimitMax(gap, srcSample.nLength); smpData += gap * srcSample.GetBytesPerSample(); srcSample.nLength -= gap; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dsm.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dsm.cpp index 204ff03cc..d5a3db99c 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dsm.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dsm.cpp @@ -6,11 +6,13 @@ * MilkyTracker can load it, but the only files of this format seen in the wild are also * available in their original format, so I did not bother implementing it so far. * - * 2. Using PLAY.EXE v1.02, commands not supported in MOD do not seem to do anything at all. + * 2. Using both PLAY.EXE v1.02 and v2.00, commands not supported in MOD do not seem to do + * anything at all. * In particular commands 0x11-0x13 handled below are ignored, and no files have been spotted * in the wild using any commands > 0x0F at all. * S3M-style retrigger does not seem to exist - it is translated to volume slides by CONV.EXE, - * and J00 in S3M files is not converted either. + * and J00 in S3M files is not converted either. S3M pattern loops (SBx) are not converted + * properly by CONV.EXE and completely ignored by PLAY.EXE. * Command 8 (set panning) uses 00-80 for regular panning and A4 for surround, probably * making DSIK one of the first applications to use this particular encoding scheme still * used in "extended" S3Ms today. @@ -36,9 +38,10 @@ MPT_BINARY_STRUCT(DSMChunk, 8) struct DSMSongHeader { char songName[28]; - char reserved1[2]; + uint16le fileVersion; uint16le flags; - char reserved2[4]; + uint16le orderPos; + uint16le restartPos; uint16le numOrders; uint16le numSamples; uint16le numPatterns; @@ -57,13 +60,12 @@ MPT_BINARY_STRUCT(DSMSongHeader, 192) struct DSMSampleHeader { char filename[13]; - uint8le flags; - char reserved1; + uint16le flags; uint8le volume; uint32le length; uint32le loopStart; uint32le loopEnd; - char reserved2[4]; + uint32le dataPtr; // Interal sample pointer during playback in DSIK uint32le sampleRate; char sampleName[28]; @@ -93,6 +95,8 @@ struct DSMSampleHeader sampleIO |= SampleIO::deltaPCM; // fairlight.dsm by Comrade J else if(flags & 0x02) sampleIO |= SampleIO::signedPCM; + if(flags & 0x04) + sampleIO |= SampleIO::_16bit; return sampleIO; } }; @@ -197,10 +201,14 @@ bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags) DSMSongHeader songHeader; file.ReadStructPartial(songHeader, chunkHeader.size); + if(songHeader.numOrders > 128 || songHeader.numChannels > 16 || songHeader.numPatterns > 256 || songHeader.restartPos > 128) + { + return false; + } InitializeGlobals(MOD_TYPE_DSM); mpt::String::Read(m_songName, songHeader.songName); - m_nChannels = Clamp(songHeader.numChannels, 1, 16); + m_nChannels = std::max(songHeader.numChannels, 1); m_nDefaultSpeed = songHeader.speed; m_nDefaultTempo.Set(songHeader.bpm); m_nDefaultGlobalVolume = std::min(songHeader.globalVol, 64) * 4u; @@ -224,6 +232,8 @@ bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags) } ReadOrderFromArray(Order(), songHeader.orders, songHeader.numOrders, 0xFF, 0xFE); + if(songHeader.restartPos < songHeader.numOrders) + Order().SetRestartPos(songHeader.restartPos); // Read pattern and sample chunks PATTERNINDEX patNum = 0; @@ -240,6 +250,7 @@ bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags) } chunk.Skip(2); + ModCommand dummy = ModCommand::Empty(); ROWINDEX row = 0; PatternRow rowBase = Patterns[patNum].GetRow(0); while(chunk.CanRead(1) && row < 64) @@ -253,7 +264,6 @@ bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags) } CHANNELINDEX chn = (flag & 0x0F); - ModCommand dummy = ModCommand(); ModCommand &m = (chn < GetNumChannels() ? rowBase[chn] : dummy); if(flag & 0x80) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dtm.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dtm.cpp index e36110e92..c821d9335 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dtm.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dtm.cpp @@ -102,6 +102,7 @@ struct DTMSample if(formatVersion == DTM_206_PATTERN_FORMAT && transpose > 0 && transpose != 48) { // Digital Home Studio applies this unconditionally, but some old songs sound wrong then (delirium.dtm). + // Digital Tracker 2.03 ignores the setting. // Maybe this should not be applied for "real" Digital Tracker modules? transposeAmount += (48 - transpose) * 128; } @@ -292,7 +293,13 @@ bool CSoundFile::ReadDTM(FileReader &file, ModLoadingFlags loadFlags) ChnSettings[chn].nPan = static_cast(128 + Util::muldivr(std::min(panning[chn], 180) - 90, 128, 90)); } - chunk.Skip(146); + chunk.Skip(16); + // Chunk ends here for old DTM modules + if(chunk.CanRead(2)) + { + m_nDefaultGlobalVolume = std::min(chunk.ReadUint16BE(), MAX_GLOBAL_VOLUME); + } + chunk.Skip(128); uint16be volume[32]; if(chunk.ReadArray(volume)) { @@ -356,9 +363,10 @@ bool CSoundFile::ReadDTM(FileReader &file, ModLoadingFlags loadFlags) chunk.ReadStruct(instr); if(instr.insNum < GetNumInstruments()) { - Samples[instr.insNum + 1].nVibDepth = instr.vibDepth; - Samples[instr.insNum + 1].nVibRate = instr.vibRate; - Samples[instr.insNum + 1].nVibSweep = 255; + ModSample &sample = Samples[instr.insNum + 1]; + sample.nVibDepth = instr.vibDepth; + sample.nVibRate = instr.vibRate; + sample.nVibSweep = 255; ModInstrument *mptIns = AllocateInstrument(instr.insNum + 1, instr.insNum + 1); if(mptIns != nullptr) @@ -463,6 +471,8 @@ bool CSoundFile::ReadDTM(FileReader &file, ModLoadingFlags loadFlags) #ifdef MODPLUG_TRACKER m->Convert(MOD_TYPE_MOD, MOD_TYPE_IT, *this); #endif + // G is 8-bit volume + // P is tremor (need to disable oldfx) } if(data[5] & 0x80) tick += (data[5] & 0x7F) * 0x100 + rowChunk.ReadUint8(); @@ -562,12 +572,12 @@ bool CSoundFile::ReadDTM(FileReader &file, ModLoadingFlags loadFlags) // Read sample data for(auto &chunk : chunks.GetAllChunks(DTMChunk::idDAIT)) { - PATTERNINDEX smp = chunk.ReadUint16BE() + 1; - if(smp == 0 || smp > GetNumSamples() || !(loadFlags & loadSampleData)) + SAMPLEINDEX smp = chunk.ReadUint16BE(); + if(smp >= GetNumSamples() || !(loadFlags & loadSampleData)) { continue; } - ModSample &mptSmp = Samples[smp]; + ModSample &mptSmp = Samples[smp + 1]; SampleIO( mptSmp.uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, mptSmp.uFlags[CHN_STEREO] ? SampleIO::stereoInterleaved: SampleIO::mono, diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_imf.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_imf.cpp index 9192bc162..411689cb8 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_imf.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_imf.cpp @@ -138,9 +138,9 @@ struct IMFInstrument if(mptIns.PitchEnv.dwFlags[ENV_ENABLED]) mptIns.PitchEnv.dwFlags.set(ENV_FILTER); - // hack to get === to stop notes (from modplug's xm loader) + // hack to get === to stop notes if(!mptIns.VolEnv.dwFlags[ENV_ENABLED] && !mptIns.nFadeOut) - mptIns.nFadeOut = 8192; + mptIns.nFadeOut = 32767; } }; @@ -284,7 +284,7 @@ static void ImportIMFEffect(ModCommand &m) m.param |= 0xE0; break; case 0x16: // cutoff - m.param >>= 1; + m.param = (0xFF - m.param) / 2u; break; case 0x1F: // set global volume m.param = MIN(m.param << 1, 0xFF); @@ -361,9 +361,9 @@ static bool ValidateHeader(const IMFFileHeader &fileHeader) return false; } bool channelFound = false; - for(uint8 chn = 0; chn < 32; chn++) + for(const auto &chn : fileHeader.channels) { - switch(fileHeader.channels[chn].status) + switch(chn.status) { case 0: // enabled; don't worry about it channelFound = true; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_it.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_it.cpp index dc0a7a6bd..da8e1d8cc 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_it.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_it.cpp @@ -1039,7 +1039,7 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) } // Now we grab the data for this particular row/channel. - ModCommand dummy; + ModCommand dummy = ModCommand::Empty(); ModCommand &m = ch < m_nChannels ? patData[ch] : dummy; if(chnMask[ch] & 0x10) @@ -1226,7 +1226,10 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) m_madeWithTracker = MPT_USTRING("BeRoTracker"); break; case 7: - m_madeWithTracker = mpt::format(MPT_USTRING("ITMCK %1.%2.%3"))((fileHeader.cwtv >> 8) & 0x0F, (fileHeader.cwtv >> 4) & 0x0F, fileHeader.cwtv & 0x0F); + if(fileHeader.cwtv == 0x7FFF && fileHeader.cmwt == 0x0215) + m_madeWithTracker = MPT_USTRING("munch.py"); + else + m_madeWithTracker = mpt::format(MPT_USTRING("ITMCK %1.%2.%3"))((fileHeader.cwtv >> 8) & 0x0F, (fileHeader.cwtv >> 4) & 0x0F, fileHeader.cwtv & 0x0F); break; case 0xD: m_madeWithTracker = MPT_USTRING("spc2it"); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_med.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_med.cpp index 332d12f4e..466a84980 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_med.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_med.cpp @@ -833,12 +833,12 @@ bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags) tracks = pmb->numtracks; if (!tracks) tracks = m_nChannels; if(!Patterns.Insert(iBlk, lines)) continue; - auto p = Patterns[iBlk].begin(); const uint8 * s = (const uint8 *)(lpStream + dwPos + 2); uint32 maxlen = tracks*lines*3; if (maxlen + dwPos > dwMemLength - 2) break; for (uint32 y=0; y dwMemLength - 8 || !Patterns.IsValidPat(iBlk)) break; - auto p = Patterns[iBlk].begin(); for (uint32 y=0; y NOTE_MAX) rnote = NOTE_MAX; p->note = (uint8)rnote; + } else if(note == 0x80) + { + p->note = NOTE_NOTECUT; } p->instr = s[1]; p->command = s[2]; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mid.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mid.cpp index 29c0024b3..0ffeecade 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mid.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mid.cpp @@ -1083,7 +1083,7 @@ bool CSoundFile::ReadMID(FileReader &file, ModLoadingFlags loadFlags) chn = 9; else if(chn < 10) chn--; - drumChns.set(chn, xg[6] != 0); + drumChns.set(chn, xg[7] != 0); } } } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp index 73827755d..831d00da0 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp @@ -2133,7 +2133,7 @@ bool CSoundFile::ReadPT36(FileReader &file, ModLoadingFlags loadFlags) && IsInRange(info.dateMinute, 0, 59) && IsInRange(info.dateSecond, 0, 59)) { FileHistory mptHistory; - MemsetZero(mptHistory.loadDate); + MemsetZero(mptHistory); mptHistory.loadDate.tm_year = info.dateYear; mptHistory.loadDate.tm_mon = info.dateMonth - 1; mptHistory.loadDate.tm_mday = info.dateDay; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp index 20640178f..563f48f72 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp @@ -492,7 +492,7 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) } CHANNELINDEX channel = (info & s3mChannelMask); - ModCommand dummy; + ModCommand dummy = ModCommand::Empty(); ModCommand &m = (channel < GetNumChannels()) ? rowBase[channel] : dummy; if(info & s3mNotePresent) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_stm.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_stm.cpp index dbce61e34..210c4cb44 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_stm.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_stm.cpp @@ -82,10 +82,11 @@ static bool ValidateHeader(const STMFileHeader &fileHeader) // After reviewing all STM files on ModLand and ModArchive, it was found that the // case-insensitive comparison is most likely not necessary for any files in the wild. if(fileHeader.filetype != 2 - || (fileHeader.dosEof != 0x1A && fileHeader.dosEof != 2) // ST2 ignores this, ST3 doesn't. putup10.stm / putup11.stm have dosEof = 2. + || (fileHeader.dosEof != 0x1A && fileHeader.dosEof != 2) // ST2 ignores this, ST3 doesn't. Broken versions of putup10.stm / putup11.stm have dosEof = 2. || fileHeader.verMajor != 2 - || fileHeader.verMinor > 21 // ST3 only accepts 0, 10, 20 and 21 - || fileHeader.globalVolume > 64 + || (fileHeader.verMinor != 0 && fileHeader.verMinor != 10 && fileHeader.verMinor != 20 && fileHeader.verMinor != 21) + || fileHeader.numPatterns > 64 + || (fileHeader.globalVolume > 64 && fileHeader.globalVolume != 0x58) // 0x58 may be a placeholder value in earlier ST2 versions. || (std::memcmp(fileHeader.trackername, "!Scream!", 8) && std::memcmp(fileHeader.trackername, "BMOD2STM", 8) && std::memcmp(fileHeader.trackername, "WUZAMOD!", 8)) @@ -160,7 +161,7 @@ bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags) m_nDefaultTempo = ConvertST2Tempo(initTempo); m_nDefaultSpeed = initTempo >> 4; if(fileHeader.verMinor > 10) - m_nDefaultGlobalVolume = fileHeader.globalVolume * 4u; + m_nDefaultGlobalVolume = std::min(fileHeader.globalVolume, 64) * 4u; // Setting up channels for(CHANNELINDEX chn = 0; chn < 4; chn++) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/MixerLoops.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/MixerLoops.cpp index 722496dfc..e4bc4bb00 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/MixerLoops.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/MixerLoops.cpp @@ -720,8 +720,13 @@ static void C_StereoFill(mixsample_t *pBuffer, uint32 nSamples, mixsample_t &rof { #ifdef MPT_INTMIXER // Equivalent to int x_r = (rofs + (rofs > 0 ? 255 : -255)) / 256; +#if MPT_COMPILER_SHIFT_SIGNED const mixsample_t x_r = (rofs + (((-rofs) >> (sizeof(mixsample_t) * 8 - 1)) & OFSDECAYMASK)) >> OFSDECAYSHIFT; const mixsample_t x_l = (lofs + (((-lofs) >> (sizeof(mixsample_t) * 8 - 1)) & OFSDECAYMASK)) >> OFSDECAYSHIFT; +#else + const mixsample_t x_r = mpt::rshift_signed(rofs + (mpt::rshift_signed(-rofs, sizeof(int) * 8 - 1) & OFSDECAYMASK), OFSDECAYSHIFT); + const mixsample_t x_l = mpt::rshift_signed(lofs + (mpt::rshift_signed(-lofs, sizeof(int) * 8 - 1) & OFSDECAYMASK), OFSDECAYSHIFT); +#endif #else const mixsample_t x_r = rofs * (1.0f / (1 << OFSDECAYSHIFT)); const mixsample_t x_l = lofs * (1.0f / (1 << OFSDECAYSHIFT)); @@ -803,8 +808,13 @@ static void C_EndChannelOfs(ModChannel &chn, mixsample_t *pBuffer, uint32 nSampl for (uint32 i=0; i> (sizeof(mixsample_t) * 8 - 1)) & OFSDECAYMASK)) >> OFSDECAYSHIFT; const mixsample_t x_l = (lofs + (((-lofs) >> (sizeof(mixsample_t) * 8 - 1)) & OFSDECAYMASK)) >> OFSDECAYSHIFT; +#else + const mixsample_t x_r = mpt::rshift_signed(rofs + (mpt::rshift_signed(-rofs, sizeof(int) * 8 - 1) & OFSDECAYMASK), OFSDECAYSHIFT); + const mixsample_t x_l = mpt::rshift_signed(lofs + (mpt::rshift_signed(-lofs, sizeof(int) * 8 - 1) & OFSDECAYMASK), OFSDECAYSHIFT); +#endif #else const mixsample_t x_r = rofs * (1.0f / (1 << OFSDECAYSHIFT)); const mixsample_t x_l = lofs * (1.0f / (1 << OFSDECAYSHIFT)); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ModInstrument.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/ModInstrument.cpp index 6b6099c28..b388d569e 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ModInstrument.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ModInstrument.cpp @@ -58,6 +58,11 @@ void InstrumentEnvelope::Convert(MODTYPE fromType, MODTYPE toType) } } } + + if(toType != MOD_TYPE_MPT) + { + nReleaseNode = ENV_RELEASE_NODE_UNSET; + } } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp index d8ae99411..e0353e615 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp @@ -1243,6 +1243,8 @@ struct SFZEnvelope env.nSustainStart = env.nSustainEnd = static_cast(env.size() - 1); if(sustainLevel != 0) { + if(envType == ENV_VOLUME && env.nSustainEnd > 0) + env.nReleaseNode = env.nSustainEnd; env.push_back(env.back().tick + ToTicks(release, tickDuration), ToValue(0, envType)); env.dwFlags.set(ENV_SUSTAIN); } @@ -1269,7 +1271,7 @@ struct SFZRegion kAlternate, }; - std::string filename; + std::string filename, name; SFZEnvelope ampEnv, pitchEnv, filterEnv; SmpLength loopStart = 0, loopEnd = 0; SmpLength end = MAX_SAMPLE_LENGTH, offset = 0; @@ -1355,6 +1357,8 @@ struct SFZRegion { if(key == "sample") filename = control.defaultPath + value; + else if(key == "region_label") + name = value; else if(key == "lokey") keyLo = ReadKey(value, control); else if(key == "hikey") @@ -1446,7 +1450,7 @@ bool CSoundFile::ReadSFZInstrument(INSTRUMENTINDEX nInstr, FileReader &file) { file.Rewind(); - enum { kNone, kGlobal, kMaster, kGroup, kRegion, kControl, kUnknown } section = kNone; + enum { kNone, kGlobal, kMaster, kGroup, kRegion, kControl, kCurve, kUnknown } section = kNone; SFZControl control; SFZRegion group, master, globals; std::vector regions; @@ -1524,6 +1528,9 @@ bool CSoundFile::ReadSFZInstrument(INSTRUMENTINDEX nInstr, FileReader &file) } else if(sec == "control") { section = kControl; + } else if(sec == "curve") + { + section = kCurve; } charsRead++; } else if(s.substr(0, 8) == "#define " || s.substr(0, 8) == "#define\t") @@ -1560,7 +1567,7 @@ bool CSoundFile::ReadSFZInstrument(INSTRUMENTINDEX nInstr, FileReader &file) auto keyEnd = s.find_first_of(" \t="); auto valueStart = s.find_first_not_of(" \t=", keyEnd); std::string key = mpt::ToLowerCaseAscii(s.substr(0, keyEnd)); - if(key == "sample" || key == "default_path" || key.substr(0, 8) == "label_cc") + if(key == "sample" || key == "default_path" || key.substr(0, 8) == "label_cc" || key.substr(0, 12) == "region_label") { // Sample / CC name may contain spaces... charsRead = s.find_first_of("=\t<", valueStart); @@ -1656,6 +1663,10 @@ bool CSoundFile::ReadSFZInstrument(INSTRUMENTINDEX nInstr, FileReader &file) prevSmp--; continue; } + if(!region.name.empty()) + { + mpt::String::Copy(m_szNames[smp], region.name); + } if(!m_szNames[smp][0]) { mpt::String::Copy(m_szNames[smp], filename.GetFileName().ToLocale()); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_flt.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_flt.cpp index d2c9225ad..98ebfbc2d 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_flt.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_flt.cpp @@ -40,10 +40,20 @@ uint8 CSoundFile::FrequencyToCutOff(double frequency) const uint32 CSoundFile::CutOffToFrequency(uint32 nCutOff, int flt_modifier) const { MPT_ASSERT(nCutOff < 128); - float Fc = 110.0f * std::pow(2.0f, 0.25f + ((float)(nCutOff * (flt_modifier + 256))) / (m_SongFlags[SONG_EXFILTERRANGE] ? 20.0f * 512.0f : 24.0f * 512.0f)); + float computedCutoff = static_cast(nCutOff * (flt_modifier + 256)); // 0...127*512 + float Fc; + if(GetType() != MOD_TYPE_IMF) + { + Fc = 110.0f * std::pow(2.0f, 0.25f + computedCutoff / (m_SongFlags[SONG_EXFILTERRANGE] ? 20.0f * 512.0f : 24.0f * 512.0f)); + } else + { + // EMU8000: Documentation says the cutoff is in quarter semitones, with 0x00 being 125 Hz and 0xFF being 8 kHz + // The first half of the sentence contradicts the second, though. + Fc = 125.0f * std::pow(2.0f, computedCutoff * 6.0f / (127.0f * 512.0f)); + } int freq = Util::Round(Fc); Limit(freq, 120, 20000); - if (freq * 2 > (int)m_MixerSettings.gdwMixingFreq) freq = m_MixerSettings.gdwMixingFreq / 2; + if(freq * 2 > (int)m_MixerSettings.gdwMixingFreq) freq = m_MixerSettings.gdwMixingFreq / 2; return static_cast(freq); } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp index 2514a7815..09a47abd9 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp @@ -57,21 +57,12 @@ public: std::unique_ptr state; struct ChnSettings { - double patLoop; - CSoundFile::samplecount_t patLoopSmp; - ROWINDEX patLoopStart; - uint32 ticksToRender; // When using sample sync, we still need to render this many ticks - bool incChanged; // When using sample sync, note frequency has changed - uint8 vol; - - ChnSettings() - : patLoop(0.0) - , patLoopSmp(0) - , patLoopStart(0) - , ticksToRender(0) - , incChanged(false) - , vol(0xFF) - { } + double patLoop = 0.0; + CSoundFile::samplecount_t patLoopSmp = 0; + ROWINDEX patLoopStart = 0; + uint32 ticksToRender = 0; // When using sample sync, we still need to render this many ticks + bool incChanged = false; // When using sample sync, note frequency has changed + uint8 vol = 0xFF; }; #ifndef NO_PLUGINS @@ -329,9 +320,9 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod bool patternBreakOnThisRow = false; bool patternLoopEndedOnThisRow = false, patternLoopStartedOnThisRow = false; - if(playState.m_nPattern == orderList.GetIgnoreIndex() && target.mode == GetLengthTarget::SeekPosition && playState.m_nCurrentOrder == target.pos.order) + if(!Patterns.IsValidPat(playState.m_nPattern) && playState.m_nPattern != orderList.GetInvalidPatIndex() && target.mode == GetLengthTarget::SeekPosition && playState.m_nCurrentOrder == target.pos.order) { - // Early test: Target is inside +++ pattern + // Early test: Target is inside +++ or non-existing pattern retval.targetReached = true; break; } @@ -494,7 +485,7 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod { // Fine Pattern Delay tickDelay += (p->param & 0x0F); - } if((p->param & 0xF0) == 0xE0 && !rowDelay) + } else if((p->param & 0xF0) == 0xE0 && !rowDelay) { // Pattern Delay if(!(GetType() & MOD_TYPE_S3M) || (p->param & 0x0F) != 0) @@ -674,12 +665,18 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod patternLoopStartedOnThisRow = true; } break; + + case 0xF0: + // Active macro + pChn->nActiveMacro = param & 0x0F; + break; } break; case CMD_MODCMDEX: - if ((param & 0xF0) == 0x60) + switch(param & 0xF0) { + case 0x60: // Pattern Loop if (param & 0x0F) { @@ -692,6 +689,12 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod memory.chnSettings[nChn].patLoopSmp = playState.m_lTotalSampleCount; memory.chnSettings[nChn].patLoopStart = playState.m_nRow; } + break; + + case 0xF0: + // Active macro + pChn->nActiveMacro = param & 0x0F; + break; } break; @@ -1158,6 +1161,12 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod if(memory.chnSettings[nChn].patLoop == i.first) { playState.m_lTotalSampleCount += (playState.m_lTotalSampleCount - memory.chnSettings[nChn].patLoopSmp) * (i.second - 1); + if(m_playBehaviour[kITPatternLoopTargetReset] || (GetType() == MOD_TYPE_S3M)) + { + memory.chnSettings[nChn].patLoop = memory.elapsedTime; + memory.chnSettings[nChn].patLoopSmp = playState.m_lTotalSampleCount; + memory.chnSettings[nChn].patLoopStart = playState.m_nRow + 1; + } break; } } @@ -1165,7 +1174,8 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod if(GetType() == MOD_TYPE_IT) { // IT pattern loop start row update - at the end of a pattern loop, set pattern loop start to next row (for upcoming pattern loops with missing SB0) - for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); nChn++) + pChn = playState.Chn; + for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); nChn++, pChn++) { if((pChn->rowCommand.command == CMD_S3MCMDEX && pChn->rowCommand.param >= 0xB1 && pChn->rowCommand.param <= 0xBF)) { @@ -1327,7 +1337,7 @@ void CSoundFile::InstrumentChange(ModChannel *pChn, uint32 instr, bool bPorta, b { // IT compatibility: No sample change (also within multi-sample instruments) during portamento when using Compatible Gxx. // Test case: PortaInsNumCompat.it, PortaSampleCompat.it, PortaCutCompat.it - if(m_playBehaviour[kITPortamentoInstrument] && m_SongFlags[SONG_ITCOMPATGXX] && pChn->nLength != 0) + if(m_playBehaviour[kITPortamentoInstrument] && m_SongFlags[SONG_ITCOMPATGXX] && !pChn->increment.IsZero()) { pSmp = pChn->pModSample; } @@ -2082,13 +2092,11 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo if (srcChn.dwFlags[CHN_MUTE]) return CHANNELINDEX_INVALID; - bool applyDNAtoPlug; //rewbs.VSTiNNA - for(CHANNELINDEX i = nChn; i < MAX_CHANNELS; i++) if(i >= m_nChannels || i == nChn) { ModChannel &chn = m_PlayState.Chn[i]; - applyDNAtoPlug = false; //rewbs.VSTiNNA + bool applyDNAtoPlug = false; if((chn.nMasterChn == nChn + 1 || i == nChn) && chn.pModInstrument != nullptr) { bool bOk = false; @@ -2098,7 +2106,7 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo // Note case DCT_NOTE: if(note && chn.nNote == note && pIns == chn.pModInstrument) bOk = true; - if(pIns && pIns->nMixPlug) applyDNAtoPlug = true; //rewbs.VSTiNNA + if(pIns && pIns->nMixPlug) applyDNAtoPlug = true; break; // Sample case DCT_SAMPLE: @@ -2107,7 +2115,6 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo // Instrument case DCT_INSTRUMENT: if(pIns == chn.pModInstrument) bOk = true; - //rewbs.VSTiNNA if(pIns && pIns->nMixPlug) applyDNAtoPlug = true; break; // Plugin @@ -2117,7 +2124,6 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo applyDNAtoPlug = true; bOk = true; } - //end rewbs.VSTiNNA break; } @@ -2178,7 +2184,7 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo pPlugin = m_MixPlugins[nPlugin-1].pMixPlugin; if(pPlugin) { - // apply NNA to this plugin iff it is currently playing a note on this tracking channel + // apply NNA to this plugin iff it is currently playing a note on this tracker channel // (and if it is playing a note, we know that would be the last note played on this chan). applyNNAtoPlug = pPlugin->IsNotePlaying(srcChn.GetPluginNote(m_playBehaviour[kITRealNoteMapping]), GetBestMidiChannel(nChn), nChn); } @@ -2187,8 +2193,7 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo #endif // NO_PLUGINS // New Note Action - //if ((pChn.nVolume) && (pChn.nLength)) - if((srcChn.nVolume != 0 && srcChn.nLength != 0) || applyNNAtoPlug) //rewbs.VSTiNNA + if((srcChn.nRealVolume > 0 && srcChn.nLength > 0) || applyNNAtoPlug) { nnaChn = GetNNAChannel(nChn); if(nnaChn != 0) @@ -4876,7 +4881,7 @@ uint32 CSoundFile::SendMIDIData(CHANNELINDEX nChn, bool isSmooth, const unsigned return 0; } - ModChannel *pChn = &m_PlayState.Chn[nChn]; + ModChannel &chn = m_PlayState.Chn[nChn]; if(macro[0] == 0xF0 && (macro[1] == 0xF0 || macro[1] == 0xF1)) { @@ -4889,60 +4894,44 @@ uint32 CSoundFile::SendMIDIData(CHANNELINDEX nChn, bool isSmooth, const unsigned const uint8 macroCode = macro[2]; const uint8 param = macro[3]; - if(macroCode == 0x00 && !isExtended) + if(macroCode == 0x00 && !isExtended && param < 0x80) { // F0.F0.00.xx: Set CutOff - int oldcutoff = pChn->nCutOff; - if(param < 0x80) + if(!isSmooth) { - if(!isSmooth) - { - pChn->nCutOff = param; - } else - { - pChn->nCutOff = (uint8)CalculateSmoothParamChange((float)pChn->nCutOff, (float)param); - } - pChn->nRestoreCutoffOnNewNote = 0; + chn.nCutOff = param; + } else + { + chn.nCutOff = Util::Round(CalculateSmoothParamChange(chn.nCutOff, param)); } - - oldcutoff -= pChn->nCutOff; - if(oldcutoff < 0) oldcutoff = -oldcutoff; - if((pChn->nVolume > 0) || (oldcutoff < 0x10) - || !pChn->dwFlags[CHN_FILTER] || (!(pChn->rightVol | pChn->leftVol))) - SetupChannelFilter(pChn, !pChn->dwFlags[CHN_FILTER]); + chn.nRestoreCutoffOnNewNote = 0; + SetupChannelFilter(&chn, !chn.dwFlags[CHN_FILTER]); return 4; - - } else if(macroCode == 0x01 && !isExtended) + } else if(macroCode == 0x01 && !isExtended && param < 0x80) { // F0.F0.01.xx: Set Resonance - if(param < 0x80) + if(!isSmooth) { - pChn->nRestoreResonanceOnNewNote = 0; - if(!isSmooth) - { - pChn->nResonance = param; - } else - { - pChn->nResonance = (uint8)CalculateSmoothParamChange((float)pChn->nResonance, (float)param); - } + chn.nResonance = param; + } else + { + chn.nResonance = (uint8)CalculateSmoothParamChange((float)chn.nResonance, (float)param); } - - SetupChannelFilter(pChn, !pChn->dwFlags[CHN_FILTER]); + chn.nRestoreResonanceOnNewNote = 0; + SetupChannelFilter(&chn, !chn.dwFlags[CHN_FILTER]); return 4; - } else if(macroCode == 0x02 && !isExtended) { // F0.F0.02.xx: Set filter mode (high nibble determines filter mode) if(param < 0x20) { - pChn->nFilterMode = (param >> 4); - SetupChannelFilter(pChn, !pChn->dwFlags[CHN_FILTER]); + chn.nFilterMode = (param >> 4); + SetupChannelFilter(&chn, !chn.dwFlags[CHN_FILTER]); } return 4; - #ifndef NO_PLUGINS } else if(macroCode == 0x03 && !isExtended) { @@ -4961,7 +4950,6 @@ uint32 CSoundFile::SendMIDIData(CHANNELINDEX nChn, bool isSmooth, const unsigned } return 4; - } else if((macroCode & 0x80) || isExtended) { // F0.F0.{80|n}.xx / F0.F1.n.xx: Set VST effect parameter n to xx @@ -4985,7 +4973,6 @@ uint32 CSoundFile::SendMIDIData(CHANNELINDEX nChn, bool isSmooth, const unsigned return 4; #endif // NO_PLUGINS - } // If we reach this point, the internal macro was invalid. @@ -4994,11 +4981,11 @@ uint32 CSoundFile::SendMIDIData(CHANNELINDEX nChn, bool isSmooth, const unsigned { #ifndef NO_PLUGINS // Not an internal device. Pass on to appropriate plugin. - const CHANNELINDEX plugChannel = (nChn < GetNumChannels()) ? nChn + 1 : pChn->nMasterChn; + const CHANNELINDEX plugChannel = (nChn < GetNumChannels()) ? nChn + 1 : chn.nMasterChn; if(plugChannel > 0 && plugChannel <= GetNumChannels()) // XXX do we need this? I guess it might be relevant for previewing notes in the pattern... Or when using this mechanism for volume/panning! { PLUGINDEX nPlug = 0; - if(!pChn->dwFlags[CHN_NOFX]) + if(!chn.dwFlags[CHN_NOFX]) { nPlug = (plugin != 0) ? plugin : GetBestPlugin(nChn, PrioritiseChannel, EvenIfMuted); } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.cpp index d34bfb21f..6369bcdbe 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.cpp @@ -320,7 +320,7 @@ CSoundFile::ProbeResult CSoundFile::Probe(ProbeFlags flags, mpt::span= ProbeRecommendedSize)) { // If the prober wants more daat but we already provided the recommended required maximum, - // just return success as this is th ebest we can do for the suggestesd probing size. + // just return success as this is the best we can do for the suggestesd probing size. result = ProbeSuccess; } } @@ -654,7 +654,7 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags) if (Reporting::Confirm(mpt::ToWide(mpt::CharsetUTF8, notFoundText.c_str()), L"OpenMPT - Plugins missing", false, true) == cnfYes) { std::string url = "https://resources.openmpt.org/plugins/search.php?p="; - for(auto &id : notFoundIDs) + for(const auto &id : notFoundIDs) { url += mpt::fmt::HEX0<8>(id->dwPluginId2.get()); url += id->szLibraryName; @@ -810,8 +810,11 @@ void CSoundFile::ResetPlayPos() void CSoundFile::SetCurrentOrder(ORDERINDEX nOrder) { - while ((nOrder < Order().size()) && (Order()[nOrder] == Order.GetIgnoreIndex())) nOrder++; - if ((nOrder >= Order().size()) || (Order()[nOrder] >= Patterns.Size())) return; + while(nOrder < Order().size() && !Order().IsValidPat(nOrder)) + nOrder++; + if(nOrder >= Order().size()) + return; + for(auto &chn : m_PlayState.Chn) { chn.nPeriod = 0; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp index 0c785bc75..848ca1792 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp @@ -1452,12 +1452,14 @@ void CSoundFile::ProcessArpeggio(CHANNELINDEX nChn, int &period, Tuning::NOTEIND // TODO other likely formats for MOD case: MED, OKT, etc uint8 note = (GetType() != MOD_TYPE_MOD) ? pChn->nNote : static_cast(GetNoteFromPeriod(period, pChn->nFineTune, pChn->nC5Speed)); + if(GetType() & (MOD_TYPE_DBM | MOD_TYPE_DIGI)) + tick += 2; switch(tick % 3) { case 1: note += (pChn->nArpeggio >> 4); break; case 2: note += (pChn->nArpeggio & 0x0F); break; } - if(note != pChn->nNote || GetType() == MOD_TYPE_STM || m_playBehaviour[KST3PortaAfterArpeggio]) + if(note != pChn->nNote || (GetType() & (MOD_TYPE_DBM | MOD_TYPE_DIGI | MOD_TYPE_STM)) || m_playBehaviour[KST3PortaAfterArpeggio]) { if(m_SongFlags[SONG_PT_MODE]) { @@ -1474,7 +1476,7 @@ void CSoundFile::ProcessArpeggio(CHANNELINDEX nChn, int &period, Tuning::NOTEIND } period = GetPeriodFromNote(note, pChn->nFineTune, pChn->nC5Speed); - if(GetType() & (MOD_TYPE_STM | MOD_TYPE_PSM)) + if(GetType() & (MOD_TYPE_DBM | MOD_TYPE_DIGI | MOD_TYPE_PSM | MOD_TYPE_STM)) { // The arpeggio note offset remains effective after the end of the current row in ScreamTracker 2. // This fixes the flute lead in MORPH.STM by Skaven, pattern 27. diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.cpp index 23cdef144..eb3937122 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.cpp @@ -651,7 +651,7 @@ bool IMixPlugin::SaveProgram() defaultDir = m_Factory.dllPath.GetPath(); } - CString progName = GetCurrentProgramName(); + CString progName = m_Factory.libraryName.ToCString() + _T(" - ") + GetCurrentProgramName(); SanitizeFilename(progName); FileDialog dlg = SaveFileDialog() @@ -928,7 +928,7 @@ void IMidiPlugin::MidiCommand(uint8 nMidiCh, uint8 nMidiProg, uint16 wMidiBank, // Problem: if a note dies out naturally and we never send a note off, this counter // will block at max until note off. Is this a problem? // Safe to assume we won't need more than 16 note offs max on a given note? - if(channel.noteOnMap[note][trackChannel] < 17) + if(channel.noteOnMap[note][trackChannel] < uint8_max) channel.noteOnMap[note][trackChannel]++; MidiSend(MIDIEvents::NoteOn(nMidiCh, static_cast(note), volume));