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