Updated libopenmpt to version 0.5.9
parent
7181656ae9
commit
24dfaf7d5c
|
@ -1,4 +1,4 @@
|
||||||
|
|
||||||
MPT_SVNVERSION=14580
|
MPT_SVNVERSION=15019
|
||||||
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.8
|
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.9
|
||||||
MPT_SVNDATE=2021-04-11T14:02:18.903044Z
|
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.
|
# emits native wasm AND javascript with full wasm optimizations.
|
||||||
# as of emscripten 1.38, this is equivalent to default.
|
# as of emscripten 1.38, this is equivalent to default.
|
||||||
CPPFLAGS += -DMPT_BUILD_WASM
|
CPPFLAGS += -DMPT_BUILD_WASM
|
||||||
CXXFLAGS += -s WASM=2 -s LEGACY_VM_SUPPORT=1
|
CXXFLAGS +=
|
||||||
CFLAGS += -s WASM=2 -s LEGACY_VM_SUPPORT=1
|
CFLAGS +=
|
||||||
LDFLAGS += -s WASM=2 -s LEGACY_VM_SUPPORT=1
|
LDFLAGS += -s WASM=2 -s LEGACY_VM_SUPPORT=1
|
||||||
|
|
||||||
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
|
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
|
||||||
|
@ -51,8 +51,8 @@ LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
|
||||||
else ifeq ($(EMSCRIPTEN_TARGET),audioworkletprocessor)
|
else ifeq ($(EMSCRIPTEN_TARGET),audioworkletprocessor)
|
||||||
# emits an es6 module in a single file suitable for use in an AudioWorkletProcessor
|
# emits an es6 module in a single file suitable for use in an AudioWorkletProcessor
|
||||||
CPPFLAGS += -DMPT_BUILD_WASM -DMPT_BUILD_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
|
CXXFLAGS +=
|
||||||
CFLAGS += -s WASM=1 -s WASM_ASYNC_COMPILATION=0 -s MODULARIZE=1 -s EXPORT_ES6=1 -s SINGLE_FILE=1
|
CFLAGS +=
|
||||||
LDFLAGS += -s WASM=1 -s WASM_ASYNC_COMPILATION=0 -s MODULARIZE=1 -s EXPORT_ES6=1 -s SINGLE_FILE=1
|
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
|
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
|
||||||
|
@ -60,8 +60,8 @@ LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
|
||||||
else ifeq ($(EMSCRIPTEN_TARGET),wasm)
|
else ifeq ($(EMSCRIPTEN_TARGET),wasm)
|
||||||
# emits native wasm.
|
# emits native wasm.
|
||||||
CPPFLAGS += -DMPT_BUILD_WASM
|
CPPFLAGS += -DMPT_BUILD_WASM
|
||||||
CXXFLAGS += -s WASM=1
|
CXXFLAGS +=
|
||||||
CFLAGS += -s WASM=1
|
CFLAGS +=
|
||||||
LDFLAGS += -s WASM=1
|
LDFLAGS += -s WASM=1
|
||||||
|
|
||||||
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
|
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
|
||||||
|
@ -69,16 +69,16 @@ LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
|
||||||
else ifeq ($(EMSCRIPTEN_TARGET),js)
|
else ifeq ($(EMSCRIPTEN_TARGET),js)
|
||||||
# emits only plain javascript with plain javascript focused optimizations.
|
# emits only plain javascript with plain javascript focused optimizations.
|
||||||
CPPFLAGS += -DMPT_BUILD_ASMJS
|
CPPFLAGS += -DMPT_BUILD_ASMJS
|
||||||
CXXFLAGS += -s WASM=0 -s LEGACY_VM_SUPPORT=1
|
CXXFLAGS +=
|
||||||
CFLAGS += -s WASM=0 -s LEGACY_VM_SUPPORT=1
|
CFLAGS +=
|
||||||
LDFLAGS += -s WASM=0 -s LEGACY_VM_SUPPORT=1
|
LDFLAGS += -s WASM=0 -s LEGACY_VM_SUPPORT=1
|
||||||
|
|
||||||
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
|
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CXXFLAGS += -s DISABLE_EXCEPTION_CATCHING=0 -s ERROR_ON_UNDEFINED_SYMBOLS=1 -s ERROR_ON_MISSING_LIBRARIES=1 -ffast-math
|
CXXFLAGS += -s DISABLE_EXCEPTION_CATCHING=0 -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
|
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'"
|
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
|
CFLAGS_SILENT += -Wno-\#warnings
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#define OPENMPT_VERSION_SVNVERSION "14580"
|
#define OPENMPT_VERSION_SVNVERSION "15019"
|
||||||
#define OPENMPT_VERSION_REVISION 14580
|
#define OPENMPT_VERSION_REVISION 15019
|
||||||
#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.8"
|
#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.9"
|
||||||
#define OPENMPT_VERSION_DATE "2021-04-11T14:02:18.903044Z"
|
#define OPENMPT_VERSION_DATE "2021-05-16T14:59:54.252327Z"
|
||||||
#define OPENMPT_VERSION_IS_PACKAGE 1
|
#define OPENMPT_VERSION_IS_PACKAGE 1
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "mptTime.h"
|
#include "mptTime.h"
|
||||||
#include "mptLibrary.h"
|
#include "mptLibrary.h"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <cstdlib>
|
#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)
|
#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
|
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()
|
void InitProcSupport()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -150,6 +163,11 @@ void InitProcSupport()
|
||||||
if(StandardFeatureFlags.c & (1<<20)) ProcSupport |= PROCSUPPORT_SSE4_2;
|
if(StandardFeatureFlags.c & (1<<20)) ProcSupport |= PROCSUPPORT_SSE4_2;
|
||||||
if(StandardFeatureFlags.c & (1<<28)) ProcSupport |= PROCSUPPORT_AVX;
|
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);
|
cpuid_result ExtendedVendorString = cpuid(0x80000000u);
|
||||||
if(ExtendedVendorString.a >= 0x80000001u)
|
if(ExtendedVendorString.a >= 0x80000001u)
|
||||||
|
@ -160,11 +178,6 @@ void InitProcSupport()
|
||||||
if(ExtendedVendorString.a >= 0x80000004u)
|
if(ExtendedVendorString.a >= 0x80000004u)
|
||||||
{
|
{
|
||||||
mpt::String::WriteAutoBuf(ProcBrandID) = cpuid(0x80000002u).as_string4() + cpuid(0x80000003u).as_string4() + cpuid(0x80000004u).as_string4();
|
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>
|
// <atomic>
|
||||||
|
|
||||||
#include "../common/misc_util.h"
|
#include "../common/misc_util.h"
|
||||||
|
// <stdexcept>
|
||||||
|
// <vector>
|
||||||
|
|
||||||
// for std::abs
|
// for std::abs
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
|
@ -357,23 +357,6 @@ mpt::ustring GetBuildFeaturesString()
|
||||||
;
|
;
|
||||||
#endif
|
#endif
|
||||||
#ifdef MODPLUG_TRACKER
|
#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_("")
|
retval += UL_("")
|
||||||
#if defined(UNICODE)
|
#if defined(UNICODE)
|
||||||
UL_(" UNICODE")
|
UL_(" UNICODE")
|
||||||
|
|
|
@ -17,7 +17,7 @@ OPENMPT_NAMESPACE_BEGIN
|
||||||
// Version definitions. The only thing that needs to be changed when changing version number.
|
// Version definitions. The only thing that needs to be changed when changing version number.
|
||||||
#define VER_MAJORMAJOR 1
|
#define VER_MAJORMAJOR 1
|
||||||
#define VER_MAJOR 29
|
#define VER_MAJOR 29
|
||||||
#define VER_MINOR 09
|
#define VER_MINOR 10
|
||||||
#define VER_MINORMINOR 00
|
#define VER_MINORMINOR 00
|
||||||
|
|
||||||
OPENMPT_NAMESPACE_END
|
OPENMPT_NAMESPACE_END
|
||||||
|
|
|
@ -5,6 +5,26 @@ 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.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)
|
### libopenmpt 0.5.8 (2021-04-11)
|
||||||
|
|
||||||
* [**Sec**] Possible null-pointer dereference read caused by a sequence of
|
* [**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);
|
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 */
|
/*! 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 */
|
/*! 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 */
|
/*! 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 )
|
#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 */
|
/*! 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 */
|
/*! 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
|
#define OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS 1
|
||||||
|
|
|
@ -103,7 +103,7 @@
|
||||||
* threads for internal use.
|
* threads for internal use.
|
||||||
* - You must ensure to only ever access a particular libopenmpt object via
|
* - You must ensure to only ever access a particular libopenmpt object via
|
||||||
* non-const member functions from a single thread at a time.
|
* 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.
|
* threads when using only const member functions from all threads.
|
||||||
* - Consecutive accesses can happen from different threads.
|
* - Consecutive accesses can happen from different threads.
|
||||||
* - Different objects can be accessed concurrently 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();
|
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
|
//! 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
|
//! 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
|
//! 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;
|
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
|
//! 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
|
//! Possible return values for openmpt::probe_file_header(). \since 0.3.0
|
||||||
enum probe_file_header_result {
|
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 ) {
|
void module_ext_impl::set_instrument_mute_status( std::int32_t instrument, bool mute ) {
|
||||||
const bool instrument_mode = get_num_instruments() != 0;
|
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 ) {
|
if ( instrument < 0 || instrument >= max_instrument ) {
|
||||||
throw openmpt::exception("invalid 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 {
|
bool module_ext_impl::get_instrument_mute_status( std::int32_t instrument ) const {
|
||||||
const bool instrument_mode = get_num_instruments() != 0;
|
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 ) {
|
if ( instrument < 0 || instrument >= max_instrument ) {
|
||||||
throw openmpt::exception("invalid 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 ) {
|
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 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 ) {
|
if ( instrument < 0 || instrument >= max_instrument ) {
|
||||||
throw openmpt::exception("invalid instrument");
|
throw openmpt::exception("invalid instrument");
|
||||||
}
|
}
|
||||||
|
@ -261,15 +261,15 @@ namespace openmpt {
|
||||||
free_channel = MAX_CHANNELS - 1;
|
free_channel = MAX_CHANNELS - 1;
|
||||||
|
|
||||||
ModChannel &chn = m_sndFile->m_PlayState.Chn[free_channel];
|
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.nMasterChn = 0; // remove NNA association
|
||||||
chn.nNewNote = chn.nLastNote = static_cast<uint8>(note);
|
chn.nNewNote = chn.nLastNote = static_cast<uint8>(note);
|
||||||
chn.ResetEnvelopes();
|
chn.ResetEnvelopes();
|
||||||
m_sndFile->InstrumentChange(chn, instrument + 1);
|
m_sndFile->InstrumentChange(chn, instrument + 1);
|
||||||
chn.nFadeOutVol = 0x10000;
|
chn.nFadeOutVol = 0x10000;
|
||||||
m_sndFile->NoteChange(chn, note, false, true, true);
|
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.nPan = mpt::saturate_round<std::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.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
|
// 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,
|
// 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 */
|
/*! \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 8
|
#define OPENMPT_API_VERSION_PATCH 9
|
||||||
/*! \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 */
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
LIBOPENMPT_VERSION_MAJOR=0
|
LIBOPENMPT_VERSION_MAJOR=0
|
||||||
LIBOPENMPT_VERSION_MINOR=5
|
LIBOPENMPT_VERSION_MINOR=5
|
||||||
LIBOPENMPT_VERSION_PATCH=8
|
LIBOPENMPT_VERSION_PATCH=9
|
||||||
LIBOPENMPT_VERSION_PREREL=
|
LIBOPENMPT_VERSION_PREREL=
|
||||||
|
|
||||||
LIBOPENMPT_LTVER_CURRENT=2
|
LIBOPENMPT_LTVER_CURRENT=2
|
||||||
LIBOPENMPT_LTVER_REVISION=8
|
LIBOPENMPT_LTVER_REVISION=9
|
||||||
LIBOPENMPT_LTVER_AGE=2
|
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")
|
#pragma comment(linker, "/EXPORT:XMPIN_GetInterface=_XMPIN_GetInterface@8")
|
||||||
|
|
||||||
}; // extern "C"
|
} // extern "C"
|
||||||
|
|
||||||
|
|
||||||
#ifdef _MFC_VER
|
#ifdef _MFC_VER
|
||||||
|
|
|
@ -280,7 +280,7 @@ void CMegaBass::Process(int * MixSoundBuffer, int * MixRearBuffer, int count, ui
|
||||||
if(nChannels >= 2)
|
if(nChannels >= 2)
|
||||||
{
|
{
|
||||||
X86_StereoDCRemoval(MixSoundBuffer, count, nDCRFlt_Y1lf, nDCRFlt_X1lf, nDCRFlt_Y1rf, nDCRFlt_X1rf);
|
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 *px = MixSoundBuffer;
|
||||||
int *py = MixRearBuffer;
|
int *py = MixRearBuffer;
|
||||||
int x1 = nXBassFlt_X1;
|
int x1 = nXBassFlt_X1;
|
||||||
|
|
|
@ -48,24 +48,12 @@ struct XPK_BufferBounds
|
||||||
{
|
{
|
||||||
const uint8 *pSrcBeg;
|
const uint8 *pSrcBeg;
|
||||||
std::size_t SrcSize;
|
std::size_t SrcSize;
|
||||||
uint8 *pDstBeg;
|
|
||||||
std::size_t DstSize;
|
|
||||||
|
|
||||||
inline uint8 SrcRead(std::size_t index)
|
inline uint8 SrcRead(std::size_t index)
|
||||||
{
|
{
|
||||||
if(index >= SrcSize) throw XPK_error();
|
if(index >= SrcSize) throw XPK_error();
|
||||||
return pSrcBeg[index];
|
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)
|
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;
|
int32 cp, cup1, type;
|
||||||
std::size_t c;
|
std::size_t c;
|
||||||
std::size_t src;
|
std::size_t src;
|
||||||
std::size_t dst;
|
|
||||||
|
|
||||||
std::size_t phist = 0;
|
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;
|
XPK_BufferBounds bufs;
|
||||||
bufs.pSrcBeg = src_;
|
bufs.pSrcBeg = src_;
|
||||||
bufs.SrcSize = srcLen;
|
bufs.SrcSize = srcLen;
|
||||||
bufs.pDstBeg = mpt::byte_cast<uint8 *>(unpackedData.data());
|
|
||||||
bufs.DstSize = len;
|
|
||||||
|
|
||||||
src = 0;
|
src = 0;
|
||||||
dst = 0;
|
|
||||||
c = src;
|
c = src;
|
||||||
while (len > 0)
|
while(len > 0)
|
||||||
{
|
{
|
||||||
type = bufs.SrcRead(c+0);
|
type = bufs.SrcRead(c+0);
|
||||||
cp = (bufs.SrcRead(c+4)<<8) | (bufs.SrcRead(c+5)); // packed
|
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)
|
if (type == 0)
|
||||||
{
|
{
|
||||||
// RAW chunk
|
// RAW chunk
|
||||||
if(cp < 0) throw XPK_error();
|
if(cp < 0 || cp > len) throw XPK_error();
|
||||||
for(int32 i = 0; i < cp; ++i)
|
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;
|
c+=cp;
|
||||||
len -= cp;
|
len -= cp;
|
||||||
continue;
|
continue;
|
||||||
|
@ -164,14 +145,14 @@ static bool XPK_DoUnpack(const uint8 *src_, uint32 srcLen, std::vector<char> &un
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
LimitMax(cup1, len);
|
||||||
len -= cup1;
|
len -= cup1;
|
||||||
cp = (cp + 3) & 0xfffc;
|
cp = (cp + 3) & 0xfffc;
|
||||||
c += cp;
|
c += cp;
|
||||||
|
|
||||||
d0 = d1 = d2 = a2 = 0;
|
d0 = d1 = d2 = a2 = 0;
|
||||||
d3 = bufs.SrcRead(src); src++;
|
d3 = bufs.SrcRead(src); src++;
|
||||||
bufs.DstWrite(dst, (uint8)d3);
|
unpackedData.push_back(static_cast<char>(d3));
|
||||||
if (dst < dstmax) dst++;
|
|
||||||
cup1--;
|
cup1--;
|
||||||
|
|
||||||
while (cup1 > 0)
|
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);
|
d4 = bfexts(src,d0,d6,bufs);
|
||||||
d0 += d6;
|
d0 += d6;
|
||||||
d3 -= d4;
|
d3 -= d4;
|
||||||
bufs.DstWrite(dst, (uint8)d3);
|
unpackedData.push_back(static_cast<char>(d3));
|
||||||
if (dst < dstmax) dst++;
|
|
||||||
cup1--;
|
cup1--;
|
||||||
d5--;
|
d5--;
|
||||||
}
|
}
|
||||||
|
@ -243,7 +223,6 @@ static bool XPK_DoUnpack(const uint8 *src_, uint32 srcLen, std::vector<char> &un
|
||||||
d2 -= d6;
|
d2 -= d6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unpackedData.resize(bufs.DstSize - len);
|
|
||||||
return !unpackedData.empty();
|
return !unpackedData.empty();
|
||||||
|
|
||||||
l75a:
|
l75a:
|
||||||
|
@ -287,22 +266,24 @@ l79e:
|
||||||
l7a6:
|
l7a6:
|
||||||
d6 += d4;
|
d6 += d4;
|
||||||
l7a8:
|
l7a8:
|
||||||
if (bfextu(src,d0,1,bufs)) goto l7c4;
|
if(bfextu(src, d0, 1, bufs))
|
||||||
d0 += 1;
|
{
|
||||||
if (bfextu(src,d0,1,bufs)) goto l7bc;
|
d5 = 12;
|
||||||
d5 = 8;
|
a5 = -0x100;
|
||||||
a5 = 0;
|
} else
|
||||||
goto l7ca;
|
{
|
||||||
|
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;
|
d0 += 1;
|
||||||
d4 = bfextu(src,d0,d5,bufs);
|
d4 = bfextu(src,d0,d5,bufs);
|
||||||
d0 += d5;
|
d0 += d5;
|
||||||
|
@ -314,13 +295,15 @@ l7ca:
|
||||||
if (d1 < 0) d1 = 0;
|
if (d1 < 0) d1 = 0;
|
||||||
}
|
}
|
||||||
d6 += 2;
|
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))
|
while ((d6 >= 0) && (cup1 > 0))
|
||||||
{
|
{
|
||||||
d3 = bufs.DstRead(phist); phist++;
|
d3 = unpackedData[phist];
|
||||||
bufs.DstWrite(dst, (uint8)d3);
|
phist++;
|
||||||
if (dst < dstmax) dst++;
|
unpackedData.push_back(static_cast<char>(d3));
|
||||||
cup1--;
|
cup1--;
|
||||||
d6--;
|
d6--;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,8 @@ struct MixLoopState
|
||||||
{
|
{
|
||||||
samplePointer = static_cast<const int8 *>(chn.pCurrentSample);
|
samplePointer = static_cast<const int8 *>(chn.pCurrentSample);
|
||||||
lookaheadPointer = nullptr;
|
lookaheadPointer = nullptr;
|
||||||
|
if(!samplePointer)
|
||||||
|
return;
|
||||||
if(chn.nLoopEnd < InterpolationMaxLookahead)
|
if(chn.nLoopEnd < InterpolationMaxLookahead)
|
||||||
lookaheadStart = chn.nLoopStart;
|
lookaheadStart = chn.nLoopStart;
|
||||||
else
|
else
|
||||||
|
@ -94,7 +96,8 @@ struct MixLoopState
|
||||||
int32 nLoopStart = chn.dwFlags[CHN_LOOP] ? chn.nLoopStart : 0;
|
int32 nLoopStart = chn.dwFlags[CHN_LOOP] ? chn.nLoopStart : 0;
|
||||||
SamplePosition nInc = chn.increment;
|
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.
|
// 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;
|
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;
|
if(mptSmp.uFlags[CHN_PANNING]) dfp |= ITSample::enablePanning;
|
||||||
|
|
||||||
// Sample Format / Loop Flags
|
// Sample Format / Loop Flags
|
||||||
if(mptSmp.HasSampleData())
|
if(mptSmp.HasSampleData() && !mptSmp.uFlags[CHN_ADLIB])
|
||||||
{
|
{
|
||||||
flags = ITSample::sampleDataPresent;
|
flags = ITSample::sampleDataPresent;
|
||||||
if(mptSmp.uFlags[CHN_LOOP]) flags |= ITSample::sampleLoop;
|
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))
|
if((vid | vis) != 0 && (fromType & MOD_TYPE_XM))
|
||||||
{
|
{
|
||||||
// Sweep is upside down in 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])
|
if(mptSmp.uFlags[CHN_ADLIB])
|
||||||
{
|
{
|
||||||
length = 12;
|
length = 12;
|
||||||
|
flags = ITSample::sampleDataPresent;
|
||||||
cvt = ITSample::cvtOPLInstrument;
|
cvt = ITSample::cvtOPLInstrument;
|
||||||
} else if(mptSmp.uFlags[SMP_KEEPONDISK])
|
} else if(mptSmp.uFlags[SMP_KEEPONDISK])
|
||||||
{
|
{
|
||||||
|
@ -668,9 +672,9 @@ uint32 DecodeITEditTimer(uint16 cwtv, uint32 editTime)
|
||||||
if((cwtv & 0xFFF) >= 0x0208)
|
if((cwtv & 0xFFF) >= 0x0208)
|
||||||
{
|
{
|
||||||
editTime ^= 0x4954524B; // 'ITRK'
|
editTime ^= 0x4954524B; // 'ITRK'
|
||||||
editTime = (editTime >> 7) | (editTime << (32 - 7));
|
editTime = mpt::rotr(editTime, 7);
|
||||||
editTime = ~editTime + 1;
|
editTime = ~editTime + 1;
|
||||||
editTime = (editTime << 4) | (editTime >> (32 - 4));
|
editTime = mpt::rotl(editTime, 4);
|
||||||
editTime ^= 0x4A54484C; // 'JTHL'
|
editTime ^= 0x4A54484C; // 'JTHL'
|
||||||
}
|
}
|
||||||
return editTime;
|
return editTime;
|
||||||
|
|
|
@ -63,7 +63,7 @@ struct ITFileHeader
|
||||||
uint8le pwd; // Pitch Wheel Depth
|
uint8le pwd; // Pitch Wheel Depth
|
||||||
uint16le msglength; // Length of Song Message
|
uint16le msglength; // Length of Song Message
|
||||||
uint32le msgoffset; // Offset of Song Message in File (IT crops message after first null)
|
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 chnpan[64]; // Initial Channel Panning
|
||||||
uint8le chnvol[64]; // Initial Channel Volume
|
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++)
|
for(std::size_t i = 0; i < CountOf(fileHeader.breaks); i++)
|
||||||
{
|
{
|
||||||
if(fileHeader.orders[i] >= 128 && fileHeader.orders[i] < 0xFE)
|
if(fileHeader.orders[i] >= 128 && fileHeader.orders[i] < 0xFE)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
if(fileHeader.orders[i] < 128 && fileHeader.tempoList[i] == 0)
|
if(fileHeader.orders[i] < 128 && fileHeader.tempoList[i] == 0)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
if(fileHeader.tempoList[i] > 15)
|
||||||
|
return false;
|
||||||
if(fileHeader.breaks[i] >= 64)
|
if(fileHeader.breaks[i] >= 64)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -242,6 +238,7 @@ bool CSoundFile::Read669(FileReader &file, ModLoadingFlags loadFlags)
|
||||||
|
|
||||||
m->param = effect[chn] & 0x0F;
|
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;
|
uint8 command = effect[chn] >> 4;
|
||||||
if(command < static_cast<uint8>(CountOf(effTrans)))
|
if(command < static_cast<uint8>(CountOf(effTrans)))
|
||||||
{
|
{
|
||||||
|
|
|
@ -478,9 +478,12 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
|
||||||
{
|
{
|
||||||
// OpenMPT Version number (Major.Minor)
|
// 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.
|
// 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))
|
if(!memcmp(&fileHeader.reserved, "OMPT", 4))
|
||||||
interpretModPlugMade = true;
|
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)
|
} else if(fileHeader.cmwt == 0x888 || fileHeader.cwtv == 0x888)
|
||||||
{
|
{
|
||||||
// OpenMPT 1.17.02.26 (r122) to 1.18 (raped IT format)
|
// 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
|
} else
|
||||||
{
|
{
|
||||||
// IT
|
// IT
|
||||||
uint32 vVersion = Version::Current().GetRawVersion();
|
const uint32 mptVersion = 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)
|
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 :)
|
itHeader.cmwt = 0x0214; // Common compatible tracker :)
|
||||||
// Hack from schism tracker:
|
// Hack from schism tracker:
|
||||||
for(INSTRUMENTINDEX nIns = 1; nIns <= GetNumInstruments(); nIns++)
|
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)
|
if(compatibilityExport)
|
||||||
{
|
itHeader.reserved = mptVersion & 0xFFFF;
|
||||||
// This way, we indicate that the file might contain OpenMPT hacks. Compatibility export puts 0 here.
|
else
|
||||||
memcpy(&itHeader.reserved, "OMPT", 4);
|
memcpy(&itHeader.reserved, "OMPT", 4);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
itHeader.flags = ITFileHeader::useStereoPlayback | ITFileHeader::useMIDIPitchController;
|
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.nPan = std::min(static_cast<uint16>(sampleHeader.panning * 2), uint16(254));
|
||||||
mptSmp.nVibType = MDLVibratoType[sampleHeader.vibType & 3];
|
mptSmp.nVibType = MDLVibratoType[sampleHeader.vibType & 3];
|
||||||
mptSmp.nVibSweep = sampleHeader.vibSweep;
|
mptSmp.nVibSweep = sampleHeader.vibSweep;
|
||||||
mptSmp.nVibDepth = sampleHeader.vibDepth;
|
mptSmp.nVibDepth = (sampleHeader.vibDepth + 3u) / 4u;
|
||||||
mptSmp.nVibRate = sampleHeader.vibSpeed;
|
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)
|
if(sampleHeader.panEnvFlags & 0x40)
|
||||||
mptSmp.uFlags.set(CHN_PANNING);
|
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.
|
// 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 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)
|
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))
|
if(ValidateMODPatternData(file, 16, true))
|
||||||
numChannels = 8;
|
numChannels = 8;
|
||||||
file.Seek(patternStartOffset);
|
file.Seek(patternStartOffset);
|
||||||
} else if(numPatterns != officialPatterns && numChannels == 4 && !wowSampleLen)
|
} else if(numPatterns != officialPatterns && validateHiddenPatterns)
|
||||||
{
|
{
|
||||||
// Fix SoundTracker modules where "hidden" patterns should be ignored.
|
// Fix SoundTracker modules where "hidden" patterns should be ignored.
|
||||||
// razor-1911.mod (MD5 b75f0f471b0ae400185585ca05bf7fe8, SHA1 4de31af234229faec00f1e85e1e8f78f405d454b)
|
// 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)
|
// 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)
|
if(maybeWOW && GetNumChannels() == 8)
|
||||||
{
|
{
|
||||||
// M.K. with 8 channels = Mod's Grave
|
// M.K. with 8 channels = Mod's Grave
|
||||||
|
@ -1511,7 +1511,7 @@ bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
|
||||||
file.ReadStruct(fileHeader);
|
file.ReadStruct(fileHeader);
|
||||||
|
|
||||||
ReadOrderFromArray(Order(), fileHeader.orderList);
|
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
|
// Most likely just a file with lots of NULs at the start
|
||||||
if(fileHeader.restartPos == 0 && fileHeader.numOrders == 0 && numPatterns <= 1)
|
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_SongFlags.set(SONG_PT_MODE);
|
||||||
m_playBehaviour.set(kMODIgnorePanning);
|
m_playBehaviour.set(kMODIgnorePanning);
|
||||||
m_playBehaviour.set(kMODOneShotLoops);
|
m_playBehaviour.set(kMODOneShotLoops);
|
||||||
m_playBehaviour.set(kMODSampleSwap);
|
m_playBehaviour.reset(kMODSampleSwap);
|
||||||
|
|
||||||
return ok;
|
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
|
// MT2 only ever calls effGetChunk for programs, and OpenMPT uses the defaultProgram value to determine
|
||||||
// whether it should use effSetChunk for programs or banks...
|
// whether it should use effSetChunk for programs or banks...
|
||||||
mixPlug.defaultProgram = -1;
|
mixPlug.defaultProgram = -1;
|
||||||
LimitMax(vstHeader.n, Util::MaxValueOfType(dataSize) - 4);
|
LimitMax(vstHeader.n, std::numeric_limits<decltype(dataSize)>::max() - 4);
|
||||||
dataSize = vstHeader.n + 4;
|
dataSize = vstHeader.n + 4;
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
mixPlug.defaultProgram = vstHeader.programNr;
|
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;
|
dataSize = vstHeader.n * 4 + 4;
|
||||||
}
|
}
|
||||||
mixPlug.pluginData.resize(dataSize);
|
mixPlug.pluginData.resize(dataSize);
|
||||||
|
|
|
@ -284,6 +284,8 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
|
||||||
m_FileHistory.push_back(hist);
|
m_FileHistory.push_back(hist);
|
||||||
}
|
}
|
||||||
nonCompatTracker = true;
|
nonCompatTracker = true;
|
||||||
|
m_playBehaviour.set(kITRetrigger);
|
||||||
|
m_playBehaviour.set(kITShortSampleRetrig);
|
||||||
m_playBehaviour.set(kST3SampleSwap); // Not exactly like ST3, but close enough
|
m_playBehaviour.set(kST3SampleSwap); // Not exactly like ST3, but close enough
|
||||||
m_nMinPeriod = 1;
|
m_nMinPeriod = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -297,13 +299,19 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
|
||||||
madeWithTracker = GetSchismTrackerVersion(fileHeader.cwtv, fileHeader.reserved2);
|
madeWithTracker = GetSchismTrackerVersion(fileHeader.cwtv, fileHeader.reserved2);
|
||||||
m_nMinPeriod = 1;
|
m_nMinPeriod = 1;
|
||||||
isSchism = true;
|
isSchism = true;
|
||||||
|
if(fileHeader.cwtv >= SchismVersionFromDate<2016, 05, 13>::Version(S3MFileHeader::trkSchismTracker))
|
||||||
|
m_playBehaviour.set(kITShortSampleRetrig);
|
||||||
}
|
}
|
||||||
nonCompatTracker = true;
|
nonCompatTracker = true;
|
||||||
break;
|
break;
|
||||||
case S3MFileHeader::trkOpenMPT:
|
case S3MFileHeader::trkOpenMPT:
|
||||||
madeWithTracker = U_("OpenMPT");
|
{
|
||||||
formatTrackerStr = true;
|
uint32 mptVersion = (fileHeader.cwtv & S3MFileHeader::versionMask) << 16;
|
||||||
m_dwLastSavedWithVersion = Version((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;
|
break;
|
||||||
case S3MFileHeader::trkBeRoTracker:
|
case S3MFileHeader::trkBeRoTracker:
|
||||||
madeWithTracker = U_("BeRoTracker");
|
madeWithTracker = U_("BeRoTracker");
|
||||||
|
@ -676,7 +684,9 @@ bool CSoundFile::SaveS3M(std::ostream &f) const
|
||||||
// Version info following: ST3.20 = 0x1320
|
// Version info following: ST3.20 = 0x1320
|
||||||
// Most significant nibble = Tracker ID, see S3MFileHeader::S3MTrackerVersions
|
// Most significant nibble = Tracker ID, see S3MFileHeader::S3MTrackerVersions
|
||||||
// Following: One nibble = Major version, one byte = Minor version (hex)
|
// 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;
|
fileHeader.formatVersion = S3MFileHeader::newVersion;
|
||||||
memcpy(fileHeader.magic, "SCRM", 4);
|
memcpy(fileHeader.magic, "SCRM", 4);
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "MixerLoops.h"
|
#include "MixerLoops.h"
|
||||||
#include "..//soundbase/SampleBuffer.h"
|
#include "../soundbase/SampleBuffer.h"
|
||||||
#include "Snd_defs.h"
|
#include "Snd_defs.h"
|
||||||
#include "ModChannel.h"
|
#include "ModChannel.h"
|
||||||
#ifdef ENABLE_SSE2
|
#ifdef ENABLE_SSE2
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
OPENMPT_NAMESPACE_BEGIN
|
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)
|
if(resetMask & resetSetPosBasic)
|
||||||
{
|
{
|
||||||
|
@ -81,6 +81,11 @@ void ModChannel::Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELI
|
||||||
dwFlags = sndFile.ChnSettings[sourceChannel].dwFlags;
|
dwFlags = sndFile.ChnSettings[sourceChannel].dwFlags;
|
||||||
nPan = sndFile.ChnSettings[sourceChannel].nPan;
|
nPan = sndFile.ChnSettings[sourceChannel].nPan;
|
||||||
nGlobalVol = sndFile.ChnSettings[sourceChannel].nVolume;
|
nGlobalVol = sndFile.ChnSettings[sourceChannel].nVolume;
|
||||||
|
if(dwFlags[CHN_MUTE])
|
||||||
|
{
|
||||||
|
dwFlags.reset(CHN_MUTE);
|
||||||
|
dwFlags.set(muteFlag);
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
dwFlags.reset();
|
dwFlags.reset();
|
||||||
|
|
|
@ -174,7 +174,7 @@ struct ModChannel
|
||||||
resetTotal = resetSetPosFull,
|
resetTotal = resetSetPosFull,
|
||||||
};
|
};
|
||||||
|
|
||||||
void Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELINDEX sourceChannel);
|
void Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELINDEX sourceChannel, ChannelFlags muteFlag);
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
bool IsSamplePlaying() const noexcept { return !increment.IsZero(); }
|
bool IsSamplePlaying() const noexcept { return !increment.IsZero(); }
|
||||||
|
|
|
@ -457,22 +457,21 @@ void ModSample::TransposeToFrequency()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Return tranpose.finetune as 25.7 fixed point value.
|
// Return a pair of {tranpose, finetune}
|
||||||
int32 ModSample::FrequencyToTranspose(uint32 freq)
|
std::pair<int8, int8> ModSample::FrequencyToTranspose(uint32 freq)
|
||||||
{
|
{
|
||||||
if(!freq)
|
if(!freq)
|
||||||
return 0;
|
return {};
|
||||||
else
|
|
||||||
return mpt::saturate_round<int32>(std::log(freq * (1.0 / 8363.0)) * (12.0 * 128.0 * (1.0 / M_LN2)));
|
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()
|
void ModSample::FrequencyToTranspose()
|
||||||
{
|
{
|
||||||
const int f2t = Clamp(FrequencyToTranspose(nC5Speed), -16384, 16383);
|
std::tie(RelativeTone, nFineTune) = FrequencyToTranspose(nC5Speed);
|
||||||
const auto fine = std::div(f2t, 128);
|
|
||||||
RelativeTone = static_cast<int8>(fine.quot);
|
|
||||||
nFineTune = static_cast<int8>(fine.rem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,7 @@ struct ModSample
|
||||||
// Transpose <-> Frequency conversions
|
// Transpose <-> Frequency conversions
|
||||||
static uint32 TransposeToFrequency(int transpose, int finetune = 0);
|
static uint32 TransposeToFrequency(int transpose, int finetune = 0);
|
||||||
void TransposeToFrequency();
|
void TransposeToFrequency();
|
||||||
static int32 FrequencyToTranspose(uint32 freq);
|
static std::pair<int8, int8> FrequencyToTranspose(uint32 freq);
|
||||||
void FrequencyToTranspose();
|
void FrequencyToTranspose();
|
||||||
|
|
||||||
// Transpose the sample by amount specified in octaves (i.e. amount=1 transposes one octave up)
|
// 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 masterVolume; // Sample Volume (0...127, stereo if high bit is set)
|
||||||
uint8le ultraClicks; // Number of channels used for ultra click removal
|
uint8le ultraClicks; // Number of channels used for ultra click removal
|
||||||
uint8le usePanningTable; // 0xFC => read extended panning table
|
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
|
uint32le reserved3; // Impulse Tracker hides its edit timer here
|
||||||
uint16le reserved4;
|
uint16le reserved4;
|
||||||
uint16le special; // Pointer to special custom data (unused)
|
uint16le special; // Pointer to special custom data (unused)
|
||||||
|
|
|
@ -249,7 +249,7 @@ std::vector<FileType> CSoundFile::GetMediaFoundationFileTypes()
|
||||||
|
|
||||||
std::wstring guid = std::wstring(valueNameBuf);
|
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_("Byte Stream Handler"), U_("Files"));
|
||||||
description = mpt::String::Replace(description, U_("ByteStreamHandler"), U_("Files"));
|
description = mpt::String::Replace(description, U_("ByteStreamHandler"), U_("Files"));
|
||||||
|
|
||||||
|
|
|
@ -268,7 +268,7 @@ enum SongFlags
|
||||||
};
|
};
|
||||||
DECLARE_FLAGSET(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)
|
#define SONG_PLAY_FLAGS (~SONG_FILE_FLAGS)
|
||||||
|
|
||||||
// Global Options (Renderer)
|
// Global Options (Renderer)
|
||||||
|
|
|
@ -93,9 +93,10 @@ public:
|
||||||
state->m_nMusicTempo = sndFile.m_nDefaultTempo;
|
state->m_nMusicTempo = sndFile.m_nDefaultTempo;
|
||||||
state->m_nGlobalVolume = sndFile.m_nDefaultGlobalVolume;
|
state->m_nGlobalVolume = sndFile.m_nDefaultGlobalVolume;
|
||||||
chnSettings.assign(sndFile.GetNumChannels(), ChnSettings());
|
chnSettings.assign(sndFile.GetNumChannels(), ChnSettings());
|
||||||
|
const auto muteFlag = CSoundFile::GetChannelMuteFlag();
|
||||||
for(CHANNELINDEX chn = 0; chn < sndFile.GetNumChannels(); chn++)
|
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].nOldGlobalVolSlide = 0;
|
||||||
state->Chn[chn].nOldChnVolSlide = 0;
|
state->Chn[chn].nOldChnVolSlide = 0;
|
||||||
state->Chn[chn].nNote = state->Chn[chn].nNewNote = state->Chn[chn].nLastNote = NOTE_NONE;
|
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)
|
if(chn.rowCommand.vol)
|
||||||
{
|
{
|
||||||
const auto [porta, clearEffectCommand] = GetVolCmdTonePorta(chn.rowCommand, 0);
|
const auto [porta, clearEffectCommand] = GetVolCmdTonePorta(chn.rowCommand, 0);
|
||||||
chn.nPortamentoSlide = porta * 4;
|
chn.nPortamentoSlide = porta;
|
||||||
if(clearEffectCommand)
|
if(clearEffectCommand)
|
||||||
command = CMD_NONE;
|
command = CMD_NONE;
|
||||||
}
|
}
|
||||||
|
@ -791,7 +792,7 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
|
||||||
break;
|
break;
|
||||||
// Tone-Portamento
|
// Tone-Portamento
|
||||||
case CMD_TONEPORTAMENTO:
|
case CMD_TONEPORTAMENTO:
|
||||||
if (param) chn.nPortamentoSlide = param << 2;
|
if (param) chn.nPortamentoSlide = param;
|
||||||
break;
|
break;
|
||||||
// Offset
|
// Offset
|
||||||
case CMD_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))
|
if(!srcChn.nLength || srcChn.dwFlags[CHN_MUTE] || !(srcChn.rightVol | srcChn.leftVol))
|
||||||
return CHANNELINDEX_INVALID;
|
return CHANNELINDEX_INVALID;
|
||||||
|
|
||||||
|
if(srcChn.dwFlags[CHN_ADLIB] && m_opl)
|
||||||
|
{
|
||||||
|
m_opl->NoteCut(nChn, false);
|
||||||
|
return CHANNELINDEX_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
const CHANNELINDEX nnaChn = GetNNAChannel(nChn);
|
const CHANNELINDEX nnaChn = GetNNAChannel(nChn);
|
||||||
if(nnaChn == CHANNELINDEX_INVALID)
|
if(nnaChn == CHANNELINDEX_INVALID)
|
||||||
return CHANNELINDEX_INVALID;
|
return CHANNELINDEX_INVALID;
|
||||||
|
@ -2211,10 +2218,6 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo
|
||||||
srcChn.position.Set(0);
|
srcChn.position.Set(0);
|
||||||
srcChn.nROfs = srcChn.nLOfs = 0;
|
srcChn.nROfs = srcChn.nLOfs = 0;
|
||||||
srcChn.rightVol = srcChn.leftVol = 0;
|
srcChn.rightVol = srcChn.leftVol = 0;
|
||||||
if(srcChn.dwFlags[CHN_ADLIB] && m_opl)
|
|
||||||
{
|
|
||||||
m_opl->NoteCut(nChn);
|
|
||||||
}
|
|
||||||
return nnaChn;
|
return nnaChn;
|
||||||
}
|
}
|
||||||
if(instr > GetNumInstruments())
|
if(instr > GetNumInstruments())
|
||||||
|
@ -4193,18 +4196,17 @@ void CSoundFile::TonePortamento(ModChannel &chn, uint32 param) const
|
||||||
chn.nOldPortaUp = chn.nOldPortaDown = static_cast<uint8>(param);
|
chn.nOldPortaUp = chn.nOldPortaDown = static_cast<uint8>(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(param)
|
||||||
|
chn.nPortamentoSlide = param;
|
||||||
|
|
||||||
if(chn.HasCustomTuning())
|
if(chn.HasCustomTuning())
|
||||||
{
|
{
|
||||||
//Behavior: Param tells number of finesteps(or 'fullsteps'(notes) with glissando)
|
//Behavior: Param tells number of finesteps(or 'fullsteps'(notes) with glissando)
|
||||||
//to slide per row(not per tick).
|
//to slide per row(not per tick).
|
||||||
const int32 oldPortamentoTickSlide = (m_PlayState.m_nTickCount != 0) ? chn.m_PortamentoTickSlide : 0;
|
const int32 oldPortamentoTickSlide = (m_PlayState.m_nTickCount != 0) ? chn.m_PortamentoTickSlide : 0;
|
||||||
|
|
||||||
if(param)
|
if(chn.nPortamentoSlide == 0)
|
||||||
chn.nPortamentoSlide = param;
|
return;
|
||||||
else
|
|
||||||
if(chn.nPortamentoSlide == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
|
||||||
if((chn.nPortamentoDest > 0 && chn.nPortamentoSlide < 0) ||
|
if((chn.nPortamentoDest > 0 && chn.nPortamentoSlide < 0) ||
|
||||||
(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))
|
|| (GetType() & (MOD_TYPE_DBM | MOD_TYPE_669))
|
||||||
|| (m_PlayState.m_nMusicSpeed == 1 && m_playBehaviour[kSlidesAtSpeed1])
|
|| (m_PlayState.m_nMusicSpeed == 1 && m_playBehaviour[kSlidesAtSpeed1])
|
||||||
|| (GetType() == MOD_TYPE_MED && m_SongFlags[SONG_FASTVOLSLIDES]);
|
|| (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;
|
doPorta = chn.isFirstTick;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(param)
|
if(GetType() == MOD_TYPE_669)
|
||||||
{
|
{
|
||||||
if(GetType() == MOD_TYPE_669)
|
delta *= 10;
|
||||||
{
|
|
||||||
param *= 10;
|
|
||||||
}
|
|
||||||
chn.nPortamentoSlide = param * 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(chn.nPeriod && chn.nPortamentoDest && doPorta)
|
if(chn.nPeriod && chn.nPortamentoDest && doPorta)
|
||||||
{
|
{
|
||||||
if (chn.nPeriod < chn.nPortamentoDest)
|
if (chn.nPeriod < chn.nPortamentoDest)
|
||||||
{
|
{
|
||||||
int32 delta = chn.nPortamentoSlide;
|
|
||||||
if(m_SongFlags[SONG_LINEARSLIDES] && GetType() != MOD_TYPE_XM)
|
if(m_SongFlags[SONG_LINEARSLIDES] && GetType() != MOD_TYPE_XM)
|
||||||
{
|
{
|
||||||
uint32 n = chn.nPortamentoSlide / 4;
|
uint32 n = delta;
|
||||||
if (n > 255) n = 255;
|
if (n > 255) n = 255;
|
||||||
// Return (a*b+c/2)/c - no divide error
|
// Return (a*b+c/2)/c - no divide error
|
||||||
// Table is 65536*2(n/192)
|
// Table is 65536*2(n/192)
|
||||||
delta = Util::muldivr(chn.nPeriod, LinearSlideUpTable[n], 65536) - chn.nPeriod;
|
delta = Util::muldivr(chn.nPeriod, LinearSlideUpTable[n], 65536) - chn.nPeriod;
|
||||||
if (delta < 1) delta = 1;
|
if (delta < 1) delta = 1;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
delta *= 4;
|
||||||
}
|
}
|
||||||
chn.nPeriod += delta;
|
chn.nPeriod += delta;
|
||||||
if (chn.nPeriod > chn.nPortamentoDest) chn.nPeriod = chn.nPortamentoDest;
|
if (chn.nPeriod > chn.nPortamentoDest) chn.nPeriod = chn.nPortamentoDest;
|
||||||
} else
|
} else
|
||||||
if (chn.nPeriod > chn.nPortamentoDest)
|
if (chn.nPeriod > chn.nPortamentoDest)
|
||||||
{
|
{
|
||||||
int32 delta = -chn.nPortamentoSlide;
|
|
||||||
if(m_SongFlags[SONG_LINEARSLIDES] && GetType() != MOD_TYPE_XM)
|
if(m_SongFlags[SONG_LINEARSLIDES] && GetType() != MOD_TYPE_XM)
|
||||||
{
|
{
|
||||||
uint32 n = chn.nPortamentoSlide / 4;
|
uint32 n = delta;
|
||||||
if (n > 255) n = 255;
|
if (n > 255) n = 255;
|
||||||
delta = Util::muldivr(chn.nPeriod, LinearSlideDownTable[n], 65536) - chn.nPeriod;
|
delta = Util::muldivr(chn.nPeriod, LinearSlideDownTable[n], 65536) - chn.nPeriod;
|
||||||
if (delta > -1) delta = -1;
|
if (delta > -1) delta = -1;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
delta *= -4;
|
||||||
}
|
}
|
||||||
chn.nPeriod += delta;
|
chn.nPeriod += delta;
|
||||||
if (chn.nPeriod < chn.nPortamentoDest) chn.nPeriod = chn.nPortamentoDest;
|
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))
|
if(retrigCount && !(retrigCount % retrigSpeed))
|
||||||
doRetrig = true;
|
doRetrig = true;
|
||||||
retrigCount++;
|
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)
|
} else if(GetType() == MOD_TYPE_MTM)
|
||||||
{
|
{
|
||||||
// In MultiTracker, E9x retriggers the last note at exactly the x-th tick of the row
|
// 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;
|
uint32 note = chn.nNewNote;
|
||||||
int32 oldPeriod = chn.nPeriod;
|
int32 oldPeriod = chn.nPeriod;
|
||||||
const bool retrigAdlib = chn.dwFlags[CHN_ADLIB] && m_playBehaviour[kOPLRealRetrig];
|
// ST3 doesn't retrigger OPL notes
|
||||||
if(note >= NOTE_MIN && note <= NOTE_MAX && chn.nLength && retrigAdlib)
|
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);
|
CheckNNA(nChn, 0, note, true);
|
||||||
bool resetEnv = false;
|
bool resetEnv = false;
|
||||||
if(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))
|
if(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))
|
||||||
|
@ -5638,11 +5651,6 @@ void CSoundFile::RetrigNote(CHANNELINDEX nChn, int param, int offset)
|
||||||
if(param < 0x100)
|
if(param < 0x100)
|
||||||
resetEnv = true;
|
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 bool fading = chn.dwFlags[CHN_NOTEFADE];
|
||||||
const auto oldPrevNoteOffset = chn.prevNoteOffset;
|
const auto oldPrevNoteOffset = chn.prevNoteOffset;
|
||||||
|
|
|
@ -478,11 +478,13 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adjust channels
|
// 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));
|
LimitMax(ChnSettings[chn].nVolume, uint16(64));
|
||||||
if (ChnSettings[ich].nPan > 256) ChnSettings[ich].nPan = 128;
|
if(ChnSettings[chn].nPan > 256)
|
||||||
m_PlayState.Chn[ich].Reset(ModChannel::resetTotal, *this, ich);
|
ChnSettings[chn].nPan = 128;
|
||||||
|
m_PlayState.Chn[chn].Reset(ModChannel::resetTotal, *this, chn, muteFlag);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checking samples, load external samples
|
// Checking samples, load external samples
|
||||||
|
@ -770,8 +772,9 @@ double CSoundFile::GetCurrentBPM() const
|
||||||
|
|
||||||
void CSoundFile::ResetPlayPos()
|
void CSoundFile::ResetPlayPos()
|
||||||
{
|
{
|
||||||
|
const auto muteFlag = GetChannelMuteFlag();
|
||||||
for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++)
|
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);
|
visitedSongRows.Initialize(true);
|
||||||
m_SongFlags.reset(SONG_FADINGSONG | SONG_ENDREACHED);
|
m_SongFlags.reset(SONG_FADINGSONG | SONG_ENDREACHED);
|
||||||
|
@ -1055,7 +1058,6 @@ PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type)
|
||||||
{
|
{
|
||||||
playBehaviour.set(kOPLFlexibleNoteOff);
|
playBehaviour.set(kOPLFlexibleNoteOff);
|
||||||
playBehaviour.set(kOPLwithNNA);
|
playBehaviour.set(kOPLwithNNA);
|
||||||
playBehaviour.set(kOPLRealRetrig);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1176,7 +1178,6 @@ PlayBehaviourSet CSoundFile::GetDefaultPlaybackBehaviour(MODTYPE type)
|
||||||
playBehaviour.set(kITDoNotOverrideChannelPan);
|
playBehaviour.set(kITDoNotOverrideChannelPan);
|
||||||
playBehaviour.set(kITDCTBehaviour);
|
playBehaviour.set(kITDCTBehaviour);
|
||||||
playBehaviour.set(kOPLwithNNA);
|
playBehaviour.set(kOPLwithNNA);
|
||||||
playBehaviour.set(kOPLRealRetrig);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MOD_TYPE_S3M:
|
case MOD_TYPE_S3M:
|
||||||
|
@ -1293,10 +1294,11 @@ const char *CSoundFile::GetInstrumentName(INSTRUMENTINDEX nInstr) const
|
||||||
|
|
||||||
bool CSoundFile::InitChannel(CHANNELINDEX nChn)
|
bool CSoundFile::InitChannel(CHANNELINDEX nChn)
|
||||||
{
|
{
|
||||||
if(nChn >= MAX_BASECHANNELS) return true;
|
if(nChn >= MAX_BASECHANNELS)
|
||||||
|
return true;
|
||||||
|
|
||||||
ChnSettings[nChn].Reset();
|
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
|
#ifdef MODPLUG_TRACKER
|
||||||
if(GetpModDoc() != nullptr)
|
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.
|
// 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_INVLAID is returned if no free sample slot could be found.
|
||||||
SAMPLEINDEX CSoundFile::GetNextFreeSample(INSTRUMENTINDEX targetInstrument, SAMPLEINDEX start) const
|
SAMPLEINDEX CSoundFile::GetNextFreeSample(INSTRUMENTINDEX targetInstrument, SAMPLEINDEX start) const
|
||||||
|
|
|
@ -462,16 +462,17 @@ public:
|
||||||
ResamplingMode m_nResampling; // Resampling mode (if overriding the globally set resampling)
|
ResamplingMode m_nResampling; // Resampling mode (if overriding the globally set resampling)
|
||||||
int32 m_nRepeatCount = 0; // -1 means repeat infinitely.
|
int32 m_nRepeatCount = 0; // -1 means repeat infinitely.
|
||||||
ORDERINDEX m_nMaxOrderPosition;
|
ORDERINDEX m_nMaxOrderPosition;
|
||||||
ModChannelSettings ChnSettings[MAX_BASECHANNELS]; // Initial channels settings
|
ModChannelSettings ChnSettings[MAX_BASECHANNELS]; // Initial channels settings
|
||||||
CPatternContainer Patterns;
|
CPatternContainer Patterns;
|
||||||
ModSequenceSet Order; // Pattern sequences (order lists)
|
ModSequenceSet Order; // Pattern sequences (order lists)
|
||||||
protected:
|
protected:
|
||||||
ModSample Samples[MAX_SAMPLES]; // Sample Headers
|
ModSample Samples[MAX_SAMPLES];
|
||||||
public:
|
public:
|
||||||
ModInstrument *Instruments[MAX_INSTRUMENTS]; // Instrument Headers
|
ModInstrument *Instruments[MAX_INSTRUMENTS]; // Instrument Headers
|
||||||
MIDIMacroConfig m_MidiCfg; // MIDI Macro config table
|
MIDIMacroConfig m_MidiCfg; // MIDI Macro config table
|
||||||
#ifndef NO_PLUGINS
|
#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
|
#endif
|
||||||
mpt::charbuf<MAX_SAMPLENAME> m_szNames[MAX_SAMPLES]; // Sample names
|
mpt::charbuf<MAX_SAMPLENAME> m_szNames[MAX_SAMPLES]; // Sample names
|
||||||
|
|
||||||
|
@ -720,6 +721,8 @@ public:
|
||||||
const CModSpecifications& GetModSpecifications() const {return *m_pModSpecs;}
|
const CModSpecifications& GetModSpecifications() const {return *m_pModSpecs;}
|
||||||
static const CModSpecifications& GetModSpecifications(const MODTYPE type);
|
static const CModSpecifications& GetModSpecifications(const MODTYPE type);
|
||||||
|
|
||||||
|
static ChannelFlags GetChannelMuteFlag();
|
||||||
|
|
||||||
#ifdef MODPLUG_TRACKER
|
#ifdef MODPLUG_TRACKER
|
||||||
void PatternTranstionChnSolo(const CHANNELINDEX chnIndex);
|
void PatternTranstionChnSolo(const CHANNELINDEX chnIndex);
|
||||||
void PatternTransitionChnUnmuteAll();
|
void PatternTransitionChnUnmuteAll();
|
||||||
|
|
|
@ -206,18 +206,6 @@ CSoundFile::samplecount_t CSoundFile::Read(samplecount_t count, IAudioReadTarget
|
||||||
{
|
{
|
||||||
MPT_ASSERT_ALWAYS(m_MixerSettings.IsValid());
|
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 countRendered = 0;
|
||||||
samplecount_t countToRender = count;
|
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);
|
m_opl->Mix(MixSoundBuffer, countChunk, m_OPLVolumeFactor * m_nVSTiVolume / 48);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NO_REVERB
|
#ifndef NO_REVERB
|
||||||
m_Reverb.Process(MixSoundBuffer, countChunk);
|
m_Reverb.Process(MixSoundBuffer, countChunk);
|
||||||
#endif // NO_REVERB
|
#endif // NO_REVERB
|
||||||
|
|
||||||
if(mixPlugins)
|
#ifndef NO_PLUGINS
|
||||||
|
if(m_loadedPlugins)
|
||||||
{
|
{
|
||||||
ProcessPlugins(countChunk);
|
ProcessPlugins(countChunk);
|
||||||
}
|
}
|
||||||
|
#endif // NO_PLUGINS
|
||||||
|
|
||||||
if(m_MixerSettings.gnChannels == 1)
|
if(m_MixerSettings.gnChannels == 1)
|
||||||
{
|
{
|
||||||
|
@ -653,8 +643,9 @@ bool CSoundFile::ProcessRow()
|
||||||
visitedSongRows.Initialize(true);
|
visitedSongRows.Initialize(true);
|
||||||
}
|
}
|
||||||
// When jumping to the next subsong, stop all playing notes from the previous song...
|
// 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++)
|
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();
|
StopAllVsti();
|
||||||
// ...and the global playback information.
|
// ...and the global playback information.
|
||||||
m_PlayState.m_nMusicSpeed = m_nDefaultSpeed;
|
m_PlayState.m_nMusicSpeed = m_nDefaultSpeed;
|
||||||
|
@ -2348,7 +2339,7 @@ bool CSoundFile::ReadNote()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Volume ramping
|
// 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;
|
constexpr uint8 VUMETER_DECAY = 4;
|
||||||
chn.nLeftVU = (chn.nLeftVU > VUMETER_DECAY) ? (chn.nLeftVU - VUMETER_DECAY) : 0;
|
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++)
|
for(SAMPLEINDEX i = 1; i <= GetNumSamples(); i++)
|
||||||
{
|
{
|
||||||
if(Samples[i].uFlags[CHN_ADLIB])
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -330,9 +330,7 @@ void XMSample::ConvertToXM(const ModSample &mptSmp, MODTYPE fromType, bool compa
|
||||||
relnote = mptSmp.RelativeTone;
|
relnote = mptSmp.RelativeTone;
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
int f2t = ModSample::FrequencyToTranspose(mptSmp.nC5Speed);
|
std::tie(relnote, finetune) = ModSample::FrequencyToTranspose(mptSmp.nC5Speed);
|
||||||
relnote = static_cast<int8>(f2t / 128);
|
|
||||||
finetune = static_cast<int8>(f2t & 0x7F);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
flags = 0;
|
flags = 0;
|
||||||
|
|
|
@ -44,6 +44,7 @@ IMixPlugin::IMixPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN
|
||||||
, m_SndFile(sndFile)
|
, m_SndFile(sndFile)
|
||||||
, m_pMixStruct(mixStruct)
|
, m_pMixStruct(mixStruct)
|
||||||
{
|
{
|
||||||
|
m_SndFile.m_loadedPlugins++;
|
||||||
m_MixState.pMixBuffer = (mixsample_t *)((((intptr_t)m_MixBuffer) + 7) & ~7);
|
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)
|
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;
|
if (m_pPrev) m_pPrev->m_pNext = m_pNext;
|
||||||
m_pPrev = nullptr;
|
m_pPrev = nullptr;
|
||||||
m_pNext = 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))
|
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(ParseMaybeNullTerminatedStringFromBufferWithSizeInBytes<mpt::winstring>(name, datasize)));
|
||||||
|
|
||||||
VSTPluginLib *plug = new (std::nothrow) VSTPluginLib(DMOPlugin::Create, true, mpt::PathString::FromNative(Util::GUIDToString(clsid)), mpt::PathString::FromNative(name));
|
|
||||||
if(plug != nullptr)
|
if(plug != nullptr)
|
||||||
{
|
{
|
||||||
try
|
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.m_SongFlags & SONG_FILE_FLAGS), SONG_FASTVOLSLIDES);
|
||||||
VERIFY_EQUAL_NONCONT(sndFile.GetMixLevels(), mixLevelsCompatible);
|
VERIFY_EQUAL_NONCONT(sndFile.GetMixLevels(), mixLevelsCompatible);
|
||||||
VERIFY_EQUAL_NONCONT(sndFile.m_nTempoMode, tempoModeClassic);
|
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);
|
VERIFY_EQUAL_NONCONT(sndFile.Order().GetRestartPos(), 0);
|
||||||
|
|
||||||
// Channels
|
// Channels
|
||||||
|
|
Loading…
Reference in New Issue