Updated libopenmpt to version 0.4.5
parent
947ec7f691
commit
65d553a45c
|
@ -1204,6 +1204,7 @@ bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION).makefile.tar: bin/dist.mk bin
|
||||||
rm -rf bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)
|
rm -rf bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)
|
||||||
mkdir -p bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)
|
mkdir -p bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)
|
||||||
mkdir -p bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build
|
mkdir -p bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build
|
||||||
|
mkdir -p bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc
|
||||||
mkdir -p bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include
|
mkdir -p bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include
|
||||||
svn export ./LICENSE bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSE
|
svn export ./LICENSE bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSE
|
||||||
svn export ./README.md bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/README.md
|
svn export ./README.md bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/README.md
|
||||||
|
@ -1213,6 +1214,9 @@ bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION).makefile.tar: bin/dist.mk bin
|
||||||
svn export ./build/make bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/make
|
svn export ./build/make bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/make
|
||||||
svn export ./build/svn_version bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/svn_version
|
svn export ./build/svn_version bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/svn_version
|
||||||
svn export ./common bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/common
|
svn export ./common bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/common
|
||||||
|
svn export ./doc/contributing.md bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc/contributing.md
|
||||||
|
svn export ./doc/libopenmpt_styleguide.md bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc/libopenmpt_styleguide.md
|
||||||
|
svn export ./doc/module_formats.md bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc/module_formats.md
|
||||||
svn export ./soundbase bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/soundbase
|
svn export ./soundbase bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/soundbase
|
||||||
svn export ./soundlib bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/soundlib
|
svn export ./soundlib bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/soundlib
|
||||||
svn export ./sounddsp bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/sounddsp
|
svn export ./sounddsp bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/sounddsp
|
||||||
|
@ -1239,6 +1243,7 @@ bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION).msvc.zip: bin/dist.mk bin/svn
|
||||||
mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build
|
mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build
|
||||||
mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/genie
|
mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/genie
|
||||||
mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/premake
|
mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/premake
|
||||||
|
mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc
|
||||||
mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include
|
mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include
|
||||||
svn export ./LICENSE bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSE --native-eol CRLF
|
svn export ./LICENSE bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSE --native-eol CRLF
|
||||||
svn export ./README.md bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/README.md --native-eol CRLF
|
svn export ./README.md bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/README.md --native-eol CRLF
|
||||||
|
@ -1260,6 +1265,9 @@ bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION).msvc.zip: bin/dist.mk bin/svn
|
||||||
svn export ./build/winstore82 bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/winstore82 --native-eol CRLF
|
svn export ./build/winstore82 bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/winstore82 --native-eol CRLF
|
||||||
svn export ./build/download_externals.cmd bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/download_externals.cmd --native-eol CRLF
|
svn export ./build/download_externals.cmd bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/download_externals.cmd --native-eol CRLF
|
||||||
svn export ./common bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/common --native-eol CRLF
|
svn export ./common bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/common --native-eol CRLF
|
||||||
|
svn export ./doc/contributing.md bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc/contributing.md --native-eol CRLF
|
||||||
|
svn export ./doc/libopenmpt_styleguide.md bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc/libopenmpt_styleguide.md --native-eol CRLF
|
||||||
|
svn export ./doc/module_formats.md bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc/module_formats.md --native-eol CRLF
|
||||||
svn export ./soundbase bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/soundbase --native-eol CRLF
|
svn export ./soundbase bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/soundbase --native-eol CRLF
|
||||||
svn export ./soundlib bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/soundlib --native-eol CRLF
|
svn export ./soundlib bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/soundlib --native-eol CRLF
|
||||||
svn export ./sounddsp bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/sounddsp --native-eol CRLF
|
svn export ./sounddsp bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/sounddsp --native-eol CRLF
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
|
||||||
|
README
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
OpenMPT and libopenmpt
|
OpenMPT and libopenmpt
|
||||||
======================
|
======================
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,11 @@
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
|
|
||||||
#define MPT_COMPILER_MSVC 1
|
#define MPT_COMPILER_MSVC 1
|
||||||
#if (_MSC_VER >= 1916)
|
#if (_MSC_VER >= 1921)
|
||||||
|
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2019,1)
|
||||||
|
#elif (_MSC_VER >= 1920)
|
||||||
|
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2019,0)
|
||||||
|
#elif (_MSC_VER >= 1916)
|
||||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2017,9)
|
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2017,9)
|
||||||
#elif (_MSC_VER >= 1915)
|
#elif (_MSC_VER >= 1915)
|
||||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2017,8)
|
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2017,8)
|
||||||
|
|
|
@ -56,7 +56,7 @@ void* align(std::size_t alignment, std::size_t size, void* &ptr, std::size_t &sp
|
||||||
|
|
||||||
aligned_raw_memory aligned_alloc_impl(std::size_t size, std::size_t count, std::size_t alignment)
|
aligned_raw_memory aligned_alloc_impl(std::size_t size, std::size_t count, std::size_t alignment)
|
||||||
{
|
{
|
||||||
#if MPT_CXX_AT_LEAST(17) && (!MPT_COMPILER_MSVC && !MPT_GCC_BEFORE(8,1,0) && !MPT_CLANG_BEFORE(5,0,0)) && !(MPT_COMPILER_CLANG && defined(__GLIBCXX__)) && !(MPT_COMPILER_CLANG && MPT_OS_MACOSX_OR_IOS) && !MPT_OS_EMSCRIPTEN
|
#if MPT_CXX_AT_LEAST(17) && (!MPT_COMPILER_MSVC && !MPT_GCC_BEFORE(8,1,0) && !MPT_CLANG_BEFORE(5,0,0)) && !(MPT_COMPILER_GCC && defined(__GLIBCXX__) && (defined(__MINGW32__) || defined(__MINGW64__))) && !(MPT_COMPILER_CLANG && defined(__GLIBCXX__)) && !(MPT_COMPILER_CLANG && MPT_OS_MACOSX_OR_IOS) && !MPT_OS_EMSCRIPTEN
|
||||||
std::size_t space = count * size;
|
std::size_t space = count * size;
|
||||||
void* mem = std::aligned_alloc(alignment, space);
|
void* mem = std::aligned_alloc(alignment, space);
|
||||||
if(!mem)
|
if(!mem)
|
||||||
|
@ -103,7 +103,7 @@ aligned_raw_memory aligned_alloc_impl(std::size_t size, std::size_t count, std::
|
||||||
|
|
||||||
void aligned_free(aligned_raw_memory raw)
|
void aligned_free(aligned_raw_memory raw)
|
||||||
{
|
{
|
||||||
#if MPT_CXX_AT_LEAST(17) && (!MPT_COMPILER_MSVC && !MPT_GCC_BEFORE(8,1,0) && !MPT_CLANG_BEFORE(5,0,0)) && !(MPT_COMPILER_CLANG && defined(__GLIBCXX__)) && !(MPT_COMPILER_CLANG && MPT_OS_MACOSX_OR_IOS) && !MPT_OS_EMSCRIPTEN
|
#if MPT_CXX_AT_LEAST(17) && (!MPT_COMPILER_MSVC && !MPT_GCC_BEFORE(8,1,0) && !MPT_CLANG_BEFORE(5,0,0)) && !(MPT_COMPILER_GCC && defined(__GLIBCXX__) && (defined(__MINGW32__) || defined(__MINGW64__))) && !(MPT_COMPILER_CLANG && defined(__GLIBCXX__)) && !(MPT_COMPILER_CLANG && MPT_OS_MACOSX_OR_IOS) && !MPT_OS_EMSCRIPTEN
|
||||||
std::free(raw.mem);
|
std::free(raw.mem);
|
||||||
#elif MPT_COMPILER_MSVC
|
#elif MPT_COMPILER_MSVC
|
||||||
_aligned_free(raw.mem);
|
_aligned_free(raw.mem);
|
||||||
|
|
|
@ -28,7 +28,7 @@ OPENMPT_NAMESPACE_BEGIN
|
||||||
namespace mpt
|
namespace mpt
|
||||||
{
|
{
|
||||||
|
|
||||||
template <typename T> T get_exception_text_impl(const std::exception & e) noexcept
|
template <typename T> T get_exception_text_impl(const std::exception & e)
|
||||||
{
|
{
|
||||||
if(e.what() && (std::strlen(e.what()) > 0))
|
if(e.what() && (std::strlen(e.what()) > 0))
|
||||||
{
|
{
|
||||||
|
@ -42,28 +42,28 @@ template <typename T> T get_exception_text_impl(const std::exception & e) noexce
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> inline T get_exception_text(const std::exception & e) noexcept
|
template <typename T> inline T get_exception_text(const std::exception & e)
|
||||||
{
|
{
|
||||||
return mpt::get_exception_text_impl<T>(e);
|
return mpt::get_exception_text_impl<T>(e);
|
||||||
}
|
}
|
||||||
template <> inline std::string get_exception_text<std::string>(const std::exception & e) noexcept
|
template <> inline std::string get_exception_text<std::string>(const std::exception & e)
|
||||||
{
|
{
|
||||||
return mpt::get_exception_text_impl<std::string>(e);
|
return mpt::get_exception_text_impl<std::string>(e);
|
||||||
}
|
}
|
||||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||||
template <> inline mpt::lstring get_exception_text<mpt::lstring>(const std::exception & e) noexcept
|
template <> inline mpt::lstring get_exception_text<mpt::lstring>(const std::exception & e)
|
||||||
{
|
{
|
||||||
return mpt::ToLocale(mpt::CharsetLocaleOrUTF8, mpt::get_exception_text_impl<std::string>(e));
|
return mpt::ToLocale(mpt::CharsetLocaleOrUTF8, mpt::get_exception_text_impl<std::string>(e));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if MPT_WSTRING_FORMAT
|
#if MPT_WSTRING_FORMAT
|
||||||
template <> inline std::wstring get_exception_text<std::wstring>(const std::exception & e) noexcept
|
template <> inline std::wstring get_exception_text<std::wstring>(const std::exception & e)
|
||||||
{
|
{
|
||||||
return mpt::ToWide(mpt::CharsetLocaleOrUTF8, mpt::get_exception_text_impl<std::string>(e));
|
return mpt::ToWide(mpt::CharsetLocaleOrUTF8, mpt::get_exception_text_impl<std::string>(e));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if MPT_USTRING_MODE_UTF8
|
#if MPT_USTRING_MODE_UTF8
|
||||||
template <> inline mpt::ustring get_exception_text<mpt::ustring>(const std::exception & e) noexcept
|
template <> inline mpt::ustring get_exception_text<mpt::ustring>(const std::exception & e)
|
||||||
{
|
{
|
||||||
return mpt::ToUnicode(mpt::CharsetLocaleOrUTF8, mpt::get_exception_text_impl<std::string>(e));
|
return mpt::ToUnicode(mpt::CharsetLocaleOrUTF8, mpt::get_exception_text_impl<std::string>(e));
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,6 +221,14 @@ void PathString::SplitPath(PathString *drive, PathString *dir, PathString *fname
|
||||||
}
|
}
|
||||||
mpt::RawPathString::size_type last_dot = p.find_last_of(PL_("."));
|
mpt::RawPathString::size_type last_dot = p.find_last_of(PL_("."));
|
||||||
if(last_dot == mpt::RawPathString::npos)
|
if(last_dot == mpt::RawPathString::npos)
|
||||||
|
{
|
||||||
|
if(fname) *fname = mpt::PathString::FromNative(p);
|
||||||
|
if(ext) *ext = mpt::PathString();
|
||||||
|
} else if(last_dot == 0)
|
||||||
|
{
|
||||||
|
if(fname) *fname = mpt::PathString::FromNative(p);
|
||||||
|
if(ext) *ext = mpt::PathString();
|
||||||
|
} else if(p == PL_(".") || p == PL_(".."))
|
||||||
{
|
{
|
||||||
if(fname) *fname = mpt::PathString::FromNative(p);
|
if(fname) *fname = mpt::PathString::FromNative(p);
|
||||||
if(ext) *ext = mpt::PathString();
|
if(ext) *ext = mpt::PathString();
|
||||||
|
|
|
@ -245,10 +245,17 @@ bool IsUTF8(const std::string &str);
|
||||||
#define MPT_LITERAL(x) x
|
#define MPT_LITERAL(x) x
|
||||||
#define MPT_STRING(x) std::string( x )
|
#define MPT_STRING(x) std::string( x )
|
||||||
|
|
||||||
|
#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
|
||||||
#define MPT_WCHAR_TYPE wchar_t
|
#define MPT_WCHAR_TYPE wchar_t
|
||||||
#define MPT_WCHAR(x) L ## x
|
#define MPT_WCHAR(x) L ## x
|
||||||
#define MPT_WLITERAL(x) L ## x
|
#define MPT_WLITERAL(x) L ## x
|
||||||
#define MPT_WSTRING(x) std::wstring( L ## x )
|
#define MPT_WSTRING(x) std::wstring( L ## x )
|
||||||
|
#else // MPT_COMPILER_QUIRK_NO_WCHAR
|
||||||
|
#define MPT_WCHAR_TYPE char32_t
|
||||||
|
#define MPT_WCHAR(x) U ## x
|
||||||
|
#define MPT_WLITERAL(x) U ## x
|
||||||
|
#define MPT_WSTRING(x) std::u32string( U ## x )
|
||||||
|
#endif // !MPT_COMPILER_QUIRK_NO_WCHAR
|
||||||
|
|
||||||
|
|
||||||
template <mpt::Charset charset_tag>
|
template <mpt::Charset charset_tag>
|
||||||
|
|
|
@ -185,7 +185,6 @@ public:
|
||||||
, mode(mode)
|
, mode(mode)
|
||||||
{
|
{
|
||||||
MPT_STATIC_ASSERT(sizeof(Tchar) == 1);
|
MPT_STATIC_ASSERT(sizeof(Tchar) == 1);
|
||||||
MPT_ASSERT(size > 0);
|
|
||||||
}
|
}
|
||||||
StringModeBufRefImpl(const StringModeBufRefImpl &) = delete;
|
StringModeBufRefImpl(const StringModeBufRefImpl &) = delete;
|
||||||
StringModeBufRefImpl(StringModeBufRefImpl &&) = default;
|
StringModeBufRefImpl(StringModeBufRefImpl &&) = default;
|
||||||
|
@ -218,7 +217,6 @@ public:
|
||||||
, mode(mode)
|
, mode(mode)
|
||||||
{
|
{
|
||||||
MPT_STATIC_ASSERT(sizeof(Tchar) == 1);
|
MPT_STATIC_ASSERT(sizeof(Tchar) == 1);
|
||||||
MPT_ASSERT(size > 0);
|
|
||||||
}
|
}
|
||||||
StringModeBufRefImpl(const StringModeBufRefImpl &) = delete;
|
StringModeBufRefImpl(const StringModeBufRefImpl &) = delete;
|
||||||
StringModeBufRefImpl(StringModeBufRefImpl &&) = default;
|
StringModeBufRefImpl(StringModeBufRefImpl &&) = default;
|
||||||
|
@ -400,6 +398,8 @@ namespace String
|
||||||
buffer[size - 1] = 0;
|
buffer[size - 1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
|
||||||
|
|
||||||
template <size_t size>
|
template <size_t size>
|
||||||
void SetNullTerminator(wchar_t (&buffer)[size])
|
void SetNullTerminator(wchar_t (&buffer)[size])
|
||||||
{
|
{
|
||||||
|
@ -413,6 +413,8 @@ namespace String
|
||||||
buffer[size - 1] = 0;
|
buffer[size - 1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // !MPT_COMPILER_QUIRK_NO_WCHAR
|
||||||
|
|
||||||
|
|
||||||
// Remove any chars after the first null char
|
// Remove any chars after the first null char
|
||||||
template <size_t size>
|
template <size_t size>
|
||||||
|
@ -633,6 +635,11 @@ namespace String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if MPT_GCC_AT_LEAST(8,1,0)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wstringop-truncation"
|
||||||
|
#endif
|
||||||
|
|
||||||
// Copy from a char array to a fixed size char array.
|
// Copy from a char array to a fixed size char array.
|
||||||
template <size_t destSize>
|
template <size_t destSize>
|
||||||
void CopyN(char (&destBuffer)[destSize], const char *srcBuffer, const size_t srcSize = std::numeric_limits<size_t>::max())
|
void CopyN(char (&destBuffer)[destSize], const char *srcBuffer, const size_t srcSize = std::numeric_limits<size_t>::max())
|
||||||
|
@ -676,6 +683,10 @@ namespace String
|
||||||
dest.assign(src);
|
dest.assign(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MPT_GCC_AT_LEAST(8,1,0)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if MPT_COMPILER_MSVC
|
#if MPT_COMPILER_MSVC
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
|
|
|
@ -20,7 +20,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 28
|
#define VER_MAJOR 28
|
||||||
#define VER_MINOR 03
|
#define VER_MINOR 05
|
||||||
#define VER_MINORMINOR 00
|
#define VER_MINORMINOR 00
|
||||||
|
|
||||||
//Numerical value of the version.
|
//Numerical value of the version.
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
|
||||||
|
Contributing
|
||||||
|
============
|
||||||
|
|
||||||
|
OpenMPT, libopenmpt, openmpt123, xmp-openmpt, in_openmpt and foo_openmpt are
|
||||||
|
developed in the Subversion repository at
|
||||||
|
[https://source.openmpt.org/browse/openmpt/trunk/OpenMPT/](https://source.openmpt.org/browse/openmpt/trunk/OpenMPT/).
|
||||||
|
Patches can be provided either against this Subversion repository or against our
|
||||||
|
GitHub mirror at
|
||||||
|
[https://github.com/OpenMPT/openmpt/](https://github.com/OpenMPT/openmpt/).
|
||||||
|
|
||||||
|
We do not have a developer mailing list. Discussions about new features or
|
||||||
|
problems can happen at:
|
||||||
|
* [Issue Tracker](https://bugs.openmpt.org/), preferred for specific bug
|
||||||
|
reports or bug fixes and feature development discussion
|
||||||
|
* [Forum](https://forum.openmpt.org/), preferred for long-term discussion of
|
||||||
|
new features or specific questions about development
|
||||||
|
* [IRC channel (`EsperNET/#modplug`)](irc://irc.esper.net:5555/#modplug),
|
||||||
|
preferred for shorter questions
|
||||||
|
* [GitHub pull requests](https://github.com/OpenMPT/openmpt/pulls), please
|
||||||
|
only use for rather tiny fixes, see below
|
||||||
|
|
||||||
|
For patch submissions, please also see
|
||||||
|
[OpenMPT style guide](openmpt_styleguide.md) and
|
||||||
|
[libopenmpt style guide](libopenmpt_styleguide.md).
|
||||||
|
|
||||||
|
### Contributing via GitHub
|
||||||
|
|
||||||
|
As OpenMPT is developed in a Subversion repository and the GitHub repository is
|
||||||
|
just mirrored from that, we cannot directly take pull requests via GitHub. We
|
||||||
|
recognize that, especially for tiny bug fixes, the burden to choose a different
|
||||||
|
way than GitHub for contributing can be too high. Thus, we will of course react,
|
||||||
|
give feedback, and take patches also via GitHub pull requests. However, as the
|
||||||
|
GitHub repository is strictly downstream from our Subversion repository (and
|
||||||
|
this will not change, due to considerable complications when synchronizing this
|
||||||
|
two-way), we cannot directly merge pull requests on GitHub. We will merge
|
||||||
|
contributions to our Subversion repository, which will then in turn be mirrored
|
||||||
|
to GitHub automatically, after which we will close the pull request. Authorship
|
||||||
|
attribution in git relies on the email address used in the commit header, which
|
||||||
|
is not how it usually works in Subversion. We will thus add an additional line
|
||||||
|
to the commit message in the form of `Patch-by: John Doe <user@example.com>`. If
|
||||||
|
you prefer to be attributed with your nickname and/or without your email
|
||||||
|
address, that would also be fine for us.
|
|
@ -0,0 +1,104 @@
|
||||||
|
|
||||||
|
Coding conventions
|
||||||
|
------------------
|
||||||
|
|
||||||
|
|
||||||
|
### libopenmpt
|
||||||
|
|
||||||
|
**Note:**
|
||||||
|
**This applies to `libopenmpt/` and `openmpt123/` directories only.**
|
||||||
|
**Use OpenMPT style otherwise.**
|
||||||
|
|
||||||
|
The code generally tries to follow these conventions, but they are not
|
||||||
|
strictly enforced and there are valid reasons to diverge from these
|
||||||
|
conventions. Using common sense is recommended.
|
||||||
|
|
||||||
|
- In general, the most important thing is to keep style consistent with
|
||||||
|
directly surrounding code.
|
||||||
|
- Use C++ std types when possible, prefer `std::size_t` and `std::int32_t`
|
||||||
|
over `long` or `int`. Do not use C99 std types (e.g. no pure `int32_t`)
|
||||||
|
- Qualify namespaces explicitly, do not use `using`.
|
||||||
|
Members of `namespace openmpt` can be named without full namespace
|
||||||
|
qualification.
|
||||||
|
- Prefer the C++ version in `namespace std` if the same functionality is
|
||||||
|
provided by the C standard library as well. Also, include the C++
|
||||||
|
version of C standard library headers (e.g. use `<cstdio>` instead of
|
||||||
|
`<stdio.h>`.
|
||||||
|
- Do not use ANY locale-dependant C functions. For locale-dependant C++
|
||||||
|
functionaly (especially iostream), always imbue the
|
||||||
|
`std::locale::classic()` locale.
|
||||||
|
- Prefer kernel_style_names over CamelCaseNames.
|
||||||
|
- If a folder (or one of its parent folders) contains .clang-format,
|
||||||
|
use clang-format v3.5 for indenting C++ and C files, otherwise:
|
||||||
|
- `{` are placed at the end of the opening line.
|
||||||
|
- Enclose even single statements in curly braces.
|
||||||
|
- Avoid placing single statements on the same line as the `if`.
|
||||||
|
- Opening parentheses are separated from keywords with a space.
|
||||||
|
- Opening parentheses are not separated from function names.
|
||||||
|
- Place spaces around operators and inside parentheses.
|
||||||
|
- Align `:` and `,` when inheriting or initializing members in a
|
||||||
|
constructor.
|
||||||
|
- The pointer `*` is separated from both the type and the variable name.
|
||||||
|
- Use tabs for identation, spaces for formatting.
|
||||||
|
Tabs should only appear at the very beginning of a line.
|
||||||
|
Do not assume any particular width of the TAB character. If width is
|
||||||
|
important for formatting reasons, use spaces.
|
||||||
|
- Use empty lines at will.
|
||||||
|
- API documentation is done with doxygen.
|
||||||
|
Use general C doxygen for the C API.
|
||||||
|
Use QT-style doxygen for the C++ API.
|
||||||
|
|
||||||
|
#### libopenmpt indentation example
|
||||||
|
|
||||||
|
~~~~{.cpp}
|
||||||
|
namespace openmpt {
|
||||||
|
|
||||||
|
// This is totally meaningless code and just illustrates indentation.
|
||||||
|
|
||||||
|
class foo
|
||||||
|
: public base
|
||||||
|
, public otherbase
|
||||||
|
{
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::int32_t x;
|
||||||
|
std::int16_t y;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
foo()
|
||||||
|
: x(0)
|
||||||
|
, y(-1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bar() const;
|
||||||
|
|
||||||
|
}; // class foo
|
||||||
|
|
||||||
|
int foo::bar() const {
|
||||||
|
|
||||||
|
for ( int i = 0; i < 23; ++i ) {
|
||||||
|
switch ( x ) {
|
||||||
|
case 2:
|
||||||
|
something( y );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
something( ( y - 1 ) * 2 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( x == 12 ) {
|
||||||
|
return -1;
|
||||||
|
} else if ( x == 42 ) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 42;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace openmpt
|
||||||
|
~~~~
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
How to add support for new module formats
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
This document describes the basics of writing a new module loader and related
|
||||||
|
work that has to be done. We will not discuss in detail how to write the loader,
|
||||||
|
have a look at existing loaders to get an idea how they work in general.
|
||||||
|
|
||||||
|
General hints
|
||||||
|
-------------
|
||||||
|
* We strive for quality over quantity. The goal is not to support as many module
|
||||||
|
formats as possible, but to support them as well as possible.
|
||||||
|
* Write defensive code. Guard against out-of-bound values, division by zero and
|
||||||
|
similar stuff. libopenmpt is constantly fuzz-tested to catch any crashes, but
|
||||||
|
of course we want our code to be reliable from the start.
|
||||||
|
* Every format should have its own `MODTYPE` flag, unless it can be reasonably
|
||||||
|
represented as a subset of another format (like Ice Tracker ICE files being
|
||||||
|
a subset of ProTracker MOD).
|
||||||
|
* When reading binary structs from the file, use our data types with defined
|
||||||
|
endianness, which can be found in `common/Endianness.h`:
|
||||||
|
* Big-Endian: (u)int8/16/32/64be, float32be, float64be
|
||||||
|
* Little-Endian: (u)int8/16/32/64le, float32le, float64le
|
||||||
|
|
||||||
|
Entire structs containing integers with defined endianness can be read in one
|
||||||
|
go if they are tagged with `MPT_BINARY_STRUCT` (see existing loaders for an
|
||||||
|
example).
|
||||||
|
* `m_nChannels` **MUST NOT** be changed after a pattern has been created, as
|
||||||
|
existing patterns will be interpreted incorrectly. For module formats that
|
||||||
|
support per-pattern channel amounts, the maximum number of channels must be
|
||||||
|
determined beforehand.
|
||||||
|
* Strings can be safely handled using:
|
||||||
|
* `FileReader::ReadString` and friends for reading them directly from a file
|
||||||
|
* `mpt::String::Read` for reading them from a struct or char array,
|
||||||
|
* `mpt::String::Copy` for copying between char arrays or `std::string`.
|
||||||
|
|
||||||
|
"Read" functions take care of string padding (zero / space padding), so those
|
||||||
|
should be used when extracting strings from files. "Copy" should only be used
|
||||||
|
on strings that have previously been read using the "Read" functions.
|
||||||
|
If the target is a char array rather than a `std::string`, these will take
|
||||||
|
care of properly null-terminating the target char array, and prevent reading
|
||||||
|
past the end of a (supposedly null-terminated) source char array.
|
||||||
|
* Do not use non-const static variables in your loader. Loaders need to be
|
||||||
|
thread-safe for libopenmpt.
|
||||||
|
* `FileReader` instances may be used to treat a portion of another file as its
|
||||||
|
own independent file (through `FileReader::ReadChunk`). This can be useful
|
||||||
|
with "embedded files" such as WAV or Ogg samples. Container formats are
|
||||||
|
another good example for this usage.
|
||||||
|
* Samples *either* use middle-C frequency *or* finetune + transpose. For the few
|
||||||
|
weird formats that use both, it may make sense to translate everything into
|
||||||
|
middle-C frequency.
|
||||||
|
* Add the new `MODTYPE` to `CSoundFile::UseFinetuneAndTranspose` if applicable,
|
||||||
|
and see if any effect handlers in `soundlib/Snd_fx.cpp` need to know the new
|
||||||
|
`MODTYPE`.
|
||||||
|
* Do not rely on hard-coded magic numbers. For example, when comparing if an
|
||||||
|
index is valid for a given array, do not hard-code the array size but rather
|
||||||
|
use `mpt::size` or, for ensuring that char arrays are null-terminated,
|
||||||
|
`mpt::String::SetNullTerminator`. Similarly, do not assume any specific
|
||||||
|
quantities for OpenMPT's constants like MAX_SAMPLES, MAX_PATTERN_ROWS, etc.
|
||||||
|
These may change at any time.
|
||||||
|
* Pay attention to off-by-one errors when comparing against MAX_SAMPLES and
|
||||||
|
MAX_INSTRUMENTS, since sample and instrument numbers are 1-based.
|
||||||
|
* Placement of the loader function in `CSoundFile::Create` depends on various
|
||||||
|
factors. In general, module formats that have very bad magic numbers (and thus
|
||||||
|
might cause other formats to get mis-interpreted) should be placed at the
|
||||||
|
bottom of the list. Two notable examples are 669 files, where the first two
|
||||||
|
bytes of the file are "if" (which may e.g. cause a song title starting with
|
||||||
|
"if ..." in various other formats to be interpreted as a 669 module), and of
|
||||||
|
course Ultimate SoundTracker modules, which have no magic bytes at all.
|
||||||
|
* Avoid use of functions tagged with MPT_DEPRECATED.
|
||||||
|
|
||||||
|
Probing
|
||||||
|
-------
|
||||||
|
libopenmpt provides fast probing functions that can be used by library users
|
||||||
|
to quickly check if a file is most likely playable with libopenmpt, even if only
|
||||||
|
a fraction of the file is available (e.g. when streaming from the internet).
|
||||||
|
|
||||||
|
In order to satisfy these requirements, probing functions should do as little
|
||||||
|
work as possible (e.g. only parse the header of the file), but as much as
|
||||||
|
required to tell with some certainty that the file is really of a certain mod
|
||||||
|
format. However, probing functions should not rely on having access to more than
|
||||||
|
the first `CSoundFile::ProbeRecommendedSize` bytes of the file.
|
||||||
|
|
||||||
|
* Probing functions **must not** allocate any memory on the heap.
|
||||||
|
* Probing functions **must not** return ProbeFailure or ProbeWantMoreData for
|
||||||
|
any file that would normally be accepted by the loader. In particular, this
|
||||||
|
means that any header checks must not be any more aggressive than they would
|
||||||
|
be in the real loader (hence it is a good idea to not copy-paste this code but
|
||||||
|
rather put it in a separate function), and the minimum additional size passed
|
||||||
|
to `CSoundFile::ProbeAdditionalSize` must not be higher than the biggest size
|
||||||
|
that would cause a hard failure (i.e. returning `false`) in the module loader.
|
||||||
|
* Probing functions **may** return ProbeSuccess for files that would be rejected
|
||||||
|
by a loader after a more thorough inspection. For example, probing functions
|
||||||
|
do not need to verify that all required chunks of an IFF-like file format are
|
||||||
|
actually present, if the header makes it obvious enough that the file is
|
||||||
|
highly likely to be a module.
|
||||||
|
|
||||||
|
Adding loader to the build systems and various other locations
|
||||||
|
--------------------------------------------------------------
|
||||||
|
Apart from writing the module loader itself, there are a couple of other places
|
||||||
|
that need to be updated:
|
||||||
|
* Add loader file to `build/android_ndk/Android.mk`.
|
||||||
|
* Add loader file to `build/autotools/Makefile.am`.
|
||||||
|
* Run `build/regenerate_vs_projects.sh` / `build/regenerate_vs_projects.cmd`
|
||||||
|
(depending on your platform)
|
||||||
|
* Add file extension to `installer/filetypes.iss` (in four places).
|
||||||
|
* Add file extension to `CTrackApp::OpenModulesDialog` in `mptrack/Mptrack.cpp`.
|
||||||
|
* Add format information to `soundlib/Tables.cpp`.
|
|
@ -1,6 +1,6 @@
|
||||||
This folder contains the stb_vorbis library from
|
This folder contains the stb_vorbis library from
|
||||||
https://github.com/nothings/stb/blob/master/stb_vorbis.c v1.15
|
https://github.com/nothings/stb/blob/master/stb_vorbis.c v1.16
|
||||||
commit 59e9702be5bfc0061e756c7beab7dcd3d363400d (2019-02-07)
|
commit 2c2908f50515dcd939f24be261c3ccbcd277bb49 (2019-03-05)
|
||||||
|
|
||||||
Modifications:
|
Modifications:
|
||||||
* Use of alloca has been replaced with malloc, as alloca is not in C99 and
|
* Use of alloca has been replaced with malloc, as alloca is not in C99 and
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Ogg Vorbis audio decoder - v1.15 - public domain
|
// Ogg Vorbis audio decoder - v1.16 - public domain
|
||||||
// http://nothings.org/stb_vorbis/
|
// http://nothings.org/stb_vorbis/
|
||||||
//
|
//
|
||||||
// Original version written by Sean Barrett in 2007.
|
// Original version written by Sean Barrett in 2007.
|
||||||
|
@ -33,6 +33,7 @@
|
||||||
// Timur Gagiev
|
// Timur Gagiev
|
||||||
//
|
//
|
||||||
// Partial history:
|
// Partial history:
|
||||||
|
// 1.16 - 2019-03-04 - fix warnings
|
||||||
// 1.15 - 2019-02-07 - explicit failure if Ogg Skeleton data is found
|
// 1.15 - 2019-02-07 - explicit failure if Ogg Skeleton data is found
|
||||||
// 1.14 - 2018-02-11 - delete bogus dealloca usage
|
// 1.14 - 2018-02-11 - delete bogus dealloca usage
|
||||||
// 1.13 - 2018-01-29 - fix truncation of last frame (hopefully)
|
// 1.13 - 2018-01-29 - fix truncation of last frame (hopefully)
|
||||||
|
@ -5004,7 +5005,13 @@ stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, con
|
||||||
|
|
||||||
stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc)
|
stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc)
|
||||||
{
|
{
|
||||||
FILE *f = fopen(filename, "rb");
|
FILE *f;
|
||||||
|
#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__)
|
||||||
|
if (0 != fopen_s(&f, filename, "rb"))
|
||||||
|
f = NULL;
|
||||||
|
#else
|
||||||
|
f = fopen(filename, "rb");
|
||||||
|
#endif
|
||||||
if (f)
|
if (f)
|
||||||
return stb_vorbis_open_file(f, TRUE, error, alloc);
|
return stb_vorbis_open_file(f, TRUE, error, alloc);
|
||||||
if (error) *error = VORBIS_file_open_failure;
|
if (error) *error = VORBIS_file_open_failure;
|
||||||
|
|
|
@ -785,9 +785,12 @@ INPUT = libopenmpt/dox/index.dox \
|
||||||
README.md \
|
README.md \
|
||||||
libopenmpt/dox/dependencies.md \
|
libopenmpt/dox/dependencies.md \
|
||||||
libopenmpt/dox/packaging.md \
|
libopenmpt/dox/packaging.md \
|
||||||
|
doc/contributing.md \
|
||||||
|
doc/libopenmpt_styleguide.md \
|
||||||
libopenmpt/dox/tests.md \
|
libopenmpt/dox/tests.md \
|
||||||
libopenmpt/dox/changelog.md \
|
libopenmpt/dox/changelog.md \
|
||||||
libopenmpt/dox/todo.md \
|
libopenmpt/dox/todo.md \
|
||||||
|
doc/module_formats.md \
|
||||||
libopenmpt/libopenmpt.hpp \
|
libopenmpt/libopenmpt.hpp \
|
||||||
libopenmpt/libopenmpt.h \
|
libopenmpt/libopenmpt.h \
|
||||||
libopenmpt/libopenmpt_stream_callbacks_buffer.h \
|
libopenmpt/libopenmpt_stream_callbacks_buffer.h \
|
||||||
|
|
|
@ -5,6 +5,28 @@ 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.4.5 (2019-05-27)
|
||||||
|
|
||||||
|
* [**Sec**] Possible crash during playback due out-of-bounds read in XM and
|
||||||
|
MT2 files (r11608).
|
||||||
|
|
||||||
|
* Breaking out of a sustain loop through Note-Off sometimes didn't continue in
|
||||||
|
the regular sample loop.
|
||||||
|
* Seeking did not stop notes playing with XM Key Off (Kxx) effect.
|
||||||
|
|
||||||
|
### libopenmpt 0.4.4 (2019-04-07)
|
||||||
|
|
||||||
|
* [**Bug**] Channel VU meters were swapped.
|
||||||
|
|
||||||
|
* Startrekker: Clamp speed to 31 ticks per row.
|
||||||
|
* MTM: Ignore unused Exy commands on import. Command E5x (Set Finetune) is now
|
||||||
|
applied correctly.
|
||||||
|
* MOD: Sample swapping was always enabled since it has been separated from the
|
||||||
|
ProTracker 1/2 compatibility flag. Now it is always enabled for Amiga-style
|
||||||
|
modules and otherwise the old heuristic is used again.
|
||||||
|
|
||||||
|
* stb_vorbis: Update to v1.16 (2019-03-05).
|
||||||
|
|
||||||
### libopenmpt 0.4.3 (2019-02-11)
|
### libopenmpt 0.4.3 (2019-02-11)
|
||||||
|
|
||||||
* [**Sec**] Possible crash due to null-pointer access when doing a portamento
|
* [**Sec**] Possible crash due to null-pointer access when doing a portamento
|
||||||
|
|
|
@ -11,8 +11,11 @@
|
||||||
* - \ref md_README "README"
|
* - \ref md_README "README"
|
||||||
* - \ref dependencies "Dependencies"
|
* - \ref dependencies "Dependencies"
|
||||||
* - \ref packaging "Packaging"
|
* - \ref packaging "Packaging"
|
||||||
|
* - \ref md_doc_contributing "Contributing"
|
||||||
|
* - \ref md_doc_libopenmpt_styleguide "Style Guide"
|
||||||
* - \ref tests "Tests"
|
* - \ref tests "Tests"
|
||||||
* - \ref changelog "Changelog"
|
* - \ref changelog "Changelog"
|
||||||
|
* - \ref md_doc_module_formats "Implementing new Module Formats"
|
||||||
* - \ref todo "TODO"
|
* - \ref todo "TODO"
|
||||||
* \subsection toc_apis APIs
|
* \subsection toc_apis APIs
|
||||||
* - libopenmpt
|
* - libopenmpt
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
/*! \brief libopenmpt minor version number */
|
/*! \brief libopenmpt minor version number */
|
||||||
#define OPENMPT_API_VERSION_MINOR 4
|
#define OPENMPT_API_VERSION_MINOR 4
|
||||||
/*! \brief libopenmpt patch version number */
|
/*! \brief libopenmpt patch version number */
|
||||||
#define OPENMPT_API_VERSION_PATCH 3
|
#define OPENMPT_API_VERSION_PATCH 5
|
||||||
/*! \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=4
|
LIBOPENMPT_VERSION_MINOR=4
|
||||||
LIBOPENMPT_VERSION_PATCH=3
|
LIBOPENMPT_VERSION_PATCH=5
|
||||||
LIBOPENMPT_VERSION_PREREL=
|
LIBOPENMPT_VERSION_PREREL=
|
||||||
|
|
||||||
LIBOPENMPT_LTVER_CURRENT=1
|
LIBOPENMPT_LTVER_CURRENT=1
|
||||||
LIBOPENMPT_LTVER_REVISION=3
|
LIBOPENMPT_LTVER_REVISION=5
|
||||||
LIBOPENMPT_LTVER_AGE=1
|
LIBOPENMPT_LTVER_AGE=1
|
||||||
|
|
|
@ -29,11 +29,11 @@ enum SampleFormatEnum
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Tsample> struct SampleFormatTraits;
|
template<typename Tsample> struct SampleFormatTraits;
|
||||||
template<> struct SampleFormatTraits<uint8> { static MPT_CONSTEXPR11_VAR SampleFormatEnum sampleFormat = SampleFormatUnsigned8; };
|
template<> struct SampleFormatTraits<uint8> { static MPT_CONSTEXPR11_FUN SampleFormatEnum sampleFormat() { return SampleFormatUnsigned8; } };
|
||||||
template<> struct SampleFormatTraits<int16> { static MPT_CONSTEXPR11_VAR SampleFormatEnum sampleFormat = SampleFormatInt16; };
|
template<> struct SampleFormatTraits<int16> { static MPT_CONSTEXPR11_FUN SampleFormatEnum sampleFormat() { return SampleFormatInt16; } };
|
||||||
template<> struct SampleFormatTraits<int24> { static MPT_CONSTEXPR11_VAR SampleFormatEnum sampleFormat = SampleFormatInt24; };
|
template<> struct SampleFormatTraits<int24> { static MPT_CONSTEXPR11_FUN SampleFormatEnum sampleFormat() { return SampleFormatInt24; } };
|
||||||
template<> struct SampleFormatTraits<int32> { static MPT_CONSTEXPR11_VAR SampleFormatEnum sampleFormat = SampleFormatInt32; };
|
template<> struct SampleFormatTraits<int32> { static MPT_CONSTEXPR11_FUN SampleFormatEnum sampleFormat() { return SampleFormatInt32; } };
|
||||||
template<> struct SampleFormatTraits<float> { static MPT_CONSTEXPR11_VAR SampleFormatEnum sampleFormat = SampleFormatFloat32; };
|
template<> struct SampleFormatTraits<float> { static MPT_CONSTEXPR11_FUN SampleFormatEnum sampleFormat() { return SampleFormatFloat32; } };
|
||||||
|
|
||||||
template<SampleFormatEnum sampleFormat> struct SampleFormatToType;
|
template<SampleFormatEnum sampleFormat> struct SampleFormatToType;
|
||||||
template<> struct SampleFormatToType<SampleFormatUnsigned8> { typedef uint8 type; };
|
template<> struct SampleFormatToType<SampleFormatUnsigned8> { typedef uint8 type; };
|
||||||
|
|
|
@ -40,7 +40,7 @@ public:
|
||||||
, outputBuffer(buffer)
|
, outputBuffer(buffer)
|
||||||
, outputBuffers(buffers)
|
, outputBuffers(buffers)
|
||||||
{
|
{
|
||||||
MPT_ASSERT(SampleFormat(SampleFormatTraits<Tsample>::sampleFormat).IsValid());
|
MPT_ASSERT(SampleFormat(SampleFormatTraits<Tsample>::sampleFormat()).IsValid());
|
||||||
}
|
}
|
||||||
std::size_t GetRenderedCount() const { return countRendered; }
|
std::size_t GetRenderedCount() const { return countRendered; }
|
||||||
public:
|
public:
|
||||||
|
@ -48,7 +48,7 @@ public:
|
||||||
{
|
{
|
||||||
// Convert to output sample format and optionally perform dithering and clipping if needed
|
// Convert to output sample format and optionally perform dithering and clipping if needed
|
||||||
|
|
||||||
const SampleFormat sampleFormat = SampleFormatTraits<Tsample>::sampleFormat;
|
const SampleFormat sampleFormat = SampleFormatTraits<Tsample>::sampleFormat();
|
||||||
|
|
||||||
if(sampleFormat.IsInt())
|
if(sampleFormat.IsInt())
|
||||||
{
|
{
|
||||||
|
|
|
@ -120,9 +120,9 @@ PSB. PanEnv.nSustainStart;
|
||||||
PSE. PanEnv.nSustainEnd;
|
PSE. PanEnv.nSustainEnd;
|
||||||
PTTL pitchToTempoLock;
|
PTTL pitchToTempoLock;
|
||||||
PTTF pitchToTempoLock (fractional part);
|
PTTF pitchToTempoLock (fractional part);
|
||||||
PVEH nPluginVelocityHandling;
|
PVEH pluginVelocityHandling;
|
||||||
PVOH nPluginVolumeHandling;
|
PVOH pluginVolumeHandling;
|
||||||
R... nResampling;
|
R... resampling;
|
||||||
RP.. [EXT] nRestartPos;
|
RP.. [EXT] nRestartPos;
|
||||||
RPB. [EXT] nRowsPerBeat;
|
RPB. [EXT] nRowsPerBeat;
|
||||||
RPM. [EXT] nRowsPerMeasure;
|
RPM. [EXT] nRowsPerMeasure;
|
||||||
|
@ -314,12 +314,12 @@ if(!writeAll)
|
||||||
WRITE_MPTHEADER_envelope_member( ENV_PITCH , value , uint8 , MagicBE("PiE[") )
|
WRITE_MPTHEADER_envelope_member( ENV_PITCH , value , uint8 , MagicBE("PiE[") )
|
||||||
WRITE_MPTHEADER_sized_member( nMixPlug , uint8 , MagicBE("MiP.") )
|
WRITE_MPTHEADER_sized_member( nMixPlug , uint8 , MagicBE("MiP.") )
|
||||||
WRITE_MPTHEADER_sized_member( nVolRampUp , uint16 , MagicBE("VR..") )
|
WRITE_MPTHEADER_sized_member( nVolRampUp , uint16 , MagicBE("VR..") )
|
||||||
WRITE_MPTHEADER_trunc_member( nResampling , uint16 , MagicBE("R...") )
|
WRITE_MPTHEADER_sized_member( resampling , uint8 , MagicBE("R...") )
|
||||||
WRITE_MPTHEADER_sized_member( nCutSwing , uint8 , MagicBE("CS..") )
|
WRITE_MPTHEADER_sized_member( nCutSwing , uint8 , MagicBE("CS..") )
|
||||||
WRITE_MPTHEADER_sized_member( nResSwing , uint8 , MagicBE("RS..") )
|
WRITE_MPTHEADER_sized_member( nResSwing , uint8 , MagicBE("RS..") )
|
||||||
WRITE_MPTHEADER_sized_member( nFilterMode , uint8 , MagicBE("FM..") )
|
WRITE_MPTHEADER_sized_member( nFilterMode , uint8 , MagicBE("FM..") )
|
||||||
WRITE_MPTHEADER_sized_member( nPluginVelocityHandling , uint8 , MagicBE("PVEH") )
|
WRITE_MPTHEADER_sized_member( pluginVelocityHandling , uint8 , MagicBE("PVEH") )
|
||||||
WRITE_MPTHEADER_sized_member( nPluginVolumeHandling , uint8 , MagicBE("PVOH") )
|
WRITE_MPTHEADER_sized_member( pluginVolumeHandling , uint8 , MagicBE("PVOH") )
|
||||||
WRITE_MPTHEADER_trunc_member( pitchToTempoLock.GetInt() , uint16 , MagicBE("PTTL") )
|
WRITE_MPTHEADER_trunc_member( pitchToTempoLock.GetInt() , uint16 , MagicBE("PTTL") )
|
||||||
WRITE_MPTHEADER_trunc_member( pitchToTempoLock.GetFract() , uint16 , MagicLE("PTTF") )
|
WRITE_MPTHEADER_trunc_member( pitchToTempoLock.GetFract() , uint16 , MagicLE("PTTF") )
|
||||||
WRITE_MPTHEADER_sized_member( PitchEnv.nReleaseNode , uint8 , MagicBE("PERN") )
|
WRITE_MPTHEADER_sized_member( PitchEnv.nReleaseNode , uint8 , MagicBE("PERN") )
|
||||||
|
@ -373,9 +373,9 @@ void CSoundFile::SaveExtendedInstrumentProperties(INSTRUMENTINDEX numInstruments
|
||||||
WritePropertyIfNeeded(*this, &ModInstrument::nMidiChannel, MagicBE("MC.."), sizeof(ModInstrument::nMidiChannel), f, numInstruments);
|
WritePropertyIfNeeded(*this, &ModInstrument::nMidiChannel, MagicBE("MC.."), sizeof(ModInstrument::nMidiChannel), f, numInstruments);
|
||||||
WritePropertyIfNeeded(*this, &ModInstrument::nMidiProgram, MagicBE("MP.."), sizeof(ModInstrument::nMidiProgram), f, numInstruments);
|
WritePropertyIfNeeded(*this, &ModInstrument::nMidiProgram, MagicBE("MP.."), sizeof(ModInstrument::nMidiProgram), f, numInstruments);
|
||||||
WritePropertyIfNeeded(*this, &ModInstrument::wMidiBank, MagicBE("MB.."), sizeof(ModInstrument::wMidiBank), f, numInstruments);
|
WritePropertyIfNeeded(*this, &ModInstrument::wMidiBank, MagicBE("MB.."), sizeof(ModInstrument::wMidiBank), f, numInstruments);
|
||||||
WritePropertyIfNeeded(*this, &ModInstrument::nResampling, MagicBE("R..."), sizeof(ModInstrument::nResampling), f, numInstruments);
|
WritePropertyIfNeeded(*this, &ModInstrument::resampling, MagicBE("R..."), sizeof(ModInstrument::resampling), f, numInstruments);
|
||||||
WritePropertyIfNeeded(*this, &ModInstrument::nPluginVelocityHandling, MagicBE("PVEH"), sizeof(ModInstrument::nPluginVelocityHandling), f, numInstruments);
|
WritePropertyIfNeeded(*this, &ModInstrument::pluginVelocityHandling, MagicBE("PVEH"), sizeof(ModInstrument::pluginVelocityHandling), f, numInstruments);
|
||||||
WritePropertyIfNeeded(*this, &ModInstrument::nPluginVolumeHandling, MagicBE("PVOH"), sizeof(ModInstrument::nPluginVolumeHandling), f, numInstruments);
|
WritePropertyIfNeeded(*this, &ModInstrument::pluginVolumeHandling, MagicBE("PVOH"), sizeof(ModInstrument::pluginVolumeHandling), f, numInstruments);
|
||||||
|
|
||||||
if(!(GetType() & MOD_TYPE_XM))
|
if(!(GetType() & MOD_TYPE_XM))
|
||||||
{
|
{
|
||||||
|
@ -579,12 +579,11 @@ bool ReadInstrumentHeaderField(ModInstrument *input, uint32 fcode, uint16 fsize,
|
||||||
GET_MPTHEADER_chararray_member( filename , char , MagicBE("fn[.") )
|
GET_MPTHEADER_chararray_member( filename , char , MagicBE("fn[.") )
|
||||||
GET_MPTHEADER_sized_member( nMixPlug , uint8 , MagicBE("MiP.") )
|
GET_MPTHEADER_sized_member( nMixPlug , uint8 , MagicBE("MiP.") )
|
||||||
GET_MPTHEADER_sized_member( nVolRampUp , uint16 , MagicBE("VR..") )
|
GET_MPTHEADER_sized_member( nVolRampUp , uint16 , MagicBE("VR..") )
|
||||||
GET_MPTHEADER_sized_member( nResampling , uint32 , MagicBE("R...") )
|
|
||||||
GET_MPTHEADER_sized_member( nCutSwing , uint8 , MagicBE("CS..") )
|
GET_MPTHEADER_sized_member( nCutSwing , uint8 , MagicBE("CS..") )
|
||||||
GET_MPTHEADER_sized_member( nResSwing , uint8 , MagicBE("RS..") )
|
GET_MPTHEADER_sized_member( nResSwing , uint8 , MagicBE("RS..") )
|
||||||
GET_MPTHEADER_sized_member( nFilterMode , uint8 , MagicBE("FM..") )
|
GET_MPTHEADER_sized_member( nFilterMode , uint8 , MagicBE("FM..") )
|
||||||
GET_MPTHEADER_sized_member( nPluginVelocityHandling , uint8 , MagicBE("PVEH") )
|
GET_MPTHEADER_sized_member( pluginVelocityHandling , uint8 , MagicBE("PVEH") )
|
||||||
GET_MPTHEADER_sized_member( nPluginVolumeHandling , uint8 , MagicBE("PVOH") )
|
GET_MPTHEADER_sized_member( pluginVolumeHandling , uint8 , MagicBE("PVOH") )
|
||||||
GET_MPTHEADER_sized_member( PitchEnv.nReleaseNode , uint8 , MagicBE("PERN") )
|
GET_MPTHEADER_sized_member( PitchEnv.nReleaseNode , uint8 , MagicBE("PERN") )
|
||||||
GET_MPTHEADER_sized_member( PanEnv.nReleaseNode , uint8 , MagicBE("AERN") )
|
GET_MPTHEADER_sized_member( PanEnv.nReleaseNode , uint8 , MagicBE("AERN") )
|
||||||
GET_MPTHEADER_sized_member( VolEnv.nReleaseNode , uint8 , MagicBE("VERN") )
|
GET_MPTHEADER_sized_member( VolEnv.nReleaseNode , uint8 , MagicBE("VERN") )
|
||||||
|
@ -592,6 +591,14 @@ bool ReadInstrumentHeaderField(ModInstrument *input, uint32 fcode, uint16 fsize,
|
||||||
GET_MPTHEADER_sized_member( PanEnv.dwFlags , uint8 , MagicBE("AFLG") )
|
GET_MPTHEADER_sized_member( PanEnv.dwFlags , uint8 , MagicBE("AFLG") )
|
||||||
GET_MPTHEADER_sized_member( VolEnv.dwFlags , uint8 , MagicBE("VFLG") )
|
GET_MPTHEADER_sized_member( VolEnv.dwFlags , uint8 , MagicBE("VFLG") )
|
||||||
GET_MPTHEADER_sized_member( midiPWD , int8 , MagicBE("MPWD") )
|
GET_MPTHEADER_sized_member( midiPWD , int8 , MagicBE("MPWD") )
|
||||||
|
case MagicBE("R..."):
|
||||||
|
{
|
||||||
|
// Resampling has been written as various sizes including uint16 and uint32 in the past
|
||||||
|
uint32 tmp = file.ReadTruncatedIntLE<uint32>(fsize);
|
||||||
|
if(Resampling::IsKnownMode(tmp))
|
||||||
|
input->resampling = static_cast<ResamplingMode>(tmp);
|
||||||
|
result = true;
|
||||||
|
} break;
|
||||||
case MagicBE("PTTL"):
|
case MagicBE("PTTL"):
|
||||||
{
|
{
|
||||||
// Integer part of pitch/tempo lock
|
// Integer part of pitch/tempo lock
|
||||||
|
|
|
@ -376,15 +376,16 @@ struct AMInstrument
|
||||||
sample.RelativeTone = static_cast<int8>(-12 * octave);
|
sample.RelativeTone = static_cast<int8>(-12 * octave);
|
||||||
if(sample.AllocateSample())
|
if(sample.AllocateSample())
|
||||||
{
|
{
|
||||||
|
int8 *p = sample.sample8();
|
||||||
for(SmpLength i = 0; i < sample.nLength; i++)
|
for(SmpLength i = 0; i < sample.nLength; i++)
|
||||||
{
|
{
|
||||||
switch(waveform)
|
switch(waveform)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
case 0: sample.sample8()[i] = ModSinusTable[i * 2]; break; // Sine
|
case 0: p[i] = ModSinusTable[i * 2]; break; // Sine
|
||||||
case 1: sample.sample8()[i] = static_cast<int8>(-128 + i * 8); break; // Saw
|
case 1: p[i] = static_cast<int8>(-128 + i * 8); break; // Saw
|
||||||
case 2: sample.sample8()[i] = i < 16 ? -128 : 127; break; // Square
|
case 2: p[i] = i < 16 ? -128 : 127; break; // Square
|
||||||
case 3: sample.sample8()[i] = mpt::random<int8>(rng); break; // Noise
|
case 3: p[i] = mpt::random<int8>(rng); break; // Noise
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -492,7 +493,7 @@ MPT_BINARY_STRUCT(PT36InfoChunk, 64)
|
||||||
|
|
||||||
|
|
||||||
// Check if header magic equals a given string.
|
// Check if header magic equals a given string.
|
||||||
static bool IsMagic(const char *magic1, const char *magic2)
|
static bool IsMagic(const char *magic1, const char (&magic2)[5])
|
||||||
{
|
{
|
||||||
return std::memcmp(magic1, magic2, 4) == 0;
|
return std::memcmp(magic1, magic2, 4) == 0;
|
||||||
}
|
}
|
||||||
|
@ -1023,11 +1024,15 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags)
|
||||||
|
|
||||||
if(m.command || m.param)
|
if(m.command || m.param)
|
||||||
{
|
{
|
||||||
// No support for Startrekker assembly macros
|
|
||||||
if(isStartrekker && m.command == 0x0E)
|
if(isStartrekker && m.command == 0x0E)
|
||||||
{
|
{
|
||||||
|
// No support for Startrekker assembly macros
|
||||||
m.command = CMD_NONE;
|
m.command = CMD_NONE;
|
||||||
m.param = 0;
|
m.param = 0;
|
||||||
|
} else if(isStartrekker && m.command == 0x0F && m.param > 0x1F)
|
||||||
|
{
|
||||||
|
// Startrekker caps speed at 31 ticks per row
|
||||||
|
m.param = 0x1F;
|
||||||
}
|
}
|
||||||
ConvertModCommand(m);
|
ConvertModCommand(m);
|
||||||
}
|
}
|
||||||
|
@ -1521,8 +1526,7 @@ bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
|
||||||
if(fileHeader.restartPos != 0x78)
|
if(fileHeader.restartPos != 0x78)
|
||||||
{
|
{
|
||||||
// Convert to CIA timing
|
// Convert to CIA timing
|
||||||
//m_nDefaultTempo = TEMPO(((709378.92 / 50.0) * 125.0) / ((240 - fileHeader.restartPos) * 122.0));
|
m_nDefaultTempo = TEMPO((709379.0 * 125.0 / 50.0) / ((240 - fileHeader.restartPos) * 122.0));
|
||||||
m_nDefaultTempo.Set((709379 / ((240 - fileHeader.restartPos) * 122)) * 125 / 50);
|
|
||||||
if(minVersion > UST1_80)
|
if(minVersion > UST1_80)
|
||||||
{
|
{
|
||||||
// D.O.C. SoundTracker IX re-introduced the variable tempo after some other versions dropped it.
|
// D.O.C. SoundTracker IX re-introduced the variable tempo after some other versions dropped it.
|
||||||
|
|
|
@ -1060,7 +1060,7 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
|
||||||
{
|
{
|
||||||
if(drumSample[drum] == i && Instruments[drumMap[drum]] != nullptr)
|
if(drumSample[drum] == i && Instruments[drumMap[drum]] != nullptr)
|
||||||
{
|
{
|
||||||
Instruments[drumMap[drum]]->nResampling = SRCMODE_NEAREST;
|
Instruments[drumMap[drum]]->resampling = SRCMODE_NEAREST;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1105,7 +1105,7 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
|
||||||
mptSmp.nFineTune = group.pitch;
|
mptSmp.nFineTune = group.pitch;
|
||||||
if(sampleNoInterpolation[sample - 1])
|
if(sampleNoInterpolation[sample - 1])
|
||||||
{
|
{
|
||||||
mptIns->nResampling = SRCMODE_NEAREST;
|
mptIns->resampling = SRCMODE_NEAREST;
|
||||||
}
|
}
|
||||||
if(sampleSynchronized[sample - 1])
|
if(sampleSynchronized[sample - 1])
|
||||||
{
|
{
|
||||||
|
|
|
@ -58,8 +58,8 @@ struct MTMSampleHeader
|
||||||
LimitMax(mptSmp.nLoopEnd, mptSmp.nLength);
|
LimitMax(mptSmp.nLoopEnd, mptSmp.nLength);
|
||||||
if(mptSmp.nLoopStart + 4 >= mptSmp.nLoopEnd) mptSmp.nLoopStart = mptSmp.nLoopEnd = 0;
|
if(mptSmp.nLoopStart + 4 >= mptSmp.nLoopEnd) mptSmp.nLoopStart = mptSmp.nLoopEnd = 0;
|
||||||
if(mptSmp.nLoopEnd) mptSmp.uFlags.set(CHN_LOOP);
|
if(mptSmp.nLoopEnd) mptSmp.uFlags.set(CHN_LOOP);
|
||||||
mptSmp.nFineTune = MOD2XMFineTune(finetune);
|
mptSmp.nFineTune = finetune; // Uses MOD units but allows the full int8 range rather than just -8...+7 so we keep the value as-is and convert it during playback
|
||||||
mptSmp.nC5Speed = ModSample::TransposeToFrequency(0, mptSmp.nFineTune);
|
mptSmp.nC5Speed = ModSample::TransposeToFrequency(0, finetune * 16);
|
||||||
|
|
||||||
if(attribute & 0x01)
|
if(attribute & 0x01)
|
||||||
{
|
{
|
||||||
|
@ -204,11 +204,25 @@ bool CSoundFile::ReadMTM(FileReader &file, ModLoadingFlags loadFlags)
|
||||||
{
|
{
|
||||||
// No 8xx panning in MultiTracker, only E8x
|
// No 8xx panning in MultiTracker, only E8x
|
||||||
cmd = param = 0;
|
cmd = param = 0;
|
||||||
|
} else if(cmd == 0x0E)
|
||||||
|
{
|
||||||
|
// MultiTracker does not support these commands
|
||||||
|
switch(param & 0xF0)
|
||||||
|
{
|
||||||
|
case 0x00:
|
||||||
|
case 0x30:
|
||||||
|
case 0x40:
|
||||||
|
case 0x60:
|
||||||
|
case 0x70:
|
||||||
|
case 0xF0:
|
||||||
|
cmd = param = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m->command = cmd;
|
|
||||||
m->param = param;
|
|
||||||
if(cmd != 0 || param != 0)
|
if(cmd != 0 || param != 0)
|
||||||
{
|
{
|
||||||
|
m->command = cmd;
|
||||||
|
m->param = param;
|
||||||
ConvertModCommand(*m);
|
ConvertModCommand(*m);
|
||||||
#ifdef MODPLUG_TRACKER
|
#ifdef MODPLUG_TRACKER
|
||||||
m->Convert(MOD_TYPE_MTM, MOD_TYPE_S3M, *this);
|
m->Convert(MOD_TYPE_MTM, MOD_TYPE_S3M, *this);
|
||||||
|
|
|
@ -28,8 +28,8 @@ struct ModChannel
|
||||||
struct EnvInfo
|
struct EnvInfo
|
||||||
{
|
{
|
||||||
FlagSet<EnvelopeFlags> flags;
|
FlagSet<EnvelopeFlags> flags;
|
||||||
uint32 nEnvPosition;
|
uint32 nEnvPosition = 0;
|
||||||
int32 nEnvValueAtReleaseJump;
|
int32 nEnvValueAtReleaseJump = NOT_YET_RELEASED;
|
||||||
|
|
||||||
void Reset()
|
void Reset()
|
||||||
{
|
{
|
||||||
|
@ -87,7 +87,7 @@ struct ModChannel
|
||||||
CHANNELINDEX nMasterChn;
|
CHANNELINDEX nMasterChn;
|
||||||
ModCommand rowCommand;
|
ModCommand rowCommand;
|
||||||
// 8-bit members
|
// 8-bit members
|
||||||
uint8 resamplingMode;
|
ResamplingMode resamplingMode;
|
||||||
uint8 nRestoreResonanceOnNewNote; // See nRestorePanOnNewNote
|
uint8 nRestoreResonanceOnNewNote; // See nRestorePanOnNewNote
|
||||||
uint8 nRestoreCutoffOnNewNote; // ditto
|
uint8 nRestoreCutoffOnNewNote; // ditto
|
||||||
uint8 nNote;
|
uint8 nNote;
|
||||||
|
|
|
@ -163,13 +163,13 @@ ModInstrument::ModInstrument(SAMPLEINDEX sample)
|
||||||
|
|
||||||
nMixPlug = 0;
|
nMixPlug = 0;
|
||||||
nVolRampUp = 0;
|
nVolRampUp = 0;
|
||||||
nResampling = SRCMODE_DEFAULT;
|
resampling = SRCMODE_DEFAULT;
|
||||||
nCutSwing = 0;
|
nCutSwing = 0;
|
||||||
nResSwing = 0;
|
nResSwing = 0;
|
||||||
nFilterMode = FLTMODE_UNCHANGED;
|
nFilterMode = FLTMODE_UNCHANGED;
|
||||||
pitchToTempoLock.Set(0);
|
pitchToTempoLock.Set(0);
|
||||||
nPluginVelocityHandling = PLUGIN_VELOCITYHANDLING_CHANNEL;
|
pluginVelocityHandling = PLUGIN_VELOCITYHANDLING_CHANNEL;
|
||||||
nPluginVolumeHandling = PLUGIN_VOLUMEHANDLING_IGNORE;
|
pluginVolumeHandling = PLUGIN_VOLUMEHANDLING_IGNORE;
|
||||||
|
|
||||||
pTuning = CSoundFile::GetDefaultTuning();
|
pTuning = CSoundFile::GetDefaultTuning();
|
||||||
|
|
||||||
|
|
|
@ -92,10 +92,10 @@ struct ModInstrument
|
||||||
uint8 nCutSwing; // Random cutoff factor (0...64)
|
uint8 nCutSwing; // Random cutoff factor (0...64)
|
||||||
uint8 nResSwing; // Random resonance factor (0...64)
|
uint8 nResSwing; // Random resonance factor (0...64)
|
||||||
InstrFilterMode nFilterMode; // Default filter mode
|
InstrFilterMode nFilterMode; // Default filter mode
|
||||||
uint8 nPluginVelocityHandling; // How to deal with plugin velocity (PLUGIN_VELOCITYHANDLING_* constants)
|
PlugVelocityHandling pluginVelocityHandling; // How to deal with plugin velocity
|
||||||
uint8 nPluginVolumeHandling; // How to deal with plugin volume (PLUGIN_VOLUMEHANDLING_* constants)
|
PlugVolumeHandling pluginVolumeHandling; // How to deal with plugin volume
|
||||||
|
ResamplingMode resampling; // Resampling mode
|
||||||
TEMPO pitchToTempoLock; // BPM at which the samples assigned to this instrument loop correctly (0 = unset)
|
TEMPO pitchToTempoLock; // BPM at which the samples assigned to this instrument loop correctly (0 = unset)
|
||||||
uint32 nResampling; // Resampling mode (SRCMODE_* constants)
|
|
||||||
CTuning *pTuning; // sample tuning assigned to this instrument
|
CTuning *pTuning; // sample tuning assigned to this instrument
|
||||||
|
|
||||||
InstrumentEnvelope VolEnv; // Volume envelope data
|
InstrumentEnvelope VolEnv; // Volume envelope data
|
||||||
|
|
|
@ -113,6 +113,11 @@ void ModSample::Convert(MODTYPE fromType, MODTYPE toType)
|
||||||
if(!CSoundFile::SupportsOPL(toType) && uFlags[CHN_ADLIB])
|
if(!CSoundFile::SupportsOPL(toType) && uFlags[CHN_ADLIB])
|
||||||
{
|
{
|
||||||
SetAdlib(false);
|
SetAdlib(false);
|
||||||
|
} else if(toType == MOD_TYPE_S3M && uFlags[CHN_ADLIB])
|
||||||
|
{
|
||||||
|
// No support for OPL3 waveforms in S3M
|
||||||
|
adlib[8] &= 0x03;
|
||||||
|
adlib[9] &= 0x03;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -342,27 +342,31 @@ bool ModSequenceSet::ConvertSubsongsToMultipleSequences()
|
||||||
Reporting::Confirm("The order list contains separator items.\nThe new format supports multiple sequences, do you want to convert those separate tracks into multiple song sequences?",
|
Reporting::Confirm("The order list contains separator items.\nThe new format supports multiple sequences, do you want to convert those separate tracks into multiple song sequences?",
|
||||||
"Order list conversion", false, true) == cnfYes)
|
"Order list conversion", false, true) == cnfYes)
|
||||||
{
|
{
|
||||||
ORDERINDEX length = m_Sequences[0].GetLengthTailTrimmed();
|
ORDERINDEX length = m_Sequences[0].GetLength();
|
||||||
for(ORDERINDEX ord = 0; ord < length; ord++)
|
for(ORDERINDEX ord = 0; ord < length; ord++)
|
||||||
{
|
{
|
||||||
// End of subsong?
|
// End of subsong?
|
||||||
if(!m_Sequences[0].IsValidPat(ord) && m_Sequences[0][ord] != GetIgnoreIndex())
|
if(!m_Sequences[0].IsValidPat(ord) && m_Sequences[0][ord] != GetIgnoreIndex())
|
||||||
{
|
{
|
||||||
// remove all separator patterns between current and next subsong first
|
// Remove all separator patterns between current and next subsong first
|
||||||
while(ord < length && !m_sndFile.Patterns.IsValidIndex(m_Sequences[0][ord]))
|
while(ord < length && !m_sndFile.Patterns.IsValidPat(m_Sequences[0][ord]))
|
||||||
{
|
{
|
||||||
m_Sequences[0][ord] = GetInvalidPatIndex();
|
m_Sequences[0][ord] = GetInvalidPatIndex();
|
||||||
ord++;
|
ord++;
|
||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
if(ord >= length) break;
|
if(ord >= length)
|
||||||
ORDERINDEX startOrd = ord;
|
break;
|
||||||
|
|
||||||
|
const SEQUENCEINDEX newSeq = AddSequence(false);
|
||||||
|
if(newSeq == SEQUENCEINDEX_INVALID)
|
||||||
|
break;
|
||||||
|
|
||||||
|
const ORDERINDEX startOrd = ord;
|
||||||
|
m_Sequences[newSeq].reserve(length - startOrd);
|
||||||
modified = true;
|
modified = true;
|
||||||
|
|
||||||
SEQUENCEINDEX newSeq = AddSequence(false);
|
// Now, move all following orders to the new sequence
|
||||||
m_Sequences[newSeq].reserve(length - startOrd);
|
|
||||||
|
|
||||||
// now, move all following orders to the new sequence
|
|
||||||
while(ord < length && m_Sequences[0][ord] != GetInvalidPatIndex())
|
while(ord < length && m_Sequences[0][ord] != GetInvalidPatIndex())
|
||||||
{
|
{
|
||||||
PATTERNINDEX copyPat = m_Sequences[0][ord];
|
PATTERNINDEX copyPat = m_Sequences[0][ord];
|
||||||
|
@ -370,7 +374,7 @@ bool ModSequenceSet::ConvertSubsongsToMultipleSequences()
|
||||||
m_Sequences[0][ord] = GetInvalidPatIndex();
|
m_Sequences[0][ord] = GetInvalidPatIndex();
|
||||||
ord++;
|
ord++;
|
||||||
|
|
||||||
// is this a valid pattern? adjust pattern jump commands, if necessary.
|
// Is this a valid pattern? adjust pattern jump commands, if necessary.
|
||||||
if(m_sndFile.Patterns.IsValidPat(copyPat))
|
if(m_sndFile.Patterns.IsValidPat(copyPat))
|
||||||
{
|
{
|
||||||
for(auto &m : m_sndFile.Patterns[copyPat])
|
for(auto &m : m_sndFile.Patterns[copyPat])
|
||||||
|
@ -382,6 +386,7 @@ bool ModSequenceSet::ConvertSubsongsToMultipleSequences()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ord--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetSequence(0);
|
SetSequence(0);
|
||||||
|
|
|
@ -196,8 +196,8 @@ struct FLACDecoder
|
||||||
if(length > 6 && !mpt::CompareNoCaseAscii(tag, "TITLE=", 6))
|
if(length > 6 && !mpt::CompareNoCaseAscii(tag, "TITLE=", 6))
|
||||||
{
|
{
|
||||||
mpt::ustring sampleName;
|
mpt::ustring sampleName;
|
||||||
mpt::String::Read<mpt::String::maybeNullTerminated>(sampleName, client.sndFile.GetCharsetInternal(), tag + 6, length - 6);
|
mpt::String::Read<mpt::String::maybeNullTerminated>(sampleName, mpt::CharsetUTF8, tag + 6, length - 6);
|
||||||
mpt::String::Copy(client.sndFile.m_szNames[client.sample], mpt::ToCharset(mpt::CharsetUTF8, sampleName));
|
mpt::String::Copy(client.sndFile.m_szNames[client.sample], mpt::ToCharset(client.sndFile.GetCharsetInternal(), sampleName));
|
||||||
} else if(length > 11 && !mpt::CompareNoCaseAscii(tag, "SAMPLERATE=", 11))
|
} else if(length > 11 && !mpt::CompareNoCaseAscii(tag, "SAMPLERATE=", 11))
|
||||||
{
|
{
|
||||||
uint32 sampleRate = ConvertStrTo<uint32>(tag + 11);
|
uint32 sampleRate = ConvertStrTo<uint32>(tag + 11);
|
||||||
|
|
|
@ -1018,8 +1018,7 @@ size_t SampleIO::WriteSample(std::ostream &f, const ModSample &sample, SmpLength
|
||||||
MPT_ASSERT(len == numSamples);
|
MPT_ASSERT(len == numSamples);
|
||||||
if(sample.uFlags[CHN_16BIT])
|
if(sample.uFlags[CHN_16BIT])
|
||||||
{
|
{
|
||||||
const int16 *const pSample16 = sample.sample16();
|
const int16 *p = sample.sample16();
|
||||||
const int16 *p = pSample16;
|
|
||||||
int s_old = 0;
|
int s_old = 0;
|
||||||
const int s_ofs = (GetEncoding() == unsignedPCM) ? 0x80 : 0;
|
const int s_ofs = (GetEncoding() == unsignedPCM) ? 0x80 : 0;
|
||||||
for(SmpLength j = 0; j < numSamples; j++)
|
for(SmpLength j = 0; j < numSamples; j++)
|
||||||
|
@ -1028,7 +1027,7 @@ size_t SampleIO::WriteSample(std::ostream &f, const ModSample &sample, SmpLength
|
||||||
p++;
|
p++;
|
||||||
if(sample.uFlags[CHN_STEREO])
|
if(sample.uFlags[CHN_STEREO])
|
||||||
{
|
{
|
||||||
s_new = (s_new + (static_cast<int>(*p)) + 1) / 2;
|
s_new = (s_new + mpt::rshift_signed(*p, 8) + 1) / 2;
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
if(GetEncoding() == deltaPCM)
|
if(GetEncoding() == deltaPCM)
|
||||||
|
|
|
@ -366,14 +366,14 @@ enum PluginMutePriority
|
||||||
};
|
};
|
||||||
|
|
||||||
// Plugin velocity handling options
|
// Plugin velocity handling options
|
||||||
enum PLUGVELOCITYHANDLING
|
enum PlugVelocityHandling : uint8
|
||||||
{
|
{
|
||||||
PLUGIN_VELOCITYHANDLING_CHANNEL = 0,
|
PLUGIN_VELOCITYHANDLING_CHANNEL = 0,
|
||||||
PLUGIN_VELOCITYHANDLING_VOLUME
|
PLUGIN_VELOCITYHANDLING_VOLUME
|
||||||
};
|
};
|
||||||
|
|
||||||
// Plugin volumecommand handling options
|
// Plugin volumecommand handling options
|
||||||
enum PLUGVOLUMEHANDLING
|
enum PlugVolumeHandling : uint8
|
||||||
{
|
{
|
||||||
PLUGIN_VOLUMEHANDLING_MIDI = 0,
|
PLUGIN_VOLUMEHANDLING_MIDI = 0,
|
||||||
PLUGIN_VOLUMEHANDLING_DRYWET,
|
PLUGIN_VOLUMEHANDLING_DRYWET,
|
||||||
|
@ -514,6 +514,7 @@ enum PlayBehaviour
|
||||||
kFT2NoteDelayWithoutInstr, // Sometime between OpenMPT 1.18.03.00 and 1.19.01.00, delayed instrument-less notes in XM started recalling the default sample volume and panning
|
kFT2NoteDelayWithoutInstr, // Sometime between OpenMPT 1.18.03.00 and 1.19.01.00, delayed instrument-less notes in XM started recalling the default sample volume and panning
|
||||||
kOPLFlexibleNoteOff, // Full control after note-off over OPL voices, ^^^ sends note cut instead of just note-off
|
kOPLFlexibleNoteOff, // Full control after note-off over OPL voices, ^^^ sends note cut instead of just note-off
|
||||||
kITInstrWithNoteOffOldEffects, // Instrument number with note-off recalls default volume - special cases with Old Effects enabled
|
kITInstrWithNoteOffOldEffects, // Instrument number with note-off recalls default volume - special cases with Old Effects enabled
|
||||||
|
kMIDIVolumeOnNoteOffBug, // Update MIDI channel volume on note-off (legacy bug emulation)
|
||||||
|
|
||||||
// Add new play behaviours here.
|
// Add new play behaviours here.
|
||||||
|
|
||||||
|
|
|
@ -1025,7 +1025,8 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
|
||||||
|
|
||||||
if(m.note == NOTE_KEYOFF || m.note == NOTE_NOTECUT || (m.note == NOTE_FADE && GetNumInstruments())
|
if(m.note == NOTE_KEYOFF || m.note == NOTE_NOTECUT || (m.note == NOTE_FADE && GetNumInstruments())
|
||||||
|| ((m.command == CMD_MODCMDEX || m.command == CMD_S3MCMDEX) && (m.param & 0xF0) == 0xC0 && paramLo < numTicks)
|
|| ((m.command == CMD_MODCMDEX || m.command == CMD_S3MCMDEX) && (m.param & 0xF0) == 0xC0 && paramLo < numTicks)
|
||||||
|| (m.command == CMD_DELAYCUT && paramLo != 0 && startTick + paramLo < numTicks))
|
|| (m.command == CMD_DELAYCUT && paramLo != 0 && startTick + paramLo < numTicks)
|
||||||
|
|| m.command == CMD_KEYOFF)
|
||||||
{
|
{
|
||||||
stopNote = true;
|
stopNote = true;
|
||||||
}
|
}
|
||||||
|
@ -1452,7 +1453,6 @@ void CSoundFile::InstrumentChange(ModChannel &chn, uint32 instr, bool bPorta, bo
|
||||||
|
|
||||||
if(returnAfterVolumeAdjust) return;
|
if(returnAfterVolumeAdjust) return;
|
||||||
|
|
||||||
|
|
||||||
// Instrument adjust
|
// Instrument adjust
|
||||||
chn.nNewIns = 0;
|
chn.nNewIns = 0;
|
||||||
|
|
||||||
|
@ -4487,6 +4487,15 @@ void CSoundFile::ExtendedMODCommands(CHANNELINDEX nChn, ModCommand::PARAM param)
|
||||||
{
|
{
|
||||||
chn.nFineTune = MOD2XMFineTune(param);
|
chn.nFineTune = MOD2XMFineTune(param);
|
||||||
if(chn.nPeriod && chn.rowCommand.IsNote()) chn.nPeriod = GetPeriodFromNote(chn.nNote, chn.nFineTune, chn.nC5Speed);
|
if(chn.nPeriod && chn.rowCommand.IsNote()) chn.nPeriod = GetPeriodFromNote(chn.nNote, chn.nFineTune, chn.nC5Speed);
|
||||||
|
} else if(GetType() == MOD_TYPE_MTM)
|
||||||
|
{
|
||||||
|
if(chn.rowCommand.IsNote() && chn.pModSample != nullptr)
|
||||||
|
{
|
||||||
|
// Effect is permanent in MultiTracker
|
||||||
|
const_cast<ModSample *>(chn.pModSample)->nFineTune = param;
|
||||||
|
chn.nFineTune = param;
|
||||||
|
if(chn.nPeriod) chn.nPeriod = GetPeriodFromNote(chn.nNote, chn.nFineTune, chn.nC5Speed);
|
||||||
|
}
|
||||||
} else if(chn.rowCommand.IsNote())
|
} else if(chn.rowCommand.IsNote())
|
||||||
{
|
{
|
||||||
chn.nFineTune = MOD2XMFineTune(param - 8);
|
chn.nFineTune = MOD2XMFineTune(param - 8);
|
||||||
|
@ -5578,7 +5587,7 @@ void CSoundFile::KeyOff(ModChannel &chn) const
|
||||||
if(chn.position.GetUInt() > chn.nLength)
|
if(chn.position.GetUInt() > chn.nLength)
|
||||||
{
|
{
|
||||||
// Test case: SusAfterLoop.it
|
// Test case: SusAfterLoop.it
|
||||||
chn.position.Set(chn.position.GetInt() - chn.nLength + chn.nLoopStart);
|
chn.position.Set(chn.nLoopStart + ((chn.position.GetInt() - chn.nLoopStart) % (chn.nLoopEnd - chn.nLoopStart)));
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
|
@ -5657,7 +5666,7 @@ void CSoundFile::SetTempo(TEMPO param, bool setFromUI)
|
||||||
// ProTracker sets the tempo after the first tick.
|
// ProTracker sets the tempo after the first tick.
|
||||||
// Note: The case of one tick per row is handled in ProcessRow() instead.
|
// Note: The case of one tick per row is handled in ProcessRow() instead.
|
||||||
// Test case: TempoChange.mod
|
// Test case: TempoChange.mod
|
||||||
#if MPT_MSVC_AT_LEAST(2017,8)
|
#if MPT_MSVC_AT_LEAST(2017,8) && MPT_MSVC_BEFORE(2019,0)
|
||||||
// Work-around MSVC getting confused about deduced const input type in noexcept operator inside noexcept condition.
|
// Work-around MSVC getting confused about deduced const input type in noexcept operator inside noexcept condition.
|
||||||
m_PlayState.m_nMusicTempo.SetRaw(std::min(param.GetRaw(), specs.GetTempoMax().GetRaw()));
|
m_PlayState.m_nMusicTempo.SetRaw(std::min(param.GetRaw(), specs.GetTempoMax().GetRaw()));
|
||||||
#else
|
#else
|
||||||
|
@ -5837,15 +5846,18 @@ uint32 CSoundFile::GetPeriodFromNote(uint32 note, int32 nFineTune, uint32 nC5Spe
|
||||||
return Util::muldiv_unsigned(8363, (FreqS3MTable[note % 12u] << 5), nC5Speed << (note / 12u));
|
return Util::muldiv_unsigned(8363, (FreqS3MTable[note % 12u] << 5), nC5Speed << (note / 12u));
|
||||||
//8363 * freq[note%12] / nC5Speed * 2^(5-note/12)
|
//8363 * freq[note%12] / nC5Speed * 2^(5-note/12)
|
||||||
}
|
}
|
||||||
} else if (GetType() == MOD_TYPE_XM)
|
} else if (GetType() & (MOD_TYPE_XM | MOD_TYPE_MTM))
|
||||||
{
|
{
|
||||||
if (note < 12) note = 12;
|
if (note < 12) note = 12;
|
||||||
note -= 12;
|
note -= 12;
|
||||||
|
|
||||||
|
if(GetType() == MOD_TYPE_MTM)
|
||||||
|
{
|
||||||
|
nFineTune *= 16;
|
||||||
|
} else if(m_playBehaviour[kFT2FinetunePrecision])
|
||||||
|
{
|
||||||
// FT2 Compatibility: The lower three bits of the finetune are truncated.
|
// FT2 Compatibility: The lower three bits of the finetune are truncated.
|
||||||
// Test case: Finetune-Precision.xm
|
// Test case: Finetune-Precision.xm
|
||||||
if(m_playBehaviour[kFT2FinetunePrecision])
|
|
||||||
{
|
|
||||||
nFineTune &= ~7;
|
nFineTune &= ~7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5892,7 +5904,7 @@ uint32 CSoundFile::GetPeriodFromNote(uint32 note, int32 nFineTune, uint32 nC5Spe
|
||||||
uint32 CSoundFile::GetFreqFromPeriod(uint32 period, uint32 c5speed, int32 nPeriodFrac) const
|
uint32 CSoundFile::GetFreqFromPeriod(uint32 period, uint32 c5speed, int32 nPeriodFrac) const
|
||||||
{
|
{
|
||||||
if (!period) return 0;
|
if (!period) return 0;
|
||||||
if (GetType() == MOD_TYPE_XM)
|
if (GetType() & (MOD_TYPE_XM | MOD_TYPE_MTM))
|
||||||
{
|
{
|
||||||
if(m_playBehaviour[kFT2Periods])
|
if(m_playBehaviour[kFT2Periods])
|
||||||
{
|
{
|
||||||
|
|
|
@ -711,7 +711,7 @@ void CSoundFile::SetDspEffects(uint32 DSPMask)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_ASM
|
#ifdef ENABLE_ASM
|
||||||
#ifndef NO_REVERB
|
#ifndef NO_REVERB
|
||||||
if(!(GetProcSupport() & PROCSUPPORT_MMX)) DSPMask &= ~SNDDSP_REVERB;
|
if(!(GetRealProcSupport() & PROCSUPPORT_MMX)) DSPMask &= ~SNDDSP_REVERB;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
m_MixerSettings.DSPMask = DSPMask;
|
m_MixerSettings.DSPMask = DSPMask;
|
||||||
|
@ -1163,7 +1163,6 @@ PlayBehaviourSet CSoundFile::GetDefaultPlaybackBehaviour(MODTYPE type)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MOD_TYPE_MOD:
|
case MOD_TYPE_MOD:
|
||||||
playBehaviour.set(kMODSampleSwap);
|
|
||||||
playBehaviour.set(kRowDelayWithNoteDelay);
|
playBehaviour.set(kRowDelayWithNoteDelay);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -1036,7 +1036,8 @@ void CSoundFile::ProcessVolumeEnvelope(ModChannel &chn, int &vol) const
|
||||||
// if we are in the release portion of the envelope,
|
// if we are in the release portion of the envelope,
|
||||||
// rescale envelope factor so that it is proportional to the release point
|
// rescale envelope factor so that it is proportional to the release point
|
||||||
// and release envelope beginning.
|
// and release envelope beginning.
|
||||||
if(chn.VolEnv.nEnvValueAtReleaseJump != NOT_YET_RELEASED)
|
if(pIns->VolEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET
|
||||||
|
&& chn.VolEnv.nEnvValueAtReleaseJump != NOT_YET_RELEASED)
|
||||||
{
|
{
|
||||||
int envValueAtReleaseJump = chn.VolEnv.nEnvValueAtReleaseJump;
|
int envValueAtReleaseJump = chn.VolEnv.nEnvValueAtReleaseJump;
|
||||||
int envValueAtReleaseNode = pIns->VolEnv[pIns->VolEnv.nReleaseNode].value * 4;
|
int envValueAtReleaseNode = pIns->VolEnv[pIns->VolEnv.nReleaseNode].value * 4;
|
||||||
|
@ -2315,12 +2316,12 @@ bool CSoundFile::ReadNote()
|
||||||
if (chn.pCurrentSample || (chn.HasMIDIOutput() && !chn.dwFlags[CHN_KEYOFF | CHN_NOTEFADE]))
|
if (chn.pCurrentSample || (chn.HasMIDIOutput() && !chn.dwFlags[CHN_KEYOFF | CHN_NOTEFADE]))
|
||||||
{
|
{
|
||||||
// Update VU-Meter (nRealVolume is 14-bit)
|
// Update VU-Meter (nRealVolume is 14-bit)
|
||||||
uint32 vul = (chn.nRealVolume * chn.nRealPan) / (1 << 14);
|
uint32 vul = (chn.nRealVolume * (256-chn.nRealPan)) / (1 << 14);
|
||||||
if (vul > 127) vul = 127;
|
if (vul > 127) vul = 127;
|
||||||
if (chn.nLeftVU > 127) chn.nLeftVU = (uint8)vul;
|
if (chn.nLeftVU > 127) chn.nLeftVU = (uint8)vul;
|
||||||
vul /= 2;
|
vul /= 2;
|
||||||
if (chn.nLeftVU < vul) chn.nLeftVU = (uint8)vul;
|
if (chn.nLeftVU < vul) chn.nLeftVU = (uint8)vul;
|
||||||
uint32 vur = (chn.nRealVolume * (256-chn.nRealPan)) / (1 << 14);
|
uint32 vur = (chn.nRealVolume * chn.nRealPan) / (1 << 14);
|
||||||
if (vur > 127) vur = 127;
|
if (vur > 127) vur = 127;
|
||||||
if (chn.nRightVU > 127) chn.nRightVU = (uint8)vur;
|
if (chn.nRightVU > 127) chn.nRightVU = (uint8)vur;
|
||||||
vur /= 2;
|
vur /= 2;
|
||||||
|
@ -2394,13 +2395,13 @@ bool CSoundFile::ReadNote()
|
||||||
//if (chn.nNewRightVol > 0xFFFF) chn.nNewRightVol = 0xFFFF;
|
//if (chn.nNewRightVol > 0xFFFF) chn.nNewRightVol = 0xFFFF;
|
||||||
//if (chn.nNewLeftVol > 0xFFFF) chn.nNewLeftVol = 0xFFFF;
|
//if (chn.nNewLeftVol > 0xFFFF) chn.nNewLeftVol = 0xFFFF;
|
||||||
|
|
||||||
if(chn.pModInstrument && Resampling::IsKnownMode(chn.pModInstrument->nResampling))
|
if(chn.pModInstrument && Resampling::IsKnownMode(chn.pModInstrument->resampling))
|
||||||
{
|
{
|
||||||
// For defined resampling modes, use per-instrument resampling mode if set
|
// For defined resampling modes, use per-instrument resampling mode if set
|
||||||
chn.resamplingMode = static_cast<uint8>(chn.pModInstrument->nResampling);
|
chn.resamplingMode = chn.pModInstrument->resampling;
|
||||||
} else if(Resampling::IsKnownMode(m_nResampling))
|
} else if(Resampling::IsKnownMode(m_nResampling))
|
||||||
{
|
{
|
||||||
chn.resamplingMode = static_cast<uint8>(m_nResampling);
|
chn.resamplingMode = m_nResampling;
|
||||||
} else if(m_SongFlags[SONG_ISAMIGA] && m_Resampler.m_Settings.emulateAmiga)
|
} else if(m_SongFlags[SONG_ISAMIGA] && m_Resampler.m_Settings.emulateAmiga)
|
||||||
{
|
{
|
||||||
// Enforce Amiga resampler for Amiga modules
|
// Enforce Amiga resampler for Amiga modules
|
||||||
|
@ -2408,7 +2409,7 @@ bool CSoundFile::ReadNote()
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
// Default to global mixer settings
|
// Default to global mixer settings
|
||||||
chn.resamplingMode = static_cast<uint8>(m_Resampler.m_Settings.SrcMode);
|
chn.resamplingMode = m_Resampler.m_Settings.SrcMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(chn.increment.IsUnity() && !(chn.dwFlags[CHN_VIBRATO] || chn.nAutoVibDepth || chn.resamplingMode == SRCMODE_AMIGA))
|
if(chn.increment.IsUnity() && !(chn.dwFlags[CHN_VIBRATO] || chn.nAutoVibDepth || chn.resamplingMode == SRCMODE_AMIGA))
|
||||||
|
@ -2540,11 +2541,13 @@ void CSoundFile::ProcessMidiOut(CHANNELINDEX nChn)
|
||||||
if(note != NOTE_NONE)
|
if(note != NOTE_NONE)
|
||||||
{
|
{
|
||||||
int32 velocity = static_cast<int32>(4 * defaultVolume);
|
int32 velocity = static_cast<int32>(4 * defaultVolume);
|
||||||
switch(pIns->nPluginVelocityHandling)
|
switch(pIns->pluginVelocityHandling)
|
||||||
{
|
{
|
||||||
case PLUGIN_VELOCITYHANDLING_CHANNEL:
|
case PLUGIN_VELOCITYHANDLING_CHANNEL:
|
||||||
velocity = chn.nVolume;
|
velocity = chn.nVolume;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 swing = chn.nVolSwing;
|
int32 swing = chn.nVolSwing;
|
||||||
|
@ -2560,23 +2563,23 @@ void CSoundFile::ProcessMidiOut(CHANNELINDEX nChn)
|
||||||
SendMIDINote(nChn, realNote, static_cast<uint16>(velocity));
|
SendMIDINote(nChn, realNote, static_cast<uint16>(velocity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool processVolumeAlsoOnNote = (pIns->pluginVelocityHandling == PLUGIN_VELOCITYHANDLING_VOLUME);
|
||||||
|
const bool hasNote = m_playBehaviour[kMIDIVolumeOnNoteOffBug] ? (note != NOTE_NONE) : ModCommand::IsNote(note);
|
||||||
|
|
||||||
const bool processVolumeAlsoOnNote = (pIns->nPluginVelocityHandling == PLUGIN_VELOCITYHANDLING_VOLUME);
|
if((hasVolCommand && !hasNote) || (hasNote && processVolumeAlsoOnNote))
|
||||||
|
|
||||||
if((hasVolCommand && !note) || (note && processVolumeAlsoOnNote))
|
|
||||||
{
|
{
|
||||||
switch(pIns->nPluginVolumeHandling)
|
switch(pIns->pluginVolumeHandling)
|
||||||
{
|
{
|
||||||
case PLUGIN_VOLUMEHANDLING_DRYWET:
|
case PLUGIN_VOLUMEHANDLING_DRYWET:
|
||||||
if(hasVolCommand) pPlugin->SetDryRatio(2 * vol);
|
if(hasVolCommand) pPlugin->SetDryRatio(2 * vol);
|
||||||
else pPlugin->SetDryRatio(2 * defaultVolume);
|
else pPlugin->SetDryRatio(2 * defaultVolume);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PLUGIN_VOLUMEHANDLING_MIDI:
|
case PLUGIN_VOLUMEHANDLING_MIDI:
|
||||||
if(hasVolCommand) pPlugin->MidiCC(MIDIEvents::MIDICC_Volume_Coarse, std::min<uint8>(127u, 2u * vol), nChn);
|
if(hasVolCommand) pPlugin->MidiCC(MIDIEvents::MIDICC_Volume_Coarse, std::min<uint8>(127u, 2u * vol), nChn);
|
||||||
else pPlugin->MidiCC(MIDIEvents::MIDICC_Volume_Coarse, static_cast<uint8>(std::min<uint32>(127u, 2u * defaultVolume)), nChn);
|
else pPlugin->MidiCC(MIDIEvents::MIDICC_Volume_Coarse, static_cast<uint8>(std::min<uint32>(127u, 2u * defaultVolume)), nChn);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -413,6 +413,18 @@ void CSoundFile::UpgradeModule()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 28, 03, 04))
|
||||||
|
{
|
||||||
|
for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) if (Instruments[i] != nullptr)
|
||||||
|
{
|
||||||
|
if(Instruments[i]->pluginVolumeHandling == PLUGIN_VOLUMEHANDLING_MIDI || Instruments[i]->pluginVolumeHandling == PLUGIN_VOLUMEHANDLING_DRYWET)
|
||||||
|
{
|
||||||
|
m_playBehaviour.set(kMIDIVolumeOnNoteOffBug);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Patterns.ForEachModCommand(UpgradePatternData(*this));
|
Patterns.ForEachModCommand(UpgradePatternData(*this));
|
||||||
|
|
||||||
// Convert compatibility flags
|
// Convert compatibility flags
|
||||||
|
|
|
@ -2598,6 +2598,41 @@ static MPT_NOINLINE void TestCharsets()
|
||||||
VERIFY_EQUAL(P_("\\directory\\file.txt").GetFileExt(), P_(".txt"));
|
VERIFY_EQUAL(P_("\\directory\\file.txt").GetFileExt(), P_(".txt"));
|
||||||
VERIFY_EQUAL(P_("\\directory\\file.txt").GetFullFileName(), P_("file.txt"));
|
VERIFY_EQUAL(P_("\\directory\\file.txt").GetFullFileName(), P_("file.txt"));
|
||||||
|
|
||||||
|
VERIFY_EQUAL(P_(".").GetDrive(), P_(""));
|
||||||
|
VERIFY_EQUAL(P_(".").GetDir(), P_(""));
|
||||||
|
VERIFY_EQUAL(P_(".").GetPath(), P_(""));
|
||||||
|
VERIFY_EQUAL(P_(".").GetFileName(), P_("."));
|
||||||
|
VERIFY_EQUAL(P_(".").GetFileExt(), P_(""));
|
||||||
|
VERIFY_EQUAL(P_(".").GetFullFileName(), P_("."));
|
||||||
|
|
||||||
|
VERIFY_EQUAL(P_("..").GetDrive(), P_(""));
|
||||||
|
VERIFY_EQUAL(P_("..").GetDir(), P_(""));
|
||||||
|
VERIFY_EQUAL(P_("..").GetPath(), P_(""));
|
||||||
|
VERIFY_EQUAL(P_("..").GetFileName(), P_(".."));
|
||||||
|
VERIFY_EQUAL(P_("..").GetFileExt(), P_(""));
|
||||||
|
VERIFY_EQUAL(P_("..").GetFullFileName(), P_(".."));
|
||||||
|
|
||||||
|
VERIFY_EQUAL(P_("dir\\.").GetDrive(), P_(""));
|
||||||
|
VERIFY_EQUAL(P_("dir\\.").GetDir(), P_("dir\\"));
|
||||||
|
VERIFY_EQUAL(P_("dir\\.").GetPath(), P_("dir\\"));
|
||||||
|
VERIFY_EQUAL(P_("dir\\.").GetFileName(), P_("."));
|
||||||
|
VERIFY_EQUAL(P_("dir\\.").GetFileExt(), P_(""));
|
||||||
|
VERIFY_EQUAL(P_("dir\\.").GetFullFileName(), P_("."));
|
||||||
|
|
||||||
|
VERIFY_EQUAL(P_("dir\\..").GetDrive(), P_(""));
|
||||||
|
VERIFY_EQUAL(P_("dir\\..").GetDir(), P_("dir\\"));
|
||||||
|
VERIFY_EQUAL(P_("dir\\..").GetPath(), P_("dir\\"));
|
||||||
|
VERIFY_EQUAL(P_("dir\\..").GetFileName(), P_(".."));
|
||||||
|
VERIFY_EQUAL(P_("dir\\..").GetFileExt(), P_(""));
|
||||||
|
VERIFY_EQUAL(P_("dir\\..").GetFullFileName(), P_(".."));
|
||||||
|
|
||||||
|
VERIFY_EQUAL(P_(".txt").GetDrive(), P_(""));
|
||||||
|
VERIFY_EQUAL(P_(".txt").GetDir(), P_(""));
|
||||||
|
VERIFY_EQUAL(P_(".txt").GetPath(), P_(""));
|
||||||
|
VERIFY_EQUAL(P_(".txt").GetFileName(), P_(".txt"));
|
||||||
|
VERIFY_EQUAL(P_(".txt").GetFileExt(), P_(""));
|
||||||
|
VERIFY_EQUAL(P_(".txt").GetFullFileName(), P_(".txt"));
|
||||||
|
|
||||||
VERIFY_EQUAL(P_("C:tmp.txt").GetDrive(), P_("C:"));
|
VERIFY_EQUAL(P_("C:tmp.txt").GetDrive(), P_("C:"));
|
||||||
VERIFY_EQUAL(P_("C:tmp.txt").GetDir(), P_(""));
|
VERIFY_EQUAL(P_("C:tmp.txt").GetDir(), P_(""));
|
||||||
VERIFY_EQUAL(P_("C:tmp.txt").GetPath(), P_("C:"));
|
VERIFY_EQUAL(P_("C:tmp.txt").GetPath(), P_("C:"));
|
||||||
|
@ -3079,7 +3114,7 @@ static void TestLoadXMFile(const CSoundFile &sndFile)
|
||||||
VERIFY_EQUAL_NONCONT(pIns->nPPC, NOTE_MIDDLEC - 1);
|
VERIFY_EQUAL_NONCONT(pIns->nPPC, NOTE_MIDDLEC - 1);
|
||||||
|
|
||||||
VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
|
VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
|
||||||
VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_SINC8LP);
|
VERIFY_EQUAL_NONCONT(pIns->resampling, SRCMODE_SINC8LP);
|
||||||
|
|
||||||
VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), false);
|
VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), false);
|
||||||
VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0);
|
VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0);
|
||||||
|
@ -3105,8 +3140,8 @@ static void TestLoadXMFile(const CSoundFile &sndFile)
|
||||||
|
|
||||||
VERIFY_EQUAL_NONCONT(pIns->pitchToTempoLock, TEMPO(0, 0));
|
VERIFY_EQUAL_NONCONT(pIns->pitchToTempoLock, TEMPO(0, 0));
|
||||||
|
|
||||||
VERIFY_EQUAL_NONCONT(pIns->nPluginVelocityHandling, PLUGIN_VELOCITYHANDLING_VOLUME);
|
VERIFY_EQUAL_NONCONT(pIns->pluginVelocityHandling, PLUGIN_VELOCITYHANDLING_VOLUME);
|
||||||
VERIFY_EQUAL_NONCONT(pIns->nPluginVolumeHandling, PLUGIN_VOLUMEHANDLING_MIDI);
|
VERIFY_EQUAL_NONCONT(pIns->pluginVolumeHandling, PLUGIN_VOLUMEHANDLING_MIDI);
|
||||||
|
|
||||||
for(size_t i = sndFile.GetModSpecifications().noteMin; i < sndFile.GetModSpecifications().noteMax; i++)
|
for(size_t i = sndFile.GetModSpecifications().noteMin; i < sndFile.GetModSpecifications().noteMax; i++)
|
||||||
{
|
{
|
||||||
|
@ -3372,7 +3407,7 @@ static void TestLoadMPTMFile(const CSoundFile &sndFile)
|
||||||
VERIFY_EQUAL_NONCONT(pIns->nPPC, (NOTE_MIDDLEC - NOTE_MIN) + 6); // F#5
|
VERIFY_EQUAL_NONCONT(pIns->nPPC, (NOTE_MIDDLEC - NOTE_MIN) + 6); // F#5
|
||||||
|
|
||||||
VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
|
VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
|
||||||
VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_SINC8LP);
|
VERIFY_EQUAL_NONCONT(pIns->resampling, SRCMODE_SINC8LP);
|
||||||
|
|
||||||
VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), true);
|
VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), true);
|
||||||
VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0x32);
|
VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0x32);
|
||||||
|
@ -3399,8 +3434,8 @@ static void TestLoadMPTMFile(const CSoundFile &sndFile)
|
||||||
|
|
||||||
VERIFY_EQUAL_NONCONT(pIns->pitchToTempoLock, TEMPO(130, 2000));
|
VERIFY_EQUAL_NONCONT(pIns->pitchToTempoLock, TEMPO(130, 2000));
|
||||||
|
|
||||||
VERIFY_EQUAL_NONCONT(pIns->nPluginVelocityHandling, PLUGIN_VELOCITYHANDLING_VOLUME);
|
VERIFY_EQUAL_NONCONT(pIns->pluginVelocityHandling, PLUGIN_VELOCITYHANDLING_VOLUME);
|
||||||
VERIFY_EQUAL_NONCONT(pIns->nPluginVolumeHandling, PLUGIN_VOLUMEHANDLING_MIDI);
|
VERIFY_EQUAL_NONCONT(pIns->pluginVolumeHandling, PLUGIN_VOLUMEHANDLING_MIDI);
|
||||||
|
|
||||||
for(size_t i = 0; i < NOTE_MAX; i++)
|
for(size_t i = 0; i < NOTE_MAX; i++)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue