Updated libopenmpt to version 0.3.9.
parent
baace3fea9
commit
dce35b2924
|
@ -629,6 +629,13 @@ mpt::ustring GetFullCreditsString()
|
|||
"http://www.hermannseib.com/english/vsthost.htm\n"
|
||||
"\n"
|
||||
#endif
|
||||
"Storlek for all the IT compatibility hints and testcases\n"
|
||||
"as well as the IMF, MDL, OKT and ULT loaders\n"
|
||||
"http://schismtracker.org/\n"
|
||||
"\n"
|
||||
"Sergei \"x0r\" Kolzun for various hints on Scream Tracker 2 compatibility\n"
|
||||
"https://github.com/viiri/st2play\n"
|
||||
"\n"
|
||||
"Laurent Cl\xc3\xA9vy for unofficial MO3 documentation and decompression code\n"
|
||||
"https://github.com/lclevy/unmo3\n"
|
||||
"\n"
|
||||
|
@ -716,10 +723,6 @@ mpt::ustring GetFullCreditsString()
|
|||
"https://github.com/kazuho/picojson\n"
|
||||
"\n"
|
||||
#endif
|
||||
"Storlek for all the IT compatibility hints and testcases\n"
|
||||
"as well as the IMF, MDL, OKT and ULT loaders\n"
|
||||
"http://schismtracker.org/\n"
|
||||
"\n"
|
||||
#ifdef MODPLUG_TRACKER
|
||||
"Lennart Poettering and David Henningsson for RealtimeKit\n"
|
||||
"http://git.0pointer.net/rtkit.git/\n"
|
||||
|
|
|
@ -19,7 +19,7 @@ OPENMPT_NAMESPACE_BEGIN
|
|||
#define VER_MAJORMAJOR 1
|
||||
#define VER_MAJOR 27
|
||||
#define VER_MINOR 07
|
||||
#define VER_MINORMINOR 00
|
||||
#define VER_MINORMINOR 02
|
||||
|
||||
//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)
|
||||
|
|
|
@ -5,10 +5,26 @@ Changelog {#changelog}
|
|||
For fully detailed change log, please see the source repository directly. This
|
||||
is just a high-level summary.
|
||||
|
||||
### libopenmpt 0.3.9 (2018-04-29)
|
||||
|
||||
* [**Sec**] Possible write near address 0 in out-of-memory situations when
|
||||
reading AMS files (r10149).
|
||||
|
||||
* [**Bug**] openmpt123: Fixed build failure in C++17 due to use of removed
|
||||
feature `std::random_shuffle`.
|
||||
|
||||
* STM: Having both Bxx and Cxx commands in a pattern imported the Bxx command
|
||||
incorrectly.
|
||||
* STM: Last character of sample name was missing.
|
||||
* Speed up reading of truncated ULT files.
|
||||
* ULT: Portamento import was sometimes broken.
|
||||
* The resonant filter was sometimes unstable when combining low-volume
|
||||
samples, low cutoff and high mixing rates.
|
||||
|
||||
### libopenmpt 0.3.8 (2018-04-08)
|
||||
|
||||
* [**Sec**] Possible out-of-bounds memory read with IT / ITP / MO3 files
|
||||
containing pattern loops (r10028).
|
||||
* [**Sec**] Possible out-of-bounds memory read with IT and MO3 files
|
||||
containing many nested pattern loops (r10028).
|
||||
|
||||
* Keep track of active SFx macro during seeking.
|
||||
* The "note cut" duplicate note action did not volume-ramp the previously
|
||||
|
@ -60,7 +76,6 @@ is just a high-level summary.
|
|||
* Tighten M15 and MOD file rejection heuristics.
|
||||
* J2B: Ignore frequency limits from file header. Fixes Medivo.j2b, broken
|
||||
since libopenmpt-0.2.6401-beta17.
|
||||
* STM: Last character of sample name was missing.
|
||||
* ParamEq plugin center frequency was not limited correctly.
|
||||
* libopenmpt_ext C API was not included in the documentation.
|
||||
|
||||
|
|
|
@ -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 8
|
||||
#define OPENMPT_API_VERSION_PATCH 9
|
||||
/*! \brief libopenmpt pre-release tag */
|
||||
#define OPENMPT_API_VERSION_PREREL ""
|
||||
/*! \brief libopenmpt pre-release flag */
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
LIBOPENMPT_VERSION_MAJOR=0
|
||||
LIBOPENMPT_VERSION_MINOR=3
|
||||
LIBOPENMPT_VERSION_PATCH=8
|
||||
LIBOPENMPT_VERSION_PATCH=9
|
||||
LIBOPENMPT_VERSION_PREREL=
|
||||
|
||||
LIBOPENMPT_LTVER_CURRENT=1
|
||||
LIBOPENMPT_LTVER_REVISION=8
|
||||
LIBOPENMPT_LTVER_REVISION=9
|
||||
LIBOPENMPT_LTVER_AGE=1
|
||||
|
|
|
@ -290,7 +290,7 @@ static void load_settings_from_map( libopenmpt::plugin::settings & s, const std:
|
|||
|
||||
static void load_settings_from_xml( libopenmpt::plugin::settings & s, const std::string & xml ) {
|
||||
pugi::xml_document doc;
|
||||
doc.load( xml.c_str() );
|
||||
doc.load_string( xml.c_str() );
|
||||
pugi::xml_node settings_node = doc.child( "settings" );
|
||||
std::map<std::string,int> map;
|
||||
for ( pugi::xml_attribute_iterator it = settings_node.attributes_begin(); it != settings_node.attributes_end(); ++it ) {
|
||||
|
|
|
@ -47,6 +47,7 @@ static const char * const license =
|
|||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <random>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
@ -1754,18 +1755,17 @@ static void render_file( commandlineflags & flags, const std::string & filename,
|
|||
}
|
||||
|
||||
|
||||
static std::string get_random_filename(std::set<std::string> & filenames) {
|
||||
// TODO: actually use a useful random distribution
|
||||
std::size_t index = std::rand() % filenames.size();
|
||||
static std::string get_random_filename( std::set<std::string> & filenames, std::default_random_engine & prng ) {
|
||||
std::size_t index = std::uniform_int_distribution<std::size_t>( 0, filenames.size() - 1 )( prng );
|
||||
std::set<std::string>::iterator it = filenames.begin();
|
||||
std::advance( it, index );
|
||||
return *it;
|
||||
}
|
||||
|
||||
|
||||
static void render_files( commandlineflags & flags, textout & log, write_buffers_interface & audio_stream ) {
|
||||
static void render_files( commandlineflags & flags, textout & log, write_buffers_interface & audio_stream, std::default_random_engine & prng ) {
|
||||
if ( flags.randomize ) {
|
||||
std::random_shuffle( flags.filenames.begin(), flags.filenames.end() );
|
||||
std::shuffle( flags.filenames.begin(), flags.filenames.end(), prng );
|
||||
}
|
||||
try {
|
||||
while ( true ) {
|
||||
|
@ -1777,7 +1777,7 @@ static void render_files( commandlineflags & flags, textout & log, write_buffers
|
|||
if ( shuffle_set.empty() ) {
|
||||
break;
|
||||
}
|
||||
std::string filename = get_random_filename( shuffle_set );
|
||||
std::string filename = get_random_filename( shuffle_set, prng );
|
||||
try {
|
||||
flags.playlist_index = std::find( flags.filenames.begin(), flags.filenames.end(), filename ) - flags.filenames.begin();
|
||||
render_file( flags, filename, log, audio_stream );
|
||||
|
@ -2393,7 +2393,10 @@ static int main( int argc, char * argv [] ) {
|
|||
|
||||
log.writeout();
|
||||
|
||||
std::srand( static_cast<unsigned int>( std::time( NULL ) ) );
|
||||
std::random_device rd;
|
||||
std::seed_seq seq{ rd(), static_cast<unsigned int>( std::time( NULL ) ) };
|
||||
std::default_random_engine prng( seq );
|
||||
std::srand( std::uniform_int_distribution<unsigned int>()( prng ) );
|
||||
|
||||
switch ( flags.mode ) {
|
||||
case ModeProbe: {
|
||||
|
@ -2404,42 +2407,42 @@ static int main( int argc, char * argv [] ) {
|
|||
} break;
|
||||
case ModeInfo: {
|
||||
void_audio_stream dummy;
|
||||
render_files( flags, log, dummy );
|
||||
render_files( flags, log, dummy, prng );
|
||||
} break;
|
||||
case ModeUI:
|
||||
case ModeBatch: {
|
||||
if ( flags.use_stdout ) {
|
||||
flags.apply_default_buffer_sizes();
|
||||
stdout_stream_raii stdout_audio_stream;
|
||||
render_files( flags, log, stdout_audio_stream );
|
||||
render_files( flags, log, stdout_audio_stream, prng );
|
||||
} else if ( !flags.output_filename.empty() ) {
|
||||
flags.apply_default_buffer_sizes();
|
||||
file_audio_stream_raii file_audio_stream( flags, flags.output_filename, log );
|
||||
render_files( flags, log, file_audio_stream );
|
||||
render_files( flags, log, file_audio_stream, prng );
|
||||
#if defined( MPT_WITH_PULSEAUDIO )
|
||||
} else if ( flags.driver == "pulseaudio" || flags.driver.empty() ) {
|
||||
pulseaudio_stream_raii pulseaudio_stream( flags, log );
|
||||
render_files( flags, log, pulseaudio_stream );
|
||||
render_files( flags, log, pulseaudio_stream, prng );
|
||||
#endif
|
||||
#if defined( MPT_WITH_SDL2 )
|
||||
} else if ( flags.driver == "sdl2" || flags.driver.empty() ) {
|
||||
sdl2_stream_raii sdl2_stream( flags, log );
|
||||
render_files( flags, log, sdl2_stream );
|
||||
render_files( flags, log, sdl2_stream, prng );
|
||||
#endif
|
||||
#if defined( MPT_WITH_SDL )
|
||||
} else if ( flags.driver == "sdl" || flags.driver.empty() ) {
|
||||
sdl_stream_raii sdl_stream( flags, log );
|
||||
render_files( flags, log, sdl_stream );
|
||||
render_files( flags, log, sdl_stream, prng );
|
||||
#endif
|
||||
#if defined( MPT_WITH_PORTAUDIO )
|
||||
} else if ( flags.driver == "portaudio" || flags.driver.empty() ) {
|
||||
portaudio_stream_raii portaudio_stream( flags, log );
|
||||
render_files( flags, log, portaudio_stream );
|
||||
render_files( flags, log, portaudio_stream, prng );
|
||||
#endif
|
||||
#if defined( WIN32 )
|
||||
} else if ( flags.driver == "waveout" || flags.driver.empty() ) {
|
||||
waveout_stream_raii waveout_stream( flags );
|
||||
render_files( flags, log, waveout_stream );
|
||||
render_files( flags, log, waveout_stream, prng );
|
||||
#endif
|
||||
} else {
|
||||
if ( flags.driver.empty() ) {
|
||||
|
|
|
@ -361,8 +361,10 @@ struct ResonantFilter
|
|||
}
|
||||
}
|
||||
|
||||
// To avoid a precision loss in the state variables especially with quiet samples at low cutoff and high mix rate, we pre-amplify the sample.
|
||||
#define MIXING_FILTER_PREAMP 256
|
||||
// Filter values are clipped to double the input range
|
||||
#define ClipFilter(x) Clamp<typename Traits::output_t, typename Traits::output_t>(x, int16_min * 2, int16_max * 2)
|
||||
#define ClipFilter(x) Clamp<typename Traits::output_t, typename Traits::output_t>(x, int16_min * 2 * MIXING_FILTER_PREAMP, int16_max * 2 * MIXING_FILTER_PREAMP)
|
||||
|
||||
MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const ModChannel &chn)
|
||||
{
|
||||
|
@ -370,14 +372,15 @@ struct ResonantFilter
|
|||
|
||||
for(int i = 0; i < Traits::numChannelsIn; i++)
|
||||
{
|
||||
typename Traits::output_t val = static_cast<typename Traits::output_t>((
|
||||
Util::mul32to64(outSample[i], chn.nFilter_A0) +
|
||||
const auto inputAmp = outSample[i] * MIXING_FILTER_PREAMP;
|
||||
typename Traits::output_t val = static_cast<typename Traits::output_t>(mpt::rshift_signed(
|
||||
Util::mul32to64(inputAmp, chn.nFilter_A0) +
|
||||
Util::mul32to64(ClipFilter(fy[i][0]), chn.nFilter_B0) +
|
||||
Util::mul32to64(ClipFilter(fy[i][1]), chn.nFilter_B1) +
|
||||
(1 << (MIXING_FILTER_PRECISION - 1))) / (1 << MIXING_FILTER_PRECISION));
|
||||
(1 << (MIXING_FILTER_PRECISION - 1)), MIXING_FILTER_PRECISION));
|
||||
fy[i][1] = fy[i][0];
|
||||
fy[i][0] = val - (outSample[i] & chn.nFilter_HP);
|
||||
outSample[i] = val;
|
||||
fy[i][0] = val - (inputAmp & chn.nFilter_HP);
|
||||
outSample[i] = val / MIXING_FILTER_PREAMP;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -179,7 +179,7 @@ bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags)
|
|||
if(sampleHeader.zero != 0 && sampleHeader.zero != 46) // putup10.stm has zero = 46
|
||||
return false;
|
||||
sampleHeader.ConvertToMPT(Samples[smp]);
|
||||
mpt::String::Read<mpt::String::nullTerminated>(m_szNames[smp], sampleHeader.filename);
|
||||
mpt::String::Read<mpt::String::maybeNullTerminated>(m_szNames[smp], sampleHeader.filename);
|
||||
sampleOffsets[smp - 1] = sampleHeader.offset;
|
||||
}
|
||||
|
||||
|
@ -212,7 +212,7 @@ bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags)
|
|||
ORDERINDEX breakPos = ORDERINDEX_INVALID;
|
||||
ROWINDEX breakRow = 63; // Candidate row for inserting pattern break
|
||||
|
||||
for(int i = 0; i < 64 * 4; i++, m++)
|
||||
for(unsigned int i = 0; i < 64 * 4; i++, m++)
|
||||
{
|
||||
uint8 note = file.ReadUint8(), insvol, volcmd, cmdinf;
|
||||
switch(note)
|
||||
|
@ -226,9 +226,13 @@ bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags)
|
|||
m->note = NOTE_NOTECUT;
|
||||
continue;
|
||||
default:
|
||||
insvol = file.ReadUint8();
|
||||
volcmd = file.ReadUint8();
|
||||
cmdinf = file.ReadUint8();
|
||||
{
|
||||
uint8 patData[3];
|
||||
file.ReadArray(patData);
|
||||
insvol = patData[0];
|
||||
volcmd = patData[1];
|
||||
cmdinf = patData[2];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -266,16 +270,22 @@ bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags)
|
|||
{
|
||||
case CMD_VOLUMESLIDE:
|
||||
// Lower nibble always has precedence, and there are no fine slides.
|
||||
if(m->param & 0x0F) m->param &= 0x0F;
|
||||
else m->param &= 0xF0;
|
||||
if(m->param & 0x0F)
|
||||
m->param &= 0x0F;
|
||||
else
|
||||
m->param &= 0xF0;
|
||||
break;
|
||||
|
||||
case CMD_PATTERNBREAK:
|
||||
m->param = (m->param & 0xF0) * 10 + (m->param & 0x0F);
|
||||
if(breakRow > m->param)
|
||||
if(breakPos != ORDERINDEX_INVALID && m->param == 0)
|
||||
{
|
||||
breakRow = m->param;
|
||||
// Merge Bxx + C00 into just Bxx
|
||||
m->command = CMD_POSITIONJUMP;
|
||||
m->param = static_cast<ModCommand::PARAM>(breakPos);
|
||||
breakPos = ORDERINDEX_INVALID;
|
||||
}
|
||||
LimitMax(breakRow, i / 4u);
|
||||
break;
|
||||
|
||||
case CMD_POSITIONJUMP:
|
||||
|
|
|
@ -85,6 +85,17 @@ struct UltSample
|
|||
MPT_BINARY_STRUCT(UltSample, 66)
|
||||
|
||||
|
||||
struct UltPatternCommand
|
||||
{
|
||||
uint8 instr;
|
||||
uint8 cmd;
|
||||
uint8 param1;
|
||||
uint8 param2;
|
||||
};
|
||||
|
||||
MPT_BINARY_STRUCT(UltPatternCommand, 4)
|
||||
|
||||
|
||||
/* Unhandled effects:
|
||||
5x1 - do not loop sample (x is unused)
|
||||
9xx - set sample offset to xx * 1024
|
||||
|
@ -215,13 +226,14 @@ static int ReadULTEvent(ModCommand &m, FileReader &file, uint8 version)
|
|||
b = file.ReadUint8();
|
||||
}
|
||||
|
||||
m.note = (b > 0 && b < 61) ? b + 36 : NOTE_NONE;
|
||||
m.instr = file.ReadUint8();
|
||||
b = file.ReadUint8();
|
||||
cmd1 = b & 0x0F;
|
||||
cmd2 = b >> 4;
|
||||
param1 = file.ReadUint8();
|
||||
param2 = file.ReadUint8();
|
||||
m.note = (b > 0 && b < 61) ? (b + 35 + NOTE_MIN) : NOTE_NONE;
|
||||
UltPatternCommand patCmd;
|
||||
file.ReadStruct(patCmd);
|
||||
m.instr = patCmd.instr;
|
||||
cmd1 = patCmd.cmd & 0x0F;
|
||||
cmd2 = patCmd.cmd >> 4;
|
||||
param1 = patCmd.param1;
|
||||
param2 = patCmd.param2;
|
||||
TranslateULTCommands(cmd1, param1, version);
|
||||
TranslateULTCommands(cmd2, param2, version);
|
||||
|
||||
|
@ -295,7 +307,7 @@ struct PostFixUltCommands
|
|||
// Apply porta?
|
||||
if(m.note == NOTE_NONE && isPortaActive[curChannel])
|
||||
{
|
||||
if(m.command == CMD_NONE && m.vol != VOLCMD_TONEPORTAMENTO)
|
||||
if(m.command == CMD_NONE && m.volcmd != VOLCMD_TONEPORTAMENTO)
|
||||
{
|
||||
m.command = CMD_TONEPORTAMENTO;
|
||||
m.param = 0;
|
||||
|
@ -345,6 +357,10 @@ static bool ValidateHeader(const UltFileHeader &fileHeader)
|
|||
return true;
|
||||
}
|
||||
|
||||
static uint64 GetHeaderMinimumAdditionalSize(const UltFileHeader &fileHeader)
|
||||
{
|
||||
return fileHeader.messageLength * 32u;
|
||||
}
|
||||
|
||||
CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderULT(MemoryFileReader file, const uint64 *pfilesize)
|
||||
{
|
||||
|
@ -357,8 +373,7 @@ CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderULT(MemoryFileReader file, co
|
|||
{
|
||||
return ProbeFailure;
|
||||
}
|
||||
MPT_UNREFERENCED_PARAMETER(pfilesize);
|
||||
return ProbeSuccess;
|
||||
return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
|
||||
}
|
||||
|
||||
|
||||
|
@ -379,6 +394,10 @@ bool CSoundFile::ReadUlt(FileReader &file, ModLoadingFlags loadFlags)
|
|||
{
|
||||
return true;
|
||||
}
|
||||
if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
InitializeGlobals(MOD_TYPE_ULT);
|
||||
mpt::String::Read<mpt::String::maybeNullTerminated>(m_songName, fileHeader.songName);
|
||||
|
@ -442,12 +461,9 @@ bool CSoundFile::ReadUlt(FileReader &file, ModLoadingFlags loadFlags)
|
|||
for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++)
|
||||
{
|
||||
ModCommand evnote;
|
||||
ModCommand *note;
|
||||
evnote.Clear();
|
||||
|
||||
for(PATTERNINDEX pat = 0; pat < numPats; pat++)
|
||||
for(PATTERNINDEX pat = 0; pat < numPats && file.CanRead(5); pat++)
|
||||
{
|
||||
note = Patterns[pat].GetpModCommand(0, chn);
|
||||
ModCommand *note = Patterns[pat].GetpModCommand(0, chn);
|
||||
ROWINDEX row = 0;
|
||||
while(row < 64)
|
||||
{
|
||||
|
|
|
@ -16,7 +16,7 @@ OPENMPT_NAMESPACE_BEGIN
|
|||
|
||||
#ifdef MPT_INTMIXER
|
||||
typedef int32 mixsample_t;
|
||||
enum { MIXING_FILTER_PRECISION = 16 }; // Fixed point resonant filter bits
|
||||
enum { MIXING_FILTER_PRECISION = 24 }; // Fixed point resonant filter bits
|
||||
#else
|
||||
typedef float mixsample_t;
|
||||
#endif
|
||||
|
|
|
@ -1665,7 +1665,7 @@ bool CSoundFile::ReadSFZInstrument(INSTRUMENTINDEX nInstr, FileReader &file)
|
|||
}
|
||||
if(!region.name.empty())
|
||||
{
|
||||
mpt::String::Copy(m_szNames[smp], region.name);
|
||||
mpt::String::Copy(m_szNames[smp], mpt::ToCharset(GetCharsetInternal(), mpt::CharsetUTF8, region.name));
|
||||
}
|
||||
if(!m_szNames[smp][0])
|
||||
{
|
||||
|
|
|
@ -133,7 +133,7 @@ public:
|
|||
const_iterator end() const { return m_ModCommands.end(); }
|
||||
const_iterator cend() const { return m_ModCommands.cend(); }
|
||||
|
||||
CPattern(CPatternContainer& patCont) : m_ModCommands(0), m_Rows(64), m_RowsPerBeat(0), m_RowsPerMeasure(0), m_rPatternContainer(patCont) {};
|
||||
CPattern(CPatternContainer& patCont) : m_rPatternContainer(patCont) {};
|
||||
CPattern(const CPattern &) = default;
|
||||
CPattern(CPattern &&) noexcept = default;
|
||||
|
||||
|
@ -148,9 +148,9 @@ protected:
|
|||
//BEGIN: DATA
|
||||
protected:
|
||||
std::vector<ModCommand> m_ModCommands;
|
||||
ROWINDEX m_Rows;
|
||||
ROWINDEX m_RowsPerBeat; // patterns-specific time signature. if != 0, this is implicitely set.
|
||||
ROWINDEX m_RowsPerMeasure; // ditto
|
||||
ROWINDEX m_Rows = 0;
|
||||
ROWINDEX m_RowsPerBeat = 0; // patterns-specific time signature. if != 0, this is implicitely set.
|
||||
ROWINDEX m_RowsPerMeasure = 0; // ditto
|
||||
TempoSwing m_tempoSwing;
|
||||
std::string m_PatternName;
|
||||
CPatternContainer& m_rPatternContainer;
|
||||
|
|
Loading…
Reference in New Issue