# HG changeset patch # User Matti Hamalainen # Date 1349646280 -10800 # Node ID 81f3993412ae0f03a1dd54d3af5b5e8f2fcaeae1 # Parent 9fa8e9326d18a19092290b170fa4a8dcd52095bf 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. diff -r 9fa8e9326d18 -r 81f3993412ae jssplr.c --- 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]); diff -r 9fa8e9326d18 -r 81f3993412ae jssplr.h --- 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,