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