Updated libopenmpt to version 0.5.9
parent
7181656ae9
commit
24dfaf7d5c
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -140,6 +140,8 @@
|
|||
// <atomic>
|
||||
|
||||
#include "../common/misc_util.h"
|
||||
// <stdexcept>
|
||||
// <vector>
|
||||
|
||||
// for std::abs
|
||||
#include <cstdlib>
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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--;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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)))
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"));
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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--;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue