Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libopenmpt for openSUSE:Factory checked in at 2024-07-24 15:32:55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libopenmpt (Old) and /work/SRC/openSUSE:Factory/.libopenmpt.new.1869 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "libopenmpt" Wed Jul 24 15:32:55 2024 rev:49 rq:1188976 version:0.7.9 Changes: -------- --- /work/SRC/openSUSE:Factory/libopenmpt/libopenmpt.changes 2024-06-10 17:37:02.805640641 +0200 +++ /work/SRC/openSUSE:Factory/.libopenmpt.new.1869/libopenmpt.changes 2024-07-25 11:56:03.090727649 +0200 @@ -1,0 +2,57 @@ +Mon Jul 22 09:16:49 UTC 2024 - Mia Herkt <mia@0x0.st> + +- Update to 0.7.9: + * [Sec] Potential division by 0 when seeking in the module with + seek.sync_samples enabled (r21167). + * [Change] The work-around for + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115049 + has been changed from forcing -O1 on GCC 14 to setting + -fno-ipa-ra on all GCC versions on non-ELF platforms. + * MOD: Allow sample swapping to work when swapping from a + non-looping, stopped sample back to a looping sample + (fixes MOD.energy). + * DBM: Import second sustain point in case the first sustain + point is not set, or if it has a lower index than the first. + * DBM: When several instruments referenced the same sample with + different properties (volume, loop points, etc.), only one set + of properties was imported (fixes DBM.Supernova). + * DBM: Prioritize effects more correctly when the same effect is + encountered in both effect columns of a cell + (fixes DBM.143_Gnoj). + * DBM: Don’t import offset effects when there’s a tone portmento + next to them. + * DBM: A few IT-specific playback quirks are disabled for more + accurate playback (e.g. in “Are You Flying With Me?” by + Jazzcat). + * DIGI: Sample play direction was reset if adjacent channel + contained a Note Cut note. + * AMF: When running out of sample slots, file reading became be + misaligned because the sample name was not skipped. + * MED: Command 0F was not imported. + * MED: Upper frequency limits should be more accurate now. + * MED: Channel panning is now only applied in MMD2 files if the + free pan flag is set. + * MED: Volume command resolution was incorrect for pre-MMD3 + files. + * XM: oggmod does not support stereo samples but keeps the stereo + flag when encoding such samples. Such samples are now imported + as mono samples instead of not importing them at all. + * XM: For files saved with registered MadTracker 2 versions, + do not put binary garbage (the user ID) in the tracker metadata + field. It is replaced with “registered” instead. + * For some truncated files, the used tracker was not identified + correctly. + * S3M: Identify files saved with early Impulse Tracker versions, + Sound Club 2, Liquid Tracker, NESMusa, UNMO3, deMODifier, + Kosmic To-S3M, and better tell old ModPlug Tracker versions + apart. + * S3M: When skipping sample loading, some tracker identifications + were not working as intended. + * IT: Identify files saved with itwriter. + * DTM: Identify files saved with Digital Tracker 2.3. + * xmp-openmpt: If there is only one subsong, set the song title + to the “global” song title instead of the name of that subsong. + * xmp-openmpt: Sample and instrument names were not sanitized, + sometimes showing on multiple rows. + +------------------------------------------------------------------- Old: ---- libopenmpt-0.7.8+release.autotools.tar.gz New: ---- libopenmpt-0.7.9+release.autotools.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libopenmpt.spec ++++++ --- /var/tmp/diff_new_pack.cp4JHW/_old 2024-07-25 11:56:03.734755319 +0200 +++ /var/tmp/diff_new_pack.cp4JHW/_new 2024-07-25 11:56:03.738755491 +0200 @@ -21,7 +21,7 @@ %define libopenmpt_modplug_version 0.8.9.0 Name: libopenmpt -Version: 0.7.8 +Version: 0.7.9 Release: 0 Summary: C++ and C library to decode tracker music files License: BSD-3-Clause ++++++ libopenmpt-0.7.8+release.autotools.tar.gz -> libopenmpt-0.7.9+release.autotools.tar.gz ++++++ ++++ 2186 lines of diff (skipped) ++++ retrying with extended exclude list diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/Makefile.am new/libopenmpt-0.7.9+release.autotools/Makefile.am --- old/libopenmpt-0.7.8+release.autotools/Makefile.am 2024-04-10 14:24:33.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/Makefile.am 2024-07-14 18:10:07.000000000 +0200 @@ -313,6 +313,7 @@ MPT_FILES_SRC_OPENMPT += src/openmpt/soundbase/SampleFormat.hpp MPT_FILES_COMMON = MPT_FILES_COMMON += common/BuildSettings.h +MPT_FILES_COMMON += common/BuildSettingsCompiler.h MPT_FILES_COMMON += common/ComponentManager.cpp MPT_FILES_COMMON += common/ComponentManager.h MPT_FILES_COMMON += common/Dither.h diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/common/BuildSettings.h new/libopenmpt-0.7.9+release.autotools/common/BuildSettings.h --- old/libopenmpt-0.7.8+release.autotools/common/BuildSettings.h 2024-05-12 13:07:25.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/common/BuildSettings.h 2024-07-14 18:10:07.000000000 +0200 @@ -12,6 +12,10 @@ +#include "BuildSettingsCompiler.h" + + + #include "mpt/base/detect_compiler.hpp" #include "mpt/base/detect_os.hpp" #include "mpt/base/detect_quirks.hpp" @@ -362,57 +366,6 @@ -// compiler configuration - -#if MPT_COMPILER_MSVC - -#pragma warning(default:4800) // Implicit conversion from 'int' to bool. Possible information loss - -#pragma warning(disable:4355) // 'this' : used in base member initializer list - -// happens for immutable classes (i.e. classes containing const members) -#pragma warning(disable:4512) // assignment operator could not be generated - -#pragma warning(error:4309) // Treat "truncation of constant value"-warning as error. -#pragma warning(error:4463) // Treat overflow; assigning value to bit-field that can only hold values from low_value to high_value"-warning as error. - -#ifdef MPT_BUILD_ANALYZED -// Disable Visual Studio static analyzer warnings that generate too many false positives in VS2010. -//#pragma warning(disable:6246) -//#pragma warning(disable:6262) -#pragma warning(disable:6297) // 32-bit value is shifted, then cast to 64-bit value. Results might not be an expected value. -#pragma warning(disable:6326) // Potential comparison of a constant with another constant -//#pragma warning(disable:6385) -//#pragma warning(disable:6386) -#endif // MPT_BUILD_ANALYZED - -#endif // MPT_COMPILER_MSVC - -#if MPT_COMPILER_GCC - -#ifdef MPT_COMPILER_QUIRK_GCC_NO_O2 -// See <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115049>. -#if defined(__OPTIMIZE__) -#pragma GCC optimize("O1") -#endif -#endif // MPT_COMPILER_QUIRK_GCC_NO_O2 - -#endif // MPT_COMPILER_GCC - -#if MPT_COMPILER_CLANG - -#if defined(MPT_BUILD_MSVC) -#pragma clang diagnostic warning "-Wimplicit-fallthrough" -#endif // MPT_BUILD_MSVC - -#if defined(MODPLUG_TRACKER) -#pragma clang diagnostic ignored "-Wunused-local-typedef" -#endif // MODPLUG_TRACKER - -#endif // MPT_COMPILER_CLANG - - - // third-party library configuration #ifdef MPT_WITH_STBVORBIS diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/common/BuildSettingsCompiler.h new/libopenmpt-0.7.9+release.autotools/common/BuildSettingsCompiler.h --- old/libopenmpt-0.7.8+release.autotools/common/BuildSettingsCompiler.h 1970-01-01 01:00:00.000000000 +0100 +++ new/libopenmpt-0.7.9+release.autotools/common/BuildSettingsCompiler.h 2024-07-18 20:26:32.000000000 +0200 @@ -0,0 +1,73 @@ +/* + * BuildSettingsCompiler.h + * ----------------------- + * Purpose: Global compiler setting overrides + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#pragma once + + + +#include "mpt/base/detect_compiler.hpp" + + + +// compiler configuration + +#if MPT_COMPILER_MSVC + +#pragma warning(default:4800) // Implicit conversion from 'int' to bool. Possible information loss + +#pragma warning(disable:4355) // 'this' : used in base member initializer list + +// happens for immutable classes (i.e. classes containing const members) +#pragma warning(disable:4512) // assignment operator could not be generated + +#pragma warning(error:4309) // Treat "truncation of constant value"-warning as error. +#pragma warning(error:4463) // Treat overflow; assigning value to bit-field that can only hold values from low_value to high_value"-warning as error. + +#ifdef MPT_BUILD_ANALYZED +// Disable Visual Studio static analyzer warnings that generate too many false positives in VS2010. +//#pragma warning(disable:6246) +//#pragma warning(disable:6262) +#pragma warning(disable:6297) // 32-bit value is shifted, then cast to 64-bit value. Results might not be an expected value. +#pragma warning(disable:6326) // Potential comparison of a constant with another constant +//#pragma warning(disable:6385) +//#pragma warning(disable:6386) +#endif // MPT_BUILD_ANALYZED + +#endif // MPT_COMPILER_MSVC + +#if MPT_COMPILER_GCC + +#ifdef MPT_COMPILER_SETTING_QUIRK_GCC_BROKEN_IPA +// See <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115049>. +#if MPT_GCC_BEFORE(9, 0, 0) +// Earlier GCC get confused about setting a global function attribute. +// We need to check for 9.0 instead of 9.1 because of +// <https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1028580>. +// It also gets confused when setting global optimization -O1, +// so we have no way of fixing GCC 8 or earlier. +//#pragma GCC optimize("O1") +#else +#pragma GCC optimize("no-ipa-ra") +#endif +#endif // MPT_COMPILER_SETTING_QUIRK_GCC_BROKEN_IPA + +#endif // MPT_COMPILER_GCC + +#if MPT_COMPILER_CLANG + +#if defined(MPT_BUILD_MSVC) +#pragma clang diagnostic warning "-Wimplicit-fallthrough" +#endif // MPT_BUILD_MSVC + +#if defined(MODPLUG_TRACKER) +#pragma clang diagnostic ignored "-Wunused-local-typedef" +#endif // MODPLUG_TRACKER + +#endif // MPT_COMPILER_CLANG diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/common/versionNumber.h new/libopenmpt-0.7.9+release.autotools/common/versionNumber.h --- old/libopenmpt-0.7.8+release.autotools/common/versionNumber.h 2024-06-09 11:52:49.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/common/versionNumber.h 2024-07-21 13:55:40.000000000 +0200 @@ -17,7 +17,7 @@ // Version definitions. The only thing that needs to be changed when changing version number. #define VER_MAJORMAJOR 1 #define VER_MAJOR 31 -#define VER_MINOR 08 +#define VER_MINOR 09 #define VER_MINORMINOR 00 OPENMPT_NAMESPACE_END diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/configure.ac new/libopenmpt-0.7.9+release.autotools/configure.ac --- old/libopenmpt-0.7.8+release.autotools/configure.ac 2024-06-09 12:58:34.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/configure.ac 2024-07-21 14:35:14.000000000 +0200 @@ -1,4 +1,4 @@ -AC_INIT([libopenmpt], [0.7.8+release.autotools], [https://bugs.openmpt.org/], [libopenmpt], [https://lib.openmpt.org/]) +AC_INIT([libopenmpt], [0.7.9+release.autotools], [https://bugs.openmpt.org/], [libopenmpt], [https://lib.openmpt.org/]) AC_PREREQ([2.69]) # we do want 2.70, but distributions are not ready yet #AC_PREREQ([2.70]) @@ -54,6 +54,18 @@ [] ) +# work-around <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115049> +# This is somewhat pessimistic, but necessary for GCC 8 or earlier, +# which we still support and where we cannot use #pragma GCC optimize. +AC_LANG_PUSH([C]) +AX_CHECK_COMPILE_FLAG([-fno-ipa-ra], [CFLAGS="$CFLAGS -fno-ipa-ra"]) +AX_CFLAGS_WARN_ALL +AC_LANG_POP([C]) +AC_LANG_PUSH([C++]) +AX_CHECK_COMPILE_FLAG([-fno-ipa-ra], [CXXFLAGS="$CXXFLAGS -fno-ipa-ra"]) +AX_CXXFLAGS_WARN_ALL +AC_LANG_POP([C++]) + LIBOPENMPT_LTVER_CURRENT=4 LIBOPENMPT_LTVER_REVISION=4 @@ -62,9 +74,9 @@ AC_SUBST([LIBOPENMPT_LTVER_REVISION]) AC_SUBST([LIBOPENMPT_LTVER_AGE]) -AC_DEFINE([MPT_SVNURL], ["https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.7.8"], [svn version]) -AC_DEFINE([MPT_SVNVERSION], ["20990"], [svn version]) -AC_DEFINE([MPT_SVNDATE], ["2024-06-09T10:46:26.177639Z"], [svn date]) +AC_DEFINE([MPT_SVNURL], ["https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.7.9"], [svn version]) +AC_DEFINE([MPT_SVNVERSION], ["21223"], [svn version]) +AC_DEFINE([MPT_SVNDATE], ["2024-07-21T12:01:13.335584Z"], [svn date]) AC_DEFINE([MPT_PACKAGE], [true], [is package]) @@ -72,8 +84,15 @@ AC_CANONICAL_HOST -case $host_os in - mingw32*) + +# work-around NetBSD toolchain not understanding transitive shared object dependencies at all +AS_CASE([$host_os], + [netbsd*], [LIBS="$LIBS -lstdc++"], + [] +) + +AS_CASE([$host_os], + [mingw32*],[ LIBOPENMPT_WIN32_LIBS= LIBOPENMPT_LIBS_PRIVATE_WIN32= LIBOPENMPTTEST_WIN32_LIBS="-lole32 -lrpcrt4" @@ -83,8 +102,8 @@ WIN32_CFLAGS="-municode -mthreads" WIN32_CONSOLE_CXXFLAGS=-mconsole WIN32_CONSOLE_CFLAGS=-mconsole - ;; - *) + ], + [ LIBOPENMPT_WIN32_LIBS= LIBOPENMPT_LIBS_PRIVATE_WIN32= LIBOPENMPTTEST_WIN32_LIBS= @@ -94,8 +113,8 @@ WIN32_CFLAGS= WIN32_CONSOLE_CXXFLAGS= WIN32_CONSOLE_CFLAGS= - ;; -esac + ] +) AC_SUBST([LIBOPENMPT_WIN32_LIBS]) AC_SUBST([LIBOPENMPTTEST_WIN32_LIBS]) AC_SUBST([OPENMPT123_WIN32_LIBS]) @@ -198,8 +217,8 @@ # Optional openmpt123 dependency AC_ARG_WITH([pulseaudio], AS_HELP_STRING([--with-pulseaudio], [Enable use of libpulse and libpulse-simple (enabled by default on Linux).])) AS_IF([test "x$enable_openmpt123" != "xno"],[ -case $host_os in - linux*) +AS_CASE([$host_os], + [linux*],[ AS_IF([test "x$with_pulseaudio" != "xno"], [ PKG_CHECK_MODULES([PULSEAUDIO], [libpulse libpulse-simple], @@ -236,8 +255,9 @@ have_pulseaudio=0 ] ) - ;; -esac + ], + [] +) ],[have_pulseaudio=0]) # Optional openmpt123 and examples dependency diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/doc/libopenmpt/changelog.md new/libopenmpt-0.7.9+release.autotools/doc/libopenmpt/changelog.md --- old/libopenmpt-0.7.8+release.autotools/doc/libopenmpt/changelog.md 2024-06-09 12:46:24.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/doc/libopenmpt/changelog.md 2024-07-21 14:01:11.000000000 +0200 @@ -5,6 +5,61 @@ For fully detailed change log, please see the source repository directly. This is just a high-level summary. +### libopenmpt 0.7.9 (2024-07-21) + + * [**Sec**] Potential division by 0 when seeking in the module with + `seek.sync_samples` enabled (r21167). + + * [**Change**] The work-around for + <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115049> has been changed from + forcing `-O1` on GCC 14 to setting `-fno-ipa-ra` on all GCC versions on + non-ELF platforms. We are still not 100% sure if this work-around is + sufficient in all circumstances. If you are using a non-ELF platform, it is + strongly recommended to update GCC to versions 12.5.0, 13.4.0, 14.2.0, or + 15.1.0 as soon as they are released, or to apply the patch from the linked + GCC issues. + + * MOD: Allow sample swapping to work when swapping from a non-looping, stopped + sample back to a looping sample (fixes MOD.energy). + * DBM: Import second sustain point in case the first sustain point is not set, + or if it has a lower index than the first. + * DBM: When several instruments referenced the same sample with different + properties (volume, loop points, etc.), only one set of properties was + imported (fixes DBM.Supernova). + * DBM: Prioritize effects more correctly when the same effect is encountered + in both effect columns of a cell (fixes DBM.143_Gnoj). + * DBM: Don't import offset effects when there's a tone portmento next to them. + * DBM: A few IT-specific playback quirks are disabled for more accurate + playback (e.g. in "Are You Flying With Me?" by Jazzcat). + * DIGI: Sample play direction was reset if adjacent channel contained a + Note Cut note. + * AMF: When running out of sample slots, file reading became be misaligned + because the sample name was not skipped. + * MED: Command 0F was not imported. + * MED: Upper frequency limits should be more accurate now. + * MED: Channel panning is now only applied in MMD2 files if the free pan flag + is set. + * MED: Volume command resolution was incorrect for pre-MMD3 files. + * XM: oggmod does not support stereo samples but keeps the stereo flag when + encoding such samples. Such samples are now imported as mono samples instead + of not importing them at all. + * XM: For files saved with registered MadTracker 2 versions, do not put + binary garbage (the user ID) in the tracker metadata field. It is replaced + with "registered" instead. + * For some truncated files, the used tracker was not identified correctly. + * S3M: Identify files saved with early Impulse Tracker versions, Sound Club 2, + Liquid Tracker, NESMusa, UNMO3, deMODifier, Kosmic To-S3M, and better tell + old ModPlug Tracker versions apart. + * S3M: When skipping sample loading, some tracker identifications were not + working as intended. + * IT: Identify files saved with itwriter. + * DTM: Identify files saved with Digital Tracker 2.3. + + * xmp-openmpt: If there is only one subsong, set the song title to the + "global" song title instead of the name of that subsong. + * xmp-openmpt: Sample and instrument names were not sanitized, sometimes + showing on multiple rows. + ### libopenmpt 0.7.8 (2024-06-09) * [**Sec**] Potential heap out-of-bounds read with malformed Dynamic Studio @@ -43,7 +98,7 @@ * IT: Disable a few more compatibility flags for older SchismTracker builds. * IT: Halve the output volume of files saved with ChibiTracker, as its mixer - * is about half as loud as ours. + is about half as loud as ours. * S3M: In mono mode, the ratio between sample and OPL volume was incorrect. * S3M: Detect files saved with PlayerPRO. * XM: Detect files saved with PlayerPRO. Improved detection of files saved diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/libopenmpt/libopenmpt_version.h new/libopenmpt-0.7.9+release.autotools/libopenmpt/libopenmpt_version.h --- old/libopenmpt-0.7.8+release.autotools/libopenmpt/libopenmpt_version.h 2024-06-09 12:46:24.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/libopenmpt/libopenmpt_version.h 2024-07-21 14:01:11.000000000 +0200 @@ -21,7 +21,7 @@ /*! \brief libopenmpt minor version number */ #define OPENMPT_API_VERSION_MINOR 7 /*! \brief libopenmpt patch version number */ -#define OPENMPT_API_VERSION_PATCH 8 +#define OPENMPT_API_VERSION_PATCH 9 /*! \brief libopenmpt pre-release tag */ #define OPENMPT_API_VERSION_PREREL "" /*! \brief libopenmpt pre-release flag */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/libopenmpt/libopenmpt_version.mk new/libopenmpt-0.7.9+release.autotools/libopenmpt/libopenmpt_version.mk --- old/libopenmpt-0.7.8+release.autotools/libopenmpt/libopenmpt_version.mk 2024-06-09 12:46:24.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/libopenmpt/libopenmpt_version.mk 2024-07-21 14:01:11.000000000 +0200 @@ -1,8 +1,8 @@ LIBOPENMPT_VERSION_MAJOR=0 LIBOPENMPT_VERSION_MINOR=7 -LIBOPENMPT_VERSION_PATCH=8 +LIBOPENMPT_VERSION_PATCH=9 LIBOPENMPT_VERSION_PREREL= LIBOPENMPT_LTVER_CURRENT=4 -LIBOPENMPT_LTVER_REVISION=8 +LIBOPENMPT_LTVER_REVISION=9 LIBOPENMPT_LTVER_AGE=4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/man/openmpt123.1 new/libopenmpt-0.7.9+release.autotools/man/openmpt123.1 --- old/libopenmpt-0.7.8+release.autotools/man/openmpt123.1 2024-06-09 12:58:33.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/man/openmpt123.1 2024-07-21 14:35:13.000000000 +0200 @@ -1,12 +1,12 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH OPENMPT123 "1" "June 2024" "openmpt123 v0.7.8" "User Commands" +.TH OPENMPT123 "1" "July 2024" "openmpt123 v0.7.9" "User Commands" .SH NAME openmpt123 - command line module music player based on libopenmpt .SH SYNOPSIS .B openmpt123 [\fI\,options\/\fR] [\fI\,--\/\fR] \fI\,file1 \/\fR[\fI\,file2\/\fR] ... .SH DESCRIPTION -openmpt123 v0.7.8, libopenmpt 0.7.8+r20990 (OpenMPT 1.31.08.00 https://source.openmpt.org/svn/openmpt/tags/libopenmpt\-0.7.8@20990 (2024\-06\-09T10:46:26.177639Z) clean) +openmpt123 v0.7.9, libopenmpt 0.7.9+r21223 (OpenMPT 1.31.09.00 https://source.openmpt.org/svn/openmpt/tags/libopenmpt\-0.7.9@21223 (2024\-07\-21T12:01:13.335584Z) clean) Copyright \(co 2013\-2024 OpenMPT Project Developers and Contributors <https://lib.openmpt.org/> .PP openmpt123 plays module music files. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/soundlib/Load_ams.cpp new/libopenmpt-0.7.9+release.autotools/soundlib/Load_ams.cpp --- old/libopenmpt-0.7.8+release.autotools/soundlib/Load_ams.cpp 2024-06-01 15:58:00.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/soundlib/Load_ams.cpp 2024-06-14 23:11:55.000000000 +0200 @@ -826,12 +826,12 @@ } uint8 numSamples = file.ReadUint8(); - uint8 sampleAssignment[120]; - MemsetZero(sampleAssignment); // Only really needed for v2.0, where the lowest and highest octave aren't cleared. + std::array<uint8, 120> sampleAssignment; + sampleAssignment.fill(0); // Only really needed for v2.0, where the lowest and highest octave aren't cleared. if(numSamples == 0 - || (fileHeader.versionLow > 0 && !file.ReadArray(sampleAssignment)) // v2.01+: 120 Notes - || (fileHeader.versionLow == 0 && !file.ReadRaw(mpt::span(sampleAssignment + 12, 96)).size())) // v2.0: 96 Notes + || (fileHeader.versionLow > 0 && !file.ReadArray(sampleAssignment)) // v2.01+: 120 Notes + || (fileHeader.versionLow == 0 && !file.ReadRaw(mpt::as_span(sampleAssignment).subspan(12, 96)).size())) // v2.0: 96 Notes { continue; } @@ -878,18 +878,17 @@ // Sample headers - we will have to read them even for shadow samples, and we will have to load them several times, // as it is possible that shadow samples use different sample settings like base frequency or panning. const SAMPLEINDEX firstSmp = GetNumSamples() + 1; + std::string sampleName; for(SAMPLEINDEX smp = 0; smp < numSamples; smp++) { - if(firstSmp + smp >= MAX_SAMPLES) - { - file.Skip(sizeof(AMS2SampleHeader)); - break; - } - file.ReadSizedString<uint8le, mpt::String::spacePadded>(m_szNames[firstSmp + smp]); - + file.ReadSizedString<uint8le, mpt::String::spacePadded>(sampleName); AMS2SampleHeader sampleHeader; file.ReadStruct(sampleHeader); + if(firstSmp + smp >= MAX_SAMPLES) + continue; + sampleHeader.ConvertToMPT(Samples[firstSmp + smp]); + m_szNames[firstSmp + smp] = sampleName; uint16 settings = (instrHeader.shadowInstr & instrIndexMask) | ((smp << sampleIndexShift) & sampleIndexMask) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/soundlib/Load_dbm.cpp new/libopenmpt-0.7.9+release.autotools/soundlib/Load_dbm.cpp --- old/libopenmpt-0.7.8+release.autotools/soundlib/Load_dbm.cpp 2023-02-25 15:41:10.000000000 +0100 +++ new/libopenmpt-0.7.9+release.autotools/soundlib/Load_dbm.cpp 2024-06-25 23:35:15.000000000 +0200 @@ -38,17 +38,17 @@ // 32-Bit chunk identifiers enum ChunkIdentifiers { - idNAME = MagicBE("NAME"), - idINFO = MagicBE("INFO"), - idSONG = MagicBE("SONG"), - idINST = MagicBE("INST"), - idVENV = MagicBE("VENV"), - idPENV = MagicBE("PENV"), - idPATT = MagicBE("PATT"), - idPNAM = MagicBE("PNAM"), - idSMPL = MagicBE("SMPL"), - idDSPE = MagicBE("DSPE"), - idMPEG = MagicBE("MPEG"), + idNAME = MagicBE("NAME"), + idINFO = MagicBE("INFO"), + idSONG = MagicBE("SONG"), + idINST = MagicBE("INST"), + idVENV = MagicBE("VENV"), + idPENV = MagicBE("PENV"), + idPATT = MagicBE("PATT"), + idPNAM = MagicBE("PNAM"), + idSMPL = MagicBE("SMPL"), + idDSPE = MagicBE("DSPE"), + idMPEG = MagicBE("MPEG"), }; uint32be id; @@ -85,18 +85,43 @@ { enum DBMInstrFlags { - smpLoop = 0x01, - smpPingPongLoop = 0x02, + smpLoop = 0x01, + smpPingPongLoop = 0x02, }; char name[30]; - uint16be sample; // Sample reference - uint16be volume; // 0...64 + uint16be sample; // Sample reference + uint16be volume; // 0...64 uint32be sampleRate; uint32be loopStart; uint32be loopLength; - int16be panning; // -128...128 - uint16be flags; // See DBMInstrFlags + int16be panning; // -128...128 + uint16be flags; // See DBMInstrFlags + + void ConvertToMPT(ModInstrument &mptIns) const + { + mptIns.name = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, name); + mptIns.nFadeOut = 0; + mptIns.nPan = static_cast<uint16>(panning + 128); + LimitMax(mptIns.nPan, uint32(256)); + mptIns.dwFlags.set(INS_SETPANNING); + } + + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.Initialize(); + mptSmp.nVolume = std::min(static_cast<uint16>(volume), uint16(64)) * 4u; + mptSmp.nC5Speed = Util::muldivr(sampleRate, 8303, 8363); + + if(loopLength && (flags & (smpLoop | smpPingPongLoop))) + { + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = mptSmp.nLoopStart + loopLength; + mptSmp.uFlags.set(CHN_LOOP); + if(flags & smpPingPongLoop) + mptSmp.uFlags.set(CHN_PINGPONGLOOP); + } + } }; MPT_BINARY_STRUCT(DBMInstrument, 50) @@ -107,19 +132,55 @@ { enum DBMEnvelopeFlags { - envEnabled = 0x01, - envSustain = 0x02, - envLoop = 0x04, + envEnabled = 0x01, + envSustain1 = 0x02, + envLoop = 0x04, + envSustain2 = 0x08, }; uint16be instrument; - uint8be flags; // See DBMEnvelopeFlags - uint8be numSegments; // Number of envelope points - 1 + uint8be flags; // See DBMEnvelopeFlags + uint8be numSegments; // Number of envelope points - 1 uint8be sustain1; uint8be loopBegin; uint8be loopEnd; - uint8be sustain2; // Second sustain point + uint8be sustain2; // Second sustain point uint16be data[2 * 32]; + + void ConvertToMPT(InstrumentEnvelope &mptEnv, bool scaleEnv) const + { + if(numSegments) + { + if(flags & envEnabled) mptEnv.dwFlags.set(ENV_ENABLED); + if(flags & (envSustain1 | envSustain2)) mptEnv.dwFlags.set(ENV_SUSTAIN); + if(flags & envLoop) mptEnv.dwFlags.set(ENV_LOOP); + } + + uint8 numPoints = std::min(numSegments.get(), uint8(31)) + 1; + mptEnv.resize(numPoints); + + mptEnv.nLoopStart = loopBegin; + mptEnv.nLoopEnd = loopEnd; + if((flags & (envSustain1 | envSustain2)) == envSustain1) + mptEnv.nSustainStart = mptEnv.nSustainEnd = sustain1; + else if((flags & (envSustain1 | envSustain2)) == envSustain2) + mptEnv.nSustainStart = mptEnv.nSustainEnd = sustain2; + else + mptEnv.nSustainStart = mptEnv.nSustainEnd = std::min(sustain1, sustain2); + + for(uint8 i = 0; i < numPoints; i++) + { + mptEnv[i].tick = data[i * 2]; + uint16 val = data[i * 2 + 1]; + if(scaleEnv) + { + // Panning envelopes are -128...128 in DigiBooster Pro 3.x + val = static_cast<uint16>((val + 128) / 4); + } + LimitMax(val, uint16(64)); + mptEnv[i].value = static_cast<uint8>(val); + } + } }; MPT_BINARY_STRUCT(DBMEnvelope, 136) @@ -137,11 +198,11 @@ CMD_NONE, CMD_PANNINGSLIDE, CMD_NONE, CMD_NONE, CMD_NONE, CMD_NONE, CMD_NONE, #ifndef NO_PLUGINS - CMD_DBMECHO, // Toggle DSP - CMD_MIDI, // Wxx Echo Delay - CMD_MIDI, // Xxx Echo Feedback - CMD_MIDI, // Yxx Echo Mix - CMD_MIDI, // Zxx Echo Cross + CMD_DBMECHO, // Toggle DSP + CMD_MIDI, // Wxx Echo Delay + CMD_MIDI, // Xxx Echo Feedback + CMD_MIDI, // Yxx Echo Mix + CMD_MIDI, // Zxx Echo Cross #endif // NO_PLUGINS }; @@ -197,15 +258,15 @@ case CMD_MODCMDEX: switch(param & 0xF0) { - case 0x30: // Play backwards + case 0x30: // Play backwards command = CMD_S3MCMDEX; param = 0x9F; break; - case 0x40: // Turn off sound in channel (volume / portamento commands after this can't pick up the note anymore) + case 0x40: // Turn off sound in channel (volume / portamento commands after this can't pick up the note anymore) command = CMD_S3MCMDEX; param = 0xC0; break; - case 0x50: // Turn on/off channel + case 0x50: // Turn on/off channel // TODO: Apparently this should also kill the playing note. if((param & 0x0F) <= 0x01) { @@ -213,7 +274,7 @@ param = (param == 0x50) ? 0x00 : 0x40; } break; - case 0x70: // Coarse offset + case 0x70: // Coarse offset command = CMD_S3MCMDEX; param = 0xA0 | (param & 0x0F); break; @@ -258,35 +319,7 @@ uint16 dbmIns = dbmEnv.instrument; if(dbmIns > 0 && dbmIns <= sndFile.GetNumInstruments() && (sndFile.Instruments[dbmIns] != nullptr)) { - ModInstrument *mptIns = sndFile.Instruments[dbmIns]; - InstrumentEnvelope &mptEnv = mptIns->GetEnvelope(envType); - - if(dbmEnv.numSegments) - { - if(dbmEnv.flags & DBMEnvelope::envEnabled) mptEnv.dwFlags.set(ENV_ENABLED); - if(dbmEnv.flags & DBMEnvelope::envSustain) mptEnv.dwFlags.set(ENV_SUSTAIN); - if(dbmEnv.flags & DBMEnvelope::envLoop) mptEnv.dwFlags.set(ENV_LOOP); - } - - uint8 numPoints = std::min(dbmEnv.numSegments.get(), uint8(31)) + 1; - mptEnv.resize(numPoints); - - mptEnv.nLoopStart = dbmEnv.loopBegin; - mptEnv.nLoopEnd = dbmEnv.loopEnd; - mptEnv.nSustainStart = mptEnv.nSustainEnd = dbmEnv.sustain1; - - for(uint8 i = 0; i < numPoints; i++) - { - mptEnv[i].tick = dbmEnv.data[i * 2]; - uint16 val = dbmEnv.data[i * 2 + 1]; - if(scaleEnv) - { - // Panning envelopes are -128...128 in DigiBooster Pro 3.x - val = (val + 128) / 4; - } - LimitMax(val, uint16(64)); - mptEnv[i].value = static_cast<uint8>(val); - } + dbmEnv.ConvertToMPT(sndFile.Instruments[dbmIns]->GetEnvelope(envType), scaleEnv); } } } @@ -356,6 +389,8 @@ m_playBehaviour.set(kSlidesAtSpeed1); m_playBehaviour.reset(kITVibratoTremoloPanbrello); m_playBehaviour.reset(kITArpeggio); + m_playBehaviour.reset(kITInstrWithNoteOff); + m_playBehaviour.reset(kITInstrWithNoteOffOldEffects); m_modFormat.formatName = U_("DigiBooster Pro"); m_modFormat.type = U_("dbm"); @@ -407,41 +442,41 @@ #endif // MPT_DBM_USE_REAL_SUBSONGS // Read instruments + std::map<SAMPLEINDEX, SAMPLEINDEX> copySample; if(FileReader instChunk = chunks.GetChunk(DBMChunk::idINST)) { + std::set<SAMPLEINDEX> sampleUsed; for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) { DBMInstrument instrHeader; instChunk.ReadStruct(instrHeader); - ModInstrument *mptIns = AllocateInstrument(i, instrHeader.sample); - if(mptIns == nullptr || instrHeader.sample >= MAX_SAMPLES) + SAMPLEINDEX mappedSample = instrHeader.sample; + if(sampleUsed.count(mappedSample) && CanAddMoreSamples()) { - continue; + ModSample mptSmp; + instrHeader.ConvertToMPT(mptSmp); + const ModSample &origSmp = Samples[mappedSample]; + if(mptSmp.nVolume != origSmp.nVolume + || mptSmp.uFlags != origSmp.uFlags + || mptSmp.nLoopStart != origSmp.nLoopStart + || mptSmp.nLoopEnd != origSmp.nLoopEnd + || mptSmp.nC5Speed != origSmp.nC5Speed) + { + // Need to duplicate + mappedSample = ++m_nSamples; + copySample.emplace(mappedSample, instrHeader.sample); + } } + ModInstrument *mptIns = AllocateInstrument(i, mappedSample); + if(mptIns == nullptr || mappedSample >= MAX_SAMPLES) + continue; - mptIns->name = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, instrHeader.name); - m_szNames[instrHeader.sample] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, instrHeader.name); - - mptIns->nFadeOut = 0; - mptIns->nPan = static_cast<uint16>(instrHeader.panning + 128); - LimitMax(mptIns->nPan, uint32(256)); - mptIns->dwFlags.set(INS_SETPANNING); - + instrHeader.ConvertToMPT(*mptIns); // Sample Info - ModSample &mptSmp = Samples[instrHeader.sample]; - mptSmp.Initialize(); - mptSmp.nVolume = std::min(static_cast<uint16>(instrHeader.volume), uint16(64)) * 4u; - mptSmp.nC5Speed = Util::muldivr(instrHeader.sampleRate, 8303, 8363); - - if(instrHeader.loopLength && (instrHeader.flags & (DBMInstrument::smpLoop | DBMInstrument::smpPingPongLoop))) - { - mptSmp.nLoopStart = instrHeader.loopStart; - mptSmp.nLoopEnd = mptSmp.nLoopStart + instrHeader.loopLength; - mptSmp.uFlags.set(CHN_LOOP); - if(instrHeader.flags & DBMInstrument::smpPingPongLoop) - mptSmp.uFlags.set(CHN_PINGPONGLOOP); - } + instrHeader.ConvertToMPT(Samples[mappedSample]); + m_szNames[mappedSample] = mptIns->name; + sampleUsed.insert(mappedSample); } // Read envelopes @@ -466,7 +501,7 @@ if(patternChunk.IsValid() && (loadFlags & loadPatternData)) { FileReader patternNameChunk = chunks.GetChunk(DBMChunk::idPNAM); - patternNameChunk.Skip(1); // Encoding, should be UTF-8 or ASCII + patternNameChunk.Skip(1); // Encoding (0 = unspecified ASCII-compatible 8-bit encoding, 106 = UTF-8) Patterns.ResizeArray(infoData.patterns); std::vector<std::pair<EffectCommand, ModCommand::PARAM>> lostGlobalCommands; @@ -538,6 +573,14 @@ { std::swap(cmd1, cmd2); std::swap(param1, param2); + } else if(cmd1 == CMD_TONEPORTAMENTO && cmd2 == CMD_OFFSET && param2 == 0) + { + // Offset + Portmaneto: Ignore portamento. If the offset command has a non-zero parameter, keep it for effect memory. + cmd2 = CMD_NONE; + } else if(cmd2 == CMD_TONEPORTAMENTO && cmd1 == CMD_OFFSET && param1 == 0) + { + // Ditto + cmd1 = CMD_NONE; } const auto lostCommand = m.FillInTwoCommands(cmd1, param1, cmd2, param2); @@ -641,6 +684,13 @@ { for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { + if(auto copyFrom = copySample.find(smp); copyFrom != copySample.end()) + { + Samples[smp].nLength = Samples[copyFrom->second].nLength; + Samples[smp].CopyWaveform(Samples[copyFrom->second]); + continue; + } + uint32 sampleFlags = sampleChunk.ReadUint32BE(); uint32 sampleLength = sampleChunk.ReadUint32BE(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/soundlib/Load_dtm.cpp new/libopenmpt-0.7.9+release.autotools/soundlib/Load_dtm.cpp --- old/libopenmpt-0.7.8+release.autotools/soundlib/Load_dtm.cpp 2024-06-08 15:44:28.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/soundlib/Load_dtm.cpp 2024-06-14 23:11:55.000000000 +0200 @@ -576,6 +576,9 @@ if(patternFormat == DTM_206_PATTERN_FORMAT) { tracker = U_("Digital Home Studio"); + } else if(patternFormat == DTM_PT_PATTERN_FORMAT) + { + tracker = U_("Digital Tracker 2.3"); } else if(FileReader chunk = chunks.GetChunk(DTMChunk::idVERS)) { uint32 version = chunk.ReadUint32BE(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/soundlib/Load_it.cpp new/libopenmpt-0.7.9+release.autotools/soundlib/Load_it.cpp --- old/libopenmpt-0.7.8+release.autotools/soundlib/Load_it.cpp 2024-05-06 21:58:26.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/soundlib/Load_it.cpp 2024-06-14 23:11:55.000000000 +0200 @@ -1320,7 +1320,12 @@ madeWithTracker = MPT_UFORMAT("ITMCK {}.{}.{}")((fileHeader.cwtv >> 8) & 0x0F, (fileHeader.cwtv >> 4) & 0x0F, fileHeader.cwtv & 0x0F); break; case 0xD: - madeWithTracker = U_("spc2it"); + if(fileHeader.cwtv == 0xDAEB) + madeWithTracker = U_("spc2it"); + else if(fileHeader.cwtv == 0xD1CE) + madeWithTracker = U_("itwriter"); + else + madeWithTracker = U_("Unknown"); break; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/soundlib/Load_med.cpp new/libopenmpt-0.7.9+release.autotools/soundlib/Load_med.cpp --- old/libopenmpt-0.7.8+release.autotools/soundlib/Load_med.cpp 2024-06-06 22:31:37.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/soundlib/Load_med.cpp 2024-07-20 16:22:36.000000000 +0200 @@ -419,9 +419,11 @@ if(param > 0 && param <= 20) m.SetEffectCommand(CMD_SPEED, param); break; - case 0x0C: // Set Volume + case 0x0C: // Set Volume (note: parameters >= 0x80 (only in hex mode?) should set the default instrument volume, which we don't support) if(!ctx.volHex && param < 0x99) m.SetEffectCommand(CMD_VOLUME, static_cast<ModCommand::PARAM>((param >> 4) * 10 + (param & 0x0F))); + else if(ctx.volHex && ctx.version < 3) + m.SetEffectCommand(CMD_VOLUME, static_cast<ModCommand::PARAM>(std::min(param & 0x7F, 64))); else if(ctx.volHex) m.SetEffectCommand(CMD_VOLUME, static_cast<ModCommand::PARAM>(((param & 0x7F) + 1) / 2)); break; @@ -458,7 +460,7 @@ if(m.param < 0x20) m.param = 0x20; #endif // MODPLUG_TRACKER - } else switch(command) + } else switch(param) { case 0xF1: // Play note twice m.SetEffectCommand(CMD_MODCMDEX, 0x93); @@ -603,7 +605,7 @@ cmd = command; param1 = param; } - // Octave wrapping for 4-channel modules (TODO: this should not be set because of synth instruments) + // Octave wrapping for 4-channel modules if(ctx.hardwareMixSamples && note >= NOTE_MIDDLEC + 2 * 12) needInstruments = true; @@ -794,6 +796,7 @@ // - starkelsesirap.mmd0 (synth instruments) on the other hand don't need it // In MMD2 / MMD3, the mix flag is used instead. const bool hardwareMixSamples = (version < 2) || (version >= 2 && !(songHeader.flags2 & MMDSong::FLAG2_MIX)); + m_nMinPeriod = hardwareMixSamples ? (113 * 4) : (55 * 4); bool needInstruments = false; bool anySynthInstrs = false; @@ -1153,7 +1156,7 @@ ChnSettings[chn].nVolume = std::min<uint8>(file.ReadUint8(), 64); } } - if(header.trackPanOffset && file.Seek(header.trackPanOffset)) + if((freePan || version > 2) && header.trackPanOffset && file.Seek(header.trackPanOffset)) { for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++) { @@ -1183,11 +1186,11 @@ mixPlug.Info.szLibraryName = "Echo"; std::array<float32le, 6> params{}; - params[1] = 1.0f; // WetDryMix - params[2] = feedback; // Feedback - params[3] = delay; // LeftDelay - params[4] = delay; // RightDelay - params[5] = header.mixEchoType == 2 ? 1.0f : 0.0f; // PanDelay + params[1] = 1.0f; // WetDryMix + params[2] = feedback; // Feedback + params[3] = delay; // LeftDelay + params[4] = delay; // RightDelay + params[5] = header.mixEchoType - 1.0f; // PanDelay mixPlug.pluginData.resize(sizeof(params)); memcpy(mixPlug.pluginData.data(), params.data(), sizeof(params)); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/soundlib/Load_mid.cpp new/libopenmpt-0.7.9+release.autotools/soundlib/Load_mid.cpp --- old/libopenmpt-0.7.8+release.autotools/soundlib/Load_mid.cpp 2023-04-29 21:43:40.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/soundlib/Load_mid.cpp 2024-06-22 20:45:37.000000000 +0200 @@ -270,9 +270,12 @@ }; +static constexpr uint8 NUM_MIDI_CHANNELS = 32; + + //////////////////////////////////////////////////////////////////////////////// // Maps a midi instrument - returns the instrument number in the file -uint32 CSoundFile::MapMidiInstrument(uint8 program, uint16 bank, uint8 midiChannel, uint8 note, bool isXG, std::bitset<16> drumChns) +uint32 CSoundFile::MapMidiInstrument(uint8 program, uint16 bank, uint8 midiChannel, uint8 note, bool isXG, std::bitset<NUM_MIDI_CHANNELS> drumChns) { ModInstrument *pIns; program &= 0x7F; @@ -361,6 +364,7 @@ FileReader track; tick_t nextEvent = 0; uint8 command = 0; + uint8 midiBaseChannel = 0; bool finished = false; }; @@ -506,7 +510,7 @@ } -static void MIDINoteOff(MidiChannelState &midiChn, std::vector<ModChannelState> &modChnStatus, uint8 note, uint8 delay, mpt::span<ModCommand> patRow, std::bitset<16> drumChns) +static void MIDINoteOff(MidiChannelState &midiChn, std::vector<ModChannelState> &modChnStatus, uint8 note, uint8 delay, mpt::span<ModCommand> patRow, std::bitset<NUM_MIDI_CHANNELS> drumChns) { CHANNELINDEX chn = midiChn.noteOn[note]; if(chn == CHANNELINDEX_INVALID) @@ -666,13 +670,14 @@ ppqn = 96; Order().clear(); - MidiChannelState midiChnStatus[16]; + std::array<MidiChannelState, NUM_MIDI_CHANNELS> midiChnStatus; const CHANNELINDEX tempoChannel = m_nChannels - 2, globalVolChannel = m_nChannels - 1; const uint16 numTracks = fileHeader.numTracks; std::vector<TrackState> tracks(numTracks); std::vector<ModChannelState> modChnStatus(m_nChannels); - std::bitset<16> drumChns; + std::bitset<NUM_MIDI_CHANNELS> drumChns; drumChns.set(MIDI_DRUMCHANNEL - 1); + drumChns.set(MIDI_DRUMCHANNEL + 15); tick_t timeShift = 0; for(auto &track : tracks) @@ -820,6 +825,9 @@ case 8: // Patch name case 9: // Port name break; + case 0x21: // MIDI port + tracks[t].midiBaseChannel = chunk.ReadUint8() * 16u; + break; case 0x2F: // End Of Track tracks[t].finished = true; break; @@ -840,6 +848,14 @@ tempo = newTempo; } break; + case 0x7F: // Sequencer specific + { + // Yamaha MIDI port selection + uint32 data = chunk.ReadUint32BE(); + if(chunk.LengthIs(4) && (data & 0xFFFFFF00) == 0x43000100) + tracks[t].midiBaseChannel = static_cast<uint8>((data & 0xFF) * 16u); + } + break; default: break; @@ -857,7 +873,7 @@ data1 = track.ReadUint8(); } } - uint8 midiCh = command & 0x0F; + const uint8 midiCh = ((command & 0x0F) + tracks[t].midiBaseChannel) % NUM_MIDI_CHANNELS; switch(command & 0xF0) { @@ -1079,7 +1095,7 @@ midiChnStatus[midiCh].SetPitchbend(data1 | (track.ReadUint8() << 7)); break; case 0xF0: // General / Immediate - switch(midiCh) + switch(command & 0x0F) { case MIDIEvents::sysExStart: // SysEx case MIDIEvents::sysExEnd: // SysEx (continued) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/soundlib/Load_s3m.cpp new/libopenmpt-0.7.9+release.autotools/soundlib/Load_s3m.cpp --- old/libopenmpt-0.7.8+release.autotools/soundlib/Load_s3m.cpp 2024-05-11 17:30:11.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/soundlib/Load_s3m.cpp 2024-07-13 19:37:24.000000000 +0200 @@ -35,7 +35,7 @@ case '@': m.command = (m.param ? CMD_DUMMY : CMD_NONE); break; case 'A': m.command = CMD_SPEED; break; case 'B': m.command = CMD_POSITIONJUMP; break; - case 'C': m.command = CMD_PATTERNBREAK; if (!fromIT) m.param = (m.param >> 4) * 10 + (m.param & 0x0F); break; + case 'C': m.command = CMD_PATTERNBREAK; if(!fromIT) m.param = static_cast<uint8>((m.param >> 4) * 10 + (m.param & 0x0F)); break; case 'D': m.command = CMD_VOLUMESLIDE; break; case 'E': m.command = CMD_PORTAMENTODOWN; break; case 'F': m.command = CMD_PORTAMENTOUP; break; @@ -86,8 +86,8 @@ case CMD_POSITIONJUMP: command = 'B'; break; case CMD_PATTERNBREAK: command = 'C'; if(!toIT) param = ((param / 10) << 4) + (param % 10); break; case CMD_VOLUMESLIDE: command = 'D'; break; - case CMD_PORTAMENTODOWN: command = 'E'; if (param >= 0xE0 && (GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM))) param = 0xDF; break; - case CMD_PORTAMENTOUP: command = 'F'; if (param >= 0xE0 && (GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM))) param = 0xDF; break; + case CMD_PORTAMENTODOWN: command = 'E'; if(param >= 0xE0 && (GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM))) param = 0xDF; break; + case CMD_PORTAMENTOUP: command = 'F'; if(param >= 0xE0 && (GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM))) param = 0xDF; break; case CMD_TONEPORTAMENTO: command = 'G'; break; case CMD_VIBRATO: command = 'H'; break; case CMD_TREMOR: command = 'I'; break; @@ -110,11 +110,11 @@ command = 'X'; if(toIT && !(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM | MOD_TYPE_MOD))) { - if (param == 0xA4) { command = 'S'; param = 0x91; } - else if (param == 0x80) { param = 0xFF; } - else if (param < 0x80) { param <<= 1; } + if(param == 0xA4) { command = 'S'; param = 0x91; } + else if(param == 0x80) { param = 0xFF; } + else if(param < 0x80) { param <<= 1; } else command = 0; - } else if (!toIT && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM | MOD_TYPE_MOD))) + } else if(!toIT && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM | MOD_TYPE_MOD))) { param >>= 1; } @@ -240,43 +240,50 @@ bool nonCompatTracker = false; bool isST3 = false; bool isSchism = false; + const bool usePanningTable = fileHeader.usePanningTable == S3MFileHeader::idPanning; const int32 schismDateVersion = SchismTrackerEpoch + ((fileHeader.cwtv == 0x4FFF) ? fileHeader.reserved2 : (fileHeader.cwtv - 0x4050)); switch(fileHeader.cwtv & S3MFileHeader::trackerMask) { case S3MFileHeader::trkAkord & S3MFileHeader::trackerMask: if(fileHeader.cwtv == S3MFileHeader::trkAkord) - madeWithTracker = U_("Akord"); + madeWithTracker = UL_("Akord"); break; case S3MFileHeader::trkScreamTracker: - if(fileHeader.cwtv == S3MFileHeader::trkST3_20 && fileHeader.special == 0 && (fileHeader.ordNum & 0x0F) == 0 && fileHeader.ultraClicks == 0 && (fileHeader.flags & ~0x50) == 0 && fileHeader.usePanningTable == S3MFileHeader::idPanning) + if(!memcmp(&fileHeader.reserved2, "SCLUB2.0", 8)) + { + madeWithTracker = UL_("Sound Club 2"); + } else if(fileHeader.cwtv == S3MFileHeader::trkST3_20 && fileHeader.special == 0 && (fileHeader.ordNum & 0x0F) == 0 && fileHeader.ultraClicks == 0 && (fileHeader.flags & ~0x50) == 0 && usePanningTable) { // MPT and OpenMPT before 1.17.03.02 - Simply keep default (filter) MIDI macros if((fileHeader.masterVolume & 0x80) != 0) { - m_dwLastSavedWithVersion = MPT_V("1.16.00.00"); - madeWithTracker = U_("ModPlug Tracker / OpenMPT 1.17"); + m_dwLastSavedWithVersion = MPT_V("1.16"); + madeWithTracker = UL_("ModPlug Tracker / OpenMPT 1.17"); } else { - // MPT 1.0 alpha5 doesn't set the stereo flag, but MPT 1.0 beta1 does. - m_dwLastSavedWithVersion = MPT_V("1.00.00.00"); - madeWithTracker = U_("ModPlug Tracker 1.0 alpha"); + // MPT 1.0 alpha5 doesn't set the stereo flag, but MPT 1.0 alpha6 does. + m_dwLastSavedWithVersion = MPT_V("1.00.00.A0"); + madeWithTracker = UL_("ModPlug Tracker 1.0 alpha"); } keepMidiMacros = true; nonCompatTracker = true; m_playBehaviour.set(kST3LimitPeriod); - } else if(fileHeader.cwtv == S3MFileHeader::trkST3_20 && fileHeader.special == 0 && fileHeader.ultraClicks == 0 && fileHeader.flags == 0 && fileHeader.usePanningTable == 0) + } else if(fileHeader.cwtv == S3MFileHeader::trkST3_20 && fileHeader.special == 0 && fileHeader.ultraClicks == 0 && fileHeader.flags == 0 && !usePanningTable) { if(fileHeader.globalVol == 64 && fileHeader.masterVolume == 48) - madeWithTracker = U_("PlayerPRO"); + madeWithTracker = UL_("PlayerPRO"); else // Always stereo - madeWithTracker = U_("Velvet Studio"); + madeWithTracker = UL_("Velvet Studio"); + } else if(fileHeader.cwtv == S3MFileHeader::trkST3_20 && fileHeader.special == 0 && fileHeader.ultraClicks == 0 && fileHeader.flags == 8 && !usePanningTable) + { + madeWithTracker = UL_("Impulse Tracker < 1.03"); // Not sure if 1.02 saves like this as I don't have it } else { // ST3.20 should only ever write ultra-click values 16, 24 and 32 (corresponding to 8, 12 and 16 in the GUI), ST3.01/3.03 should only write 0, // though several ST3.01/3.03 files with ultra-click values of 16 have been found as well. // However, we won't fingerprint these values here as it's unlikely that there is any other tracker out there disguising as ST3 and using a strange ultra-click value. // Also, re-saving a file with a strange ultra-click value in ST3 doesn't fix this value unless the user manually changes it, or if it's below 16. - madeWithTracker = U_("Scream Tracker"); + madeWithTracker = UL_("Scream Tracker"); formatTrackerStr = true; isST3 = true; } @@ -284,16 +291,19 @@ case S3MFileHeader::trkImagoOrpheus: formatTrackerStr = (fileHeader.cwtv != S3MFileHeader::trkPlayerPRO); if(formatTrackerStr) - madeWithTracker = U_("Imago Orpheus"); + madeWithTracker = UL_("Imago Orpheus"); else - madeWithTracker = U_("PlayerPRO"); + madeWithTracker = UL_("PlayerPRO"); nonCompatTracker = true; break; case S3MFileHeader::trkImpulseTracker: if(fileHeader.cwtv <= S3MFileHeader::trkIT2_14) { - madeWithTracker = U_("Impulse Tracker"); + madeWithTracker = UL_("Impulse Tracker"); formatTrackerStr = true; + } else if(fileHeader.cwtv == S3MFileHeader::trkIT1_old) + { + madeWithTracker = UL_("Impulse Tracker 1.03"); // Could also be 1.02, maybe? I don't have that one } else { madeWithTracker = MPT_UFORMAT("Impulse Tracker 2.14p{}")(fileHeader.cwtv - S3MFileHeader::trkIT2_14); @@ -317,7 +327,7 @@ case S3MFileHeader::trkSchismTracker: if(fileHeader.cwtv == S3MFileHeader::trkBeRoTrackerOld) { - madeWithTracker = U_("BeRoTracker"); + madeWithTracker = UL_("BeRoTracker"); m_playBehaviour.set(kST3LimitPeriod); } else { @@ -333,28 +343,40 @@ nonCompatTracker = true; break; case S3MFileHeader::trkOpenMPT: - if(fileHeader.cwtv != S3MFileHeader::trkGraoumfTracker) + if((fileHeader.cwtv & 0xFF00) == S3MFileHeader::trkNESMusa) + { + madeWithTracker = UL_("NESMusa"); + formatTrackerStr = true; + } else if(fileHeader.reserved2 == 0 && fileHeader.ultraClicks == 16 && fileHeader.channels[1] != 1) + { + // Liquid Tracker's ID clashes with OpenMPT's. + // OpenMPT started writing full version information with OpenMPT 1.29 and later changed the ultraClicks value from 8 to 16. + // Liquid Tracker writes an ultraClicks value of 16. + // So we assume that a file was saved with Liquid Tracker if the reserved fields are 0 and ultraClicks is 16. + madeWithTracker = UL_("Liquid Tracker"); + formatTrackerStr = true; + } else if(fileHeader.cwtv != S3MFileHeader::trkGraoumfTracker) { uint32 mptVersion = (fileHeader.cwtv & S3MFileHeader::versionMask) << 16; if(mptVersion >= 0x01'29'00'00) mptVersion |= fileHeader.reserved2; m_dwLastSavedWithVersion = Version(mptVersion); - madeWithTracker = U_("OpenMPT ") + mpt::ufmt::val(m_dwLastSavedWithVersion); + madeWithTracker = UL_("OpenMPT ") + mpt::ufmt::val(m_dwLastSavedWithVersion); } else { - madeWithTracker = U_("Graoumf Tracker"); + madeWithTracker = UL_("Graoumf Tracker"); } break; case S3MFileHeader::trkBeRoTracker: - madeWithTracker = U_("BeRoTracker"); + madeWithTracker = UL_("BeRoTracker"); m_playBehaviour.set(kST3LimitPeriod); break; case S3MFileHeader::trkCreamTracker: - madeWithTracker = U_("CreamTracker"); + madeWithTracker = UL_("CreamTracker"); break; default: if(fileHeader.cwtv == S3MFileHeader::trkCamoto) - madeWithTracker = U_("Camoto"); + madeWithTracker = UL_("Camoto"); break; } if(formatTrackerStr) @@ -362,8 +384,8 @@ madeWithTracker = MPT_UFORMAT("{} {}.{}")(madeWithTracker, (fileHeader.cwtv & 0xF00) >> 8, mpt::ufmt::hex0<2>(fileHeader.cwtv & 0xFF)); } - m_modFormat.formatName = U_("Scream Tracker 3"); - m_modFormat.type = U_("s3m"); + m_modFormat.formatName = UL_("Scream Tracker 3"); + m_modFormat.type = UL_("s3m"); m_modFormat.madeWithTracker = std::move(madeWithTracker); m_modFormat.charset = m_dwLastSavedWithVersion ? mpt::Charset::Windows1252 : mpt::Charset::CP437; @@ -377,7 +399,7 @@ m_playBehaviour.reset(kST3OffsetWithoutInstrument); m_playBehaviour.reset(kApplyUpperPeriodLimit); } - if (fileHeader.cwtv <= S3MFileHeader::trkST3_01) + if(fileHeader.cwtv <= S3MFileHeader::trkST3_01) { // This broken behaviour is not present in ST3.01 m_playBehaviour.reset(kST3TonePortaWithAdlibNote); @@ -498,16 +520,28 @@ file.ReadVector(patternOffsets, fileHeader.patNum); // Read extended channel panning - if(fileHeader.usePanningTable == S3MFileHeader::idPanning) + if(usePanningTable) { + bool hasChannelsWithoutPanning = false; const auto pan = file.ReadArray<uint8, 32>(); for(CHANNELINDEX i = 0; i < 32; i++) { if((pan[i] & 0x20) != 0 && (!isST3 || !isAdlibChannel[i])) { ChnSettings[i].nPan = (static_cast<uint16>(pan[i] & 0x0F) * 256 + 8) / 15; + } else if(pan[i] < 0x10) + { + hasChannelsWithoutPanning = true; } } + if(m_nChannels < 32 && m_dwLastSavedWithVersion == MPT_V("1.16")) + { + // MPT 1.0 alpha 6 up to 1.16.203 set ths panning bit for all channels, regardless of whether they are used or not. + if(hasChannelsWithoutPanning) + m_modFormat.madeWithTracker = UL_("ModPlug Tracker 1.16 / OpenMPT 1.17"); + else + m_modFormat.madeWithTracker = UL_("ModPlug Tracker"); + } } // Reading sample headers @@ -528,11 +562,11 @@ if(sampleHeader.sampleType < S3MSampleHeader::typeAdMel) { - const uint32 sampleOffset = sampleHeader.GetSampleOffset(); - if((loadFlags & loadSampleData) && sampleHeader.length != 0 && file.Seek(sampleOffset)) + if(sampleHeader.length != 0) { SampleIO sampleIO = sampleHeader.GetSampleFormat((fileHeader.formatVersion == S3MFileHeader::oldVersion)); - sampleIO.ReadSample(Samples[smp + 1], file); + if((loadFlags & loadSampleData) && file.Seek(sampleHeader.GetSampleOffset())) + sampleIO.ReadSample(Samples[smp + 1], file); anySamples = true; if(sampleIO.GetEncoding() == SampleIO::ADPCM) anyADPCM = true; @@ -548,7 +582,17 @@ // Hence if a file claims to be written with ST3 (but not ST3.00), but has no GUS addresses, we deduce that it must be written by some other software (e.g. some PSM -> S3M conversions) isST3 = false; MPT_UNUSED(isST3); - m_modFormat.madeWithTracker = U_("Unknown"); + m_modFormat.madeWithTracker = UL_("Unknown"); + // Check these only after we are certain that it can't be ST3.01 because that version doesn't sanitize the ultraClicks value yet + if(fileHeader.cwtv == S3MFileHeader::trkST3_01 && fileHeader.ultraClicks == 0) + { + if(!(fileHeader.flags & ~(S3MFileHeader::fastVolumeSlides | S3MFileHeader::amigaLimits)) && (fileHeader.masterVolume & 0x80) && usePanningTable) + m_modFormat.madeWithTracker = UL_("UNMO3"); + else if(!fileHeader.flags && fileHeader.globalVol == 48 && fileHeader.masterVolume == 176 && fileHeader.tempo == 150 && !usePanningTable) + m_modFormat.madeWithTracker = UL_("deMODifier"); // SoundSmith to S3M converter + else if(!fileHeader.flags && fileHeader.globalVol == 64 && (fileHeader.masterVolume & 0x7F) == 48 && fileHeader.speed == 6 && fileHeader.tempo == 125 && !usePanningTable) + m_modFormat.madeWithTracker = UL_("Kosmic To-S3M"); // MTM to S3M converter by Zab/Kosmic + } } else if(isST3) { // Saving an S3M file in ST3 with the Gravis Ultrasound driver loaded will write a unique GUS memory address for each non-empty sample slot (and 0 for unused slots). @@ -565,7 +609,7 @@ } if(anyADPCM) - m_modFormat.madeWithTracker += U_(" (ADPCM packed)"); + m_modFormat.madeWithTracker += UL_(" (ADPCM packed)"); // Try to find out if Zxx commands are supposed to be panning commands (PixPlay). // Actually I am only aware of one module that uses this panning style, namely "Crawling Despair" by $volkraq diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/soundlib/Load_xm.cpp new/libopenmpt-0.7.9+release.autotools/soundlib/Load_xm.cpp --- old/libopenmpt-0.7.8+release.autotools/soundlib/Load_xm.cpp 2024-05-11 21:51:49.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/soundlib/Load_xm.cpp 2024-07-13 19:29:22.000000000 +0200 @@ -480,6 +480,13 @@ { decodedSamples = ret; LimitMax(decodedSamples, mpt::saturate_cast<long>(sample.nLength - offset)); + if(offset == 0 && channels == 1 && sample.GetNumChannels() == 2) + { + // oggmod doesn't know what stereo samples are, so it treats them as mono samples, but doesn't clear the unknown stereo flag. + // We just take the left channel in this case, as it is difficult (if possible at all) to properly reconstruct the waveform of the right channel. + // Due to XM's delta-encoding and Vorbis being a lossless codec, samples could distort easily even when the delta encoding was off by a very small amount. + sample.uFlags.reset(CHN_STEREO); + } if(decodedSamples > 0 && channels == sample.GetNumChannels()) { if(sample.uFlags[CHN_16BIT]) @@ -663,6 +670,10 @@ // Fix arpeggios in kragle_-_happy_day.xm m_playBehaviour.reset(kFT2Arpeggio); isMadTracker = true; + if(memcmp(fileHeader.trackerName + 15, "\0\0\0\0", 4)) + madeWithTracker = UL_("MadTracker 2 (registered)"); + else + madeWithTracker = UL_("MadTracker 2"); } else if(!memcmp(fileHeader.trackerName, "Skale Tracker\0", 14) || !memcmp(fileHeader.trackerName, "Sk@le Tracker\0", 14)) { m_playBehaviour.reset(kFT2ST3OffsetOutOfRange); @@ -720,6 +731,11 @@ // Reading instruments for(INSTRUMENTINDEX instr = 1; instr <= m_nInstruments; instr++) { + if(!AllocateInstrument(instr)) + return false; + if(!file.CanRead(4)) + continue; + // First, try to read instrument header length... uint32 headerSize = file.ReadUint32LE(); if(headerSize == 0) @@ -782,11 +798,6 @@ } } - if(AllocateInstrument(instr) == nullptr) - { - continue; - } - instrHeader.ConvertToMPT(*Instruments[instr]); if(lastInstrType == -1) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/soundlib/S3MTools.h new/libopenmpt-0.7.9+release.autotools/soundlib/S3MTools.h --- old/libopenmpt-0.7.8+release.autotools/soundlib/S3MTools.h 2024-05-11 17:30:11.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/soundlib/S3MTools.h 2024-07-13 19:37:24.000000000 +0200 @@ -46,14 +46,16 @@ trkAkord = 0x0208, trkST3_00 = 0x1300, - trkST3_20 = 0x1320, trkST3_01 = 0x1301, + trkST3_20 = 0x1320, + trkIT1_old = 0x3320, trkIT2_07 = 0x3207, trkIT2_14 = 0x3214, trkBeRoTrackerOld = 0x4100, // Used from 2004 to 2012 trkGraoumfTracker = 0x5447, + trkNESMusa = 0x5700, trkCamoto = 0xCA00, - trkPlayerPRO = 0x2013 // PlayerPRO on Intel doesn't byte-swap the tracker ID bytes + trkPlayerPRO = 0x2013, // PlayerPRO on Intel doesn't byte-swap the tracker ID bytes }; // Flags diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/soundlib/Snd_fx.cpp new/libopenmpt-0.7.9+release.autotools/soundlib/Snd_fx.cpp --- old/libopenmpt-0.7.8+release.autotools/soundlib/Snd_fx.cpp 2024-06-08 15:44:28.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/soundlib/Snd_fx.cpp 2024-07-14 15:28:14.000000000 +0200 @@ -220,7 +220,7 @@ if(chn.position >= sampleEnd || (chn.position < loopStart && inc.IsNegative())) { - if(!chn.dwFlags[CHN_LOOP]) + if(!chn.dwFlags[CHN_LOOP] || !loopLength) { // Past sample end. stopNote = true; @@ -1064,7 +1064,8 @@ { if(m.command == CMD_OFFSET) { - ProcessSampleOffset(chn, nChn, playState); + if(!porta || !(GetType() & (MOD_TYPE_XM | MOD_TYPE_DBM))) + ProcessSampleOffset(chn, nChn, playState); } else if(m.command == CMD_OFFSETPERCENTAGE) { SampleOffset(chn, Util::muldiv_unsigned(chn.nLength, m.param, 256)); @@ -1365,7 +1366,7 @@ void CSoundFile::InstrumentChange(ModChannel &chn, uint32 instr, bool bPorta, bool bUpdVol, bool bResetEnv) const { const ModInstrument *pIns = instr <= GetNumInstruments() ? Instruments[instr] : nullptr; - const ModSample *pSmp = &Samples[instr]; + const ModSample *pSmp = &Samples[instr <= GetNumSamples() ? instr : 0]; const auto oldInsVol = chn.nInsVol; ModCommand::NOTE note = chn.nNewNote; @@ -2707,8 +2708,8 @@ if(m_playBehaviour[kMODSampleSwap]) { // ProTracker Compatibility: If a sample was stopped before, lone instrument numbers can retrigger it - // Test case: PTSwapEmpty.mod, PTInstrVolume.mod, SampleSwap.s3m - if(!chn.IsSamplePlaying() && (chn.pModSample == nullptr || !chn.pModSample->HasSampleData())) + // Test cases: PTSwapEmpty.mod, PTInstrVolume.mod, PTStoppedSwap.mod + if(!chn.IsSamplePlaying() && instr <= GetNumSamples() && Samples[instr].uFlags[CHN_LOOP]) keepInstr = true; } @@ -2951,7 +2952,8 @@ } NoteChange(chn, note, bPorta, !(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2)), false, nChn); - HandleDigiSamplePlayDirection(m_PlayState, nChn); + if(ModCommand::IsNote(note)) + HandleDigiSamplePlayDirection(m_PlayState, nChn); if ((bPorta) && (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2)) && (instr)) { chn.dwFlags.set(CHN_FASTVOLRAMP); @@ -3229,7 +3231,7 @@ { // FT2 compatibility: Portamento + Offset = Ignore offset // Test case: porta-offset.xm - if(bPorta && GetType() == MOD_TYPE_XM) + if(bPorta && (GetType() & (MOD_TYPE_XM | MOD_TYPE_DBM))) break; ProcessSampleOffset(chn, nChn, m_PlayState); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/soundlib/Sndfile.h new/libopenmpt-0.7.9+release.autotools/soundlib/Sndfile.h --- old/libopenmpt-0.7.8+release.autotools/soundlib/Sndfile.h 2024-01-10 21:33:43.000000000 +0100 +++ new/libopenmpt-0.7.9+release.autotools/soundlib/Sndfile.h 2024-06-22 20:45:37.000000000 +0200 @@ -1285,7 +1285,7 @@ // Resolve note/instrument combination to real sample index. Return value is guaranteed to be in [0, GetNumSamples()]. SAMPLEINDEX GetSampleIndex(ModCommand::NOTE note, uint32 instr) const noexcept; - uint32 MapMidiInstrument(uint8 program, uint16 bank, uint8 midiChannel, uint8 note, bool isXG, std::bitset<16> drumChns); + uint32 MapMidiInstrument(uint8 program, uint16 bank, uint8 midiChannel, uint8 note, bool isXG, std::bitset<32> drumChns); size_t ITInstrToMPT(FileReader &file, ModInstrument &ins, uint16 trkvers); std::pair<bool, bool> LoadMixPlugins(FileReader &file); #ifndef NO_PLUGINS diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/soundlib/modcommand.cpp new/libopenmpt-0.7.9+release.autotools/soundlib/modcommand.cpp --- old/libopenmpt-0.7.8+release.autotools/soundlib/modcommand.cpp 2024-06-01 15:58:00.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/soundlib/modcommand.cpp 2024-06-25 20:47:51.000000000 +0200 @@ -1348,6 +1348,41 @@ std::pair<EffectCommand, ModCommand::PARAM> ModCommand::FillInTwoCommands(EffectCommand effect1, uint8 param1, EffectCommand effect2, uint8 param2) { + if(effect1 == effect2) + { + // For non-sliding, absolute effects, it doesn't make sense to keep both commands + switch(effect1) + { + case CMD_ARPEGGIO: + case CMD_PANNING8: + case CMD_OFFSET: + case CMD_POSITIONJUMP: + case CMD_VOLUME: + case CMD_PATTERNBREAK: + case CMD_SPEED: + case CMD_TEMPO: + case CMD_CHANNELVOLUME: + case CMD_GLOBALVOLUME: + case CMD_KEYOFF: + case CMD_SETENVPOSITION: + case CMD_MIDI: + case CMD_SMOOTHMIDI: + case CMD_DELAYCUT: + case CMD_FINETUNE: + case CMD_FINETUNE_SMOOTH: + case CMD_DUMMY: + case CMD_REVERSEOFFSET: + case CMD_DBMECHO: + case CMD_OFFSETPERCENTAGE: + case CMD_DIGIREVERSESAMPLE: + case CMD_VOLUME8: + effect2 = CMD_NONE; + break; + default: + break; + } + } + for(uint8 n = 0; n < 4; n++) { if(auto volCmd = ModCommand::ConvertToVolCommand(effect1, param1, (n > 1)); effect1 == CMD_NONE || volCmd.first != VOLCMD_NONE) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/soundlib/plugins/PluginManager.cpp new/libopenmpt-0.7.9+release.autotools/soundlib/plugins/PluginManager.cpp --- old/libopenmpt-0.7.8+release.autotools/soundlib/plugins/PluginManager.cpp 2023-02-11 15:52:59.000000000 +0100 +++ new/libopenmpt-0.7.9+release.autotools/soundlib/plugins/PluginManager.cpp 2024-07-03 19:09:44.000000000 +0200 @@ -779,7 +779,11 @@ } #ifdef MPT_WITH_VST - if(pFound && mixPlugin.Info.dwPluginId1 == Vst::kEffectMagic) + // Note: we don't check if dwPluginId1 matches Vst::kEffectMagic here, even if it should. + // I have an old file I made with OpenMPT 1.17 where the primary plugin ID has an unexpected value. + // No idea how that could happen, apart from some plugin.cache corruption (back then, the IDs were not re-checked + // after instantiating a plugin and the cached plugin ID was blindly written to the module file) + if(pFound) { Vst::AEffect *pEffect = nullptr; HINSTANCE hLibrary = nullptr; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/src/mpt/base/detect_compiler.hpp new/libopenmpt-0.7.9+release.autotools/src/mpt/base/detect_compiler.hpp --- old/libopenmpt-0.7.8+release.autotools/src/mpt/base/detect_compiler.hpp 2024-05-22 11:10:28.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/src/mpt/base/detect_compiler.hpp 2024-07-19 12:42:56.000000000 +0200 @@ -204,4 +204,30 @@ +// detect compiler setting quirks + +#if MPT_COMPILER_GCC +#if (MPT_GCC_AT_LEAST(14, 0, 0) && MPT_GCC_BEFORE(14, 2, 0)) || (MPT_GCC_AT_LEAST(13, 0, 0) && MPT_GCC_BEFORE(13, 4, 0)) || (MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(12, 5, 0)) || MPT_GCC_BEFORE(12, 0, 0) +// GCC 14 causes severe miscompilation of inline functions on MinGW. +// See <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115049>. +// Current investigation suggests a general problem with -fipa-ra on non-ELF +// platforms. +// As far as we understand the issue, it could possibly also manifest with +// other inter-procedure-optimizations and with older GCC versions. +// Fixed in GCC 15 +// (<https://gcc.gnu.org/git/?p=gcc.git;h=5080840d8fbf25a321dd27543a1462d393d338bc>), +// GCC 14.2 +// (<https://gcc.gnu.org/git/?p=gcc.git;h=747c4b58573ea00419f64293a61537eb69f43307>). +// GCC 13.4 +// (<https://gcc.gnu.org/git/?p=gcc.git;h=953bf37690d22de956d75c6aef7a9690ad55b9a7>). +// and GCC 12.5 +// (<https://gcc.gnu.org/git/?p=gcc.git;h=2c5f48a43f26223cb8603b826d7c0d52cdbcfb46>). +#if !defined(__ELF__) +#define MPT_COMPILER_SETTING_QUIRK_GCC_BROKEN_IPA +#endif +#endif +#endif + + + #endif // MPT_BASE_DETECT_COMPILER_HPP diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/src/mpt/base/detect_quirks.hpp new/libopenmpt-0.7.9+release.autotools/src/mpt/base/detect_quirks.hpp --- old/libopenmpt-0.7.8+release.autotools/src/mpt/base/detect_quirks.hpp 2024-05-12 13:07:25.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/src/mpt/base/detect_quirks.hpp 2024-07-14 18:10:07.000000000 +0200 @@ -19,16 +19,6 @@ -#if MPT_GCC_AT_LEAST(14, 0, 0) && MPT_GCC_BEFORE(15, 0, 0) -// GCC 14 causes severe miscompilation of inline functions. -// See <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115049>. -#if defined(__OPTIMIZE__) -#define MPT_COMPILER_QUIRK_GCC_NO_O2 -#endif -#endif - - - #if MPT_COMPILER_MSVC #if !defined(_MSVC_TRADITIONAL) #define MPT_COMPILER_QUIRK_MSVC_OLD_PREPROCESSOR diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/src/mpt/check/compiler.hpp new/libopenmpt-0.7.9+release.autotools/src/mpt/check/compiler.hpp --- old/libopenmpt-0.7.8+release.autotools/src/mpt/check/compiler.hpp 2024-05-12 13:07:25.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/src/mpt/check/compiler.hpp 2024-07-14 15:00:00.000000000 +0200 @@ -7,13 +7,6 @@ #include "mpt/base/detect_quirks.hpp" #include "mpt/base/compiletime_warning.hpp" -#ifndef MPT_CHECK_CXX_IGNORE_WARNING_O2 -#if defined(MPT_COMPILER_QUIRK_GCC_NO_O2) -// See <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115049>. -MPT_WARNING("GCC 14 is known to cause severe miscompilation of inline functions. OpenMPT has forced optimization settings down to -O1. This comes at a roughly 15% performance cost. It is strongly recommended to stay with GCC 13 for the time being. You will need to edit the source to opt-out of this safety guard.") -#endif -#endif - #ifndef MPT_CHECK_CXX_IGNORE_PREPROCESSOR #if defined(MPT_COMPILER_QUIRK_MSVC_OLD_PREPROCESSOR) MPT_WARNING("C++ preprocessor is not standard conformings.") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/src/mpt/string_transcode/transcode.hpp new/libopenmpt-0.7.9+release.autotools/src/mpt/string_transcode/transcode.hpp --- old/libopenmpt-0.7.8+release.autotools/src/mpt/string_transcode/transcode.hpp 2023-04-11 11:17:44.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/src/mpt/string_transcode/transcode.hpp 2024-06-25 16:04:01.000000000 +0200 @@ -678,6 +678,7 @@ out.push_back(replacement); ucs4 = 0; charsleft = 0; + continue; } if (ucs4 <= 0xffff) { out.push_back(static_cast<mpt::widechar>(ucs4)); @@ -817,7 +818,7 @@ char32_t ucs4 = static_cast<char32_t>(static_cast<uint32>(in[i])); if (ucs4 > 0x1fffff) { out.push_back(static_cast<typename Tdststring::value_type>(static_cast<uint16>(replacement))); - ucs4 = 0; + continue; } if (ucs4 <= 0xffff) { out.push_back(static_cast<typename Tdststring::value_type>(static_cast<uint16>(ucs4))); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libopenmpt-0.7.8+release.autotools/src/openmpt/all/BuildSettings.hpp new/libopenmpt-0.7.9+release.autotools/src/openmpt/all/BuildSettings.hpp --- old/libopenmpt-0.7.8+release.autotools/src/openmpt/all/BuildSettings.hpp 2021-05-24 11:10:03.000000000 +0200 +++ new/libopenmpt-0.7.9+release.autotools/src/openmpt/all/BuildSettings.hpp 2024-07-14 18:10:07.000000000 +0200 @@ -6,6 +6,12 @@ +#if defined(MODPLUG_TRACKER) || defined(LIBOPENMPT_BUILD) +#include "BuildSettingsCompiler.h" +#endif + + + #include "mpt/base/detect_compiler.hpp" #include "mpt/base/detect_os.hpp" #include "mpt/base/detect_quirks.hpp"