Updated libopenmpt to version 0.5.9

CQTexperiment
Christopher Snowhill 2021-05-16 16:54:35 -07:00
parent 7181656ae9
commit 24dfaf7d5c
43 changed files with 283 additions and 226 deletions

View File

@ -1,4 +1,4 @@
MPT_SVNVERSION=14580
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.8
MPT_SVNDATE=2021-04-11T14:02:18.903044Z
MPT_SVNVERSION=15019
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.9
MPT_SVNDATE=2021-05-16T14:59:54.252327Z

View File

@ -42,8 +42,8 @@ else ifeq ($(EMSCRIPTEN_TARGET),all)
# emits native wasm AND javascript with full wasm optimizations.
# as of emscripten 1.38, this is equivalent to default.
CPPFLAGS += -DMPT_BUILD_WASM
CXXFLAGS += -s WASM=2 -s LEGACY_VM_SUPPORT=1
CFLAGS += -s WASM=2 -s LEGACY_VM_SUPPORT=1
CXXFLAGS +=
CFLAGS +=
LDFLAGS += -s WASM=2 -s LEGACY_VM_SUPPORT=1
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
@ -51,8 +51,8 @@ LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
else ifeq ($(EMSCRIPTEN_TARGET),audioworkletprocessor)
# emits an es6 module in a single file suitable for use in an AudioWorkletProcessor
CPPFLAGS += -DMPT_BUILD_WASM -DMPT_BUILD_AUDIOWORKLETPROCESSOR
CXXFLAGS += -s WASM=1 -s WASM_ASYNC_COMPILATION=0 -s MODULARIZE=1 -s EXPORT_ES6=1 -s SINGLE_FILE=1
CFLAGS += -s WASM=1 -s WASM_ASYNC_COMPILATION=0 -s MODULARIZE=1 -s EXPORT_ES6=1 -s SINGLE_FILE=1
CXXFLAGS +=
CFLAGS +=
LDFLAGS += -s WASM=1 -s WASM_ASYNC_COMPILATION=0 -s MODULARIZE=1 -s EXPORT_ES6=1 -s SINGLE_FILE=1
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
@ -60,8 +60,8 @@ LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
else ifeq ($(EMSCRIPTEN_TARGET),wasm)
# emits native wasm.
CPPFLAGS += -DMPT_BUILD_WASM
CXXFLAGS += -s WASM=1
CFLAGS += -s WASM=1
CXXFLAGS +=
CFLAGS +=
LDFLAGS += -s WASM=1
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
@ -69,16 +69,16 @@ LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
else ifeq ($(EMSCRIPTEN_TARGET),js)
# emits only plain javascript with plain javascript focused optimizations.
CPPFLAGS += -DMPT_BUILD_ASMJS
CXXFLAGS += -s WASM=0 -s LEGACY_VM_SUPPORT=1
CFLAGS += -s WASM=0 -s LEGACY_VM_SUPPORT=1
CXXFLAGS +=
CFLAGS +=
LDFLAGS += -s WASM=0 -s LEGACY_VM_SUPPORT=1
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
endif
CXXFLAGS += -s DISABLE_EXCEPTION_CATCHING=0 -s ERROR_ON_UNDEFINED_SYMBOLS=1 -s ERROR_ON_MISSING_LIBRARIES=1 -ffast-math
CFLAGS += -s DISABLE_EXCEPTION_CATCHING=0 -s ERROR_ON_UNDEFINED_SYMBOLS=1 -s ERROR_ON_MISSING_LIBRARIES=1 -ffast-math -fno-strict-aliasing
CXXFLAGS += -s DISABLE_EXCEPTION_CATCHING=0 -ffast-math
CFLAGS += -s DISABLE_EXCEPTION_CATCHING=0 -ffast-math -fno-strict-aliasing
LDFLAGS += -s DISABLE_EXCEPTION_CATCHING=0 -s ERROR_ON_UNDEFINED_SYMBOLS=1 -s ERROR_ON_MISSING_LIBRARIES=1 -s EXPORT_NAME="'libopenmpt'"
CFLAGS_SILENT += -Wno-\#warnings

View File

@ -1,10 +1,10 @@
#pragma once
#define OPENMPT_VERSION_SVNVERSION "14580"
#define OPENMPT_VERSION_REVISION 14580
#define OPENMPT_VERSION_SVNVERSION "15019"
#define OPENMPT_VERSION_REVISION 15019
#define OPENMPT_VERSION_DIRTY 0
#define OPENMPT_VERSION_MIXEDREVISIONS 0
#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.8"
#define OPENMPT_VERSION_DATE "2021-04-11T14:02:18.903044Z"
#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_IS_PACKAGE 1

View File

@ -30,6 +30,7 @@
#include "mptTime.h"
#include "mptLibrary.h"
#include <stdexcept>
#include <vector>
#include <cstdlib>
@ -230,4 +231,17 @@ std::string getenv(const std::string &env_var, const std::string &def = std::str
#endif // MODPLUG_TRACKER || (LIBOPENMPT_BUILD && LIBOPENMPT_BUILD_TEST)
#if MPT_OS_WINDOWS
template <typename Tstring, typename Tbuf, typename Tsize>
Tstring ParseMaybeNullTerminatedStringFromBufferWithSizeInBytes(const Tbuf *buf, Tsize sizeBytes)
{
// REG_SZ may contain a single NUL terminator, multiple NUL terminators, or no NUL terminator at all
return Tstring(reinterpret_cast<const typename Tstring::value_type*>(buf), reinterpret_cast<const typename Tstring::value_type*>(buf) + (sizeBytes / sizeof(typename Tstring::value_type))).c_str();
}
#endif // MPT_OS_WINDOWS
OPENMPT_NAMESPACE_END

View File

@ -98,6 +98,19 @@ static cpuid_result cpuid(uint32 function)
}
static cpuid_result cpuidex(uint32 function_a, uint32 function_c)
{
cpuid_result result;
int CPUInfo[4];
__cpuidex(CPUInfo, function_a, function_c);
result.a = CPUInfo[0];
result.b = CPUInfo[1];
result.c = CPUInfo[2];
result.d = CPUInfo[3];
return result;
}
void InitProcSupport()
{
@ -150,6 +163,11 @@ void InitProcSupport()
if(StandardFeatureFlags.c & (1<<20)) ProcSupport |= PROCSUPPORT_SSE4_2;
if(StandardFeatureFlags.c & (1<<28)) ProcSupport |= PROCSUPPORT_AVX;
}
if(VendorString.a >= 0x00000007u)
{
cpuid_result ExtendedFeatures = cpuidex(0x00000007u, 0x00000000u);
if(ExtendedFeatures.b & (1<< 5)) ProcSupport |= PROCSUPPORT_AVX2;
}
cpuid_result ExtendedVendorString = cpuid(0x80000000u);
if(ExtendedVendorString.a >= 0x80000001u)
@ -160,11 +178,6 @@ void InitProcSupport()
if(ExtendedVendorString.a >= 0x80000004u)
{
mpt::String::WriteAutoBuf(ProcBrandID) = cpuid(0x80000002u).as_string4() + cpuid(0x80000003u).as_string4() + cpuid(0x80000004u).as_string4();
if(ExtendedVendorString.a >= 0x80000007u)
{
cpuid_result ExtendedFeatures = cpuid(0x80000007u);
if(ExtendedFeatures.b & (1<< 5)) ProcSupport |= PROCSUPPORT_AVX2;
}
}
}

View File

@ -140,6 +140,8 @@
// <atomic>
#include "../common/misc_util.h"
// <stdexcept>
// <vector>
// for std::abs
#include <cstdlib>

View File

