Updated libOpenMPT to version 0.6.6

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
main
Christopher Snowhill 2022-10-11 22:47:02 -07:00
parent 929ab11738
commit 894aada3d2
17 changed files with 199 additions and 57 deletions

View File

@ -1,4 +1,4 @@
MPT_SVNVERSION=17761
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.6.5
MPT_SVNDATE=2022-08-21T11:52:57.985463Z
MPT_SVNVERSION=17954
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.6.6
MPT_SVNDATE=2022-09-25T14:18:19.447172Z

View File

@ -80,6 +80,11 @@ CXXFLAGS +=
CFLAGS +=
LDFLAGS += -s WASM=2 -s LEGACY_VM_SUPPORT=1 -Wno-transpile
# work-around <https://github.com/emscripten-core/emscripten/issues/17897>.
CXXFLAGS += -fno-inline-functions
CFLAGS += -fno-inline-functions
LDFLAGS += -fno-inline-functions
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
else ifeq ($(EMSCRIPTEN_TARGET),audioworkletprocessor)
@ -107,6 +112,11 @@ CXXFLAGS +=
CFLAGS +=
LDFLAGS += -s WASM=0 -s LEGACY_VM_SUPPORT=1 -Wno-transpile
# work-around <https://github.com/emscripten-core/emscripten/issues/17897>.
CXXFLAGS += -fno-inline-functions
CFLAGS += -fno-inline-functions
LDFLAGS += -fno-inline-functions
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
endif

View File

@ -1,10 +1,10 @@
#pragma once
#define OPENMPT_VERSION_SVNVERSION "17761"
#define OPENMPT_VERSION_REVISION 17761
#define OPENMPT_VERSION_SVNVERSION "17954"
#define OPENMPT_VERSION_REVISION 17954
#define OPENMPT_VERSION_DIRTY 0
#define OPENMPT_VERSION_MIXEDREVISIONS 0
#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.6.5"
#define OPENMPT_VERSION_DATE "2022-08-21T11:52:57.985463Z"
#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.6.6"
#define OPENMPT_VERSION_DATE "2022-09-25T14:18:19.447172Z"
#define OPENMPT_VERSION_IS_PACKAGE 1

View File

@ -17,7 +17,7 @@ OPENMPT_NAMESPACE_BEGIN
// Version definitions. The only thing that needs to be changed when changing version number.
#define VER_MAJORMAJOR 1
#define VER_MAJOR 30
#define VER_MINOR 06
#define VER_MINOR 07
#define VER_MINORMINOR 00
OPENMPT_NAMESPACE_END

View File

