Updated libopenmpt to version 0.4.3

CQTexperiment
Chris Moeller 2019-02-12 00:07:17 -08:00 committed by Christopher Snowhill
parent d484ed47e0
commit 947ec7f691
20 changed files with 238 additions and 153 deletions

View File

@ -56,7 +56,7 @@ void* align(std::size_t alignment, std::size_t size, void* &ptr, std::size_t &sp
aligned_raw_memory aligned_alloc_impl(std::size_t size, std::size_t count, std::size_t alignment)
{
#if MPT_CXX_AT_LEAST(17) && (!MPT_COMPILER_MSVC && !MPT_GCC_BEFORE(8,1,0) && !MPT_CLANG_BEFORE(5,0,0)) && !(MPT_COMPILER_CLANG && defined(__GLIBCXX__)) && !MPT_OS_EMSCRIPTEN
#if MPT_CXX_AT_LEAST(17) && (!MPT_COMPILER_MSVC && !MPT_GCC_BEFORE(8,1,0) && !MPT_CLANG_BEFORE(5,0,0)) && !(MPT_COMPILER_CLANG && defined(__GLIBCXX__)) && !(MPT_COMPILER_CLANG && MPT_OS_MACOSX_OR_IOS) && !MPT_OS_EMSCRIPTEN
std::size_t space = count * size;
void* mem = std::aligned_alloc(alignment, space);
if(!mem)
@ -103,7 +103,7 @@ aligned_raw_memory aligned_alloc_impl(std::size_t size, std::size_t count, std::
void aligned_free(aligned_raw_memory raw)
{
#if MPT_CXX_AT_LEAST(17) && (!MPT_COMPILER_MSVC && !MPT_GCC_BEFORE(8,1,0) && !MPT_CLANG_BEFORE(5,0,0)) && !(MPT_COMPILER_CLANG && defined(__GLIBCXX__)) && !MPT_OS_EMSCRIPTEN
#if MPT_CXX_AT_LEAST(17) && (!MPT_COMPILER_MSVC && !MPT_GCC_BEFORE(8,1,0) && !MPT_CLANG_BEFORE(5,0,0)) && !(MPT_COMPILER_CLANG && defined(__GLIBCXX__)) && !(MPT_COMPILER_CLANG && MPT_OS_MACOSX_OR_IOS) && !MPT_OS_EMSCRIPTEN
std::free(raw.mem);
#elif MPT_COMPILER_MSVC
_aligned_free(raw.mem);

View File

@ -100,7 +100,7 @@ namespace mpt
#if MPT_CXX_AT_LEAST(17) && !(MPT_COMPILER_CLANG && defined(__GLIBCXX__))
#if MPT_CXX_AT_LEAST(17) && !(MPT_COMPILER_CLANG && defined(__GLIBCXX__)) && !(MPT_COMPILER_CLANG && MPT_OS_MACOSX_OR_IOS)
using std::launder;
#else
template <class T>

View File

@ -20,8 +20,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 28
#define VER_MINOR 02
#define VER_MINORMINOR 04
#define VER_MINOR 03
#define VER_MINORMINOR 00
//Numerical value of the version.
#define MPT_VERSION_CURRENT MAKE_VERSION_NUMERIC(VER_MAJORMAJOR,VER_MAJOR,VER_MINOR,VER_MINORMINOR)

View File

@ -0,0 +1,22 @@
Copyright 2013-2014 RAD Game Tools and Valve Software
Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,6 +1,6 @@
miniz DEFLATE implementation.
https://github.com/richgel999/miniz
2.0.7
2.0.8
Modifications for OpenMPT:
* #define MINIZ_NO_STDIO has been set because OpenMPT does not need stdio
functionality and miniz relies on secure-CRT file i/o functions in windows

View File

@ -2709,18 +2709,19 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_nex
}
}
#endif
do
while(counter>2)
{
pOut_buf_cur[0] = pSrc[0];
pOut_buf_cur[1] = pSrc[1];
pOut_buf_cur[2] = pSrc[2];
pOut_buf_cur += 3;
pSrc += 3;
} while ((int)(counter -= 3) > 2);
if ((int)counter > 0)
counter -= 3;
}
if (counter > 0)
{
pOut_buf_cur[0] = pSrc[0];
if ((int)counter > 1)
if (counter > 1)
pOut_buf_cur[1] = pSrc[1];
pOut_buf_cur += counter;
}
@ -6092,6 +6093,17 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n
}
#endif /* #ifndef MINIZ_NO_TIME */
if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
{
uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size);
uncomp_size = buf_size;
if (uncomp_size <= 3)
{
level = 0;
store_data_uncompressed = MZ_TRUE;
}
}
archive_name_size = strlen(pArchive_name);
if (archive_name_size > MZ_UINT16_MAX)
return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
@ -6207,24 +6219,13 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n
cur_archive_file_ofs += archive_name_size;
}
if (user_extra_data_len > 0)
{
if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len)
return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
if (user_extra_data_len > 0)
{
if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len)
return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
cur_archive_file_ofs += user_extra_data_len;
}
if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
{
uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size);
uncomp_size = buf_size;
if (uncomp_size <= 3)
{
level = 0;
store_data_uncompressed = MZ_TRUE;
}
}
cur_archive_file_ofs += user_extra_data_len;
}
if (store_data_uncompressed)
{

View File

@ -1,4 +1,4 @@
/* miniz.c 2.0.7 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing
/* miniz.c 2.0.8 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing
See "unlicense" statement at the end of this file.
Rich Geldreich <richgel99@gmail.com>, last updated Oct. 13, 2013
Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt
@ -247,11 +247,11 @@ enum
MZ_DEFAULT_COMPRESSION = -1
};
#define MZ_VERSION "10.0.2"
#define MZ_VERNUM 0xA020
#define MZ_VERSION "10.0.3"
#define MZ_VERNUM 0xA030
#define MZ_VER_MAJOR 10
#define MZ_VER_MINOR 0
#define MZ_VER_REVISION 2
#define MZ_VER_REVISION 3
#define MZ_VER_SUBREVISION 0
#ifndef MINIZ_NO_ZLIB_APIS
@ -1149,13 +1149,6 @@ MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip);
/* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */
size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n);
/* Attempts to locates a file in the archive's central directory. */
/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */
/* Returns -1 if the file cannot be found. */
int mz_zip_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags);
/* Returns MZ_FALSE if the file cannot be found. */
mz_bool mz_zip_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex);
/* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this field. */
/* Note that the m_last_error functionality is not thread safe. */
mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num);

