Hello community,

here is the log from the commit of package libxmp for openSUSE:Factory checked 
in at 2015-04-15 16:22:11
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libxmp (Old)
 and      /work/SRC/openSUSE:Factory/.libxmp.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libxmp"

Changes:
--------
--- /work/SRC/openSUSE:Factory/libxmp/libxmp.changes    2015-03-25 
21:33:26.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.libxmp.new/libxmp.changes       2015-04-15 
16:22:13.000000000 +0200
@@ -1,0 +2,13 @@
+Tue Apr  7 12:28:49 UTC 2015 - jeng...@inai.de
+
+- Update to new upstream release 4.3.8
+* Fix Impluse Tracker sample mode note cut on invalid sample,
+  IT sample mode note end detection,
+  IT envelope handling with carry and fadeout,
+  IT tone portamento with sample changes,
+  IT keyoff with instrument in old effects mode,
+  IT note release at end of envelope sustain loop
+* Recognize IT high offset command (SAx) and surround command (S9x).
+* Add IT surround channel support and sample pan setting support.
+
+-------------------------------------------------------------------

Old:
----
  libxmp-4.3.6.tar.gz

New:
----
  libxmp-4.3.8.tar.gz

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

Other differences:
------------------
++++++ libxmp.spec ++++++
--- /var/tmp/diff_new_pack.VhnzYv/_old  2015-04-15 16:22:13.000000000 +0200
+++ /var/tmp/diff_new_pack.VhnzYv/_new  2015-04-15 16:22:13.000000000 +0200
@@ -18,7 +18,7 @@
 
 Name:           libxmp
 %define lname  libxmp4
-Version:        4.3.6
+Version:        4.3.8
 Release:        0
 Summary:        Module Player library for MOD, S3M, IT and others
 License:        LGPL-2.1

++++++ libxmp-4.3.6.tar.gz -> libxmp-4.3.8.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/Makefile.in new/libxmp-4.3.8/Makefile.in
--- old/libxmp-4.3.6/Makefile.in        2015-02-17 14:39:35.000000000 +0100
+++ new/libxmp-4.3.8/Makefile.in        2015-04-02 02:38:02.000000000 +0200
@@ -1,6 +1,6 @@
 VERSION_MAJOR  = 4
 VERSION_MINOR  = 3
-VERSION_RELEASE        = 6
+VERSION_RELEASE        = 8
 
 VERSION                = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/docs/Changelog 
new/libxmp-4.3.8/docs/Changelog
--- old/libxmp-4.3.6/docs/Changelog     2015-03-24 00:08:04.000000000 +0100
+++ new/libxmp-4.3.8/docs/Changelog     2015-04-04 03:35:05.000000000 +0200
@@ -1,6 +1,35 @@
 Stable versions
 ---------------
 
+4.3.8 (20150404):
+       Fix bugs caught in the OpenMPT test cases:
+       - fix pre-increment of envelope indexes
+       - fix IT note release at end of envelope sustain loop
+       - reset channel flags in case of delay effect
+       Other changes:
+       - fix MMD3 16-bit samples (reported by jbb666)
+       - refactor XM envelopes
+       - refactor IT envelopes
+
+4.3.7 (20150329):
+       Fix bugs caught in the OpenMPT test cases:
+       - fix IT sample mode note cut on invalid sample
+       - fix IT sample mode note end detection
+       - fix IT envelope handling with carry and fadeout
+       - fix IT tone portamento with sample changes
+       - fix IT initial global volume setting
+       - fix IT keyoff with instrument in old effects mode
+       - fix IT filter maximum values with resonance
+       Other changes:
+       - fix IT random volume variation
+       - fix pattern initialization sanity check
+       - fix ++ pattern handling in IT loader (reported by honguito98)
+       - fix Soundtracker short rip loading (reported by Shlomi Fish)
+       - add IT high offset command (SAx)
+       - add IT surround command (S9x)
+       - add IT surround channel support
+       - add IT sample pan setting support
+
 4.3.6 (20150322):
        Fix bugs caught in the OpenMPT test cases:
        - fix IT volume column volume slide effect memory
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/include/xmp.h 
new/libxmp-4.3.8/include/xmp.h
--- old/libxmp-4.3.6/include/xmp.h      2015-03-24 00:18:18.000000000 +0100
+++ new/libxmp-4.3.8/include/xmp.h      2015-04-04 13:37:05.000000000 +0200
@@ -5,11 +5,11 @@
 extern "C" {
 #endif
 
-#define XMP_VERSION "4.3.6"
-#define XMP_VERCODE 0x040306
+#define XMP_VERSION "4.3.8"
+#define XMP_VERCODE 0x040308
 #define XMP_VER_MAJOR 4
 #define XMP_VER_MINOR 3
-#define XMP_VER_RELEASE 6
+#define XMP_VER_RELEASE 8
 
 #if defined(_WIN32) && !defined(__CYGWIN__)
 # if defined(BUILDING_STATIC)
@@ -105,6 +105,7 @@
 #define XMP_CHANNEL_SYNTH      (1 << 0)  /* Channel is synthesized */
 #define XMP_CHANNEL_MUTE       (1 << 1)  /* Channel is muted */
 #define XMP_CHANNEL_SPLIT      (1 << 2)  /* Split Amiga channel in bits 5-4 */
+#define XMP_CHANNEL_SURROUND   (1 << 4)  /* Surround channel */
        int flg;                        /* Channel flags */
 };
 
@@ -231,7 +232,7 @@
        struct xmp_track **xxt;         /* Tracks */
        struct xmp_instrument *xxi;     /* Instruments */
        struct xmp_sample *xxs;         /* Samples */
-       struct xmp_channel xxc[64];     /* Channel info */
+       struct xmp_channel xxc[XMP_MAX_CHANNELS]; /* Channel info */
        unsigned char xxo[XMP_MAX_MOD_LENGTH];  /* Orders */
 };
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/libxmp.pc.in 
new/libxmp-4.3.8/libxmp.pc.in
--- old/libxmp-4.3.6/libxmp.pc.in       2015-03-24 00:18:18.000000000 +0100
+++ new/libxmp-4.3.8/libxmp.pc.in       2015-04-04 13:37:05.000000000 +0200
@@ -5,7 +5,7 @@
 
 Name: libxmp
 Description: Xmp module player library
-Version: 4.3.6
+Version: 4.3.8
 
 Requires:
 Libs: -L${libdir} -lxmp
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/src/common.h 
new/libxmp-4.3.8/src/common.h
--- old/libxmp-4.3.6/src/common.h       2015-03-22 11:28:02.000000000 +0100
+++ new/libxmp-4.3.8/src/common.h       2015-03-29 18:24:13.000000000 +0200
@@ -154,7 +154,7 @@
 #define QUIRK_VIBALL   (1 << 20)       /* Vibrato in all frames */
 #define QUIRK_VIBINV   (1 << 21)       /* Vibrato has inverse waveform */
 #define QUIRK_PRENV    (1 << 22)       /* Portamento resets envelope & fade */
-/*#define QUIRK_S3MLFO (1 << 23)*/     /* S3M-style LFO waveforms */
+#define QUIRK_ITOLDFX  (1 << 23)       /* IT old effects mode */
 #define QUIRK_S3MRTG   (1 << 24)       /* S3M-style retrig when count == 0 */
 #define QUIRK_RTDELAY  (1 << 25)       /* Delay effect retrigs instrument */
 #define QUIRK_FT2BUGS  (1 << 26)       /* FT2 bug compatibility */
