Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package schismtracker for openSUSE:Factory 
checked in at 2021-06-26 21:25:35
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/schismtracker (Old)
 and      /work/SRC/openSUSE:Factory/.schismtracker.new.2625 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "schismtracker"

Sat Jun 26 21:25:35 2021 rev:15 rq:902485 version:20210525

Changes:
--------
--- /work/SRC/openSUSE:Factory/schismtracker/schismtracker.changes      
2020-07-05 01:17:36.516886932 +0200
+++ /work/SRC/openSUSE:Factory/.schismtracker.new.2625/schismtracker.changes    
2021-06-26 21:26:04.983392426 +0200
@@ -1,0 +2,12 @@
+Sat Jun 26 09:43:41 UTC 2021 - Jan Engelhardt <jeng...@inai.de>
+
+- Update to release 20210525
+  * Add support for saving MOD files
+  * Fix conflict in MIDI setup when ALSA and OSS are both available
+  * Fix instrument and sample panning overwriting channel panning
+  * Fix issues related to portamento with Amiga slides
+  * Support compressed stereo samples in ITI/ITS files
+  * Convert XM/MOD EA0/EB0 to D00 when loading
+  * Fix memory access bug in the MTM loader
+
+-------------------------------------------------------------------

Old:
----
  20200412.tar.gz

New:
----
  20210525.tar.gz

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

Other differences:
------------------
++++++ schismtracker.spec ++++++
--- /var/tmp/diff_new_pack.pvmoDB/_old  2021-06-26 21:26:05.447393038 +0200
+++ /var/tmp/diff_new_pack.pvmoDB/_new  2021-06-26 21:26:05.451393044 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package schismtracker
 #
-# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2021 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,7 +17,7 @@
 
 
 Name:           schismtracker
-Version:        20200412
+Version:        20210525
 Release:        0
 Summary:        Music editor that matches the look and feel of Impulse Tracker
 License:        GPL-2.0-or-later
@@ -25,7 +25,7 @@
 URL:            http://schismtracker.org/
 
 #Git-Clone:     https://github.com/schismtracker/schismtracker
-Source:         
https://github.com/schismtracker/schismtracker/archive/%version.tar.gz
+Source:         
https://github.com/schismtracker/schismtracker/archive/refs/tags/%version.tar.gz
 Source2:        %name.desktop
 Patch1:         schism-alsa.diff
 Patch2:         schism-nodate.diff
@@ -37,7 +37,7 @@
 BuildRequires:  freeglut-devel
 BuildRequires:  gcc-c++
 BuildRequires:  libtool
-BuildRequires:  python >= 2.4
+BuildRequires:  python3-base
 BuildRequires:  update-desktop-files
 BuildRequires:  pkgconfig(x11)
 BuildRequires:  pkgconfig(xv)
@@ -51,13 +51,12 @@
 bugfixes and changes to improve IT playback.
 
 %prep
-%setup -q
-%patch -P 1 -P 2 -P 3 -p1
+%autosetup -p1
 
 %build
 autoreconf -fi
 %configure
-make %{?_smp_mflags}
+%make_build
 
 %install
 b="%buildroot"
@@ -72,7 +71,6 @@
 %suse_update_desktop_file -i %name
 
 %files
-%defattr(-,root,root)
 %license COPYING
 %doc NEWS README.md
 %_bindir/schismtracker

++++++ 20200412.tar.gz -> 20210525.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/.gitignore 
new/schismtracker-20210525/.gitignore
--- old/schismtracker-20200412/.gitignore       2020-05-12 16:45:03.000000000 
+0200
+++ new/schismtracker-20210525/.gitignore       2021-05-25 01:32:00.000000000 
+0200
@@ -1,15 +1,26 @@
 *.swp
