changeset 55:e0e470c3fc8e

Initial round of cleaning up the player code a bit.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 01 Oct 2012 06:28:29 +0300
parents 65cdb4de6fd8
children 8725853609db
files jssplr.c jssplr.h testpl.c
diffstat 3 files changed, 372 insertions(+), 434 deletions(-) [+]
line wrap: on
line diff
--- a/jssplr.c	Mon Oct 01 04:18:15 2012 +0300
+++ b/jssplr.c	Mon Oct 01 06:28:29 2012 +0300
@@ -90,7 +90,7 @@
 static void jmpCSetPitch(JSSPlayer *mp, int channel, int value)
 {
     assert(mp != NULL);
-    assert(mp->pDevice != NULL);
+    assert(mp->device != NULL);
 
     if (value > 0)
     {
@@ -98,90 +98,54 @@
         {
             // Frequency = 8363*1712 / Period
 //fprintf(stderr, "jmpCSetPitch::AMIGA(%d, %d)\n", channel, value);
-            jvmSetFreq(mp->pDevice, channel, 14317456.0f / (double) value);
+            jvmSetFreq(mp->device, channel, 14317456.0f / (double) value);
         }
         else
         {
             // Frequency = Frequency = 8363*2^((6*12*16*4 - Period) / (12*16*4))
 //fprintf(stderr, "jmpCSetPitch::Linear(%d, %d)\n", channel, value);
-            jvmSetFreq(mp->pDevice, channel,
+            jvmSetFreq(mp->device, channel,
                 8363.0f * pow(2.0f, (4608.0f - (double) value) / 768.0f));
         }
     }
 }
 
 
-static void jmpCSetInstrument(JSSPlayer * mp, int channel)
+static void jmpCSetVolume(JSSPlayer * mp, JSSPlayerChannel *chn, int channel, int volume)
 {
-    JSSInstrument *instr;
     assert(mp != NULL);
-    assert(mp->pDevice != NULL);
-
-    instr = mp->iCInstrument[channel];
+    assert(mp->device != NULL);
 
-    if (instr)
-    {
-        jvmSetSample(mp->pDevice, channel,
-            instr->data, instr->size,
-            instr->loopS, instr->loopE,
-            instr->flags);
-    }
+    if (volume < mpMinVol) volume = mpMinVol; else
+    if (volume > mpMaxVol) volume = mpMaxVol;
+
+//fprintf(stderr, "chn %d: vol=%d, fad=%d, env=%d\n", channel, volume, chn->iCFadeOutVol, chn->iCVolEnv);
+
+    jvmSetVolume(mp->device, channel,
+        (chn->iCFadeOutVol * chn->iCVolEnv * volume) / (16 * 65536));
 }
 
 
-static void jmpCSetVolume(JSSPlayer * mp, int channel, int volume)
+static void jmpCSetPanning(JSSPlayer * mp, JSSPlayerChannel *chn, int channel, int panning)
 {
     assert(mp != NULL);
-    assert(mp->pDevice != NULL);
-    if (volume < 0) volume = 0; else
-    if (volume > 64) volume = 64;
-
-//fprintf(stderr, "chn %d: vol=%d, fad=%d, env=%d\n", channel, volume, mp->iCFadeOutVol[channel], mp->iCVolEnv[channel]);
+    assert(mp->device != NULL);
 
-    jvmSetVolume(mp->pDevice, channel,
-        (mp->iCFadeOutVol[channel] * mp->iCVolEnv[channel] * volume) / (16 * 65536));
-}
-
-
-static void jmpCSetPanning(JSSPlayer * mp, int channel, int panning)
-{
-    assert(mp != NULL);
-    assert(mp->pDevice != NULL);
-
-    jvmSetPan(mp->pDevice, channel,
-        panning + (((mp->iCPanEnv[channel] - 32) * (128 - abs(panning - 128))) / 32));
+    jvmSetPan(mp->device, channel,
+        panning + (((chn->iCPanEnv - 32) * (128 - abs(panning - 128))) / 32));
 }
 
 
 static void jmpCSetPosition(JSSPlayer * mp, int channel, int value)
 {
     assert(mp != NULL);
-    assert(mp->pDevice != NULL);
+    assert(mp->device != NULL);
 
-    jvmSetPos(mp->pDevice, channel, value);
+    jvmSetPos(mp->device, channel, value);
 }
 
 
-static void jmpCPlay(JSSPlayer * mp, int channel)
-{
-    assert(mp != NULL);
-    assert(mp->pDevice != NULL);
-
-    jvmPlay(mp->pDevice, channel);
-}
-
-
-static void jmpCStop(JSSPlayer * mp, int channel)
-{
-    assert(mp != NULL);
-    assert(mp->pDevice != NULL);
-
-    jvmStop(mp->pDevice, channel);
-}
-
-
-
-static int jmpFindEnvPoint(JSSEnvelope * env, int pos)
+static int jmpFindEnvPoint(JSSEnvelope * env, const int pos)
 {
     int i;
     
@@ -241,9 +205,9 @@
 }
 
 
-static void jmpProcessExtInstrument(JSSPlayer * mp, int channel)
+static void jmpProcessExtInstrument(JSSPlayer * mp, JSSPlayerChannel *chn, int channel)
 {
-    JSSExtInstrument *inst = mp->iCExtInstrument[channel];
+    JSSExtInstrument *inst = chn->iCExtInstrument;
 
     // Get the instrument for envelope data
     if (!inst) return;
@@ -257,21 +221,22 @@
     if (inst->volumeEnv.flags & jenvfUsed)
     {
         // Process the instrument volume fadeout
-        if (mp->iCKeyOff[channel] && (mp->iCFadeOutVol[channel] > 0) && (inst->fadeOut > 0))
+        if (chn->iCKeyOff && chn->iCFadeOutVol > 0 && inst->fadeOut > 0)
         {
-            int tmp = (mp->iCFadeOutVol[channel] - inst->fadeOut);
+            int tmp = chn->iCFadeOutVol - inst->fadeOut;
             if (tmp < 0) tmp = 0;
-            mp->iCFadeOutVol[channel] = tmp;
+            chn->iCFadeOutVol = tmp;
 
             JMPSETNDFLAGS(cdfNewVolume);
         }
 
-        if (mp->iCVolEnv_Exec[channel])
+        if (chn->iCVolEnv_Exec)
         {
             // Execute the volume envelope
-            jmpExecEnvelope(&(inst->volumeEnv), mp->iCKeyOff[channel],
-                    &(mp->iCVolEnv_Frames[channel]), &(mp->iCVolEnv_Exec[channel]),
-                    &(mp->iCVolEnv[channel]));
+            jmpExecEnvelope(&(inst->volumeEnv),
+                chn->iCKeyOff,
+                &(chn->iCVolEnv_Frames), &(chn->iCVolEnv_Exec),
+                &(chn->iCVolEnv));
 
             JMPSETNDFLAGS(cdfNewVolume);
         }
@@ -279,10 +244,10 @@
     else
     {
         // If the envelope is not used, set max volume
-        if (mp->iCVolEnv[channel] != mpMaxVol)
+        if (chn->iCVolEnv != mpMaxVol)
         {
-            mp->iCVolEnv[channel] = mpMaxVol;
-            mp->iCFadeOutVol[channel] = mpMaxFadeoutVol;
+            chn->iCVolEnv = mpMaxVol;
+            chn->iCFadeOutVol = mpMaxFadeoutVol;
             JMPSETNDFLAGS(cdfNewVolume);
         }
     }
@@ -290,12 +255,12 @@
     // Process the panning envelope
     if (inst->panningEnv.flags & jenvfUsed)
     {
-        if (mp->iCPanEnv_Exec[channel])
+        if (chn->iCPanEnv_Exec)
         {
             // Execute the panning envelope
-            jmpExecEnvelope(&(inst->panningEnv), mp->iCKeyOff[channel],
-                    &(mp->iCPanEnv_Frames[channel]), &(mp->iCPanEnv_Exec[channel]),
-                    &(mp->iCPanEnv[channel]));
+            jmpExecEnvelope(&(inst->panningEnv), chn->iCKeyOff,
+                    &(chn->iCPanEnv_Frames), &(chn->iCPanEnv_Exec),
+                    &(chn->iCPanEnv));
 
             JMPSETNDFLAGS(cdfNewPanPos);
         }
@@ -303,9 +268,9 @@
     else
     {
         // If the envelope is not used, set center panning
-        if (mp->iCPanEnv[channel] != mpPanCenter)
+        if (chn->iCPanEnv != mpPanCenter)
         {
-            mp->iCPanEnv[channel] = mpPanCenter;
+            chn->iCPanEnv = mpPanCenter;
             JMPSETNDFLAGS(cdfNewPanPos);
         }
     }
@@ -339,7 +304,7 @@
         JSSERROR(DMERR_MALLOC, NULL, "Could not allocate memory for player structure.\n");
 
     // Set variables
-    mp->pDevice = pDevice;
+    mp->device = pDevice;
 #ifdef JSS_SUP_THREADS
     mp->mutex = dmCreateMutex();
 #endif
@@ -371,17 +336,27 @@
 
 /* Reset the envelopes for given channel.
  */
-static void jmpResetEnvelopes(JSSPlayer * mp, int channel)
+static void jmpResetEnvelopes(JSSPlayerChannel *chn)
 {
-    assert(mp != NULL);
-
-    mp->iCPanEnv_Frames[channel] = mp->iCVolEnv_Frames[channel] = 0;
-    mp->iCPanEnv_Exec[channel] = mp->iCVolEnv_Exec[channel] = TRUE;
+    chn->iCPanEnv_Frames = chn->iCVolEnv_Frames = 0;
+    chn->iCPanEnv_Exec   = chn->iCVolEnv_Exec   = TRUE;
 }
 
 
 /* Clear module player structure
  */
+void jmpClearChannel(JSSPlayerChannel *chn)
+{
+    memset(chn, 0, sizeof(JSSPlayerChannel));
+
+    chn->iCNote            = jsetNotSet;
+    chn->iCInstrumentN     = jsetNotSet;
+    chn->iCExtInstrumentN  = jsetNotSet;
+    chn->iCPanning         = mpPanCenter;
+    chn->iCPanEnv          = mpPanCenter;
+}
+
+
 void jmpClearPlayer(JSSPlayer * mp)
 {
     int i;
@@ -389,72 +364,16 @@
     JSS_LOCK(mp);
 
     // Initialize general variables
-    mp->iPatternDelay = 0;
-    mp->newRowSet = FALSE;
-    mp->newOrderSet = FALSE;
-    mp->iTick = jsetNotSet;
-    mp->iRow = 0;
-    mp->iLastPatLoopRow = 0;
+    mp->patternDelay      = 0;
+    mp->newRowSet          = FALSE;
+    mp->newOrderSet        = FALSE;
+    mp->tick               = jsetNotSet;
+    mp->row                = 0;
+    mp->lastPatLoopRow    = 0;
 
     // Initialize channel data
-    memset(&(mp->iPatLoopRow), 0, sizeof(mp->iPatLoopRow));
-    memset(&(mp->iPatLoopCount), 0, sizeof(mp->iPatLoopCount));
-
-    memset(&mp->iLastPortaParam, 0, sizeof(mp->iLastPortaParam));
-    memset(&mp->iLastPortaToNoteParam, 0, sizeof(mp->iLastPortaToNoteParam));
-    memset(&mp->iLastPortaToNotePitch, 0, sizeof(mp->iLastPortaToNotePitch));
-
-    memset(&mp->iVibratoPos, 0, sizeof(mp->iVibratoPos));
-    memset(&mp->iVibratoSpeed, 0, sizeof(mp->iVibratoSpeed));
-    memset(&mp->iVibratoDepth, 0, sizeof(mp->iVibratoDepth));
-    memset(&mp->iVibratoWC, 0, sizeof(mp->iVibratoWC));
-
-    memset(&mp->iTremoloPos, 0, sizeof(mp->iTremoloPos));
-    memset(&mp->iTremoloSpeed, 0, sizeof(mp->iTremoloSpeed));
-    memset(&mp->iTremoloDepth, 0, sizeof(mp->iTremoloDepth));
-    memset(&mp->iTremoloWC, 0, sizeof(mp->iTremoloWC));
-
-    memset(&mp->iLastTremorParam, 0, sizeof(mp->iLastTremorParam));
-    memset(&mp->iTremorCount, 0, sizeof(mp->iTremorCount));
-    memset(&mp->iLastSampleOffset, 0, sizeof(mp->iLastSampleOffset));
-    memset(&mp->iLastRetrigParam, 0, sizeof(mp->iLastRetrigParam));
-    memset(&mp->iLastVolSlideParam, 0, sizeof(mp->iLastVolSlideParam));
-
-    memset(&mp->iRetrigNDFlags, 0, sizeof(mp->iRetrigNDFlags));
-    memset(&mp->iSaveNDFlags, 0, sizeof(mp->iSaveNDFlags));
-
-    memset(&mp->iCNewDataFlags, 0, sizeof(mp->iCNewDataFlags));
-    memset(&mp->iCPitch, 0, sizeof(mp->iCPitch));
-    memset(&mp->iCPosition, 0, sizeof(mp->iCPosition));
-    memset(&mp->iCVolume, 0, sizeof(mp->iCVolume));
-    memset(&mp->iCFadeOutVol, 0, sizeof(mp->iCFadeOutVol));
-    memset(&mp->iCVolEnv, 0, sizeof(mp->iCVolEnv));
-
-    memset(&mp->iCAutoVib_Frames, 0, sizeof(mp->iCAutoVib_Frames));
-    memset(&mp->iCPanEnv_Frames, 0, sizeof(mp->iCPanEnv_Frames));
-    memset(&mp->iCVolEnv_Frames, 0, sizeof(mp->iCVolEnv_Frames));
-
-    memset(&mp->iCLastFineVolumeslideUpParam, 0, sizeof(mp->iCLastFineVolumeslideUpParam));
-    memset(&mp->iCLastFineVolumeslideDownParam, 0, sizeof(mp->iCLastFineVolumeslideDownParam));
-    memset(&mp->iCLastExtraFinePortamentoUpParam, 0, sizeof(mp->iCLastExtraFinePortamentoUpParam));
-    memset(&mp->iCLastExtraFinePortamentoDownParam, 0, sizeof(mp->iCLastExtraFinePortamentoDownParam));
-    memset(&mp->iCLastFinePortamentoUpParam, 0, sizeof(mp->iCLastFinePortamentoUpParam));
-    memset(&mp->iCLastFinePortamentoDownParam, 0, sizeof(mp->iCLastFinePortamentoDownParam));
-
-    memset(&mp->iCPanEnv_Exec, 0, sizeof(mp->iCPanEnv_Exec));
-    memset(&mp->iCVolEnv_Exec, 0, sizeof(mp->iCVolEnv_Exec));
-    memset(&mp->iCKeyOff, 0, sizeof(mp->iCKeyOff));
-
     for (i = 0; i < jsetNChannels; i++)
-    {
-        mp->iCNote[i] = jsetNotSet;
-        mp->iCInstrument[i] = NULL;
-        mp->iCInstrumentN[i] = jsetNotSet;
-        mp->iCExtInstrument[i] = NULL;
-        mp->iCExtInstrumentN[i] = jsetNotSet;
-        mp->iCPanning[i] = mpPanCenter;
-        mp->iCPanEnv[i] = mpPanCenter;
-    }
+        jmpClearChannel(&mp->channels[i]);
     
     JSS_UNLOCK(mp);
 }
@@ -462,7 +381,7 @@
 
 /* Set module
  */
-void jmpSetModule(JSSPlayer * mp, JSSModule * pModule)
+void jmpSetModule(JSSPlayer * mp, JSSModule * module)
 {
     assert(mp != NULL);
     JSS_LOCK(mp);
@@ -470,7 +389,7 @@
     jmpStop(mp);
     jmpClearPlayer(mp);
 
-    mp->pModule = pModule;
+    mp->module = module;
 
     JSS_UNLOCK(mp);
 }
@@ -485,8 +404,7 @@
 
     if (mp->isPlaying)
     {
-        // Remove callback
-        jvmRemoveCallback(mp->pDevice);
+        jvmRemoveCallback(mp->device);
         mp->isPlaying = FALSE;
     }
     
@@ -503,7 +421,7 @@
 
     if (!mp->isPlaying)
     {
-        int result = jvmSetCallback(mp->pDevice, jmpExec, (void *) mp);
+        int result = jvmSetCallback(mp->device, jmpExec, (void *) mp);
         if (result != DMERR_OK)
             JSSERROR(result,, "Could not initialize callback for player.\n");
 
@@ -524,25 +442,25 @@
     int pattern;
     
     pattern = jsetOrderEnd;
-    mp->iOrder = jsetNotSet;
+    mp->order = jsetNotSet;
     orderOK = FALSE;
 
     while (!orderOK)
     {
-        if (order < 0 || order >= mp->pModule->norders)
+        if (order < 0 || order >= mp->module->norders)
         {
             jmpStop(mp);
             orderOK = TRUE;
         }
         else
         {
-            pattern = mp->pModule->orderList[order];
+            pattern = mp->module->orderList[order];
             if (pattern == jsetOrderSkip)
             {
                 order++;
             }
             else
-            if (pattern >= mp->pModule->npatterns || pattern == jsetOrderEnd)
+            if (pattern >= mp->module->npatterns || pattern == jsetOrderEnd)
             {
                 jmpStop(mp);
                 orderOK = TRUE;
@@ -551,9 +469,9 @@
             {
                 // All OK
                 orderOK = TRUE;
-                mp->pPattern = mp->pModule->patterns[pattern];
-                mp->iPattern = pattern;
-                mp->iOrder = order;
+                mp->pattern = mp->module->patterns[pattern];
+                mp->npattern = pattern;
+                mp->order = order;
             }
         }
     }
@@ -566,10 +484,10 @@
 {
     assert(mp != NULL);
     JSS_LOCK(mp);
-    assert(mp->pDevice != NULL);
+    assert(mp->device != NULL);
 
-    mp->iTempo = tempo;
-    jvmSetCallbackFreq(mp->pDevice, (tempo * 2) / 5);
+    mp->tempo = tempo;
+    jvmSetCallbackFreq(mp->device, (tempo * 2) / 5);
     JSS_UNLOCK(mp);
 }
 
@@ -579,13 +497,13 @@
     int i;
     assert(mp != NULL);
     JSS_LOCK(mp);
-    assert(mp->pDevice != NULL);
-    assert(mp->pModule != NULL);
+    assert(mp->device != NULL);
+    assert(mp->module != NULL);
 
-    for (i = 0; i < mp->pModule->nchannels; i++)
+    for (i = 0; i < mp->module->nchannels; i++)
     {
-        jvmStop(mp->pDevice, i);
-        jvmClear(mp->pDevice, i);
+        jvmStop(mp->device, i);
+        jvmClear(mp->device, i);
     }
 
     JSS_UNLOCK(mp);
@@ -594,21 +512,20 @@
 
 /* Starts playing module from a given ORDER.
  */
-int jmpPlayOrder(JSSPlayer * mp, int iStartOrder)
+int jmpPlayOrder(JSSPlayer * mp, int order)
 {
     int result;
     assert(mp != NULL);
 
     JSS_LOCK(mp);
-    assert(mp->pModule != NULL);
+    assert(mp->module != NULL);
 
     // Stop if already playing
     jmpStop(mp);
-
     jmpClearChannels(mp);
 
     // Check starting order
-    if (iStartOrder < 0 || iStartOrder >= mp->pModule->norders)
+    if (order < 0 || order >= mp->module->norders)
     {
         JSS_UNLOCK(mp);
         JSSERROR(DMERR_INVALID_ARGS, DMERR_INVALID_ARGS, "Invalid playing startorder given.\n");
@@ -617,20 +534,20 @@
     // Initialize playing
     jmpClearPlayer(mp);
 
-    jmpSetNewOrder(mp, iStartOrder);
+    jmpSetNewOrder(mp, order);
 
-    if (mp->iOrder == jsetNotSet)
+    if (mp->order == jsetNotSet)
     {
         JSS_UNLOCK(mp);
         JSSERROR(DMERR_NOT_SUPPORTED, DMERR_NOT_SUPPORTED,
-             "Could not start playing from given order #%i\n", iStartOrder);
+             "Could not start playing from given order #%i\n", order);
     }
 
-    mp->iSpeed = mp->pModule->defSpeed;
-    jmpSetTempo(mp, mp->pModule->defTempo);
+    mp->speed = mp->module->defSpeed;
+    jmpSetTempo(mp, mp->module->defTempo);
 
     // Set callback
-    result = jvmSetCallback(mp->pDevice, jmpExec, (void *) mp);
+    result = jvmSetCallback(mp->device, jmpExec, (void *) mp);
     if (result != DMERR_OK)
     {
         JSS_UNLOCK(mp);
@@ -651,7 +568,7 @@
     int result;
     assert(mp != NULL);
     JSS_LOCK(mp);
-    assert(mp->pModule != NULL);
+    assert(mp->module != NULL);
 
     // Stop if already playing
     jmpStop(mp);
@@ -660,12 +577,12 @@
     // Initialize playing
     jmpClearPlayer(mp);
 
-    mp->iPattern = pattern;
-    mp->iSpeed = mp->pModule->defSpeed;
-    jmpSetTempo(mp, mp->pModule->defTempo);
+    mp->npattern = pattern;
+    mp->speed = mp->module->defSpeed;
+    jmpSetTempo(mp, mp->module->defTempo);
 
     // Set callback
-    result = jvmSetCallback(mp->pDevice, jmpExec, (void *) mp);
+    result = jvmSetCallback(mp->device, jmpExec, (void *) mp);
     if (result != DMERR_OK)
     {
         JSS_UNLOCK(mp);
@@ -681,45 +598,43 @@
 
 /* Set volume for given module channel.
  */
-static void jmpSetVolume(JSSPlayer * mp, int channel, int value)
+static void jmpSetVolume(JSSPlayerChannel * chn, int channel, int volume)
 {
     // Check values
-    if (value < mpMinVol)
-        value = mpMinVol;
-    else if (value > mpMaxVol)
-        value = mpMaxVol;
+    if (volume < mpMinVol) volume = mpMinVol; else
+    if (volume > mpMaxVol) volume = mpMaxVol;
 
     // Set the volume
-    mp->iCVolume[channel] = value;
+    chn->iCVolume = volume;
     JMPSETNDFLAGS(cdfNewVolume);
 }
 
-#define jmpChangeVolume(Q, Z, X) jmpSetVolume(Q, Z, mp->iCVolume[channel] + (X))
+#define jmpChangeVolume(Q, Z, X) jmpSetVolume(Q, Z, chn->iCVolume + (X))
 
 
 /* Change the pitch of given channel by ADelta.
  */
-static void jmpChangePitch(JSSPlayer * mp, int channel, int delta)
+static void jmpChangePitch(JSSPlayerChannel *chn, int channel, int delta)
 {
     int value;
 
     // Calculate new pitch and check it
-    value = (mp->iCPitch[channel] + delta);
+    value = chn->iCPitch + delta;
     if (value < 0)
         value = 0;
 
     // Set the new pitch
-    mp->iCPitch[channel] = value;
+    chn->iCPitch = value;
     JMPSETNDFLAGS(cdfNewPitch);
 }
 
 
 /* Do a note portamento (pitch slide) effect for given module channel.
  */
-static void jmpDoPortamento(JSSPlayer * mp, int channel)
+static void jmpDoPortamento(JSSPlayerChannel * chn, int channel)
 {
     // Check for zero parameter
-    if (mp->iLastPortaToNoteParam[channel] == 0)
+    if (chn->iLastPortaToNoteParam == 0)
     {
         JMPSETNDFLAGS(cdfNewPitch);
         return;
@@ -728,21 +643,21 @@
     /* Slide the pitch of channel to the destination value
      * with speed of iLastPortaToNoteParam[] * 4 and stop when it equals.
      */
-    if (mp->iCPitch[channel] != mp->iLastPortaToNotePitch[channel])
+    if (chn->iCPitch != chn->iLastPortaToNotePitch)
     {
-        if (mp->iCPitch[channel] < mp->iLastPortaToNotePitch[channel])
+        if (chn->iCPitch < chn->iLastPortaToNotePitch)
         {
             // Increase pitch UP
-            jmpChangePitch(mp, channel, mp->iLastPortaToNoteParam[channel] * 4);
-            if (mp->iCPitch[channel] > mp->iLastPortaToNotePitch[channel])
-                mp->iCPitch[channel] = mp->iLastPortaToNotePitch[channel];
+            jmpChangePitch(chn, channel, chn->iLastPortaToNoteParam * 4);
+            if (chn->iCPitch > chn->iLastPortaToNotePitch)
+                chn->iCPitch = chn->iLastPortaToNotePitch;
         }
         else
         {
             // Decrease pitch DOWN
-            jmpChangePitch(mp, channel, -(mp->iLastPortaToNoteParam[channel] * 4));
-            if (mp->iCPitch[channel] < mp->iLastPortaToNotePitch[channel])
-                mp->iCPitch[channel] = mp->iLastPortaToNotePitch[channel];
+            jmpChangePitch(chn, channel, -(chn->iLastPortaToNoteParam * 4));
+            if (chn->iCPitch < chn->iLastPortaToNotePitch)
+                chn->iCPitch = chn->iLastPortaToNotePitch;
         }
     }
 }
@@ -750,19 +665,19 @@
 
 /* Do a tremolo effect for given module channel.
  */
-static void jmpDoTremolo(JSSPlayer * mp, int channel)
+static void jmpDoTremolo(JSSPlayer * mp, JSSPlayerChannel *chn, int channel)
 {
     int delta, pos, depth;
     
     // Check settings
-    if (mp->iTremoloDepth[channel] == 0 || mp->iTremoloSpeed[channel] == 0)
+    if (chn->iTremoloDepth == 0 || chn->iTremoloSpeed == 0)
         return;
 
     // Get position of tremolo waveform
-    pos = mp->iTremoloPos[channel] & 255;
-    depth = mp->iTremoloDepth[channel];
+    pos = chn->iTremoloPos & 255;
+    depth = chn->iTremoloDepth;
 
-    switch (mp->iTremoloWC[channel] & 3)
+    switch (chn->iTremoloWC & 3)
     {
         case 0:    // Sine-wave
             delta = (jmpSineTable[pos] * depth) / 2048;
@@ -781,30 +696,30 @@
     }
 
     // Set the new volume
-    jmpCSetVolume(mp, channel, mp->iCVolume[channel] + delta);
+    jmpCSetVolume(mp, chn, channel, chn->iCVolume + delta);
 
     // Advance tremolo waveform position
-    mp->iTremoloPos[channel] += mp->iTremoloSpeed[channel];
-    if (mp->iTremoloPos[channel] > 255)
-        mp->iTremoloPos[channel] = 0;
+    chn->iTremoloPos += chn->iTremoloSpeed;
+    if (chn->iTremoloPos > 255)
+        chn->iTremoloPos = 0;
 }
 
 
 /* Do a vibrato effect for given module channel.
  */
-static void jmpDoVibrato(JSSPlayer * mp, int channel)
+static void jmpDoVibrato(JSSPlayer * mp, JSSPlayerChannel *chn, int channel)
 {
     int delta, pos, depth;
 
     // Check settings
-    if (mp->iVibratoDepth[channel] == 0 || mp->iVibratoSpeed[channel] == 0)
+    if (chn->iVibratoDepth == 0 || chn->iVibratoSpeed == 0)
         return;
     
     // Get position of vibrato waveform
-    pos = mp->iVibratoPos[channel] & 255;
-    depth = mp->iVibratoDepth[channel];
+    pos = chn->iVibratoPos & 255;
+    depth = chn->iVibratoDepth;
 
-    switch (mp->iVibratoWC[channel] & 3)
+    switch (chn->iVibratoWC & 3)
     {
         case 0:    // Sine-wave
             delta = (jmpSineTable[pos] * depth) / 2048;
@@ -823,27 +738,27 @@
     }
 
     // Set the new frequency
-    jmpCSetPitch(mp, channel, mp->iCPitch[channel] + delta);
+    jmpCSetPitch(mp, channel, chn->iCPitch + delta);
 
     // Advance vibrato waveform position
-    mp->iVibratoPos[channel] += mp->iVibratoSpeed[channel];
-    if (mp->iVibratoPos[channel] > 255)
-        mp->iVibratoPos[channel] = 0;
+    chn->iVibratoPos += chn->iVibratoSpeed;
+    if (chn->iVibratoPos > 255)
+        chn->iVibratoPos = 0;
 }
 
 
 /* Do a volume slide effect for given module channel.
  */
-static void jmpDoVolumeSlide(JSSPlayer * mp, int channel, int param)
+static void jmpDoVolumeSlide(JSSPlayerChannel * chn, int channel, int param)
 {
     int paramX, paramY;
 
     JMPMAKEPARAM(param, paramX, paramY)
 
     if (paramY == 0)
-        jmpChangeVolume(mp, channel, paramX);
+        jmpChangeVolume(chn, channel, paramX);
     if (paramX == 0)
-        jmpChangeVolume(mp, channel, -paramY);
+        jmpChangeVolume(chn, channel, -paramY);
 }
 
 
@@ -854,47 +769,48 @@
  * here is included also a slightly kludgy implementation of the
  * FT2 patloop bug.
  */
-static void jmpDoPatternLoop(JSSPlayer * mp, int channel, int paramY)
+static void jmpDoPatternLoop(JSSPlayer * mp, JSSPlayerChannel *chn, int channel, int paramY)
 {
     // Check what we need to do
     if (paramY > 0)
     {
         // SBx/E6x loops 'x' times
-        if (mp->iPatLoopCount[channel] == 1)
-            mp->iPatLoopCount[channel] = 0;
+        if (chn->iPatLoopCount == 1)
+            chn->iPatLoopCount = 0;
         else
         {
             // Check if we need to set the count
-            if (mp->iPatLoopCount[channel] == 0)
-                mp->iPatLoopCount[channel] = (paramY + 1);
+            if (chn->iPatLoopCount == 0)
+                chn->iPatLoopCount = (paramY + 1);
 
             // Loop to specified row
-            mp->iPatLoopCount[channel]--;
-            mp->iNewRow = mp->iPatLoopRow[channel];
+            chn->iPatLoopCount--;
+            mp->newRow = chn->iPatLoopRow;
             mp->newRowSet = TRUE;
         }
     }
     else
     {
         // SB0/E60 sets the loop start point
-        mp->iPatLoopRow[channel] = mp->iRow;
+        chn->iPatLoopRow = mp->row;
 
         // This is here because of the infamous FT2 patloop bug
-        mp->iLastPatLoopRow = mp->iRow;
+        mp->lastPatLoopRow = mp->row;
     }
 }
 
 
 /* Do arpeggio effect
  */
-static void jmpDoArpeggio(JSSPlayer * mp, int channel, int paramY, int paramX)
+static void jmpDoArpeggio(JSSPlayer * mp, JSSPlayerChannel *chn, int channel, int paramY, int paramX)
 {
-    JSSInstrument *tempInst = mp->iCInstrument[channel];
+    JSSInstrument *tempInst = chn->iCInstrument;
+
     if (tempInst)
     {
-        int tmp = mp->iCNote[channel];
+        int tmp = chn->iCNote;
         if (tmp == jsetNotSet || tmp == jsetNoteOff) return;
-        switch (mp->iTick & 3)
+        switch (mp->tick & 3)
         {
             case 1:
                 tmp += paramX;
@@ -913,6 +829,7 @@
  */
 static void jmpProcessRowEffect(JSSPlayer * mp, int channel, JSSNote * currNote)
 {
+    JSSPlayerChannel *chn = &(mp->channels[channel]);
     int param, paramX, paramY;
     char effect;
 
@@ -923,7 +840,7 @@
     switch (effect)
     {
         case '0':        // 0xy = Arpeggio
-            jmpDoArpeggio(mp, channel, paramX, paramY);
+            jmpDoArpeggio(mp, chn, channel, paramX, paramY);
             break;
 
         case 'W':        // Used widely in demo-music as MIDAS Sound System sync-command
@@ -934,46 +851,46 @@
         case '1':
         case '2':        // 1xy = Portamento Up, 2xy = Portamento Down : IMPL.VERIFIED
             if (param)
-                mp->iLastPortaParam[channel] = param;
+                chn->iLastPortaParam = param;
             break;
 
         case '3':        // 3xy = Porta To Note
             if (param)
-                mp->iLastPortaToNoteParam[channel] = param;
+                chn->iLastPortaToNoteParam = param;
 
             if (currNote->note != jsetNotSet && currNote->note != jsetNoteOff) {
-                mp->iLastPortaToNotePitch[channel] = mp->iCPitch[channel];
-                mp->iCPitch[channel] = mp->iCOldPitch[channel];
+                chn->iLastPortaToNotePitch = chn->iCPitch;
+                chn->iCPitch = chn->iCOldPitch;
                 JMPUNSETNDFLAGS(cdfNewPitch | cdfNewInstr | cdfNewPanPos);
             }
             break;
 
         case '4':        // 4xy = Vibrato : IMPL.VERIFIED
             if (paramX)
-                mp->iVibratoSpeed[channel] = paramX;
+                chn->iVibratoSpeed = paramX;
 
             if (paramY)
-                mp->iVibratoDepth[channel] = paramY;
+                chn->iVibratoDepth = paramY;
 
-            if ((mp->iVibratoWC[channel] & 4) == 0)
-                mp->iVibratoPos[channel] = 0;
+            if ((chn->iVibratoWC & 4) == 0)
+                chn->iVibratoPos = 0;
             break;
 
         case '5':        // 5xy = Portamento + Volume Slide
         case '6':        // 6xy = Vibrato + Volume slide
             if (param)
-                mp->iLastVolSlideParam[channel] = param;
+                chn->iLastVolSlideParam = param;
             break;
 
         case '7':        // 7xy = Tremolo
             if (paramX)
-                mp->iTremoloSpeed[channel] = paramX;
+                chn->iTremoloSpeed = paramX;
 
             if (paramY)
-                mp->iTremoloDepth[channel] = paramY;
+                chn->iTremoloDepth = paramY;
 
-            if ((mp->iTremoloWC[channel] & 4) == 0)
-                mp->iTremoloPos[channel] = 0;
+            if ((chn->iTremoloWC & 4) == 0)
+                chn->iTremoloPos = 0;
             break;
 
         case '8':        // 8xx = Set Panning
@@ -981,40 +898,40 @@
             break;
 
         case '9':        // 9xx = Set Sample Offset : IMPL.VERIFIED
-            if (mp->iCNewDataFlags[channel] & cdfNewPitch)
+            if (chn->iCNewDataFlags & cdfNewPitch)
             {
-                mp->iCPosition[channel] = param * 0x100;
+                chn->iCPosition = param * 0x100;
                 JMPSETNDFLAGS(cdfNewPos);
             }
             break;
 
         case 'A':        // Axy = Volume Slide : IMPL.VERIFIED
             if (param)
-                mp->iLastVolSlideParam[channel] = param;
+                chn->iLastVolSlideParam = param;
             break;
 
         case 'B':        // Bxx = Pattern Jump : IMPL.VERIFIED
-            mp->iNewOrder = param;
+            mp->newOrder = param;
             mp->newOrderSet = TRUE;
             mp->jumpFlag = TRUE;
-            mp->iLastPatLoopRow = 0;
+            mp->lastPatLoopRow = 0;
             break;
 
         case 'C':        // Cxx = Set Volume : IMPL.VERIFIED
-            jmpSetVolume(mp, channel, param);
+            jmpSetVolume(chn, channel, param);
             break;
 
         case 'D':        // Dxx = Pattern Break : IMPL.VERIFIED
             // Compute the new row
-            mp->iNewRow = (paramX * 10) + paramY;
-            if (mp->iNewRow >= mp->pPattern->nrows)
-                mp->iNewRow = 0;
+            mp->newRow = (paramX * 10) + paramY;
+            if (mp->newRow >= mp->pattern->nrows)
+                mp->newRow = 0;
 
             mp->newRowSet = TRUE;
 
             // Now we do some tricky tests
             if (!mp->breakFlag && !mp->jumpFlag) {
-                mp->iNewOrder = mp->iOrder + 1;
+                mp->newOrder = mp->order + 1;
                 mp->newOrderSet = TRUE;
             }
 
@@ -1029,23 +946,23 @@
 
             case 0x01:    // E1x - Fine Portamento Up
                 if (paramY)
-                    mp->iCLastFinePortamentoUpParam[channel] = paramY;
+                    chn->iCLastFinePortamentoUpParam = paramY;
 
-                jmpChangePitch(mp, channel, -(mp->iCLastFinePortamentoUpParam[channel] * 4));
+                jmpChangePitch(chn, channel, -(chn->iCLastFinePortamentoUpParam * 4));
                 break;
 
             case 0x02:    // E2x - Fine Portamento Down
                 if (paramY)
-                    mp->iCLastFinePortamentoDownParam[channel] = paramY;
+                    chn->iCLastFinePortamentoDownParam = paramY;
 
-                jmpChangePitch(mp, channel, (mp->iCLastFinePortamentoDownParam[channel] * 4));
+                jmpChangePitch(chn, channel, (chn->iCLastFinePortamentoDownParam * 4));
                 break;
 
             case 0x03:    // E3x - Glissando Control (NOT SUPPORTED)
                 break;
 
             case 0x04:    // E4x - Set Vibrato waveform
-                mp->iVibratoWC[channel] = paramY;
+                chn->iVibratoWC = paramY;
                 break;
 
             case 0x05:    // E5x - Set Finetune
@@ -1053,15 +970,15 @@
                 break;
 
             case 0x06:    // E6x - Set Pattern Loop
-                jmpDoPatternLoop(mp, channel, paramY);
+                jmpDoPatternLoop(mp, chn, channel, paramY);
                 break;
 
             case 0x07:    // E7x - Set Tremolo waveform
-                mp->iTremoloWC[channel] = paramY;
+                chn->iTremoloWC = paramY;
                 break;
 
             case 0x08:    // E8x - Set Pan Position
-                mp->iCPanning[channel] = (paramY * 16);
+                chn->iCPanning = (paramY * 16);
                 JMPSETNDFLAGS(cdfNewPanPos);
                 break;
 
@@ -1071,15 +988,15 @@
 
             case 0x0a:    // EAx - Fine Volumeslide Up
                 if (paramY)
-                    mp->iCLastFineVolumeslideUpParam[channel] = paramY;
+                    chn->iCLastFineVolumeslideUpParam = paramY;
 
-                jmpChangeVolume(mp, channel, mp->iCLastFineVolumeslideUpParam[channel]);
+                jmpChangeVolume(chn, channel, chn->iCLastFineVolumeslideUpParam);
                 break;
 
             case 0x0b:    // EBx - Fine Volumeslide Down
                 if (paramY)
-                    mp->iCLastFineVolumeslideDownParam[channel] = paramY;
-                jmpChangeVolume(mp, channel, -(mp->iCLastFineVolumeslideDownParam[channel]));
+                    chn->iCLastFineVolumeslideDownParam = paramY;
+                jmpChangeVolume(chn, channel, -(chn->iCLastFineVolumeslideDownParam));
                 break;
 
             case 0x0c:    // ECx - Set Note Cut (NOT PROCESSED IN TICK0)
@@ -1089,14 +1006,14 @@
                 if (paramY > 0)
                 {
                     // Save the ND-flags, then clear
-                    mp->iSaveNDFlags[channel] = mp->iCNewDataFlags[channel];
-                    mp->iCNewDataFlags[channel] = 0;
+                    chn->iSaveNDFlags = chn->iCNewDataFlags;
+                    chn->iCNewDataFlags = 0;
                     // TODO .. does this only affect NOTE or also instrument?
                 }
                 break;
 
             case 0x0e:    // EEx - Set Pattern Delay : IMPL.VERIFIED
-                mp->iPatternDelay = paramY;
+                mp->patternDelay = paramY;
                 break;
 
             case 0x0f:    // EFx - Invert Loop (NOT SUPPORTED)
@@ -1112,14 +1029,14 @@
             if (param > 0)
             {
                 if (param < 0x20)
-                    mp->iSpeed = param;
+                    mp->speed = param;
                 else
                     jmpSetTempo(mp, param);
             }
             break;
 
         case 'G':        // Gxx = Global Volume
-            mp->iGlobalVol = param;
+            mp->globalVol = param;
             JMPSETNDFLAGS(cdfNewGlobalVol);
             break;
 
@@ -1129,15 +1046,15 @@
             break;
 
         case 'K':        // Kxx = Key-off (Same as key-off note)
-            mp->iCKeyOff[channel] = TRUE;
+            chn->iCKeyOff = TRUE;
             break;
 
         case 'L':        // Lxx = Set Envelope Position
             JMPDEBUG("Set Envelope Position used, NOT verified with FT2");
-            mp->iCPanEnv_Frames[channel] = param;
-            mp->iCVolEnv_Frames[channel] = param;
-            mp->iCPanEnv_Exec[channel] = TRUE;
-            mp->iCVolEnv_Exec[channel] = TRUE;
+            chn->iCPanEnv_Frames = param;
+            chn->iCVolEnv_Frames = param;
+            chn->iCPanEnv_Exec = TRUE;
+            chn->iCVolEnv_Exec = TRUE;
             break;
 
         case 'R':        // Rxy = Multi Retrig note
@@ -1146,7 +1063,7 @@
 
         case 'T':        // Txy = Tremor
             if (param)
-                mp->iLastTremorParam[channel] = param;
+                chn->iLastTremorParam = param;
             break;
 
         case 'X':        // Xxy = Extra Fine Portamento
@@ -1154,16 +1071,16 @@
             {
                 case 0x01:    // X1y - Extra Fine Portamento Up
                     if (paramY)
-                        mp->iCLastExtraFinePortamentoUpParam[param] = paramY;
+                        chn->iCLastExtraFinePortamentoUpParam = paramY;
 
-                    jmpChangePitch(mp, channel, -(mp->iCLastExtraFinePortamentoUpParam[param]));
+                    jmpChangePitch(chn, channel, - chn->iCLastExtraFinePortamentoUpParam);
                     break;
 
                 case 0x02:    // X2y - Extra Fine Portamento Down
                     if (paramY)
-                        mp->iCLastExtraFinePortamentoDownParam[param] = paramY;
+                        chn->iCLastExtraFinePortamentoDownParam = paramY;
 
-                    jmpChangePitch(mp, channel, mp->iCLastExtraFinePortamentoUpParam[param]);
+                    jmpChangePitch(chn, channel, chn->iCLastExtraFinePortamentoUpParam);
                     break;
 
                 default:
@@ -1186,32 +1103,34 @@
     JSSInstrument *inst = NULL;
     BOOL newNote = FALSE;
     int tmp, paramX, paramY;
+    JSSPlayerChannel *chn = &(mp->channels[channel]);
 
-    JMPGETNOTE(currNote, mp->iRow, channel);
+    JMPGETNOTE(currNote, mp->row, channel);
 
     // Check for a new note/keyoff here
     if (currNote->note == jsetNoteOff)
-        mp->iCKeyOff[channel] = TRUE;
+        chn->iCKeyOff = TRUE;
     else
     if (currNote->note >= 0 && currNote->note <= 96)
     {
         // New note was set
         newNote = TRUE;
-        mp->iCNote[channel] = currNote->note;
+        chn->iCNote = currNote->note;
     }
 
     // Check for new instrument
-    if (currNote->instrument != jsetNotSet) {
+    if (currNote->instrument != jsetNotSet)
+    {
         /* Envelopes and ext.instrument fadeout are initialized always if
          * new instrument is set, even if the instrument does not exist.
          */
-        jmpResetEnvelopes(mp, channel);
-        mp->iCKeyOff[channel] = FALSE;
-        mp->iCFadeOutVol[channel] = mpMaxFadeoutVol;
+        jmpResetEnvelopes(chn);
+        chn->iCKeyOff = FALSE;
+        chn->iCFadeOutVol = mpMaxFadeoutVol;
 
         // We save the instrument number here for later use
-        if (currNote->instrument >= 0 && currNote->instrument < mp->pModule->nextInstruments)
-            mp->iCExtInstrumentN[channel] = currNote->instrument;
+        if (currNote->instrument >= 0 && currNote->instrument < mp->module->nextInstruments)
+            chn->iCExtInstrumentN = currNote->instrument;
     }
 
     /* ONLY if newNote was SET NOW and ExtInstrument HAS BEEN set, we can
@@ -1219,16 +1138,16 @@
      */
     if (newNote)
     {
-        if (mp->iCExtInstrumentN[channel] != jsetNotSet)
-            extInst = mp->pModule->extInstruments[mp->iCExtInstrumentN[channel]];
+        if (chn->iCExtInstrumentN != jsetNotSet)
+            extInst = mp->module->extInstruments[chn->iCExtInstrumentN];
         else
             extInst = NULL;
 
         if (extInst)
         {
             // Set instrument
-            int note = mp->iCNote[channel];
-            mp->iCExtInstrument[channel] = extInst;
+            int note = chn->iCNote;
+            chn->iCExtInstrument = extInst;
 
             // We set new Instrument ONLY if NEW NOTE has been set
             if (note != jsetNotSet)
@@ -1236,14 +1155,14 @@
                 // Get instrument number
                 tmp = extInst->sNumForNotes[note];
 
-                if (tmp >= 0 && tmp < mp->pModule->ninstruments) {
+                if (tmp >= 0 && tmp < mp->module->ninstruments) {
                     // Set the new instrument
-                    inst = mp->pModule->instruments[tmp];
-                    mp->iCInstrumentN[channel] = tmp;
-                    mp->iCInstrument[channel] = inst;
-                    mp->iCVolume[channel] = inst->volume;
-                    mp->iCPanning[channel] = inst->EPanning;
-                    mp->iCPosition[channel] = 0;
+                    inst = mp->module->instruments[tmp];
+                    chn->iCInstrumentN = tmp;
+                    chn->iCInstrument = inst;
+                    chn->iCVolume = inst->volume;
+                    chn->iCPanning = inst->EPanning;
+                    chn->iCPosition = 0;
 
                     // Set NDFlags
                     JMPSETNDFLAGS(cdfNewInstr | cdfNewPos | cdfNewPanPos | cdfNewVolume);
@@ -1255,17 +1174,17 @@
     if (inst)
     {
         // Save old pitch for later use
-        mp->iCOldPitch[channel] = mp->iCPitch[channel];
+        chn->iCOldPitch = chn->iCPitch;
 
         // Compute new pitch
-        tmp = (mp->iCNote[channel] + inst->ERelNote);
-//fprintf(stderr, "HEH: %d + %d = %d\n", mp->iCNote[channel], inst->ERelNote, tmp);
+        tmp = (chn->iCNote + inst->ERelNote);
+//fprintf(stderr, "HEH: %d + %d = %d\n", chn->iCNote, inst->ERelNote, tmp);
         if (tmp < 0)
             tmp = 0;
         else if (tmp > 119)
             tmp = 119;
 
-        mp->iCPitch[channel] = jmpGetPeriodFromNote(mp, tmp, inst->EFineTune);
+        chn->iCPitch = jmpGetPeriodFromNote(mp, tmp, inst->EFineTune);
         JMPSETNDFLAGS(cdfNewPitch);
     }
     
@@ -1279,33 +1198,33 @@
         case 0x02:
         case 0x03:
         case 0x04:
-            jmpSetVolume(mp, channel, currNote->volume);
+            jmpSetVolume(chn, channel, currNote->volume);
             break;
 
         case 0x07:        // Dx = Fine Volumeslide Down : IMPL.VERIFIED
-            jmpChangeVolume(mp, channel, -paramY);
+            jmpChangeVolume(chn, channel, -paramY);
             break;
 
         case 0x08:        // Ux = Fine Volumeslide Up : IMPL.VERIFIED
-            jmpChangeVolume(mp, channel, paramY);
+            jmpChangeVolume(chn, channel, paramY);
             break;
 
         case 0x09:        // Sx = Set vibrato speed : IMPL.VERIFIED
-            mp->iVibratoSpeed[channel] = paramY;
+            chn->iVibratoSpeed = paramY;
             break;
 
         case 0x0a:        // Vx = Vibrato : IMPL.VERIFIED
             if (paramY)
-                mp->iVibratoDepth[channel] = paramY;
+                chn->iVibratoDepth = paramY;
             break;
 
         case 0x0e:        // Mx = Porta To Note : IMPL.VERIFIED
             if (paramY)
-                mp->iLastPortaToNoteParam[channel] = paramY;
+                chn->iLastPortaToNoteParam = paramY;
 
             if (currNote->note != jsetNotSet && currNote->note != jsetNoteOff) {
-                mp->iLastPortaToNotePitch[channel] = mp->iCPitch[channel];
-                mp->iCPitch[channel] = mp->iCOldPitch[channel];
+                chn->iLastPortaToNotePitch = chn->iCPitch;
+                chn->iCPitch = chn->iCOldPitch;
                 JMPUNSETNDFLAGS(cdfNewPitch | cdfNewInstr | cdfNewPanPos);
             }
             break;
@@ -1319,30 +1238,31 @@
 
 static void jmpProcessEffects(JSSPlayer * mp, int channel)
 {
+    JSSPlayerChannel *chn = &(mp->channels[channel]);
     JSSNote *currNote;
     int param, paramX, paramY, tmp;
     char effect;
 
     // Process the volume column effects
-    JMPGETNOTE(currNote, mp->iRow, channel);
+    JMPGETNOTE(currNote, mp->row, channel);
     JMPMAKEPARAM(currNote->volume, paramX, paramY);
 
     switch (paramX)
     {
         case 0x05: // -x = Volumeslide Down : IMPL.VERIFIED
-            jmpChangeVolume(mp, channel, -paramY);
+            jmpChangeVolume(chn, channel, -paramY);
             break;
 
         case 0x06: // +x = Volumeslide Down : IMPL.VERIFIED
-            jmpChangeVolume(mp, channel, paramY);
+            jmpChangeVolume(chn, channel, paramY);
             break;
 
         case 0x0a: // Vx = Vibrato : IMPL.VERIFIED
-            jmpDoVibrato(mp, channel);
+            jmpDoVibrato(mp, chn, channel);
             break;
 
         case 0x0e: // Mx = Porta To Note : IMPL.VERIFIED
-            jmpDoPortamento(mp, channel);
+            jmpDoPortamento(chn, channel);
             break;
     }
 
@@ -1357,71 +1277,71 @@
     switch (effect)
     {
         case '0': // 0xy = Arpeggio
-            jmpDoArpeggio(mp, channel, paramX, paramY);
+            jmpDoArpeggio(mp, chn, channel, paramX, paramY);
             break;
 
         case '1': // 1xy = Portamento Up
-            if (mp->iLastPortaParam[channel] > 0)
-                jmpChangePitch(mp, channel, -(mp->iLastPortaParam[channel] * 4));
+            if (chn->iLastPortaParam > 0)
+                jmpChangePitch(chn, channel, -(chn->iLastPortaParam * 4));
             break;
 
         case '2': // 2xy = Portamento Down
-            if (mp->iLastPortaParam[channel] > 0)
-                jmpChangePitch(mp, channel, (mp->iLastPortaParam[channel] * 4));
+            if (chn->iLastPortaParam > 0)
+                jmpChangePitch(chn, channel, (chn->iLastPortaParam * 4));
             break;
 
         case '3': // 3xy = Porta To Note
-            jmpDoPortamento(mp, channel);
+            jmpDoPortamento(chn, channel);
             break;
 
         case '4': // 4xy = Vibrato
-            jmpDoVibrato(mp, channel);
+            jmpDoVibrato(mp, chn, channel);
             break;
 
         case '5': // 5xy = Portamento + Volume Slide
-            jmpDoPortamento(mp, channel);
-            jmpDoVolumeSlide(mp, channel, mp->iLastVolSlideParam[channel]);
+            jmpDoPortamento(chn, channel);
+            jmpDoVolumeSlide(chn, channel, chn->iLastVolSlideParam);
             break;
 
         case '6': // 6xy = Vibrato + Volume Slide
-            jmpDoVibrato(mp, channel);
-            jmpDoVolumeSlide(mp, channel, mp->iLastVolSlideParam[channel]);
+            jmpDoVibrato(mp, chn, channel);
+            jmpDoVolumeSlide(chn, channel, chn->iLastVolSlideParam);
             break;
 
         case '7': // 7xy = Tremolo
-            jmpDoTremolo(mp, channel);
+            jmpDoTremolo(mp, chn, channel);
             break;
 
         case 'A': // Axy = Volume slide
-            jmpDoVolumeSlide(mp, channel, mp->iLastVolSlideParam[channel]);
+            jmpDoVolumeSlide(chn, channel, chn->iLastVolSlideParam);
             break;
 
         case 'E': // Exy = Special Effects
             switch (paramX)
             {
                 case 0x0c: // ECx - Set Note Cut
-                    if (mp->iTick == paramY)
-                        jmpSetVolume(mp, channel, jsetMinVol);
+                    if (mp->tick == paramY)
+                        jmpSetVolume(chn, channel, jsetMinVol);
                     break;
 
                 case 0x0d: // EDx - Set Note Delay
-                    if (mp->iTick == paramY)
-                        mp->iCNewDataFlags[channel] = mp->iSaveNDFlags[channel];
+                    if (mp->tick == paramY)
+                        chn->iCNewDataFlags = chn->iSaveNDFlags;
                     break;
             }
             break;
 
         case 'T': // Txy = Tremor
-            JMPMAKEPARAM(mp->iLastTremorParam[channel], paramX, paramY)
+            JMPMAKEPARAM(chn->iLastTremorParam, paramX, paramY)
             paramX++;
             paramY++;
-            tmp = (mp->iTremorCount[channel] % (paramX + paramY));
+            tmp = (chn->iTremorCount % (paramX + paramY));
             if (tmp < paramX)
-                jmpCSetVolume(mp, channel, mp->iCVolume[channel]);
+                jmpCSetVolume(mp, chn, channel, chn->iCVolume);
             else
-                jmpCSetVolume(mp, channel, jsetMinVol);
+                jmpCSetVolume(mp, chn, channel, jsetMinVol);
 
-            mp->iTremorCount[channel] = (tmp + 1);
+            chn->iTremorCount = (tmp + 1);
             break;
     }
 }
@@ -1443,8 +1363,8 @@
     JSS_LOCK(mp);
 
     dev = (JSSMixer *) pDEV;
-    assert(mp->pDevice == dev);
-    assert(mp->pModule != NULL);
+    assert(mp->device == dev);
+    assert(mp->module != NULL);
 
     // Check if we are playing
     if (!mp->isPlaying)
@@ -1453,64 +1373,66 @@
     // Clear channel new data flags
     mp->jumpFlag = FALSE;
     mp->breakFlag = FALSE;
-    memset(mp->iCNewDataFlags, 0, sizeof(mp->iCNewDataFlags));
 
-//fprintf(stderr, "1: iTick=%d, iOrder=%d, iPattern=%d, iRow=%d\n", mp->iTick, mp->iOrder, mp->iPattern, mp->iRow);
+    for (channel = 0; channel < jsetNChannels; channel++)
+        mp->channels[channel].iCNewDataFlags = 0;
+
+//fprintf(stderr, "1: tick=%d, order=%d, iPattern=%d, row=%d\n", mp->tick, mp->order, mp->npattern, mp->row);
 
     // Check for init-tick
-    if (mp->iTick < 0)
+    if (mp->tick < 0)
     {
         // Initialize pattern
-        if (mp->iOrder != jsetNotSet)
-            jmpSetNewOrder(mp, mp->iOrder);
+        if (mp->order != jsetNotSet)
+            jmpSetNewOrder(mp, mp->order);
 
-        mp->iNewRow = 0;
+        mp->newRow = 0;
         mp->newRowSet = TRUE;
-        mp->iTick = mp->iSpeed;
+        mp->tick = mp->speed;
     }
 
-//fprintf(stderr, "2: iTick=%d, iOrder=%d, iPattern=%d, iRow=%d\n", mp->iTick, mp->iOrder, mp->iPattern, mp->iRow);
+//fprintf(stderr, "2: tick=%d, order=%d, iPattern=%d, row=%d\n", mp->tick, mp->order, mp->npattern, mp->row);
 
     // Check if we are playing
     if (!mp->isPlaying)
         goto out;
 
-    assert(mp->pPattern);
+    assert(mp->pattern);
 
     // Update the tick
-    mp->iTick++;
-    if (mp->iTick >= mp->iSpeed)
+    mp->tick++;
+    if (mp->tick >= mp->speed)
     {
         // Re-init tick counter
-        mp->iTick = 0;
+        mp->tick = 0;
 
         // Check pattern delay
-        if (mp->iPatternDelay > 0)
-            mp->iPatternDelay--;
+        if (mp->patternDelay > 0)
+            mp->patternDelay--;
         else
         {
             // New pattern row
             if (mp->newRowSet)
             {
-                mp->iRow = mp->iNewRow;
+                mp->row = mp->newRow;
                 mp->newRowSet = FALSE;
             } else
-                mp->iRow++;
+                mp->row++;
 
             // Check for end of pattern
-            if (mp->iRow >= mp->pPattern->nrows)
+            if (mp->row >= mp->pattern->nrows)
             {
                 // Go to next order
-                if (mp->iOrder != jsetNotSet)
-                    jmpSetNewOrder(mp, mp->iOrder + 1);
+                if (mp->order != jsetNotSet)
+                    jmpSetNewOrder(mp, mp->order + 1);
                 else
                     mp->isPlaying = FALSE;
                 
                 // Check for FT2 quirks
                 if (JMPGETMODFLAGS(mp, jmdfFT2Replay))
-                    mp->iRow = mp->iLastPatLoopRow;
+                    mp->row = mp->lastPatLoopRow;
                 else
-                    mp->iRow = 0;
+                    mp->row = 0;
             }
 
             if (!mp->isPlaying)
@@ -1519,28 +1441,28 @@
             // Check current order
             if (mp->newOrderSet)
             {
-                jmpSetNewOrder(mp, mp->iNewOrder);
+                jmpSetNewOrder(mp, mp->newOrder);
                 mp->newOrderSet = FALSE;
             }
 
-//fprintf(stderr, "3: iTick=%d, iOrder=%d, iPattern=%d, iRow=%d\n", mp->iTick, mp->iOrder, mp->iPattern, mp->iRow);
+//fprintf(stderr, "3: tick=%d, order=%d, iPattern=%d, row=%d\n", mp->tick, mp->order, mp->npattern, mp->row);
 
             if (!mp->isPlaying)
                 goto out;
 
             // TICK #0: Process new row
-            for (channel = 0; channel < mp->pModule->nchannels; channel++)
+            for (channel = 0; channel < mp->module->nchannels; channel++)
                 jmpProcessNewRow(mp, channel);
-        } // iPatternDelay
-    } // iTick
+        } // patternDelay
+    } // tick
     else
     {
         // Implement FT2's pattern delay-effect: don't update effects while on patdelay
         if (!JMPGETMODFLAGS(mp, jmdfFT2Replay) ||
-            (JMPGETMODFLAGS(mp, jmdfFT2Replay) && mp->iPatternDelay <= 0))
+            (JMPGETMODFLAGS(mp, jmdfFT2Replay) && mp->patternDelay <= 0))
         {
             // TICK n: Process the effects
-            for (channel = 0; channel < mp->pModule->nchannels; channel++)
+            for (channel = 0; channel < mp->module->nchannels; channel++)
                 jmpProcessEffects(mp, channel);
         }
     }
@@ -1550,41 +1472,52 @@
         goto out;
 
     // Update player data to audio device/mixer
-    for (channel = 0; channel < mp->pModule->nchannels; channel++)
+    for (channel = 0; channel < mp->module->nchannels; channel++)
     {
+        JSSPlayerChannel *chn = &mp->channels[channel];
+
         // Process extended instruments
-        jmpProcessExtInstrument(mp, channel);
+        jmpProcessExtInstrument(mp, chn, channel);
         
         // Check NDFlags and update channel data
-        flags = mp->iCNewDataFlags[channel];
+        flags = chn->iCNewDataFlags;
         if (flags)
         {
             // Check if we stop?
             if (flags & cdfStop)
-                jmpCStop(mp, channel);
+            {
+                jvmStop(mp->device, channel);
+            }
             else
             {
                 // No, handle other flags
                 if (flags & cdfNewInstr)
                 {
-                    jmpCSetInstrument(mp, channel);
-                    jmpCPlay(mp, channel);
+                    JSSInstrument *instr = chn->iCInstrument;
+                    if (instr != NULL)
+                    {
+                        jvmSetSample(mp->device, channel,
+                            instr->data, instr->size,
+                            instr->loopS, instr->loopE,
+                            instr->flags);
+                    }
+                    jvmPlay(mp->device, channel);
                 }
 
                 if (flags & cdfNewPitch)
-                    jmpCSetPitch(mp, channel, mp->iCPitch[channel]);
+                    jmpCSetPitch(mp, channel, chn->iCPitch);
 
                 if (flags & cdfNewPos)
-                    jmpCSetPosition(mp, channel, mp->iCPosition[channel]);
+                    jmpCSetPosition(mp, channel, chn->iCPosition);
 
                 if (flags & cdfNewVolume)
-                    jmpCSetVolume(mp, channel, mp->iCVolume[channel]);
+                    jmpCSetVolume(mp, chn, channel, chn->iCVolume);
 
                 if (flags & cdfNewPanPos)
-                    jmpCSetPanning(mp, channel, mp->iCPanning[channel]);
+                    jmpCSetPanning(mp, chn, channel, chn->iCPanning);
 
                 if (flags & cdfNewGlobalVol)
-                    jvmSetGlobalVol(mp->pDevice, mp->iGlobalVol);
+                    jvmSetGlobalVol(mp->device, mp->globalVol);
             }
         }
     }
--- a/jssplr.h	Mon Oct 01 04:18:15 2012 +0300
+++ b/jssplr.h	Mon Oct 01 06:28:29 2012 +0300
@@ -29,40 +29,11 @@
 #define cdfStop             (0x80)    // Stop channel playing
 
 
-// Typedefs for channel structures
-typedef int                  JDInt[jsetNChannels];
-typedef BOOL                 JDBool[jsetNChannels];
-typedef JSSInstrument *      JDInst[jsetNChannels];
-typedef JSSExtInstrument *   JDEInst[jsetNChannels];
-
-
-// Struct holding all player related information
+// Player channel structure
 typedef struct
 {
-    // General variables
-    int     iTempo,                 // Current values
-            iSpeed,
-            iTick,
-            iOrder,
-            iPattern,
-            iRow,
-            iGlobalVol,
-            iOptions;               // Playing option flags
-    BOOL    isPlaying;              // Are we playing?
-
-    int     iNewOrder,              // NEW order number
-            iNewRow;                // NEW row number
-    BOOL    newOrderSet,            // TRUE if new order has been set
-            newRowSet;              // TRUE if new row has been set
-
-    // Parameters for effects, etc
-    BOOL    jumpFlag,               // Pattern jump flag
-            breakFlag;              // Pattern break flag
-    int     iPatternDelay,          // Pattern delay tick-counter
-            iLastPatLoopRow;        // Latest set pattern loop row (any channel)
-
-    JDInt   iPatLoopRow,            // Pattern loop start row for each channel
-            iPatLoopCount,          // Pattern loop count for each channel
+    int     iPatLoopRow,            // Pattern loop start row
+            iPatLoopCount,          // Pattern loop count
         
             iLastPortaParam,        // Last portamento effect parameter
             iLastPortaToNoteParam,  // Last porta-to-note parameter
@@ -89,17 +60,18 @@
             iSaveNDFlags;           // For notedelay-effect
 
     // Current channel data
-    JDInst  iCInstrument;           // Instruments
-    JDEInst iCExtInstrument;       // ExtInstruments
-    JDInt   iCInstrumentN,
+    JSSInstrument  *iCInstrument;           // Instrument
+    JSSExtInstrument *iCExtInstrument;       // ExtInstrument
+    int     iCInstrumentN,
             iCExtInstrumentN,
+            iCNote,                 // Current note
+            iCPitch,                // Pitch (NOT actual frequency!)
+            iCOldPitch,
+            iCPosition,             // Sample position
+            iCVolume,               // Volume
+            iCPanning,              // Panning position
+
             iCNewDataFlags,         // New data flags
-            iCNote,                 // Current notes
-            iCPitch,                // Pitches (NOT actual frequencies!)
-            iCOldPitch,
-            iCPosition,             // Sample positions
-            iCVolume,               // Volumes
-            iCPanning,              // Panning positions
 
             iCFadeOutVol,
 
@@ -117,14 +89,47 @@
             iCLastFinePortamentoUpParam,
             iCLastFinePortamentoDownParam;
     
-    JDBool  iCPanEnv_Exec,
+    BOOL    iCPanEnv_Exec,
             iCVolEnv_Exec,
             iCKeyOff;
+} JSSPlayerChannel;
+
+
+// Struct holding all player related information
+typedef struct
+{
+    // General variables
+    int     tempo,              // Current values
+            speed,
+            tick,
+            order,
+            npattern,
+            row,
+            globalVol,
+            options;            // Playing option flags
+    BOOL    isPlaying;          // Are we playing?
+
+    int     newOrder,           // NEW order number
+            newRow;             // NEW row number
+    BOOL    newOrderSet,        // TRUE if new order has been set
+            newRowSet;          // TRUE if new row has been set
+
+    int     patternDelay,       // Pattern delay tick-counter
+            lastPatLoopRow;     // Latest set pattern loop row (any channel)
+
+
+    // All channels for this player
+//    int     nchannels;
+    JSSPlayerChannel channels[jsetNChannels];
+
+    // Parameters for effects, etc
+    BOOL    jumpFlag,           // Pattern jump flag
+            breakFlag;          // Pattern break flag
 
     // Module and sounddevice specific
-    JSSModule *pModule;          // Current module in this player
-    JSSPattern *pPattern;        // Current pattern
-    JSSMixer *pDevice;           // Pointer to mixing device structure
+    JSSModule *module;          // Current module in this player
+    JSSPattern *pattern;        // Current pattern
+    JSSMixer *device;           // Pointer to mixing device structure
 
 #ifdef JSS_SUP_THREADS
     DMMutex *mutex;
@@ -148,11 +153,11 @@
 /* Helper macros
  */
 #define JMPMAKEPARAM(AIVAL, AVALX, AVALY) { AVALX = (((AIVAL) >> 4) & 0x0f); AVALY = ((AIVAL) & 0x0f); }
-#define JMPSETNDFLAGS(IVAL) mp->iCNewDataFlags[channel] |= IVAL
-#define JMPUNSETNDFLAGS(IVAL) mp->iCNewDataFlags[channel] &= (~(IVAL))
-#define JMPGETNOTE(MNOTE, MROW, MCHAN) assert(mp); assert(mp->pPattern); assert((MROW) >= 0); assert((MROW) < mp->pPattern->nrows); MNOTE = &mp->pPattern->data[(mp->pPattern->nchannels * MROW) + (MCHAN)]
+#define JMPSETNDFLAGS(IVAL) chn->iCNewDataFlags |= IVAL
+#define JMPUNSETNDFLAGS(IVAL) chn->iCNewDataFlags &= (~(IVAL))
+#define JMPGETNOTE(MNOTE, MROW, MCHAN) assert(mp); assert(mp->pattern); assert((MROW) >= 0); assert((MROW) < mp->pattern->nrows); MNOTE = &mp->pattern->data[(mp->pattern->nchannels * MROW) + (MCHAN)]
 #define JMPGETEFFECT(MEFF, MIEFF) if ((MIEFF >= 0) && (MIEFF < jmpNMODEffectTable)) MEFF = jmpMODEffectTable[MIEFF]; else MEFF = 0
-#define JMPGETMODFLAGS(Q, Z) ((Q->pModule->defFlags & (Z)) == (Z))
+#define JMPGETMODFLAGS(Q, Z) ((Q->module->defFlags & (Z)) == (Z))
 
 
 /* Debugging macros
--- a/testpl.c	Mon Oct 01 04:18:15 2012 +0300
+++ b/testpl.c	Mon Oct 01 06:28:29 2012 +0300
@@ -247,11 +247,11 @@
     SDL_PauseAudio(0);
     while (p->isPlaying)
     {
-        int r = p->iRow;
-        while (r == p->iRow && p->isPlaying)
+        int r = p->row;
+        while (r == p->row && p->isPlaying)
             SDL_Delay(50);
 
-        printRow(stdout, p->pPattern, p->iRow);
+        printRow(stdout, p->pattern, p->row);
         printf("\n");
     }