@@ -187,9 +187,7 @@
 #define MED_TIME_FACTOR                2.64
 
 #define MAX_SEQUENCES          16
-
-/* Arbitrary limit to prevent unreasonably large allocations */
-#define MAX_SAMPLE_SIZE                0x00800000
+#define MAX_SAMPLE_SIZE                0x10000000
 #define MAX_SAMPLES            1024
 
 struct ord_data {
@@ -229,6 +227,7 @@
        int c4rate;                     /* C4 replay rate */
        int volbase;                    /* Volume base */
        int gvolbase;                   /* Global volume base */
+       int gvol;                       /* Global volume */
        int *vol_table;                 /* Volume translation table */
        int quirk;                      /* player quirks */
 #define READ_EVENT_MOD 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/src/effects.c 
new/libxmp-4.3.8/src/effects.c
--- old/libxmp-4.3.6/src/effects.c      2015-03-07 14:51:39.000000000 +0100
+++ new/libxmp-4.3.8/src/effects.c      2015-03-29 18:25:45.000000000 +0200
@@ -74,7 +74,7 @@
        if (note >= 1 && note <= 0x80 && (uint32)xc->ins < m->mod.ins) {
                note--;
                xc->porta.target = note_to_period(note + sub->xpo +
-                       instrument->map[xc->key].xpo, xc->finetune,
+                       instrument->map[xc->key_porta].xpo, xc->finetune,
                        HAS_QUIRK(QUIRK_LINEAR), xc->per_adj);
        }
        xc->porta.dir = xc->period < xc->porta.target ? 1 : -1;
@@ -91,6 +91,11 @@
        uint8 note, fxp, fxt;
        int h, l;
 
+       /* key_porta is IT only */
+       if (m->read_event_type != READ_EVENT_IT) {
+               xc->key_porta = xc->key;
+       }
+
        note = e->note;
        if (fnum == 0) {
                fxt = e->fxt;
@@ -252,13 +257,16 @@
                    || e->fxt != FX_EXTENDED            /* or not delay */
                    || MSN(e->fxp) != EX_DELAY) {
                        xc->pan.val = fxp;
+                       xc->pan.surround = 0;
                }
                break;
        case FX_OFFSET:         /* Set sample offset */
                EFFECT_MEMORY(fxp, xc->offset.memory);
                SET(OFFSET);
                if (note) {
-                       xc->offset.val = xc->offset.val2 = fxp << 8;
+                       xc->offset.val &= xc->offset.val & ~0xffff;
+                       xc->offset.val |= fxp << 8;
+                       xc->offset.val2 = fxp << 8;
                }
                if (e->ins) {
                        xc->offset.val2 = fxp << 8;
@@ -772,6 +780,13 @@
        case FX_PANBRELLO_WF:   /* Panbrello waveform */
                set_lfo_waveform(&xc->panbrello.lfo, fxp & 3);
                break;
+       case FX_HIOFFSET:       /* High offset */
+               xc->offset.val &= 0xffff;
+               xc->offset.val |= fxp << 16;
+               break;
+       case FX_SURROUND:
+               xc->pan.surround = fxp;
+               break;
 #endif
 
 #ifndef LIBXMP_CORE_PLAYER
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/src/effects.h 
new/libxmp-4.3.8/src/effects.h
--- old/libxmp-4.3.6/src/effects.h      2015-02-17 19:09:46.000000000 +0100
+++ new/libxmp-4.3.8/src/effects.h      2015-03-29 18:24:13.000000000 +0200
@@ -81,6 +81,8 @@
 #define FX_IT_PANSLIDE 0x89
 #define FX_PANBRELLO   0x8a
 #define FX_PANBRELLO_WF        0x8b
+#define FX_HIOFFSET    0x8c
+#define FX_SURROUND    0x8d
 #endif
 
 #ifndef LIBXMP_CORE_PLAYER
@@ -123,4 +125,5 @@
 #define FX_VSLIDE_DN_2 0xc1
 #define FX_F_VSLIDE_UP_2 0xc2
 #define FX_F_VSLIDE_DN_2 0xc3
+
 #endif /* LIBXMP_EFFECTS_H */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/src/envelope.c 
new/libxmp-4.3.8/src/envelope.c
--- old/libxmp-4.3.6/src/envelope.c     2015-02-17 14:39:35.000000000 +0100
+++ new/libxmp-4.3.8/src/envelope.c     2015-04-04 13:31:48.000000000 +0200
@@ -69,11 +69,6 @@
        /* interpolate */
        y1 = data[index + 1];
        x2 = data[index + 2];
-
-       if (env->flg & XMP_ENVELOPE_LOOP && index == (env->lpe << 1)) {
-               index = (env->lps - 1) * 2;
-       }
-
        y2 = data[index + 3];
 
        return x2 == x1 ? y2 : ((y2 - y1) * (x - x1) / (x2 - x1)) + y1;
@@ -83,14 +78,7 @@
 {
        int16 *data = env->data;
        int has_loop, has_sus;
-       int lpe, lps, sus, sue;
-
-       if (x < 0)
-               return -1;
-
-       if (~env->flg & XMP_ENVELOPE_ON || env->npt <= 0) {
-               return x;
-       }
+       int lpe, lps, sus;
 
        has_loop = env->flg & XMP_ENVELOPE_LOOP;
        has_sus = env->flg & XMP_ENVELOPE_SUS;
@@ -98,7 +86,6 @@
        lps = env->lps << 1;
        lpe = env->lpe << 1;
        sus = env->sus << 1;
-       sue = env->sue << 1;
 
        /* FT2 and IT envelopes behave in a different way regarding loops,
         * sustain and release. When the sustain point is at the end of the
@@ -111,16 +98,14 @@
                        has_sus = 0;
        }
 
-       /* FT2 doesn't have sustain loop */
-       if (!release && has_sus && x == data[sus]) {
-               /* stay in the sustain point */
-               x--;
-       }
-
-       if (x < 0xffff) {       /* increment tick */
-               x++;
+       /* If enabled, stay at the sustain point */
+       if (has_sus && !release) {
+               if (x >= data[sus]) {
+                       x = data[sus];
+               }
        }
 
+       /* Envelope loops */
        if (has_loop && x >= data[lpe]) {
                if (!(release && has_sus && sus == lpe))
                        x = data[lps];
@@ -131,19 +116,12 @@
 
 #ifndef LIBXMP_CORE_DISABLE_IT
 
-static int update_envelope_it(struct xmp_envelope *env, int x, int release)
+static int update_envelope_it(struct xmp_envelope *env, int x, int release, 
int key_off)
 {
        int16 *data = env->data;
        int has_loop, has_sus;
        int lpe, lps, sus, sue;
 
-       if (x < 0)
-               return -1;
-
-       if (~env->flg & XMP_ENVELOPE_ON || env->npt <= 0) {
-               return x;
-       }
-
        has_loop = env->flg & XMP_ENVELOPE_LOOP;
        has_sus = env->flg & XMP_ENVELOPE_SUS;
 
@@ -152,40 +130,45 @@
        sus = env->sus << 1;
        sue = env->sue << 1;
 
-       if (env->flg & XMP_ENVELOPE_SLOOP) {
-               if (!release && has_sus) {
-                       if (x == data[sue])
-                               x = data[sus] - 1;
-               } else if (has_loop) {
-                       if (x == data[lpe])
-                               x = data[lps] - 1;
-               }
-       } else {
-               if (!release && has_sus && x == data[sus]) {
-                       /* stay in the sustain point */
-                       x--;
+       /* Release at the end of a sustain loop, run another loop */
+       if (has_sus && key_off && x == data[sue] + 1) {
+               x = data[sus];
+       } else
+       /* If enabled, stay in the sustain loop */
+       if (has_sus && !release) {
+               if (x == data[sue] + 1) {
+                       x = data[sus];
                }
-
-               if (has_loop && x == data[lpe]) {
-                       if (!(release && has_sus && sus == lpe))
-                               x = data[lps] - 1;
+       } else
+       /* Finally, execute the envelope loop */
+       if (has_loop) {
+               if (x > data[lpe]) {
+                       x = data[lps];
                }
        }
 
-       if (x < 0xffff) {       /* increment tick */
-               x++;
-       }
-
        return x;
 }
 
 #endif
 
-int update_envelope(struct xmp_envelope *env, int x, int release, int it_env)
+int update_envelope(struct xmp_envelope *env, int x, int release, int key_off, 
int it_env)
 {
+       if (x < 0xffff) {       /* increment tick */
+               x++;
+       }
+
+       if (x < 0) {
+               return -1;
+       }
+
+       if (~env->flg & XMP_ENVELOPE_ON || env->npt <= 0) {
+               return x;
+       }
+
 #ifndef LIBXMP_CORE_DISABLE_IT
        return it_env ?
-               update_envelope_it(env, x, release) :
+               update_envelope_it(env, x, release, key_off) :
                update_envelope_xm(env, x, release);
 #else
        return update_envelope_xm(env, x, release);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/src/envelope.h 
new/libxmp-4.3.8/src/envelope.h
--- old/libxmp-4.3.6/src/envelope.h     2015-02-17 14:39:35.000000000 +0100
+++ new/libxmp-4.3.8/src/envelope.h     2015-04-04 00:18:48.000000000 +0200
@@ -4,7 +4,7 @@
 /* Envelope */
 
 int get_envelope(struct xmp_envelope *, int, int);
-int update_envelope(struct xmp_envelope *, int, int, int);
+int update_envelope(struct xmp_envelope *, int, int, int, int);
 int check_envelope_fade(struct xmp_envelope *, int);
 int check_envelope_end(struct xmp_envelope *, int);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/src/fmopl.c new/libxmp-4.3.8/src/fmopl.c
--- old/libxmp-4.3.6/src/fmopl.c        2015-02-17 14:39:35.000000000 +0100
+++ new/libxmp-4.3.8/src/fmopl.c        2015-03-29 18:24:13.000000000 +0200
@@ -590,7 +590,7 @@
                OPL->AR_TABLE[i] = rate / ARRATE;
                OPL->DR_TABLE[i] = rate / DRRATE;
        }
-       for (i = 60;i < 76;i++)
+       for (i = 60;i < 75;i++)
        {
                OPL->AR_TABLE[i] = EG_AED-1;
                OPL->DR_TABLE[i] = OPL->DR_TABLE[60];
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/src/load.c new/libxmp-4.3.8/src/load.c
--- old/libxmp-4.3.6/src/load.c 2015-03-22 01:41:59.000000000 +0100
+++ new/libxmp-4.3.8/src/load.c 2015-03-29 18:24:13.000000000 +0200
@@ -373,23 +373,26 @@
        }
 
        if (load_result < 0) {
-               xmp_release_module(opaque);
-               return -XMP_ERROR_LOAD;
+               goto err_load;
        }
 
        /* Sanity check */
        if (mod->chn > XMP_MAX_CHANNELS || mod->len > XMP_MAX_MOD_LENGTH) {
-               xmp_release_module(opaque);
-               return -XMP_ERROR_LOAD;
+               goto err_load;
        }
 
        /* Sanity check */
+       if (mod->xxp == NULL) {
+               goto err_load;
+       }
        for (i = 0; i < mod->pat; i++) {
+               if (mod->xxp[i] == NULL) {
+                       goto err_load;
+               }
                for (j = 0; j < mod->chn; j++) {
                        int t = mod->xxp[i]->index[j];
-                       if (t >= mod->trk || mod->xxt[t] == NULL) {
-                               xmp_release_module(opaque);
-                               return -XMP_ERROR_LOAD;
+                       if (t < 0 || t >= mod->trk || mod->xxt[t] == NULL) {
+                               goto err_load;
                        }
                }
        }
@@ -408,6 +411,10 @@
        ctx->state = XMP_STATE_LOADED;
 
        return 0;
+
+    err_load:
+       xmp_release_module(opaque);
+       return -XMP_ERROR_LOAD;
 }
 
 int xmp_load_module(xmp_context opaque, char *path)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/src/load_helpers.c 
new/libxmp-4.3.8/src/load_helpers.c
--- old/libxmp-4.3.6/src/load_helpers.c 2015-03-08 00:18:22.000000000 +0100
+++ new/libxmp-4.3.8/src/load_helpers.c 2015-04-02 02:38:02.000000000 +0200
@@ -162,6 +162,11 @@
        if (env->lps >= env->npt || env->lpe >= env->npt) {
                env->flg &= ~XMP_ENVELOPE_LOOP;
        }
+
+       /* Disable envelope loop if invalid sustain */
+       if (env->sus >= env->npt) {
+               env->flg &= ~XMP_ENVELOPE_ON;
+       }
 }
 
 void load_prologue(struct context_data *ctx)
@@ -174,7 +179,7 @@
        m->rrate = PAL_RATE;
        m->c4rate = C4_PAL_RATE;
        m->volbase = 0x40;
-       m->gvolbase = 0x40;
+       m->gvol = m->gvolbase = 0x40;
        m->vol_table = NULL;
        m->quirk = 0;
        m->read_event_type = READ_EVENT_MOD;
@@ -213,7 +218,7 @@
        struct xmp_module *mod = &m->mod;
        int i, j;
 
-       mod->gvl = m->gvolbase;
+       mod->gvl = m->gvol;
 
        /* Sanity check for module parameters */
        CLAMP(mod->len, 0, XMP_MAX_MOD_LENGTH);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/src/loaders/it.h 
new/libxmp-4.3.8/src/loaders/it.h
--- old/libxmp-4.3.6/src/loaders/it.h   2015-02-17 14:39:35.000000000 +0100
+++ new/libxmp-4.3.8/src/loaders/it.h   2015-03-29 18:25:45.000000000 +0200
@@ -161,7 +161,7 @@
        uint8 dosname[12];      /* DOS filename */
        uint8 zero;             /* Always zero */
        uint8 gvl;              /* Global volume for instrument */
-       uint8 flags;            /* Instrument flags */
+       uint8 flags;            /* Sample flags */
        uint8 vol;              /* Volume */
        uint8 name[26];         /* ASCIIZ sample name */
        uint8 convert;          /* Sample flags */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/src/loaders/it_load.c 
new/libxmp-4.3.8/src/loaders/it_load.c
--- old/libxmp-4.3.6/src/loaders/it_load.c      2015-03-22 01:13:24.000000000 
+0100
+++ new/libxmp-4.3.8/src/loaders/it_load.c      2015-04-04 12:51:14.000000000 
+0200
@@ -148,9 +148,14 @@
            e->fxt = FX_SETPAN;
            e->fxp = l << 4;
            break;
-       case 0x9:               /* 0x91 = set surround -- NOT IMPLEMENTED */
-           e->fxt = e->fxp = 0;
+       case 0x9:               /* 0x91 = set surround */
+            e->fxt = FX_SURROUND;
+           e->fxp = l;
            break;
+       case 0xa:               /* High offset */
+            e->fxt = FX_HIOFFSET;
+            e->fxp = l;
+            break;
        case 0xb:               /* Pattern loop */
            e->fxp = 0x60 | l;
            break;
@@ -197,7 +202,6 @@
     if (e->fxt == FX_OFFSET && e->f2t == FX_TONEPORTA) {
         e->f2t = e->f2p = 0;
     }
-
 }
 
 
@@ -354,6 +358,11 @@
     ifh.sep = hio_read8(f);
     ifh.pwd = hio_read8(f);
 
+    /* Sanity check */
+    if (ifh.gv > 0x80 || ifh.mv > 0x80) {
+        goto err;
+    }
+
     ifh.msglen = hio_read16l(f);
     ifh.msgofs = hio_read32l(f);
     ifh.rsvd = hio_read32l(f);
@@ -368,7 +377,7 @@
     mod->pat = ifh.patnum;
 
     /* Sanity check */
-    if (mod->len > 256 || mod->ins > 255 || mod->smp > 255 || mod->pat > 255) {
+    if (mod->ins > 255 || mod->smp > 255 || mod->pat > 255) {
        goto err;
     }
 
@@ -394,18 +403,19 @@
     sample_mode = ~ifh.flags & IT_USE_INST;
 
     if (ifh.flags & IT_LINEAR_FREQ) {
-       m->quirk |= QUIRK_LINEAR;
+        m->quirk |= QUIRK_LINEAR;
     }
 
     if (!sample_mode && ifh.cmwt >= 0x200) {
-       m->quirk |= QUIRK_INSVOL;
+        m->quirk |= QUIRK_INSVOL;
     }
 
     for (i = 0; i < 64; i++) {
        struct xmp_channel *xxc = &mod->xxc[i];
 
-       if (ifh.chpan[i] == 100)        /* Surround -> center */
-           ifh.chpan[i] = 32;
+       if (ifh.chpan[i] == 100) {      /* Surround -> center */
+           mod->xxc[i].flg |= XMP_CHANNEL_SURROUND;
+        }
 
        if (ifh.chpan[i] & 0x80) {      /* Channel mute */
            ifh.chvol[i] = 0;
@@ -432,13 +442,6 @@
 
     new_fx = ifh.flags & IT_OLD_FX ? 0 : 1;
 
-    /* S3M skips pattern 0xfe */
-    for (i = 0; i < (mod->len - 1); i++) {
-       if (mod->xxo[i] == 0xfe) {
-           memmove(&mod->xxo[i], &mod->xxo[i + 1], mod->len - i - 1);
-           mod->len--;
-       }
-    }
     for (i = 0; i < mod->ins; i++)
        pp_ins[i] = hio_read32l(f);
     for (i = 0; i < mod->smp; i++)
@@ -901,6 +904,11 @@
                    sub->vsw = (0xff - ish.vir) >> 1;
 
                    c2spd_to_note(ish.c5spd, &mod->xxi[j].sub[k].xpo, 
&mod->xxi[j].sub[k].fin);
+
+                    /* Set sample pan (overrides subinstrument) */
+                    if (ish.dfp & 0x80) {
+                        sub->pan = (ish.dfp & 0x7f) * 4;
+                    }
                }
            }
        }
@@ -1168,13 +1176,15 @@
        m->quirk |= QUIRK_VIBHALF | QUIRK_VIBINV;
     } else {
        m->quirk &= ~QUIRK_VIBALL;
+       m->quirk |= QUIRK_ITOLDFX;
     }
 
     if (sample_mode) {
-       m->quirk &= ~QUIRK_VIRTUAL;
+       m->quirk &= ~(QUIRK_VIRTUAL | QUIRK_RSTCHN);
     }
 
     m->gvolbase = 0x80;
+    m->gvol = ifh.gv;
     m->read_event_type = READ_EVENT_IT;
 
     return 0;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/src/loaders/mmd3_load.c 
new/libxmp-4.3.8/src/loaders/mmd3_load.c
--- old/libxmp-4.3.6/src/loaders/mmd3_load.c    2015-03-22 10:50:14.000000000 
+0100
+++ new/libxmp-4.3.8/src/loaders/mmd3_load.c    2015-04-02 02:38:02.000000000 
+0200
@@ -484,7 +484,7 @@
                        D_(D_WARN "stereo sample unsupported");
                        mod->xxi[i].nsm = 0;
                        continue;
-               } */ else if (instr.type == 0) {                /* Sample */
+               } */ else if ((instr.type & ~S_16) == 0) {      /* Sample */
                        int ret;
 
                        hio_seek(f, start + smpl_offset + 6, SEEK_SET);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/src/loaders/sample.c 
new/libxmp-4.3.8/src/loaders/sample.c
--- old/libxmp-4.3.6/src/loaders/sample.c       2015-02-17 14:39:35.000000000 
+0100
+++ new/libxmp-4.3.8/src/loaders/sample.c       2015-04-04 12:51:14.000000000 
+0200
@@ -331,7 +331,7 @@
                int x = hio_read(xxs->data, 1, bytelen, f);
                if (x != bytelen) {
                        D_(D_WARN "short read (%d) in sample load", x - 
bytelen);
-                       memset(xxs->data + x, 0, bytelen - x);
+                       return -1;
                }
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/src/loaders/st_load.c 
new/libxmp-4.3.8/src/loaders/st_load.c
--- old/libxmp-4.3.6/src/loaders/st_load.c      2015-02-17 14:39:35.000000000 
+0100
+++ new/libxmp-4.3.8/src/loaders/st_load.c      2015-03-29 18:24:13.000000000 
+0200
@@ -48,7 +48,7 @@
 static int st_test(HIO_HANDLE *f, char *t, const int start)
 {
     int i, j, k;
-    int pat, smp_size;
+    int pat, ins, smp_size;
     struct st_header mh;
     uint8 mod_event[4];
     long size;
@@ -128,18 +128,20 @@
     if (smp_size < 8)
        return -1;
 
-    if (size < (600 + pat * 1024 + smp_size))
-       return -1;
-
-    for (i = 0; i < pat; i++) {
+    for (ins = i = 0; i < pat; i++) {
        for (j = 0; j < (64 * 4); j++) {
-           int p;
+           int p, s;
        
-           hio_read (mod_event, 1, 4, f);
+           hio_read(mod_event, 1, 4, f);
+
+            s = (mod_event[0] & 0xf0) | MSN(mod_event[2]);
 
-           if (MSN(mod_event[0]))      /* sample number > 15 */
+           if (s > 15)         /* sample number > 15 */
                return -1;
 
+            if (s > ins)       /* find highest used sample */
+                ins = s;
+
            p = 256 * LSN(mod_event[0]) + mod_event[1];
 
            if (p == 0)
@@ -157,6 +159,18 @@
        }
     }
 
+    /* Check if file was cut before any unused samples */
+    if (size < 600 + pat * 1024 + smp_size) {
+        int ss;
+        for (ss = i = 0; i < ins; i++) {
+            ss += 2 * mh.ins[i].size;
+        }
+
+        if (size < 600 + pat * 1024 + ss) {
+            return -1;
+        }
+    }
+
     hio_seek(f, start, SEEK_SET);
     read_title(f, t, 20);
 
@@ -171,14 +185,18 @@
     struct xmp_event ev, *event;
     struct st_header mh;
     uint8 mod_event[4];
-    int ust = 1, serr = 0;
+    int ust = 1;
     /* int lps_mult = m->fetch & XMP_CTL_FIXLOOP ? 1 : 2; */
     char *modtype;
     int fxused;
     int pos;
+    int used_ins;              /* Number of samples actually used */
+    long size;
 
     LOAD_INIT();
 
+    size = hio_size(f);
+
     mod->ins = 15;
     mod->smp = mod->ins;
     smp_size = 0;
@@ -273,7 +291,7 @@
        for (j = 0; j < (64 * mod->chn); j++) {
            hio_read (mod_event, 1, 4, f);
 
-           decode_protracker_event (&ev, mod_event);
+           decode_protracker_event(&ev, mod_event);
 
            if (ev.fxt)
                fxused |= 1 << ev.fxt;
@@ -317,10 +335,6 @@
 
     MODULE_INFO();
 
-    if (serr) {
-       D_(D_CRIT "File size error: %d", serr);
-    }
-
     hio_seek(f, start + pos, SEEK_SET);
 
     if (pattern_init(mod) < 0)
@@ -330,6 +344,7 @@
 
     D_(D_INFO "Stored patterns: %d", mod->pat);
 
+    used_ins = 0;
     for (i = 0; i < mod->pat; i++) {
        if (pattern_tracks_alloc(mod, i, 64) < 0)
            return -1;
@@ -339,6 +354,9 @@
            hio_read (mod_event, 1, 4, f);
 
            decode_protracker_event(event, mod_event);
+
+            if (ev.ins > used_ins)
+                used_ins = ev.ins;
        }
     }
 
@@ -383,7 +401,9 @@
 
     D_(D_INFO "Stored samples: %d", mod->smp);
 
-    for (i = 0; i < mod->smp; i++) {
+    for (i = 0; i < mod->ins; i++) {
+        int val;
+
        if (!mod->xxs[i].len)
            continue;
 
@@ -400,7 +420,14 @@
         */
        hio_seek(f, mh.ins[i].loop_start, SEEK_CUR);
 
-       if (load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) {
+       val = load_sample(m, f, 0, &mod->xxs[i], NULL);
+
+        /* Samples actually used in the module are mandatory, and errors
+         * loading unused samples won't be fatal. This will allow us to load
+         * ripped modules cut after the last used sample, such as sll7.mod
+         * (reported by Shlomi Fish).
+         */
+        if (i < used_ins && val < 0) {
            return -1;
        }
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/src/mixer.c new/libxmp-4.3.8/src/mixer.c
--- old/libxmp-4.3.6/src/mixer.c        2015-03-08 00:07:10.000000000 +0100
+++ new/libxmp-4.3.8/src/mixer.c        2015-03-29 22:28:54.000000000 +0200
@@ -377,8 +377,13 @@
                vi->pos0 = vi->pos;
 
                buf_pos = s->buf32;
-               vol_r = vi->vol * (0x80 - vi->pan);
-               vol_l = vi->vol * (0x80 + vi->pan);
+               if (vi->pan == PAN_SURROUND) {
+                       vol_r = vi->vol * 0x80;
+                       vol_l = -vi->vol * 0x80;
+               } else {
+                       vol_r = vi->vol * (0x80 - vi->pan);
+                       vol_l = vi->vol * (0x80 + vi->pan);
+               }
 
 #ifndef LIBXMP_CORE_PLAYER
                if (vi->fidx & FLAG_SYNTH) {
@@ -452,10 +457,11 @@
                                }
 
 #ifndef LIBXMP_CORE_DISABLE_IT
-                               /* "Beautiful Ones" apparently uses 0xfe as
-                                * 'no filter' :\ */
-                               if (vi->filter.cutoff >= 0xfe)
+                               /* See OpenMPT env-flt-max.it */
+                               if (vi->filter.cutoff >= 0xfe &&
+                                    vi->filter.resonance == 0) {
                                        mixer &= ~FLAG_FILTER;
+                               }
 #endif
 
                                mix_fn = (*mixers)[mixer];
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/src/mixer.h new/libxmp-4.3.8/src/mixer.h
--- old/libxmp-4.3.6/src/mixer.h        2015-03-07 23:48:35.000000000 +0100
+++ new/libxmp-4.3.8/src/mixer.h        2015-03-29 18:24:13.000000000 +0200
@@ -20,6 +20,7 @@
        int root;               /* */
        unsigned int age;       /* */
        int note;               /* */
+#define PAN_SURROUND 0x8000
        int pan;                /* */
        int vol;                /* */
        int period;             /* current period */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/src/player.c 
new/libxmp-4.3.8/src/player.c
--- old/libxmp-4.3.6/src/player.c       2015-03-08 00:15:05.000000000 +0100
+++ new/libxmp-4.3.8/src/player.c       2015-04-04 00:37:53.000000000 +0200
@@ -172,6 +172,11 @@
                } else {
                        xc->split = 0;
                }
+
+               /* Surround channel */
+               if (mod->xxc[i].flg & XMP_CHANNEL_SURROUND) {
+                       xc->pan.surround = 1;
+               }
        }
 }
 
@@ -267,6 +272,9 @@
                                med_hold_hack(ctx, pat, chn, row);
 #endif
                        }
+               } else {
+                       /* Reset flags. See SlideDelay.it */
+                       p->xc_data[chn].flags = 0;
                }
        }
 }
@@ -347,6 +355,12 @@
                }
        }
 
+       if (!TEST_PER(VENV_PAUSE)) {
+               xc->v_idx = update_envelope(&instrument->aei, xc->v_idx,
+                                       DOENV_RELEASE, TEST(KEY_OFF),
+                                       m->read_event_type == READ_EVENT_IT);
+       }
+
        vol_envelope = get_envelope(&instrument->aei, xc->v_idx, 64);
        if (check_envelope_end(&instrument->aei, xc->v_idx)) {
                if (vol_envelope == 0)
@@ -354,12 +368,6 @@
                SET_NOTE(NOTE_ENV_END);
        }
 
-       if (!TEST_PER(VENV_PAUSE)) {
-               xc->v_idx = update_envelope(&instrument->aei, xc->v_idx,
-                       DOENV_RELEASE, m->read_event_type == READ_EVENT_IT);
-       }
-
-
        /* If note ended in background channel, we can safely reset it */
        if (TEST_NOTE(NOTE_END) && chn >= p->virt.num_tracks) {
                virt_resetchannel(ctx, chn);
@@ -467,11 +475,12 @@
 
        instrument = get_instrument(ctx, xc->ins);
 
-       frq_envelope = get_envelope(&instrument->fei, xc->f_idx, 0);
        if (!TEST_PER(FENV_PAUSE)) {
                xc->f_idx = update_envelope(&instrument->fei, xc->f_idx,
-                       DOENV_RELEASE, m->read_event_type == READ_EVENT_IT);
+                                       DOENV_RELEASE, TEST(KEY_OFF),
+                                       m->read_event_type == READ_EVENT_IT);
        }
+       frq_envelope = get_envelope(&instrument->fei, xc->f_idx, 0);
 
 #ifndef LIBXMP_CORE_PLAYER
        /* Do note slide */
@@ -603,11 +612,12 @@
 
        instrument = get_instrument(ctx, xc->ins);
 
-       pan_envelope = get_envelope(&instrument->pei, xc->p_idx, 32);
        if (!TEST_PER(PENV_PAUSE)) {
                xc->p_idx = update_envelope(&instrument->pei, xc->p_idx,
-                       DOENV_RELEASE, m->read_event_type == READ_EVENT_IT);
+                                       DOENV_RELEASE, TEST(KEY_OFF),
+                                       m->read_event_type == READ_EVENT_IT);
        }
