changeset 224:81f3993412ae

Move jmpProcessRowEffect() into jmpProcessNewRow(); Fix volume-column tone portamento ('M') effect, the parameter must be * 16. Improve retrig note E9x, so that it also triggers on E90 aka tick 0. Fix tone portamento (and volume column tone portamento) to work with retrig note and multi-retrig.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 08 Oct 2012 00:44:40 +0300
parents 9fa8e9326d18
children 83f942efc55d
files jssplr.c jssplr.h
diffstat 2 files changed, 162 insertions(+), 157 deletions(-) [+]
line wrap: on
line diff
--- a/jssplr.c	Mon Oct 08 00:20:20 2012 +0300
+++ b/jssplr.c	Mon Oct 08 00:44:40 2012 +0300
@@ -815,11 +815,160 @@
 /*
  * Process pattern effects
  */
-static void jmpProcessRowEffect(JSSPlayer * mp, int channel, JSSNote * currNote)
+static void jmpTriggerNote(JSSPlayer * mp, JSSPlayerChannel *chn, BOOL newExtInstrument)
 {
+    if (chn->nextInstrument >= 0 &&
+        chn->nextInstrument < mp->module->nextInstruments &&
+        mp->module->extInstruments[chn->nextInstrument] != NULL)
+    {
+        chn->extInstrument = mp->module->extInstruments[chn->nextInstrument];
+    }
+    else
+    {
+        chn->extInstrument = NULL;
+        chn->instrument = NULL;
+        chn->ninstrument = jsetNotSet;
+    }
+
+    if (chn->extInstrument != NULL)
+    {
+        int tmp = chn->extInstrument->sNumForNotes[chn->note];
+
+        if (tmp >= 0 && tmp < mp->module->ninstruments &&
+            mp->module->instruments[tmp] != NULL)
+        {
+            if (chn->ninstrument != tmp)
+                JMPSETNDFLAGS(cdfNewInstr);
+
+            chn->ninstrument = tmp;
+            chn->instrument  = mp->module->instruments[chn->ninstrument];
+
+            if (newExtInstrument)
+            {
+                chn->volume      = chn->instrument->volume;
+                chn->panning     = chn->instrument->EPanning;
+                JMPSETNDFLAGS(cdfNewPanPos | cdfNewVolume);
+            }
+        }
+    }
+
+    if (chn->instrument != NULL)
+    {
+        int tmp;
+        JSSInstrument *inst = chn->instrument;
+
+        // Save old pitch for later use
+        chn->oldPitch = chn->pitch;
+
+        chn->position = 0;
+
+        // Compute new pitch
+        tmp = dmClamp(chn->note + inst->ERelNote, 0, 119);
+        chn->pitch = jmpGetPeriodFromNote(mp, tmp, inst->EFineTune);
+        JMPSETNDFLAGS(cdfNewPitch | cdfPlay | cdfNewPos);
+    }
+    else
+    {
+        chn->volume = 0;
+        chn->panning = jchPanMiddle;
+        JMPSETNDFLAGS(cdfStop | cdfNewPanPos | cdfNewVolume);
+    }
+}
+
+
+static void jmpProcessNewRow(JSSPlayer * mp, int channel)
+{
+    JSSNote *currNote;
+    BOOL newNote = FALSE, newExtInstrument = FALSE;
+    char effect;
+    int param, paramX, paramY;
     JSSPlayerChannel *chn = &(mp->channels[channel]);
-    int param, paramX, paramY;
-    char effect;
+
+    JMPGETNOTE(currNote, mp->row, channel);
+
+    // Check for a new note/keyoff here
+    if (currNote->note == jsetNoteOff)
+        chn->keyOff = TRUE;
+    else
+    if (currNote->note >= 0 && currNote->note <= 96)
+    {
+        newNote = TRUE;
+        chn->oldNote = chn->note;
+        chn->note = currNote->note;
+        chn->keyOff = FALSE;
+    }
+
+    // Check for new instrument
+    if (currNote->instrument != jsetNotSet)
+    {
+        /* Envelopes and ext.instrument fadeout are initialized always if
+         * new instrument is set, even if the instrument does not exist.
+         */
+        jmpResetEnvelope(&chn->volumeEnv);
+        jmpResetEnvelope(&chn->panningEnv);
+        chn->keyOff = FALSE;
+        chn->fadeOutVol = mpMaxFadeoutVol;
+
+        JMPSETNDFLAGS(cdfNewPanPos | cdfPlay | cdfNewVolume);
+
+        // We save the instrument number here for later use
+        chn->nextInstrument = currNote->instrument;
+        newExtInstrument = TRUE;
+    }
+
+    if (newNote)
+    {
+        jmpTriggerNote(mp, chn, newExtInstrument);
+    }
+
+    // Process the volume column
+    JMPMAKEPARAM(currNote->volume, paramX, paramY);
+
+    switch (paramX)
+    {
+        case 0x0:
+        case 0x1:
+        case 0x2:
+        case 0x3:
+        case 0x4:
+            jmpSetVolume(chn, channel, currNote->volume);
+            break;
+
+        case 0x7:        // Dx = Fine Volumeslide Down : IMPL.VERIFIED
+            jmpChangeVolume(chn, channel, -paramY);
+            break;
+
+        case 0x8:        // Ux = Fine Volumeslide Up : IMPL.VERIFIED
+            jmpChangeVolume(chn, channel, paramY);
+            break;
+
+        case 0x9:        // Sx = Set vibrato speed : IMPL.VERIFIED
+            chn->vibrato.speed = paramY;
+            break;
+
+        case 0xa:        // Vx = Vibrato : IMPL.VERIFIED
+            if (paramY)
+                chn->vibrato.depth = paramY;
+            break;
+
+        case 0xe:        // Mx = Porta To Note : IMPL.VERIFIED
+            if (paramY)
+                chn->iLastPortaToNoteParam = paramY * 16;
+
+            if (currNote->note != jsetNotSet && currNote->note != jsetNoteOff)
+            {
+                chn->lastPortaToNoteNote = chn->note;
+                chn->iLastPortaToNotePitch = chn->pitch;
+                chn->pitch = chn->oldPitch;
+                chn->note = chn->oldNote;
+                JMPUNSETNDFLAGS(cdfNewPitch | cdfPlay);
+            }
+            break;
+    }
+
+    // ...And finally process the Normal effects
+    if (currNote->effect == jsetNotSet)
+        return;
 
     param = currNote->param;
     JMPMAKEPARAM(param, paramX, paramY);
@@ -848,9 +997,11 @@
 
             if (currNote->note != jsetNotSet && currNote->note != jsetNoteOff)
             {
+                chn->lastPortaToNoteNote = chn->note;
                 chn->iLastPortaToNotePitch = chn->pitch;
                 chn->pitch = chn->oldPitch;
-                JMPUNSETNDFLAGS(cdfNewPitch);
+                chn->note = chn->oldNote;
+                JMPUNSETNDFLAGS(cdfNewPitch | cdfPlay);
             }
             break;
 
@@ -972,6 +1123,11 @@
                 JMPSETNDFLAGS(cdfNewPanPos);
                 break;
 
+            case 0x09:    // E9x - Retrig note
+                if (mp->tick == paramY)
+                    jmpTriggerNote(mp, chn, FALSE);
+                break;
+
             case 0x0a:    // EAx - Fine Volumeslide Up
                 if (paramY)
                     chn->iCLastFineVolumeslideUpParam = paramY;
@@ -1085,159 +1241,6 @@
 }
 
 