@ -5,6 +5,22 @@ Changelog {#changelog}
For fully detailed change log, please see the source repository directly. This
is just a high-level summary.
### libopenmpt 0.6.6 (2022-09-25)
* [**Sec**] Possible crash when playing manipulated IT / MPTM files with a T00
command. (r17789)
* MTM: In MultiTracker, setting speed and tempo are mutually exclusive
commands. Still, some MultiTracker modules were made to be played with
external players such as DMP, so they actually rely on "standard" speed /
tempo behaviour. Decide which behaviour to use by checking of speed and
tempo commands are found on the same row.
* MTM: Ignore sample loops if the loop end is <= 2.
* Echo DMO: Migrate left and right delay values in modules made with OpenMPT
versions between 1.27.01.00 and 1.30.05.00 to the correct interpretation.
* FLAC: Update to v1.4.1 (2022-09-22).
### libopenmpt 0.6.5 (2022-08-21)
* [**Bug**] `Makefile` now also uses `CC`, `CXX`, `LD`, and `AR` when set as

View File

@ -21,7 +21,7 @@
/*! \brief libopenmpt minor version number */
#define OPENMPT_API_VERSION_MINOR 6
/*! \brief libopenmpt patch version number */
#define OPENMPT_API_VERSION_PATCH 5
#define OPENMPT_API_VERSION_PATCH 6
/*! \brief libopenmpt pre-release tag */
#define OPENMPT_API_VERSION_PREREL ""
/*! \brief libopenmpt pre-release flag */

View File

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

View File

@ -646,6 +646,7 @@ bool CDLSBank::FindAndExtract(CSoundFile &sndFile, const INSTRUMENTINDEX ins, co
const uint32 program = (pIns->nMidiProgram != 0) ? pIns->nMidiProgram - 1 : 0;
const uint32 key = isDrum ? (pIns->nMidiDrumKey & 0x7F) : 0xFF;
if(FindInstrument(isDrum, (pIns->wMidiBank - 1) & 0x3FFF, program, key, &dlsIns)
|| FindInstrument(isDrum, (pIns->wMidiBank - 1) & 0x3F80, program, key, &dlsIns)
|| FindInstrument(isDrum, 0xFFFF, isDrum ? 0xFF : program, key, &dlsIns))
{
if(key < 0x80) drumRgn = GetRegionFromKey(dlsIns, key);

View File

@ -17,18 +17,18 @@ OPENMPT_NAMESPACE_BEGIN
// File Header
struct MTMFileHeader
{
char id[3]; // MTM file marker
uint8le version; // Tracker version
char songName[20]; // ASCIIZ songname
uint16le numTracks; // Number of tracks saved
uint8le lastPattern; // Last pattern number saved
uint8le lastOrder; // Last order number to play (songlength-1)
uint16le commentSize; // Length of comment field
uint8le numSamples; // Number of samples saved
uint8le attribute; // Attribute byte (unused)
uint8le beatsPerTrack; // Numbers of rows in every pattern (MultiTracker itself does not seem to support values != 64)
uint8le numChannels; // Number of channels used
uint8le panPos[32]; // Channel pan positions
char id[3]; // MTM file marker
uint8le version; // Tracker version
char songName[20]; // ASCIIZ songname
uint16le numTracks; // Number of tracks saved
uint8le lastPattern; // Last pattern number saved
uint8le lastOrder; // Last order number to play (songlength-1)
uint16le commentSize; // Length of comment field
uint8le numSamples; // Number of samples saved
uint8le attribute; // Attribute byte (unused)
uint8le beatsPerTrack; // Numbers of rows in every pattern (MultiTracker itself does not seem to support values != 64)
uint8le numChannels; // Number of channels used
uint8le panPos[32]; // Channel pan positions
};
MPT_BINARY_STRUCT(MTMFileHeader, 66)
@ -56,8 +56,10 @@ struct MTMSampleHeader
mptSmp.nLoopStart = loopStart;
mptSmp.nLoopEnd = std::max(loopEnd.get(), uint32(1)) - 1;
LimitMax(mptSmp.nLoopEnd, mptSmp.nLength);
if(mptSmp.nLoopStart + 4 >= mptSmp.nLoopEnd) mptSmp.nLoopStart = mptSmp.nLoopEnd = 0;
if(mptSmp.nLoopEnd) mptSmp.uFlags.set(CHN_LOOP);
if(mptSmp.nLoopStart + 4 >= mptSmp.nLoopEnd)
mptSmp.nLoopStart = mptSmp.nLoopEnd = 0;
if(mptSmp.nLoopEnd > 2)
mptSmp.uFlags.set(CHN_LOOP);
mptSmp.nFineTune = finetune; // Uses MOD units but allows the full int8 range rather than just -8...+7 so we keep the value as-is and convert it during playback
mptSmp.nC5Speed = ModSample::TransposeToFrequency(0, finetune * 16);
@ -170,6 +172,8 @@ bool CSoundFile::ReadMTM(FileReader &file, ModLoadingFlags loadFlags)
if(loadFlags & loadPatternData)
Patterns.ResizeArray(fileHeader.lastPattern + 1);
bool hasSpeed = false, hasTempo = false;
for(PATTERNINDEX pat = 0; pat <= fileHeader.lastPattern; pat++)
{
if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, rowsPerPat))
@ -228,6 +232,63 @@ bool CSoundFile::ReadMTM(FileReader &file, ModLoadingFlags loadFlags)
#ifdef MODPLUG_TRACKER
m->Convert(MOD_TYPE_MTM, MOD_TYPE_S3M, *this);
#endif
if(m->command == CMD_SPEED)
hasSpeed = true;
else if(m->command == CMD_TEMPO)
hasTempo = true;
}
}
}
}
// Curiously, speed commands reset the tempo to 125 in MultiTracker, and tempo commands reset the speed to 6.
// External players of the time (e.g. DMP) did not implement this quirk and assumed a more ProTracker-like interpretation of speed and tempo.
// Quite a few musicians created MTMs that make use DMP's speed and tempo interpretation, which in return means that they will play too
// fast or too slow in MultiTracker. On the other hand there are also a few MTMs that break when using ProTracker-like speed and tempo.
// As a way to support as many modules of both types as possible, we will assume a ProTracker-like interpretation if both speed and tempo
// commands are found on the same line, and a MultiTracker-like interpretation when they are never found on the same line.
if(hasSpeed && hasTempo)
{
bool hasSpeedAndTempoOnSameRow = false;
for(const auto &pattern : Patterns)
{
for(ROWINDEX row = 0; row < pattern.GetNumRows(); row++)
{
const auto rowBase = pattern.GetRow(row);
bool hasSpeedOnRow = false, hasTempoOnRow = false;
for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++)
{
if(rowBase[chn].command == CMD_SPEED)
hasSpeedOnRow = true;
else if(rowBase[chn].command == CMD_TEMPO)
hasTempoOnRow = true;
}
if(hasSpeedOnRow && hasTempoOnRow)
{
hasSpeedAndTempoOnSameRow = true;
break;
}
}
if(hasSpeedAndTempoOnSameRow)
break;
}
if(!hasSpeedAndTempoOnSameRow)
{
for(auto &pattern : Patterns)
{
for(ROWINDEX row = 0; row < pattern.GetNumRows(); row++)
{
const auto rowBase = pattern.GetRow(row);
for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++)
{
if(rowBase[chn].command == CMD_SPEED || rowBase[chn].command == CMD_TEMPO)
{
const bool writeTempo = rowBase[chn].command == CMD_SPEED;
pattern.WriteEffect(EffectWriter(writeTempo ? CMD_TEMPO : CMD_SPEED, writeTempo ? 125 : 6).Row(row));
break;
}
}
}
}
}