+       pan_envelope = get_envelope(&instrument->pei, xc->p_idx, 32);
 
        if (TEST(PANBRELLO)) {
                panbrello = get_lfo(ctx, &xc->panbrello.lfo, 512, 0);
@@ -617,7 +627,7 @@
        finalpan = xc->pan.val + panbrello + (pan_envelope - 32) *
                                (128 - abs(xc->pan.val - 128)) / 32;
 
-       if (s->format & XMP_FORMAT_MONO) {
+       if (s->format & XMP_FORMAT_MONO || xc->pan.surround) {
                finalpan = 0;
        } else {
                finalpan = (finalpan - 0x80) * s->mix / 100;
@@ -627,7 +637,11 @@
 
        xc->info_finalpan = finalpan + 0x80;
 
-       virt_setpan(ctx, chn, finalpan);
+       if (xc->pan.surround) {
+               virt_setpan(ctx, chn, PAN_SURROUND);
+       } else {
+               virt_setpan(ctx, chn, finalpan);
+       }
 }
 
 static void update_volume(struct context_data *ctx, int chn)
@@ -835,6 +849,8 @@
                        if (xc->retrig.type < 0x10) {
                                /* don't retrig on cut */
                                virt_voicepos(ctx, chn, 0);
+                       } else {
+                               SET_NOTE(NOTE_END);
                        }
                        xc->volume += rval[xc->retrig.type].s;
                        xc->volume *= rval[xc->retrig.type].m;
@@ -863,6 +879,10 @@
        }
 #endif
 
+       if (TEST_NOTE(NOTE_SUSEXIT)) {
+               SET_NOTE(NOTE_RELEASE);
+       }
+
        xc->info_position = virt_getvoicepos(ctx, chn);
 }
 