-Makefile.in
-aclocal.m4
-autom4te.cache/
-build/
-buildx86/
-buildx64/
-compile
-config.guess
-config.h.in
-config.sub
-configure
-depcomp
-install-sh
-missing
+*.o
+.deps/
+.dirstamp
+.vs/
+/Makefile
+/Makefile.in
+/aclocal.m4
+/auto/
+/autom4te.cache/
+/build/
+/buildx86/
+/buildx64/
+/compile
+/config.guess
+/config.h
+/config.h.in
+/config.log
+/config.status
+/config.sub
+/configure
+/depcomp
+/install-sh
+/missing
+/schismtracker
+/stamp-h1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/README.md 
new/schismtracker-20210525/README.md
--- old/schismtracker-20200412/README.md        2020-05-12 16:45:03.000000000 
+0200
+++ new/schismtracker-20210525/README.md        2021-05-25 01:32:00.000000000 
+0200
@@ -38,3 +38,7 @@
 See the
 [docs/](https://github.com/schismtracker/schismtracker/tree/master/docs) folder
 for platform-specific instructions.
+
+## Packaging status
+
+[![Packaging 
status](https://repology.org/badge/vertical-allrepos/schismtracker.svg)](https://repology.org/project/schismtracker/versions)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/fmt/aiff.c 
new/schismtracker-20210525/fmt/aiff.c
--- old/schismtracker-20200412/fmt/aiff.c       2020-05-12 16:45:03.000000000 
+0200
+++ new/schismtracker-20210525/fmt/aiff.c       2021-05-25 01:32:00.000000000 
+0200
@@ -394,7 +394,7 @@
        bps = aiff_header(fp, (smp->flags & CHN_16BIT) ? 16 : 8, (smp->flags & 
CHN_STEREO) ? 2 : 1,
                smp->c5speed, smp->name, smp->length, NULL);
 
-       if (csf_write_sample(fp, smp, flags) != smp->length * bps) {
+       if (csf_write_sample(fp, smp, flags, UINT32_MAX) != smp->length * bps) {
                log_appendf(4, "AIFF: unexpected data size written");
                return SAVE_INTERNAL_ERROR;
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/fmt/au.c 
new/schismtracker-20210525/fmt/au.c
--- old/schismtracker-20200412/fmt/au.c 2020-05-12 16:45:03.000000000 +0200
+++ new/schismtracker-20210525/fmt/au.c 2021-05-25 01:32:00.000000000 +0200
@@ -174,7 +174,8 @@
        disko_write(fp, smp->name, 25);
        csf_write_sample(fp, smp, SF_BE | SF_PCMS
                        | ((smp->flags & CHN_16BIT) ? SF_16 : SF_8)
-                       | ((smp->flags & CHN_STEREO) ? SF_SI : SF_M));
+                       | ((smp->flags & CHN_STEREO) ? SF_SI : SF_M),
+                       UINT32_MAX);
 
        return SAVE_SUCCESS;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/fmt/imf.c 
new/schismtracker-20210525/fmt/imf.c
--- old/schismtracker-20200412/fmt/imf.c        2020-05-12 16:45:03.000000000 
+0200
+++ new/schismtracker-20210525/fmt/imf.c        2021-05-25 01:32:00.000000000 
+0200
@@ -490,9 +490,9 @@
                ins->name[25] = 0;
 
                if (imfins.smpnum) {
-                       for (s = 0; s < 120; s++) {
+                       for (s = 12; s < 120; s++) {
                                ins->note_map[s] = s + 1;
-                               ins->sample_map[s] = firstsample + 
imfins.map[s];
+                               ins->sample_map[s] = firstsample + imfins.map[s 
- 12];
                        }
                }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/fmt/it.c 
new/schismtracker-20210525/fmt/it.c
--- old/schismtracker-20200412/fmt/it.c 2020-05-12 16:45:03.000000000 +0200
+++ new/schismtracker-20210525/fmt/it.c 2021-05-25 01:32:00.000000000 +0200
@@ -690,7 +690,12 @@
                // :)
                tid = "OpenSPC conversion";
        } else if ((hdr.cwtv >> 12) == 5) {
-               tid = (hdr.reserved == 0x54504d4f) ? "OpenMPT %d.%02x" : 
"OpenMPT %d.%02x (compat.)";
+               if (hdr.reserved == 0x54504d4f)
+                       tid = "OpenMPT %d.%02x";
+               else if (hdr.cwtv < 0x5129 || !(hdr.reserved & 0xffff))
+                       tid = "OpenMPT %d.%02x (compat.)";
+               else
+                       sprintf(song->tracker_id, "OpenMPT %d.%02x.%02x.%02x 
(compat.)", (hdr.cwtv & 0xf00) >> 8, hdr.cwtv & 0xff, (hdr.reserved >> 8) & 
0xff, (hdr.reserved & 0xff));
        } else if (hdr.cwtv == 0x0888 && hdr.cmwt == 0x0888 && hdr.reserved == 
0/* && hdr.ordnum == 256*/) {
                // erh.
                // There's a way to identify the exact version apparently, but 
it seems too much trouble
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/fmt/its.c 
new/schismtracker-20210525/fmt/its.c
--- old/schismtracker-20200412/fmt/its.c        2020-05-12 16:45:03.000000000 
+0200
+++ new/schismtracker-20210525/fmt/its.c        2021-05-25 01:32:00.000000000 
+0200
@@ -95,15 +95,12 @@
 
        // endianness (always little)
        format = SF_LE;
+       // channels
+       format |= (its->flags & 4) ? SF_SS : SF_M;
        if (its->flags & 8) {
-               // no such thing as compressed stereo
-               // (TODO perhaps test with various players to see how this is 
implemented)
-               format |= SF_M;
                // compression algorithm
                format |= (its->cvt & 4) ? SF_IT215 : SF_IT214;
        } else {
-               // channels
-               format |= (its->flags & 4) ? SF_SS : SF_M;
                // signedness (or delta?)
                format |= (its->cvt & 4) ? SF_PCMD : (its->cvt & 1) ? SF_PCMS : 
SF_PCMU;
        }
@@ -224,7 +221,8 @@
        save_its_header(fp, smp);
        csf_write_sample(fp, smp, SF_LE | SF_PCMS
                        | ((smp->flags & CHN_16BIT) ? SF_16 : SF_8)
-                       | ((smp->flags & CHN_STEREO) ? SF_SS : SF_M));
+                       | ((smp->flags & CHN_STEREO) ? SF_SS : SF_M),
+                       UINT32_MAX);
 
        /* Write the sample pointer. In an ITS file, the sample data is right 
after the header,
        so its position in the file will be the same as the size of the header. 
*/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/fmt/mod.c 
new/schismtracker-20210525/fmt/mod.c
--- old/schismtracker-20200412/fmt/mod.c        2020-05-12 16:45:03.000000000 
+0200
+++ new/schismtracker-20210525/fmt/mod.c        2021-05-25 01:32:00.000000000 
+0200
@@ -28,6 +28,13 @@
 
 #include "sndfile.h"
 
+#include "version.h"
+#include "disko.h"
+#include "log.h"
+
+
+
+
 /* --------------------------------------------------------------------- */
 
 /* TODO: WOW files */
@@ -75,6 +82,66 @@
        {NULL, NULL}
 };
 
+enum {
+       WARN_LINEARSLIDES,
+       WARN_SAMPLEVOL,
+       WARN_LOOPS,
+       WARN_SAMPLEVIB,
+       WARN_INSTRUMENTS,
+       WARN_PATTERNLEN,
+       WARN_MAXCHANNELS,
+       WARN_NOTERANGE,
+       WARN_VOLEFFECTS,
+       WARN_MAXSAMPLES,
+       WARN_LONGSAMPLES,
+       WARN_UNUSEDPATS,
+
+       MAX_WARN
+};
+
+static const char *mod_warnings[] = {
+       [WARN_LINEARSLIDES] = "Linear slides",
+       [WARN_SAMPLEVOL]    = "Sample volumes",
+       [WARN_LOOPS]        = "Sustain and Ping Pong loops",
+       [WARN_SAMPLEVIB]    = "Sample vibrato",
+       [WARN_INSTRUMENTS]  = "Instrument functions",
+       [WARN_PATTERNLEN]   = "Pattern lengths other than 64 rows",
+       [WARN_MAXCHANNELS]  = "Data outside 4 channels",
+       [WARN_NOTERANGE]    = "Notes outside the range C-4 to B-6",
+       [WARN_VOLEFFECTS]   = "Extended volume column effects",
+       [WARN_MAXSAMPLES]   = "Over 31 samples",
+       [WARN_LONGSAMPLES]  = "Odd sample length or greater than 131070",
+       [WARN_UNUSEDPATS]   = "Patterns outside order list",
+
+       [MAX_WARN]          = NULL
+};
+
+const uint16_t amigaperiod_table[256] = {
+       0,
+       0,    0,    0,    0,    0,    0,    0,    0,    0,   0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,    0,   0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,    0,   0,    0,    0,
+       1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960, 906,
+       856,  808,  762,  720,  678,  640,  604,  570,  538,  508,  480, 453,
+       428,  404,  381,  360,  339,  320,  302,  285,  269,  254,  240, 226,
+       214,  202,  190,  180,  170,  160,  151,  143,  135,  127,  120, 113,
+       107,  101,  95,   90,   85,   80,   75,   71,   67,   63,   60,  56,
+       0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   0,
+       0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   0,
+       0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   0,
+       0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   0,
+       0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   0,
+       0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   0,
+       0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   0,
+       0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   0,
+       0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   0,
+       0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   0,
+       0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   0,
+       0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   0,
+       0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   0,
+       0,    0,    0
+};
+
 int fmt_mod_read_info(dmoz_file_t *file, const uint8_t *data, size_t length)
 {
        char tag[4];
@@ -105,23 +172,9 @@
 
 /* 
---------------------------------------------------------------------------------------------------------
 */
 
-/* loads everything but old 15-instrument mods... yes, even FLT8 and WOW files
-   (and the definition of "everything" is always changing) */
-int fmt_mod31_load_song(song_t *song, slurp_t *fp, unsigned int lflags)
-{
-       return fmt_mod_load_song(song, fp, lflags, 0);
-}
-
-/* loads everything including old 15-instrument mods. this is a separate
-   function so that it can be called later in the format-checking sequence. */
-int fmt_mod15_load_song(song_t *song, slurp_t *fp, unsigned int lflags)
-{
-       return fmt_mod_load_song(song, fp, lflags, 1);
-}
-
 /* force determines whether the loader will force-read untagged files as
    15-sample mods */
-int fmt_mod_load_song(song_t *song, slurp_t *fp, unsigned int lflags, int 
force)
+static int fmt_mod_load_song(song_t *song, slurp_t *fp, unsigned int lflags, 
int force)
 {
        uint8_t tag[4];
        int n, npat, pat, chan, nchan, nord;
@@ -397,3 +450,232 @@
        return LOAD_SUCCESS;
 }
 
+/* loads everything but old 15-instrument mods... yes, even FLT8 and WOW files
+   (and the definition of "everything" is always changing) */
+int fmt_mod31_load_song(song_t *song, slurp_t *fp, unsigned int lflags)
+{
+       return fmt_mod_load_song(song, fp, lflags, 0);
+}
+
+/* loads everything including old 15-instrument mods. this is a separate
+   function so that it can be called later in the format-checking sequence. */
+int fmt_mod15_load_song(song_t *song, slurp_t *fp, unsigned int lflags)
+{
+       return fmt_mod_load_song(song, fp, lflags, 1);
+}
+
+/* incomplete 31 sample M.K. amiga mod saving routine */
+int fmt_mod_save_song(disko_t *fp, song_t *song)
+{
+       uint8_t mod_songtitle[20];
+       uint8_t mod_sampleheader[30];
+       uint8_t mod_orders[128];
+       uint8_t tmp[128];
+       uint8_t mod_pattern[1024];
+
+       int nord, nsmp, maxpat, jmax, joutpos;
+       long tmppos;
+       int i, j, n, period;
+       unsigned int warn = 0;
+       song_note_t *m;
+
+       if (song->flags & SONG_INSTRUMENTMODE)
+               warn |= 1 << WARN_INSTRUMENTS;
+       if (song->flags & SONG_LINEARSLIDES)
+               warn |= 1 << WARN_LINEARSLIDES;
+
+       nsmp = csf_get_num_samples(song); // Getting number of samples
+       if (nsmp > 31) {
+               nsmp = 31;
+               warn |= 1 << WARN_MAXSAMPLES;
+       }
+
+       if (3 < csf_get_highest_used_channel(song))
+               warn |= 1 << WARN_MAXCHANNELS;
+
+       memcpy(mod_songtitle, song->title, 20);
+       disko_write(fp, mod_songtitle, 20); // writing song title
+
+       // Now writing sample headers
+       for(n = 1; n <= 31; ++n) {
+               for(i = 0; i < 30; ++i) mod_sampleheader[i] = 0;
+               if(n <= nsmp) {
+                       if(song->samples[n].global_volume != 64)
+                               warn |= 1 << WARN_SAMPLEVOL;
+                       if((song->samples[n].flags & (CHN_LOOP | 
CHN_PINGPONGLOOP)) == (CHN_LOOP | CHN_PINGPONGLOOP) || (song->samples[n].flags 
& CHN_SUSTAINLOOP))
+                               warn |= 1 << WARN_LOOPS;
+                       if(song->samples[n].vib_depth != 0)
+                               warn |= 1 << WARN_SAMPLEVIB;
+                       memcpy(mod_sampleheader, song->samples[n].name, 22); // 
sample name
+                       if(song->samples[n].length <= 0x1FFFE) {
+                               mod_sampleheader[22] = song->samples[n].length 
>> 9; // sample 11th word MSB length/2
+                               mod_sampleheader[23] = song->samples[n].length 
>> 1; // sample 11th word LSB length/2
+                               if(1 & song->samples[n].length)
+                                       warn |= 1 << WARN_LONGSAMPLES;
+                       } else {
+                               mod_sampleheader[22] = 0xFF;
+                               mod_sampleheader[23] = 0xFF;
+                               warn |= 1 << WARN_LONGSAMPLES;
+                       }
+                       for(j = 15; j && (finetune_table[j] > 
song->samples[n].c5speed); --j)
+                               if(((song->samples[n].c5speed) > 10000) && (j 
== 8))
+                                       break; // determine from finetune_table 
entry
+                       mod_sampleheader[24] = (j ^ 8) & 0x0f; // sample 24th 
byte finetune value
+                       mod_sampleheader[25] = (song->samples[n].volume + 1) / 
4; // sample 25th byte sample volume value 0..64 scaled
+                       if( (song->samples[n].flags & CHN_LOOP) && 
(song->samples[n].loop_start < song->samples[n].loop_end) && 
(song->samples[n].loop_end <= MIN(song->samples[n].length, 0x1FFFE)) ) {
+                               mod_sampleheader[26] = 
song->samples[n].loop_start >> 9;// loop start MSB /2
+                               mod_sampleheader[27] = 
song->samples[n].loop_start >> 1;// loop start LSB /2
+                               mod_sampleheader[28] = 
(song->samples[n].loop_end - song->samples[n].loop_start) >> 9;// loop length 
MSB /2
+                               mod_sampleheader[29] = 
(song->samples[n].loop_end - song->samples[n].loop_start) >> 1;// loop length 
LSB /2
+                       } else {
+                               mod_sampleheader[26] = 0;
+                               mod_sampleheader[27] = 0;
+                               mod_sampleheader[28] = 0;
+                               mod_sampleheader[29] = 1;
+                       }
+               }
+               disko_write(fp, mod_sampleheader, 30); // writing current 
sample header
+       }
+
+       tmp[0] = nord = csf_get_num_orders(song); // or 
"csf_get_num_orders(song_t *csf);"
+       tmp[1] = 0x7f;
+       disko_write(fp, tmp, 2);
+
+       for(maxpat = i = 0; (i < nord) && (i < 128); ++i) {
+               mod_orders[i] = song->orderlist[i];
+               if(maxpat < mod_orders[i]) maxpat = mod_orders[i];
+       }
+       if (maxpat + 1 < csf_get_num_patterns(song))
+               warn |= 1 << WARN_UNUSEDPATS;
+       for(; i < 128; ++i)
+               mod_orders[i] = 0;
+
+       disko_write(fp, mod_orders, 128);
+
+       if(maxpat < 64)
+               disko_write(fp, valid_tags[0][0], 4);
+       else
+               disko_write(fp, valid_tags[1][0], 4);
+
+       for(n = 0; n <= maxpat; ++n) {
+               m = song->patterns[n];
+               for(i = 0; i < 1024; ++i)
+                       mod_pattern[i] = 0;
+               jmax = song->pattern_size[n];
+               if(jmax != 64) {
+                       if(jmax > 64)
+                               jmax = 64;
+                       warn |= 1 << WARN_PATTERNLEN;
+               }
+               jmax *= MAX_CHANNELS;
+               for (j = joutpos = 0; j < jmax; ++j, ++m) {
+                       uint8_t mod_fx, mod_fx_val;
+                       if ((j % MAX_CHANNELS) < 4) {
+                               //if (m->note || m->instrument || m->voleffect 
|| m->volparam || m->effect || m->param) {...
+                               period = amigaperiod_table[(m->note) & 0xff];
+                               if (((m->note) & 0xff) && ((period < 113) || 
(period > 856)))
+                                       warn |= 1 << WARN_NOTERANGE;
+                               mod_pattern[joutpos] = ((m->instrument) & 0x10) 
| (period >> 8);
+                               mod_pattern[joutpos + 1] = period & 0xff;
+                               mod_pattern[joutpos + 2] = (m->instrument & 
0xf) << 4;
+                               mod_fx = 0; mod_fx_val = m->param;
+                               if(m->voleffect == VOLFX_VOLUME) {
+                                       mod_fx = 0x0c;
+                                       mod_fx_val = m->volparam;
+                               } else if (m->voleffect == VOLFX_NONE) {
+                                       switch(m->effect) {
+                                               case FX_NONE: mod_fx_val = 0; 
break;
+                                               case FX_ARPEGGIO: mod_fx = 0; 
break;
+                                               case FX_PORTAMENTOUP:
+                                                       mod_fx = 1;
+                                                       if ((mod_fx_val & 0xf0) 
== 0xe0) {
+                                                               mod_fx = 0x0e;
+                                                               mod_fx_val = 
0x10 | ((mod_fx_val & 0xf) >> 2);
+                                                       } else if ((mod_fx_val 
& 0xf0) == 0xf0) {
+                                                               mod_fx = 0x0e;
+                                                               mod_fx_val = 
0x10 | (mod_fx_val & 0xf);
+                                                       }
+                                                       break;
+                                               case FX_PORTAMENTODOWN:
+                                                       mod_fx = 2;
+                                                       if ((mod_fx_val & 0xf0) 
== 0xe0) {
+                                                               mod_fx = 0x0e;
+                                                               mod_fx_val = 
0x20 | ((mod_fx_val & 0xf) >> 2);
+                                                       } else if ((mod_fx_val 
& 0xf0) == 0xf0) {
+                                                               mod_fx = 0x0e;
+                                                               mod_fx_val = 
0x20 | (mod_fx_val & 0xf);
+                                                       }
+                                                       break;
+                                               case FX_TONEPORTAMENTO: mod_fx 
= 3; break;
+                                               case FX_VIBRATO: mod_fx = 4; 
break;
+                                               case FX_TONEPORTAVOL: mod_fx = 
5; break;
+                                               case FX_VIBRATOVOL: mod_fx = 6; 
break;
+                                               case FX_TREMOLO: mod_fx = 7; 
break;
+                                               case FX_PANNING: mod_fx = 8; 
break;
+                                               case FX_OFFSET: mod_fx = 9; 
break;
+                                               case FX_VOLUMESLIDE:
+                                                       mod_fx = 0x0a;
+                                                       if( (mod_fx_val & 0xf0) 
&& (mod_fx_val & 0x0f) )
+                                                               if ((mod_fx_val 
& 0xf0) == 0xf0) { // fine volslide down!
+                                                                       mod_fx 
= 0x0e;
+                                                                       
mod_fx_val &= 0xbf;
+                                                               } else if 
((mod_fx_val & 0x0f) == 0x0f) { // fine volslide up!
+                                                                       mod_fx 
= 0x0e;
+                                                                       
mod_fx_val = 0xa0 | (mod_fx_val >> 4);
+                                                               }
+                                                       break;
+                                               case FX_POSITIONJUMP: mod_fx = 
0x0b; break;
+                                               case FX_VOLUME: mod_fx = 0x0c; 
break;
+                                               case FX_PATTERNBREAK: mod_fx = 
0x0d; mod_fx_val = ((mod_fx_val / 10) << 4) | (mod_fx_val % 10); break;
+                                               case FX_SPEED: mod_fx = 0x0f; 
break;
+                                               case FX_TEMPO: mod_fx = 0x0f; 
break;
+                                               case FX_SPECIAL:
+                                                       mod_fx = 0x0e;
+                                                       switch (mod_fx_val & 
0xf0) {
+                                                               case 0x10: 
mod_fx_val = (mod_fx_val & 0x0f) | 0x30; break;
+                                                               case 0x20: 
mod_fx_val = (mod_fx_val & 0x0f) | 0x50; break; // there is an error in 
Protracker 2.1 docs!
+                                                               case 0x30: 
mod_fx_val = (mod_fx_val & 0x0f) | 0x40; break;
+                                                               case 0x40: 
mod_fx_val = (mod_fx_val & 0x0f) | 0x70; break;
+                                                               case 0xb0: 
mod_fx_val = (mod_fx_val & 0x0f) | 0x60; break;
+                                                               default: break; 
// handling silently E0x,E6x,E8x,ECx,EDx,EEx,(?EFx)
+                                                       }
+                                                       break;
+                                               case FX_RETRIG: mod_fx = 0x0e; 
mod_fx_val = 0x90 | (mod_fx_val & 0x0f); break;
+                                               default:
+                                                       warn |= 1 << 
WARN_VOLEFFECTS;
+                                                       break;
+                                       }
+                               } else {
+                                       warn |= 1 << WARN_VOLEFFECTS;
+                               }
+                               mod_pattern[joutpos + 2] |= mod_fx & 0x0f;
+                               mod_pattern[joutpos + 3] = mod_fx_val;
+                               joutpos += 4;
+                       }
+               }
+               disko_write(fp, mod_pattern, 1024);
+       }
+
+       // Now writing sample data
+       for (tmp[0] = tmp[1] = n = 0; (n < nsmp) && (n < 31); ++n) {
+               song_sample_t *smp = song->samples + (n + 1);
+               if (smp->data)
+                       if( (smp->flags & CHN_LOOP) && (smp->loop_start < 
smp->loop_end) && (smp->loop_end <= MIN(smp->length, 0x1FFFE)) ) {
+                               csf_write_sample(fp, smp, RS_PCM8S, 0x1FFFE); 
// third argument is a compound flag: PCMS,8,M,LE
+                       } else if (1 < smp->length) { // floor(smp->length / 2) 
MUST be positive!
+                               tmppos = disko_tell(fp);
+                               csf_write_sample(fp, smp, RS_PCM8S, 0x1FFFE); 
// third argument is a compound flag: PCMS,8,M,LE
+                               disko_seek(fp, tmppos, SEEK_SET);
+                               disko_write(fp, tmp, 2);
+                               disko_seek(fp, 0, SEEK_END);
+                       }
+       }
+
+       /* announce all the things we broke - ripped from s3m.c */
+       for (n = 0; n < MAX_WARN; ++n) {
+               if (warn & (1 << n))
+                       log_appendf(4, " Warning: %s unsupported in MOD 
format", mod_warnings[n]);
+       }
+
+       return SAVE_SUCCESS;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/fmt/mtm.c 
new/schismtracker-20210525/fmt/mtm.c
--- old/schismtracker-20200412/fmt/mtm.c        2020-05-12 16:45:03.000000000 
+0200
+++ new/schismtracker-20210525/fmt/mtm.c        2021-05-25 01:32:00.000000000 
+0200
@@ -207,7 +207,6 @@
 
                song->patterns[pat] = csf_allocate_pattern(MAX(rows, 32));
                song->pattern_size[pat] = song->pattern_alloc_size[pat] = 64;
-               tracknote = trackdata[n];
                for (chan = 0; chan < 32; chan++) {
                        slurp_read(fp, &tmp, 2);
                        tmp = bswapLE16(tmp);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/fmt/raw.c 
new/schismtracker-20210525/fmt/raw.c
--- old/schismtracker-20200412/fmt/raw.c        2020-05-12 16:45:03.000000000 
+0200
+++ new/schismtracker-20210525/fmt/raw.c        2021-05-25 01:32:00.000000000 
+0200
@@ -48,7 +48,8 @@
 {
        csf_write_sample(fp, smp, SF_LE
                | ((smp->flags & CHN_16BIT) ? SF_16 | SF_PCMS : SF_8 | SF_PCMU)
-               | ((smp->flags & CHN_STEREO) ? SF_SI : SF_M));
+               | ((smp->flags & CHN_STEREO) ? SF_SI : SF_M),
+               UINT32_MAX);
        return SAVE_SUCCESS;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/fmt/s3m.c 
new/schismtracker-20210525/fmt/s3m.c
--- old/schismtracker-20200412/fmt/s3m.c        2020-05-12 16:45:03.000000000 
+0200
+++ new/schismtracker-20210525/fmt/s3m.c        2021-05-25 01:32:00.000000000 
+0200
@@ -420,7 +420,10 @@
                        ver_decode_cwtv(trkvers, reserved, song->tracker_id + 
strlen(song->tracker_id));
                        break;
                case 5:
-                       tid = "OpenMPT %d.%02x";
+                       if (trkvers >= 0x5129 && reserved)
+                               sprintf(song->tracker_id, "OpenMPT 
%d.%02x.%02x.%02x", (trkvers & 0xf00) >> 8, trkvers & 0xff, (reserved >> 8) & 
0xff, reserved & 0xff);
+                       else
+                               tid = "OpenMPT %d.%02x";
                        break;
                }
        }
@@ -898,7 +901,14 @@
        hdr.gv = song->initial_global_volume / 2;
        hdr.is = song->initial_speed;
        hdr.it = song->initial_tempo;
-       hdr.mv = song->mixing_volume;
+
+       /* .S3M "MasterVolume" only supports 0x10 .. 0x7f,
+        * if we save 0x80, the schism max volume, it becomes zero in S3M.
+        * I didn't test to see what ScreamTracker does if a value below 0x10
+        * is loaded into it, but its UI prevents setting below 0x10.
+        * Just enforce both bounds here.
+        */
+       hdr.mv = MIN(MAX(0x10, song->mixing_volume), 0x7f);
        if (!(song->flags & SONG_NOSTEREO))
                hdr.mv |= 128;
        hdr.uc = 16; // ultraclick (the "Waste GUS channels" option)
@@ -964,7 +974,8 @@
                para_sdata[n] = disko_tell(fp);
                csf_write_sample(fp, smp, SF_LE | SF_PCMU
                        | ((smp->flags & CHN_16BIT) ? SF_16 : SF_8)
-                       | ((smp->flags & CHN_STEREO) ? SF_SS : SF_M));
+                       | ((smp->flags & CHN_STEREO) ? SF_SS : SF_M),
+                       UINT32_MAX);
        }
 
        /* now that we're done adding stuff to the end of the file,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/fmt/wav.c 
new/schismtracker-20210525/fmt/wav.c
--- old/schismtracker-20200412/fmt/wav.c        2020-05-12 16:45:03.000000000 
+0200
+++ new/schismtracker-20210525/fmt/wav.c        2021-05-25 01:32:00.000000000 
+0200
@@ -306,7 +306,7 @@
        bps = wav_header(fp, (smp->flags & CHN_16BIT) ? 16 : 8, (smp->flags & 
CHN_STEREO) ? 2 : 1,
                smp->c5speed, smp->length, NULL);
 
-       if (csf_write_sample(fp, smp, flags) != smp->length * bps) {
+       if (csf_write_sample(fp, smp, flags, UINT32_MAX) != smp->length * bps) {
                log_appendf(4, "WAV: unexpected data size written");
                return SAVE_INTERNAL_ERROR;
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/include/fmt-types.h 
new/schismtracker-20210525/include/fmt-types.h
--- old/schismtracker-20200412/include/fmt-types.h      2020-05-12 
16:45:03.000000000 +0200
+++ new/schismtracker-20210525/include/fmt-types.h      2021-05-25 
01:32:00.000000000 +0200
@@ -79,7 +79,7 @@
 
 This only handles 31-sample mods; 15-sample ones have no identifying
 information and are therefore placed much lower in this list. */
-READ_INFO(mod) LOAD_SONG(mod31)
+READ_INFO(mod) LOAD_SONG(mod31) SAVE_SONG(mod)
 
 /* S3M needs to be before a lot of stuff. */
 READ_INFO(s3m) LOAD_SONG(s3m) SAVE_SONG(s3m)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/include/sndfile.h 
new/schismtracker-20210525/include/sndfile.h
--- old/schismtracker-20200412/include/sndfile.h        2020-05-12 
16:45:03.000000000 +0200
+++ new/schismtracker-20210525/include/sndfile.h        2021-05-25 
01:32:00.000000000 +0200
@@ -430,7 +430,7 @@
        int32_t final_panning; // range 0-256 (but can temporarily exceed that 
range during calculations)
        int32_t volume, panning; // range 0-256 (?); these are the current 
values set for the channel
        int32_t fadeout_volume;
-       int32_t period;
+       int32_t frequency;
        int32_t c5speed;
        int32_t sample_freq; // only used on the info page (F5)
        int32_t portamento_target;
@@ -450,6 +450,7 @@
        uint32_t autovib_position, vibrato_position, tremolo_position, 
panbrello_position;
        // 16-bit members
        int vol_swing, pan_swing;
+       uint16_t channel_panning;
 
        // formally 8-bit members
        unsigned int note; // the note that's playing
@@ -617,7 +618,7 @@
 void csf_free_instrument(song_instrument_t *p);
 
 uint32_t csf_read_sample(song_sample_t *sample, uint32_t flags, const void 
*filedata, uint32_t datalength);
-uint32_t csf_write_sample(disko_t *fp, song_sample_t *sample, uint32_t flags);
+uint32_t csf_write_sample(disko_t *fp, song_sample_t *sample, uint32_t flags, 
uint32_t maxlengthmask);
 void csf_adjust_sample_loop(song_sample_t *sample);
 
 extern void (*csf_midi_out_note)(int chan, const song_note_t *m);
@@ -669,6 +670,7 @@
 uint32_t csf_get_nna_channel(song_t *csf, uint32_t chan);
 void csf_check_nna(song_t *csf, uint32_t chan, uint32_t instr, int note, int 
force_cut);
 void csf_process_effects(song_t *csf, int firsttick);
+int32_t csf_fx_do_freq_slide(uint32_t flags, int32_t frequency, int32_t slide, 
int is_tone_portamento);
 
 void fx_note_cut(song_t *csf, uint32_t chan, int clear_note);
 void fx_key_off(song_t *csf, uint32_t chan);
@@ -678,9 +680,8 @@
 song_sample_t *csf_translate_keyboard(song_t *csf, song_instrument_t *ins, 
uint32_t note, song_sample_t *def);
 
 // various utility functions in snd_fx.c
-int get_note_from_period(int period);
-int get_period_from_note(int note, unsigned int c5speed, int linear);
-unsigned int get_freq_from_period(int period, int linear);
+int get_note_from_frequency(int frequency, unsigned int c5speed);
+int get_frequency_from_note(int note, unsigned int c5speed);
 unsigned int transpose_to_frequency(int transp, int ftune);
 int frequency_to_transpose(unsigned int freq);
 unsigned long calc_halftone(unsigned long hz, int rel);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/player/csndfile.c 
new/schismtracker-20210525/player/csndfile.c
--- old/schismtracker-20200412/player/csndfile.c        2020-05-12 
16:45:03.000000000 +0200
+++ new/schismtracker-20210525/player/csndfile.c        2021-05-25 
01:32:00.000000000 +0200
@@ -473,7 +473,7 @@
        for (uint32_t j = 0; j < MAX_VOICES; j++) {
                song_voice_t *v = csf->voices + j;
 
-               v->period = 0;
+               v->frequency = 0;
                v->note = v->new_note = v->new_instrument = 0;
                v->portamento_target = 0;
                v->n_command = 0;
@@ -538,9 +538,11 @@
 #define SF_FAIL(name, n) \
        ({ log_appendf(4, "%s: internal error: unsupported %s %d", 
__FUNCTION__, name, n); return 0; })
 
-uint32_t csf_write_sample(disko_t *fp, song_sample_t *sample, uint32_t flags)
+uint32_t csf_write_sample(disko_t *fp, song_sample_t *sample, uint32_t flags, 
uint32_t maxlengthmask)
 {
        uint32_t pos, len = sample->length;
+       if(maxlengthmask != UINT32_MAX)
+               len = len > maxlengthmask ? maxlengthmask : (len & 
maxlengthmask);
        int stride = 1;     // how much to add to the left/right pointer per 
sample written
        int byteswap = 0;   // should the sample data be byte-swapped?
        int add = 0;        // how much to add to the sample data (for 
converting to unsigned)
@@ -1207,7 +1209,7 @@
                        v->note = v->new_note = v->new_instrument = 0;
                        v->fadeout_volume = 0;
                        v->flags |= CHN_KEYOFF | CHN_NOTEFADE;
-                       v->period = 0;
+                       v->frequency = 0;
                        v->position = v->length = 0;
                        v->loop_start = 0;
                        v->loop_end = 0;
@@ -1283,19 +1285,19 @@
                        case 0x70: param = (param & 0x0F) | 0x40; break;
                        case 0x90: effect = FX_RETRIG; param &= 0x0F; break;
                        case 0xA0:
+                               effect = FX_VOLUMESLIDE;
                                if (param & 0x0F) {
-                                       effect = FX_VOLUMESLIDE;
                                        param = (param << 4) | 0x0F;
                                } else {
-                                       effect = param = 0;
+                                       param = 0;
                                }
                                break;
                        case 0xB0:
+                               effect = FX_VOLUMESLIDE;
                                if (param & 0x0F) {
-                                       effect = FX_VOLUMESLIDE;
                                        param |= 0xF0;
                                } else {
-                                       effect=param=0;
+                                       param = 0;
                                }
                                break;
                }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/player/effects.c 
new/schismtracker-20210525/player/effects.c
--- old/schismtracker-20200412/player/effects.c 2020-05-12 16:45:03.000000000 
+0200
+++ new/schismtracker-20210525/player/effects.c 2021-05-25 01:32:00.000000000 
+0200
@@ -37,33 +37,28 @@
 void (*csf_midi_out_raw)(const unsigned char *,unsigned int, unsigned int) = 
NULL;
 
 /* 
---------------------------------------------------------------------------------------------------------
 */
-/* note/freq/period conversion functions */
+/* note/freq conversion functions */
 
-int get_note_from_period(int period)
+int get_note_from_frequency(int frequency, unsigned int c5speed)
 {
        int n;
-       if (!period)
+       if (!frequency)
                return 0;
        for (n = 0; n <= 120; n++) {
-               /* Essentially, this is just doing a note_to_period(n, 8363), 
but with less
+               /* Essentially, this is just doing a note_to_frequency(n, 
8363), but with less
                computation since there's no c5speed to deal with. */
-               if (period >= (32 * period_table[n % 12] >> (n / 12)))
+               if (frequency <= get_frequency_from_note(n + 1, c5speed))
                        return n + 1;
        }
        return 120;
 }
 
-int get_period_from_note(int note, unsigned int c5speed, int linear)
+int get_frequency_from_note(int note, unsigned int c5speed)
 {
        if (!note || note > 0xF0)
                return 0;
        note--;
-       if (linear)
-               return _muldiv(c5speed, linear_slide_up_table[(note % 12) * 16] 
<< (note / 12), 65536 << 5);
-       else if (!c5speed)
-               return INT_MAX;
-       else
-               return _muldiv(8363, (period_table[note % 12] << 5), c5speed << 
(note / 12));
+       return _muldiv(c5speed, linear_slide_up_table[(note % 12) * 16] << 
(note / 12), 65536 << 5);
 }
 
 
@@ -99,7 +94,7 @@
        if (clear_note) {
                // keep instrument numbers from picking up old notes
                // (SCx doesn't do this)
-               chan->period = 0;
+               chan->frequency = 0;
        }
        if (chan->flags & CHN_ADLIB) {
                //Do this only if really an adlib chan. Important!
@@ -165,87 +160,99 @@
 }
 
 
-// negative value for slide = up, positive = down
-static void fx_do_freq_slide(uint32_t flags, song_voice_t *chan, int32_t slide)
+// negative value for slide = down, positive = up
+int32_t csf_fx_do_freq_slide(uint32_t flags, int32_t frequency, int32_t slide, 
int is_tone_portamento)
 {
        // IT Linear slides
-       if (!chan->period) return;
+       if (!frequency) return 0;
        if (flags & SONG_LINEARSLIDES) {
-               int32_t old_period = chan->period;
-               if (slide < 0) {
-                       uint32_t n = (-slide) >> 2;
-                       if (n > 255)
-                               n = 255;
-                       chan->period = _muldivr(chan->period, 
linear_slide_up_table[n], 65536);
-                       if (old_period == chan->period)
-                               chan->period++;
-               } else {
-                       uint32_t n = (slide) >> 2;
-                       if (n > 255)
-                               n = 255;
-                       chan->period = _muldivr(chan->period, 
linear_slide_down_table[n], 65536);
-                       if (old_period == chan->period)
-                               chan->period--;
+               int32_t old_frequency = frequency;
+               uint32_t n = abs(slide), delta = 0;
+               if (n > 255 * 4) n = 255 * 4;
+
+               if (slide > 0) {
+                       if (n < 16)
+                               frequency = _muldivr(frequency, 
fine_linear_slide_up_table[n], 65536);
+                       else
+                               frequency = _muldivr(frequency, 
linear_slide_up_table[n / 4], 65536);
+                       if (old_frequency == frequency)
+                               frequency++;
+               } else if (slide < 0) {
+                       if (n < 16)
+                               frequency = _muldivr(frequency, 
fine_linear_slide_down_table[n], 65536);
+                       else
+                               frequency = _muldivr(frequency, 
linear_slide_down_table[n / 4], 65536);
+                       if (old_frequency == frequency)
+                               frequency--;
                }
        } else {
-               chan->period += slide;
+               if (slide < 0) {
+                       frequency = (int32_t)((1712 * 8363 * 
(int64_t)frequency) / (((int64_t)(frequency) * -slide) + 1712 * 8363));
+               } else if (slide > 0) {
+                       int32_t frequency_div = 1712 * 8363 - 
((int64_t)(frequency) * slide);
+                       if (frequency_div <= 0) {
+                               if (is_tone_portamento)
+                                       frequency_div = 1;
+                               else
+                                       return 0;
+                       }
+                       int64_t freq = ((1712 * 8363 * (int64_t)frequency) / 
frequency_div);
+                       if (freq > INT32_MAX)
+                               frequency = INT32_MAX;
+                       else
+                               frequency = (int32_t)freq;
+               }
        }
+       return frequency;
+}
+
+static void set_instrument_panning(song_voice_t *chan, int32_t panning)
+{
+       chan->channel_panning = (int16_t)(chan->panning + 1);
+       if (chan->flags & CHN_SURROUND)
+               chan->channel_panning |= 0x8000;
+       chan->panning = panning;
+       chan->flags &= ~CHN_SURROUND;
 }
 
 static void fx_fine_portamento_up(uint32_t flags, song_voice_t *chan, uint32_t 
param)
 {
-       if ((flags & SONG_FIRSTTICK) && chan->period && param) {
-               if (flags & SONG_LINEARSLIDES) {
-                       chan->period = _muldivr(chan->period, 
linear_slide_up_table[param & 0x0F], 65536);
-               } else {
-                       chan->period -= (int)(param * 4);
-               }
+       if ((flags & SONG_FIRSTTICK) && chan->frequency && param) {
+               chan->frequency = csf_fx_do_freq_slide(flags, chan->frequency, 
param * 4, 0);
        }
 }
 
 static void fx_fine_portamento_down(uint32_t flags, song_voice_t *chan, 
uint32_t param)
 {
-       if ((flags & SONG_FIRSTTICK) && chan->period && param) {
-               if (flags & SONG_LINEARSLIDES) {
-                       chan->period = _muldivr(chan->period, 
linear_slide_down_table[param & 0x0F], 65536);
-               } else {
-                       chan->period += (int)(param * 4);
-               }
+       if ((flags & SONG_FIRSTTICK) && chan->frequency && param) {
+               chan->frequency = csf_fx_do_freq_slide(flags, chan->frequency, 
param * -4, 0);
        }
 }
 
 static void fx_extra_fine_portamento_up(uint32_t flags, song_voice_t *chan, 
uint32_t param)
 {
-       if ((flags & SONG_FIRSTTICK) && chan->period && param) {
-               if (flags & SONG_LINEARSLIDES) {
-                       chan->period = _muldivr(chan->period, 
fine_linear_slide_up_table[param & 0x0F], 65536);
-               } else {
-                       chan->period -= (int)(param);
-               }
+       if ((flags & SONG_FIRSTTICK) && chan->frequency && param) {
+               chan->frequency = csf_fx_do_freq_slide(flags, chan->frequency, 
param, 0);
        }
 }
 
 static void fx_extra_fine_portamento_down(uint32_t flags, song_voice_t *chan, 
uint32_t param)
 {
-       if ((flags & SONG_FIRSTTICK) && chan->period && param) {
-               if (flags & SONG_LINEARSLIDES) {
-                       chan->period = _muldivr(chan->period, 
fine_linear_slide_down_table[param & 0x0F], 65536);
-               } else {
-                       chan->period += (int)(param);
-               }
+       if ((flags & SONG_FIRSTTICK) && chan->frequency && param) {
+               chan->frequency = csf_fx_do_freq_slide(flags, chan->frequency, 
-(int)param, 0);
        }
 }
 
 static void fx_reg_portamento_up(uint32_t flags, song_voice_t *chan, uint32_t 
param)
 {
        if (!(flags & SONG_FIRSTTICK))
-               fx_do_freq_slide(flags, chan, -(int)(param * 4));
+               chan->frequency = csf_fx_do_freq_slide(flags, chan->frequency, 
(int)(param * 4), 0);
 }
 
 static void fx_reg_portamento_down(uint32_t flags, song_voice_t *chan, 
uint32_t param)
 {
        if (!(flags & SONG_FIRSTTICK))
-               fx_do_freq_slide(flags, chan, (int)(param * 4));
+               chan->frequency = csf_fx_do_freq_slide(flags, chan->frequency, 
-(int)(param * 4), 0);
 }
 
 
@@ -287,37 +294,21 @@
 
 static void fx_tone_portamento(uint32_t flags, song_voice_t *chan, uint32_t 
param)
 {
-       int delta;
-
        if (!param)
                param = chan->mem_portanote;
 
        chan->flags |= CHN_PORTAMENTO;
-       if (chan->period && chan->portamento_target && !(flags & 
SONG_FIRSTTICK)) {
-               if (chan->period < chan->portamento_target) {
-                       if (flags & SONG_LINEARSLIDES) {
-                               uint32_t n = MIN(255, param);
-                               delta = _muldivr(chan->period, 
linear_slide_up_table[n], 65536) - chan->period;
-                               if (delta < 1) delta = 1;
-                       } else {
-                               delta = param * 4;
-                       }
-                       chan->period += delta;
-                       if (chan->period > chan->portamento_target) {
-                               chan->period = chan->portamento_target;
+       if (chan->frequency && chan->portamento_target && !(flags & 
SONG_FIRSTTICK)) {
+               if (chan->frequency < chan->portamento_target) {
+                       chan->frequency = csf_fx_do_freq_slide(flags, 
chan->frequency, param * 4, 1);
+                       if (chan->frequency > chan->portamento_target) {
+                               chan->frequency = chan->portamento_target;
                                chan->portamento_target = 0;
                        }
-               } else if (chan->period > chan->portamento_target) {
-                       if (flags & SONG_LINEARSLIDES) {
-                               uint32_t n = MIN(255, param);
-                               delta = _muldivr(chan->period, 
linear_slide_down_table[n], 65536) - chan->period;
-                               if (delta > -1) delta = -1;
-                       } else {
-                               delta = -param * 4;
-                       }
-                       chan->period += delta;
-                       if (chan->period < chan->portamento_target) {
-                               chan->period = chan->portamento_target;
+               } else if (chan->frequency > chan->portamento_target) {
+                       chan->frequency = csf_fx_do_freq_slide(flags, 
chan->frequency, param * -4, 1);
+                       if (chan->frequency < chan->portamento_target) {
+                               chan->frequency = chan->portamento_target;
                                chan->portamento_target = 0;
                        }
                }
@@ -341,9 +332,9 @@
                if (--chan->note_slide_counter == 0) {
                        chan->note_slide_counter = chan->note_slide_speed;
                        // update it
-                       chan->period = get_period_from_note
-                               (sign * chan->note_slide_step + 
get_note_from_period(chan->period),
-                                8363, 0);
+                       chan->frequency = get_frequency_from_note
+                               (sign * chan->note_slide_step + 
get_note_from_frequency(chan->frequency, chan->c5speed),
+                                       chan->c5speed);
                }
        }
 }
@@ -480,6 +471,7 @@
        if (slide) {
                slide += chan->panning;
                chan->panning = CLAMP(slide, 0, 256);
+               chan->channel_panning = 0;
        }
        chan->flags &= ~CHN_SURROUND;
        chan->panbrello_delta = 0;
@@ -550,12 +542,12 @@
                }
 
                uint32_t note = chan->new_note;
-               int32_t period = chan->period;
+               int32_t frequency = chan->frequency;
                if (NOTE_IS_NOTE(note) && chan->length)
                        csf_check_nna(csf, nchan, 0, note, 1);
                csf_note_change(csf, nchan, note, 1, 1, 0);
-               if (period && chan->row_note == NOTE_NONE)
-                       chan->period = period;
+               if (frequency && chan->row_note == NOTE_NONE)
+                       chan->frequency = frequency;
                chan->position = chan->position_frac = 0;
        }
 }
@@ -712,6 +704,7 @@
                        chan->flags &= ~CHN_SURROUND;
                        chan->panbrello_delta = 0;
                        chan->panning = (param << 4) + 8;
+                       chan->channel_panning = 0;
                        chan->flags |= CHN_FASTVOLRAMP;
                        chan->pan_swing = 0;
                }
@@ -722,6 +715,7 @@
                        chan->flags |= CHN_SURROUND;
                        chan->panbrello_delta = 0;
                        chan->panning = 128;
+                       chan->channel_panning = 0;
                }
                break;
        // SAx: Set 64k Offset
@@ -1211,18 +1205,10 @@
                if (penv) {
                        penv->played = 1;
                        chan->instrument_volume = (psmp->global_volume * 
penv->global_volume) >> 7;
-                       if (penv->flags & ENV_SETPANNING) {
-                               chan->panning = penv->panning;
-                               chan->flags &= ~CHN_SURROUND;
-                       }
                        chan->nna = penv->nna;
                } else {
                        chan->instrument_volume = psmp->global_volume;
                }
-               if (psmp->flags & CHN_PANNING) {
-                       chan->panning = psmp->panning;
-                       chan->flags &= ~CHN_SURROUND;
-               }
        }
 
        // Reset envelopes
@@ -1285,10 +1271,9 @@
 
        if ((chan->flags & (CHN_KEYOFF | CHN_NOTEFADE)) && inst_column) {
                // Don't start new notes after ===/~~~
-               chan->period = 0;
+               chan->frequency = 0;
        } else {
-               chan->period = get_period_from_note(note, psmp->c5speed,
-                       csf->flags & SONG_LINEARSLIDES);
+               chan->frequency = get_frequency_from_note(note, psmp->c5speed);
        }
        chan->flags &= ~(CHN_SAMPLE_FLAGS | CHN_KEYOFF | CHN_NOTEFADE
                           | CHN_VOLENV | CHN_PANENV | CHN_PITCHENV);
@@ -1376,17 +1361,17 @@
 
        if(!porta || !chan->length)
                chan->c5speed = pins->c5speed;
-        
+
        note = CLAMP(note, NOTE_FIRST, NOTE_LAST);
        chan->note = CLAMP(truenote, NOTE_FIRST, NOTE_LAST);
        chan->new_instrument = 0;
-       uint32_t period = get_period_from_note(note, chan->c5speed, csf->flags 
& SONG_LINEARSLIDES);
-       if (period) {
-               if (porta && chan->period) {
-                       chan->portamento_target = period;
+       uint32_t frequency = get_frequency_from_note(note, chan->c5speed);
+       if (frequency) {
+               if (porta && chan->frequency) {
+                       chan->portamento_target = frequency;
                } else {
                        chan->portamento_target = 0;
-                       chan->period = period;
+                       chan->frequency = frequency;
                }
                if (!porta || !chan->length) {
                        chan->ptr_sample = pins;
@@ -1415,6 +1400,12 @@
                porta = 0;
        }
 
+       if (penv && (penv->flags & ENV_SETPANNING)) {
+               set_instrument_panning(chan, penv->panning);
+       } else if (pins->flags & CHN_PANNING) {
+               set_instrument_panning(chan, pins->panning);
+       }
+
        if (!porta)
                env_reset(chan, 0);
 
@@ -1796,6 +1787,7 @@
                chan->flags &= ~CHN_SURROUND;
                chan->panbrello_delta = 0;
                chan->panning = param;
+               chan->channel_panning = 0;
                chan->pan_swing = 0;
                chan->flags |= CHN_FASTVOLRAMP;
                break;
@@ -1924,6 +1916,7 @@
                if (start_note) {
                        if (vol > 64) vol = 64;
                        chan->panning = vol << 2;
+                       chan->channel_panning = 0;
                        chan->pan_swing = 0;
                        chan->flags |= CHN_FASTVOLRAMP;
                        chan->flags &= ~CHN_SURROUND;
@@ -2103,6 +2096,14 @@
                                instr = 0;
                        } else if (NOTE_IS_NOTE(note)) {
                                chan->new_note = note;
+                               if (chan->channel_panning > 0)
+                               {
+                                       chan->panning = (chan->channel_panning 
& 0x7FFF) - 1;
+                                       if (chan->channel_panning & 0x8000)
+                                               chan->flags |= CHN_SURROUND;
+                                       chan->channel_panning = 0;
+                               }
+
                                // New Note Action ? (not when paused!!!)
                                if (!porta)
                                        csf_check_nna(csf, nchan, instr, note, 
0);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/player/snd_gm.c 
new/schismtracker-20210525/player/snd_gm.c
--- old/schismtracker-20200412/player/snd_gm.c  2020-05-12 16:45:03.000000000 
+0200
+++ new/schismtracker-20210525/player/snd_gm.c  2021-05-25 01:32:00.000000000 
+0200
@@ -342,7 +342,7 @@
                }
        }
 
-       int best_mc = c,
+       int best_mc = c % 16,
            best_score = -999;
 
        for (int mc = 0; mc < 16; ++mc) {
@@ -449,6 +449,8 @@
                        percu = s3m_chans[c].patch - 128;
 
                int mc = s3m_chans[c].chan = 9;
+               // Percussion can have different banks too
+               msi_set_patch_and_bank(&midi_chans[mc], mc, s3m_chans[c].patch, 
s3m_chans[c].bank);
                msi_set_pan(&midi_chans[mc], mc, s3m_chans[c].pan);
                msi_set_volume(&midi_chans[mc], mc, GM_volume(vol));
                s3m_chans[c].note = key;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/player/sndmix.c 
new/schismtracker-20210525/player/sndmix.c
--- old/schismtracker-20200412/player/sndmix.c  2020-05-12 16:45:03.000000000 
+0200
+++ new/schismtracker-20210525/player/sndmix.c  2021-05-25 01:32:00.000000000 
+0200
@@ -104,17 +104,6 @@
 }
 
 
-unsigned int get_freq_from_period(int period, int linear)
-{
-       if (period <= 0)
-               return INT_MAX;
-       else if (linear)
-               return period;
-       else
-               return _muldiv(8363, 1712L << 8, (period << 8));
-}
-
-
 
////////////////////////////////////////////////////////////////////////////////////////////
 //
 // XXX * I prefixed these with `rn_' to avoid any namespace conflicts
@@ -133,7 +122,7 @@
 }
 
 
-static inline int rn_vibrato(song_t *csf, song_voice_t *chan, int period)
+static inline int rn_vibrato(song_t *csf, song_voice_t *chan, int frequency)
 {
        unsigned int vibpos = chan->vibrato_position & 0xFF;
        int vdelta;
@@ -163,33 +152,17 @@
        }
        vdelta = (vdelta * (int)chan->vibrato_depth) >> vdepth;
 
-       if (csf->flags & SONG_LINEARSLIDES) {
-               int l = abs(vdelta);
-
-               if (vdelta < 0) {
-                       vdelta = _muldiv(period, linear_slide_up_table[l >> 2], 
0x10000) - period;
-
-                       if (l & 0x03)
-                               vdelta += _muldiv(period, 
fine_linear_slide_up_table[l & 0x03], 0x10000) - period;
-               } else {
-                       vdelta = _muldiv(period, linear_slide_down_table[l >> 
2], 0x10000) - period;
-
-                       if (l & 0x03)
-                               vdelta += _muldiv(period, 
fine_linear_slide_down_table[l & 0x03], 0x10000) - period;
-               }
-       }
-
-       period -= vdelta;
+       frequency = csf_fx_do_freq_slide(csf->flags, frequency, vdelta, 0);
 
        // handle on tick-N, or all ticks if not in old-effects mode
        if (!(csf->flags & SONG_FIRSTTICK) || !(csf->flags & 
SONG_ITOLDEFFECTS)) {
                chan->vibrato_position = (vibpos + 4 * chan->vibrato_speed) & 
0xFF;
        }
 
-       return period;
+       return frequency;
 }
 
-static inline int rn_sample_vibrato(song_t *csf, song_voice_t *chan, int 
period)
+static inline int rn_sample_vibrato(song_t *csf, song_voice_t *chan, int 
frequency)
 {
        unsigned int vibpos = chan->autovib_position & 0xFF;
        int vdelta, adepth;
@@ -236,23 +209,17 @@
        if (vdelta < 0) {
                linear_slide_table = linear_slide_up_table;
                fine_linear_slide_table = fine_linear_slide_up_table;
-                       vdelta += _muldiv(period, fine_linear_slide_up_table[l 
& 0x03], 0x10000) - period;
        } else {
                linear_slide_table = linear_slide_down_table;
                fine_linear_slide_table = fine_linear_slide_down_table;
        }
 
-       if (csf->flags & SONG_LINEARSLIDES) {
-               vdelta = _muldiv(period, linear_slide_table[l >> 2], 0x10000) - 
period;
-               if (l & 0x03)
-                       vdelta += _muldiv(period, fine_linear_slide_table[l & 
0x03], 0x10000) - period;
-       } else {
-               vdelta = _muldiv(period, 0x10000, linear_slide_table[l >> 2]) - 
period;
-               if (l & 0x03)
-                       vdelta += _muldiv(period, 0x10000, 
fine_linear_slide_table[l & 0x03]) - period;
-       }
+       if(l < 16)
+               vdelta = _muldiv(frequency, fine_linear_slide_table[l], 
0x10000) - frequency;
+       else
+               vdelta = _muldiv(frequency, linear_slide_table[l >> 2], 
0x10000) - frequency;
 
-       return period - vdelta;
+       return frequency - vdelta;
 }
 
 
@@ -369,7 +336,7 @@
 }
 
 
-static inline int rn_arpeggio(song_t *csf, song_voice_t *chan, int period)
+static inline int rn_arpeggio(song_t *csf, song_voice_t *chan, int frequency)
 {
        int a;
 
@@ -385,22 +352,20 @@
        }
 
        if (!a)
-               return period;
+               return frequency;
 
        a = linear_slide_up_table[a * 16];
-       return ((csf->flags & SONG_LINEARSLIDES)
-               ? _muldiv(period, a, 65536)
-               : _muldiv(period, 65536, a));
+       return _muldiv(frequency, a, 65536);
 }
 
 
 static inline void rn_pitch_filter_envelope(song_t *csf, song_voice_t *chan,
-       int *nenvpitch, int *nperiod)
+       int *nenvpitch, int *nfrequency)
 {
        song_instrument_t *penv = chan->ptr_instrument;
        int envpos = chan->pitch_env_position;
        unsigned int pt = penv->pitch_env.nodes - 1;
-       int period = *nperiod;
+       int frequency = *nfrequency;
        int envpitch = *nenvpitch;
 
        for (unsigned int i = 0; i < (unsigned int)(penv->pitch_env.nodes - 1); 
i++) {
@@ -443,14 +408,10 @@
                        l = 255;
 
                int ratio = (envpitch < 0 ? linear_slide_down_table : 
linear_slide_up_table)[l];
-               if (csf->flags & SONG_LINEARSLIDES) {
-                       period = _muldiv(period, ratio, 0x10000);
-               } else {
-                       period = _muldiv(period, 0x10000, ratio);
-               }
+               frequency = _muldiv(frequency, ratio, 0x10000);
        }
 
-       *nperiod = period;
+       *nfrequency = frequency;
        *nenvpitch = envpitch;
 }
 
@@ -658,20 +619,20 @@
                // 8363 is st3s middle C sample rate. 261.625 is the Hertz for 
middle C in a tempered scale (A4 = 440)
                //Also, note that to be true to ST3, the frequencies should be 
quantized, like using the glissando control.
 
-        // OPL_Patch is called in csf_process_effects, from csf_read_note or 
csf_process_tick, before calling this method.
+               // OPL_Patch is called in csf_process_effects, from 
csf_read_note or csf_process_tick, before calling this method.
                int oplmilliHertz = (long long int)freq*261625L/8363L;
                OPL_HertzTouch(chan_num, oplmilliHertz, chan->flags & 
CHN_KEYOFF);
 
                // ST32 ignores global & master volume in adlib mode, guess we 
should do the same -Bisqwit
                // This gives a value in the range 0..63.
-        // log_appendf(2,"vol: %d, voiceinsvol: %d", vol , 
chan->instrument_volume);
+               // log_appendf(2,"vol: %d, voiceinsvol: %d", vol , 
chan->instrument_volume);
                OPL_Touch(chan_num, vol * chan->instrument_volume * 63 / (1 << 
20));
-        if (csf->flags&SONG_NOSTEREO) {
-            OPL_Pan(chan_num, 128);
-        }
-        else {
-            OPL_Pan(chan_num, chan->final_panning);
-        }
+               if (csf->flags&SONG_NOSTEREO) {
+                       OPL_Pan(chan_num, 128);
+               }
+               else {
+                       OPL_Pan(chan_num, chan->final_panning);
+               }
        }
 }
 