View File

@ -1,6 +1,6 @@
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)
https://github.com/nothings/stb/blob/master/stb_vorbis.c v1.15
commit 59e9702be5bfc0061e756c7beab7dcd3d363400d (2019-02-07)
Modifications:
* Use of alloca has been replaced with malloc, as alloca is not in C99 and

View File

@ -1,4 +1,4 @@
// Ogg Vorbis audio decoder - v1.14 - public domain
// Ogg Vorbis audio decoder - v1.15 - public domain
// http://nothings.org/stb_vorbis/
//
// Original version written by Sean Barrett in 2007.
@ -33,6 +33,7 @@
// Timur Gagiev
//
// Partial history:
// 1.15 - 2019-02-07 - explicit failure if Ogg Skeleton data is found
// 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
@ -253,7 +254,7 @@ extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
// the _current_ seek point (ftell). on failure, returns NULL and sets *error.
// note that stb_vorbis must "own" this stream; if you seek it in between
// calls to stb_vorbis, it will become confused. Morever, if you attempt to
// calls to stb_vorbis, it will become confused. Moreover, if you attempt to
// perform stb_vorbis_seek_*() operations on this file, it will assume it
// owns the _entire_ rest of the file after the start point. Use the next
// function, stb_vorbis_open_file_section(), to limit it.
@ -374,7 +375,8 @@ enum STBVorbisError
VORBIS_invalid_first_page,
VORBIS_bad_packet_type,
VORBIS_cant_find_last_page,
VORBIS_seek_failed
VORBIS_seek_failed,
VORBIS_ogg_skeleton_not_supported
};
@ -1082,7 +1084,7 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values)
assert(z >= 0 && z < 32);
available[z] = 0;
add_entry(c, bit_reverse(res), i, m++, len[i], values);
// propogate availability up the tree
// propagate availability up the tree
if (z != len[i]) {
assert(len[i] >= 0 && len[i] < 32);
for (y=len[i]; y > z; --y) {
@ -2646,7 +2648,7 @@ static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype)
// once I combined the passes.
// so there's a missing 'times 2' here (for adding X to itself).
// this propogates through linearly to the end, where the numbers
// this propagates through linearly to the end, where the numbers
// are 1/2 too small, and need to be compensated for.
{
@ -3587,7 +3589,22 @@ static int start_decoder(vorb *f)
if (f->page_flag & PAGEFLAG_continued_packet) return error(f, VORBIS_invalid_first_page);
// check for expected packet length
if (f->segment_count != 1) return error(f, VORBIS_invalid_first_page);
if (f->segments[0] != 30) return error(f, VORBIS_invalid_first_page);
if (f->segments[0] != 30) {
// check for the Ogg skeleton fishead identifying header to refine our error
if (f->segments[0] == 64 &&
getn(f, header, 6) &&
header[0] == 'f' &&
header[1] == 'i' &&
header[2] == 's' &&
header[3] == 'h' &&
header[4] == 'e' &&
header[5] == 'a' &&
get8(f) == 'd' &&
get8(f) == '\0') return error(f, VORBIS_ogg_skeleton_not_supported);
else
return error(f, VORBIS_invalid_first_page);
}
// read packet
// check packet header
if (get8(f) != VORBIS_packet_id) return error(f, VORBIS_invalid_first_page);
@ -4580,7 +4597,7 @@ static int get_seek_page_info(stb_vorbis *f, ProbedPage *z)
return 1;
}
// rarely used function to seek back to the preceeding page while finding the
// rarely used function to seek back to the preceding page while finding the
// start of a packet
static int go_to_page_before(stb_vorbis *f, unsigned int limit_offset)
{

View File

@ -5,6 +5,20 @@ Changelog {#changelog}
For fully detailed change log, please see the source repository directly. This
is just a high-level summary.
### libopenmpt 0.4.3 (2019-02-11)
* [**Sec**] Possible crash due to null-pointer access when doing a portamento
from an OPL instrument to an empty instrument note map slot (r11348).
* [**Bug**] libopenmpt did not compile on Apple platforms in C++17 mode.
* IT: Various fixes for note-off + instrument number in Old Effects mode.
* MO3: Import IT row highlights as written by MO3 2.4.1.2 or newer. Required
for modules using modern tempo mode.
* miniz: Update to v2.0.8 (2018-09-19).
* stb_vorbis: Update to v1.15 (2019-02-07).
### libopenmpt 0.4.2 (2019-01-22)
* [**Sec**] DSM: Assertion failure during file parsing with debug STLs

View File

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

View File

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

View File

@ -63,7 +63,7 @@ struct MixLoopState
// If there is no interpolation happening, there is no lookahead happening the sample read-out is exact.
if(chn.dwFlags[CHN_LOOP] && chn.resamplingMode != SRCMODE_NEAREST)
{
const bool inSustainLoop = chn.InSustainLoop();
const bool inSustainLoop = chn.InSustainLoop() && chn.nLoopStart == chn.pModSample->nSustainStart && chn.nLoopEnd == chn.pModSample->nSustainEnd;
// Do not enable wraparound magic if we're previewing a custom loop!
if(inSustainLoop || chn.nLoopEnd == chn.pModSample->nLoopEnd)

View File

@ -1415,7 +1415,7 @@ bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool c
if(!compatibilityExport)
{
// This way, we indicate that the file will most likely contain OpenMPT hacks. Compatibility export puts 0 here.
// This way, we indicate that the file might contain OpenMPT hacks. Compatibility export puts 0 here.
memcpy(&itHeader.reserved, "OMPT", 4);
}
}
@ -1428,17 +1428,17 @@ bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool c
if(m_SongFlags[SONG_ITCOMPATGXX]) itHeader.flags |= ITFileHeader::itCompatGxx;
if(m_SongFlags[SONG_EXFILTERRANGE] && !compatibilityExport) itHeader.flags |= ITFileHeader::extendedFilterRange;
itHeader.globalvol = (uint8)(m_nDefaultGlobalVolume >> 1);
itHeader.mv = (uint8)MIN(m_nSamplePreAmp, 128u);
itHeader.speed = (uint8)MIN(m_nDefaultSpeed, 255u);
itHeader.tempo = (uint8)MIN(m_nDefaultTempo.GetInt(), 255u); //Limit this one to 255, we save the real one as an extension below.
itHeader.globalvol = static_cast<uint8>(m_nDefaultGlobalVolume / 2u);
itHeader.mv = static_cast<uint8>(std::min(m_nSamplePreAmp, uint32(128)));
itHeader.speed = mpt::saturate_cast<uint8>(m_nDefaultSpeed);
itHeader.tempo = mpt::saturate_cast<uint8>(m_nDefaultTempo.GetInt()); // We save the real tempo in an extension below if it exceeds 255.
itHeader.sep = 128; // pan separation
// IT doesn't have a per-instrument Pitch Wheel Depth setting, so we just store the first non-zero PWD setting in the header.
for(INSTRUMENTINDEX ins = 1; ins < GetNumInstruments(); ins++)
for(INSTRUMENTINDEX ins = 1; ins <= GetNumInstruments(); ins++)
{
if(Instruments[ins] != nullptr && Instruments[ins]->midiPWD != 0)
{
itHeader.pwd = (uint8)mpt::abs(Instruments[ins]->midiPWD);
itHeader.pwd = static_cast<uint8>(mpt::abs(Instruments[ins]->midiPWD));
break;
}
}
@ -1613,7 +1613,7 @@ bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool c
uint16 writeSize = 0;
uint16le patinfo[4];
patinfo[0] = 0;
patinfo[1] = (uint16)writeRows;
patinfo[1] = static_cast<uint16>(writeRows);
patinfo[2] = 0;
patinfo[3] = 0;
@ -1744,11 +1744,11 @@ bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool c
if (b != chnmask[ch])
{
chnmask[ch] = b;
buf[len++] = uint8((ch + 1) | IT_bitmask_patternChanEnabled_c);
buf[len++] = static_cast<uint8>((ch + 1) | IT_bitmask_patternChanEnabled_c);
buf[len++] = b;
} else
{
buf[len++] = uint8(ch + 1);
buf[len++] = static_cast<uint8>(ch + 1);
}
if (b & 1) buf[len++] = note;
if (b & 2) buf[len++] = m->instr;
@ -1790,7 +1790,7 @@ bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool c
bool compress = false;
#endif // MODPLUG_TRACKER
// Old MPT, DUMB and probably other libraries will only consider the IT2.15 compression flag if the header version also indicates IT2.15.
// MilkyTracker <= 0.90.85 will only assume IT2.15 compression with cmwt == 0x215, ignoring the delta flag completely.
// MilkyTracker <= 0.90.85 assumes IT2.15 compression with cmwt == 0x215, ignoring the delta flag completely.
itss.ConvertToIT(sample, GetType(), compress, itHeader.cmwt >= 0x215, GetType() == MOD_TYPE_MPT);
const bool isExternal = itss.cvt == ITSample::cvtExternalSample;

View File

@ -194,22 +194,29 @@ struct MO3Instrument
panEnv.ConvertToMPT(mptIns.PanEnv, 0);
pitchEnv.ConvertToMPT(mptIns.PitchEnv, 5);
mptIns.nFadeOut = fadeOut;
if(midiChannel >= 128)
{
// Plugin
mptIns.nMixPlug = midiChannel - 127;
} else if(midiChannel < 17 && (flags & playOnMIDI))
{
// XM / IT with recent encoder
// XM, or IT with recent encoder
mptIns.nMidiChannel = midiChannel + MidiFirstChannel;
} else if(midiChannel > 0 && midiChannel < 17)
{
// IT encoded with MO3 version prior to 2.4.1 (yes, channel 0 is represented the same way as "no channel")
mptIns.nMidiChannel = midiChannel + MidiFirstChannel;
}
mptIns.wMidiBank = midiBank;
mptIns.nMidiProgram = midiPatch;
mptIns.midiPWD = midiBend;
if(mptIns.nMidiChannel != MidiNoChannel)
{
if(mptIns.wMidiBank < 128)
mptIns.wMidiBank = midiBank + 1;
if(mptIns.nMidiProgram < 128)
mptIns.nMidiProgram = midiPatch + 1;
mptIns.midiPWD = midiBend;
}
if(type == MOD_TYPE_IT)
mptIns.nGlobalVol = std::min<uint8>(globalVol, 128) / 2u;
if(panning <= 256)
@ -1811,6 +1818,10 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
break;
}
break;
case MagicLE("PRHI"):
m_nDefaultRowsPerBeat = chunk.ReadUint8();
m_nDefaultRowsPerMeasure = chunk.ReadUint8();
break;
case MagicLE("MIDI"):
// Full MIDI config
chunk.ReadStruct<MIDIMacroConfigData>(m_MidiCfg);

View File

@ -513,6 +513,7 @@ enum PlayBehaviour
kReleaseNodePastSustainBug, // OpenMPT 1.23.01.02 / r4009 broke release nodes past the sustain point, fixed in OpenMPT 1.28
kFT2NoteDelayWithoutInstr, // Sometime between OpenMPT 1.18.03.00 and 1.19.01.00, delayed instrument-less notes in XM started recalling the default sample volume and panning
kOPLFlexibleNoteOff, // Full control after note-off over OPL voices, ^^^ sends note cut instead of just note-off
kITInstrWithNoteOffOldEffects, // Instrument number with note-off recalls default volume - special cases with Old Effects enabled
// Add new play behaviours here.

View File

@ -1327,6 +1327,7 @@ void CSoundFile::InstrumentChange(ModChannel &chn, uint32 instr, bool bPorta, bo
{
const ModInstrument *pIns = instr <= GetNumInstruments() ? Instruments[instr] : nullptr;
const ModSample *pSmp = &Samples[instr];
const auto oldInsVol = chn.nInsVol;
ModCommand::NOTE note = chn.nNewNote;
if(note == NOTE_NONE && m_playBehaviour[kITInstrWithoutNote]) return;
@ -1491,9 +1492,12 @@ void CSoundFile::InstrumentChange(ModChannel &chn, uint32 instr, bool bPorta, bo
if(m_playBehaviour[kITEnvelopeReset])
{
const bool insNumber = (instr != 0);
// IT compatibility: Note-off with instrument number + Old Effects retriggers envelopes.
// Test case: ResetEnvNoteOffOldFx.it
const bool isKeyOff = chn.dwFlags[CHN_NOTEFADE | CHN_KEYOFF] || (chn.rowCommand.note == NOTE_KEYOFF && m_playBehaviour[kITInstrWithNoteOffOldEffects]);
reset = (!chn.nLength
|| (insNumber && bPorta && m_SongFlags[SONG_ITCOMPATGXX])
|| (insNumber && !bPorta && chn.dwFlags[CHN_NOTEFADE | CHN_KEYOFF] && m_SongFlags[SONG_ITOLDEFFECTS]));
|| (insNumber && !bPorta && isKeyOff && m_SongFlags[SONG_ITOLDEFFECTS]));
// NOTE: IT2.14 with SB/GUS/etc. output is different. We are going after IT's WAV writer here.
// For SB/GUS/etc. emulation, envelope carry should only apply when the NNA isn't set to "Note Cut".
// Test case: CarryNNA.it
@ -1597,6 +1601,21 @@ void CSoundFile::InstrumentChange(ModChannel &chn, uint32 instr, bool bPorta, bo
chn.increment.Set(0);
}
// IT compatibility: Note-off with instrument number + Old Effects retriggers envelopes.
// If the instrument changes, keep playing the previous sample, but load the new instrument's envelopes.
// Test case: ResetEnvNoteOffOldFx.it
if(chn.rowCommand.note == NOTE_KEYOFF && m_playBehaviour[kITInstrWithNoteOffOldEffects] && m_SongFlags[SONG_ITOLDEFFECTS] && sampleChanged)
{
if(chn.pModSample)
{
chn.dwFlags |= (chn.pModSample->uFlags & CHN_SAMPLEFLAGS);
}
chn.nInsVol = oldInsVol;
chn.nVolume = pSmp->nVolume;
if(pSmp->uFlags[CHN_PANNING]) chn.nPan = pSmp->nPan;
return;
}
chn.pModSample = pSmp;
chn.nLength = pSmp->nLength;
chn.nLoopStart = pSmp->nLoopStart;
@ -1622,13 +1641,11 @@ void CSoundFile::InstrumentChange(ModChannel &chn, uint32 instr, bool bPorta, bo
// Don't reset finetune changed by "set finetune" command.
// Test case: finetune.xm, finetune.mod
// But *do* change the finetune if we switch to a different sample, to fix
// Miranda`s axe by Jamson (jam007.xm) - this file doesn't use compatible play mode,
// so we may want to use IsCompatibleMode instead if further problems arise.
// Miranda`s axe by Jamson (jam007.xm).
chn.nC5Speed = pSmp->nC5Speed;
chn.nFineTune = pSmp->nFineTune;
}
chn.nTranspose = pSmp->RelativeTone;
// FT2 compatibility: Don't reset portamento target with new instrument numbers.
@ -1694,6 +1711,10 @@ void CSoundFile::NoteChange(ModChannel &chn, int note, bool bPorta, bool bResetE
if(note == NOTE_KEYOFF || !(GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)))
{
KeyOff(chn);
// IT compatibility: Note-off + instrument releases sample sustain but does not release envelopes or fade the instrument
// Test case: noteoff3.it, ResetEnvNoteOffOldFx2.it
if(!bPorta && m_playBehaviour[kITInstrWithNoteOffOldEffects] && m_SongFlags[SONG_ITOLDEFFECTS] && chn.rowCommand.instr)
chn.dwFlags.reset(CHN_NOTEFADE | CHN_KEYOFF);
} else // Invalid Note -> Note Fade
{
if(/*note == NOTE_FADE && */ GetNumInstruments())
@ -2783,7 +2804,10 @@ bool CSoundFile::ProcessEffects()
if(smp > 0 && smp <= GetNumSamples() && !Samples[smp].uFlags[SMP_NODEFAULTVOLUME])
chn.nVolume = Samples[smp].nVolume;
}
instr = 0;
// IT compatibility: Note-off with instrument number + Old Effects retriggers envelopes.
// Test case: ResetEnvNoteOffOldFx.it
if(!m_playBehaviour[kITInstrWithNoteOffOldEffects] || !m_SongFlags[SONG_ITOLDEFFECTS])
instr = 0;
}
if(ModCommand::IsNote(note))

View File

@ -1038,6 +1038,7 @@ PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type)
playBehaviour.set(kITInstrWithNoteOff);
playBehaviour.set(kITMultiSampleInstrumentNumber);
playBehaviour.set(kRowDelayWithNoteDelay);
playBehaviour.set(kITInstrWithNoteOffOldEffects);
if(type == MOD_TYPE_MPT)
{
playBehaviour.set(kOPLFlexibleNoteOff);

View File

@ -2235,7 +2235,7 @@ bool CSoundFile::ReadNote()
period = m_nMinPeriod;
}
if((chn.dwFlags & (CHN_ADLIB | CHN_MUTE | CHN_SYNCMUTE)) == CHN_ADLIB && !chn.pModSample->uFlags[CHN_MUTE] && m_opl)
if((chn.dwFlags & (CHN_ADLIB | CHN_MUTE | CHN_SYNCMUTE)) == CHN_ADLIB && m_opl)
{
const bool doProcess = m_playBehaviour[kOPLFlexibleNoteOff] || !chn.dwFlags[CHN_NOTEFADE] || GetType() == MOD_TYPE_S3M;
if(doProcess && !(GetType() == MOD_TYPE_S3M && chn.dwFlags[CHN_KEYOFF]))

View File

@ -430,49 +430,49 @@ void CSoundFile::UpgradeModule()
// Pre-1.26: Detailed compatibility flags did not exist.
static constexpr PlayBehaviourVersion behaviours[] =
{
{ kTempoClamp, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kPerChannelGlobalVolSlide, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kPanOverride, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITInstrWithoutNote, MAKE_VERSION_NUMERIC(1, 17, 02, 46) },
{ kITVolColFinePortamento, MAKE_VERSION_NUMERIC(1, 17, 02, 49) },
{ kITArpeggio, MAKE_VERSION_NUMERIC(1, 17, 02, 49) },
{ kITOutOfRangeDelay, MAKE_VERSION_NUMERIC(1, 17, 02, 49) },
{ kITPortaMemoryShare, MAKE_VERSION_NUMERIC(1, 17, 02, 49) },
{ kITPatternLoopTargetReset, MAKE_VERSION_NUMERIC(1, 17, 02, 49) },
{ kITFT2PatternLoop, MAKE_VERSION_NUMERIC(1, 17, 02, 49) },
{ kITPingPongNoReset, MAKE_VERSION_NUMERIC(1, 17, 02, 51) },
{ kITEnvelopeReset, MAKE_VERSION_NUMERIC(1, 17, 02, 51) },
{ kITClearOldNoteAfterCut, MAKE_VERSION_NUMERIC(1, 17, 02, 52) },
{ kITVibratoTremoloPanbrello, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITTremor, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITRetrigger, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITMultiSampleBehaviour, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITPortaTargetReached, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITPatternLoopBreak, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITOffset, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITSwingBehaviour, MAKE_VERSION_NUMERIC(1, 18, 00, 00) },
{ kITNNAReset, MAKE_VERSION_NUMERIC(1, 18, 00, 00) },
{ kITSCxStopsSample, MAKE_VERSION_NUMERIC(1, 18, 00, 01) },
{ kITEnvelopePositionHandling, MAKE_VERSION_NUMERIC(1, 18, 01, 00) },
{ kITPortamentoInstrument, MAKE_VERSION_NUMERIC(1, 19, 00, 01) },
{ kITPingPongMode, MAKE_VERSION_NUMERIC(1, 19, 00, 21) },
{ kITRealNoteMapping, MAKE_VERSION_NUMERIC(1, 19, 00, 30) },
{ kITHighOffsetNoRetrig, MAKE_VERSION_NUMERIC(1, 20, 00, 14) },
{ kITFilterBehaviour, MAKE_VERSION_NUMERIC(1, 20, 00, 35) },
{ kITNoSurroundPan, MAKE_VERSION_NUMERIC(1, 20, 00, 53) },
{ kITShortSampleRetrig, MAKE_VERSION_NUMERIC(1, 20, 00, 54) },
{ kITPortaNoNote, MAKE_VERSION_NUMERIC(1, 20, 00, 56) },
{ kRowDelayWithNoteDelay, MAKE_VERSION_NUMERIC(1, 20, 00, 76) },
{ kITDontResetNoteOffOnPorta, MAKE_VERSION_NUMERIC(1, 20, 02, 06) },
{ kITVolColMemory, MAKE_VERSION_NUMERIC(1, 21, 01, 16) },
{ kITPortamentoSwapResetsPos, MAKE_VERSION_NUMERIC(1, 21, 01, 25) },
{ kITEmptyNoteMapSlot, MAKE_VERSION_NUMERIC(1, 21, 01, 25) },
{ kITFirstTickHandling, MAKE_VERSION_NUMERIC(1, 22, 07, 09) },
{ kITSampleAndHoldPanbrello, MAKE_VERSION_NUMERIC(1, 22, 07, 19) },
{ kITClearPortaTarget, MAKE_VERSION_NUMERIC(1, 23, 04, 03) },
{ kITPanbrelloHold, MAKE_VERSION_NUMERIC(1, 24, 01, 06) },
{ kITPanningReset, MAKE_VERSION_NUMERIC(1, 24, 01, 06) },
{ kITPatternLoopWithJumps, MAKE_VERSION_NUMERIC(1, 25, 00, 19) },
{ kTempoClamp, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kPerChannelGlobalVolSlide, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kPanOverride, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITInstrWithoutNote, MAKE_VERSION_NUMERIC(1, 17, 02, 46) },
{ kITVolColFinePortamento, MAKE_VERSION_NUMERIC(1, 17, 02, 49) },
{ kITArpeggio, MAKE_VERSION_NUMERIC(1, 17, 02, 49) },
{ kITOutOfRangeDelay, MAKE_VERSION_NUMERIC(1, 17, 02, 49) },
{ kITPortaMemoryShare, MAKE_VERSION_NUMERIC(1, 17, 02, 49) },
{ kITPatternLoopTargetReset, MAKE_VERSION_NUMERIC(1, 17, 02, 49) },
{ kITFT2PatternLoop, MAKE_VERSION_NUMERIC(1, 17, 02, 49) },
{ kITPingPongNoReset, MAKE_VERSION_NUMERIC(1, 17, 02, 51) },
{ kITEnvelopeReset, MAKE_VERSION_NUMERIC(1, 17, 02, 51) },
{ kITClearOldNoteAfterCut, MAKE_VERSION_NUMERIC(1, 17, 02, 52) },
{ kITVibratoTremoloPanbrello, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITTremor, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITRetrigger, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITMultiSampleBehaviour, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITPortaTargetReached, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITPatternLoopBreak, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITOffset, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITSwingBehaviour, MAKE_VERSION_NUMERIC(1, 18, 00, 00) },
{ kITNNAReset, MAKE_VERSION_NUMERIC(1, 18, 00, 00) },
{ kITSCxStopsSample, MAKE_VERSION_NUMERIC(1, 18, 00, 01) },
{ kITEnvelopePositionHandling, MAKE_VERSION_NUMERIC(1, 18, 01, 00) },
{ kITPortamentoInstrument, MAKE_VERSION_NUMERIC(1, 19, 00, 01) },
{ kITPingPongMode, MAKE_VERSION_NUMERIC(1, 19, 00, 21) },
{ kITRealNoteMapping, MAKE_VERSION_NUMERIC(1, 19, 00, 30) },
{ kITHighOffsetNoRetrig, MAKE_VERSION_NUMERIC(1, 20, 00, 14) },
{ kITFilterBehaviour, MAKE_VERSION_NUMERIC(1, 20, 00, 35) },
{ kITNoSurroundPan, MAKE_VERSION_NUMERIC(1, 20, 00, 53) },
{ kITShortSampleRetrig, MAKE_VERSION_NUMERIC(1, 20, 00, 54) },
{ kITPortaNoNote, MAKE_VERSION_NUMERIC(1, 20, 00, 56) },
{ kRowDelayWithNoteDelay, MAKE_VERSION_NUMERIC(1, 20, 00, 76) },
{ kITDontResetNoteOffOnPorta, MAKE_VERSION_NUMERIC(1, 20, 02, 06) },
{ kITVolColMemory, MAKE_VERSION_NUMERIC(1, 21, 01, 16) },
{ kITPortamentoSwapResetsPos, MAKE_VERSION_NUMERIC(1, 21, 01, 25) },
{ kITEmptyNoteMapSlot, MAKE_VERSION_NUMERIC(1, 21, 01, 25) },
{ kITFirstTickHandling, MAKE_VERSION_NUMERIC(1, 22, 07, 09) },
{ kITSampleAndHoldPanbrello, MAKE_VERSION_NUMERIC(1, 22, 07, 19) },
{ kITClearPortaTarget, MAKE_VERSION_NUMERIC(1, 23, 04, 03) },
{ kITPanbrelloHold, MAKE_VERSION_NUMERIC(1, 24, 01, 06) },
{ kITPanningReset, MAKE_VERSION_NUMERIC(1, 24, 01, 06) },
{ kITPatternLoopWithJumps, MAKE_VERSION_NUMERIC(1, 25, 00, 19) },
};
for(const auto &b : behaviours)
@ -484,36 +484,36 @@ void CSoundFile::UpgradeModule()
// Pre-1.26: Detailed compatibility flags did not exist.
static constexpr PlayBehaviourVersion behaviours[] =
{
{ kTempoClamp, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kPerChannelGlobalVolSlide, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kPanOverride, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITFT2PatternLoop, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2Arpeggio, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2Retrigger, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2VolColVibrato, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2PortaNoNote, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2KeyOff, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2PanSlide, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2OffsetOutOfRange, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2RestrictXCommand, MAKE_VERSION_NUMERIC(1, 18, 00, 00) },
{ kFT2RetrigWithNoteDelay, MAKE_VERSION_NUMERIC(1, 18, 00, 00) },
{ kFT2SetPanEnvPos, MAKE_VERSION_NUMERIC(1, 18, 00, 00) },
{ kFT2PortaIgnoreInstr, MAKE_VERSION_NUMERIC(1, 18, 00, 01) },
{ kFT2VolColMemory, MAKE_VERSION_NUMERIC(1, 18, 01, 00) },
{ kFT2LoopE60Restart, MAKE_VERSION_NUMERIC(1, 18, 02, 01) },
{ kFT2ProcessSilentChannels, MAKE_VERSION_NUMERIC(1, 18, 02, 01) },
{ kFT2ReloadSampleSettings, MAKE_VERSION_NUMERIC(1, 20, 00, 36) },
{ kFT2PortaDelay, MAKE_VERSION_NUMERIC(1, 20, 00, 40) },
{ kFT2Transpose, MAKE_VERSION_NUMERIC(1, 20, 00, 62) },
{ kFT2PatternLoopWithJumps, MAKE_VERSION_NUMERIC(1, 20, 00, 69) },
{ kFT2PortaTargetNoReset, MAKE_VERSION_NUMERIC(1, 20, 00, 69) },
{ kFT2EnvelopeEscape, MAKE_VERSION_NUMERIC(1, 20, 00, 77) },
{ kFT2Tremor, MAKE_VERSION_NUMERIC(1, 20, 01, 11) },
{ kFT2OutOfRangeDelay, MAKE_VERSION_NUMERIC(1, 20, 02, 02) },
{ kFT2Periods, MAKE_VERSION_NUMERIC(1, 22, 03, 01) },
{ kFT2PanWithDelayedNoteOff, MAKE_VERSION_NUMERIC(1, 22, 03, 02) },
{ kFT2VolColDelay, MAKE_VERSION_NUMERIC(1, 22, 07, 19) },
{ kFT2FinetunePrecision, MAKE_VERSION_NUMERIC(1, 22, 07, 19) },
{ kTempoClamp, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kPerChannelGlobalVolSlide, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kPanOverride, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITFT2PatternLoop, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2Arpeggio, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2Retrigger, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2VolColVibrato, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2PortaNoNote, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2KeyOff, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2PanSlide, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2OffsetOutOfRange, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2RestrictXCommand, MAKE_VERSION_NUMERIC(1, 18, 00, 00) },
{ kFT2RetrigWithNoteDelay, MAKE_VERSION_NUMERIC(1, 18, 00, 00) },
{ kFT2SetPanEnvPos, MAKE_VERSION_NUMERIC(1, 18, 00, 00) },
{ kFT2PortaIgnoreInstr, MAKE_VERSION_NUMERIC(1, 18, 00, 01) },
{ kFT2VolColMemory, MAKE_VERSION_NUMERIC(1, 18, 01, 00) },
{ kFT2LoopE60Restart, MAKE_VERSION_NUMERIC(1, 18, 02, 01) },
{ kFT2ProcessSilentChannels, MAKE_VERSION_NUMERIC(1, 18, 02, 01) },
{ kFT2ReloadSampleSettings, MAKE_VERSION_NUMERIC(1, 20, 00, 36) },
{ kFT2PortaDelay, MAKE_VERSION_NUMERIC(1, 20, 00, 40) },
{ kFT2Transpose, MAKE_VERSION_NUMERIC(1, 20, 00, 62) },
{ kFT2PatternLoopWithJumps, MAKE_VERSION_NUMERIC(1, 20, 00, 69) },
{ kFT2PortaTargetNoReset, MAKE_VERSION_NUMERIC(1, 20, 00, 69) },
{ kFT2EnvelopeEscape, MAKE_VERSION_NUMERIC(1, 20, 00, 77) },
{ kFT2Tremor, MAKE_VERSION_NUMERIC(1, 20, 01, 11) },
{ kFT2OutOfRangeDelay, MAKE_VERSION_NUMERIC(1, 20, 02, 02) },
{ kFT2Periods, MAKE_VERSION_NUMERIC(1, 22, 03, 01) },
{ kFT2PanWithDelayedNoteOff, MAKE_VERSION_NUMERIC(1, 22, 03, 02) },
{ kFT2VolColDelay, MAKE_VERSION_NUMERIC(1, 22, 07, 19) },
{ kFT2FinetunePrecision, MAKE_VERSION_NUMERIC(1, 22, 07, 19) },
};
for(const auto &b : behaviours)
@ -527,8 +527,9 @@ void CSoundFile::UpgradeModule()
// The following behaviours were added in/after OpenMPT 1.26, so are not affected by the upgrade mechanism above.
static constexpr PlayBehaviourVersion behaviours[] =
{
{ kITInstrWithNoteOff, MAKE_VERSION_NUMERIC(1, 26, 00, 01) },
{ kITMultiSampleInstrumentNumber, MAKE_VERSION_NUMERIC(1, 27, 00, 27) },
{ kITInstrWithNoteOff, MAKE_VERSION_NUMERIC(1, 26, 00, 01) },
{ kITMultiSampleInstrumentNumber, MAKE_VERSION_NUMERIC(1, 27, 00, 27) },
{ kITInstrWithNoteOffOldEffects, MAKE_VERSION_NUMERIC(1, 28, 02, 06) },
};
for(const auto &b : behaviours)
@ -544,12 +545,12 @@ void CSoundFile::UpgradeModule()
// The following behaviours were added after OpenMPT 1.26, so are not affected by the upgrade mechanism above.
static constexpr PlayBehaviourVersion behaviours[] =
{
{ kFT2NoteOffFlags, MAKE_VERSION_NUMERIC(1, 27, 00, 27) },
{ kRowDelayWithNoteDelay, MAKE_VERSION_NUMERIC(1, 27, 00, 37) },
{ kFT2TremoloRampWaveform, MAKE_VERSION_NUMERIC(1, 27, 00, 37) },
{ kFT2PortaUpDownMemory, MAKE_VERSION_NUMERIC(1, 27, 00, 37) },
{ kFT2PanSustainRelease, MAKE_VERSION_NUMERIC(1, 28, 00, 09) },
{ kFT2NoteDelayWithoutInstr, MAKE_VERSION_NUMERIC(1, 28, 00, 44) },
{ kFT2NoteOffFlags, MAKE_VERSION_NUMERIC(1, 27, 00, 27) },
{ kRowDelayWithNoteDelay, MAKE_VERSION_NUMERIC(1, 27, 00, 37) },
{ kFT2TremoloRampWaveform, MAKE_VERSION_NUMERIC(1, 27, 00, 37) },
{ kFT2PortaUpDownMemory, MAKE_VERSION_NUMERIC(1, 27, 00, 37) },
{ kFT2PanSustainRelease, MAKE_VERSION_NUMERIC(1, 28, 00, 09) },
{ kFT2NoteDelayWithoutInstr, MAKE_VERSION_NUMERIC(1, 28, 00, 44) },
};
for(const auto &b : behaviours)