@@ -1223,12 +1243,15 @@
                }
        }
 
-       /* check new row */
+       for (i = 0; i < mod->chn; i++) {
+               struct channel_data *xc = &p->xc_data[i];
+               RESET(KEY_OFF);
+       }
+
+       /* check new r w */
 
        if (p->frame == 0) {                    /* first frame in row */
-
                check_end_of_module(ctx);
-
                read_row(ctx, mod->xxo[p->ord], p->row);
 
 #ifndef LIBXMP_CORE_PLAYER
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/src/player.h 
new/libxmp-4.3.8/src/player.h
--- old/libxmp-4.3.6/src/player.h       2015-03-01 22:06:27.000000000 +0100
+++ new/libxmp-4.3.8/src/player.h       2015-04-04 00:18:48.000000000 +0200
@@ -56,6 +56,7 @@
 #define FENV_PAUSE     (1 << 24)
 #define FINE_VOLS_2    (1 << 25)
 #define GLISSANDO      (1 << 26)
+#define KEY_OFF                (1 << 27)       /* for IT release on envloop 
end */
 
 #define NOTE_FADEOUT   (1 << 0)
 #define NOTE_RELEASE   (1 << 1)
@@ -64,6 +65,7 @@
 #define NOTE_ENV_END   (1 << 4)
 #define NOTE_SAMPLE_END        (1 << 5)
 #define NOTE_SET       (1 << 6)        /* for IT portamento after keyoff */
+#define NOTE_SUSEXIT   (1 << 7)        /* for delayed note release */
 
 #define IS_VALID_INSTRUMENT(x) ((uint32)(x) < mod->ins && mod->xxi[(x)].nsm > 
0)
 #define IS_VALID_INSTRUMENT_OR_SFX(x) (((uint32)(x) < mod->ins && 
