Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package libopenmpt for openSUSE:Factory 
checked in at 2021-12-06 23:59:02
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libopenmpt (Old)
 and      /work/SRC/openSUSE:Factory/.libopenmpt.new.31177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libopenmpt"

Mon Dec  6 23:59:02 2021 rev:32 rq:935240 version:0.5.13

Changes:
--------
--- /work/SRC/openSUSE:Factory/libopenmpt/libopenmpt.changes    2021-10-29 
22:34:27.391687181 +0200
+++ /work/SRC/openSUSE:Factory/.libopenmpt.new.31177/libopenmpt.changes 
2021-12-06 23:59:03.464633251 +0100
@@ -1,0 +2,16 @@
+Wed Dec  1 10:26:39 UTC 2021 - Danilo Spinella <[email protected]>
+
+- Update to 0.5.13:
+  * [Bug] Fixed various undefined behaviour found with ubsan.
+  * IMF: Change envelope interpretation to be more like in XM instead of
+    IT and tighten header validation.
+  * MED: Some samples had a ping-pong loop when there should be no loop at all.
+  * MT2: Ignore incorrect drums chunk size in early MT2 files (fixes e.g.
+    ???A little Rock??? by Csumi).
+  * MT2: Work around initial master volume of 0 used in some files that apply
+    a fade-in a the song start using track automation that would stay silent
+    forever otherwise (track automation is currently not supported).
+  * OKT: Apply portamento on every tick.
+  * mpg123: Update to v1.29.2 (2021-10-23).
+
+-------------------------------------------------------------------

Old:
----
  libopenmpt-0.5.12+release.autotools.tar.gz

New:
----
  libopenmpt-0.5.13+release.autotools.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ libopenmpt.spec ++++++
--- /var/tmp/diff_new_pack.ZIUHER/_old  2021-12-06 23:59:04.216630592 +0100
+++ /var/tmp/diff_new_pack.ZIUHER/_new  2021-12-06 23:59:04.220630578 +0100
@@ -21,7 +21,7 @@
 %define libopenmpt_modplug_version 0.8.9.0
 
 Name:           libopenmpt
-Version:        0.5.12
+Version:        0.5.13
 Release:        0
 Summary:        C++ and C library to decode tracker music files
 License:        BSD-3-Clause

++++++ libopenmpt-0.5.12+release.autotools.tar.gz -> 
libopenmpt-0.5.13+release.autotools.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libopenmpt-0.5.12+release.autotools/common/versionNumber.h 
new/libopenmpt-0.5.13+release.autotools/common/versionNumber.h
--- old/libopenmpt-0.5.12+release.autotools/common/versionNumber.h      
2021-10-03 17:44:24.000000000 +0200
+++ new/libopenmpt-0.5.13+release.autotools/common/versionNumber.h      
2021-11-14 17:44:35.000000000 +0100
@@ -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      29
-#define VER_MINOR      13
+#define VER_MINOR      14
 #define VER_MINORMINOR 00
 
 OPENMPT_NAMESPACE_END
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libopenmpt-0.5.12+release.autotools/configure 
new/libopenmpt-0.5.13+release.autotools/configure
--- old/libopenmpt-0.5.12+release.autotools/configure   2021-10-04 
15:51:33.000000000 +0200
+++ new/libopenmpt-0.5.13+release.autotools/configure   2021-11-14 
18:11:21.000000000 +0100
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for libopenmpt 0.5.12+release.autotools.
+# Generated by GNU Autoconf 2.69 for libopenmpt 0.5.13+release.autotools.
 #
 # Report bugs to <https://bugs.openmpt.org/>.
 #
@@ -590,8 +590,8 @@
 # Identity of this package.
 PACKAGE_NAME='libopenmpt'
 PACKAGE_TARNAME='libopenmpt'
-PACKAGE_VERSION='0.5.12+release.autotools'
-PACKAGE_STRING='libopenmpt 0.5.12+release.autotools'
+PACKAGE_VERSION='0.5.13+release.autotools'
+PACKAGE_STRING='libopenmpt 0.5.13+release.autotools'
 PACKAGE_BUGREPORT='https://bugs.openmpt.org/'
 PACKAGE_URL='https://lib.openmpt.org/'
 