@ -357,23 +357,6 @@ mpt::ustring GetBuildFeaturesString()
;
#endif
#ifdef MODPLUG_TRACKER
if constexpr(mpt::arch_bits == 64)
{
if (true
&& (mpt::Windows::Version::GetMinimumKernelLevel() <= mpt::Windows::Version::WinXP64)
&& (mpt::Windows::Version::GetMinimumAPILevel() <= mpt::Windows::Version::WinXP64)
) {
retval += UL_(" WIN64OLD");
}
} else if constexpr(mpt::arch_bits == 32)
{
if (true
&& (mpt::Windows::Version::GetMinimumKernelLevel() <= mpt::Windows::Version::WinXP)
&& (mpt::Windows::Version::GetMinimumAPILevel() <= mpt::Windows::Version::WinXP)
) {
retval += UL_(" WIN32OLD");
}
}
retval += UL_("")
#if defined(UNICODE)
UL_(" UNICODE")

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 29
#define VER_MINOR 09
#define VER_MINOR 10
#define VER_MINORMINOR 00
OPENMPT_NAMESPACE_END

View File

@ -5,6 +5,26 @@ Changelog {#changelog}
For fully detailed change log, please see the source repository directly. This
is just a high-level summary.
### libopenmpt 0.5.9 (2021-05-16)
* `Makefile` `CONFIG=emscripten` does not pass linker options to the compiler
any more, which caused latest Emscripten to issue warnings.
* The retrigger effect didn't work correctly for OPL instruments in some cases
depending on the chosen output sample rate.
* S3M: Emulate IT short sample retrigger quirk in S3M files saved with
Impulse Tracker and Schism Tracker.
* ProTracker 3.6 doesn't support sample swapping. It is now disabled when
loading a ProTracker 3.6 IFF module.
* Some files with "hidden" garbage patterns were not played correctly since
libopenmpt 0.5.3.
* MOD: E9x retrigger now works the same way as in ProTracker 2.
* MDL: Improve auto-vibrato accuracy.
* 669: Reject files that contain any pattern tempo higher than 15.
* Reduce memory consumption of malformed XPK-compressed files.
* mpg123: Update to v1.27.2 (2021-05-08).
### libopenmpt 0.5.8 (2021-04-11)
* [**Sec**] Possible null-pointer dereference read caused by a sequence of

View File

@ -559,14 +559,14 @@ LIBOPENMPT_API double openmpt_could_open_probability2( openmpt_stream_callbacks
LIBOPENMPT_API size_t openmpt_probe_file_header_get_recommended_size(void);
/*! Probe for module formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0 */
#define OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES 0x1ul
#define OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES 0x1ull
/*! Probe for module-specific container formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0 */
#define OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS 0x2ul
#define OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS 0x2ull
/*! Probe for the default set of formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0 */
#define OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT ( OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES | OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS )
/*! Probe for no formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0 */
#define OPENMPT_PROBE_FILE_HEADER_FLAGS_NONE 0x0ul
#define OPENMPT_PROBE_FILE_HEADER_FLAGS_NONE 0x0ull
/*! Possible return values fo openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(). \since 0.3.0 */
#define OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS 1

View File

@ -103,7 +103,7 @@
* threads for internal use.
* - You must ensure to only ever access a particular libopenmpt object via
* non-const member functions from a single thread at a time.
* - You may access a particular libopenmpt objects concurrently from different
* - You may access a particular libopenmpt object concurrently from different
* threads when using only const member functions from all threads.
* - Consecutive accesses can happen from different threads.
* - Different objects can be accessed concurrently from different threads.
@ -273,16 +273,16 @@ LIBOPENMPT_ATTR_DEPRECATED LIBOPENMPT_CXX_API double could_open_propability( std
LIBOPENMPT_CXX_API std::size_t probe_file_header_get_recommended_size();
//! Probe for module formats in openmpt::probe_file_header(). \since 0.3.0
static const std::uint64_t probe_file_header_flags_modules = 0x1ul;
static const std::uint64_t probe_file_header_flags_modules = 0x1ull;
//! Probe for module-specific container formats in openmpt::probe_file_header(). \since 0.3.0
static const std::uint64_t probe_file_header_flags_containers = 0x2ul;
static const std::uint64_t probe_file_header_flags_containers = 0x2ull;
//! Probe for the default set of formats in openmpt::probe_file_header(). \since 0.3.0
static const std::uint64_t probe_file_header_flags_default = probe_file_header_flags_modules | probe_file_header_flags_containers;
//! Probe for no formats in openmpt::probe_file_header(). \since 0.3.0
static const std::uint64_t probe_file_header_flags_none = 0x0ul;
static const std::uint64_t probe_file_header_flags_none = 0x0ull;
//! Possible return values for openmpt::probe_file_header(). \since 0.3.0
enum probe_file_header_result {

View File

@ -215,7 +215,7 @@ namespace openmpt {
void module_ext_impl::set_instrument_mute_status( std::int32_t instrument, bool mute ) {
const bool instrument_mode = get_num_instruments() != 0;
const int32_t max_instrument = instrument_mode ? get_num_instruments() : get_num_samples();
const std::int32_t max_instrument = instrument_mode ? get_num_instruments() : get_num_samples();
if ( instrument < 0 || instrument >= max_instrument ) {
throw openmpt::exception("invalid instrument");
}
@ -230,7 +230,7 @@ namespace openmpt {
bool module_ext_impl::get_instrument_mute_status( std::int32_t instrument ) const {
const bool instrument_mode = get_num_instruments() != 0;
const int32_t max_instrument = instrument_mode ? get_num_instruments() : get_num_samples();
const std::int32_t max_instrument = instrument_mode ? get_num_instruments() : get_num_samples();
if ( instrument < 0 || instrument >= max_instrument ) {
throw openmpt::exception("invalid instrument");
}
@ -246,7 +246,7 @@ namespace openmpt {
std::int32_t module_ext_impl::play_note( std::int32_t instrument, std::int32_t note, double volume, double panning ) {
const bool instrument_mode = get_num_instruments() != 0;
const int32_t max_instrument = instrument_mode ? get_num_instruments() : get_num_samples();
const std::int32_t max_instrument = instrument_mode ? get_num_instruments() : get_num_samples();
if ( instrument < 0 || instrument >= max_instrument ) {
throw openmpt::exception("invalid instrument");
}
@ -261,15 +261,15 @@ namespace openmpt {
free_channel = MAX_CHANNELS - 1;
ModChannel &chn = m_sndFile->m_PlayState.Chn[free_channel];
chn.Reset(ModChannel::resetTotal, *m_sndFile, CHANNELINDEX_INVALID);
chn.Reset(ModChannel::resetTotal, *m_sndFile, CHANNELINDEX_INVALID, CHN_MUTE);
chn.nMasterChn = 0; // remove NNA association
chn.nNewNote = chn.nLastNote = static_cast<uint8>(note);
chn.ResetEnvelopes();
m_sndFile->InstrumentChange(chn, instrument + 1);
chn.nFadeOutVol = 0x10000;
m_sndFile->NoteChange(chn, note, false, true, true);
chn.nPan = mpt::saturate_round<int32_t>( Clamp( panning * 128.0, -128.0, 128.0 ) + 128.0 );
chn.nVolume = mpt::saturate_round<int32_t>( Clamp( volume * 256.0, 0.0, 256.0 ) );
chn.nPan = mpt::saturate_round<std::int32_t>( Clamp( panning * 128.0, -128.0, 128.0 ) + 128.0 );
chn.nVolume = mpt::saturate_round<std::int32_t>( Clamp( volume * 256.0, 0.0, 256.0 ) );
// Remove channel from list of mixed channels to fix https://bugs.openmpt.org/view.php?id=209
// This is required because a previous note on the same channel might have just stopped playing,

View File

@ -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 8
#define OPENMPT_API_VERSION_PATCH 9
/*! \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=5
LIBOPENMPT_VERSION_PATCH=8
LIBOPENMPT_VERSION_PATCH=9
LIBOPENMPT_VERSION_PREREL=
LIBOPENMPT_LTVER_CURRENT=2
LIBOPENMPT_LTVER_REVISION=8
LIBOPENMPT_LTVER_REVISION=9
LIBOPENMPT_LTVER_AGE=2

View File

@ -1748,7 +1748,7 @@ XMPIN * WINAPI XMPIN_GetInterface( DWORD face, InterfaceProc faceproc ) {
}
#pragma comment(linker, "/EXPORT:XMPIN_GetInterface=_XMPIN_GetInterface@8")
}; // extern "C"
} // extern "C"
#ifdef _MFC_VER

View File

@ -280,7 +280,7 @@ void CMegaBass::Process(int * MixSoundBuffer, int * MixRearBuffer, int count, ui
if(nChannels >= 2)
{
X86_StereoDCRemoval(MixSoundBuffer, count, nDCRFlt_Y1lf, nDCRFlt_X1lf, nDCRFlt_Y1rf, nDCRFlt_X1rf);
if(nChannels > 2) X86_StereoDCRemoval(MixSoundBuffer, count, nDCRFlt_Y1lb, nDCRFlt_X1lb, nDCRFlt_Y1rb, nDCRFlt_X1rb);
if(nChannels > 2) X86_StereoDCRemoval(MixRearBuffer, count, nDCRFlt_Y1lb, nDCRFlt_X1lb, nDCRFlt_Y1rb, nDCRFlt_X1rb);
int *px = MixSoundBuffer;
int *py = MixRearBuffer;
int x1 = nXBassFlt_X1;

View File

@ -48,24 +48,12 @@ struct XPK_BufferBounds
{
const uint8 *pSrcBeg;
std::size_t SrcSize;
uint8 *pDstBeg;
std::size_t DstSize;
inline uint8 SrcRead(std::size_t index)
{
if(index >= SrcSize) throw XPK_error();
return pSrcBeg[index];
}
inline void DstWrite(std::size_t index, uint8 value)
{
if(index >= DstSize) throw XPK_error();
pDstBeg[index] = value;
}
inline uint8 DstRead(std::size_t index)
{
if(index >= DstSize) throw XPK_error();
return pDstBeg[index];
}
};
static int32 bfextu(std::size_t p, int32 bo, int32 bc, XPK_BufferBounds &bufs)
@ -119,23 +107,17 @@ static bool XPK_DoUnpack(const uint8 *src_, uint32 srcLen, std::vector<char> &un
int32 cp, cup1, type;
std::size_t c;
std::size_t src;
std::size_t dst;
std::size_t phist = 0;
std::size_t dstmax = len;
unpackedData.resize(len);
unpackedData.reserve(std::min(static_cast<uint32>(len), std::min(srcLen, uint32_max / 20u) * 20u));
XPK_BufferBounds bufs;
bufs.pSrcBeg = src_;
bufs.SrcSize = srcLen;
bufs.pDstBeg = mpt::byte_cast<uint8 *>(unpackedData.data());
bufs.DstSize = len;
src = 0;
dst = 0;
c = src;
while (len > 0)
while(len > 0)
{
type = bufs.SrcRead(c+0);
cp = (bufs.SrcRead(c+4)<<8) | (bufs.SrcRead(c+5)); // packed
@ -146,12 +128,11 @@ static bool XPK_DoUnpack(const uint8 *src_, uint32 srcLen, std::vector<char> &un
if (type == 0)
{
// RAW chunk
if(cp < 0) throw XPK_error();
if(cp < 0 || cp > len) throw XPK_error();
for(int32 i = 0; i < cp; ++i)
{
bufs.DstWrite(dst + i, bufs.SrcRead(c + i));
unpackedData.push_back(bufs.SrcRead(c + i));
}
dst+=cp;
c+=cp;
len -= cp;
continue;
@ -164,14 +145,14 @@ static bool XPK_DoUnpack(const uint8 *src_, uint32 srcLen, std::vector<char> &un
#endif
break;
}
LimitMax(cup1, len);
len -= cup1;
cp = (cp + 3) & 0xfffc;
c += cp;
d0 = d1 = d2 = a2 = 0;
d3 = bufs.SrcRead(src); src++;
bufs.DstWrite(dst, (uint8)d3);
if (dst < dstmax) dst++;
unpackedData.push_back(static_cast<char>(d3));
cup1--;
while (cup1 > 0)
@ -230,8 +211,7 @@ static bool XPK_DoUnpack(const uint8 *src_, uint32 srcLen, std::vector<char> &un
d4 = bfexts(src,d0,d6,bufs);
d0 += d6;
d3 -= d4;
bufs.DstWrite(dst, (uint8)d3);
if (dst < dstmax) dst++;
unpackedData.push_back(static_cast<char>(d3));
cup1--;
d5--;
}
@ -243,7 +223,6 @@ static bool XPK_DoUnpack(const uint8 *src_, uint32 srcLen, std::vector<char> &un
d2 -= d6;
}
}
unpackedData.resize(bufs.DstSize - len);
return !unpackedData.empty();
l75a:
@ -287,22 +266,24 @@ l79e:
l7a6:
d6 += d4;
l7a8:
if (bfextu(src,d0,1,bufs)) goto l7c4;
d0 += 1;
if (bfextu(src,d0,1,bufs)) goto l7bc;
d5 = 8;
a5 = 0;
goto l7ca;
if(bfextu(src, d0, 1, bufs))
{
d5 = 12;
a5 = -0x100;
} else
{
d0 += 1;
if(bfextu(src, d0, 1, bufs))
{
d5 = 14;
a5 = -0x1100;
} else
{
d5 = 8;
a5 = 0;
}
}
l7bc:
d5 = 14;
a5 = -0x1100;
goto l7ca;
l7c4:
d5 = 12;
a5 = -0x100;
l7ca:
d0 += 1;
d4 = bfextu(src,d0,d5,bufs);
d0 += d5;
@ -314,13 +295,15 @@ l7ca:
if (d1 < 0) d1 = 0;
}
d6 += 2;
phist = dst + a5 - d4 - 1;
phist = unpackedData.size() + a5 - d4 - 1;
if(phist >= unpackedData.size())
throw XPK_error();
while ((d6 >= 0) && (cup1 > 0))
{
d3 = bufs.DstRead(phist); phist++;
bufs.DstWrite(dst, (uint8)d3);
if (dst < dstmax) dst++;
d3 = unpackedData[phist];
phist++;
unpackedData.push_back(static_cast<char>(d3));
cup1--;
d6--;
}

View File

@ -59,6 +59,8 @@ struct MixLoopState
{
samplePointer = static_cast<const int8 *>(chn.pCurrentSample);
lookaheadPointer = nullptr;
if(!samplePointer)
return;
if(chn.nLoopEnd < InterpolationMaxLookahead)
lookaheadStart = chn.nLoopStart;
else
@ -94,7 +96,8 @@ struct MixLoopState
int32 nLoopStart = chn.dwFlags[CHN_LOOP] ? chn.nLoopStart : 0;
SamplePosition nInc = chn.increment;
if ((nSamples <= 0) || nInc.IsZero() || (!chn.nLength)) return 0;
if(nSamples <= 0 || nInc.IsZero() || !chn.nLength || !samplePointer)
return 0;
// Part 1: Making sure the play position is valid, and if necessary, invert the play direction in case we reached a loop boundary of a ping-pong loop.
chn.pCurrentSample = samplePointer;

View File

@ -448,7 +448,7 @@ void ITSample::ConvertToIT(const ModSample &mptSmp, MODTYPE fromType, bool compr
if(mptSmp.uFlags[CHN_PANNING]) dfp |= ITSample::enablePanning;
// Sample Format / Loop Flags
if(mptSmp.HasSampleData())
if(mptSmp.HasSampleData() && !mptSmp.uFlags[CHN_ADLIB])
{
flags = ITSample::sampleDataPresent;
if(mptSmp.uFlags[CHN_LOOP]) flags |= ITSample::sampleLoop;
@ -498,12 +498,16 @@ void ITSample::ConvertToIT(const ModSample &mptSmp, MODTYPE fromType, bool compr
if((vid | vis) != 0 && (fromType & MOD_TYPE_XM))
{
// Sweep is upside down in XM
vir = 255 - vir;
if(mptSmp.nVibSweep != 0)
vir = mpt::saturate_cast<decltype(vir)::base_type>(Util::muldivr_unsigned(mptSmp.nVibDepth, 256, mptSmp.nVibSweep));
else
vir = 255;
}
if(mptSmp.uFlags[CHN_ADLIB])
{
length = 12;
flags = ITSample::sampleDataPresent;
cvt = ITSample::cvtOPLInstrument;
} else if(mptSmp.uFlags[SMP_KEEPONDISK])
{
@ -668,9 +672,9 @@ uint32 DecodeITEditTimer(uint16 cwtv, uint32 editTime)
if((cwtv & 0xFFF) >= 0x0208)
{
editTime ^= 0x4954524B; // 'ITRK'
editTime = (editTime >> 7) | (editTime << (32 - 7));
editTime = mpt::rotr(editTime, 7);
editTime = ~editTime + 1;
editTime = (editTime << 4) | (editTime >> (32 - 4));
editTime = mpt::rotl(editTime, 4);
editTime ^= 0x4A54484C; // 'JTHL'
}
return editTime;

View File

@ -63,7 +63,7 @@ struct ITFileHeader
uint8le pwd; // Pitch Wheel Depth
uint16le msglength; // Length of Song Message
uint32le msgoffset; // Offset of Song Message in File (IT crops message after first null)
uint32le reserved; // Some IT versions save an edit timer here. ChibiTracker writes "CHBI" here. OpenMPT writes "OMPT" here in some cases, see Load_it.cpp
uint32le reserved; // Some IT versions save an edit timer here. ChibiTracker writes "CHBI" here. OpenMPT and Schism Tracker save extended version information here.
uint8le chnpan[64]; // Initial Channel Panning
uint8le chnvol[64]; // Initial Channel Volume
};

View File

@ -74,17 +74,13 @@ static bool ValidateHeader(const _669FileHeader &fileHeader)
for(std::size_t i = 0; i < CountOf(fileHeader.breaks); i++)
{
if(fileHeader.orders[i] >= 128 && fileHeader.orders[i] < 0xFE)
{
return false;
}
if(fileHeader.orders[i] < 128 && fileHeader.tempoList[i] == 0)
{
return false;
}
if(fileHeader.tempoList[i] > 15)
return false;
if(fileHeader.breaks[i] >= 64)
{
return false;
}
}
return true;
}
@ -242,6 +238,7 @@ bool CSoundFile::Read669(FileReader &file, ModLoadingFlags loadFlags)
m->param = effect[chn] & 0x0F;
// Weird stuff happening in corehop.669 with effects > 8... they seem to do the same thing as if the high bit wasn't set, but the sample also behaves strangely.
uint8 command = effect[chn] >> 4;
if(command < static_cast<uint8>(CountOf(effTrans)))
{

View File

@ -478,9 +478,12 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
{
// OpenMPT Version number (Major.Minor)
// This will only be interpreted as "made with ModPlug" (i.e. disable compatible playback etc) if the "reserved" field is set to "OMPT" - else, compatibility was used.
m_dwLastSavedWithVersion = Version((fileHeader.cwtv & 0x0FFF) << 16);
uint32 mptVersion = (fileHeader.cwtv & 0x0FFF) << 16;
if(!memcmp(&fileHeader.reserved, "OMPT", 4))
interpretModPlugMade = true;
else if(mptVersion >= 0x01'29'00'00)
mptVersion |= fileHeader.reserved & 0xFFFF;
m_dwLastSavedWithVersion = Version(mptVersion);
} else if(fileHeader.cmwt == 0x888 || fileHeader.cwtv == 0x888)
{
// OpenMPT 1.17.02.26 (r122) to 1.18 (raped IT format)
@ -1416,8 +1419,8 @@ bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool c
} else
{
// IT
uint32 vVersion = Version::Current().GetRawVersion();
itHeader.cwtv = 0x5000 | (uint16)((vVersion >> 16) & 0x0FFF); // format: txyy (t = tracker ID, x = version major, yy = version minor), e.g. 0x5117 (OpenMPT = 5, 117 = v1.17)
const uint32 mptVersion = Version::Current().GetRawVersion();
itHeader.cwtv = 0x5000 | static_cast<uint16>((mptVersion >> 16) & 0x0FFF); // format: txyy (t = tracker ID, x = version major, yy = version minor), e.g. 0x5117 (OpenMPT = 5, 117 = v1.17)
itHeader.cmwt = 0x0214; // Common compatible tracker :)
// Hack from schism tracker:
for(INSTRUMENTINDEX nIns = 1; nIns <= GetNumInstruments(); nIns++)
@ -1429,11 +1432,10 @@ bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool c
}
}
if(!compatibilityExport)
{
// This way, we indicate that the file might contain OpenMPT hacks. Compatibility export puts 0 here.
if(compatibilityExport)
itHeader.reserved = mptVersion & 0xFFFF;
else
memcpy(&itHeader.reserved, "OMPT", 4);
}
}
itHeader.flags = ITFileHeader::useStereoPlayback | ITFileHeader::useMIDIPitchController;

View File

@ -635,8 +635,13 @@ bool CSoundFile::ReadMDL(FileReader &file, ModLoadingFlags loadFlags)
mptSmp.nPan = std::min(static_cast<uint16>(sampleHeader.panning * 2), uint16(254));
mptSmp.nVibType = MDLVibratoType[sampleHeader.vibType & 3];
mptSmp.nVibSweep = sampleHeader.vibSweep;
mptSmp.nVibDepth = sampleHeader.vibDepth;
mptSmp.nVibDepth = (sampleHeader.vibDepth + 3u) / 4u;
mptSmp.nVibRate = sampleHeader.vibSpeed;
// Convert to IT-like vibrato sweep
if(mptSmp.nVibSweep != 0)
mptSmp.nVibSweep = mpt::saturate_cast<decltype(mptSmp.nVibSweep)>(Util::muldivr_unsigned(mptSmp.nVibDepth, 256, mptSmp.nVibSweep));
else
mptSmp.nVibSweep = 255;
if(sampleHeader.panEnvFlags & 0x40)
mptSmp.uFlags.set(CHN_PANNING);
}

View File

@ -552,7 +552,7 @@ static bool ValidateMODPatternData(TFileReader &file, const uint32 threshold, co
// Parse the order list to determine how many patterns are used in the file.
static PATTERNINDEX GetNumPatterns(FileReader &file, ModSequence &Order, ORDERINDEX numOrders, SmpLength totalSampleLen, CHANNELINDEX &numChannels, SmpLength wowSampleLen = 0)
static PATTERNINDEX GetNumPatterns(FileReader &file, ModSequence &Order, ORDERINDEX numOrders, SmpLength totalSampleLen, CHANNELINDEX &numChannels, SmpLength wowSampleLen, bool validateHiddenPatterns)
{
PATTERNINDEX numPatterns = 0; // Total number of patterns in file (determined by going through the whole order list) with pattern number < 128
PATTERNINDEX officialPatterns = 0; // Number of patterns only found in the "official" part of the order list (i.e. order positions < claimed order length)
@ -590,7 +590,7 @@ static PATTERNINDEX GetNumPatterns(FileReader &file, ModSequence &Order, ORDERIN
if(ValidateMODPatternData(file, 16, true))
numChannels = 8;
file.Seek(patternStartOffset);
} else if(numPatterns != officialPatterns && numChannels == 4 && !wowSampleLen)
} else if(numPatterns != officialPatterns && validateHiddenPatterns)
{
// Fix SoundTracker modules where "hidden" patterns should be ignored.
// razor-1911.mod (MD5 b75f0f471b0ae400185585ca05bf7fe8, SHA1 4de31af234229faec00f1e85e1e8f78f405d454b)
@ -913,7 +913,7 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags)
}
// Get number of patterns (including some order list sanity checks)
PATTERNINDEX numPatterns = GetNumPatterns(file, Order(), realOrders, totalSampleLen, m_nChannels, wowSampleLen);
PATTERNINDEX numPatterns = GetNumPatterns(file, Order(), realOrders, totalSampleLen, m_nChannels, wowSampleLen, false);
if(maybeWOW && GetNumChannels() == 8)
{
// M.K. with 8 channels = Mod's Grave
@ -1511,7 +1511,7 @@ bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
file.ReadStruct(fileHeader);
ReadOrderFromArray(Order(), fileHeader.orderList);
PATTERNINDEX numPatterns = GetNumPatterns(file, Order(), fileHeader.numOrders, totalSampleLen, m_nChannels);
PATTERNINDEX numPatterns = GetNumPatterns(file, Order(), fileHeader.numOrders, totalSampleLen, m_nChannels, 0, true);
// Most likely just a file with lots of NULs at the start
if(fileHeader.restartPos == 0 && fileHeader.numOrders == 0 && numPatterns <= 1)
@ -2201,7 +2201,7 @@ bool CSoundFile::ReadPT36(FileReader &file, ModLoadingFlags loadFlags)
m_SongFlags.set(SONG_PT_MODE);
m_playBehaviour.set(kMODIgnorePanning);
m_playBehaviour.set(kMODOneShotLoops);
m_playBehaviour.set(kMODSampleSwap);
m_playBehaviour.reset(kMODSampleSwap);
return ok;
}

View File

@ -721,12 +721,12 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
// MT2 only ever calls effGetChunk for programs, and OpenMPT uses the defaultProgram value to determine
// whether it should use effSetChunk for programs or banks...
mixPlug.defaultProgram = -1;
LimitMax(vstHeader.n, Util::MaxValueOfType(dataSize) - 4);
LimitMax(vstHeader.n, std::numeric_limits<decltype(dataSize)>::max() - 4);
dataSize = vstHeader.n + 4;
} else
{
mixPlug.defaultProgram = vstHeader.programNr;
LimitMax(vstHeader.n, (Util::MaxValueOfType(dataSize) / 4u) - 1);
LimitMax(vstHeader.n, (std::numeric_limits<decltype(dataSize)>::max() / 4u) - 1);
dataSize = vstHeader.n * 4 + 4;
}
mixPlug.pluginData.resize(dataSize);

View File

@ -284,6 +284,8 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
m_FileHistory.push_back(hist);
}
nonCompatTracker = true;
m_playBehaviour.set(kITRetrigger);
m_playBehaviour.set(kITShortSampleRetrig);
m_playBehaviour.set(kST3SampleSwap); // Not exactly like ST3, but close enough
m_nMinPeriod = 1;
break;
@ -297,13 +299,19 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
madeWithTracker = GetSchismTrackerVersion(fileHeader.cwtv, fileHeader.reserved2);
m_nMinPeriod = 1;
isSchism = true;
if(fileHeader.cwtv >= SchismVersionFromDate<2016, 05, 13>::Version(S3MFileHeader::trkSchismTracker))
m_playBehaviour.set(kITShortSampleRetrig);
}
nonCompatTracker = true;
break;
case S3MFileHeader::trkOpenMPT:
madeWithTracker = U_("OpenMPT");
formatTrackerStr = true;
m_dwLastSavedWithVersion = Version((fileHeader.cwtv & S3MFileHeader::versionMask) << 16);
{
uint32 mptVersion = (fileHeader.cwtv & S3MFileHeader::versionMask) << 16;
if(mptVersion >= 0x01'29'00'00)
mptVersion |= fileHeader.reserved2;
m_dwLastSavedWithVersion = Version(mptVersion);
madeWithTracker = U_("OpenMPT ") + mpt::ufmt::val(m_dwLastSavedWithVersion);
}
break;
case S3MFileHeader::trkBeRoTracker:
madeWithTracker = U_("BeRoTracker");
@ -676,7 +684,9 @@ bool CSoundFile::SaveS3M(std::ostream &f) const
// Version info following: ST3.20 = 0x1320
// Most significant nibble = Tracker ID, see S3MFileHeader::S3MTrackerVersions
// Following: One nibble = Major version, one byte = Minor version (hex)
fileHeader.cwtv = S3MFileHeader::trkOpenMPT | static_cast<uint16>((Version::Current().GetRawVersion() >> 16) & S3MFileHeader::versionMask);
const uint32 mptVersion = Version::Current().GetRawVersion();
fileHeader.cwtv = S3MFileHeader::trkOpenMPT | static_cast<uint16>((mptVersion >> 16) & S3MFileHeader::versionMask);
fileHeader.reserved2 = static_cast<uint16>(mptVersion);
fileHeader.formatVersion = S3MFileHeader::newVersion;
memcpy(fileHeader.magic, "SCRM", 4);

View File

@ -12,7 +12,7 @@
#include "stdafx.h"
#include "MixerLoops.h"
#include "..//soundbase/SampleBuffer.h"
#include "../soundbase/SampleBuffer.h"
#include "Snd_defs.h"
#include "ModChannel.h"
#ifdef ENABLE_SSE2

View File

@ -15,7 +15,7 @@
OPENMPT_NAMESPACE_BEGIN
void ModChannel::Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELINDEX sourceChannel)
void ModChannel::Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELINDEX sourceChannel, ChannelFlags muteFlag)
{
if(resetMask & resetSetPosBasic)
{
@ -81,6 +81,11 @@ void ModChannel::Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELI
dwFlags = sndFile.ChnSettings[sourceChannel].dwFlags;
nPan = sndFile.ChnSettings[sourceChannel].nPan;
nGlobalVol = sndFile.ChnSettings[sourceChannel].nVolume;
if(dwFlags[CHN_MUTE])
{
dwFlags.reset(CHN_MUTE);
dwFlags.set(muteFlag);
}
} else
{
dwFlags.reset();

View File

@ -174,7 +174,7 @@ struct ModChannel
resetTotal = resetSetPosFull,
};
void Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELINDEX sourceChannel);
void Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELINDEX sourceChannel, ChannelFlags muteFlag);
void Stop();
bool IsSamplePlaying() const noexcept { return !increment.IsZero(); }

View File

@ -457,22 +457,21 @@ void ModSample::TransposeToFrequency()
}
// Return tranpose.finetune as 25.7 fixed point value.
int32 ModSample::FrequencyToTranspose(uint32 freq)
// Return a pair of {tranpose, finetune}
std::pair<int8, int8> ModSample::FrequencyToTranspose(uint32 freq)
{
if(!freq)
return 0;
else
return mpt::saturate_round<int32>(std::log(freq * (1.0 / 8363.0)) * (12.0 * 128.0 * (1.0 / M_LN2)));
return {};
const auto f2t = mpt::saturate_round<int32>(std::log(freq * (1.0 / 8363.0)) * (12.0 * 128.0 * (1.0 / M_LN2)));
const auto fine = std::div(Clamp(f2t, -16384, 16383), int32(128));
return {static_cast<int8>(fine.quot), static_cast<int8>(fine.rem)};
}
void ModSample::FrequencyToTranspose()
{
const int f2t = Clamp(FrequencyToTranspose(nC5Speed), -16384, 16383);
const auto fine = std::div(f2t, 128);
RelativeTone = static_cast<int8>(fine.quot);
nFineTune = static_cast<int8>(fine.rem);
std::tie(RelativeTone, nFineTune) = FrequencyToTranspose(nC5Speed);
}

View File

@ -146,7 +146,7 @@ struct ModSample
// Transpose <-> Frequency conversions
static uint32 TransposeToFrequency(int transpose, int finetune = 0);
void TransposeToFrequency();
static int32 FrequencyToTranspose(uint32 freq);
static std::pair<int8, int8> FrequencyToTranspose(uint32 freq);
void FrequencyToTranspose();
// Transpose the sample by amount specified in octaves (i.e. amount=1 transposes one octave up)

View File

@ -84,7 +84,7 @@ struct S3MFileHeader
uint8le masterVolume; // Sample Volume (0...127, stereo if high bit is set)
uint8le ultraClicks; // Number of channels used for ultra click removal
uint8le usePanningTable; // 0xFC => read extended panning table
uint16le reserved2; // Schism Tracker uses this for its extended version information
uint16le reserved2; // Schism Tracker and OpenMPT use this for their extended version information
uint32le reserved3; // Impulse Tracker hides its edit timer here
uint16le reserved4;
uint16le special; // Pointer to special custom data (unused)

View File

@ -249,7 +249,7 @@ std::vector<FileType> CSoundFile::GetMediaFoundationFileTypes()
std::wstring guid = std::wstring(valueNameBuf);
mpt::ustring description = mpt::ToUnicode(std::wstring(reinterpret_cast<WCHAR*>(valueData)));
mpt::ustring description = mpt::ToUnicode(ParseMaybeNullTerminatedStringFromBufferWithSizeInBytes<std::wstring>(valueData, valueDataLen));
description = mpt::String::Replace(description, U_("Byte Stream Handler"), U_("Files"));
description = mpt::String::Replace(description, U_("ByteStreamHandler"), U_("Files"));

View File

@ -268,7 +268,7 @@ enum SongFlags
};
DECLARE_FLAGSET(SongFlags)
#define SONG_FILE_FLAGS (SONG_FASTVOLSLIDES|SONG_ITOLDEFFECTS|SONG_ITCOMPATGXX|SONG_LINEARSLIDES|SONG_EXFILTERRANGE|SONG_AMIGALIMITS|SONG_S3MOLDVIBRATO|SONG_PT_MODE|SONG_ISAMIGA)
#define SONG_FILE_FLAGS (SONG_FASTVOLSLIDES|SONG_ITOLDEFFECTS|SONG_ITCOMPATGXX|SONG_LINEARSLIDES|SONG_EXFILTERRANGE|SONG_AMIGALIMITS|SONG_S3MOLDVIBRATO|SONG_PT_MODE|SONG_ISAMIGA|SONG_IMPORTED)
#define SONG_PLAY_FLAGS (~SONG_FILE_FLAGS)
// Global Options (Renderer)

View File

@ -93,9 +93,10 @@ public:
state->m_nMusicTempo = sndFile.m_nDefaultTempo;
state->m_nGlobalVolume = sndFile.m_nDefaultGlobalVolume;
chnSettings.assign(sndFile.GetNumChannels(), ChnSettings());
const auto muteFlag = CSoundFile::GetChannelMuteFlag();
for(CHANNELINDEX chn = 0; chn < sndFile.GetNumChannels(); chn++)
{
state->Chn[chn].Reset(ModChannel::resetTotal, sndFile, chn);
state->Chn[chn].Reset(ModChannel::resetTotal, sndFile, chn, muteFlag);
state->Chn[chn].nOldGlobalVolSlide = 0;
state->Chn[chn].nOldChnVolSlide = 0;
state->Chn[chn].nNote = state->Chn[chn].nNewNote = state->Chn[chn].nLastNote = NOTE_NONE;
@ -592,7 +593,7 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
if(chn.rowCommand.vol)
{
const auto [porta, clearEffectCommand] = GetVolCmdTonePorta(chn.rowCommand, 0);
chn.nPortamentoSlide = porta * 4;
chn.nPortamentoSlide = porta;
if(clearEffectCommand)
command = CMD_NONE;
}
@ -791,7 +792,7 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
break;
// Tone-Portamento
case CMD_TONEPORTAMENTO:
if (param) chn.nPortamentoSlide = param << 2;
if (param) chn.nPortamentoSlide = param;
break;
// Offset
case CMD_OFFSET:
@ -2192,6 +2193,12 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo
if(!srcChn.nLength || srcChn.dwFlags[CHN_MUTE] || !(srcChn.rightVol | srcChn.leftVol))
return CHANNELINDEX_INVALID;
if(srcChn.dwFlags[CHN_ADLIB] && m_opl)
{
m_opl->NoteCut(nChn, false);
return CHANNELINDEX_INVALID;
}
const CHANNELINDEX nnaChn = GetNNAChannel(nChn);
if(nnaChn == CHANNELINDEX_INVALID)
return CHANNELINDEX_INVALID;
@ -2211,10 +2218,6 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo
srcChn.position.Set(0);
srcChn.nROfs = srcChn.nLOfs = 0;
srcChn.rightVol = srcChn.leftVol = 0;
if(srcChn.dwFlags[CHN_ADLIB] && m_opl)
{
m_opl->NoteCut(nChn);
}
return nnaChn;
}
if(instr > GetNumInstruments())
@ -4193,18 +4196,17 @@ void CSoundFile::TonePortamento(ModChannel &chn, uint32 param) const
chn.nOldPortaUp = chn.nOldPortaDown = static_cast<uint8>(param);
}
if(param)
chn.nPortamentoSlide = param;
if(chn.HasCustomTuning())
{
//Behavior: Param tells number of finesteps(or 'fullsteps'(notes) with glissando)
//to slide per row(not per tick).
const int32 oldPortamentoTickSlide = (m_PlayState.m_nTickCount != 0) ? chn.m_PortamentoTickSlide : 0;
if(param)
chn.nPortamentoSlide = param;
else
if(chn.nPortamentoSlide == 0)
return;
if(chn.nPortamentoSlide == 0)
return;
if((chn.nPortamentoDest > 0 && chn.nPortamentoSlide < 0) ||
(chn.nPortamentoDest < 0 && chn.nPortamentoSlide > 0))
@ -4242,47 +4244,49 @@ void CSoundFile::TonePortamento(ModChannel &chn, uint32 param) const
|| (GetType() & (MOD_TYPE_DBM | MOD_TYPE_669))
|| (m_PlayState.m_nMusicSpeed == 1 && m_playBehaviour[kSlidesAtSpeed1])
|| (GetType() == MOD_TYPE_MED && m_SongFlags[SONG_FASTVOLSLIDES]);
if(GetType() == MOD_TYPE_PLM && param >= 0xF0)
int32 delta = chn.nPortamentoSlide;
if(GetType() == MOD_TYPE_PLM && delta >= 0xF0)
{
param -= 0xF0;
delta -= 0xF0;
doPorta = chn.isFirstTick;
}
if(param)
if(GetType() == MOD_TYPE_669)
{
if(GetType() == MOD_TYPE_669)
{
param *= 10;
}
chn.nPortamentoSlide = param * 4;
delta *= 10;
}
if(chn.nPeriod && chn.nPortamentoDest && doPorta)
{
if (chn.nPeriod < chn.nPortamentoDest)
{
int32 delta = chn.nPortamentoSlide;
if(m_SongFlags[SONG_LINEARSLIDES] && GetType() != MOD_TYPE_XM)
{
uint32 n = chn.nPortamentoSlide / 4;
uint32 n = delta;
if (n > 255) n = 255;
// Return (a*b+c/2)/c - no divide error
// Table is 65536*2(n/192)
delta = Util::muldivr(chn.nPeriod, LinearSlideUpTable[n], 65536) - chn.nPeriod;
if (delta < 1) delta = 1;
} else
{
delta *= 4;
}
chn.nPeriod += delta;
if (chn.nPeriod > chn.nPortamentoDest) chn.nPeriod = chn.nPortamentoDest;
} else
if (chn.nPeriod > chn.nPortamentoDest)
{
int32 delta = -chn.nPortamentoSlide;
if(m_SongFlags[SONG_LINEARSLIDES] && GetType() != MOD_TYPE_XM)
{
uint32 n = chn.nPortamentoSlide / 4;
uint32 n = delta;
if (n > 255) n = 255;
delta = Util::muldivr(chn.nPeriod, LinearSlideDownTable[n], 65536) - chn.nPeriod;
if (delta > -1) delta = -1;
} else
{
delta *= -4;
}
chn.nPeriod += delta;
if (chn.nPeriod < chn.nPortamentoDest) chn.nPeriod = chn.nPortamentoDest;
@ -5562,6 +5566,15 @@ void CSoundFile::RetrigNote(CHANNELINDEX nChn, int param, int offset)
if(retrigCount && !(retrigCount % retrigSpeed))
doRetrig = true;
retrigCount++;
} else if(GetType() == MOD_TYPE_MOD)
{
// ProTracker-style retrigger
// Test case: PTRetrigger.mod
const auto tick = m_PlayState.m_nTickCount % m_PlayState.m_nMusicSpeed;
if(!tick && chn.rowCommand.IsNote())
return;
if(retrigSpeed && !(tick % retrigSpeed))
doRetrig = true;
} else if(GetType() == MOD_TYPE_MTM)
{
// In MultiTracker, E9x retriggers the last note at exactly the x-th tick of the row
@ -5624,8 +5637,8 @@ void CSoundFile::RetrigNote(CHANNELINDEX nChn, int param, int offset)
}
uint32 note = chn.nNewNote;
int32 oldPeriod = chn.nPeriod;
const bool retrigAdlib = chn.dwFlags[CHN_ADLIB] && m_playBehaviour[kOPLRealRetrig];
if(note >= NOTE_MIN && note <= NOTE_MAX && chn.nLength && retrigAdlib)
// ST3 doesn't retrigger OPL notes
if(note >= NOTE_MIN && note <= NOTE_MAX && chn.nLength && (!chn.dwFlags[CHN_ADLIB] || GetType() != MOD_TYPE_S3M || m_playBehaviour[kOPLRealRetrig]))
CheckNNA(nChn, 0, note, true);
bool resetEnv = false;
if(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))
@ -5638,11 +5651,6 @@ void CSoundFile::RetrigNote(CHANNELINDEX nChn, int param, int offset)
if(param < 0x100)
resetEnv = true;
}
if(retrigAdlib && chn.pModSample && m_opl)
{
m_opl->NoteCut(nChn);
m_opl->Patch(nChn, chn.pModSample->adlib);
}
const bool fading = chn.dwFlags[CHN_NOTEFADE];
const auto oldPrevNoteOffset = chn.prevNoteOffset;

View File

@ -478,11 +478,13 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags)
}
// Adjust channels
for(CHANNELINDEX ich = 0; ich < MAX_BASECHANNELS; ich++)
const auto muteFlag = GetChannelMuteFlag();
for(CHANNELINDEX chn = 0; chn < MAX_BASECHANNELS; chn++)
{
LimitMax(ChnSettings[ich].nVolume, uint16(64));
if (ChnSettings[ich].nPan > 256) ChnSettings[ich].nPan = 128;
m_PlayState.Chn[ich].Reset(ModChannel::resetTotal, *this, ich);
LimitMax(ChnSettings[chn].nVolume, uint16(64));
if(ChnSettings[chn].nPan > 256)
ChnSettings[chn].nPan = 128;
m_PlayState.Chn[chn].Reset(ModChannel::resetTotal, *this, chn, muteFlag);
}
// Checking samples, load external samples
@ -770,8 +772,9 @@ double CSoundFile::GetCurrentBPM() const
void CSoundFile::ResetPlayPos()
{
const auto muteFlag = GetChannelMuteFlag();
for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++)
m_PlayState.Chn[i].Reset(ModChannel::resetSetPosFull, *this, i);
m_PlayState.Chn[i].Reset(ModChannel::resetSetPosFull, *this, i, muteFlag);
visitedSongRows.Initialize(true);
m_SongFlags.reset(SONG_FADINGSONG | SONG_ENDREACHED);
@ -1055,7 +1058,6 @@ PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type)
{
playBehaviour.set(kOPLFlexibleNoteOff);
playBehaviour.set(kOPLwithNNA);
playBehaviour.set(kOPLRealRetrig);
}
break;
@ -1176,7 +1178,6 @@ PlayBehaviourSet CSoundFile::GetDefaultPlaybackBehaviour(MODTYPE type)
playBehaviour.set(kITDoNotOverrideChannelPan);
playBehaviour.set(kITDCTBehaviour);
playBehaviour.set(kOPLwithNNA);
playBehaviour.set(kOPLRealRetrig);
break;
case MOD_TYPE_S3M:
@ -1293,10 +1294,11 @@ const char *CSoundFile::GetInstrumentName(INSTRUMENTINDEX nInstr) const
bool CSoundFile::InitChannel(CHANNELINDEX nChn)
{
if(nChn >= MAX_BASECHANNELS) return true;
if(nChn >= MAX_BASECHANNELS)
return true;
ChnSettings[nChn].Reset();
m_PlayState.Chn[nChn].Reset(ModChannel::resetTotal, *this, nChn);
m_PlayState.Chn[nChn].Reset(ModChannel::resetTotal, *this, nChn, GetChannelMuteFlag());
#ifdef MODPLUG_TRACKER
if(GetpModDoc() != nullptr)
@ -1775,6 +1777,16 @@ const CModSpecifications& CSoundFile::GetModSpecifications(const MODTYPE type)
}
ChannelFlags CSoundFile::GetChannelMuteFlag()
{
#ifdef MODPLUG_TRACKER
return (TrackerSettings::Instance().m_dwPatternSetup & PATTERN_SYNCMUTE) ? CHN_SYNCMUTE : CHN_MUTE;
#else
return CHN_MUTE;
#endif
}
// Find an unused sample slot. If it is going to be assigned to an instrument, targetInstrument should be specified.
// SAMPLEINDEX_INVLAID is returned if no free sample slot could be found.
SAMPLEINDEX CSoundFile::GetNextFreeSample(INSTRUMENTINDEX targetInstrument, SAMPLEINDEX start) const

View File

@ -462,16 +462,17 @@ public:
ResamplingMode m_nResampling; // Resampling mode (if overriding the globally set resampling)
int32 m_nRepeatCount = 0; // -1 means repeat infinitely.
ORDERINDEX m_nMaxOrderPosition;
ModChannelSettings ChnSettings[MAX_BASECHANNELS]; // Initial channels settings
ModChannelSettings ChnSettings[MAX_BASECHANNELS]; // Initial channels settings
CPatternContainer Patterns;
ModSequenceSet Order; // Pattern sequences (order lists)
ModSequenceSet Order; // Pattern sequences (order lists)
protected:
ModSample Samples[MAX_SAMPLES]; // Sample Headers
ModSample Samples[MAX_SAMPLES];
public:
ModInstrument *Instruments[MAX_INSTRUMENTS]; // Instrument Headers
MIDIMacroConfig m_MidiCfg; // MIDI Macro config table
ModInstrument *Instruments[MAX_INSTRUMENTS]; // Instrument Headers
MIDIMacroConfig m_MidiCfg; // MIDI Macro config table
#ifndef NO_PLUGINS
SNDMIXPLUGIN m_MixPlugins[MAX_MIXPLUGINS]; // Mix plugins
SNDMIXPLUGIN m_MixPlugins[MAX_MIXPLUGINS]; // Mix plugins
uint32 m_loadedPlugins = 0; // Not a PLUGINDEX because number of loaded plugins may exceed MAX_MIXPLUGINS during MIDI conversion
#endif
mpt::charbuf<MAX_SAMPLENAME> m_szNames[MAX_SAMPLES]; // Sample names
@ -720,6 +721,8 @@ public:
const CModSpecifications& GetModSpecifications() const {return *m_pModSpecs;}
static const CModSpecifications& GetModSpecifications(const MODTYPE type);
static ChannelFlags GetChannelMuteFlag();
#ifdef MODPLUG_TRACKER
void PatternTranstionChnSolo(const CHANNELINDEX chnIndex);
void PatternTransitionChnUnmuteAll();

View File

@ -206,18 +206,6 @@ CSoundFile::samplecount_t CSoundFile::Read(samplecount_t count, IAudioReadTarget
{
MPT_ASSERT_ALWAYS(m_MixerSettings.IsValid());
bool mixPlugins = false;
#ifndef NO_PLUGINS
for(const auto &plug : m_MixPlugins)
{
if(plug.pMixPlugin)
{
mixPlugins = true;
break;
}
}
#endif // NO_PLUGINS
samplecount_t countRendered = 0;
samplecount_t countToRender = count;
@ -303,14 +291,16 @@ CSoundFile::samplecount_t CSoundFile::Read(samplecount_t count, IAudioReadTarget
m_opl->Mix(MixSoundBuffer, countChunk, m_OPLVolumeFactor * m_nVSTiVolume / 48);
}
#ifndef NO_REVERB
m_Reverb.Process(MixSoundBuffer, countChunk);
#endif // NO_REVERB
#ifndef NO_REVERB
m_Reverb.Process(MixSoundBuffer, countChunk);
#endif // NO_REVERB
if(mixPlugins)
#ifndef NO_PLUGINS
if(m_loadedPlugins)
{
ProcessPlugins(countChunk);
}
#endif // NO_PLUGINS
if(m_MixerSettings.gnChannels == 1)
{
@ -653,8 +643,9 @@ bool CSoundFile::ProcessRow()
visitedSongRows.Initialize(true);
}
// When jumping to the next subsong, stop all playing notes from the previous song...
const auto muteFlag = CSoundFile::GetChannelMuteFlag();
for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++)
m_PlayState.Chn[i].Reset(ModChannel::resetSetPosFull, *this, i);
m_PlayState.Chn[i].Reset(ModChannel::resetSetPosFull, *this, i, muteFlag);
StopAllVsti();
// ...and the global playback information.
m_PlayState.m_nMusicSpeed = m_nDefaultSpeed;
@ -2348,7 +2339,7 @@ bool CSoundFile::ReadNote()
}
// Volume ramping
chn.dwFlags.set(CHN_VOLUMERAMP, (chn.nRealVolume | chn.rightVol | chn.leftVol) != 0);
chn.dwFlags.set(CHN_VOLUMERAMP, (chn.nRealVolume | chn.rightVol | chn.leftVol) != 0 && !chn.dwFlags[CHN_ADLIB]);
constexpr uint8 VUMETER_DECAY = 4;
chn.nLeftVU = (chn.nLeftVU > VUMETER_DECAY) ? (chn.nLeftVU - VUMETER_DECAY) : 0;

View File

@ -656,13 +656,18 @@ void CSoundFile::UpgradeModule()
}
}
if(GetType() == MOD_TYPE_MPT && GetNumInstruments() && m_dwLastSavedWithVersion >= MPT_V("1.28.00.20") && m_dwLastSavedWithVersion <= MPT_V("1.29.55.00"))
if(GetType() & (MOD_TYPE_MPT | MOD_TYPE_S3M))
{
for(SAMPLEINDEX i = 1; i <= GetNumSamples(); i++)
{
if(Samples[i].uFlags[CHN_ADLIB])
{
m_playBehaviour.set(kOPLNoResetAtEnvelopeEnd);
if(GetType() == MOD_TYPE_MPT && GetNumInstruments() && m_dwLastSavedWithVersion >= MPT_V("1.28.00.20") && m_dwLastSavedWithVersion <= MPT_V("1.29.00.55"))
m_playBehaviour.set(kOPLNoResetAtEnvelopeEnd);
if(GetType() == MOD_TYPE_S3M && m_dwLastSavedWithVersion < MPT_V("1.29"))
m_playBehaviour.set(kOPLRealRetrig);
else if(GetType() != MOD_TYPE_S3M)
m_playBehaviour.reset(kOPLRealRetrig);
break;
}
}

View File

@ -330,9 +330,7 @@ void XMSample::ConvertToXM(const ModSample &mptSmp, MODTYPE fromType, bool compa
relnote = mptSmp.RelativeTone;
} else
{
int f2t = ModSample::FrequencyToTranspose(mptSmp.nC5Speed);
relnote = static_cast<int8>(f2t / 128);
finetune = static_cast<int8>(f2t & 0x7F);
std::tie(relnote, finetune) = ModSample::FrequencyToTranspose(mptSmp.nC5Speed);
}
flags = 0;

View File

@ -44,6 +44,7 @@ IMixPlugin::IMixPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN
, m_SndFile(sndFile)
, m_pMixStruct(mixStruct)
{
m_SndFile.m_loadedPlugins++;
m_MixState.pMixBuffer = (mixsample_t *)((((intptr_t)m_MixBuffer) + 7) & ~7);
while(m_pMixStruct != &(m_SndFile.m_MixPlugins[m_nSlot]) && m_nSlot < MAX_MIXPLUGINS - 1)
{
@ -71,6 +72,7 @@ IMixPlugin::~IMixPlugin()
if (m_pPrev) m_pPrev->m_pNext = m_pNext;
m_pPrev = nullptr;
m_pNext = nullptr;
m_SndFile.m_loadedPlugins--;
}

View File

@ -392,9 +392,7 @@ void CVstPluginManager::EnumerateDirectXDMOs()
if(ERROR_SUCCESS == RegQueryValueEx(hksub, nullptr, 0, &datatype, (LPBYTE)name, &datasize))
{
mpt::String::SetNullTerminator(name);
VSTPluginLib *plug = new (std::nothrow) VSTPluginLib(DMOPlugin::Create, true, mpt::PathString::FromNative(Util::GUIDToString(clsid)), mpt::PathString::FromNative(name));
VSTPluginLib *plug = new (std::nothrow) VSTPluginLib(DMOPlugin::Create, true, mpt::PathString::FromNative(Util::GUIDToString(clsid)), mpt::PathString::FromNative(ParseMaybeNullTerminatedStringFromBufferWithSizeInBytes<mpt::winstring>(name, datasize)));
if(plug != nullptr)
{
try

View File

@ -3607,7 +3607,7 @@ static void TestLoadS3MFile(const CSoundFile &sndFile, bool resaved)
VERIFY_EQUAL_NONCONT((sndFile.m_SongFlags & SONG_FILE_FLAGS), SONG_FASTVOLSLIDES);
VERIFY_EQUAL_NONCONT(sndFile.GetMixLevels(), mixLevelsCompatible);
VERIFY_EQUAL_NONCONT(sndFile.m_nTempoMode, tempoModeClassic);
VERIFY_EQUAL_NONCONT(sndFile.m_dwLastSavedWithVersion, resaved ? Version(Version::Current().GetRawVersion() & 0xFFFF0000u) : MPT_V("1.27.00.00"));
VERIFY_EQUAL_NONCONT(sndFile.m_dwLastSavedWithVersion, resaved ? Version::Current() : MPT_V("1.27.00.00"));
VERIFY_EQUAL_NONCONT(sndFile.Order().GetRestartPos(), 0);
// Channels