libOpenMPT Legacy: Updated to version 0.5.17

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
CQTexperiment
Christopher Snowhill 2022-03-14 04:35:36 -07:00
parent aa28b2beb1
commit 3815ba0baf
15 changed files with 150 additions and 109 deletions

View File

@ -1,4 +1,4 @@
MPT_SVNVERSION=16768 MPT_SVNVERSION=17112
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.16 MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.17
MPT_SVNDATE=2022-01-30T16:50:10.915999Z MPT_SVNDATE=2022-03-13T14:51:00.976461Z

View File

@ -1,10 +1,10 @@
#pragma once #pragma once
#define OPENMPT_VERSION_SVNVERSION "16768" #define OPENMPT_VERSION_SVNVERSION "17112"
#define OPENMPT_VERSION_REVISION 16768 #define OPENMPT_VERSION_REVISION 17112
#define OPENMPT_VERSION_DIRTY 0 #define OPENMPT_VERSION_DIRTY 0
#define OPENMPT_VERSION_MIXEDREVISIONS 0 #define OPENMPT_VERSION_MIXEDREVISIONS 0
#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.16" #define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.17"
#define OPENMPT_VERSION_DATE "2022-01-30T16:50:10.915999Z" #define OPENMPT_VERSION_DATE "2022-03-13T14:51:00.976461Z"
#define OPENMPT_VERSION_IS_PACKAGE 1 #define OPENMPT_VERSION_IS_PACKAGE 1

View File

@ -18,6 +18,6 @@ OPENMPT_NAMESPACE_BEGIN
#define VER_MAJORMAJOR 1 #define VER_MAJORMAJOR 1
#define VER_MAJOR 29 #define VER_MAJOR 29
#define VER_MINOR 15 #define VER_MINOR 15
#define VER_MINORMINOR 04 #define VER_MINORMINOR 06
OPENMPT_NAMESPACE_END OPENMPT_NAMESPACE_END

View File

@ -5,6 +5,21 @@ Changelog {#changelog}
For fully detailed change log, please see the source repository directly. This For fully detailed change log, please see the source repository directly. This
is just a high-level summary. is just a high-level summary.
### libopenmpt 0.5.17 (2022-03-13)
* [**Sec**] Possible out-of-bounds write in malformed IT / XM / MPTM files
using the internal LFO plugin. (r17081)
* [**Sec**] Possible out-of-bounds read when using Amiga BLEP interpolation
with extremely high-pitched notes. (r17082)
* MO3: Pattern indices 254 / 255 were not treated as playable patterns even if
the original file was a MOD / XM.
* Correctly apply ST3-style effect memory when seeking in S3M files.
* Command S (S3M / IT style) effect memory was not applied when seeking.
* FLAC: Update to v1.3.4 (2022-02-21).
* pugixml: Update to v1.12.1 (2022-02-16).
### libopenmpt 0.5.16 (2022-01-30) ### libopenmpt 0.5.16 (2022-01-30)
* [**Bug**] Possible hang with malformed DMF, DSM, MED and OKT files * [**Bug**] Possible hang with malformed DMF, DSM, MED and OKT files

View File

@ -127,12 +127,12 @@
/*! \defgroup libopenmpt_cpp libopenmpt C++ */ /*! \defgroup libopenmpt_cpp libopenmpt C++ */
namespace openmpt {
/*! \addtogroup libopenmpt_cpp /*! \addtogroup libopenmpt_cpp
@{ @{
*/ */
namespace openmpt {
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma warning(push) #pragma warning(push)
#pragma warning(disable:4275) #pragma warning(disable:4275)
@ -1163,10 +1163,10 @@ public:
}; // class module }; // class module
} // namespace openmpt
/*! /*!
@} @}
*/ */
} // namespace openmpt
#endif // LIBOPENMPT_HPP #endif // LIBOPENMPT_HPP

View File