@@ -1126,7 +1087,7 @@
        for (cn = 0, chan = csf->voices; cn < MAX_VOICES; cn++, chan++) {
                /*if(cn == 0 || cn == 1)
                fprintf(stderr, "considering channel %d (per %d, pos %d/%d, 
flags %X)\n",
-                       (int)cn, chan->period, chan->position, chan->length, 
chan->flags);*/
+                       (int)cn, chan->frequency, chan->position, chan->length, 
chan->flags);*/
 
                if (chan->flags & CHN_NOTEFADE &&
                    !(chan->fadeout_volume | chan->right_volume | 
chan->left_volume)) {
@@ -1148,7 +1109,7 @@
                chan->ramp_length = 0;
 
                // Calc Frequency
-               if (chan->period && (chan->length || (chan->flags & 
CHN_ADLIB))) {
+               if (chan->frequency && (chan->length || (chan->flags & 
CHN_ADLIB))) {
                        int vol = chan->volume;
 
                        if (chan->flags & CHN_TREMOLO)
@@ -1187,37 +1148,34 @@
                                         1 << 19);
                        }
 
-                       int period = chan->period;
+                       int frequency = chan->frequency;
 
                        if ((chan->flags & (CHN_GLISSANDO|CHN_PORTAMENTO)) == 
(CHN_GLISSANDO|CHN_PORTAMENTO)) {
-                               period = 
get_period_from_note(get_note_from_period(period),
-                                       chan->c5speed, csf->flags & 
SONG_LINEARSLIDES);
+                               frequency = 
get_frequency_from_note(get_note_from_frequency(frequency, chan->c5speed), 
chan->c5speed);
                        }
 
                        // Arpeggio ?
                        if (chan->n_command == FX_ARPEGGIO)
-                               period = rn_arpeggio(csf, chan, period);
+                               frequency = rn_arpeggio(csf, chan, frequency);
 
                        // Pitch/Filter Envelope
                        int envpitch = 0;
 
                        if ((csf->flags & SONG_INSTRUMENTMODE) && 
chan->ptr_instrument
                                && (chan->flags & CHN_PITCHENV) && 
chan->ptr_instrument->pitch_env.nodes)
-                               rn_pitch_filter_envelope(csf, chan, &envpitch, 
&period);
+                               rn_pitch_filter_envelope(csf, chan, &envpitch, 
&frequency);
 
                        // Vibrato
                        if (chan->flags & CHN_VIBRATO)
-                               period = rn_vibrato(csf, chan, period);
+                               frequency = rn_vibrato(csf, chan, frequency);
 
                        // Sample Auto-Vibrato
                        if (chan->ptr_sample && chan->ptr_sample->vib_depth) {
-                               period = rn_sample_vibrato(csf, chan, period);
+                               frequency = rn_sample_vibrato(csf, chan, 
frequency);
                        }
 
-                       unsigned int freq = get_freq_from_period(period, 
csf->flags & SONG_LINEARSLIDES);
-
                        if (!(chan->flags & CHN_NOTEFADE))
-                               rn_gen_key(csf, chan, cn, freq, vol);
+                               rn_gen_key(csf, chan, cn, frequency, vol);
 
                        // Filter Envelope: controls cutoff frequency
                        if (chan && chan->ptr_instrument && 
chan->ptr_instrument->flags & ENV_FILTER) {
@@ -1225,9 +1183,9 @@
                                        !(chan->flags & CHN_FILTER), envpitch, 
csf->mix_frequency);
                        }
 
