Update libopenmpt to version 0.5.6
parent
ba7aaec69c
commit
9a427cf03c
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2004-2020, OpenMPT contributors
|
||||
Copyright (c) 2004-2021, OpenMPT contributors
|
||||
Copyright (c) 1997-2003, Olivier Lapicque
|
||||
All rights reserved.
|
||||
|
||||
|
|
|
@ -170,36 +170,24 @@ For detailed requirements, see `libopenmpt/dox/quickstart.md`.
|
|||
|
||||
- emscripten (on Unix-like systems):
|
||||
|
||||
libopenmpt has been tested and verified to work with emscripten 1.38.5
|
||||
or later. Earlier versions are not supported.
|
||||
|
||||
Run:
|
||||
|
||||
# generates WebAssembly with dynamic heap growth
|
||||
# generates WebAssembly with JavaScript fallback
|
||||
make CONFIG=emscripten EMSCRIPTEN_TARGET=all
|
||||
|
||||
or
|
||||
|
||||
# generates WebAssembly
|
||||
make CONFIG=emscripten EMSCRIPTEN_TARGET=wasm
|
||||
|
||||
or
|
||||
|
||||
# generates asm.js with a fixed size 128MB heap
|
||||
make CONFIG=emscripten EMSCRIPTEN_TARGET=asmjs128m
|
||||
|
||||
or
|
||||
|
||||
# generates asm.js with a fixed default size heap (as of Emscripten
|
||||
# 1.38.11, this amounts to 16MB)
|
||||
make CONFIG=emscripten EMSCRIPTEN_TARGET=asmjs
|
||||
|
||||
or
|
||||
|
||||
# generates JavaScript with dynamic heap growth and with
|
||||
# compatibility for older VMs
|
||||
# generates JavaScript with compatibility for older VMs
|
||||
make CONFIG=emscripten EMSCRIPTEN_TARGET=js
|
||||
|
||||
Running the test suite on the command line is also supported by using
|
||||
node.js. Version 8.9.1 or greater has been tested. Earlier versions
|
||||
might or might not work. Depending on how your distribution calls the
|
||||
`node.js` binary, you might have to edit
|
||||
`build/make/config-emscripten.mk`.
|
||||
node.js. Depending on how your distribution calls the `node.js` binary,
|
||||
you might have to edit `build/make/config-emscripten.mk`.
|
||||
|
||||
- DJGPP / DOS
|
||||
|
||||
|
@ -229,7 +217,7 @@ For detailed requirements, see `libopenmpt/dox/quickstart.md`.
|
|||
|
||||
- other compilers:
|
||||
|
||||
To compile libopenmpt with other C++14 compliant compilers, run:
|
||||
To compile libopenmpt with other C++17 compliant compilers, run:
|
||||
|
||||
make CONFIG=generic
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
MPT_SVNVERSION=13932
|
||||
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.4
|
||||
MPT_SVNDATE=2020-11-29T15:01:39.790705Z
|
||||
MPT_SVNVERSION=14311
|
||||
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.6
|
||||
MPT_SVNDATE=2021-03-14T15:27:41.476009Z
|
||||
|
|
|
@ -48,6 +48,15 @@ LDFLAGS += -s WASM=2 -s LEGACY_VM_SUPPORT=1
|
|||
|
||||
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
|
||||
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
|
||||
|
||||
else ifeq ($(EMSCRIPTEN_TARGET),wasm)
|
||||
# emits native wasm.
|
||||
CPPFLAGS += -DMPT_BUILD_WASM
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
#pragma once
|
||||
#define OPENMPT_VERSION_SVNVERSION "13932"
|
||||
#define OPENMPT_VERSION_REVISION 13932
|
||||
#define OPENMPT_VERSION_SVNVERSION "14311"
|
||||
#define OPENMPT_VERSION_REVISION 14311
|
||||
#define OPENMPT_VERSION_DIRTY 0
|
||||
#define OPENMPT_VERSION_MIXEDREVISIONS 0
|
||||
#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.4"
|
||||
#define OPENMPT_VERSION_DATE "2020-11-29T15:01:39.790705Z"
|
||||
#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.6"
|
||||
#define OPENMPT_VERSION_DATE "2021-03-14T15:27:41.476009Z"
|
||||
#define OPENMPT_VERSION_IS_PACKAGE 1
|
||||
|
||||
|
|
|
@ -309,6 +309,12 @@
|
|||
#endif
|
||||
|
||||
|
||||
#if MPT_OS_EMSCRIPTEN && defined(MPT_BUILD_AUDIOWORKLETPROCESSOR)
|
||||
#define MPT_COMPILER_QUIRK_CHRONO_NO_HIGH_RESOLUTION_CLOCK
|
||||
#define MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE
|
||||
#endif
|
||||
|
||||
|
||||
#if MPT_OS_DJGPP
|
||||
#define MPT_COMPILER_QUIRK_NO_WCHAR
|
||||
#endif
|
||||
|
|
|
@ -27,6 +27,8 @@ namespace mpt
|
|||
{
|
||||
|
||||
|
||||
#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE)
|
||||
|
||||
template <typename T>
|
||||
static T log2(T x)
|
||||
{
|
||||
|
@ -58,6 +60,8 @@ static MPT_CONSTEXPR14_FUN bool is_mask(T x)
|
|||
return false;
|
||||
}
|
||||
|
||||
#endif // !MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE
|
||||
|
||||
|
||||
namespace {
|
||||
template <typename T> struct default_hash { };
|
||||
|
@ -91,6 +95,7 @@ static T generate_timeseed()
|
|||
hash(std::begin(bytes), std::end(bytes));
|
||||
}
|
||||
|
||||
#if !defined(MPT_COMPILER_QUIRK_CHRONO_NO_HIGH_RESOLUTION_CLOCK)
|
||||
{
|
||||
uint64be time;
|
||||
time = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock().now().time_since_epoch()).count();
|
||||
|
@ -98,6 +103,7 @@ static T generate_timeseed()
|
|||
std::memcpy(bytes, &time, sizeof(time));
|
||||
hash(std::begin(bytes), std::end(bytes));
|
||||
}
|
||||
#endif // !MPT_COMPILER_QUIRK_CHRONO_NO_HIGH_RESOLUTION_CLOCK
|
||||
|
||||
return static_cast<T>(hash.result());
|
||||
|
||||
|
@ -126,8 +132,11 @@ crand::result_type crand::operator()()
|
|||
#endif // MODPLUG_TRACKER
|
||||
|
||||
sane_random_device::sane_random_device()
|
||||
#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE)
|
||||
: rd_reliable(false)
|
||||
#endif // MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE
|
||||
{
|
||||
#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE)
|
||||
try
|
||||
{
|
||||
prd = std::make_unique<std::random_device>();
|
||||
|
@ -140,6 +149,7 @@ sane_random_device::sane_random_device()
|
|||
rd_reliable = false;
|
||||
}
|
||||
if(!rd_reliable)
|
||||
#endif // MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE
|
||||
{
|
||||
init_fallback();
|
||||
}
|
||||
|
@ -147,8 +157,11 @@ sane_random_device::sane_random_device()
|
|||
|
||||
sane_random_device::sane_random_device(const std::string & token_)
|
||||
: token(token_)
|
||||
#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE)
|
||||
, rd_reliable(false)
|
||||
#endif // MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE
|
||||
{
|
||||
#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE)
|
||||
try
|
||||
{
|
||||
prd = std::make_unique<std::random_device>(token);
|
||||
|
@ -161,6 +174,7 @@ sane_random_device::sane_random_device(const std::string & token_)
|
|||
rd_reliable = false;
|
||||
}
|
||||
if(!rd_reliable)
|
||||
#endif // MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE
|
||||
{
|
||||
init_fallback();
|
||||
}
|
||||
|
@ -198,6 +212,7 @@ sane_random_device::result_type sane_random_device::operator()()
|
|||
{
|
||||
mpt::lock_guard<mpt::mutex> l(m);
|
||||
result_type result = 0;
|
||||
#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE)
|
||||
if(prd)
|
||||
{
|
||||
try
|
||||
|
@ -244,6 +259,7 @@ sane_random_device::result_type sane_random_device::operator()()
|
|||
rd_reliable = false;
|
||||
}
|
||||
if(!rd_reliable)
|
||||
#endif // MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE
|
||||
{ // std::random_device is unreliable
|
||||
// XOR the generated random number with more entropy from the time-seeded
|
||||
// PRNG.
|
||||
|
|
|
@ -449,8 +449,10 @@ class sane_random_device
|
|||
private:
|
||||
mpt::mutex m;
|
||||
std::string token;
|
||||
#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE)
|
||||
std::unique_ptr<std::random_device> prd;
|
||||
bool rd_reliable;
|
||||
#endif // !MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE
|
||||
std::unique_ptr<std::mt19937> rd_fallback;
|
||||
public:
|
||||
typedef unsigned int result_type;
|
||||
|
|
|
@ -582,12 +582,12 @@ mpt::ustring GetFullCreditsString()
|
|||
"libopenmpt (based on OpenMPT / ModPlug Tracker)\n"
|
||||
#endif
|
||||
"\n"
|
||||
"Copyright \xC2\xA9 2004-2020 Contributors\n"
|
||||
"Copyright \xC2\xA9 2004-2021 Contributors\n"
|
||||
"Copyright \xC2\xA9 1997-2003 Olivier Lapicque\n"
|
||||
"\n"
|
||||
"Contributors:\n"
|
||||
"Johannes Schultz (2008-2020)\n"
|
||||
"J\xC3\xB6rn Heusipp (2012-2020)\n"
|
||||
"Johannes Schultz (2008-2021)\n"
|
||||
"J\xC3\xB6rn Heusipp (2012-2021)\n"
|
||||
"Ahti Lepp\xC3\xA4nen (2005-2011)\n"
|
||||
"Robin Fernandes (2004-2007)\n"
|
||||
"Sergiy Pylypenko (2007)\n"
|
||||
|
@ -777,7 +777,7 @@ mpt::ustring GetFullCreditsString()
|
|||
mpt::ustring GetLicenseString()
|
||||
{
|
||||
return MPT_UTF8(
|
||||
"Copyright (c) 2004-2020, OpenMPT contributors" "\n"
|
||||
"Copyright (c) 2004-2021, OpenMPT contributors" "\n"
|
||||
"Copyright (c) 1997-2003, Olivier Lapicque" "\n"
|
||||
"All rights reserved." "\n"
|
||||
"" "\n"
|
||||
|
|
|
@ -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 06
|
||||
#define VER_MINOR 08
|
||||
#define VER_MINORMINOR 00
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2004-2020, OpenMPT contributors
|
||||
Copyright (c) 2004-2021, OpenMPT contributors
|
||||
Copyright (c) 1997-2003, Olivier Lapicque
|
||||
All rights reserved.
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2004-2020, OpenMPT contributors
|
||||
Copyright (c) 2004-2021, OpenMPT contributors
|
||||
Copyright (c) 1997-2003, Olivier Lapicque
|
||||
All rights reserved.
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ Modifications:
|
|||
fails to compile.
|
||||
* Macro redefinition of alloca with mingw-w64 has been fixed.
|
||||
* Macro redefinition of STB_VORBIS_NO_STDIO has been fixed.
|
||||
* Bugfix https://github.com/nothings/stb/pull/1064 has been applied.
|
||||
Modifications are always additions and have been marked with // OpenMPT.
|
||||
|
||||
For building, premake is used to generate Visual Studio project files.
|
||||
|
|
|
@ -3652,7 +3652,12 @@ static int start_decoder(vorb *f)
|
|||
//user comments
|
||||
f->comment_list_length = get32_packet(f);
|
||||
f->comment_list = (char**)setup_malloc(f, sizeof(char*) * (f->comment_list_length));
|
||||
#if 0 // OpenMPT
|
||||
if (f->comment_list == NULL) return error(f, VORBIS_outofmem);
|
||||
#else // OpenMPT
|
||||
// Bugfix from https://github.com/nothings/stb/pull/1064 // OpenMPT
|
||||
if (f->comment_list_length > 0 && f->comment_list == NULL) return error(f, VORBIS_outofmem); // OpenMPT
|
||||
#endif // OpenMPT
|
||||
|
||||
for(i=0; i < f->comment_list_length; ++i) {
|
||||
len = get32_packet(f);
|
||||
|
|
|
@ -981,7 +981,7 @@ Declare Function openmpt_module_read_interleaved_stereo(ByVal module As openmpt_
|
|||
\param module The module handle to work on.
|
||||
\param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
|
||||
\param count Number of audio frames to render per channel.
|
||||
\param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved suad surround output in the order (L,R,RL,RR).
|
||||
\param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR).
|
||||
\return The number of frames actually rendered.
|
||||
\retval 0 The end of song has been reached.
|
||||
\remarks The output buffers are only written to up to the returned number of elements.
|
||||
|
@ -1011,7 +1011,7 @@ Declare Function openmpt_module_read_interleaved_float_stereo(ByVal module As op
|
|||
\param module The module handle to work on.
|
||||
\param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
|
||||
\param count Number of audio frames to render per channel.
|
||||
\param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved suad surround output in the order (L,R,RL,RR).
|
||||
\param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR).
|
||||
\return The number of frames actually rendered.
|
||||
\retval 0 The end of song has been reached.
|
||||
\remarks The output buffers are only written to up to the returned number of elements.
|
||||
|
|
|
@ -5,6 +5,36 @@ Changelog {#changelog}
|
|||
For fully detailed change log, please see the source repository directly. This
|
||||
is just a high-level summary.
|
||||
|
||||
### libopenmpt 0.5.6 (2021-03-14)
|
||||
|
||||
* AMS: Avoid allocating excessive amount of memory for compressed song message
|
||||
in malformed files.
|
||||
* S3M: Some samples or OPL patches were imported with a too high sample rate
|
||||
if module was saved with Scream Tracker 3.
|
||||
|
||||
* vorbis: Update to v1.3.7 (2020-07-04).
|
||||
|
||||
### libopenmpt 0.5.5 (2021-01-31)
|
||||
|
||||
* [**New**] `Makefile` `CONFIG=emscripten` now supports
|
||||
`EMSCRIPTEN_TARGET=audioworkletprocessor` which builds an ES6 module in
|
||||
a single file with reduced dependencies suitable to be used in an
|
||||
AudioWorkletProcessor.
|
||||
|
||||
* [**Bug**] stb_vorbis: Fix decoding of Vorbis streams without comments which
|
||||
affected most Vorbis samples since stb_vorbis v1.20.
|
||||
|
||||
* `openmpt::ext::interactive::set_pitch_factor` wasn't applied to OPL voices.
|
||||
* OPL channel state (in particular current patch) is now updated when seeking.
|
||||
* The FT2 tremolo quirk is now also applied to MOD files. FT2 just copied the
|
||||
quirky code from ProTracker!
|
||||
* DMF: Preserve effects better in some situations where there is more than one
|
||||
effect in a pattern cell.
|
||||
* DMF: Improve import of finetune effect with parameters larger than +/-15.
|
||||
|
||||
* mpg123: Update to v1.26.4 (2020-12-24).
|
||||
* pugixml: Update to v1.11.4 (2020-12-22).
|
||||
|
||||
### libopenmpt 0.5.4 (2020-11-29)
|
||||
|
||||
* AMS: An upper bound for uncompressed sample size is now established to
|
||||
|
|
|
@ -210,7 +210,7 @@ static void config( HWND hwndParent ) {
|
|||
static void about( HWND hwndParent ) {
|
||||
std::ostringstream about;
|
||||
about << SHORT_TITLE << " version " << openmpt::string::get( "library_version" ) << " " << "(built " << openmpt::string::get( "build" ) << ")" << std::endl;
|
||||
about << " Copyright (c) 2013-2020 OpenMPT developers (https://lib.openmpt.org/)" << std::endl;
|
||||
about << " Copyright (c) 2013-2021 OpenMPT developers (https://lib.openmpt.org/)" << std::endl;
|
||||
about << " OpenMPT version " << openmpt::string::get( "core_version" ) << std::endl;
|
||||
about << std::endl;
|
||||
about << openmpt::string::get( "contact" ) << std::endl;
|
||||
|
|
|
@ -1071,7 +1071,7 @@ LIBOPENMPT_API size_t openmpt_module_read_interleaved_stereo( openmpt_module * m
|
|||
* \param mod The module handle to work on.
|
||||
* \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
|
||||
* \param count Number of audio frames to render per channel.
|
||||
* \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved suad surround output in the order (L,R,RL,RR).
|
||||
* \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR).
|
||||
* \return The number of frames actually rendered.
|
||||
* \retval 0 The end of song has been reached.
|
||||
* \remarks The output buffers are only written to up to the returned number of elements.
|
||||
|
@ -1099,7 +1099,7 @@ LIBOPENMPT_API size_t openmpt_module_read_interleaved_float_stereo( openmpt_modu
|
|||
* \param mod The module handle to work on.
|
||||
* \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
|
||||
* \param count Number of audio frames to render per channel.
|
||||
* \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved suad surround output in the order (L,R,RL,RR).
|
||||
* \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR).
|
||||
* \return The number of frames actually rendered.
|
||||
* \retval 0 The end of song has been reached.
|
||||
* \remarks The output buffers are only written to up to the returned number of elements.
|
||||
|
|
|
@ -750,7 +750,7 @@ public:
|
|||
/*!
|
||||
\param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
|
||||
\param count Number of audio frames to render per channel.
|
||||
\param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved suad surround output in the order (L,R,RL,RR).
|
||||
\param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR).
|
||||
\return The number of frames actually rendered.
|
||||
\retval 0 The end of song has been reached.
|
||||
\remarks The output buffers are only written to up to the returned number of elements.
|
||||
|
@ -776,7 +776,7 @@ public:
|
|||
/*!
|
||||
\param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
|
||||
\param count Number of audio frames to render per channel.
|
||||
\param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved suad surround output in the order (L,R,RL,RR).
|
||||
\param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR).
|
||||
\return The number of frames actually rendered.
|
||||
\retval 0 The end of song has been reached.
|
||||
\remarks The output buffers are only written to up to the returned number of elements.
|
||||
|
@ -1119,7 +1119,7 @@ public:
|
|||
\param value The value that should be set.
|
||||
\throws openmpt::exception Throws an exception derived from openmpt::exception in case the value is not sensible (e.g. negative tempo factor) or under the circumstances outlined in openmpt::module::get_ctls.
|
||||
\sa openmpt::module::get_ctls
|
||||
\deprecated Please use openmpt::module::ctl_set_bool(), openmpt::module::ctl_set_int(), openmpt::module::ctl_set_float(), or openmpt::module::ctl_set_string().
|
||||
\deprecated Please use openmpt::module::ctl_set_bool(), openmpt::module::ctl_set_int(), openmpt::module::ctl_set_floatingpoint(), or openmpt::module::ctl_set_string().
|
||||
*/
|
||||
LIBOPENMPT_ATTR_DEPRECATED void ctl_set( const std::string & ctl, const std::string & value );
|
||||
//! Set ctl boolean value
|
||||
|
|
|
@ -1734,12 +1734,12 @@ int openmpt_module_ext_get_interface( openmpt_module_ext * mod_ext, const char *
|
|||
openmpt::interface::check_pointer( interface );
|
||||
std::memset( interface, 0, interface_size );
|
||||
int result = 0;
|
||||
if ( !strcmp( interface_id, "" ) ) {
|
||||
if ( !std::strcmp( interface_id, "" ) ) {
|
||||
result = 0;
|
||||
|
||||
|
||||
|
||||
} else if ( !strcmp( interface_id, LIBOPENMPT_EXT_C_INTERFACE_PATTERN_VIS ) && ( interface_size == sizeof( openmpt_module_ext_interface_pattern_vis ) ) ) {
|
||||
} else if ( !std::strcmp( interface_id, LIBOPENMPT_EXT_C_INTERFACE_PATTERN_VIS ) && ( interface_size == sizeof( openmpt_module_ext_interface_pattern_vis ) ) ) {
|
||||
openmpt_module_ext_interface_pattern_vis * i = static_cast< openmpt_module_ext_interface_pattern_vis * >( interface );
|
||||
i->get_pattern_row_channel_volume_effect_type = &get_pattern_row_channel_volume_effect_type;
|
||||
i->get_pattern_row_channel_effect_type = &get_pattern_row_channel_effect_type;
|
||||
|
@ -1747,7 +1747,7 @@ int openmpt_module_ext_get_interface( openmpt_module_ext * mod_ext, const char *
|
|||
|
||||
|
||||
|
||||
} else if ( !strcmp( interface_id, LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE ) && ( interface_size == sizeof( openmpt_module_ext_interface_interactive ) ) ) {
|
||||
} else if ( !std::strcmp( interface_id, LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE ) && ( interface_size == sizeof( openmpt_module_ext_interface_interactive ) ) ) {
|
||||
openmpt_module_ext_interface_interactive * i = static_cast< openmpt_module_ext_interface_interactive * >( interface );
|
||||
i->set_current_speed = &set_current_speed;
|
||||
i->set_current_tempo = &set_current_tempo;
|
||||
|
|
|
@ -66,8 +66,8 @@ MPT_WARNING("Warning: libopenmpt built in non thread-safe mode because mutexes a
|
|||
MPT_WARNING("Warning: Building libopenmpt with MinGW-w64 without std::thread support is not recommended and is deprecated. Please use MinGW-w64 with posix threading model (as opposed to win32 threading model), or build with mingw-std-threads.")
|
||||
#endif // MINGW
|
||||
|
||||
#if MPT_CLANG_AT_LEAST(5,0,0) && defined(__powerpc__) && !defined(__powerpc64__)
|
||||
MPT_WARNING("Warning: libopenmpt is known to trigger bad code generation with Clang 5 or later on powerpc (32bit) when using -O3. See <https://bugs.llvm.org/show_bug.cgi?id=46683>.")
|
||||
#if MPT_CLANG_AT_LEAST(5,0,0) && MPT_CLANG_BEFORE(11,0,0) && defined(__powerpc__) && !defined(__powerpc64__)
|
||||
MPT_WARNING("Warning: libopenmpt is known to trigger bad code generation with Clang 5..10 on powerpc (32bit) when using -O3. See <https://bugs.llvm.org/show_bug.cgi?id=46683>.")
|
||||
#endif
|
||||
|
||||
#endif // !MPT_BUILD_SILENCE_LIBOPENMPT_CONFIGURATION_WARNINGS
|
||||
|
@ -1106,9 +1106,9 @@ double module_impl::set_position_seconds( double seconds ) {
|
|||
} else {
|
||||
subsong = &subsongs[m_current_subsong];
|
||||
}
|
||||
m_sndFile->SetCurrentOrder( static_cast<ORDERINDEX>( subsong->start_order ) );
|
||||
GetLengthType t = m_sndFile->GetLength( m_ctl_seek_sync_samples ? eAdjustSamplePositions : eAdjust, GetLengthTarget( seconds ).StartPos( static_cast<SEQUENCEINDEX>( subsong->sequence ), static_cast<ORDERINDEX>( subsong->start_order ), static_cast<ROWINDEX>( subsong->start_row ) ) ).back();
|
||||
m_sndFile->m_PlayState.m_nCurrentOrder = t.lastOrder;
|
||||
m_sndFile->SetCurrentOrder( t.lastOrder );
|
||||
m_sndFile->m_PlayState.m_nNextOrder = m_sndFile->m_PlayState.m_nCurrentOrder = t.lastOrder;
|
||||
m_sndFile->m_PlayState.m_nNextRow = t.lastRow;
|
||||
m_currentPositionSeconds = base_seconds + t.duration;
|
||||
return m_currentPositionSeconds;
|
||||
|
|
|
@ -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 4
|
||||
#define OPENMPT_API_VERSION_PATCH 6
|
||||
/*! \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=4
|
||||
LIBOPENMPT_VERSION_PATCH=6
|
||||
LIBOPENMPT_VERSION_PREREL=
|
||||
|
||||
LIBOPENMPT_LTVER_CURRENT=2
|
||||
LIBOPENMPT_LTVER_REVISION=4
|
||||
LIBOPENMPT_LTVER_REVISION=6
|
||||
LIBOPENMPT_LTVER_AGE=2
|
||||
|
|
|
@ -465,7 +465,7 @@ static void clear_current_timeinfo() {
|
|||
static void WINAPI openmpt_About( HWND win ) {
|
||||
std::ostringstream about;
|
||||
about << SHORT_TITLE << " version " << openmpt::string::get( "library_version" ) << " " << "(built " << openmpt::string::get( "build" ) << ")" << std::endl;
|
||||
about << " Copyright (c) 2013-2020 OpenMPT developers (https://lib.openmpt.org/)" << std::endl;
|
||||
about << " Copyright (c) 2013-2021 OpenMPT developers (https://lib.openmpt.org/)" << std::endl;
|
||||
about << " OpenMPT version " << openmpt::string::get( "core_version" ) << std::endl;
|
||||
about << std::endl;
|
||||
about << openmpt::string::get( "contact" ) << std::endl;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*/
|
||||
|
||||
static const char * const license =
|
||||
"Copyright (c) 2004-2020, OpenMPT contributors" "\n"
|
||||
"Copyright (c) 2004-2021, OpenMPT contributors" "\n"
|
||||
"Copyright (c) 1997-2003, Olivier Lapicque" "\n"
|
||||
"All rights reserved." "\n"
|
||||
"" "\n"
|
||||
|
@ -74,6 +74,7 @@ static const char * const license =
|
|||
#include <conio.h>
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <windows.h>
|
||||
|
@ -459,7 +460,7 @@ static std::string seconds_to_string( double time ) {
|
|||
|
||||
static void show_info( std::ostream & log, bool verbose ) {
|
||||
log << "openmpt123" << " v" << OPENMPT123_VERSION_STRING << ", libopenmpt " << openmpt::string::get( "library_version" ) << " (" << "OpenMPT " << openmpt::string::get( "core_version" ) << ")" << std::endl;
|
||||
log << "Copyright (c) 2013-2020 OpenMPT developers <https://lib.openmpt.org/>" << std::endl;
|
||||
log << "Copyright (c) 2013-2021 OpenMPT developers <https://lib.openmpt.org/>" << std::endl;
|
||||
if ( !verbose ) {
|
||||
log << std::endl;
|
||||
return;
|
||||
|
@ -536,7 +537,7 @@ static void show_info( std::ostream & log, bool verbose ) {
|
|||
static void show_man_version( textout & log ) {
|
||||
log << "openmpt123" << " v" << OPENMPT123_VERSION_STRING << std::endl;
|
||||
log << std::endl;
|
||||
log << "Copyright (c) 2013-2020 OpenMPT developers <https://lib.openmpt.org/>" << std::endl;
|
||||
log << "Copyright (c) 2013-2021 OpenMPT developers <https://lib.openmpt.org/>" << std::endl;
|
||||
}
|
||||
|
||||
static void show_short_version( textout & log ) {
|
||||
|
@ -2288,8 +2289,13 @@ static int main( int argc, char * argv [] ) {
|
|||
#endif
|
||||
textout_dummy dummy_log;
|
||||
#if defined(WIN32)
|
||||
#if defined(UNICODE)
|
||||
textout_ostream_console std_out( std::wcout, STD_OUTPUT_HANDLE );
|
||||
textout_ostream_console std_err( std::wclog, STD_ERROR_HANDLE );
|
||||
#else
|
||||
textout_ostream_console std_out( std::cout, STD_OUTPUT_HANDLE );
|
||||
textout_ostream_console std_err( std::clog, STD_ERROR_HANDLE );
|
||||
#endif
|
||||
#else
|
||||
textout_ostream std_out( std::cout );
|
||||
textout_ostream std_err( std::clog );
|
||||
|
|
|
@ -890,11 +890,19 @@ public:
|
|||
|
||||
class textout_ostream_console : public textout {
|
||||
private:
|
||||
#if defined(UNICODE)
|
||||
std::wostream & s;
|
||||
#else
|
||||
std::ostream & s;
|
||||
#endif
|
||||
HANDLE handle;
|
||||
bool console;
|
||||
public:
|
||||
#if defined(UNICODE)
|
||||
textout_ostream_console( std::wostream & s_, DWORD stdHandle_ )
|
||||
#else
|
||||
textout_ostream_console( std::ostream & s_, DWORD stdHandle_ )
|
||||
#endif
|
||||
: s(s_)
|
||||
, handle(GetStdHandle( stdHandle_ ))
|
||||
, console(IsConsole( stdHandle_ ))
|
||||
|
|
|
@ -1698,6 +1698,7 @@ bool CDLSBank::ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nI
|
|||
if (usUnityNote > 0x7F) usUnityNote = 60;
|
||||
int steps = (60 + transpose - usUnityNote) * 128 + sFineTune;
|
||||
sample.Transpose(steps * (1.0 / (12.0 * 128.0)));
|
||||
sample.RelativeTone = 0;
|
||||
|
||||
Limit(lVolume, 16, 256);
|
||||
sample.nGlobalVol = (uint8)(lVolume / 4); // 0-64
|
||||
|
|
|
@ -903,12 +903,9 @@ bool CSoundFile::ReadAMS2(FileReader &file, ModLoadingFlags loadFlags)
|
|||
// Text
|
||||
|
||||
// Read composer name
|
||||
uint8 composerLength = file.ReadUint8();
|
||||
if(composerLength)
|
||||
if(std::string composer; file.ReadSizedString<uint8le, mpt::String::spacePadded>(composer))
|
||||
{
|
||||
std::string str;
|
||||
file.ReadString<mpt::String::spacePadded>(str, composerLength);
|
||||
m_songArtist = mpt::ToUnicode(mpt::Charset::CP437AMS2, str);
|
||||
m_songArtist = mpt::ToUnicode(mpt::Charset::CP437AMS2, composer);
|
||||
}
|
||||
|
||||
// Channel names
|
||||
|
@ -926,11 +923,13 @@ bool CSoundFile::ReadAMS2(FileReader &file, ModLoadingFlags loadFlags)
|
|||
}
|
||||
if(descriptionHeader.packedLen > sizeof(descriptionHeader) && file.CanRead(descriptionHeader.packedLen - sizeof(descriptionHeader)))
|
||||
{
|
||||
const size_t textLength = descriptionHeader.packedLen - sizeof(descriptionHeader);
|
||||
const uint32 textLength = descriptionHeader.packedLen - static_cast<uint32>(sizeof(descriptionHeader));
|
||||
std::vector<uint8> textIn;
|
||||
file.ReadVector(textIn, textLength);
|
||||
// In the best case, every byte triplet can decode to 255 bytes, which is a ratio of exactly 1:85
|
||||
const uint32 maxLength = std::min(textLength, Util::MaxValueOfType(textLength) / 85u) * 85u;
|
||||
std::string textOut;
|
||||
textOut.reserve(descriptionHeader.unpackedLen);
|
||||
textOut.reserve(std::min(maxLength, descriptionHeader.unpackedLen.get()));
|
||||
|
||||
size_t readLen = 0;
|
||||
while(readLen < textLength)
|
||||
|
|
|
@ -630,10 +630,19 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, const uint8 fileVersion,
|
|||
|
||||
switch(effect2)
|
||||
{
|
||||
case 1: // Note Finetune
|
||||
effect2 = static_cast<ModCommand::COMMAND>(effectParam2 < 128 ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN);
|
||||
if(effectParam2 > 128) effectParam2 = 255 - effectParam2 + 1;
|
||||
effectParam2 = 0xF0 | std::min(uint8(0x0F), effectParam2); // Well, this is not too accurate...
|
||||
case 1: // Note Finetune (1/16th of a semitone signed 8-bit value, not 1/128th as the interface claims)
|
||||
effect2 = (effectParam2 < 128) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN;
|
||||
if(effectParam2 >= 128)
|
||||
effectParam2 = ~effectParam2 + 1;
|
||||
if(effectParam2 >= 16 && m->IsNote())
|
||||
{
|
||||
if(effect2 == CMD_PORTAMENTOUP)
|
||||
m->note = static_cast<ModCommand::NOTE>(std::min(m->note + effectParam2 / 16, static_cast<int>(NOTE_MAX)));
|
||||
else
|
||||
m->note = static_cast<ModCommand::NOTE>(std::max(m->note - effectParam2 / 16, static_cast<int>(NOTE_MIN)));
|
||||
effectParam2 %= 16u;
|
||||
}
|
||||
effectParam2 = 0xF0 | std::min(uint8(0x0F), effectParam2);
|
||||
break;
|
||||
case 2: // Note Delay (wtf is the difference to Sample Delay?)
|
||||
effectParam2 = DMFdelay2MPT(effectParam2, settings.internalTicks);
|
||||
|
@ -654,7 +663,7 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, const uint8 fileVersion,
|
|||
case 4: // Portamento Up
|
||||
case 5: // Portamento Down
|
||||
effectParam2 = DMFporta2MPT(effectParam2, settings.internalTicks, true);
|
||||
effect2 = static_cast<ModCommand::COMMAND>(effect2 == 4 ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN);
|
||||
effect2 = (effect2 == 4) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN;
|
||||
useMem2 = true;
|
||||
break;
|
||||
case 6: // Portamento to Note
|
||||
|
@ -811,6 +820,12 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, const uint8 fileVersion,
|
|||
// Prefer instrument effects over any other effects
|
||||
if(effect1 != CMD_NONE)
|
||||
{
|
||||
ModCommand::TwoRegularCommandsToMPT(effect3, effectParam3, effect1, effectParam1);
|
||||
if(m->volcmd == VOLCMD_NONE && effect3 != VOLCMD_NONE)
|
||||
{
|
||||
m->volcmd = effect3;
|
||||
m->vol = effectParam3;
|
||||
}
|
||||
m->command = effect1;
|
||||
m->param = effectParam1;
|
||||
} else if(effect3 != CMD_NONE)
|
||||
|
|
|
@ -1160,6 +1160,10 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags)
|
|||
{
|
||||
m_SongFlags.set(SONG_ISAMIGA);
|
||||
}
|
||||
if(isGenericMultiChannel || isMdKd)
|
||||
{
|
||||
m_playBehaviour.set(kFT2MODTremoloRampWaveform);
|
||||
}
|
||||
if(isInconexia)
|
||||
{
|
||||
m_playBehaviour.set(kMODIgnorePanning);
|
||||
|
|
|
@ -84,6 +84,7 @@ void CSoundFile::S3MSaveConvert(uint8 &command, uint8 ¶m, bool toIT, bool co
|
|||
case CMD_TONEPORTAVOL: command = 'L'; break;
|
||||
case CMD_CHANNELVOLUME: command = 'M'; break;
|
||||
case CMD_CHANNELVOLSLIDE: command = 'N'; break;
|
||||
case CMD_OFFSETPERCENTAGE:
|
||||
case CMD_OFFSET: command = 'O'; break;
|
||||
case CMD_PANNINGSLIDE: command = 'P'; break;
|
||||
case CMD_RETRIG: command = 'Q'; break;
|
||||
|
@ -465,7 +466,7 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
|
|||
continue;
|
||||
}
|
||||
|
||||
sampleHeader.ConvertToMPT(Samples[smp + 1]);
|
||||
sampleHeader.ConvertToMPT(Samples[smp + 1], isST3);
|
||||
m_szNames[smp + 1] = mpt::String::ReadBuf(mpt::String::nullTerminated, sampleHeader.name);
|
||||
|
||||
if(sampleHeader.sampleType < S3MSampleHeader::typeAdMel)
|
||||
|
@ -527,7 +528,7 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
|
|||
}
|
||||
|
||||
CHANNELINDEX channel = (info & s3mChannelMask);
|
||||
ModCommand dummy = ModCommand::Empty();
|
||||
ModCommand dummy;
|
||||
ModCommand &m = (channel < GetNumChannels()) ? rowBase[channel] : dummy;
|
||||
|
||||
if(info & s3mNotePresent)
|
||||
|
@ -577,17 +578,14 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
|
|||
} else
|
||||
{
|
||||
if(m.param < 0x08)
|
||||
{
|
||||
zxxCountLeft++;
|
||||
} else if(m.param > 0x08)
|
||||
{
|
||||
else if(m.param > 0x08)
|
||||
zxxCountRight++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(pixPlayPanning && zxxCountLeft + zxxCountRight >= m_nChannels && (-zxxCountLeft + zxxCountRight) < static_cast<int>(m_nChannels))
|
||||
{
|
||||
|
|
|
@ -66,8 +66,10 @@ bool CSoundFile::ReadWAV(FileReader &file, ModLoadingFlags loadFlags)
|
|||
if(!wavFile.IsValid()
|
||||
|| wavFile.GetNumChannels() == 0
|
||||
|| wavFile.GetNumChannels() > MAX_BASECHANNELS
|
||||
|| wavFile.GetNumChannels() >= MAX_SAMPLES
|
||||
|| wavFile.GetBitsPerSample() == 0
|
||||
|| wavFile.GetBitsPerSample() > 32
|
||||
|| wavFile.GetBitsPerSample() > 64
|
||||
|| (wavFile.GetBitsPerSample() < 32 && wavFile.GetSampleFormat() == WAVFormatChunk::fmtFloat)
|
||||
|| (wavFile.GetSampleFormat() != WAVFormatChunk::fmtPCM && wavFile.GetSampleFormat() != WAVFormatChunk::fmtFloat))
|
||||
{
|
||||
return false;
|
||||
|
@ -173,22 +175,22 @@ bool CSoundFile::ReadWAV(FileReader &file, ModLoadingFlags loadFlags)
|
|||
|
||||
if(wavFile.GetSampleFormat() == WAVFormatChunk::fmtFloat)
|
||||
{
|
||||
CopyWavChannel<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<littleEndian32> > >(sample, sampleChunk, channel, wavFile.GetNumChannels());
|
||||
if(wavFile.GetBitsPerSample() <= 32)
|
||||
CopyWavChannel<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<littleEndian32>>>(sample, sampleChunk, channel, wavFile.GetNumChannels());
|
||||
else
|
||||
CopyWavChannel<SC::ConversionChain<SC::Convert<int16, float64>, SC::DecodeFloat64<littleEndian64>>>(sample, sampleChunk, channel, wavFile.GetNumChannels());
|
||||
} else
|
||||
{
|
||||
if(wavFile.GetBitsPerSample() <= 8)
|
||||
{
|
||||
CopyWavChannel<SC::DecodeUint8>(sample, sampleChunk, channel, wavFile.GetNumChannels());
|
||||
} else if(wavFile.GetBitsPerSample() <= 16)
|
||||
{
|
||||
CopyWavChannel<SC::DecodeInt16<0, littleEndian16> >(sample, sampleChunk, channel, wavFile.GetNumChannels());
|
||||
} else if(wavFile.GetBitsPerSample() <= 24)
|
||||
{
|
||||
CopyWavChannel<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(sample, sampleChunk, channel, wavFile.GetNumChannels());
|
||||
} else if(wavFile.GetBitsPerSample() <= 32)
|
||||
{
|
||||
CopyWavChannel<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(sample, sampleChunk, channel, wavFile.GetNumChannels());
|
||||
}
|
||||
else if(wavFile.GetBitsPerSample() <= 16)
|
||||
CopyWavChannel<SC::DecodeInt16<0, littleEndian16>>(sample, sampleChunk, channel, wavFile.GetNumChannels());
|
||||
else if(wavFile.GetBitsPerSample() <= 24)
|
||||
CopyWavChannel<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24>>>(sample, sampleChunk, channel, wavFile.GetNumChannels());
|
||||
else if(wavFile.GetBitsPerSample() <= 32)
|
||||
CopyWavChannel<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32>>>(sample, sampleChunk, channel, wavFile.GetNumChannels());
|
||||
else if(wavFile.GetBitsPerSample() <= 64)
|
||||
CopyWavChannel<SC::ConversionChain<SC::Convert<int16, int64>, SC::DecodeInt64<0, littleEndian64>>>(sample, sampleChunk, channel, wavFile.GetNumChannels());
|
||||
}
|
||||
sample.PrecomputeLoops(*this, false);
|
||||
|
||||
|
|
|
@ -114,12 +114,12 @@ size_t CopyStereoSplitSample(ModSample &sample, const Tbyte *sourceBuffer, size_
|
|||
template <typename SampleConversion, typename Tbyte>
|
||||
size_t CopyAndNormalizeSample(ModSample &sample, const Tbyte *sourceBuffer, size_t sourceSize, typename SampleConversion::peak_t *srcPeak = nullptr, SampleConversion conv = SampleConversion())
|
||||
{
|
||||
const size_t inSize = sizeof(typename SampleConversion::input_t);
|
||||
const size_t sampleSize = SampleConversion::input_inc;
|
||||
|
||||
MPT_ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t));
|
||||
|
||||
size_t numSamples = sample.nLength * sample.GetNumChannels();
|
||||
LimitMax(numSamples, sourceSize / inSize);
|
||||
LimitMax(numSamples, sourceSize / sampleSize);
|
||||
|
||||
const std::byte * inBuf = mpt::byte_cast<const std::byte*>(sourceBuffer);
|
||||
// Finding max value
|
||||
|
@ -150,7 +150,7 @@ size_t CopyAndNormalizeSample(ModSample &sample, const Tbyte *sourceBuffer, size
|
|||
*srcPeak = sampleConv.GetSrcPeak();
|
||||
}
|
||||
|
||||
return numSamples * inSize;
|
||||
return numSamples * sampleSize;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -180,18 +180,19 @@ void ModSequence::assign(ORDERINDEX newSize, PATTERNINDEX pat)
|
|||
|
||||
ORDERINDEX ModSequence::insert(ORDERINDEX pos, ORDERINDEX count, PATTERNINDEX fill)
|
||||
{
|
||||
if (pos >= m_sndFile.GetModSpecifications().ordersMax || count == 0)
|
||||
const auto ordersMax = m_sndFile.GetModSpecifications().ordersMax;
|
||||
if(pos >= ordersMax || GetLengthTailTrimmed() >= ordersMax || count == 0)
|
||||
return 0;
|
||||
// Limit number of orders to be inserted so that we don't exceed the format limit.
|
||||
LimitMax(count, ORDERINDEX(m_sndFile.GetModSpecifications().ordersMax - pos));
|
||||
reserve(pos + count);
|
||||
LimitMax(count, static_cast<ORDERINDEX>(ordersMax - pos));
|
||||
reserve(std::max(pos, GetLength()) + count);
|
||||
// Inserting past the end of the container?
|
||||
if(pos > size())
|
||||
resize(pos);
|
||||
std::vector<PATTERNINDEX>::insert(begin() + pos, count, fill);
|
||||
// Did we overgrow? Remove patterns at end.
|
||||
if(size() > m_sndFile.GetModSpecifications().ordersMax)
|
||||
resize(m_sndFile.GetModSpecifications().ordersMax);
|
||||
if(size() > ordersMax)
|
||||
resize(ordersMax);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
// Convert an S3M sample header to OpenMPT's internal sample header.
|
||||
void S3MSampleHeader::ConvertToMPT(ModSample &mptSmp) const
|
||||
void S3MSampleHeader::ConvertToMPT(ModSample &mptSmp, bool isST3) const
|
||||
{
|
||||
mptSmp.Initialize(MOD_TYPE_S3M);
|
||||
mptSmp.filename = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, filename);
|
||||
|
@ -48,17 +48,18 @@ void S3MSampleHeader::ConvertToMPT(ModSample &mptSmp) const
|
|||
}
|
||||
|
||||
// Volume / Panning
|
||||
mptSmp.nVolume = std::min(static_cast<uint8>(defaultVolume), uint8(64)) * 4;
|
||||
mptSmp.nVolume = std::min(defaultVolume.get(), uint8(64)) * 4;
|
||||
|
||||
// C-5 frequency
|
||||
mptSmp.nC5Speed = c5speed;
|
||||
// ST3 ignores the high 16 bits
|
||||
if(isST3)
|
||||
mptSmp.nC5Speed &= 0xFFFF;
|
||||
|
||||
if(mptSmp.nC5Speed == 0)
|
||||
{
|
||||
mptSmp.nC5Speed = 8363;
|
||||
} else if(mptSmp.nC5Speed < 1024)
|
||||
{
|
||||
else if(mptSmp.nC5Speed < 1024)
|
||||
mptSmp.nC5Speed = 1024;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ struct S3MSampleHeader
|
|||
char magic[4]; // "SCRS" magic bytes ("SCRI" for Adlib instruments)
|
||||
|
||||
// Convert an S3M sample header to OpenMPT's internal sample header.
|
||||
void ConvertToMPT(ModSample &mptSmp) const;
|
||||
void ConvertToMPT(ModSample &mptSmp, bool isST3 = false) const;
|
||||
// Convert OpenMPT's internal sample header to an S3M sample header.
|
||||
SmpLength ConvertToS3M(const ModSample &mptSmp);
|
||||
// Retrieve the internal sample format flags for this sample.
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "../common/mptFileIO.h"
|
||||
#endif // !MODPLUG_NO_FILESAVE
|
||||
#include "../common/misc_util.h"
|
||||
#include "../common/Endianness.h"
|
||||
#include "Tagging.h"
|
||||
#include "ITTools.h"
|
||||
#include "XMTools.h"
|
||||
|
@ -424,6 +425,7 @@ bool CSoundFile::ReadWAVSample(SAMPLEINDEX nSample, FileReader &file, bool mayNo
|
|||
|| wavFile.GetNumChannels() == 0
|
||||
|| wavFile.GetNumChannels() > 2
|
||||
|| (wavFile.GetBitsPerSample() == 0 && wavFile.GetSampleFormat() != WAVFormatChunk::fmtMP3)
|
||||
|| (wavFile.GetBitsPerSample() < 32 && wavFile.GetSampleFormat() == WAVFormatChunk::fmtFloat)
|
||||
|| (wavFile.GetBitsPerSample() > 64)
|
||||
|| (wavFile.GetSampleFormat() != WAVFormatChunk::fmtPCM && wavFile.GetSampleFormat() != WAVFormatChunk::fmtFloat && wavFile.GetSampleFormat() != WAVFormatChunk::fmtIMA_ADPCM && wavFile.GetSampleFormat() != WAVFormatChunk::fmtMP3 && wavFile.GetSampleFormat() != WAVFormatChunk::fmtALaw && wavFile.GetSampleFormat() != WAVFormatChunk::fmtULaw))
|
||||
{
|
||||
|
@ -2486,6 +2488,7 @@ struct IFFChunk
|
|||
idVHDR = MagicBE("VHDR"),
|
||||
idBODY = MagicBE("BODY"),
|
||||
idNAME = MagicBE("NAME"),
|
||||
idCHAN = MagicBE("CHAN"),
|
||||
};
|
||||
|
||||
uint32be id; // See ChunkIdentifiers
|
||||
|
@ -2538,6 +2541,7 @@ bool CSoundFile::ReadIFFSample(SAMPLEINDEX nSample, FileReader &file)
|
|||
|
||||
FileReader vhdrChunk = chunks.GetChunk(IFFChunk::idVHDR);
|
||||
FileReader bodyChunk = chunks.GetChunk(IFFChunk::idBODY);
|
||||
FileReader chanChunk = chunks.GetChunk(IFFChunk::idCHAN);
|
||||
IFFSampleHeader sampleHeader;
|
||||
if(!bodyChunk.IsValid()
|
||||
|| !vhdrChunk.IsValid()
|
||||
|
@ -2549,6 +2553,7 @@ bool CSoundFile::ReadIFFSample(SAMPLEINDEX nSample, FileReader &file)
|
|||
DestroySampleThreadsafe(nSample);
|
||||
// Default values
|
||||
const uint8 bytesPerSample = memcmp(fileHeader.magic, "8SVX", 4) ? 2 : 1;
|
||||
const uint8 channels = chanChunk.ReadUint32BE() == 6 ? 2 : 1;
|
||||
ModSample &sample = Samples[nSample];
|
||||
sample.Initialize();
|
||||
sample.nLoopStart = sampleHeader.oneShotHiSamples / bytesPerSample;
|
||||
|
@ -2569,13 +2574,13 @@ bool CSoundFile::ReadIFFSample(SAMPLEINDEX nSample, FileReader &file)
|
|||
m_szNames[nSample] = "";
|
||||
}
|
||||
|
||||
sample.nLength = mpt::saturate_cast<SmpLength>(bodyChunk.GetLength() / bytesPerSample);
|
||||
sample.nLength = mpt::saturate_cast<SmpLength>(bodyChunk.GetLength() / (bytesPerSample * channels));
|
||||
if((sample.nLoopStart + 4 < sample.nLoopEnd) && (sample.nLoopEnd <= sample.nLength)) sample.uFlags.set(CHN_LOOP);
|
||||
|
||||
// While this is an Amiga format, the 16SV version appears to be only used on PC, and only with little-endian sample data.
|
||||
SampleIO(
|
||||
(bytesPerSample == 2) ? SampleIO::_16bit : SampleIO::_8bit,
|
||||
SampleIO::mono,
|
||||
(channels == 2) ? SampleIO::stereoSplit : SampleIO::mono,
|
||||
SampleIO::littleEndian,
|
||||
SampleIO::signedPCM)
|
||||
.ReadSample(sample, bodyChunk);
|
||||
|
|
|
@ -327,7 +327,7 @@ size_t SampleIO::ReadSample(ModSample &sample, FileReader &file) const
|
|||
const auto &lut = GetEncoding() == uLaw ? uLawTable : aLawTable;
|
||||
|
||||
SmpLength readLength = sample.nLength * GetNumChannels();
|
||||
LimitMax(readLength, mpt::saturate_cast<SmpLength>(file.BytesLeft()));
|
||||
LimitMax(readLength, mpt::saturate_cast<SmpLength>(fileSize));
|
||||
bytesRead = readLength;
|
||||
|
||||
const uint8 *inBuf = mpt::byte_cast<const uint8*>(sourceBuf);
|
||||
|
|
|
@ -512,7 +512,7 @@ enum PlayBehaviour
|
|||
kFT2NoteOffFlags, // Set and reset the correct fade/key-off flags with note-off and instrument number after note-off
|
||||
kITMultiSampleInstrumentNumber, // After portamento to different sample within multi-sampled instrument, lone instrument numbers in patterns always recall the new sample's default settings
|
||||
kRowDelayWithNoteDelay, // Retrigger note delays on every reptition of a row
|
||||
kFT2TremoloRampWaveform, // FT2-compatible tremolo ramp down / triangle waveform
|
||||
kFT2MODTremoloRampWaveform, // FT2-/ProTracker-compatible tremolo ramp down / triangle waveform
|
||||
kFT2PortaUpDownMemory, // Portamento up and down have separate memory
|
||||
|
||||
kMODOutOfRangeNoteDelay, // ProTracker behaviour for out-of-range note delays
|
||||
|
|
|
@ -154,6 +154,9 @@ public:
|
|||
int vol = 0;
|
||||
sndFile.ProcessInstrumentFade(chn, vol);
|
||||
|
||||
if(chn.dwFlags[CHN_ADLIB])
|
||||
continue;
|
||||
|
||||
if(updateInc || chnSettings[channel].incChanged)
|
||||
{
|
||||
if(chn.m_CalculateFreq || chn.m_ReCalculateFreqOnFirstTick)
|
||||
|
@ -568,11 +571,6 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
|
|||
{
|
||||
if(Samples[smp].uFlags[CHN_PANNING])
|
||||
chn.SetInstrumentPan(Samples[smp].nPan, *this);
|
||||
if(Samples[smp].uFlags[CHN_ADLIB])
|
||||
{
|
||||
memory.state->Chn[nChn].Stop();
|
||||
memory.chnSettings[nChn].ticksToRender = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1301,18 +1299,25 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
|
|||
m_PlayState.m_nFrameDelay = m_PlayState.m_nPatternDelay = 0;
|
||||
m_PlayState.m_nTickCount = Util::MaxValueOfType(m_PlayState.m_nTickCount) - 1;
|
||||
m_PlayState.m_bPositionChanged = true;
|
||||
if(m_opl != nullptr)
|
||||
m_opl->Reset();
|
||||
for(CHANNELINDEX n = 0; n < GetNumChannels(); n++)
|
||||
{
|
||||
if(m_PlayState.Chn[n].nLastNote != NOTE_NONE)
|
||||
auto &chn = m_PlayState.Chn[n];
|
||||
if(chn.nLastNote != NOTE_NONE)
|
||||
{
|
||||
m_PlayState.Chn[n].nNewNote = m_PlayState.Chn[n].nLastNote;
|
||||
chn.nNewNote = chn.nLastNote;
|
||||
}
|
||||
if(memory.chnSettings[n].vol != 0xFF && !adjustSamplePos)
|
||||
{
|
||||
m_PlayState.Chn[n].nVolume = std::min(memory.chnSettings[n].vol, uint8(64)) * 4;
|
||||
chn.nVolume = std::min(memory.chnSettings[n].vol, uint8(64)) * 4;
|
||||
}
|
||||
if(chn.pModSample != nullptr && chn.pModSample->uFlags[CHN_ADLIB] && m_opl)
|
||||
{
|
||||
m_opl->Patch(n, chn.pModSample->adlib);
|
||||
m_opl->NoteCut(n);
|
||||
}
|
||||
}
|
||||
if(m_opl != nullptr) m_opl->Reset();
|
||||
|
||||
#ifndef NO_PLUGINS
|
||||
// If there were any PC events, update plugin parameters to their latest value.
|
||||
|
@ -1694,7 +1699,7 @@ void CSoundFile::InstrumentChange(ModChannel &chn, uint32 instr, bool bPorta, bo
|
|||
chn.nFineTune = pSmp->nFineTune;
|
||||
}
|
||||
|
||||
chn.nTranspose = pSmp->RelativeTone;
|
||||
chn.nTranspose = UseFinetuneAndTranspose() ? pSmp->RelativeTone : 0;
|
||||
|
||||
// FT2 compatibility: Don't reset portamento target with new instrument numbers.
|
||||
// Test case: Porta-Pickup.xm
|
||||
|
@ -4984,6 +4989,7 @@ void CSoundFile::ProcessMIDIMacro(CHANNELINDEX nChn, bool isSmooth, const char *
|
|||
// MIDI channel
|
||||
isNibble = true;
|
||||
data = 0xFF;
|
||||
#ifndef NO_PLUGINS
|
||||
const PLUGINDEX plug = (plugin != 0) ? plugin : GetBestPlugin(nChn, PrioritiseChannel, EvenIfMuted);
|
||||
if(plug > 0 && plug <= MAX_MIXPLUGINS)
|
||||
{
|
||||
|
@ -4991,6 +4997,7 @@ void CSoundFile::ProcessMIDIMacro(CHANNELINDEX nChn, bool isSmooth, const char *
|
|||
if(midiPlug)
|
||||
data = midiPlug->GetMidiChannel(nChn);
|
||||
}
|
||||
#endif // NO_PLUGINS
|
||||
if(data == 0xFF)
|
||||
{
|
||||
// Fallback if no plugin was found
|
||||
|
|
|
@ -537,9 +537,14 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags)
|
|||
m_nInstruments = maxInstr;
|
||||
|
||||
// Set default play state values
|
||||
if (!m_nDefaultTempo.GetInt()) m_nDefaultTempo.Set(125);
|
||||
if (!m_nDefaultSpeed) m_nDefaultSpeed = 6;
|
||||
if (m_nDefaultRowsPerMeasure < m_nDefaultRowsPerBeat) m_nDefaultRowsPerMeasure = m_nDefaultRowsPerBeat;
|
||||
if(!m_nDefaultTempo.GetInt())
|
||||
m_nDefaultTempo.Set(125);
|
||||
else
|
||||
LimitMax(m_nDefaultTempo, TEMPO(uint16_max, 0));
|
||||
if(!m_nDefaultSpeed)
|
||||
m_nDefaultSpeed = 6;
|
||||
if(m_nDefaultRowsPerMeasure < m_nDefaultRowsPerBeat)
|
||||
m_nDefaultRowsPerMeasure = m_nDefaultRowsPerBeat;
|
||||
m_PlayState.m_nMusicSpeed = m_nDefaultSpeed;
|
||||
m_PlayState.m_nMusicTempo = m_nDefaultTempo;
|
||||
m_PlayState.m_nCurrentRowsPerBeat = m_nDefaultRowsPerBeat;
|
||||
|
@ -1085,7 +1090,7 @@ PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type)
|
|||
playBehaviour.set(kFT2FinetunePrecision);
|
||||
playBehaviour.set(kFT2NoteOffFlags);
|
||||
playBehaviour.set(kRowDelayWithNoteDelay);
|
||||
playBehaviour.set(kFT2TremoloRampWaveform);
|
||||
playBehaviour.set(kFT2MODTremoloRampWaveform);
|
||||
playBehaviour.set(kFT2PortaUpDownMemory);
|
||||
playBehaviour.set(kFT2PanSustainRelease);
|
||||
playBehaviour.set(kFT2NoteDelayWithoutInstr);
|
||||
|
@ -1116,6 +1121,7 @@ PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type)
|
|||
playBehaviour.set(kMODOutOfRangeNoteDelay);
|
||||
playBehaviour.set(kMODTempoOnSecondTick);
|
||||
playBehaviour.set(kRowDelayWithNoteDelay);
|
||||
playBehaviour.set(kFT2MODTremoloRampWaveform);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -889,7 +889,7 @@ void CSoundFile::ProcessTremolo(ModChannel &chn, int &vol) const
|
|||
const uint8 attenuation = ((GetType() & (MOD_TYPE_XM | MOD_TYPE_MOD)) || m_playBehaviour[kITVibratoTremoloPanbrello]) ? 5 : 6;
|
||||
|
||||
int delta = GetVibratoDelta(chn.nTremoloType, chn.nTremoloPos);
|
||||
if((chn.nTremoloType & 0x03) == 1 && m_playBehaviour[kFT2TremoloRampWaveform])
|
||||
if((chn.nTremoloType & 0x03) == 1 && m_playBehaviour[kFT2MODTremoloRampWaveform])
|
||||
{
|
||||
// FT2 compatibility: Tremolo ramp down / triangle implementation is weird and affected by vibrato position (copypaste bug)
|
||||
// Test case: TremoloWaveforms.xm, TremoloVibrato.xm
|
||||
|
@ -2295,7 +2295,10 @@ bool CSoundFile::ReadNote()
|
|||
// In ST3, a sample rate of 8363 Hz is mapped to middle-C, which is 261.625 Hz in a tempered scale at A4 = 440.
|
||||
// Hence, we have to translate our "sample rate" into pitch.
|
||||
const auto freq = hasTuning ? chn.nPeriod : GetFreqFromPeriod(period, chn.nC5Speed, nPeriodFrac);
|
||||
const auto milliHertz = Util::muldivr_unsigned(freq, 261625, 8363 << FREQ_FRACBITS);
|
||||
auto milliHertz = Util::muldivr_unsigned(freq, 261625, 8363 << FREQ_FRACBITS);
|
||||
#ifndef MODPLUG_TRACKER
|
||||
milliHertz = Util::muldivr_unsigned(milliHertz, m_nFreqFactor, 65536);
|
||||
#endif // !MODPLUG_TRACKER
|
||||
const bool keyOff = chn.dwFlags[CHN_KEYOFF] || (chn.dwFlags[CHN_NOTEFADE] && chn.nFadeOutVol == 0);
|
||||
m_opl->Frequency(nChn, milliHertz, keyOff, m_playBehaviour[kOPLBeatingOscillators]);
|
||||
}
|
||||
|
|
|
@ -565,7 +565,7 @@ void CSoundFile::UpgradeModule()
|
|||
{
|
||||
{ kFT2NoteOffFlags, MPT_V("1.27.00.27") },
|
||||
{ kRowDelayWithNoteDelay, MPT_V("1.27.00.37") },
|
||||
{ kFT2TremoloRampWaveform, MPT_V("1.27.00.37") },
|
||||
{ kFT2MODTremoloRampWaveform, MPT_V("1.27.00.37") },
|
||||
{ kFT2PortaUpDownMemory, MPT_V("1.27.00.37") },
|
||||
{ kFT2PanSustainRelease, MPT_V("1.28.00.09") },
|
||||
{ kFT2NoteDelayWithoutInstr, MPT_V("1.28.00.44") },
|
||||
|
|
|
@ -187,10 +187,9 @@ static void ConvertStereoToMonoMixImpl(T *pDest, const SmpLength length)
|
|||
|
||||
|
||||
template <class T>
|
||||
static void ConvertStereoToMonoOneChannelImpl(T *pDest, const SmpLength length)
|
||||
static void ConvertStereoToMonoOneChannelImpl(T *pDest, const T *pSource, const SmpLength length)
|
||||
{
|
||||
const T *pEnd = pDest + length;
|
||||
for(T *pSource = pDest; pDest != pEnd; pDest++, pSource += 2)
|
||||
for(const T *pEnd = pDest + length; pDest != pEnd; pDest++, pSource += 2)
|
||||
{
|
||||
*pDest = *pSource;
|
||||
}
|
||||
|
@ -218,9 +217,9 @@ bool ConvertToMono(ModSample &smp, CSoundFile &sndFile, StereoToMonoMode convers
|
|||
conversionMode = onlyLeft;
|
||||
}
|
||||
if(smp.GetElementarySampleSize() == 2)
|
||||
ConvertStereoToMonoOneChannelImpl(smp.sample16() + (conversionMode == onlyLeft ? 0 : 1), smp.nLength);
|
||||
ConvertStereoToMonoOneChannelImpl(smp.sample16(), smp.sample16() + (conversionMode == onlyLeft ? 0 : 1), smp.nLength);
|
||||
else if(smp.GetElementarySampleSize() == 1)
|
||||
ConvertStereoToMonoOneChannelImpl(smp.sample8() + (conversionMode == onlyLeft ? 0 : 1), smp.nLength);
|
||||
ConvertStereoToMonoOneChannelImpl(smp.sample8(), smp.sample8() + (conversionMode == onlyLeft ? 0 : 1), smp.nLength);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
@ -241,7 +240,70 @@ bool ConvertToMono(ModSample &smp, CSoundFile &sndFile, StereoToMonoMode convers
|
|||
|
||||
|
||||
template <class T>
|
||||
static void ConvertMonoToStereoImpl(const T * MPT_RESTRICT src, T * MPT_RESTRICT dst, SmpLength length)
|
||||
static void SplitStereoImpl(void *destL, void *destR, const T *source, SmpLength length)
|
||||
{
|
||||
T *l = static_cast<T *>(destL), *r = static_cast<T*>(destR);
|
||||
while(length--)
|
||||
{
|
||||
*(l++) = source[0];
|
||||
*(r++) = source[1];
|
||||
source += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Converts a stereo sample into two mono samples. Source sample will not be deleted.
|
||||
bool SplitStereo(const ModSample &source, ModSample &left, ModSample &right, CSoundFile &sndFile)
|
||||
{
|
||||
if(!source.HasSampleData() || source.GetNumChannels() != 2 || &left == &right)
|
||||
return false;
|
||||
const bool sourceIsLeft = &left == &source, sourceIsRight = &right == &source;
|
||||
if(left.HasSampleData() && !sourceIsLeft)
|
||||
return false;
|
||||
if(right.HasSampleData() && !sourceIsRight)
|
||||
return false;
|
||||
|
||||
void *leftData = sourceIsLeft ? left.samplev() : ModSample::AllocateSample(source.nLength, source.GetElementarySampleSize());
|
||||
void *rightData = sourceIsRight ? right.samplev() : ModSample::AllocateSample(source.nLength, source.GetElementarySampleSize());
|
||||
if(!leftData || !rightData)
|
||||
{
|
||||
if(!sourceIsLeft)
|
||||
ModSample::FreeSample(leftData);
|
||||
if(!sourceIsRight)
|
||||
ModSample::FreeSample(rightData);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(source.GetElementarySampleSize() == 2)
|
||||
SplitStereoImpl(leftData, rightData, source.sample16(), source.nLength);
|
||||
else if(source.GetElementarySampleSize() == 1)
|
||||
SplitStereoImpl(leftData, rightData, source.sample8(), source.nLength);
|
||||
else
|
||||
MPT_ASSERT_NOTREACHED();
|
||||
|
||||
CriticalSection cs;
|
||||
left = source;
|
||||
left.uFlags.reset(CHN_STEREO);
|
||||
left.pData.pSample = leftData;
|
||||
|
||||
right = source;
|
||||
right.uFlags.reset(CHN_STEREO);
|
||||
right.pData.pSample = rightData;
|
||||
|
||||
for(auto &chn : sndFile.m_PlayState.Chn)
|
||||
{
|
||||
if(chn.pModSample == &left || chn.pModSample == &right)
|
||||
chn.dwFlags.reset(CHN_STEREO);
|
||||
}
|
||||
|
||||
left.PrecomputeLoops(sndFile, false);
|
||||
right.PrecomputeLoops(sndFile, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
static void ConvertMonoToStereoImpl(const T *MPT_RESTRICT src, T *MPT_RESTRICT dst, SmpLength length)
|
||||
{
|
||||
while(length--)
|
||||
{
|
||||
|
|
|
@ -46,6 +46,10 @@ enum StereoToMonoMode
|
|||
// Convert a sample with any number of channels to mono
|
||||
bool ConvertToMono(ModSample &smp, CSoundFile &sndFile, StereoToMonoMode conversionMode);
|
||||
|
||||
// Converts a stereo sample into two mono samples. Source sample will not be deleted.
|
||||
// Either of the two target samples may be identical to the source sample.
|
||||
bool SplitStereo(const ModSample &source, ModSample &left, ModSample &right, CSoundFile &sndFile);
|
||||
|
||||
// Convert a mono sample to stereo
|
||||
bool ConvertToStereo(ModSample &smp, CSoundFile &sndFile);
|
||||
|
||||
|
|
|
@ -276,7 +276,7 @@ void LFOPlugin::HardAllNotesOff()
|
|||
}
|
||||
|
||||
|
||||
bool LFOPlugin::IsNotePlaying(uint32 note, CHANNELINDEX trackerChn)
|
||||
bool LFOPlugin::IsNotePlaying(uint8 note, CHANNELINDEX trackerChn)
|
||||
{
|
||||
if(IMixPlugin *plugin = GetOutputPlugin())
|
||||
return plugin->IsNotePlaying(note, trackerChn);
|
||||
|
|
|
@ -91,7 +91,7 @@ public:
|
|||
void MidiVibrato(int32 depth, int8 pwd, CHANNELINDEX trackChannel) override;
|
||||
void MidiCommand(const ModInstrument &instr, uint16 note, uint16 vol, CHANNELINDEX trackChannel) override;
|
||||
void HardAllNotesOff() override;
|
||||
bool IsNotePlaying(uint32 note, CHANNELINDEX trackerChn) override;
|
||||
bool IsNotePlaying(uint8 note, CHANNELINDEX trackerChn) override;
|
||||
|
||||
int32 GetNumPrograms() const override { return 0; }
|
||||
int32 GetCurrentProgram() override { return 0; }
|
||||
|
|
|
@ -947,8 +947,11 @@ void IMidiPlugin::MidiCommand(const ModInstrument &instr, uint16 note, uint16 vo
|
|||
}
|
||||
|
||||
|
||||
bool IMidiPlugin::IsNotePlaying(uint32 note, CHANNELINDEX trackerChn)
|
||||
bool IMidiPlugin::IsNotePlaying(uint8 note, CHANNELINDEX trackerChn)
|
||||
{
|
||||
if(!ModCommand::IsNote(note) || trackerChn >= std::size(m_MidiCh[GetMidiChannel(trackerChn)].noteOnMap[note]))
|
||||
return false;
|
||||
|
||||
note -= NOTE_MIN;
|
||||
return (m_MidiCh[GetMidiChannel(trackerChn)].noteOnMap[note][trackerChn] != 0);
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ public:
|
|||
virtual void MidiVibrato(int32 /*depth*/, int8 /*pwd*/, CHANNELINDEX /*trackerChn*/) { }
|
||||
virtual void MidiCommand(const ModInstrument &/*instr*/, uint16 /*note*/, uint16 /*vol*/, CHANNELINDEX /*trackChannel*/) { }
|
||||
virtual void HardAllNotesOff() { }
|
||||
virtual bool IsNotePlaying(uint32 /*note*/, CHANNELINDEX /*trackerChn*/) { return false; }
|
||||
virtual bool IsNotePlaying(uint8 /*note*/, CHANNELINDEX /*trackerChn*/) { return false; }
|
||||
|
||||
// Modify parameter by given amount. Only needs to be re-implemented if plugin architecture allows this to be performed atomically.
|
||||
virtual void ModifyParameter(PlugParamIndex nIndex, PlugParamValue diff);
|
||||
|
@ -264,7 +264,7 @@ public:
|
|||
void MidiPitchBend(int32 increment, int8 pwd, CHANNELINDEX trackerChn) override;
|
||||
void MidiVibrato(int32 depth, int8 pwd, CHANNELINDEX trackerChn) override;
|
||||
void MidiCommand(const ModInstrument &instr, uint16 note, uint16 vol, CHANNELINDEX trackChannel) override;
|
||||
bool IsNotePlaying(uint32 note, CHANNELINDEX trackerChn) override;
|
||||
bool IsNotePlaying(uint8 note, CHANNELINDEX trackerChn) override;
|
||||
|
||||
// Get the MIDI channel currently associated with a given tracker channel
|
||||
virtual uint8 GetMidiChannel(CHANNELINDEX trackChannel) const;
|
||||
|
|
|
@ -234,12 +234,13 @@ mpt::ustring CTuning::GetNoteName(const NOTEINDEXTYPE &x, bool addOctave) const
|
|||
|
||||
void CTuning::SetNoteName(const NOTEINDEXTYPE &n, const mpt::ustring &str)
|
||||
{
|
||||
const NOTEINDEXTYPE pos = (GetGroupSize() < 1) ? n : static_cast<NOTEINDEXTYPE>(mpt::wrapping_modulo(n, m_GroupSize));
|
||||
if(!str.empty())
|
||||
{
|
||||
m_NoteNameMap[n] = str;
|
||||
m_NoteNameMap[pos] = str;
|
||||
} else
|
||||
{
|
||||
const auto iter = m_NoteNameMap.find(n);
|
||||
const auto iter = m_NoteNameMap.find(pos);
|
||||
if(iter != m_NoteNameMap.end())
|
||||
{
|
||||
m_NoteNameMap.erase(iter);
|
||||
|
|
Loading…
Reference in New Issue