@ -22,6 +22,14 @@
#define LIBOPENMPT_CXX_API #define LIBOPENMPT_CXX_API
#undef LIBOPENMPT_CXX_API #undef LIBOPENMPT_CXX_API
/*!
@}
*/
/*! \addtogroup libopenmpt_c
@{
*/
/*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_buffer.h exists. */ /*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_buffer.h exists. */
#define LIBOPENMPT_STREAM_CALLBACKS_BUFFER #define LIBOPENMPT_STREAM_CALLBACKS_BUFFER
@ -51,6 +59,14 @@
*/ */
#define LIBOPENMPT_STREAM_CALLBACKS_FILE #define LIBOPENMPT_STREAM_CALLBACKS_FILE
/*!
@}
*/
/*! \addtogroup libopenmpt
@{
*/
#if defined(__DOXYGEN__) #if defined(__DOXYGEN__)
#define LIBOPENMPT_API_HELPER_EXPORT #define LIBOPENMPT_API_HELPER_EXPORT

View File

@ -26,12 +26,12 @@
/*! \defgroup libopenmpt_ext_cpp libopenmpt_ext C++ */ /*! \defgroup libopenmpt_ext_cpp libopenmpt_ext C++ */
namespace openmpt {
/*! \addtogroup libopenmpt_ext_cpp /*! \addtogroup libopenmpt_ext_cpp
@{ @{
*/ */
namespace openmpt {
class module_ext_impl; class module_ext_impl;
class LIBOPENMPT_CXX_API module_ext : public module { class LIBOPENMPT_CXX_API module_ext : public module {
@ -77,8 +77,16 @@ public:
}; // class module_ext }; // class module_ext
/*!
@}
*/
namespace ext { namespace ext {
/*! \addtogroup libopenmpt_ext_cpp
@{
*/
#define LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE(name) \ #define LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE(name) \
static const char name ## _id [] = # name ; \ static const char name ## _id [] = # name ; \
class name; \ class name; \
@ -300,12 +308,12 @@ class interactive {
#undef LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE #undef LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE
#undef LIBOPENMPT_EXT_CXX_INTERFACE #undef LIBOPENMPT_EXT_CXX_INTERFACE
} // namespace ext
} // namespace openmpt
/*! /*!
@} @}
*/ */
} // namespace ext
} // namespace openmpt
#endif // LIBOPENMPT_EXT_HPP #endif // LIBOPENMPT_EXT_HPP

View File

@ -34,12 +34,20 @@
#include "soundlib/mod_specifications.h" #include "soundlib/mod_specifications.h"
#include "soundlib/AudioReadTarget.h" #include "soundlib/AudioReadTarget.h"
#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
#include <windows.h>
#endif // MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
OPENMPT_NAMESPACE_BEGIN OPENMPT_NAMESPACE_BEGIN
#if !defined(MPT_BUILD_SILENCE_LIBOPENMPT_CONFIGURATION_WARNINGS) #if !defined(MPT_BUILD_SILENCE_LIBOPENMPT_CONFIGURATION_WARNINGS)
#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT #if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
#if defined(_WIN32_WINNT) #if defined(NTDDI_VERSION)
#if (NTDDI_VERSION < 0x06020000)
MPT_WARNING("Warning: libopenmpt for WinRT is built with reduced functionality. Please #define NTDDI_VERSION 0x0602000.")
#endif
#elif defined(_WIN32_WINNT)
#if (_WIN32_WINNT < 0x0602) #if (_WIN32_WINNT < 0x0602)
MPT_WARNING("Warning: libopenmpt for WinRT is built with reduced functionality. Please #define _WIN32_WINNT 0x0602.") MPT_WARNING("Warning: libopenmpt for WinRT is built with reduced functionality. Please #define _WIN32_WINNT 0x0602.")
#endif // _WIN32_WINNT #endif // _WIN32_WINNT

View File

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

View File

@ -1,8 +1,8 @@
LIBOPENMPT_VERSION_MAJOR=0 LIBOPENMPT_VERSION_MAJOR=0
LIBOPENMPT_VERSION_MINOR=5 LIBOPENMPT_VERSION_MINOR=5
LIBOPENMPT_VERSION_PATCH=16 LIBOPENMPT_VERSION_PATCH=17
LIBOPENMPT_VERSION_PREREL= LIBOPENMPT_VERSION_PREREL=
LIBOPENMPT_LTVER_CURRENT=2 LIBOPENMPT_LTVER_CURRENT=2
LIBOPENMPT_LTVER_REVISION=16 LIBOPENMPT_LTVER_REVISION=17
LIBOPENMPT_LTVER_AGE=2 LIBOPENMPT_LTVER_AGE=2

View File

@ -41,9 +41,7 @@ typedef IntToFloatTraits<2, 2, mixsample_t, int16, -int16_min> Int16SToFloatS;
template<class Traits> template<class Traits>
struct LinearInterpolation struct LinearInterpolation
{ {
MPT_FORCEINLINE void Start(const ModChannel &, const CResampler &) { } MPT_FORCEINLINE LinearInterpolation(const ModChannel &, const CResampler &, unsigned int) { }
MPT_FORCEINLINE void End(const ModChannel &) { }
MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const uint32 posLo) MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const uint32 posLo)
{ {
@ -64,8 +62,7 @@ struct LinearInterpolation
template<class Traits> template<class Traits>
struct FastSincInterpolation struct FastSincInterpolation
{ {
MPT_FORCEINLINE void Start(const ModChannel &, const CResampler &) { } MPT_FORCEINLINE FastSincInterpolation(const ModChannel &, const CResampler &, unsigned int) { }
MPT_FORCEINLINE void End(const ModChannel &) { }
MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const uint32 posLo) MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const uint32 posLo)
{ {
@ -89,14 +86,12 @@ struct PolyphaseInterpolation
{ {
const typename Traits::output_t *sinc; const typename Traits::output_t *sinc;
MPT_FORCEINLINE void Start(const ModChannel &chn, const CResampler &resampler) MPT_FORCEINLINE PolyphaseInterpolation(const ModChannel &chn, const CResampler &resampler, unsigned int)
{ {
sinc = (((chn.increment > SamplePosition(0x130000000ll)) || (chn.increment < -SamplePosition(-0x130000000ll))) ? sinc = (((chn.increment > SamplePosition(0x130000000ll)) || (chn.increment < -SamplePosition(-0x130000000ll))) ?
(((chn.increment > SamplePosition(0x180000000ll)) || (chn.increment < SamplePosition(-0x180000000ll))) ? resampler.gDownsample2x : resampler.gDownsample13x) : resampler.gKaiserSinc); (((chn.increment > SamplePosition(0x180000000ll)) || (chn.increment < SamplePosition(-0x180000000ll))) ? resampler.gDownsample2x : resampler.gDownsample13x) : resampler.gKaiserSinc);
} }
MPT_FORCEINLINE void End(const ModChannel &) { }
MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const uint32 posLo) MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const uint32 posLo)
{ {
static_assert(static_cast<int>(Traits::numChannelsIn) <= static_cast<int>(Traits::numChannelsOut), "Too many input channels"); static_assert(static_cast<int>(Traits::numChannelsIn) <= static_cast<int>(Traits::numChannelsOut), "Too many input channels");
@ -123,13 +118,11 @@ struct FIRFilterInterpolation
{ {
const typename Traits::output_t *WFIRlut; const typename Traits::output_t *WFIRlut;
MPT_FORCEINLINE void Start(const ModChannel &, const CResampler &resampler) MPT_FORCEINLINE FIRFilterInterpolation(const ModChannel &, const CResampler &resampler, unsigned int)
{ {
WFIRlut = resampler.m_WindowedFIR.lut; WFIRlut = resampler.m_WindowedFIR.lut;
} }
MPT_FORCEINLINE void End(const ModChannel &) { }
MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const uint32 posLo) MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const uint32 posLo)
{ {
static_assert(static_cast<int>(Traits::numChannelsIn) <= static_cast<int>(Traits::numChannelsOut), "Too many input channels"); static_assert(static_cast<int>(Traits::numChannelsIn) <= static_cast<int>(Traits::numChannelsOut), "Too many input channels");
@ -159,30 +152,30 @@ struct NoRamp
{ {
typename Traits::output_t lVol, rVol; typename Traits::output_t lVol, rVol;
MPT_FORCEINLINE void Start(const ModChannel &chn) MPT_FORCEINLINE NoRamp(const ModChannel &chn)
{ {
lVol = static_cast<Traits::output_t>(chn.leftVol) * (1.0f / 4096.0f); lVol = static_cast<Traits::output_t>(chn.leftVol) * (1.0f / 4096.0f);
rVol = static_cast<Traits::output_t>(chn.rightVol) * (1.0f / 4096.0f); rVol = static_cast<Traits::output_t>(chn.rightVol) * (1.0f / 4096.0f);
} }
MPT_FORCEINLINE void End(const ModChannel &) { }
}; };
struct Ramp struct Ramp
{ {
ModChannel &channel;
int32 lRamp, rRamp; int32 lRamp, rRamp;
MPT_FORCEINLINE void Start(const ModChannel &chn) MPT_FORCEINLINE Ramp(ModChannel &chn)
: channel{chn}
{ {
lRamp = chn.rampLeftVol; lRamp = chn.rampLeftVol;
rRamp = chn.rampRightVol; rRamp = chn.rampRightVol;
} }
MPT_FORCEINLINE void End(ModChannel &chn) MPT_FORCEINLINE ~Ramp()
{ {
chn.rampLeftVol = lRamp; chn.leftVol = lRamp >> VOLUMERAMPPRECISION; channel.rampLeftVol = lRamp; channel.leftVol = lRamp >> VOLUMERAMPPRECISION;
chn.rampRightVol = rRamp; chn.rightVol = rRamp >> VOLUMERAMPPRECISION; channel.rampRightVol = rRamp; channel.rightVol = rRamp >> VOLUMERAMPPRECISION;
} }
}; };
@ -259,8 +252,7 @@ struct MixStereoRamp : public Ramp
template<class Traits> template<class Traits>
struct NoFilter struct NoFilter
{ {
MPT_FORCEINLINE void Start(const ModChannel &) { } MPT_FORCEINLINE NoFilter(const ModChannel &) { }
MPT_FORCEINLINE void End(const ModChannel &) { }
MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &, const ModChannel &) { } MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &, const ModChannel &) { }
}; };
@ -270,10 +262,12 @@ struct NoFilter
template<class Traits> template<class Traits>
struct ResonantFilter struct ResonantFilter
{ {
ModChannel &channel;
// Filter history // Filter history
typename Traits::output_t fy[Traits::numChannelsIn][2]; typename Traits::output_t fy[Traits::numChannelsIn][2];
MPT_FORCEINLINE void Start(const ModChannel &chn) MPT_FORCEINLINE ResonantFilter(ModChannel &chn)
: channel{chn}
{ {
for(int i = 0; i < Traits::numChannelsIn; i++) for(int i = 0; i < Traits::numChannelsIn; i++)
{ {
@ -282,12 +276,12 @@ struct ResonantFilter
} }
} }
MPT_FORCEINLINE void End(ModChannel &chn) MPT_FORCEINLINE ~ResonantFilter(ModChannel &chn)
{ {
for(int i = 0; i < Traits::numChannelsIn; i++) for(int i = 0; i < Traits::numChannelsIn; i++)
{ {
chn.nFilter_Y[i][0] = fy[i][0]; channel.nFilter_Y[i][0] = fy[i][0];
chn.nFilter_Y[i][1] = fy[i][1]; channel.nFilter_Y[i][1] = fy[i][1];
} }
} }

View File

@ -50,23 +50,34 @@ template<class Traits>
struct AmigaBlepInterpolation struct AmigaBlepInterpolation
{ {
SamplePosition subIncrement; SamplePosition subIncrement;
Paula::State *paula; Paula::State &paula;
const Paula::BlepArray *WinSincIntegral; const Paula::BlepArray &WinSincIntegral;
int numSteps; const int numSteps;
unsigned int remainingSamples = 0;
MPT_FORCEINLINE void Start(ModChannel &chn, const CResampler &resampler) MPT_FORCEINLINE AmigaBlepInterpolation(ModChannel &chn, const CResampler &resampler, unsigned int numSamples)
: paula{chn.paulaState}
, WinSincIntegral{resampler.blepTables.GetAmigaTable(resampler.m_Settings.emulateAmiga, chn.dwFlags[CHN_AMIGAFILTER])}
, numSteps{chn.paulaState.numSteps}
{ {
paula = &chn.paulaState;
numSteps = paula->numSteps;
WinSincIntegral = &resampler.blepTables.GetAmigaTable(resampler.m_Settings.emulateAmiga, chn.dwFlags[CHN_AMIGAFILTER]);
if(numSteps) if(numSteps)
{
subIncrement = chn.increment / numSteps; subIncrement = chn.increment / numSteps;
} // May we read past the start or end of sample if we do partial sample increments?
// If that's the case, don't apply any sub increments on the source sample if we reached the last output sample
// Note that this should only happen with notes well outside the Amiga note range, e.g. in software-mixed formats like MED
const int32 targetPos = (chn.position + chn.increment * numSamples).GetInt();
if(static_cast<SmpLength>(targetPos) > chn.nLength)
remainingSamples = numSamples;
}
MPT_FORCEINLINE void End(const ModChannel &) { } }
MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo) MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
{ {
if(--remainingSamples == 0)
subIncrement = {};
SamplePosition pos(0, posLo); SamplePosition pos(0, posLo);
// First, process steps of full length (one Amiga clock interval) // First, process steps of full length (one Amiga clock interval)
for(int step = numSteps; step > 0; step--) for(int step = numSteps; step > 0; step--)
@ -75,26 +86,26 @@ struct AmigaBlepInterpolation
int32 posInt = pos.GetInt() * Traits::numChannelsIn; int32 posInt = pos.GetInt() * Traits::numChannelsIn;
for(int32 i = 0; i < Traits::numChannelsIn; i++) for(int32 i = 0; i < Traits::numChannelsIn; i++)
inSample += Traits::Convert(inBuffer[posInt + i]); inSample += Traits::Convert(inBuffer[posInt + i]);
paula->InputSample(static_cast<int16>(inSample / (4 * Traits::numChannelsIn))); paula.InputSample(static_cast<int16>(inSample / (4 * Traits::numChannelsIn)));
paula->Clock(Paula::MINIMUM_INTERVAL); paula.Clock(Paula::MINIMUM_INTERVAL);
pos += subIncrement; pos += subIncrement;
} }
paula->remainder += paula->stepRemainder; paula.remainder += paula.stepRemainder;
// Now, process any remaining integer clock amount < MINIMUM_INTERVAL // Now, process any remaining integer clock amount < MINIMUM_INTERVAL
uint32 remainClocks = paula->remainder.GetInt(); uint32 remainClocks = paula.remainder.GetInt();
if(remainClocks) if(remainClocks)
{ {
typename Traits::output_t inSample = 0; typename Traits::output_t inSample = 0;
int32 posInt = pos.GetInt() * Traits::numChannelsIn; int32 posInt = pos.GetInt() * Traits::numChannelsIn;
for(int32 i = 0; i < Traits::numChannelsIn; i++) for(int32 i = 0; i < Traits::numChannelsIn; i++)
inSample += Traits::Convert(inBuffer[posInt + i]); inSample += Traits::Convert(inBuffer[posInt + i]);
paula->InputSample(static_cast<int16>(inSample / (4 * Traits::numChannelsIn))); paula.InputSample(static_cast<int16>(inSample / (4 * Traits::numChannelsIn)));
paula->Clock(remainClocks); paula.Clock(remainClocks);
paula->remainder.RemoveInt(); paula.remainder.RemoveInt();
} }
auto out = paula->OutputSample(*WinSincIntegral); auto out = paula.OutputSample(WinSincIntegral);
for(int i = 0; i < Traits::numChannelsOut; i++) for(int i = 0; i < Traits::numChannelsOut; i++)
outSample[i] = out; outSample[i] = out;
} }
@ -104,9 +115,7 @@ struct AmigaBlepInterpolation
template<class Traits> template<class Traits>
struct LinearInterpolation struct LinearInterpolation
{ {
MPT_FORCEINLINE void Start(const ModChannel &, const CResampler &) { } MPT_FORCEINLINE LinearInterpolation(const ModChannel &, const CResampler &, unsigned int) { }
MPT_FORCEINLINE void End(const ModChannel &) { }
MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo) MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
{ {
@ -127,8 +136,7 @@ struct LinearInterpolation
template<class Traits> template<class Traits>
struct FastSincInterpolation struct FastSincInterpolation
{ {
MPT_FORCEINLINE void Start(const ModChannel &, const CResampler &) { } MPT_FORCEINLINE FastSincInterpolation(const ModChannel &, const CResampler &, unsigned int) { }
MPT_FORCEINLINE void End(const ModChannel &) { }
MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo) MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
{ {
@ -152,7 +160,7 @@ struct PolyphaseInterpolation
{ {
const SINC_TYPE *sinc; const SINC_TYPE *sinc;
MPT_FORCEINLINE void Start(const ModChannel &chn, const CResampler &resampler) MPT_FORCEINLINE PolyphaseInterpolation(const ModChannel &chn, const CResampler &resampler, unsigned int)
{ {
#ifdef MODPLUG_TRACKER #ifdef MODPLUG_TRACKER
// Otherwise causes "warning C4100: 'resampler' : unreferenced formal parameter" // Otherwise causes "warning C4100: 'resampler' : unreferenced formal parameter"
@ -164,8 +172,6 @@ struct PolyphaseInterpolation
(((chn.increment > SamplePosition(0x180000000ll)) || (chn.increment < SamplePosition(-0x180000000ll))) ? resampler.gDownsample2x : resampler.gDownsample13x) : resampler.gKaiserSinc); (((chn.increment > SamplePosition(0x180000000ll)) || (chn.increment < SamplePosition(-0x180000000ll))) ? resampler.gDownsample2x : resampler.gDownsample13x) : resampler.gKaiserSinc);
} }
MPT_FORCEINLINE void End(const ModChannel &) { }
MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo) MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
{ {
static_assert(static_cast<int>(Traits::numChannelsIn) <= static_cast<int>(Traits::numChannelsOut), "Too many input channels"); static_assert(static_cast<int>(Traits::numChannelsIn) <= static_cast<int>(Traits::numChannelsOut), "Too many input channels");
@ -192,13 +198,11 @@ struct FIRFilterInterpolation
{ {
const int16 *WFIRlut; const int16 *WFIRlut;
MPT_FORCEINLINE void Start(const ModChannel &, const CResampler &resampler) MPT_FORCEINLINE FIRFilterInterpolation(const ModChannel &, const CResampler &resampler, unsigned int)
{ {
WFIRlut = resampler.m_WindowedFIR.lut; WFIRlut = resampler.m_WindowedFIR.lut;
} }
MPT_FORCEINLINE void End(const ModChannel &) { }
MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo) MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
{ {
static_assert(static_cast<int>(Traits::numChannelsIn) <= static_cast<int>(Traits::numChannelsOut), "Too many input channels"); static_assert(static_cast<int>(Traits::numChannelsIn) <= static_cast<int>(Traits::numChannelsOut), "Too many input channels");
@ -230,30 +234,30 @@ struct NoRamp
{ {
typename Traits::output_t lVol, rVol; typename Traits::output_t lVol, rVol;
MPT_FORCEINLINE void Start(const ModChannel &chn) MPT_FORCEINLINE NoRamp(const ModChannel &chn)
{ {
lVol = chn.leftVol; lVol = chn.leftVol;
rVol = chn.rightVol; rVol = chn.rightVol;
} }
MPT_FORCEINLINE void End(const ModChannel &) { }
}; };
struct Ramp struct Ramp
{ {
ModChannel &channel;
int32 lRamp, rRamp; int32 lRamp, rRamp;
MPT_FORCEINLINE void Start(const ModChannel &chn) MPT_FORCEINLINE Ramp(ModChannel &chn)
: channel{chn}
{ {
lRamp = chn.rampLeftVol; lRamp = chn.rampLeftVol;
rRamp = chn.rampRightVol; rRamp = chn.rampRightVol;
} }
MPT_FORCEINLINE void End(ModChannel &chn) MPT_FORCEINLINE ~Ramp()
{ {
chn.rampLeftVol = lRamp; chn.leftVol = lRamp >> VOLUMERAMPPRECISION; channel.rampLeftVol = lRamp; channel.leftVol = lRamp >> VOLUMERAMPPRECISION;
chn.rampRightVol = rRamp; chn.rightVol = rRamp >> VOLUMERAMPPRECISION; channel.rampRightVol = rRamp; channel.rightVol = rRamp >> VOLUMERAMPPRECISION;
} }
}; };
@ -331,8 +335,7 @@ struct MixStereoRamp : public Ramp
template<class Traits> template<class Traits>
struct NoFilter struct NoFilter
{ {
MPT_FORCEINLINE void Start(const ModChannel &) { } MPT_FORCEINLINE NoFilter(const ModChannel &) { }
MPT_FORCEINLINE void End(const ModChannel &) { }
MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &, const ModChannel &) { } MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &, const ModChannel &) { }
}; };
@ -342,10 +345,12 @@ struct NoFilter
template<class Traits> template<class Traits>
struct ResonantFilter struct ResonantFilter
{ {
ModChannel &channel;
// Filter history // Filter history
typename Traits::output_t fy[Traits::numChannelsIn][2]; typename Traits::output_t fy[Traits::numChannelsIn][2];
MPT_FORCEINLINE void Start(const ModChannel &chn) MPT_FORCEINLINE ResonantFilter(ModChannel &chn)
: channel{chn}
{ {
for(int i = 0; i < Traits::numChannelsIn; i++) for(int i = 0; i < Traits::numChannelsIn; i++)
{ {
@ -354,12 +359,12 @@ struct ResonantFilter
} }
} }
MPT_FORCEINLINE void End(ModChannel &chn) MPT_FORCEINLINE ~ResonantFilter()
{ {
for(int i = 0; i < Traits::numChannelsIn; i++) for(int i = 0; i < Traits::numChannelsIn; i++)
{ {
chn.nFilter_Y[i][0] = fy[i][0]; channel.nFilter_Y[i][0] = fy[i][0];
chn.nFilter_Y[i][1] = fy[i][1]; channel.nFilter_Y[i][1] = fy[i][1];
} }
} }

View File

@ -41,8 +41,7 @@ struct MixerTraits
template<class Traits> template<class Traits>
struct NoInterpolation struct NoInterpolation
{ {
MPT_FORCEINLINE void Start(const ModChannel &, const CResampler &) { } MPT_FORCEINLINE NoInterpolation(const ModChannel &, const CResampler &, unsigned int) { }
MPT_FORCEINLINE void End(const ModChannel &) { }
MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const int32) MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const int32)
{ {
@ -72,14 +71,9 @@ static void SampleLoop(ModChannel &chn, const CResampler &resampler, typename Tr
ModChannel &c = chn; ModChannel &c = chn;
const typename Traits::input_t * MPT_RESTRICT inSample = static_cast<const typename Traits::input_t *>(c.pCurrentSample); const typename Traits::input_t * MPT_RESTRICT inSample = static_cast<const typename Traits::input_t *>(c.pCurrentSample);
InterpolationFunc interpolate; InterpolationFunc interpolate{c, resampler, numSamples};
FilterFunc filter; FilterFunc filter{c};
MixFunc mix; MixFunc mix{c};
// Do initialisation if necessary
interpolate.Start(c, resampler);
filter.Start(c);
mix.Start(c);
unsigned int samples = numSamples; unsigned int samples = numSamples;
SamplePosition smpPos = c.position; // Fixed-point sample position SamplePosition smpPos = c.position; // Fixed-point sample position
@ -96,10 +90,6 @@ static void SampleLoop(ModChannel &chn, const CResampler &resampler, typename Tr
smpPos += increment; smpPos += increment;
} }
mix.End(c);
filter.End(c);
interpolate.End(c);
c.position = smpPos; c.position = smpPos;
} }

View File

@ -500,6 +500,10 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
break; break;
case CMD_S3MCMDEX: case CMD_S3MCMDEX:
if(!chn.rowCommand.param && (GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT)))
chn.rowCommand.param = chn.nOldCmdEx;
else
chn.nOldCmdEx = static_cast<ModCommand::PARAM>(chn.rowCommand.param);
if((p->param & 0xF0) == 0x60) if((p->param & 0xF0) == 0x60)
{ {
// Fine Pattern Delay // Fine Pattern Delay
@ -958,6 +962,11 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
} }
break; break;
} }
if(m_playBehaviour[kST3EffectMemory] && param != 0)
{
UpdateS3MEffectMemory(chn, param);
}
} }
// Interpret F00 effect in XM files as "stop song" // Interpret F00 effect in XM files as "stop song"
@ -3439,10 +3448,6 @@ bool CSoundFile::ProcessEffects()
// S3M/IT Sxx Extended Commands // S3M/IT Sxx Extended Commands
case CMD_S3MCMDEX: case CMD_S3MCMDEX:
if(m_playBehaviour[kST3EffectMemory] && param == 0)
{
param = chn.nArpeggio; // S00 uses the last non-zero effect parameter as memory, like other effects including Arpeggio, so we "borrow" our memory there.
}
ExtendedS3MCommands(nChn, static_cast<ModCommand::PARAM>(param)); ExtendedS3MCommands(nChn, static_cast<ModCommand::PARAM>(param));
break; break;
@ -3702,9 +3707,9 @@ void CSoundFile::UpdateS3MEffectMemory(ModChannel &chn, ModCommand::PARAM param)
chn.nTremorParam = param; // Ixy chn.nTremorParam = param; // Ixy
chn.nArpeggio = param; // Jxy chn.nArpeggio = param; // Jxy
chn.nRetrigParam = param; // Qxy chn.nRetrigParam = param; // Qxy
chn.nTremoloDepth = (param & 0x0F) << 2; // Rxy chn.nTremoloDepth = (param & 0x0F) << 2; // Rxy
chn.nTremoloSpeed = (param >> 4) & 0x0F; // Rxy chn.nTremoloSpeed = (param >> 4) & 0x0F; // Rxy
// Sxy is not handled here. chn.nOldCmdEx = param; // Sxy
} }

View File

@ -117,7 +117,7 @@ void LFOPlugin::Process(float *pOutL, float *pOutR, uint32 numFrames)
if(m_outputToCC) if(m_outputToCC)
{ {
plugin->MidiSend(MIDIEvents::CC(static_cast<MIDIEvents::MidiCC>(m_outputParam & 0x7F), static_cast<uint8>((m_outputParam >> 8) & 0x0F), mpt::saturate_round<uint8>(value * 127.0f))); plugin->MidiSend(MIDIEvents::CC(static_cast<MIDIEvents::MidiCC>(m_outputParam & 0x7F), static_cast<uint8>((m_outputParam >> 8) & 0x0F), mpt::saturate_round<uint8>(value * 127.0f)));
} else } else if(m_outputParam >= 0)
{ {
plugin->SetParameter(m_outputParam, static_cast<PlugParamValue>(value)); plugin->SetParameter(m_outputParam, static_cast<PlugParamValue>(value));
} }