-                       chan->sample_freq = freq;
+                       chan->sample_freq = frequency;
 
-                       unsigned int ninc = _muldiv(freq, 0x10000, 
csf->mix_frequency);
+                       unsigned int ninc = _muldiv(frequency, 0x10000, 
csf->mix_frequency);
 
                        if (ninc >= 0xFFB0 && ninc <= 0x10090)
                                ninc = 0x10000;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/schism/audio_loadsave.c 
new/schismtracker-20210525/schism/audio_loadsave.c
--- old/schismtracker-20200412/schism/audio_loadsave.c  2020-05-12 
16:45:03.000000000 +0200
+++ new/schismtracker-20210525/schism/audio_loadsave.c  2021-05-25 
01:32:00.000000000 +0200
@@ -485,7 +485,8 @@
                        disko_seek(fp, op, SEEK_SET);
                        csf_write_sample(fp, smp, SF_LE | SF_PCMS
                                        | ((smp->flags & CHN_16BIT) ? SF_16 : 
SF_8)
-                                       | ((smp->flags & CHN_STEREO) ? SF_SS : 
SF_M));
+                                       | ((smp->flags & CHN_STEREO) ? SF_SS : 
SF_M),
+                                       UINT32_MAX);
                }
        }
 }
@@ -784,7 +785,8 @@
                if (smp->data)
                        csf_write_sample(fp, smp, SF_LE | SF_PCMS
                                        | ((smp->flags & CHN_16BIT) ? SF_16 : 
SF_8)
-                                       | ((smp->flags & CHN_STEREO) ? SF_SS : 
SF_M));
+                                       | ((smp->flags & CHN_STEREO) ? SF_SS : 
SF_M),
+                                       UINT32_MAX);
                // done using the pointer internally, so *now* swap it
                para_smp[n] = bswapLE32(para_smp[n]);
 