mod->xxi[(x)].nsm > 0) || (smix->ins > 0 && (uint32)(x) < mod->ins + smix->ins))
@@ -98,6 +100,8 @@
        int p_idx;              /* Pan envelope index */
        int f_idx;              /* Freq envelope index */
 
+       int key_porta;          /* Key number for portamento target
+                                * -- needed to handle IT portamento xpo */
        struct {
                struct lfo lfo;
                int memory;
@@ -196,6 +200,7 @@
                int slide;      /* Pan slide value */
                int fslide;     /* Pan fine slide value */
                int memory;     /* Pan slide effect memory */
+               int surround;   /* Surround channel flag */
        } pan;  
 
        struct {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libxmp-4.3.6/src/read_event.c 
new/libxmp-4.3.8/src/read_event.c
--- old/libxmp-4.3.6/src/read_event.c   2015-03-02 01:32:00.000000000 +0100
+++ new/libxmp-4.3.8/src/read_event.c   2015-04-04 00:37:14.000000000 +0200
@@ -42,6 +42,16 @@
        }
 }
 
+static inline int has_note_event(struct xmp_event *e)
+{
+       return (e->note && e->note <= XMP_MAX_KEYS);
+}
+
+static inline int is_valid_note(int note)
+{
+       return (note >= 0 && note < XMP_MAX_KEYS);
+}
+
 static struct xmp_subinstrument *get_subinstrument(struct context_data *ctx,
                                                   int ins, int key)
 {
@@ -51,7 +61,7 @@
 
        if (IS_VALID_INSTRUMENT(ins)) {
                instrument = &mod->xxi[ins];
-               if (key >= 0 && key < XMP_MAX_KEYS) {
+               if (is_valid_note(key)) {
                        int mapped = instrument->map[key].ins;
                        if (mapped != 0xff && mapped >= 0 && mapped < 
instrument->nsm)
                                return &instrument->sub[mapped];
@@ -71,9 +81,9 @@
 
        RESET_NOTE(NOTE_ENV_END);
 
-       xc->v_idx = 0;
-       xc->p_idx = 0;
-       xc->f_idx = 0;
+       xc->v_idx = -1;
+       xc->p_idx = -1;
+       xc->f_idx = -1;
 }
 
 #ifndef LIBXMP_CORE_DISABLE_IT
@@ -94,18 +104,13 @@
 
        /* Reset envelope positions */
        if (~xxi->aei.flg & XMP_ENVELOPE_CARRY) {
-               xc->v_idx = 0;
+               xc->v_idx = -1;
        }
        if (~xxi->pei.flg & XMP_ENVELOPE_CARRY) {
-               xc->p_idx = 0;
+               xc->p_idx = -1;
        }
-
-       if (xxi->fei.flg & XMP_ENVELOPE_CARRY) {
-               if (check_envelope_end(&xxi->fei, xc->f_idx)) {
-                       xc->f_idx = -1;
-               }
-       } else {
-               xc->f_idx = 0;
+       if (~xxi->fei.flg & XMP_ENVELOPE_CARRY) {
+               xc->f_idx = -1;
        }
 }
 
@@ -236,7 +241,7 @@
                if (IS_VALID_INSTRUMENT(ins)) {
                        if (is_toneporta) {
                                /* Get new instrument volume */
-                               sub = get_subinstrument(ctx, ins, e->note);
+                               sub = get_subinstrument(ctx, ins, e->note - 1);
                                if (sub != NULL) {
                                        xc->volume = sub->vol;
                                        use_ins_vol = 0;
@@ -328,6 +333,14 @@
        return 0;
 }
 
+static int sustain_check(struct xmp_envelope *env, int idx)
+{
+       return (env &&
+               (env->flg & XMP_ENVELOPE_ON) &&
+               (~env->flg & XMP_ENVELOPE_LOOP) &&
+               idx == env->data[env->sus << 1]);
+}
+
 static int read_event_ft2(struct context_data *ctx, struct xmp_event *e, int 
chn)
 {
        struct player_data *p = &ctx->p;
@@ -419,7 +432,7 @@
                use_ins_vol = 1;
                xc->fadeout = 0x10000;
                xc->per_flags = 0;
-               RESET_NOTE(NOTE_RELEASE);
+               RESET_NOTE(NOTE_RELEASE|NOTE_SUSEXIT);
                if (!k00) {
                        RESET_NOTE(NOTE_FADEOUT);
                }
@@ -474,6 +487,7 @@
                        int env_on = 0;
                        int vol_set = ev.vol != 0 || ev.fxt == FX_VOLSET;
                        int delay_fx = ev.fxt == FX_EXTENDED && ev.fxp == 0xd0;
+                       struct xmp_envelope *env = NULL;
 
                        /* OpenMPT NoteOffVolume.xm:
                         * "If an instrument has no volume envelope, a note-off
@@ -484,13 +498,23 @@
                         * ...and unless we have a keyoff+delay without setting
                         * an instrument. See OffDelay.xm.
                         */
-                       if (IS_VALID_INSTRUMENT(xc->ins) &&
-                           (mod->xxi[xc->ins].aei.flg & XMP_ENVELOPE_ON)) {
-                               env_on = 1;
+                       if (IS_VALID_INSTRUMENT(xc->ins)) {
+                               env = &mod->xxi[xc->ins].aei;
+                               if (env->flg & XMP_ENVELOPE_ON) {
+                                       env_on = 1;
+                               }
                        }
                        
                        if (env_on || (!vol_set && (!ev.ins || !delay_fx))) {
-                               SET_NOTE(NOTE_RELEASE);
+                               if (sustain_check(env, xc->v_idx)) {
+                                       /* See OpenMPT EnvOff.xm. In certain
+                                        * cases a release event is effective
+                                        * only in the next frame
+                                        */
+                                       SET_NOTE(NOTE_SUSEXIT);
+                               } else {
+                                       SET_NOTE(NOTE_RELEASE);
+                               }
                                use_ins_vol = 0;
                        } else {
                                SET_NOTE(NOTE_FADEOUT);
@@ -501,7 +525,7 @@
                            (ev.fxp >> 4) == EX_DELAY) {
                                /* See OpenMPT OffDelay.xm test case */
                                if ((ev.fxp & 0xf) != 0) {
-                                       RESET_NOTE(NOTE_RELEASE);
+                                       RESET_NOTE(NOTE_RELEASE|NOTE_SUSEXIT);
                                }
                        }
                } else if (key == XMP_KEY_FADE) {
@@ -536,7 +560,7 @@
         *  memory). The instrument number next it, however, is not affected
         *  and remains in the memory."
         */
-       if (key > 0 && (uint32)key <= XMP_MAX_KEYS) {
+       if (is_valid_note(key - 1)) {
                int k = key - 1;
                sub = get_subinstrument(ctx, xc->ins, k);
                if (!new_invalid_ins && sub != NULL) {
@@ -549,7 +573,7 @@
                }
        }
 
-       if (key > 0 && (uint32)key <= XMP_MAX_KEYS) {
+       if (is_valid_note(key - 1)) {
                xc->key = --key;
                xc->fadeout = 0x10000;
                RESET_NOTE(NOTE_END);
@@ -689,7 +713,7 @@
                                        xc->ins_fade = mod->xxi[ins].rls;
                                } else {
                                        /* Get new instrument volume */
-                                       sub = get_subinstrument(ctx, ins, 
e->note);
+                                       sub = get_subinstrument(ctx, ins, 
e->note - 1);
                                        if (sub != NULL) {
                                                xc->volume = sub->vol;
                                                use_ins_vol = 0;
@@ -789,6 +813,35 @@
 
 #ifndef LIBXMP_CORE_DISABLE_IT
 
+static int check_fadeout(struct context_data *ctx, struct channel_data *xc, 
int ins)
+{
+       struct xmp_instrument *xxi = get_instrument(ctx, ins);
+
+       if (xxi == NULL) {
+               return 1;
+       }
+
+       return (~xxi->aei.flg & XMP_ENVELOPE_ON ||
+               ~xxi->aei.flg & XMP_ENVELOPE_CARRY ||
+               xc->ins_fade == 0 ||
+               xc->fadeout <= xc->ins_fade);
+}
+
+static int check_invalid_sample(struct context_data *ctx, int ins, int key)
+{
+       struct module_data *m = &ctx->m;
+       struct xmp_module *mod = &m->mod;
+
+       if (ins < mod->ins) {
+               int smp = mod->xxi[ins].map[key].ins;
+               if (smp == 0xff || smp >= mod->smp) {
+                       return 1;
+               };
+       }
+
+       return 0;
+}
+
 static int read_event_it(struct context_data *ctx, struct xmp_event *e, int 
chn)
 {
        struct player_data *p = &ctx->p;
@@ -803,6 +856,7 @@
        int candidate_ins;
        int reset_env;
        int use_ins_vol;
+       int sample_mode;
        struct xmp_event ev;
 
        memcpy(&ev, e, sizeof (struct xmp_event));
@@ -815,6 +869,14 @@
                xc->delayed_ins = 0;
        }
 
+       /* Keyoff + instrument retrigs current instrument in old fx mode */
+       if (HAS_QUIRK(QUIRK_ITOLDFX)) {
+               if (ev.note == XMP_KEY_OFF && IS_VALID_INSTRUMENT(ev.ins -1)) {
+                       ev.note = xc->key + 1;
+                       ev.ins = xc->ins + 1;
+               }
+       }
+
        xc->flags = 0;
        note = -1;
        key = ev.note;
@@ -825,25 +887,24 @@
        reset_env = 0;
        use_ins_vol = 0;
        candidate_ins = xc->ins;
+       sample_mode = !HAS_QUIRK(QUIRK_VIRTUAL);
 
        /* Notes with unmapped instruments are ignored */
        if (ev.ins) {
-               if (ev.ins <= mod->ins && ev.note && ev.note <= XMP_MAX_KEYS) {
+               if (ev.ins <= mod->ins && has_note_event(&ev)) {
                        int ins = ev.ins - 1;
-                       int key = ev.note - 1;
-
-                       if (ins < mod->ins) {
-                               int smp = mod->xxi[ins].map[key].ins;
-                               if (smp == 0xff || smp >= mod->smp) {
-                                       candidate_ins = ins;
-                                       memset(&ev, 0, sizeof (ev));
-                               };
+                       if (check_invalid_sample(ctx, ins, ev.note - 1)) {
+                               candidate_ins = ins;
+                               memset(&ev, 0, sizeof (ev));
                        }
                }
        } else {
-               if (ev.note && ev.note <= XMP_MAX_KEYS) {
-                       if (!IS_VALID_INSTRUMENT(xc->old_ins - 1)) {
+               if (has_note_event(&ev)) {
+                       int ins = xc->old_ins - 1;
+                       if (!IS_VALID_INSTRUMENT(ins)) {
                                new_invalid_ins = 1;
+                       } else if (check_invalid_sample(ctx, ins, ev.note - 1)) 
{
+                               memset(&ev, 0, sizeof (ev));
                        }
                }
        }
@@ -856,10 +917,6 @@
                is_release = 1;
        }
 
-       if (!HAS_QUIRK(QUIRK_VIRTUAL) && virt_mapchannel(ctx, chn) < 0) {
-               is_toneporta = 0;
-       }
-
        if (xc->period <= 0 || TEST_NOTE(NOTE_END)) {
                is_toneporta = 0;
        }
@@ -913,6 +970,11 @@
                        /* valid ins */
 
                        if (!key) {
+                               /* Retrig in new ins in sample mode */
+                               if (sample_mode && TEST_NOTE(NOTE_END)) {
+                                       virt_voicepos(ctx, chn, 0);
+                               }
+
                                /* IT: Reset note for every new != ins */
                                if (xc->ins == ins) {
                                        SET(NEW_INS);
@@ -923,6 +985,7 @@
 
                                RESET_NOTE(NOTE_SET);
                        }
+
                        if (xc->ins != ins && (!is_toneporta || 
!HAS_QUIRK(QUIRK_PRENV))) {
                                struct xmp_subinstrument *s1, *s2;
                                s1 = get_subinstrument(ctx, xc->ins, xc->key);
@@ -943,6 +1006,11 @@
                                }
                        }
                } else {
+                       /* In sample mode invalid ins cut previous ins */
+                       if (sample_mode) {
+                               xc->volume = 0;
+                       }
+
                        /* Ignore invalid instruments */
                        new_invalid_ins = 1;
                        xc->flags = 0;
@@ -965,7 +1033,16 @@
                        xc->period = 0;
                        virt_resetchannel(ctx, chn);
                } else if (key == XMP_KEY_OFF) {
-                       SET_NOTE(NOTE_RELEASE);
+                       struct xmp_envelope *env = NULL;
+                       if (IS_VALID_INSTRUMENT(xc->ins)) {
+                               env = &mod->xxi[xc->ins].aei;
+                       }
+                       if (sustain_check(env, xc->v_idx)) {
+                               SET_NOTE(NOTE_SUSEXIT);
+                       } else {
+                               SET_NOTE(NOTE_RELEASE);
+                       }
+                       SET(KEY_OFF);
                        reset_env = 0;
                        use_ins_vol = 0;
                } else {
@@ -978,15 +1055,18 @@
                                 */
                                if (not_same_ins || TEST_NOTE(NOTE_END)) {
                                        SET(NEW_INS);
-                                       RESET_NOTE(NOTE_RELEASE|NOTE_FADEOUT);
+                                       
RESET_NOTE(NOTE_RELEASE|NOTE_SUSEXIT|NOTE_FADEOUT);
                                } else {
+                                       if (is_valid_note(key - 1)) {
+                                               xc->key_porta = key - 1;
+                                       }
                                        key = 0;
                                }
                        }
                }
        }
 
-       if ((uint32)key <= XMP_MAX_KEYS && key > 0 && !new_invalid_ins) {
+       if (is_valid_note(key - 1) && !new_invalid_ins) {
                xc->key = --key;
                RESET_NOTE(NOTE_END);
 
@@ -1029,14 +1109,6 @@
                }
        }
 
-       /* Reset in case of new instrument and the previous envelope has
-        * finished (OpenMPT test EnvReset.it). This must take place after
-        * channel copies in case of NNA (see test/test.it)
-        */
-       if (ev.ins && TEST_NOTE(NOTE_ENV_END)) {
-               reset_envelopes(ctx, xc);
-       }
-
        if (IS_VALID_INSTRUMENT(candidate_ins)) {
                if (xc->ins != candidate_ins) {
                        /* Reset envelopes if instrument changes */
@@ -1046,6 +1118,19 @@
                xc->ins_fade = mod->xxi[candidate_ins].rls;
        }
 
+       /* Reset in case of new instrument and the previous envelope has
+        * finished (OpenMPT test EnvReset.it). This must take place after
+        * channel copies in case of NNA (see test/test.it)
+        * Also if we have envelope in carry mode, check fadeout
+        */
+       if (ev.ins && TEST_NOTE(NOTE_ENV_END)) {
+               if (check_fadeout(ctx, xc, candidate_ins)) {
+                       reset_envelopes(ctx, xc);
+               } else {
+                       reset_env = 0;
+               }
+       }
+
        sub = get_subinstrument(ctx, xc->ins, xc->key);
 
        set_effect_defaults(ctx, note, sub, xc, is_toneporta);
@@ -1054,8 +1139,11 @@
                        int pan_swing = (sub->rvv & 0xff00) >> 8;
                        CLAMP(pan_swing, 0, 64);
 
-                       if (sub->pan >= 0)
+                       if (sub->pan >= 0) {
                                xc->pan.val = sub->pan;
+                               xc->pan.surround = 0;
+                       }
+
                        if (TEST_NOTE(NOTE_CUT)) {
                                reset_envelopes(ctx, xc);
                        } else {
@@ -1074,16 +1162,16 @@
        }
        
        /* Process new volume */
-       if (ev.vol) {
+       if (ev.vol && (!TEST_NOTE(NOTE_CUT) || ev.ins != 0)) {
                xc->volume = ev.vol - 1;
                SET(NEW_VOL);
        }
 
        /* IT: always reset sample offset */
-       xc->offset.val = 0;
+       xc->offset.val &= ~0xffff;
 
        /* According to Storlek test 25, Impulse Tracker handles the volume
-        * column effects last.
+        * column effects after the standard effects.
         */
        process_fx(ctx, xc, chn, &ev, 0);
        process_fx(ctx, xc, chn, &ev, 1);
@@ -1100,7 +1188,7 @@
 
        if (reset_env) {
                if (ev.note) {
-                       RESET_NOTE(NOTE_RELEASE | NOTE_FADEOUT);
+                       RESET_NOTE(NOTE_RELEASE|NOTE_SUSEXIT|NOTE_FADEOUT);
                }
                /* Set after copying to new virtual channel (see ambio.it) */
                xc->fadeout = 0x10000;
@@ -1113,8 +1201,8 @@
                xc->volume = sub->vol;
 
                if (vol_swing) {
-                       xc->volume = (xc->volume *
-                               (rand() % 65) * vol_swing) / (64 * 100);
+                       xc->volume = (xc->volume * (100 - vol_swing) + 
+                               (rand() % (xc->volume + 1)) * vol_swing) / 100;
                }
        }
 
@@ -1160,7 +1248,7 @@
                if (IS_VALID_INSTRUMENT(ins)) {
                        if (is_toneporta) {
                                /* Get new instrument volume */
-                               sub = get_subinstrument(ctx, ins, e->note);
+                               sub = get_subinstrument(ctx, ins, e->note - 1);
                                if (sub != NULL) {
                                        xc->volume = sub->vol;
                                        use_ins_vol = 0;
@@ -1368,6 +1456,10 @@
        if (e->ins != 0)
                xc->old_ins = e->ins;
 
+       if (TEST_NOTE(NOTE_SAMPLE_END)) {
+               SET_NOTE(NOTE_END);
+       }
+
        if (chn >= m->mod.chn) {
                return read_event_smix(ctx, e, chn);
        } else switch (m->read_event_type) {
Files old/libxmp-4.3.6/test/test.itz and new/libxmp-4.3.8/test/test.itz differ


Reply via email to