-static void jmpTriggerNote(JSSPlayer * mp, JSSPlayerChannel *chn, BOOL newExtInstrument)
-{
-    if (chn->nextInstrument >= 0 &&
-        chn->nextInstrument < mp->module->nextInstruments &&
-        mp->module->extInstruments[chn->nextInstrument] != NULL)
-    {
-        chn->extInstrument = mp->module->extInstruments[chn->nextInstrument];
-    }
-    else
-    {
-        chn->extInstrument = NULL;
-        chn->instrument = NULL;
-        chn->ninstrument = jsetNotSet;
-    }
-
-    if (chn->extInstrument != NULL)
-    {
-        int tmp = chn->extInstrument->sNumForNotes[chn->note];
-
-        if (tmp >= 0 && tmp < mp->module->ninstruments &&
-            mp->module->instruments[tmp] != NULL)
-        {
-            if (chn->ninstrument != tmp)
-                JMPSETNDFLAGS(cdfNewInstr);
-
-            chn->ninstrument = tmp;
-            chn->instrument  = mp->module->instruments[chn->ninstrument];
-
-            if (newExtInstrument)
-            {
-                chn->volume      = chn->instrument->volume;
-                chn->panning     = chn->instrument->EPanning;
-                JMPSETNDFLAGS(cdfNewPanPos | cdfNewVolume);
-            }
-        }
-    }
-
-    if (chn->instrument != NULL)
-    {
-        int tmp;
-        JSSInstrument *inst = chn->instrument;
-
-        // Save old pitch for later use
-        chn->oldPitch = chn->pitch;
-
-        chn->position = 0;
-
-        // Compute new pitch
-        tmp = dmClamp(chn->note + inst->ERelNote, 0, 119);
-        chn->pitch = jmpGetPeriodFromNote(mp, tmp, inst->EFineTune);
-        JMPSETNDFLAGS(cdfNewPitch | cdfPlay | cdfNewPos);
-    }
-    else
-    {
-        chn->volume = 0;
-        chn->panning = jchPanMiddle;
-        JMPSETNDFLAGS(cdfStop | cdfNewPanPos | cdfNewVolume);
-    }
-}
-
-
-static void jmpProcessNewRow(JSSPlayer * mp, int channel)
-{
-    JSSNote *currNote;
-    BOOL newNote = FALSE, newExtInstrument = FALSE;
-    int paramX, paramY;
-    JSSPlayerChannel *chn = &(mp->channels[channel]);
-
-    JMPGETNOTE(currNote, mp->row, channel);
-
-    // Check for a new note/keyoff here
-    if (currNote->note == jsetNoteOff)
-        chn->keyOff = TRUE;
-    else
-    if (currNote->note >= 0 && currNote->note <= 96)
-    {
-        newNote = TRUE;
-        chn->note = currNote->note;
-        chn->keyOff = FALSE;
-    }
-
-    // Check for new instrument
-    if (currNote->instrument != jsetNotSet)
-    {
-        /* Envelopes and ext.instrument fadeout are initialized always if
-         * new instrument is set, even if the instrument does not exist.
-         */
-        jmpResetEnvelope(&chn->volumeEnv);
-        jmpResetEnvelope(&chn->panningEnv);
-        chn->keyOff = FALSE;
-        chn->fadeOutVol = mpMaxFadeoutVol;
-
-        JMPSETNDFLAGS(cdfNewPanPos | cdfPlay | cdfNewVolume);
-
-        // We save the instrument number here for later use
-        chn->nextInstrument = currNote->instrument;
-        newExtInstrument = TRUE;
-    }
-
-    if (newNote)
-    {
-        jmpTriggerNote(mp, chn, newExtInstrument);
-    }
-
-    // Process the volume column
-    JMPMAKEPARAM(currNote->volume, paramX, paramY);
-
-    switch (paramX)
-    {
-        case 0x0:
-        case 0x1:
-        case 0x2:
-        case 0x3:
-        case 0x4:
-            jmpSetVolume(chn, channel, currNote->volume);
-            break;
-
-        case 0x7:        // Dx = Fine Volumeslide Down : IMPL.VERIFIED
-            jmpChangeVolume(chn, channel, -paramY);
-            break;
-
-        case 0x8:        // Ux = Fine Volumeslide Up : IMPL.VERIFIED
-            jmpChangeVolume(chn, channel, paramY);
-            break;
-
-        case 0x9:        // Sx = Set vibrato speed : IMPL.VERIFIED
-            chn->vibrato.speed = paramY;
-            break;
-
-        case 0xa:        // Vx = Vibrato : IMPL.VERIFIED
-            if (paramY)
-                chn->vibrato.depth = paramY;
-            break;
-
-        case 0xe:        // Mx = Porta To Note : IMPL.VERIFIED
-            if (paramY)
-                chn->iLastPortaToNoteParam = paramY;
-
-            if (currNote->note != jsetNotSet && currNote->note != jsetNoteOff)
-            {
-                chn->iLastPortaToNotePitch = chn->pitch;
-                chn->pitch = chn->oldPitch;
-                JMPUNSETNDFLAGS(cdfNewPitch | cdfPlay);
-            }
-            break;
-    }
-
-    // ...And finally process the Normal effects
-    if (currNote->effect != jsetNotSet)
-        jmpProcessRowEffect(mp, channel, currNote);
-}
-
-
 static void jmpProcessEffects(JSSPlayer * mp, int channel)
 {
     JSSPlayerChannel *chn = &(mp->channels[channel]);
--- a/jssplr.h	Mon Oct 08 00:20:20 2012 +0300
+++ b/jssplr.h	Mon Oct 08 00:44:40 2012 +0300
@@ -63,6 +63,7 @@
             pitch,                // Pitch (NOT actual frequency!)
             freq, cfreq,
             oldPitch,
+            oldNote,
             position,             // Sample position
             volume,               // Volume
             panning,              // Panning position
@@ -86,6 +87,7 @@
             iLastPortaParam,        // Last portamento effect parameter
             iLastPortaToNoteParam,  // Last porta-to-note parameter
             iLastPortaToNotePitch,  // Last porta-to-note pitch
+            lastPortaToNoteNote,
 
             iLastTremorParam,
             iTremorCount,