@@ -808,6 +810,7 @@
 const struct save_format song_save_formats[] = {
        {"IT", "Impulse Tracker", ".it", {.save_song = _save_it}},
        {"S3M", "Scream Tracker 3", ".s3m", {.save_song = fmt_s3m_save_song}},
+       {"MOD", "Amiga ProTracker", ".mod", {.save_song = fmt_mod_save_song}},
        {.label = NULL}
 };
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/schismtracker-20200412/schism/midi-core.c 
new/schismtracker-20210525/schism/midi-core.c
--- old/schismtracker-20200412/schism/midi-core.c       2020-05-12 
16:45:03.000000000 +0200
+++ new/schismtracker-20210525/schism/midi-core.c       2021-05-25 
01:32:00.000000000 +0200
@@ -303,10 +303,13 @@
 #ifdef USE_NETWORK
        ip_midi_setup();
 #endif
-#ifdef USE_OSS
+//Prefer ALSA MIDI over OSS, but do not enable both since ALSA's OSS emulation 
can cause conflicts
+#if defined(USE_ALSA) && defined(USE_OSS)
+       if (!alsa_midi_setup())
+               oss_midi_setup();
+#elif !defined(USE_ALSA) && defined(USE_OSS)
        oss_midi_setup();
-#endif
-#ifdef USE_ALSA
+#elif defined(USE_ALSA) && !defined(USE_OSS)
        alsa_midi_setup();
 #endif
 #ifdef WIN32

Reply via email to