View File

@ -24,6 +24,10 @@
#ifdef MPT_ENABLE_MP3_SAMPLES
#include "MPEGFrame.h"
#endif // MPT_ENABLE_MP3_SAMPLES
#if defined(MPT_WITH_MINIMP3)
#include "mpt/base/alloc.hpp"
#endif // MPT_WITH_MINIMP3
#if defined(MPT_WITH_MINIMP3)
#include <minimp3/minimp3.h>
#endif // MPT_WITH_MINIMP3
@ -163,6 +167,28 @@ static mpt::ustring ReadMPG123String(const char (&str)[N])
#endif // MPT_WITH_MPG123
#if defined(MPT_WITH_MINIMP3)
#if MPT_COMPILER_GCC
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wframe-larger-than=16000"
#endif // MPT_COMPILER_GCC
#if MPT_CLANG_AT_LEAST(13,0,0)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wframe-larger-than"
#endif // MPT_COMPILER_CLANG
static MPT_NOINLINE int mp3dec_decode_frame_no_inline(mp3dec_t *dec, const uint8_t *mp3, int mp3_bytes, mp3d_sample_t *pcm, mp3dec_frame_info_t *info)
{
return mp3dec_decode_frame(dec, mp3, mp3_bytes, pcm, info);
}
#if MPT_CLANG_AT_LEAST(13,0,0)
#pragma clang diagnostic pop
#endif // MPT_COMPILER_CLANG
#if MPT_COMPILER_GCC
#pragma GCC diagnostic pop
#endif // MPT_COMPILER_GCC
#endif // MPT_WITH_MINIMP3
bool CSoundFile::ReadMP3Sample(SAMPLEINDEX sample, FileReader &file, bool raw, bool mo3Decode)
{
#if defined(MPT_WITH_MPG123) || defined(MPT_WITH_MINIMP3)
@ -603,19 +629,19 @@ bool CSoundFile::ReadMP3Sample(SAMPLEINDEX sample, FileReader &file, bool raw, b
std::vector<int16> raw_sample_data;
mp3dec_t mp3;
std::memset(&mp3, 0, sizeof(mp3dec_t));
mp3dec_init(&mp3);
mpt::heap_value<mp3dec_t> mp3;
std::memset(&*mp3, 0, sizeof(mp3dec_t));
mp3dec_init(&*mp3);
int rate = 0;
int channels = 0;
mp3dec_frame_info_t info;
std::memset(&info, 0, sizeof(mp3dec_frame_info_t));
std::vector<int16> sample_buf(MINIMP3_MAX_SAMPLES_PER_FRAME);
do
{
int16 sample_buf[MINIMP3_MAX_SAMPLES_PER_FRAME];
int frame_samples = mp3dec_decode_frame(&mp3, stream_pos, mpt::saturate_cast<int>(bytes_left), sample_buf, &info);
int frame_samples = mp3dec_decode_frame_no_inline(&*mp3, stream_pos, mpt::saturate_cast<int>(bytes_left), sample_buf.data(), &info);
if(frame_samples < 0 || info.frame_bytes < 0) break; // internal error in minimp3
if(frame_samples > 0 && info.frame_bytes == 0) break; // internal error in minimp3
if(frame_samples == 0 && info.frame_bytes == 0) break; // end of stream, no progress
@ -635,7 +661,7 @@ bool CSoundFile::ReadMP3Sample(SAMPLEINDEX sample, FileReader &file, bool raw, b
{
try
{
mpt::append(raw_sample_data, sample_buf, sample_buf + frame_samples * channels);
mpt::append(raw_sample_data, sample_buf.data(), sample_buf.data() + frame_samples * channels);
} catch(mpt::out_of_memory e)
{
mpt::delete_out_of_memory(e);

View File

@ -913,13 +913,13 @@ bool CSoundFile::ReadSFZInstrument(INSTRUMENTINDEX nInstr, FileReader &file)
switch(region.loopMode)
{
case SFZRegion::LoopMode::kContinuous:
case SFZRegion::LoopMode::kOneShot:
sample.uFlags.set(CHN_LOOP);
break;
case SFZRegion::LoopMode::kSustain:
sample.uFlags.set(CHN_SUSTAINLOOP);
break;
case SFZRegion::LoopMode::kNoLoop:
case SFZRegion::LoopMode::kOneShot:
sample.uFlags.reset(CHN_LOOP | CHN_SUSTAINLOOP);
}
}

View File

@ -2232,8 +2232,12 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo
case DuplicateNoteAction::NoteOff:
case DuplicateNoteAction::NoteFade:
// Switch off duplicated note played on this plugin
SendMIDINote(i, chn.GetPluginNote(m_playBehaviour[kITRealNoteMapping]) + NOTE_MAX_SPECIAL, 0);
chn.nArpeggioLastNote = NOTE_NONE;
if(const auto oldNote = chn.GetPluginNote(m_playBehaviour[kITRealNoteMapping]); oldNote != NOTE_NONE)
{
SendMIDINote(i, oldNote + NOTE_MAX_SPECIAL, 0);
chn.nArpeggioLastNote = NOTE_NONE;
chn.nNote = NOTE_NONE;
}
break;
}
}
@ -2285,7 +2289,8 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo
{
// 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]), nChn);
const auto oldNote = srcChn.GetPluginNote(m_playBehaviour[kITRealNoteMapping]);
applyNNAtoPlug = (oldNote != NOTE_NONE) && pPlugin->IsNotePlaying(oldNote, nChn);
}
}
}
@ -2295,6 +2300,24 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo
if(!srcChn.IsSamplePlaying() && !applyNNAtoPlug)
return CHANNELINDEX_INVALID;
#ifndef NO_PLUGINS
if(applyNNAtoPlug && pPlugin)
{
switch(srcChn.nNNA)
{
case NewNoteAction::NoteOff:
case NewNoteAction::NoteCut:
case NewNoteAction::NoteFade:
// Switch off note played on this plugin, on this tracker channel and midi channel
SendMIDINote(nChn, NOTE_KEYOFF, 0);
srcChn.nArpeggioLastNote = NOTE_NONE;
break;
case NewNoteAction::Continue:
break;
}
}
#endif // NO_PLUGINS
CHANNELINDEX nnaChn = GetNNAChannel(nChn);
if(nnaChn == CHANNELINDEX_INVALID)
return CHANNELINDEX_INVALID;
@ -2309,23 +2332,6 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo
chn.nMasterChn = nChn < GetNumChannels() ? nChn + 1 : 0;
chn.nCommand = CMD_NONE;
#ifndef NO_PLUGINS
if(applyNNAtoPlug && pPlugin)
{
switch(srcChn.nNNA)
{
case NewNoteAction::NoteOff:
case NewNoteAction::NoteCut:
case NewNoteAction::NoteFade:
// Switch off note played on this plugin, on this tracker channel and midi channel
SendMIDINote(nChn, NOTE_KEYOFF, 0);
srcChn.nArpeggioLastNote = NOTE_NONE;
break;
case NewNoteAction::Continue:
break;
}
}
#endif // NO_PLUGINS
// Key Off the note
switch(srcChn.nNNA)

View File

@ -696,7 +696,7 @@ bool CSoundFile::ProcessRow()
{
// ProTracker sets the tempo after the first tick. This block handles the case of one tick per row.
// Test case: TempoChange.mod
m_PlayState.m_nMusicTempo = TEMPO(pChn->rowCommand.param, 0);
m_PlayState.m_nMusicTempo = TEMPO(std::max(ModCommand::PARAM(1), pChn->rowCommand.param), 0);
}
pChn->rowCommand = *m;

View File

@ -1,7 +1,8 @@
/*
* UpdateModule.cpp
* ----------------
* Purpose: CSoundFile functions for correcting modules made with previous versions of OpenMPT.
* Purpose: Compensate for playback bugs of previous OpenMPT versions during import
* by rewriting patterns / samples / instruments or enabling / disabling specific compatibility flags
* Notes : (currently none)
* Authors: OpenMPT Devs
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
@ -726,6 +727,24 @@ void CSoundFile::UpgradeModule()
plugin.Info.szLibraryName = "Flanger (Legacy)";
}
}
if(m_dwLastSavedWithVersion >= MPT_V("1.27") && m_dwLastSavedWithVersion < MPT_V("1.30.06.00") && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM)))
{
// Fix off-by-one delay length in older Echo DMO emulation
for(auto &plugin : m_MixPlugins)
{
if(plugin.Info.dwPluginId1 == kDmoMagic && plugin.Info.dwPluginId2 == int32(0xEF3E932C) && plugin.pluginData.size() == 24)
{
float32le leftDelay, rightDelay;
memcpy(&leftDelay, plugin.pluginData.data() + 12, 4);
memcpy(&rightDelay, plugin.pluginData.data() + 16, 4);
leftDelay = float32le{mpt::safe_clamp(((leftDelay * 2000.0f) - 1.0f) / 1999.0f, 0.0f, 1.0f)};
rightDelay = float32le{mpt::safe_clamp(((rightDelay * 2000.0f) - 1.0f) / 1999.0f, 0.0f, 1.0f)};
memcpy(plugin.pluginData.data() + 12, &leftDelay, 4);
memcpy(plugin.pluginData.data() + 16, &rightDelay, 4);
}
}
}
}
OPENMPT_NAMESPACE_END

View File

@ -884,7 +884,7 @@ void IMidiPlugin::MidiCommand(const ModInstrument &instr, uint16 note, uint16 vo
bool bankChanged = (channel.currentBank != midiBank) && (midiBank < 0x4000);
bool progChanged = (channel.currentProgram != midiProg) && (midiProg < 0x80);
//get vol in [0,128[
uint8 volume = static_cast<uint8>(std::min(vol / 2u, 127u));
uint8 volume = static_cast<uint8>(std::min((vol + 1u) / 2u, 127u));
// Bank change
if(bankChanged)

View File

@ -37,8 +37,8 @@ Echo::Echo(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
{
m_param[kEchoWetDry] = 0.5f;
m_param[kEchoFeedback] = 0.5f;
m_param[kEchoLeftDelay] = 0.25f;
m_param[kEchoRightDelay] = 0.25f;
m_param[kEchoLeftDelay] = (500.0f - 1.0f) / 1999.0f;
m_param[kEchoRightDelay] = (500.0f - 1.0f) / 1999.0f;
m_param[kEchoPanDelay] = 0.0f;
m_mixBuffer.Initialize(2, 2);

View File

@ -10,6 +10,9 @@
#define MPT_OS_DJGPP 1
#elif defined(__EMSCRIPTEN__)
#define MPT_OS_EMSCRIPTEN 1
#if !defined(__EMSCRIPTEN_major__) || !defined(__EMSCRIPTEN_minor__) || !defined(__EMSCRIPTEN_tiny__)
#include <emscripten/version.h>
#endif
#if defined(__EMSCRIPTEN_major__) && defined(__EMSCRIPTEN_minor__)
#if (__EMSCRIPTEN_major__ > 1)
// ok