From fc174162f71916878345cf02b5a9adeedeea20b4 Mon Sep 17 00:00:00 2001 From: Norbert Lange Date: Tue, 9 Jun 2009 20:54:55 +0000 Subject: tfmx.c,.h: added portamento and envelope-effect (envelope not active yet) renamed some variables made sure the fixed-point multiplications have the same results, even in cornercases paula.cpp: changed/reverted stuff in Paula again. svn-id: r41410 --- sound/mods/paula.cpp | 8 +--- sound/mods/tfmx.cpp | 124 +++++++++++++++++++++++++++++++++++++-------------- sound/mods/tfmx.h | 23 +++++----- tfmx/tfmxdebug.cpp | 9 ++++ tfmx/tfmxdebug.h | 1 + 5 files changed, 114 insertions(+), 51 deletions(-) diff --git a/sound/mods/paula.cpp b/sound/mods/paula.cpp index 40b5a904e6..9f2eb4290a 100644 --- a/sound/mods/paula.cpp +++ b/sound/mods/paula.cpp @@ -147,6 +147,7 @@ int Paula::readBufferIntern(int16 *buffer, const int numSamples) { _voice[voice].data = data = _voice[voice].dataRepeat; _voice[voice].length = _voice[voice].lengthRepeat; sLen = intToFrac(_voice[voice].length); + // TODO: the value in offset shouldnt be dropped but scaled to new rate if (_voice[voice].period != _voice[voice].periodRepeat) { _voice[voice].period = _voice[voice].periodRepeat; @@ -162,6 +163,7 @@ int Paula::readBufferIntern(int16 *buffer, const int numSamples) { // Repeat as long as necessary. while (neededSamples > 0) { + // TODO offset -= sLen, but only if same rate otherwise need to scale first offset &= FRAC_LO_MASK; dmaCount++; @@ -172,12 +174,6 @@ int Paula::readBufferIntern(int16 *buffer, const int numSamples) { } } - // TODO correctly handle setting registers after last 2 bytes red from channel - if (offset > sLen) { - offset &= FRAC_LO_MASK; - dmaCount++; - } - // Write back the cached data _voice[voice].offset = offset; _voice[voice].dmaCount = dmaCount; diff --git a/sound/mods/tfmx.cpp b/sound/mods/tfmx.cpp index 31f4df78c4..001895e6b9 100644 --- a/sound/mods/tfmx.cpp +++ b/sound/mods/tfmx.cpp @@ -79,15 +79,13 @@ void Tfmx::interrupt() { // see if we have to run the macro-program if (channel.macroRun) { - if (channel.macroWait == 0) { + if (!channel.macroWait) { // run macro while (macroStep(channel)) ; } else --channel.macroWait; } - // FIXME handle Volume - Paula::setChannelVolume(channel.paulaChannel, 0x40); } // Patterns are only processed each _playerCtx.timerCount + 1 tick @@ -114,22 +112,72 @@ void Tfmx::effects(ChannelContext &channel) { // vibrato if (channel.vibLength) { channel.vibValue += channel.vibDelta; - const uint16 setPeriod = (channel.period * ((1 << 11) + channel.vibValue)) >> 11; - - if (!channel.portaRate) - Paula::setChannelPeriod(channel.paulaChannel, setPeriod); - if (--channel.vibCount == 0) { channel.vibCount = channel.vibLength; channel.vibDelta = -channel.vibDelta; } + if (!channel.portaDelta) { + // 16x16 bit multiplication, casts needed for the right results + channel.period = (uint16)(((uint32)channel.refPeriod * (uint16)((1 << 11) + channel.vibValue)) >> 11); + Paula::setChannelPeriod(channel.paulaChannel, channel.period); + } } + // portamento + if (channel.portaDelta && !(--channel.portaCount)) { + channel.portaCount = channel.portaSkip; + bool resetPorta = true; + uint16 period = channel.refPeriod; + const uint16 portaVal = channel.portaValue; - // porta + if (period > portaVal) { + period = ((uint32)period * (uint16)((1 << 8) - channel.portaDelta)) >> 8; + resetPorta = (period <= portaVal); + + } else if (period < portaVal) { + period = ((uint32)period * (uint16)((1 << 8) + channel.portaDelta)) >> 8; + resetPorta = (period >= portaVal); + } + + if (resetPorta) { + channel.portaDelta = 0; + channel.portaValue = channel.refPeriod & 0x7FF; + } else { + channel.period = period & 0x7FF; + Paula::setChannelPeriod(channel.paulaChannel, channel.period); + } + } // envelope + if (channel.envSkip && !channel.envCount--) { + channel.envCount = channel.envSkip; + + const uint8 endVol = channel.envEndVolume; + int8 volume = channel.volume; + bool resetEnv = true; + + if (endVol > volume) { + volume += channel.envDelta; + resetEnv = endVol <= volume; + } else { + volume -= channel.envDelta; + resetEnv = volume < 0 || endVol >= volume; + } + + if (resetEnv) { + channel.envSkip = 0; + volume = endVol; + } + channel.volume = volume; + } + + // Fade + + // Volume + // FIXME + uint8 finVol = _playerCtx.volume * channel.volume >> 6; + Paula::setChannelVolume(channel.paulaChannel, 0x40); } FORCEINLINE bool Tfmx::macroStep(ChannelContext &channel) { @@ -137,7 +185,7 @@ FORCEINLINE bool Tfmx::macroStep(ChannelContext &channel) { ++channel.macroStep; //int channelNo = ((byte*)&channel-(byte*)_channelCtx)/sizeof(ChannelContext); - displayMacroStep(macroPtr); + displayMacroStep(macroPtr, channel.paulaChannel, channel.macroIndex); int32 temp = 0; @@ -151,7 +199,8 @@ FORCEINLINE bool Tfmx::macroStep(ChannelContext &channel) { channel.deferWait = macroPtr[1] >= 1; if (channel.deferWait) { // if set, then we expect a DMA On in the same tick. - Paula::setChannelPeriod(channel.paulaChannel, 4); + channel.period = 4; + Paula::setChannelPeriod(channel.paulaChannel, channel.period); Paula::setChannelSampleLen(channel.paulaChannel, 1); // in this state we then need to allow some commands that normally // would halt the macroprogamm to continue instead. @@ -204,6 +253,7 @@ FORCEINLINE bool Tfmx::macroStep(ChannelContext &channel) { return true; case 0x06: // Jump. Parameters: MacroIndex, MacroStep(W) + channel.macroIndex = macroPtr[1] % kMaxMacroOffsets; channel.macroOffset = _macroOffset[macroPtr[1] % kMaxMacroOffsets]; channel.macroStep = READ_BE_UINT16(¯oPtr[2]); channel.macroLoopCount = 0xFF; @@ -223,31 +273,35 @@ setNote: case 0x09: { // SetNote. Parameters: Note, Finetune(W) const uint16 noteInt = noteIntervalls[(temp + macroPtr[1]) & 0x3F]; const uint16 finetune = READ_BE_UINT16(¯oPtr[2]) + channel.fineTune + (1 << 8); - channel.portaDestPeriod = (uint16)((noteInt * finetune) >> 8); - if (!channel.portaRate) { - channel.period = channel.portaDestPeriod; - Paula::setChannelPeriod(channel.paulaChannel, channel.portaDestPeriod); + channel.refPeriod = ((uint32)noteInt * finetune >> 8); + if (!channel.portaDelta) { + channel.period = channel.refPeriod; + Paula::setChannelPeriod(channel.paulaChannel, channel.period); } return channel.deferWait; } case 0x0A: // Clear Effects - channel.envReset = 0; + channel.envSkip = 0; channel.vibLength = 0; - channel.portaRate = 0; + channel.portaDelta = 0; return true; case 0x0B: // Portamento. Parameters: count, speed - macroPtr[1]; - macroPtr[3]; + channel.portaSkip = macroPtr[1]; + channel.portaCount = 1; + // if porta is already running, then keep using old value + if (!channel.portaDelta) + channel.portaValue = channel.refPeriod; + channel.portaDelta = READ_BE_UINT16(¯oPtr[2]); return true; case 0x0C: // Vibrato. Parameters: Speed, intensity channel.vibLength = macroPtr[1]; channel.vibCount = macroPtr[1] / 2; channel.vibDelta = macroPtr[3]; - if (!channel.portaRate) { - // TODO: unnecessary command? + if (!channel.portaDelta) { + channel.period = channel.refPeriod; Paula::setChannelPeriod(channel.paulaChannel, channel.period); channel.vibValue = 0; } @@ -306,10 +360,10 @@ setNote: return true; case 0x17: // set Period. Parameters: Period(W) - channel.portaDestPeriod = READ_BE_UINT16(¯oPtr[2]); - if (!channel.portaRate) { - channel.period = channel.portaDestPeriod; - Paula::setChannelPeriod( channel.paulaChannel, channel.portaDestPeriod); + channel.refPeriod = READ_BE_UINT16(¯oPtr[2]); + if (!channel.portaDelta) { + channel.period = channel.refPeriod; + Paula::setChannelPeriod(channel.paulaChannel, channel.period); } return true; @@ -484,6 +538,7 @@ FORCEINLINE bool Tfmx::patternStep(PatternContext &pattern) { return false; case 5: // Kup^-Set key up + // TODO: add expose? case 6: // Vibrato case 7: // Envelope case 12: // Lock @@ -606,6 +661,7 @@ void Tfmx::noteCommand(const uint8 note, const uint8 param1, const uint8 param2, if (note < 0xC0) { // Play Note channel.prevNote = channel.note; channel.note = note; + channel.macroIndex = param1 % kMaxMacroOffsets; channel.macroOffset = _macroOffset[param1 % kMaxMacroOffsets]; channel.relVol = (param2 >> 4) & 0xF; channel.fineTune = (int16)param3; @@ -613,15 +669,15 @@ void Tfmx::noteCommand(const uint8 note, const uint8 param1, const uint8 param2, initMacroProgramm(channel); channel.keyUp = true; - } else if (note < 0xF0) { // do that porta stuff - channel.portaReset = param1; - channel.portaTime = 1; - if (!channel.portaRate) - channel.portaPeriod = channel.portaDestPeriod; - channel.portaRate = param3; + } else if (note < 0xF0) { // Portamento + channel.portaSkip = param1; + channel.portaCount = 1; + if (!channel.portaDelta) + channel.portaValue = channel.refPeriod; + channel.portaDelta = param3; channel.note = note & 0x3F; - channel.portaDestPeriod = noteIntervalls[channel.note]; + channel.refPeriod = noteIntervalls[channel.note]; } else switch (note & 0xF) { // Command case 5: // Key Up Release channel.keyUp = false; @@ -632,8 +688,8 @@ void Tfmx::noteCommand(const uint8 note, const uint8 param1, const uint8 param2, channel.vibValue = 0; break; case 7: // Envelope - channel.envRate = param1; - channel.envReset = channel.envTime = (param2 >> 4) + 1; + channel.envDelta = param1; + channel.envSkip = channel.envCount = (param2 >> 4) + 1; channel.envEndVolume = param3; break; } diff --git a/sound/mods/tfmx.h b/sound/mods/tfmx.h index 0f33ecb763..aa35b7ec6d 100644 --- a/sound/mods/tfmx.h +++ b/sound/mods/tfmx.h @@ -118,6 +118,7 @@ public: struct ChannelContext { byte paulaChannel; + byte macroIndex; uint16 macroWait; uint32 macroOffset; uint32 macroReturnOffset; @@ -136,23 +137,23 @@ public: uint32 sampleStart; uint16 sampleLen; + uint16 refPeriod; uint16 period; - int8 volume; + uint8 volume; uint8 relVol; uint8 note; uint8 prevNote; int16 fineTune; - uint16 portaDestPeriod; - uint16 portaPeriod; - uint8 portaReset; - uint8 portaTime; - int16 portaRate; + uint8 portaSkip; + uint8 portaCount; + uint16 portaDelta; + uint16 portaValue; - uint8 envReset; - uint8 envTime; - uint8 envRate; + uint8 envSkip; + uint8 envCount; + uint8 envDelta; uint8 envEndVolume; uint8 vibLength; @@ -211,11 +212,11 @@ public: } void clearEffects(ChannelContext &channel) { - channel.envReset = 0; + channel.envSkip = 0; channel.vibLength = 0; - channel.portaRate = 0; + channel.portaDelta = 0; } void stopChannel(ChannelContext &channel) { diff --git a/tfmx/tfmxdebug.cpp b/tfmx/tfmxdebug.cpp index f6ef03dc08..0c411582f8 100644 --- a/tfmx/tfmxdebug.cpp +++ b/tfmx/tfmxdebug.cpp @@ -120,6 +120,15 @@ void displayTrackstep(const void *const vptr) { } } +void displayMacroStep(const void *const vptr, int chan, int index) { + const byte *const macroData = (const byte *const)vptr; + + if (macroData[0] < ARRAYSIZE(macrocmds)) + debug("%02X %02X %s %02X%02X%02X", chan, index, macrocmds[macroData[0]], macroData[1], macroData[2], macroData[3]); + else + debug("%02X %02X Unkown Macro #%02X %02X%02X%02X", chan, index, macroData[0], macroData[1], macroData[2], macroData[3]); +} + void displayMacroStep(const void *const vptr) { const byte *const macroData = (const byte *const)vptr; diff --git a/tfmx/tfmxdebug.h b/tfmx/tfmxdebug.h index dba283b673..e849e561a9 100644 --- a/tfmx/tfmxdebug.h +++ b/tfmx/tfmxdebug.h @@ -4,6 +4,7 @@ void displayTrackstep(const void *const vptr); void displayPatternstep(const void *const vptr); void displayMacroStep(const void *const vptr); +void displayMacroStep(const void *const vptr, int chan, int index); void dumpTracksteps(Audio::Tfmx &player, uint16 first, uint16 last); void dumpTrackstepsBySong(Audio::Tfmx &player, int song); void dumpMacro(Audio::Tfmx &player, uint16 macroIndex, uint16 len = 0, uint16 start = 0); -- cgit v1.2.3