@@ -1472,7 +1472,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures libopenmpt 0.5.12+release.autotools to adapt to many 
kinds of systems.
+\`configure' configures libopenmpt 0.5.13+release.autotools to adapt to many 
kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1543,7 +1543,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of libopenmpt 
0.5.12+release.autotools:";;
+     short | recursive ) echo "Configuration of libopenmpt 
0.5.13+release.autotools:";;
    esac
   cat <<\_ACEOF
 
@@ -1729,7 +1729,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-libopenmpt configure 0.5.12+release.autotools
+libopenmpt configure 0.5.13+release.autotools
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2219,7 +2219,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by libopenmpt $as_me 0.5.12+release.autotools, which was
+It was created by libopenmpt $as_me 0.5.13+release.autotools, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -3090,7 +3090,7 @@
 
 # Define the identity of the package.
  PACKAGE='libopenmpt'
- VERSION='0.5.12+release.autotools'
+ VERSION='0.5.13+release.autotools'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -17251,13 +17251,13 @@
 
 
 
-$as_echo "#define MPT_SVNURL 
\"https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.12\""; >>confdefs.h
+$as_echo "#define MPT_SVNURL 
\"https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.13\""; >>confdefs.h
 
 
-$as_echo "#define MPT_SVNVERSION \"15759\"" >>confdefs.h
+$as_echo "#define MPT_SVNVERSION \"15956\"" >>confdefs.h
 
 
-$as_echo "#define MPT_SVNDATE \"2021-10-04T13:48:02.912129Z\"" >>confdefs.h
+$as_echo "#define MPT_SVNDATE \"2021-11-14T17:01:47.266406Z\"" >>confdefs.h
 
 
 $as_echo "#define MPT_PACKAGE true" >>confdefs.h
@@ -22524,7 +22524,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by libopenmpt $as_me 0.5.12+release.autotools, which was
+This file was extended by libopenmpt $as_me 0.5.13+release.autotools, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -22591,7 +22591,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; 
s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-libopenmpt config.status 0.5.12+release.autotools
+libopenmpt config.status 0.5.13+release.autotools
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libopenmpt-0.5.12+release.autotools/configure.ac 
new/libopenmpt-0.5.13+release.autotools/configure.ac
--- old/libopenmpt-0.5.12+release.autotools/configure.ac        2021-10-04 
15:51:11.000000000 +0200
+++ new/libopenmpt-0.5.13+release.autotools/configure.ac        2021-11-14 
18:11:12.000000000 +0100
@@ -1,4 +1,4 @@
-AC_INIT([libopenmpt], [0.5.12+release.autotools], [https://bugs.openmpt.org/], 
[libopenmpt], [https://lib.openmpt.org/])
+AC_INIT([libopenmpt], [0.5.13+release.autotools], [https://bugs.openmpt.org/], 
[libopenmpt], [https://lib.openmpt.org/])
 AC_PREREQ([2.68])
 
 AC_CONFIG_MACRO_DIR([m4])
@@ -27,9 +27,9 @@
 AC_SUBST([LIBOPENMPT_LTVER_REVISION])
 AC_SUBST([LIBOPENMPT_LTVER_AGE])
 
-AC_DEFINE([MPT_SVNURL], 
["https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.12";], [svn 
version])
-AC_DEFINE([MPT_SVNVERSION], ["15759"], [svn version])
-AC_DEFINE([MPT_SVNDATE], ["2021-10-04T13:48:02.912129Z"], [svn date])
+AC_DEFINE([MPT_SVNURL], 
["https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.13";], [svn 
version])
+AC_DEFINE([MPT_SVNVERSION], ["15956"], [svn version])
+AC_DEFINE([MPT_SVNDATE], ["2021-11-14T17:01:47.266406Z"], [svn date])
 AC_DEFINE([MPT_PACKAGE], [true], [is package])
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libopenmpt-0.5.12+release.autotools/libopenmpt/dox/changelog.md 
new/libopenmpt-0.5.13+release.autotools/libopenmpt/dox/changelog.md
--- old/libopenmpt-0.5.12+release.autotools/libopenmpt/dox/changelog.md 
2021-10-04 15:48:00.000000000 +0200
+++ new/libopenmpt-0.5.13+release.autotools/libopenmpt/dox/changelog.md 
2021-11-14 18:01:45.000000000 +0100
@@ -5,6 +5,22 @@
 For fully detailed change log, please see the source repository directly. This
 is just a high-level summary.
 
+### libopenmpt 0.5.13 (2021-11-14)
+
+ *  [**Bug**] Fixed various undefined behaviour found with ubsan.
+
+ *  IMF: Change envelope interpretation to be more like in XM instead of IT and
+    tighten header validation.
+ *  MED: Some samples had a ping-pong loop when there should be no loop at all.
+ *  MT2: Ignore incorrect drums chunk size in early MT2 files
+    (fixes e.g. "A little Rock" by Csumi).
+ *  MT2: Work around initial master volume of 0 used in some files that apply a
+    fade-in a the song start using track automation that would stay silent
+    forever otherwise (track automation is currently not supported).
+ *  OKT: Apply portamento on every tick.
+
+ *  mpg123: Update to v1.29.2 (2021-10-23).
+
 ### libopenmpt 0.5.12 (2021-10-04)
 
  *  [**Sec**] Possible crash when loading malformed MDL files. (r15603)
@@ -24,6 +40,8 @@
 
  *  in_openmpt: Song metadata is no longer reverted when viewing file info.
 
+ *  mpg123: Update to v1.29.0 (2021-09-06).
+
 ### libopenmpt 0.5.11 (2021-08-22)
 
  *  [**Sec**] Possible crash with malformed modules when trying to access
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libopenmpt-0.5.12+release.autotools/libopenmpt/libopenmpt_c.cpp 
new/libopenmpt-0.5.13+release.autotools/libopenmpt/libopenmpt_c.cpp
--- old/libopenmpt-0.5.12+release.autotools/libopenmpt/libopenmpt_c.cpp 
2021-01-10 16:47:53.000000000 +0100
+++ new/libopenmpt-0.5.13+release.autotools/libopenmpt/libopenmpt_c.cpp 
2021-10-05 13:35:16.000000000 +0200
@@ -88,6 +88,8 @@
 static std::string format_exception( const char * const function ) {
        std::string err;
        try {
+               // cppcheck false-positive
+               // cppcheck-suppress rethrowNoCurrentException
                throw;
        } catch ( const openmpt::exception & e ) {
                err += function;
@@ -131,6 +133,8 @@
                }
        }
        try {
+               // cppcheck false-positive
+               // cppcheck-suppress rethrowNoCurrentException
                throw;
 
        } catch ( const std::bad_alloc & e ) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libopenmpt-0.5.12+release.autotools/libopenmpt/libopenmpt_impl.cpp 
new/libopenmpt-0.5.13+release.autotools/libopenmpt/libopenmpt_impl.cpp
--- old/libopenmpt-0.5.12+release.autotools/libopenmpt/libopenmpt_impl.cpp      
2021-03-30 19:56:20.000000000 +0200
+++ new/libopenmpt-0.5.13+release.autotools/libopenmpt/libopenmpt_impl.cpp      
2021-11-13 13:08:25.000000000 +0100
@@ -1806,7 +1806,7 @@
                }
                return m_sndFile->m_nFreqFactor / 65536.0;
        } else if ( ctl == "render.opl.volume_factor" ) {
-               return static_cast<double>( m_sndFile->m_OPLVolumeFactor ) / 
static_cast<double>( m_sndFile->m_OPLVolumeFactorScale );
+               return static_cast<double>( m_sndFile->m_OPLVolumeFactor ) / 
static_cast<double>( CSoundFile::m_OPLVolumeFactorScale );
        } else {
                MPT_ASSERT_NOTREACHED();
                return 0.0;
@@ -2045,7 +2045,7 @@
                m_sndFile->m_nFreqFactor = mpt::saturate_round<uint32_t>( 
65536.0 * factor );
                m_sndFile->RecalculateSamplesPerTick();
        } else if ( ctl == "render.opl.volume_factor" ) {
-               m_sndFile->m_OPLVolumeFactor = mpt::saturate_round<int32>( 
value * static_cast<double>( m_sndFile->m_OPLVolumeFactorScale ) );
+               m_sndFile->m_OPLVolumeFactor = mpt::saturate_round<int32>( 
value * static_cast<double>( CSoundFile::m_OPLVolumeFactorScale ) );
        } else {
                MPT_ASSERT_NOTREACHED();
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libopenmpt-0.5.12+release.autotools/libopenmpt/libopenmpt_version.h 
new/libopenmpt-0.5.13+release.autotools/libopenmpt/libopenmpt_version.h
--- old/libopenmpt-0.5.12+release.autotools/libopenmpt/libopenmpt_version.h     
2021-10-04 15:48:00.000000000 +0200
+++ new/libopenmpt-0.5.13+release.autotools/libopenmpt/libopenmpt_version.h     
2021-11-14 18:01:45.000000000 +0100
@@ -19,7 +19,7 @@
 /*! \brief libopenmpt minor version number */
 #define OPENMPT_API_VERSION_MINOR 5
 /*! \brief libopenmpt patch version number */
-#define OPENMPT_API_VERSION_PATCH 12
+#define OPENMPT_API_VERSION_PATCH 13
 /*! \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' 
old/libopenmpt-0.5.12+release.autotools/libopenmpt/libopenmpt_version.mk 
new/libopenmpt-0.5.13+release.autotools/libopenmpt/libopenmpt_version.mk
--- old/libopenmpt-0.5.12+release.autotools/libopenmpt/libopenmpt_version.mk    
2021-10-04 15:48:00.000000000 +0200
+++ new/libopenmpt-0.5.13+release.autotools/libopenmpt/libopenmpt_version.mk    
2021-11-14 18:01:45.000000000 +0100
@@ -1,8 +1,8 @@
 LIBOPENMPT_VERSION_MAJOR=0
 LIBOPENMPT_VERSION_MINOR=5
-LIBOPENMPT_VERSION_PATCH=12
+LIBOPENMPT_VERSION_PATCH=13
 LIBOPENMPT_VERSION_PREREL=
 
 LIBOPENMPT_LTVER_CURRENT=2
-LIBOPENMPT_LTVER_REVISION=12
+LIBOPENMPT_LTVER_REVISION=13
 LIBOPENMPT_LTVER_AGE=2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libopenmpt-0.5.12+release.autotools/man/openmpt123.1 
new/libopenmpt-0.5.13+release.autotools/man/openmpt123.1
--- old/libopenmpt-0.5.12+release.autotools/man/openmpt123.1    2021-10-04 
15:51:11.000000000 +0200
+++ new/libopenmpt-0.5.13+release.autotools/man/openmpt123.1    2021-11-14 
18:11:12.000000000 +0100
@@ -1,5 +1,5 @@
 .\" DO NOT MODIFY THIS FILE!  It was generated by help2man 1.47.8.
-.TH OPENMPT123 "1" "October 2021" "openmpt123 v0.5.12" "User Commands"
+.TH OPENMPT123 "1" "November 2021" "openmpt123 v0.5.13" "User Commands"
 .SH NAME
 openmpt123 - command line module music player based on libopenmpt
 .SH SYNOPSIS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libopenmpt-0.5.12+release.autotools/openmpt123/openmpt123.cpp 
new/libopenmpt-0.5.13+release.autotools/openmpt123/openmpt123.cpp
--- old/libopenmpt-0.5.12+release.autotools/openmpt123/openmpt123.cpp   
2021-09-15 17:09:22.000000000 +0200
+++ new/libopenmpt-0.5.13+release.autotools/openmpt123/openmpt123.cpp   
2021-11-13 10:43:33.000000000 +0100
@@ -46,6 +46,7 @@
 #include <limits>
 #include <locale>
 #include <map>
+#include <memory>
 #include <random>
 #include <set>
 #include <sstream>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libopenmpt-0.5.12+release.autotools/soundlib/Dlsbank.cpp 
new/libopenmpt-0.5.13+release.autotools/soundlib/Dlsbank.cpp
--- old/libopenmpt-0.5.12+release.autotools/soundlib/Dlsbank.cpp        
2021-09-13 00:47:14.000000000 +0200
+++ new/libopenmpt-0.5.13+release.autotools/soundlib/Dlsbank.cpp        
2021-11-13 15:03:12.000000000 +0100
@@ -42,7 +42,6 @@
        DLSREGION_SAMPLELOOP       = 0x40,
        DLSREGION_SELFNONEXCLUSIVE = 0x80,
        DLSREGION_SUSTAINLOOP      = 0x100,
-       DLSREGION_ISGLOBAL         = 0x200,
 };
 
 ///////////////////////////////////////////////////////////////////////////
@@ -376,7 +375,7 @@
 /////////////////////////////////////////////////////////////////////
 // SF2 Structures Definitions
 
-struct SFPRESETHEADER
+struct SFPresetHeader
 {
        char     achPresetName[20];
        uint16le wPreset;
@@ -387,49 +386,49 @@
        uint32le dwMorphology;
 };
 
-MPT_BINARY_STRUCT(SFPRESETHEADER, 38)
+MPT_BINARY_STRUCT(SFPresetHeader, 38)
 
-struct SFPRESETBAG
+struct SFPresetBag
 {
        uint16le wGenNdx;
        uint16le wModNdx;
 };
 
-MPT_BINARY_STRUCT(SFPRESETBAG, 4)
+MPT_BINARY_STRUCT(SFPresetBag, 4)
 
-struct SFGENLIST
+struct SFGenList
 {
        uint16le sfGenOper;
        uint16le genAmount;
 };
 
-MPT_BINARY_STRUCT(SFGENLIST, 4)
+MPT_BINARY_STRUCT(SFGenList, 4)
 
-struct SFINST
+struct SFInst
 {
        char     achInstName[20];
        uint16le wInstBagNdx;
 };
 
-MPT_BINARY_STRUCT(SFINST, 22)
+MPT_BINARY_STRUCT(SFInst, 22)
 
-struct SFINSTBAG
+struct SFInstBag
 {
        uint16le wGenNdx;
        uint16le wModNdx;
 };
 
-MPT_BINARY_STRUCT(SFINSTBAG, 4)
+MPT_BINARY_STRUCT(SFInstBag, 4)
 
-struct SFINSTGENLIST
+struct SFInstGenList
 {
        uint16le sfGenOper;
        uint16le genAmount;
 };
 
-MPT_BINARY_STRUCT(SFINSTGENLIST, 4)
+MPT_BINARY_STRUCT(SFInstGenList, 4)
 
-struct SFSAMPLE
+struct SFSample
 {
        char     achSampleName[20];
        uint32le dwStart;
@@ -443,7 +442,7 @@
        uint16le sfSampleType;
 };
 
-MPT_BINARY_STRUCT(SFSAMPLE, 46)
+MPT_BINARY_STRUCT(SFSample, 46)
 
 // End of structures definitions
 /////////////////////////////////////////////////////////////////////
@@ -581,11 +580,17 @@
 
 const DLSINSTRUMENT *CDLSBank::FindInstrument(bool isDrum, uint32 bank, uint32 
program, uint32 key, uint32 *pInsNo) const
 {
-       if(m_Instruments.empty())
-               return nullptr;
-       for (uint32 iIns = 0; iIns < m_Instruments.size(); iIns++)
+       // This helps finding the "more correct" instrument if we search for an 
instrument in any bank, and the higher-bank instruments appear first in the file
+       // Fixes issues when loading GeneralUser GS into OpenMPT's MIDI library.
+       std::vector<std::reference_wrapper<const DLSINSTRUMENT>> 
sortedInstr{m_Instruments.begin(), m_Instruments.end()};
+       if(bank >= 0x4000 || program >= 0x80)
+       {
+               std::sort(sortedInstr.begin(), sortedInstr.end(), [](const 
DLSINSTRUMENT &l, const DLSINSTRUMENT &r)
+                               { return std::tie(l.ulBank, l.ulInstrument) < 
std::tie(r.ulBank, r.ulInstrument); });
+       }
+
+       for(const DLSINSTRUMENT &dlsIns : sortedInstr)
        {
-               const DLSINSTRUMENT &dlsIns = m_Instruments[iIns];
                uint32 insbank = ((dlsIns.ulBank & 0x7F00) >> 1) | 
(dlsIns.ulBank & 0x7F);
                if((bank >= 0x4000) || (insbank == bank))
                {
@@ -595,16 +600,16 @@
                                {
                                        for(const auto &region : dlsIns.Regions)
                                        {
-                                               if(region.nWaveLink == 
Util::MaxValueOfType(region.nWaveLink))
-                                                       continue;
-                                               if(region.fuOptions & 
DLSREGION_ISGLOBAL)
+                                               if(region.IsDummy())
                                                        continue;
 
                                                if((!key || key >= 0x80)
                                                   || (key >= region.uKeyMin && 
key <= region.uKeyMax))
                                                {
                                                        if(pInsNo)
-                                                               *pInsNo = iIns;
+                                                               *pInsNo = 
static_cast<uint32>(std::distance(m_Instruments.data(), &dlsIns));
+                                                       // cppcheck 
false-positive
+                                                       // cppcheck-suppress 
returnDanglingLifetime
                                                        return &dlsIns;
                                                }
                                        }
@@ -614,7 +619,9 @@
                                if((program >= 0x80) || (program == 
(dlsIns.ulInstrument & 0x7F)))
                                {
                                        if(pInsNo)
-                                               *pInsNo = iIns;
+                                               *pInsNo = 
static_cast<uint32>(std::distance(m_Instruments.data(), &dlsIns));
+                                       // cppcheck false-positive
+                                       // cppcheck-suppress 
returnDanglingLifetime
                                        return &dlsIns;
                                }
                        }
@@ -877,7 +884,7 @@
        case IFFID_phdr:
                if(m_Instruments.empty())
                {
-                       uint32 numIns = static_cast<uint32>(chunk.GetLength() / 
sizeof(SFPRESETHEADER));
+                       uint32 numIns = static_cast<uint32>(chunk.GetLength() / 
sizeof(SFPresetHeader));
                        if(numIns <= 1)
                                break;
                        // The terminal sfPresetHeader record should never be 
accessed, and exists only to provide a terminal wPresetBagNdx with which to 
determine the number of zones in the last preset.
@@ -887,9 +894,9 @@
                #ifdef DLSBANK_LOG
                        MPT_LOG(LogDebug, "DLSBank", mpt::format(U_("phdr: %1 
instruments"))(m_Instruments.size()));
                #endif
-                       SFPRESETHEADER psfh;
+                       SFPresetHeader psfh;
                        chunk.ReadStruct(psfh);
-                       for (auto &dlsIns : m_Instruments)
+                       for(auto &dlsIns : m_Instruments)
                        {
                                mpt::String::WriteAutoBuf(dlsIns.szName) = 
mpt::String::ReadAutoBuf(psfh.achPresetName);
                                dlsIns.ulInstrument = psfh.wPreset & 0x7F;
@@ -903,7 +910,7 @@
                break;
 
        case IFFID_pbag:
-               if(!m_Instruments.empty() && chunk.CanRead(sizeof(SFPRESETBAG)))
+               if(!m_Instruments.empty() && chunk.CanRead(sizeof(SFPresetBag)))
                {
                        sf2info.presetBags = chunk.GetChunk(chunk.BytesLeft());
                }
@@ -913,7 +920,7 @@
                break;
 
        case IFFID_pgen:
-               if(!m_Instruments.empty() && chunk.CanRead(sizeof(SFGENLIST)))
+               if(!m_Instruments.empty() && chunk.CanRead(sizeof(SFGenList)))
                {
                        sf2info.presetGens = chunk.GetChunk(chunk.BytesLeft());
                }
@@ -923,21 +930,21 @@
                break;
 
        case IFFID_inst:
-               if(!m_Instruments.empty() && chunk.CanRead(sizeof(SFINST)))
+               if(!m_Instruments.empty() && chunk.CanRead(sizeof(SFInst)))
                {
                        sf2info.insts = chunk.GetChunk(chunk.BytesLeft());
                }
                break;
 
        case IFFID_ibag:
-               if(!m_Instruments.empty() && chunk.CanRead(sizeof(SFINSTBAG)))
+               if(!m_Instruments.empty() && chunk.CanRead(sizeof(SFInstBag)))
                {
                        sf2info.instBags = chunk.GetChunk(chunk.BytesLeft());
                }
                break;
 
        case IFFID_igen:
-               if(!m_Instruments.empty() && 
chunk.CanRead(sizeof(SFINSTGENLIST)))
+               if(!m_Instruments.empty() && 
chunk.CanRead(sizeof(SFInstGenList)))
                {
                        sf2info.instGens = chunk.GetChunk(chunk.BytesLeft());
                }
@@ -946,7 +953,7 @@
        case IFFID_shdr:
                if (m_SamplesEx.empty())
                {
-                       uint32 numSmp = static_cast<uint32>(chunk.GetLength() / 
sizeof(SFSAMPLE));
+                       uint32 numSmp = static_cast<uint32>(chunk.GetLength() / 
sizeof(SFSample));
                        if (numSmp < 1) break;
                        m_SamplesEx.resize(numSmp);
                        m_WaveForms.resize(numSmp);
@@ -956,7 +963,7 @@
 
                        for (uint32 i = 0; i < numSmp; i++)
                        {
-                               SFSAMPLE p;
+                               SFSample p;
                                chunk.ReadStruct(p);
                                DLSSAMPLEEX &dlsSmp = m_SamplesEx[i];
                                mpt::String::WriteAutoBuf(dlsSmp.szName) = 
mpt::String::ReadAutoBuf(p.achSampleName);
@@ -1006,16 +1013,16 @@
        if (m_Instruments.empty() || m_SamplesEx.empty())
                return false;
 
-       const uint32 numPresetBags = 
static_cast<uint32>(sf2info.presetBags.GetLength() / sizeof(SFPRESETBAG));
-       const uint32 numPresetGens = 
static_cast<uint32>(sf2info.presetGens.GetLength() / sizeof(SFGENLIST));
-       const uint32 numInsts = static_cast<uint32>(sf2info.insts.GetLength() / 
sizeof(SFINST));
-       const uint32 numInstBags = 
static_cast<uint32>(sf2info.instBags.GetLength() / sizeof(SFINSTBAG));
-       const uint32 numInstGens = 
static_cast<uint32>(sf2info.instGens.GetLength() / sizeof(SFINSTGENLIST));
+       const uint32 numInsts = static_cast<uint32>(sf2info.insts.GetLength() / 
sizeof(SFInst));
+       const uint32 numInstBags = 
static_cast<uint32>(sf2info.instBags.GetLength() / sizeof(SFInstBag));
 
-       for (auto &dlsIns : m_Instruments)
+       std::vector<std::pair<uint16, uint16>> instruments;  // instrument, key 
range
+       std::vector<SFGenList> generators;
+       std::vector<SFInstGenList> instrGenerators;
+       for(auto &dlsIns : m_Instruments)
        {
+               instruments.clear();
                DLSENVELOPE dlsEnv;
-               std::vector<uint32> instruments;
                int32 instrAttenuation = 0;
                // Default Envelope Values
                dlsEnv.wVolAttack = 0;
@@ -1024,21 +1031,21 @@
                dlsEnv.nVolSustainLevel = 128;
                dlsEnv.nDefPan = 128;
                // Load Preset Bags
-               sf2info.presetBags.Seek(dlsIns.wPresetBagNdx * 
sizeof(SFPRESETBAG));
-               for (uint32 ipbagcnt=0; ipbagcnt<(uint32)dlsIns.wPresetBagNum; 
ipbagcnt++)
+               sf2info.presetBags.Seek(dlsIns.wPresetBagNdx * 
sizeof(SFPresetBag));
+               for(uint32 ipbagcnt = 0; ipbagcnt < dlsIns.wPresetBagNum; 
ipbagcnt++)
                {
                        // Load generators for each preset bag
-                       SFPRESETBAG bag[2];
+                       SFPresetBag bag[2];
                        if(!sf2info.presetBags.ReadArray(bag))
                                break;
-                       sf2info.presetBags.SkipBack(sizeof(SFPRESETBAG));
+                       sf2info.presetBags.SkipBack(sizeof(SFPresetBag));
 
-                       sf2info.presetGens.Seek(bag[0].wGenNdx * 
sizeof(SFGENLIST));
-                       for (uint32 ipgenndx = bag[0].wGenNdx; ipgenndx < 
bag[1].wGenNdx; ipgenndx++)
+                       sf2info.presetGens.Seek(bag[0].wGenNdx * 
sizeof(SFGenList));
+                       uint16 keyRange = 0xFFFF;
+                       if(!sf2info.presetGens.ReadVector(generators, 
bag[1].wGenNdx - bag[0].wGenNdx))
+                               continue;
+                       for(const auto &gen : generators)
                        {
-                               SFGENLIST gen;
-                               if(!sf2info.presetGens.ReadStruct(gen))
-                                       break;
                                switch(gen.sfGenOper)
                                {
                                case SF2_GEN_ATTACKVOLENV:
@@ -1058,8 +1065,12 @@
                                        dlsEnv.wVolRelease = 
SF2TimeToDLS(gen.genAmount);
                                        break;
                                case SF2_GEN_INSTRUMENT:
-                                       if(std::find(instruments.begin(), 
instruments.end(), gen.genAmount) == instruments.end())
-                                               
instruments.push_back(gen.genAmount);
+                                       if(const auto instr = 
std::make_pair(gen.genAmount.get(), keyRange); std::find(instruments.begin(), 
instruments.end(), instr) == instruments.end())
+                                               instruments.push_back(instr);
+                                       keyRange = 0xFFFF;
+                                       break;
+                               case SF2_GEN_KEYRANGE:
+                                       keyRange = gen.genAmount;
                                        break;
                                case SF2_GEN_ATTENUATION:
                                        instrAttenuation = 
-static_cast<int16>(gen.genAmount);
@@ -1081,22 +1092,35 @@
                }
                // Load Instrument Bags
                dlsIns.Regions.clear();
-               for(const auto nInstrNdx : instruments)
+               for(const auto [nInstrNdx, keyRange] : instruments)
                {
                        if(nInstrNdx >= numInsts)
                                continue;
-                       sf2info.insts.Seek(nInstrNdx * sizeof(SFINST));
-                       SFINST insts[2];
+                       sf2info.insts.Seek(nInstrNdx * sizeof(SFInst));
+                       SFInst insts[2];
                        sf2info.insts.ReadArray(insts);
-                       const auto startRegion = 
static_cast<uint32>(dlsIns.Regions.size());
-                       const auto endRegion = startRegion + 
insts[1].wInstBagNdx - insts[0].wInstBagNdx;
-                       dlsIns.Regions.resize(endRegion);
+                       const uint32 numRegions = insts[1].wInstBagNdx - 
insts[0].wInstBagNdx;
+                       dlsIns.Regions.reserve(dlsIns.Regions.size() + 
numRegions);
                        //Log("\nIns %3d, %2d regions:\n", nIns, 
pSmp->nRegions);
-                       DLSREGION *pRgn = &dlsIns.Regions[startRegion];
-                       bool hasGlobalZone = false;
-                       for(uint32 nRgn = startRegion; nRgn < endRegion; 
nRgn++, pRgn++)
+                       DLSREGION globalZone{};
+                       globalZone.uUnityNote = 0xFF;  // 0xFF means undefined 
-> use sample root note
+                       globalZone.tuning = 100;
+                       globalZone.sFineTune = 0;
+                       globalZone.nWaveLink = 
Util::MaxValueOfType(globalZone.nWaveLink);
+                       if(keyRange != 0xFFFF)
+                       {
+                               globalZone.uKeyMin = 
static_cast<uint8>(keyRange & 0xFF);
+                               globalZone.uKeyMax = 
static_cast<uint8>(keyRange >> 8);
+                               if(globalZone.uKeyMin > globalZone.uKeyMax)
+                                       std::swap(globalZone.uKeyMin, 
globalZone.uKeyMax);
+                       } else
                        {
-                               uint32 ibagcnt = insts[0].wInstBagNdx + nRgn - 
startRegion;
+                               globalZone.uKeyMin = 0;
+                               globalZone.uKeyMax = 127;
+                       }
+                       for(uint32 nRgn = 0; nRgn < numRegions; nRgn++)
+                       {
+                               uint32 ibagcnt = insts[0].wInstBagNdx + nRgn;
                                if(ibagcnt >= numInstBags)
                                        break;
                                // Create a new envelope for drums
@@ -1105,42 +1129,42 @@
                                {
                                        pDlsEnv = 
&m_Envelopes[dlsIns.nMelodicEnv - 1];
                                }
+
+                               DLSREGION rgn = globalZone;
+
                                // Region Default Values
                                int32 regionAttn = 0;
-                               pRgn->uKeyMin = 0;
-                               pRgn->uKeyMax = 127;
-                               pRgn->uUnityNote = 0xFF;  // 0xFF means 
undefined -> use sample root note
-                               pRgn->tuning = 100;
-                               pRgn->sFineTune = 0;
-                               pRgn->nWaveLink = 
Util::MaxValueOfType(pRgn->nWaveLink);
-                               if(hasGlobalZone)
-                                       *pRgn = dlsIns.Regions[startRegion];
                                // Load Generators
-                               sf2info.instBags.Seek(ibagcnt * 
sizeof(SFINSTBAG));
-                               SFINSTBAG bags[2];
+                               sf2info.instBags.Seek(ibagcnt * 
sizeof(SFInstBag));
+                               SFInstBag bags[2];
                                sf2info.instBags.ReadArray(bags);
-                               sf2info.instGens.Seek(bags[0].wGenNdx * 
sizeof(SFINSTGENLIST));
+                               sf2info.instGens.Seek(bags[0].wGenNdx * 
sizeof(SFInstGenList));
                                uint16 lastOp = SF2_GEN_SAMPLEID;
                                int32 loopStart = 0, loopEnd = 0;
-                               for(uint32 igenndx = bags[0].wGenNdx; igenndx < 
bags[1].wGenNdx; igenndx++)
+                               
if(!sf2info.instGens.ReadVector(instrGenerators, bags[1].wGenNdx - 
bags[0].wGenNdx))
+                                       break;
+                               for(const auto &gen : instrGenerators)
                                {
-                                       if(igenndx >= numInstGens)
-                                               break;
-                                       SFINSTGENLIST gen;
-                                       sf2info.instGens.ReadStruct(gen);
                                        uint16 value = gen.genAmount;
                                        lastOp = gen.sfGenOper;
 
                                        switch(gen.sfGenOper)
                                        {
                                        case SF2_GEN_KEYRANGE:
-                                               pRgn->uKeyMin = (uint8)(value & 
0xFF);
-                                               pRgn->uKeyMax = (uint8)(value 
>> 8);
-                                               if(pRgn->uKeyMin > 
pRgn->uKeyMax)
-                                                       
std::swap(pRgn->uKeyMin, pRgn->uKeyMax);
+                                               {
+                                                       uint8 keyMin = 
static_cast<uint8>(value & 0xFF);
+                                                       uint8 keyMax = 
static_cast<uint8>(value >> 8);
+                                                       if(keyMin > keyMax)
+                                                               
std::swap(keyMin, keyMax);
+                                                       rgn.uKeyMin = 
std::max(rgn.uKeyMin, keyMin);
+                                                       rgn.uKeyMax = 
std::min(rgn.uKeyMax, keyMax);
+                                                       // There was no overlap 
between instrument region and preset region - skip it
+                                                       if(rgn.uKeyMin > 
rgn.uKeyMax)
+                                                               rgn.uKeyMin = 
rgn.uKeyMax = 0xFF;
+                                               }
                                                break;
                                        case SF2_GEN_UNITYNOTE:
-                                               if (value < 128) 
pRgn->uUnityNote = (uint8)value;
+                                               if (value < 128) rgn.uUnityNote 
= (uint8)value;
                                                break;
                                        case SF2_GEN_ATTACKVOLENV:
                                                pDlsEnv->wVolAttack = 
SF2TimeToDLS(gen.genAmount);
@@ -1162,7 +1186,7 @@
                                                {
                                                        int32 pan = 
static_cast<int16>(value);
                                                        pan = 
std::clamp(Util::muldivr(pan + 500, 256, 1000), 0, 256);
-                                                       pRgn->panning = 
static_cast<int16>(pan);
+                                                       rgn.panning = 
static_cast<int16>(pan);
                                                        pDlsEnv->nDefPan = 
mpt::saturate_cast<uint8>(pan);
                                                }
                                                break;
@@ -1172,33 +1196,33 @@
                                        case SF2_GEN_SAMPLEID:
                                                if (value < m_SamplesEx.size())
                                                {
-                                                       pRgn->nWaveLink = value;
-                                                       pRgn->ulLoopStart = 
mpt::saturate_cast<uint32>(m_SamplesEx[value].dwStartloop + loopStart);
-                                                       pRgn->ulLoopEnd = 
mpt::saturate_cast<uint32>(m_SamplesEx[value].dwEndloop + loopEnd);
+                                                       rgn.nWaveLink = value;
+                                                       rgn.ulLoopStart = 
mpt::saturate_cast<uint32>(m_SamplesEx[value].dwStartloop + loopStart);
+                                                       rgn.ulLoopEnd = 
mpt::saturate_cast<uint32>(m_SamplesEx[value].dwEndloop + loopEnd);
                                                }
                                                break;
                                        case SF2_GEN_SAMPLEMODES:
                                                value &= 3;
-                                               pRgn->fuOptions &= 
uint16(~(DLSREGION_SAMPLELOOP|DLSREGION_PINGPONGLOOP|DLSREGION_SUSTAINLOOP));
+                                               rgn.fuOptions &= 
uint16(~(DLSREGION_SAMPLELOOP|DLSREGION_PINGPONGLOOP|DLSREGION_SUSTAINLOOP));
                                                if(value == 1)
-                                                       pRgn->fuOptions |= 
DLSREGION_SAMPLELOOP;
+                                                       rgn.fuOptions |= 
DLSREGION_SAMPLELOOP;
                                                else if(value == 2)
-                                                       pRgn->fuOptions |= 
DLSREGION_SAMPLELOOP | DLSREGION_PINGPONGLOOP;
+                                                       rgn.fuOptions |= 
DLSREGION_SAMPLELOOP | DLSREGION_PINGPONGLOOP;
                                                else if(value == 3)
-                                                       pRgn->fuOptions |= 
DLSREGION_SAMPLELOOP | DLSREGION_SUSTAINLOOP;
-                                               pRgn->fuOptions |= 
DLSREGION_OVERRIDEWSMP;
+                                                       rgn.fuOptions |= 
DLSREGION_SAMPLELOOP | DLSREGION_SUSTAINLOOP;
+                                               rgn.fuOptions |= 
DLSREGION_OVERRIDEWSMP;
                                                break;
                                        case SF2_GEN_KEYGROUP:
-                                               pRgn->fuOptions |= (value & 
DLSREGION_KEYGROUPMASK);
+                                               rgn.fuOptions |= (value & 
DLSREGION_KEYGROUPMASK);
                                                break;
                                        case SF2_GEN_COARSETUNE:
-                                               pRgn->sFineTune += 
static_cast<int16>(value) * 128;
+                                               rgn.sFineTune += 
static_cast<int16>(value) * 128;
                                                break;
                                        case SF2_GEN_FINETUNE:
-                                               pRgn->sFineTune += 
static_cast<int16>(Util::muldiv(static_cast<int8>(value), 128, 100));
+                                               rgn.sFineTune += 
static_cast<int16>(Util::muldiv(static_cast<int8>(value), 128, 100));
                                                break;
                                        case SF2_GEN_SCALE_TUNING:
-                                               pRgn->tuning = 
mpt::saturate_cast<uint8>(value);
+                                               rgn.tuning = 
mpt::saturate_cast<uint8>(value);
                                                break;
                                        case SF2_GEN_START_LOOP_FINE:
                                                loopStart += 
static_cast<int16>(value);
@@ -1216,14 +1240,14 @@
                                        //      Log("    gen=%d value=%04X\n", 
pgen->sfGenOper, pgen->genAmount);
                                        }
                                }
-                               if(lastOp != SF2_GEN_SAMPLEID && nRgn == 
startRegion)
-                               {
-                                       hasGlobalZone = true;
-                                       pRgn->fuOptions |= DLSREGION_ISGLOBAL;
-                               }
                                int32 linearVol = 
DLS32BitRelativeGainToLinear(((instrAttenuation + regionAttn) * 65536) / 10) / 
256;
                                Limit(linearVol, 16, 256);
-                               pRgn->usVolume = static_cast<uint16>(linearVol);
+                               rgn.usVolume = static_cast<uint16>(linearVol);
+
+                               if(lastOp != SF2_GEN_SAMPLEID && nRgn == 0)
+                                       globalZone = rgn;
+                               else if(!rgn.IsDummy())
+                                       dlsIns.Regions.push_back(rgn);
                                //Log("\n");
                        }
                }
@@ -1399,10 +1423,10 @@
                                                uint32 subID = 
listChunk.ReadUint32LE();
                                                if ((subID == IFFID_ins) && 
(nInsDef < m_Instruments.size()))
                                                {
-                                                       DLSINSTRUMENT *pDlsIns 
= &m_Instruments[nInsDef];
+                                                       DLSINSTRUMENT &dlsIns = 
m_Instruments[nInsDef];
                                                        //Log("Instrument 
%d:\n", nInsDef);
-                                                       
pDlsIns->Regions.push_back({});
-                                                       
UpdateInstrumentDefinition(pDlsIns, subData);
+                                                       
dlsIns.Regions.push_back({});
+                                                       
UpdateInstrumentDefinition(&dlsIns, subData);
                                                        nInsDef++;
                                                }
                                        } else
@@ -1483,7 +1507,7 @@
 }
 
 
////////////////////////////////////////////////////////////////////////////////////////
-// Extracts the WaveForms from a DLS bank
+// Extracts the Waveforms from a DLS/SF2 bank
 
 uint32 CDLSBank::GetRegionFromKey(uint32 nIns, uint32 nKey) const
 {
@@ -1492,9 +1516,10 @@
        const DLSINSTRUMENT &dlsIns = m_Instruments[nIns];
        for(uint32 rgn = 0; rgn < static_cast<uint32>(dlsIns.Regions.size()); 
rgn++)
        {
-               if(nKey < dlsIns.Regions[rgn].uKeyMin || nKey > 
dlsIns.Regions[rgn].uKeyMax)
+               const auto &region = dlsIns.Regions[rgn];
+               if(nKey < region.uKeyMin || nKey > region.uKeyMax)
                        continue;
-               if(dlsIns.Regions[rgn].fuOptions & DLSREGION_ISGLOBAL)
+               if(region.nWaveLink == Util::MaxValueOfType(region.nWaveLink))
                        continue;
                return rgn;
        }
@@ -1590,8 +1615,8 @@
 
        if(nIns >= m_Instruments.size())
                return false;
-       const DLSINSTRUMENT *pDlsIns = &m_Instruments[nIns];
-       if(nRgn >= pDlsIns->Regions.size())
+       const DLSINSTRUMENT &dlsIns = m_Instruments[nIns];
+       if(nRgn >= dlsIns.Regions.size())
                return false;
        if(!ExtractWaveForm(nIns, nRgn, pWaveForm, dwLen))
                return false;
@@ -1603,7 +1628,7 @@
        if (m_nType & SOUNDBANK_TYPE_SF2)
        {
                sndFile.DestroySample(nSample);
-               uint32 nWaveLink = pDlsIns->Regions[nRgn].nWaveLink;
+               uint32 nWaveLink = dlsIns.Regions[nRgn].nWaveLink;
                ModSample &sample = sndFile.GetSample(nSample);
                if (sndFile.m_nSamples < nSample) sndFile.m_nSamples = nSample;
                if (nWaveLink < m_SamplesEx.size())
@@ -1614,15 +1639,15 @@
                #endif
                        sample.Initialize();
                        sample.nLength = dwLen / 2;
-                       sample.nLoopStart = pDlsIns->Regions[nRgn].ulLoopStart;
-                       sample.nLoopEnd = pDlsIns->Regions[nRgn].ulLoopEnd;
+                       sample.nLoopStart = dlsIns.Regions[nRgn].ulLoopStart;
+                       sample.nLoopEnd = dlsIns.Regions[nRgn].ulLoopEnd;
                        sample.nC5Speed = p.dwSampleRate;
                        sample.RelativeTone = p.byOriginalPitch;
                        sample.nFineTune = p.chPitchCorrection;
                        if (p.szName[0])
                                sndFile.m_szNames[nSample] = 
mpt::String::ReadAutoBuf(p.szName);
-                       else if(pDlsIns->szName[0])
-                               sndFile.m_szNames[nSample] = 
mpt::String::ReadAutoBuf(pDlsIns->szName);
+                       else if(dlsIns.szName[0])
+                               sndFile.m_szNames[nSample] = 
mpt::String::ReadAutoBuf(dlsIns.szName);
 
                        FileReader chunk(mpt::as_span(pWaveForm.data(), dwLen));
                        SampleIO(
@@ -1637,13 +1662,13 @@
        {
                FileReader file(mpt::as_span(pWaveForm.data(), dwLen));
                hasWaveform = sndFile.ReadWAVSample(nSample, file, false, 
&wsmpChunk);
-               if(pDlsIns->szName[0])
-                       sndFile.m_szNames[nSample] = 
mpt::String::ReadAutoBuf(pDlsIns->szName);
+               if(dlsIns.szName[0])
+                       sndFile.m_szNames[nSample] = 
mpt::String::ReadAutoBuf(dlsIns.szName);
        }
        if (hasWaveform)
        {
                ModSample &sample = sndFile.GetSample(nSample);
-               const DLSREGION &rgn = pDlsIns->Regions[nRgn];
+               const DLSREGION &rgn = dlsIns.Regions[nRgn];
                sample.uFlags.reset(CHN_LOOP | CHN_PINGPONGLOOP | 
CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN);
                if (rgn.fuOptions & DLSREGION_SAMPLELOOP) 
sample.uFlags.set(CHN_LOOP);
                if (rgn.fuOptions & DLSREGION_SUSTAINLOOP) 
sample.uFlags.set(CHN_SUSTAINLOOP);
@@ -1725,35 +1750,34 @@
 
 bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, 
uint32 nIns, uint32 nDrumRgn) const
 {
-       uint32 nRgnMin, nRgnMax, nEnv;
+       uint32 minRegion, maxRegion, nEnv;
 
-       if (nIns >= m_Instruments.size()) return false;
-       const DLSINSTRUMENT *pDlsIns = &m_Instruments[nIns];
-       std::vector<SAMPLEINDEX> RgnToSmp(pDlsIns->Regions.size());
-       if (pDlsIns->ulBank & F_INSTRUMENT_DRUMS)
+       if (nIns >= m_Instruments.size())
+               return false;
+       const DLSINSTRUMENT &dlsIns = m_Instruments[nIns];
+       const bool isDrum = (dlsIns.ulBank & F_INSTRUMENT_DRUMS);
+       if(isDrum)
        {
-               if(nDrumRgn >= pDlsIns->Regions.size())
+               if(nDrumRgn >= dlsIns.Regions.size())
                        return false;
-               nRgnMin = nDrumRgn;
-               nRgnMax = nDrumRgn+1;
-               nEnv = pDlsIns->Regions[nDrumRgn].uPercEnv;
+               minRegion = nDrumRgn;
+               maxRegion = nDrumRgn + 1;
+               nEnv = dlsIns.Regions[nDrumRgn].uPercEnv;
        } else
        {
-               if(pDlsIns->Regions.empty())
+               if(dlsIns.Regions.empty())
                        return false;
-               nRgnMin = 0;
-               nRgnMax = static_cast<uint32>(pDlsIns->Regions.size());
-               nEnv = pDlsIns->nMelodicEnv;
+               minRegion = 0;
+               maxRegion = static_cast<uint32>(dlsIns.Regions.size());
+               nEnv = dlsIns.nMelodicEnv;
        }
-       if(nRgnMin == 0 && (pDlsIns->Regions[0].fuOptions & DLSREGION_ISGLOBAL))
-               nRgnMin++;
 #ifdef DLSINSTR_LOG
-       MPT_LOG(LogDebug, "DLSINSTR", mpt::format(U_("DLS Instrument #%1: 
%2"))(nIns, mpt::ToUnicode(mpt::Charset::ASCII, 
mpt::String::ReadAutoBuf(pDlsIns->szName))));
-       MPT_LOG(LogDebug, "DLSINSTR", mpt::format(U_("  Bank=0x%1 
Instrument=0x%2"))(mpt::ufmt::HEX0<4>(pDlsIns->ulBank), 
mpt::ufmt::HEX0<4>(pDlsIns->ulInstrument)));
-       MPT_LOG(LogDebug, "DLSINSTR", mpt::format(U_("  %1 regions, 
nMelodicEnv=%2"))(pDlsIns->Regions.size(), pDlsIns->nMelodicEnv));
-       for (uint32 iDbg=0; iDbg<pDlsIns->Regions.size(); iDbg++)
+       MPT_LOG(LogDebug, "DLSINSTR", mpt::format(U_("DLS Instrument #%1: 
%2"))(nIns, mpt::ToUnicode(mpt::Charset::ASCII, 
mpt::String::ReadAutoBuf(dlsIns.szName))));
+       MPT_LOG(LogDebug, "DLSINSTR", mpt::format(U_("  Bank=0x%1 
Instrument=0x%2"))(mpt::ufmt::HEX0<4>(dlsIns.ulBank), 
mpt::ufmt::HEX0<4>(dlsIns.ulInstrument)));
+       MPT_LOG(LogDebug, "DLSINSTR", mpt::format(U_("  %1 regions, 
nMelodicEnv=%2"))(dlsIns.Regions.size(), dlsIns.nMelodicEnv));
+       for (uint32 iDbg=0; iDbg<dlsIns.Regions.size(); iDbg++)
        {
-               const DLSREGION *prgn = &pDlsIns->Regions[iDbg];
+               const DLSREGION *prgn = &dlsIns.Regions[iDbg];
                MPT_LOG(LogDebug, "DLSINSTR", mpt::format(U_(" Region 
%1:"))(iDbg));
                MPT_LOG(LogDebug, "DLSINSTR", mpt::format(U_("  WaveLink = %1 
(loop [%2, %3])"))(prgn->nWaveLink, prgn->ulLoopStart, prgn->ulLoopEnd));
                MPT_LOG(LogDebug, "DLSINSTR", mpt::format(U_("  Key Range: [%1, 
%2]"))(prgn->uKeyMin, prgn->uKeyMax));
@@ -1768,57 +1792,57 @@
                return false;
        }
 
-       if (sndFile.Instruments[nInstr])
+       if(sndFile.Instruments[nInstr])
        {
                sndFile.DestroyInstrument(nInstr, deleteAssociatedSamples);
        }
        // Initializes Instrument
-       if (pDlsIns->ulBank & F_INSTRUMENT_DRUMS)
+       if(isDrum)
        {
-               uint32 key = pDlsIns->Regions[nDrumRgn].uKeyMin;
+               uint32 key = dlsIns.Regions[nDrumRgn].uKeyMin;
                if((key >= 24) && (key <= 84))
                {
                        std::string s = szMidiPercussionNames[key-24];
-                       if(!mpt::String::ReadAutoBuf(pDlsIns->szName).empty())
+                       if(!mpt::String::ReadAutoBuf(dlsIns.szName).empty())
                        {
-                               s += mpt::format(" 
(%1)")(mpt::String::RTrim<std::string>(mpt::String::ReadAutoBuf(pDlsIns->szName)));
+                               s += mpt::format(" 
(%1)")(mpt::String::RTrim<std::string>(mpt::String::ReadAutoBuf(dlsIns.szName)));
                        }
                        pIns->name = s;
                } else
                {
-                       pIns->name = mpt::String::ReadAutoBuf(pDlsIns->szName);
+                       pIns->name = mpt::String::ReadAutoBuf(dlsIns.szName);
                }
        } else
        {
-               pIns->name = mpt::String::ReadAutoBuf(pDlsIns->szName);
+               pIns->name = mpt::String::ReadAutoBuf(dlsIns.szName);
        }
-       int nTranspose = 0;
-       if(pDlsIns->ulBank & F_INSTRUMENT_DRUMS)
+       int transpose = 0;
+       if(isDrum)
        {
                for(uint32 iNoteMap = 0; iNoteMap < NOTE_MAX; iNoteMap++)
                {
                        if(sndFile.GetType() & (MOD_TYPE_IT | MOD_TYPE_MID | 
MOD_TYPE_MPT))
                        {
                                // Format has instrument note mapping
-                               if(pDlsIns->Regions[nDrumRgn].tuning == 0)
+                               if(dlsIns.Regions[nDrumRgn].tuning == 0)
                                        pIns->NoteMap[iNoteMap] = NOTE_MIDDLEC;
-                               else if(iNoteMap < 
pDlsIns->Regions[nDrumRgn].uKeyMin)
-                                       pIns->NoteMap[iNoteMap] = 
(uint8)(pDlsIns->Regions[nDrumRgn].uKeyMin + NOTE_MIN);
-                               else if(iNoteMap > 
pDlsIns->Regions[nDrumRgn].uKeyMax)
-                                       pIns->NoteMap[iNoteMap] = 
(uint8)(pDlsIns->Regions[nDrumRgn].uKeyMax + NOTE_MIN);
+                               else if (iNoteMap < 
dlsIns.Regions[nDrumRgn].uKeyMin)
+                                       pIns->NoteMap[iNoteMap] = 
(uint8)(dlsIns.Regions[nDrumRgn].uKeyMin + NOTE_MIN);
+                               else if(iNoteMap > 
dlsIns.Regions[nDrumRgn].uKeyMax)
+                                       pIns->NoteMap[iNoteMap] = 
(uint8)(dlsIns.Regions[nDrumRgn].uKeyMax + NOTE_MIN);
                        } else
                        {
-                               if(iNoteMap == 
pDlsIns->Regions[nDrumRgn].uKeyMin)
+                               if(iNoteMap == dlsIns.Regions[nDrumRgn].uKeyMin)
                                {
-                                       nTranspose = 
(pDlsIns->Regions[nDrumRgn].uKeyMin + (pDlsIns->Regions[nDrumRgn].uKeyMax - 
pDlsIns->Regions[nDrumRgn].uKeyMin) / 2) - 60;
+                                       transpose = 
(dlsIns.Regions[nDrumRgn].uKeyMin + (dlsIns.Regions[nDrumRgn].uKeyMax - 
dlsIns.Regions[nDrumRgn].uKeyMin) / 2) - 60;
                                }
                        }
                }
        }
        pIns->nFadeOut = 1024;
-       pIns->nMidiProgram = (uint8)(pDlsIns->ulInstrument & 0x7F) + 1;
-       pIns->nMidiChannel = (uint8)((pDlsIns->ulBank & F_INSTRUMENT_DRUMS) ? 
10 : 0);
-       pIns->wMidiBank = (uint16)(((pDlsIns->ulBank & 0x7F00) >> 1) | 
(pDlsIns->ulBank & 0x7F));
+       pIns->nMidiProgram = (uint8)(dlsIns.ulInstrument & 0x7F) + 1;
+       pIns->nMidiChannel = (uint8)(isDrum ? 10 : 0);
+       pIns->wMidiBank = (uint16)(((dlsIns.ulBank & 0x7F00) >> 1) | 
(dlsIns.ulBank & 0x7F));
        pIns->nNNA = NNA_NOTEOFF;
        pIns->nDCT = DCT_NOTE;
        pIns->nDNA = DNA_NOTEFADE;
@@ -1826,31 +1850,38 @@
        uint32 nLoadedSmp = 0;
        SAMPLEINDEX nextSample = 0;
        // Extract Samples
-       for (uint32 nRgn=nRgnMin; nRgn<nRgnMax; nRgn++)
+       std::vector<SAMPLEINDEX> RgnToSmp(dlsIns.Regions.size());
+       std::set<uint16> extractedSamples;
+       for(uint32 nRgn = minRegion; nRgn < maxRegion; nRgn++)
        {
                bool duplicateRegion = false;
                SAMPLEINDEX nSmp = 0;
-               const DLSREGION *pRgn = &pDlsIns->Regions[nRgn];
+               const DLSREGION &rgn = dlsIns.Regions[nRgn];
+               if(rgn.IsDummy())
+                       continue;
                // Elimitate Duplicate Regions
-               uint32 iDup;
-               for (iDup=nRgnMin; iDup<nRgn; iDup++)
+               uint32 dupRegion;
+               for(dupRegion = minRegion; dupRegion < nRgn; dupRegion++)
                {
-                       const DLSREGION *pRgn2 = &pDlsIns->Regions[iDup];
-                       if (((pRgn2->nWaveLink == pRgn->nWaveLink)
-                         && (pRgn2->ulLoopEnd == pRgn->ulLoopEnd)
-                         && (pRgn2->ulLoopStart == pRgn->ulLoopStart))
-                        || ((pRgn2->uKeyMin == pRgn->uKeyMin)
-                         && (pRgn2->uKeyMax == pRgn->uKeyMax)))
+                       const DLSREGION &rgn2 = dlsIns.Regions[dupRegion];
+                       if(RgnToSmp[dupRegion] == 0 || rgn2.IsDummy())
+                               continue;
+                       // No need to extract the same sample data twice
+                       const bool sameSample = (rgn2.nWaveLink == 
rgn.nWaveLink) && (rgn2.ulLoopEnd == rgn.ulLoopEnd) && (rgn2.ulLoopStart == 
rgn.ulLoopStart) && extractedSamples.count(rgn.nWaveLink);
+                       // Candidate for stereo sample creation
+                       const bool sameKeyRange = (rgn2.uKeyMin == rgn.uKeyMin) 
&& (rgn2.uKeyMax == rgn.uKeyMax);
+                       if(sameSample || sameKeyRange)
                        {
                                duplicateRegion = true;
-                               nSmp = RgnToSmp[iDup];
+                               if(!sameKeyRange)
+                                       nSmp = RgnToSmp[dupRegion];
                                break;
                        }
                }
                // Create a new sample
                if (!duplicateRegion)
                {
-                       uint32 nmaxsmp = (m_nType & MOD_TYPE_XM) ? 16 : 32;
+                       uint32 nmaxsmp = (m_nType & MOD_TYPE_XM) ? 16 : 
(NOTE_MAX - NOTE_MIN + 1);
                        if (nLoadedSmp >= nmaxsmp)
                        {
                                nSmp = RgnToSmp[nRgn - 1];
@@ -1866,40 +1897,41 @@
 
                RgnToSmp[nRgn] = nSmp;
                // Map all notes to the right sample
-               if (nSmp)
+               if(nSmp)
                {
-                       for (uint32 iKey=0; iKey<NOTE_MAX; iKey++)
+                       for(uint8 key = 0; key < NOTE_MAX; key++)
                        {
-                               if ((nRgn == nRgnMin) || ((iKey >= 
pRgn->uKeyMin) && (iKey <= pRgn->uKeyMax)))
+                               if(isDrum || (key >= rgn.uKeyMin && key <= 
rgn.uKeyMax))
                                {
-                                       pIns->Keyboard[iKey] = nSmp;
+                                       pIns->Keyboard[key] = nSmp;
                                }
                        }
                        // Load the sample
                        if(!duplicateRegion || 
!sndFile.GetSample(nSmp).HasSampleData())
                        {
-                               ExtractSample(sndFile, nSmp, nIns, nRgn, 
nTranspose);
-                       } else if(sndFile.GetSample(nSmp).GetNumChannels() == 1)
-                       {
-                               // Try to combine stereo samples
-                               const uint16 pan1 = GetPanning(nIns, nRgn), 
pan2 = GetPanning(nIns, iDup);
-                               if((pan1 < 16 && pan2 >= 240) || (pan2 < 16 && 
pan1 >= 240))
-                               {
-                                       ModSample &sample = 
sndFile.GetSample(nSmp);
-                                       ctrlSmp::ConvertToStereo(sample, 
sndFile);
-                                       std::vector<uint8> pWaveForm;
-                                       uint32 dwLen = 0;
-                                       if(ExtractWaveForm(nIns, nRgn, 
pWaveForm, dwLen) && dwLen >= sample.GetSampleSizeInBytes() / 2)
+                               ExtractSample(sndFile, nSmp, nIns, nRgn, 
transpose);
+                               extractedSamples.insert(rgn.nWaveLink);
+                       }
+               } else if(duplicateRegion && 
sndFile.GetSample(nSmp).GetNumChannels() == 1)
+               {
+                       // Try to combine stereo samples
+                       const uint16 pan1 = GetPanning(nIns, nRgn), pan2 = 
GetPanning(nIns, dupRegion);
+                       if((pan1 < 16 && pan2 >= 240) || (pan2 < 16 && pan1 >= 
240))
+                       {
+                               ModSample &sample = sndFile.GetSample(nSmp);
+                               ctrlSmp::ConvertToStereo(sample, sndFile);
+                               std::vector<uint8> pWaveForm;
+                               uint32 dwLen = 0;
+                               if(ExtractWaveForm(nIns, nRgn, pWaveForm, 
dwLen) && dwLen >= sample.GetSampleSizeInBytes() / 2)
+                               {
+                                       SmpLength len = sample.nLength;
+                                       const int16 *src = 
reinterpret_cast<int16 *>(pWaveForm.data());
+                                       int16 *dst = sample.sample16() + ((pan1 
== 0) ? 0 : 1);
+                                       while(len--)
                                        {
-                                               SmpLength len = sample.nLength;
-                                               const int16 *src = 
reinterpret_cast<int16 *>(pWaveForm.data());
-                                               int16 *dst = sample.sample16() 
+ ((pan1 == 0) ? 0 : 1);
-                                               while(len--)
-                                               {
-                                                       *dst = *src;
-                                                       src++;
-                                                       dst += 2;
-                                               }
+                                               *dst = *src;
+                                               src++;
+                                               dst += 2;
                                        }
                                }
                        }
@@ -1910,27 +1942,26 @@
        if(sndFile.m_nTempoMode == tempoModeModern)
        {
                uint32 ticksPerBeat = sndFile.m_nDefaultRowsPerBeat * 
sndFile.m_nDefaultSpeed;
-               if(ticksPerBeat == 0)
-                       ticksPerBeat = 24;
-               tempoScale = ticksPerBeat / 24.0f;
+               if(ticksPerBeat != 0)
+                       tempoScale = ticksPerBeat / 24.0f;
        }
 
        // Initializes Envelope
        if ((nEnv) && (nEnv <= m_Envelopes.size()))
        {
-               const DLSENVELOPE *part = &m_Envelopes[nEnv-1];
+               const DLSENVELOPE &part = m_Envelopes[nEnv - 1];
                // Volume Envelope
-               if ((part->wVolAttack) || (part->wVolDecay < 20*50) || 
(part->nVolSustainLevel) || (part->wVolRelease < 20*50))
+               if ((part.wVolAttack) || (part.wVolDecay < 20*50) || 
(part.nVolSustainLevel) || (part.wVolRelease < 20*50))
                {
                        pIns->VolEnv.dwFlags.set(ENV_ENABLED);
                        // Delay section
                        // -> DLS level 2
                        // Attack section
                        pIns->VolEnv.clear();
-                       if (part->wVolAttack)
+                       if (part.wVolAttack)
                        {
-                               pIns->VolEnv.push_back(0, (uint8)(ENVELOPE_MAX 
/ (part->wVolAttack / 2 + 2) + 8)); // /-----
-                               
pIns->VolEnv.push_back(ScaleEnvelope(part->wVolAttack, tempoScale), 
ENVELOPE_MAX); // |
+                               pIns->VolEnv.push_back(0, (uint8)(ENVELOPE_MAX 
/ (part.wVolAttack / 2 + 2) + 8)); // /-----
+                               
pIns->VolEnv.push_back(ScaleEnvelope(part.wVolAttack, tempoScale), 
ENVELOPE_MAX); // |
                        } else
                        {
                                pIns->VolEnv.push_back(0, ENVELOPE_MAX);
@@ -1938,24 +1969,24 @@
                        // Hold section
                        // -> DLS Level 2
                        // Sustain Level
-                       if (part->nVolSustainLevel > 0)
+                       if (part.nVolSustainLevel > 0)
                        {
-                               if (part->nVolSustainLevel < 128)
+                               if (part.nVolSustainLevel < 128)
                                {
                                        uint16 lStartTime = 
pIns->VolEnv.back().tick;
-                                       int32 lSusLevel = - 
DLS32BitRelativeLinearToGain(part->nVolSustainLevel << 9) / 65536;
+                                       int32 lSusLevel = - 
DLS32BitRelativeLinearToGain(part.nVolSustainLevel << 9) / 65536;
                                        int32 lDecayTime = 1;
                                        if (lSusLevel > 0)
                                        {
-                                               lDecayTime = (lSusLevel * 
(int32)part->wVolDecay) / 960;
+                                               lDecayTime = (lSusLevel * 
(int32)part.wVolDecay) / 960;
                                                for (uint32 i=0; i<7; i++)
                                                {
                                                        int32 lFactor = 128 - 
(1 << i);
-                                                       if (lFactor <= 
part->nVolSustainLevel) break;
+                                                       if (lFactor <= 
part.nVolSustainLevel) break;
                                                        int32 lev = - 
DLS32BitRelativeLinearToGain(lFactor << 9) / 65536;
                                                        if (lev > 0)
                                                        {
-                                                               int32 ltime = 
(lev * (int32)part->wVolDecay) / 960;
+                                                               int32 ltime = 
(lev * (int32)part.wVolDecay) / 960;
                                                                if ((ltime > 1) 
&& (ltime < lDecayTime))
                                                                {
                                                                        uint16 
tick = lStartTime + ScaleEnvelope(ltime, tempoScale);
@@ -1971,7 +2002,7 @@
                                        uint16 decayEnd = lStartTime + 
ScaleEnvelope(lDecayTime, tempoScale);
                                        if (decayEnd > pIns->VolEnv.back().tick)
                                        {
-                                               
pIns->VolEnv.push_back(decayEnd, (uint8)((part->nVolSustainLevel+1) / 2));
+                                               
pIns->VolEnv.push_back(decayEnd, (uint8)((part.nVolSustainLevel+1) / 2));
                                        }
                                }
                                pIns->VolEnv.dwFlags.set(ENV_SUSTAIN);
@@ -1982,9 +2013,9 @@
                        }
                        pIns->VolEnv.nSustainStart = pIns->VolEnv.nSustainEnd = 
(uint8)(pIns->VolEnv.size() - 1);
                        // Release section
-                       if ((part->wVolRelease) && (pIns->VolEnv.back().value > 
1))
+                       if ((part.wVolRelease) && (pIns->VolEnv.back().value > 
1))
                        {
-                               int32 lReleaseTime = part->wVolRelease;
+                               int32 lReleaseTime = part.wVolRelease;
                                uint16 lStartTime = pIns->VolEnv.back().tick;
                                int32 lStartFactor = pIns->VolEnv.back().value;
                                int32 lSusLevel = - 
DLS32BitRelativeLinearToGain(lStartFactor << 10) / 65536;
@@ -1999,7 +2030,7 @@
                                        int32 lev = - 
DLS32BitRelativeLinearToGain(lFactor << 10) / 65536;
                                        if (lev > 0)
                                        {
-                                               int32 ltime = 
(((int32)part->wVolRelease * lev) / 960) - lDecayEndTime;
+                                               int32 ltime = 
(((int32)part.wVolRelease * lev) / 960) - lDecayEndTime;
                                                if ((ltime > 1) && (ltime < 
lReleaseTime))
                                                {
                                                        uint16 tick = 
lStartTime + ScaleEnvelope(ltime, tempoScale);
@@ -2023,7 +2054,7 @@
                        }
                }
        }
-       if (pDlsIns->ulBank & F_INSTRUMENT_DRUMS)
+       if(isDrum)
        {
                // Create a default envelope for drums
                pIns->VolEnv.dwFlags.reset(ENV_SUSTAIN);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libopenmpt-0.5.12+release.autotools/soundlib/Dlsbank.h 
new/libopenmpt-0.5.13+release.autotools/soundlib/Dlsbank.h
--- old/libopenmpt-0.5.12+release.autotools/soundlib/Dlsbank.h  2021-08-23 
23:33:58.000000000 +0200
+++ new/libopenmpt-0.5.13+release.autotools/soundlib/Dlsbank.h  2021-11-13 
02:37:36.000000000 +0100
@@ -37,6 +37,8 @@
        uint8  uKeyMax;
        uint8  uUnityNote;
        uint8  tuning = 100;
+
+       constexpr bool IsDummy() const noexcept { return uKeyMin == 0xFF || 
nWaveLink == Util::MaxValueOfType(nWaveLink); }
 };
 
 struct DLSENVELOPE
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libopenmpt-0.5.12+release.autotools/soundlib/Load_imf.cpp 
new/libopenmpt-0.5.13+release.autotools/soundlib/Load_imf.cpp
--- old/libopenmpt-0.5.12+release.autotools/soundlib/Load_imf.cpp       
2020-10-31 13:58:24.000000000 +0100
+++ new/libopenmpt-0.5.13+release.autotools/soundlib/Load_imf.cpp       
2021-11-13 02:20:37.000000000 +0100
@@ -16,11 +16,11 @@
 
 struct IMFChannel
 {
-       char  name[12]; // Channel name (ASCIIZ-String, max 11 chars)
-       uint8 chorus;   // Default chorus
-       uint8 reverb;   // Default reverb
-       uint8 panning;  // Pan positions 00-FF
-       uint8 status;   // Channel status: 0 = enabled, 1 = mute, 2 = disabled 
(ignore effects!)
+       char  name[12];  // Channel name (ASCIIZ-String, max 11 chars)
+       uint8 chorus;    // Default chorus
+       uint8 reverb;    // Default reverb
+       uint8 panning;   // Pan positions 00-FF
+       uint8 status;    // Channel status: 0 = enabled, 1 = mute, 2 = disabled 
(ignore effects!)
 };
 
 MPT_BINARY_STRUCT(IMFChannel, 16)
@@ -32,19 +32,19 @@
                linearSlides = 0x01,
        };
 
-       char     title[32];                     // Songname (ASCIIZ-String, 
max. 31 chars)
-       uint16le ordNum;                        // Number of orders saved
-       uint16le patNum;                        // Number of patterns saved
-       uint16le insNum;                        // Number of instruments saved
-       uint16le flags;                         // See SongFlags
+       char     title[32];  // Songname (ASCIIZ-String, max. 31 chars)
+       uint16le ordNum;     // Number of orders saved
+       uint16le patNum;     // Number of patterns saved
+       uint16le insNum;     // Number of instruments saved
+       uint16le flags;      // See SongFlags
        uint8le  unused1[8];
-       uint8le  tempo;                         // Default tempo (Axx, 1...255)
-       uint8le  bpm;                           // Default beats per minute 
(BPM) (Txx, 32...255)
-       uint8le  master;                        // Default master volume (Vxx, 
0...64)
-       uint8le  amp;                           // Amplification factor (mixing 
volume, 4...127)
+       uint8le  tempo;   // Default tempo (Axx, 1...255)
+       uint8le  bpm;     // Default beats per minute (BPM) (Txx, 32...255)
+       uint8le  master;  // Default master volume (Vxx, 0...64)
+       uint8le  amp;     // Amplification factor (mixing volume, 4...127)
        uint8le  unused2[8];
-       char     im10[4];                       // 'IM10'
-       IMFChannel channels[32];        // Channel settings
+       char     im10[4];         // 'IM10'
+       IMFChannel channels[32];  // Channel settings
 };
 
 MPT_BINARY_STRUCT(IMFFileHeader, 576)
@@ -53,16 +53,16 @@
 {
        enum EnvFlags
        {
-               envEnabled      = 0x01,
-               envSustain      = 0x02,
-               envLoop         = 0x04,
+               envEnabled = 0x01,
+               envSustain = 0x02,
+               envLoop    = 0x04,
        };
 
-       uint8 points;           // Number of envelope points
-       uint8 sustain;          // Envelope sustain point
-       uint8 loopStart;        // Envelope loop start point
-       uint8 loopEnd;          // Envelope loop end point
-       uint8 flags;            // See EnvFlags
+       uint8 points;     // Number of envelope points
+       uint8 sustain;    // Envelope sustain point
+       uint8 loopStart;  // Envelope loop start point
+       uint8 loopEnd;    // Envelope loop end point
+       uint8 flags;      // See EnvFlags
        uint8 unused[3];
 };
 
@@ -80,19 +80,19 @@
 {
        enum EnvTypes
        {
-               volEnv = 0,
-               panEnv = 1,
+               volEnv    = 0,
+               panEnv    = 1,
                filterEnv = 2,
        };
 
-       char        name[32];   // Inst. name (ASCIIZ-String, max. 31 chars)
-       uint8le     map[120];   // Multisample settings
+       char        name[32];  // Inst. name (ASCIIZ-String, max. 31 chars)
+       uint8le     map[120];  // Multisample settings
        uint8le     unused[8];
        IMFEnvNode  nodes[3][16];
        IMFEnvelope env[3];
-       uint16le    fadeout;    // Fadeout rate (0...0FFFH)
-       uint16le    smpNum;             // Number of samples in instrument
-       char        ii10[4];    // 'II10'
+       uint16le    fadeout;  // Fadeout rate (0...0FFFH)
+       uint16le    smpNum;   // Number of samples in instrument
+       char        ii10[4];  // 'II10' (not verified by Orpheus)
 
        void ConvertEnvelope(InstrumentEnvelope &mptEnv, EnvTypes e) const
        {
@@ -114,6 +114,7 @@
                        minTick++;
                        mptEnv[n].value = 
static_cast<uint8>(std::min(nodes[e][n].value >> shift, ENVELOPE_MAX));
                }
+               mptEnv.Convert(MOD_TYPE_XM, MOD_TYPE_IT);
        }
 
        // Convert an IMFInstrument to OpenMPT's internal instrument 
representation.
@@ -155,20 +156,20 @@
                smpPanning              = 0x08,
        };
 
-       char     filename[13];  // Sample filename (12345678.ABC) */
+       char     filename[13];  // Sample filename (12345678.ABC) */
        uint8le  unused1[3];
-       uint32le length;                // Length (in bytes)
-       uint32le loopStart;             // Loop start (in bytes)
-       uint32le loopEnd;               // Loop end (in bytes)
-       uint32le c5Speed;               // Samplerate
-       uint8le  volume;                // Default volume (0...64)
-       uint8le  panning;               // Default pan (0...255)
+       uint32le length;        // Length (in bytes)
+       uint32le loopStart;     // Loop start (in bytes)
+       uint32le loopEnd;       // Loop end (in bytes)
+       uint32le c5Speed;       // Samplerate
+       uint8le  volume;        // Default volume (0...64)
+       uint8le  panning;       // Default pan (0...255)
        uint8le  unused2[14];
-       uint8le  flags;                 // Sample flags
+       uint8le  flags;  // Sample flags
        uint8le  unused3[5];
-       uint16le ems;                   // Reserved for internal usage
-       uint32le dram;                  // Reserved for internal usage
-       char     is10[4];               // 'IS10'
+       uint16le ems;      // Reserved for internal usage
+       uint32le dram;     // Reserved for internal usage
+       char     is10[4];  // 'IS10'
 
        // Convert an IMFSample to OpenMPT's internal sample representation.
        void ConvertToMPT(ModSample &mptSmp) const
@@ -255,7 +256,7 @@
 {
        uint8 n;
        // fix some of them
-       switch (m.command)
+       switch(m.command)
        {
        case 0xE: // fine volslide
                // hackaround to get almost-right behavior for fine slides (i 
think!)
@@ -278,7 +279,7 @@
        case 0x15: // fine slide down
                // this is about as close as we can do...
                if(m.param >> 4)
-                       m.param = 0xF0 | std::min(static_cast<uint8>(m.param >> 
4), uint8(0x0F));
+                       m.param = 0xF0 | (m.param >> 4);
                else
                        m.param |= 0xE0;
                break;
@@ -353,8 +354,12 @@
 static bool ValidateHeader(const IMFFileHeader &fileHeader)
 {
        if(std::memcmp(fileHeader.im10, "IM10", 4)
-               || fileHeader.ordNum > 256
-               || fileHeader.insNum >= MAX_INSTRUMENTS)
+          || fileHeader.ordNum > 256
+          || fileHeader.insNum >= MAX_INSTRUMENTS
+          || fileHeader.bpm < 32
+          || fileHeader.master > 64
+          || fileHeader.amp < 4
+          || fileHeader.amp > 127)
        {
                return false;
        }
@@ -480,8 +485,8 @@
        m_SongFlags.set(SONG_LINEARSLIDES, fileHeader.flags & 
IMFFileHeader::linearSlides);
        m_nDefaultSpeed = fileHeader.tempo;
        m_nDefaultTempo.Set(fileHeader.bpm);
-       m_nDefaultGlobalVolume = Clamp<uint8, uint8>(fileHeader.master, 0, 64) 
* 4;
-       m_nSamplePreAmp = Clamp<uint8, uint8>(fileHeader.amp, 4, 127);
+       m_nDefaultGlobalVolume = fileHeader.master * 4u;
+       m_nSamplePreAmp = fileHeader.amp;
 
        m_nInstruments = fileHeader.insNum;
        m_nSamples = 0; // Will be incremented later
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libopenmpt-0.5.12+release.autotools/soundlib/Load_med.cpp 
new/libopenmpt-0.5.13+release.autotools/soundlib/Load_med.cpp
--- old/libopenmpt-0.5.12+release.autotools/soundlib/Load_med.cpp       
2021-08-01 21:00:31.000000000 +0200
+++ new/libopenmpt-0.5.13+release.autotools/soundlib/Load_med.cpp       
2021-10-24 20:30:44.000000000 +0200
@@ -1011,10 +1011,8 @@
                        }
                        if(size > offsetof(MMDInstrExt, instrFlags))
                        {
-                               if(instrExt.instrFlags & 
MMDInstrExt::SSFLG_LOOP)
-                                       sample.uFlags.set(CHN_LOOP);
-                               if(instrExt.instrFlags & 
MMDInstrExt::SSFLG_PINGPONG)
-                                       sample.uFlags.set(CHN_LOOP | 
CHN_PINGPONGLOOP);
+                               sample.uFlags.set(CHN_LOOP, 
(instrExt.instrFlags & MMDInstrExt::SSFLG_LOOP) != 0);
+                               sample.uFlags.set(CHN_PINGPONGLOOP, 
(instrExt.instrFlags & MMDInstrExt::SSFLG_PINGPONG) != 0);
                                if(instrExt.instrFlags & 
MMDInstrExt::SSFLG_DISABLED)
                                        sample.nGlobalVol = 0;
                        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libopenmpt-0.5.12+release.autotools/soundlib/Load_mo3.cpp 
new/libopenmpt-0.5.13+release.autotools/soundlib/Load_mo3.cpp
--- old/libopenmpt-0.5.12+release.autotools/soundlib/Load_mo3.cpp       
2021-03-20 14:08:00.000000000 +0100
+++ new/libopenmpt-0.5.13+release.autotools/soundlib/Load_mo3.cpp       
2021-10-26 20:40:00.000000000 +0200
@@ -1456,7 +1456,7 @@
                        // Note: Every Ogg stream has a unique serial number.
                        // stb_vorbis (currently) ignores this serial number so 
we can just stitch
                        // together our sample without adjusting the shared 
header's serial number.
-                       const bool sharedHeader = sharedOggHeader != smp && 
sharedOggHeader > 0 && sharedOggHeader <= m_nSamples;
+                       const bool sharedHeader = sharedOggHeader != smp && 
sharedOggHeader > 0 && sharedOggHeader <= m_nSamples && sampleChunk.headerSize 
> 0;
 
 #if defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libopenmpt-0.5.12+release.autotools/soundlib/Load_mod.cpp 
new/libopenmpt-0.5.13+release.autotools/soundlib/Load_mod.cpp
--- old/libopenmpt-0.5.12+release.autotools/soundlib/Load_mod.cpp       
2021-06-12 22:45:46.000000000 +0200
+++ new/libopenmpt-0.5.13+release.autotools/soundlib/Load_mod.cpp       
2021-10-05 11:23:08.000000000 +0200
@@ -449,6 +449,8 @@
                        pitchEnv.dwFlags.set(ENV_ENABLED);
                        pitchEnv.reserve(2);
                        pitchEnv.push_back(0, ENVELOPE_MID);
+                       // cppcheck false-positive
+                       // cppcheck-suppress zerodiv
                        
pitchEnv.push_back(static_cast<EnvelopeNode::tick_t>(1024 / abs(pitchFall)), 
pitchFall > 0 ? ENVELOPE_MIN : ENVELOPE_MAX);
                }
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libopenmpt-0.5.12+release.autotools/soundlib/Load_mt2.cpp 
new/libopenmpt-0.5.13+release.autotools/soundlib/Load_mt2.cpp
--- old/libopenmpt-0.5.12+release.autotools/soundlib/Load_mt2.cpp       
2021-09-03 23:46:41.000000000 +0200
+++ new/libopenmpt-0.5.13+release.autotools/soundlib/Load_mt2.cpp       
2021-10-29 20:46:12.000000000 +0200
@@ -477,11 +477,13 @@
        ReadOrderFromArray(Order(), orders, fileHeader.numOrders);
        Order().SetRestartPos(fileHeader.restartPos);
 
-       FileReader drumData = file.ReadChunk(file.ReadUint16LE());
+       // This value is supposed to be the size of the drums data, but in old 
MT2.0 files it's 8 bytes too small.
+       // MadTracker itself unconditionally reads 274 bytes here if the value 
is != 0, so we do the same.
+       const bool hasDrumChannels = file.ReadUint16LE() != 0;
+       FileReader drumData = file.ReadChunk(hasDrumChannels ? 
sizeof(MT2DrumsData) : 0);
        FileReader extraData = file.ReadChunk(file.ReadUint32LE());
 
        const CHANNELINDEX channelsWithoutDrums = m_nChannels;
-       const bool hasDrumChannels = drumData.CanRead(sizeof(MT2DrumsData));
        static_assert(MAX_BASECHANNELS >= 64 + 8);
        if(hasDrumChannels)
        {
@@ -604,7 +606,10 @@
                        break;
 
                case MagicLE("TRKS"):
-                       m_nSamplePreAmp = chunk.ReadUint16LE() / 256u;  // 
131072 is 0dB... I think (that's how MTIOModule_MT2.cpp reads)
+                       m_nSamplePreAmp = chunk.ReadUint16LE() / 256u;  // 
131072 is 0dB... I think (that's how MTIOModule_MT2.cpp reads)
+                       // Dirty workaround for modules that use track 
automation for a fade-in at the song start (e.g. Rock.mt2)
+                       if(!m_nSamplePreAmp)
+                               m_nSamplePreAmp = 48;
                        m_nVSTiVolume = m_nSamplePreAmp / 2u;
                        for(CHANNELINDEX c = 0; c < GetNumChannels(); c++)
                        {
@@ -736,11 +741,11 @@
                                                
chunk.ReadRaw(mixPlug.pluginData.data() + 4, vstHeader.n);
                                        } else
                                        {
-                                               float32 *f = 
reinterpret_cast<float32 *>(mixPlug.pluginData.data());
-                                               *(f++) = 0;     // Plugin data 
type
-                                               for(uint32 param = 0; param < 
vstHeader.n; param++, f++)
+                                               auto memFile = 
std::make_pair(mpt::as_span(mixPlug.pluginData), mpt::IO::Offset(0));
+                                               
mpt::IO::WriteIntLE<uint32>(memFile, 0);  // Plugin data type
+                                               for(uint32 param = 0; param < 
vstHeader.n; param++)
                                                {
-                                                       *f = 
chunk.ReadFloatLE();
+                                                       mpt::IO::Write(memFile, 
IEEE754binary32LE{chunk.ReadFloatLE()});
                                                }
                                        }
                                } else
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libopenmpt-0.5.12+release.autotools/soundlib/Snd_fx.cpp 
new/libopenmpt-0.5.13+release.autotools/soundlib/Snd_fx.cpp
--- old/libopenmpt-0.5.12+release.autotools/soundlib/Snd_fx.cpp 2021-10-03 
13:56:57.000000000 +0200
+++ new/libopenmpt-0.5.13+release.autotools/soundlib/Snd_fx.cpp 2021-11-14 
17:12:57.000000000 +0100
@@ -1048,7 +1048,7 @@
                                                startTick = 
playState.m_nMusicSpeed - 1;
                                        } else if(m.volcmd == VOLCMD_OFFSET)
                                        {
-                                               if(m.vol <= 
CountOf(chn.pModSample->cues) && chn.pModSample != nullptr)
+                                               if(chn.pModSample != nullptr && 
m.vol <= CountOf(chn.pModSample->cues))
                                                {
                                                        SmpLength offset;
                                                        if(m.vol == 0)
@@ -1965,7 +1965,7 @@
                        // ProTracker "oneshot" loops (if loop start is 0, play 
the whole sample once and then repeat until loop end)
                        if(m_playBehaviour[kMODOneShotLoops] && chn.nLoopStart 
== 0) chn.nLoopEnd = chn.nLength = pSmp->nLength;
 
-                       if(chn.dwFlags[CHN_REVERSE])
+                       if(chn.dwFlags[CHN_REVERSE] && chn.nLength > 0)
                        {
                                chn.dwFlags.set(CHN_PINGPONGFLAG);
                                chn.position.SetInt(chn.nLength - 1);
@@ -3838,7 +3838,7 @@
        // Regular Slide
        if(!chn.isFirstTick
           || (m_PlayState.m_nMusicSpeed == 1 && 
m_playBehaviour[kSlidesAtSpeed1])
-          || GetType() == MOD_TYPE_669
+          || (GetType() & (MOD_TYPE_669 | MOD_TYPE_OKT))
           || (GetType() == MOD_TYPE_MED && m_SongFlags[SONG_FASTVOLSLIDES]))
        {
                DoFreqSlide(chn, -int(param) * 4);
@@ -3906,7 +3906,7 @@
 
        if(!chn.isFirstTick
           || (m_PlayState.m_nMusicSpeed == 1 && 
m_playBehaviour[kSlidesAtSpeed1])
-          || GetType() == MOD_TYPE_669
+          || (GetType() & (MOD_TYPE_669 | MOD_TYPE_OKT))
           || (GetType() == MOD_TYPE_MED && m_SongFlags[SONG_FASTVOLSLIDES]))
        {
                DoFreqSlide(chn, int(param) * 4);
@@ -4963,19 +4963,20 @@
 
 // Process a MIDI Macro.
 // Parameters:
-// [in] nChn: Mod channel to apply macro on
-// [in] isSmooth: If true, internal macros are interpolated between two rows
-// [in] macro: Actual MIDI Macro string
-// [in] param: Parameter for parametric macros (Z00 - Z7F)
-// [in] plugin: Plugin to send MIDI message to (if not specified but needed, 
it is autodetected)
+// nChn: Mod channel to apply macro on
+// isSmooth: If true, internal macros are interpolated between two rows
+// macro: Actual MIDI Macro string
+// param: Parameter for parametric macros (Z00 - Z7F)
+// plugin: Plugin to send MIDI message to (if not specified but needed, it is 
autodetected)
 void CSoundFile::ProcessMIDIMacro(CHANNELINDEX nChn, bool isSmooth, const char 
*macro, uint8 param, PLUGINDEX plugin)
 {
        ModChannel &chn = m_PlayState.Chn[nChn];
        const ModInstrument *pIns = GetNumInstruments() ? chn.pModInstrument : 
nullptr;
 
        uint8 out[MACRO_LENGTH];
-       uint32 outPos = 0;      // output buffer position, which also equals 
the number of complete bytes
-       const uint8 lastZxxParam = chn.lastZxxParam;
+       uint32 outPos = 0;  // output buffer position, which also equals the 
number of complete bytes
+       const uint8 lastZxxParam = chn.lastZxxParam;  // always interpolate 
based on original value in case z appears multiple times in macro string
+       uint8 updateZxxParam = 0xFF;                  // avoid updating 
lastZxxParam immediately if macro contains both internal and external MIDI 
message
        bool firstNibble = true;
 
        for(uint32 pos = 0; pos < (MACRO_LENGTH - 1) && macro[pos]; pos++)
@@ -5088,8 +5089,12 @@
                                // Interpolation for external MIDI messages - 
interpolation for internal messages
                                // is handled separately to allow for more than 
7-bit granularity where it's possible
                                data = 
static_cast<uint8>(CalculateSmoothParamChange(lastZxxParam, data));
+                               chn.lastZxxParam = data;
+                               updateZxxParam = 0x80;
+                       } else if(updateZxxParam == 0xFF)
+                       {
+                               updateZxxParam = data;
                        }
-                       chn.lastZxxParam = data;
                } else if(macro[pos] == 's')
                {
                        // SysEx Checksum (not an original Impulse Tracker 
macro variable, but added for convenience)
@@ -5137,6 +5142,8 @@
                // Finish current byte
                outPos++;
        }
+       if(updateZxxParam < 0x80)
+               chn.lastZxxParam = updateZxxParam;
 
        // Macro string has been parsed and translated, now send the 
message(s)...
        uint32 sendPos = 0;
@@ -5384,11 +5391,9 @@
 #endif // NO_PLUGINS
 
                return macroLen;
-
        }
 
        return 0;
-
 }
 
 
@@ -5504,7 +5509,7 @@
 // 
 void CSoundFile::ReverseSampleOffset(ModChannel &chn, ModCommand::PARAM param) 
const
 {
-       if(chn.pModSample != nullptr)
+       if(chn.pModSample != nullptr && chn.nLength > 0)
        {
                chn.dwFlags.set(CHN_PINGPONGFLAG);
                chn.dwFlags.reset(CHN_LOOP);

Reply via email to