From 6ec8674072438e19d37588bcd36c64f26b73abe4 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 19 May 2022 04:36:26 -0500 Subject: [PATCH] SoundUnit: many fixes. implement effects --- src/engine/dispatch.h | 7 ++ src/engine/platform/sound/su.cpp | 2 +- src/engine/platform/su.cpp | 127 ++++++++++++++++++++++++++++++- src/engine/platform/su.h | 20 ++++- src/engine/playback.cpp | 7 ++ src/engine/sysDef.cpp | 71 ++++++++++++++++- 6 files changed, 226 insertions(+), 8 deletions(-) diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index bf80c645e..c7e892a9f 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -169,6 +169,13 @@ enum DivDispatchCmds { DIV_CMD_N163_GLOBAL_WAVE_LOADLEN, DIV_CMD_N163_GLOBAL_WAVE_LOADMODE, + DIV_CMD_SU_SWEEP_PERIOD_LOW, // (which, val) + DIV_CMD_SU_SWEEP_PERIOD_HIGH, // (which, val) + DIV_CMD_SU_SWEEP_BOUND, // (which, val) + DIV_CMD_SU_SWEEP_ENABLE, // (which, val) + DIV_CMD_SU_SYNC_PERIOD_LOW, + DIV_CMD_SU_SYNC_PERIOD_HIGH, + DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol DIV_CMD_MAX diff --git a/src/engine/platform/sound/su.cpp b/src/engine/platform/sound/su.cpp index a9e6d2430..b7fa731a6 100644 --- a/src/engine/platform/sound/su.cpp +++ b/src/engine/platform/sound/su.cpp @@ -110,7 +110,7 @@ void SoundUnit::NextSample(short* l, short* r) { } } } - fns[i]=ns[i]*chan[i].vol*2; + fns[i]=ns[i]*chan[i].vol*(chan[i].flags.pcm?4:2); if (chan[i].flags.fmode!=0) { int ff=chan[i].cutoff; nslow[i]=nslow[i]+(((ff)*nsband[i])>>16); diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index 724fb5901..26cee340f 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -73,6 +73,12 @@ const char* DivPlatformSoundUnit::getEffectName(unsigned char effect) { case 0x1d: return "1Dxx: Set cutoff sweep boundary"; break; + case 0x1e: + return "17xx: Set phase reset period low byte"; + break; + case 0x1f: + return "18xx: Set phase reset period high byte"; + break; case 0x20: return "20xx: Toggle frequency sweep (bit 0-6: speed; bit 7: direction is up)"; break; @@ -169,7 +175,7 @@ void DivPlatformSoundUnit::tick(bool sysTick) { chan[i].freqChanged=true; } if (chan[i].std.ex1.had) { - chan[i].cutoff=chan[i].std.ex1.val&16383; + chan[i].cutoff=((chan[i].std.ex1.val&16383)*chan[i].baseCutoff)/16380; chWrite(i,0x06,chan[i].cutoff&0xff); chWrite(i,0x07,chan[i].cutoff>>8); } @@ -208,9 +214,11 @@ void DivPlatformSoundUnit::tick(bool sysTick) { DivSample* sample=parent->getSample(ins->amiga.getSample(chan[i].note)); if (sample!=NULL) { unsigned int sampleEnd=sample->offSU+sample->samples; + unsigned int off=sample->offSU+chan[i].hasOffset; + chan[i].hasOffset=0; if (sampleEnd>=getSampleMemCapacity(0)) sampleEnd=getSampleMemCapacity(0)-1; - chWrite(i,0x0a,sample->offSU&0xff); - chWrite(i,0x0b,sample->offSU>>8); + chWrite(i,0x0a,off&0xff); + chWrite(i,0x0b,off>>8); chWrite(i,0x0c,sampleEnd&0xff); chWrite(i,0x0d,sampleEnd>>8); if (sample->loopStart>=0 && sample->loopStart<(int)sample->samples) { @@ -242,6 +250,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SU); if (chan[c.chan].pcm && ins->type!=DIV_INS_AMIGA) { + chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA); writeControl(c.chan); writeControlUpper(c.chan); } @@ -293,7 +302,113 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) { chan[c.chan].freqChanged=true; break; case DIV_CMD_WAVE: - chan[c.chan].wave=c.value; + chan[c.chan].wave=c.value&7; + writeControl(c.chan); + break; + case DIV_CMD_STD_NOISE_MODE: + chan[c.chan].duty=c.value&127; + chWrite(c.chan,0x08,chan[c.chan].duty); + break; + case DIV_CMD_C64_RESONANCE: + chan[c.chan].res=c.value; + chWrite(c.chan,0x09,chan[c.chan].res); + break; + case DIV_CMD_C64_FILTER_MODE: + chan[c.chan].control=c.value&15; + break; + case DIV_CMD_SU_SWEEP_PERIOD_LOW: { + switch (c.value) { + case 0: + chan[c.chan].freqSweepP=(chan[c.chan].freqSweepP&0xff00)|c.value2; + chWrite(c.chan,0x10,chan[c.chan].freqSweepP&0xff); + break; + case 1: + chan[c.chan].volSweepP=(chan[c.chan].volSweepP&0xff00)|c.value2; + chWrite(c.chan,0x14,chan[c.chan].volSweepP&0xff); + break; + case 2: + chan[c.chan].cutSweepP=(chan[c.chan].cutSweepP&0xff00)|c.value2; + chWrite(c.chan,0x18,chan[c.chan].cutSweepP&0xff); + break; + } + break; + } + case DIV_CMD_SU_SWEEP_PERIOD_HIGH: { + switch (c.value) { + case 0: + chan[c.chan].freqSweepP=(chan[c.chan].freqSweepP&0xff)|(c.value2<<8); + chWrite(c.chan,0x11,chan[c.chan].freqSweepP>>8); + break; + case 1: + chan[c.chan].volSweepP=(chan[c.chan].volSweepP&0xff)|(c.value2<<8); + chWrite(c.chan,0x15,chan[c.chan].volSweepP>>8); + break; + case 2: + chan[c.chan].cutSweepP=(chan[c.chan].cutSweepP&0xff)|(c.value2<<8); + chWrite(c.chan,0x19,chan[c.chan].cutSweepP>>8); + break; + } + break; + } + case DIV_CMD_SU_SWEEP_BOUND: { + switch (c.value) { + case 0: + chan[c.chan].freqSweepB=c.value2; + chWrite(c.chan,0x13,chan[c.chan].freqSweepB); + break; + case 1: + chan[c.chan].volSweepB=c.value2; + chWrite(c.chan,0x17,chan[c.chan].volSweepB); + break; + case 2: + chan[c.chan].cutSweepB=c.value2; + chWrite(c.chan,0x1b,chan[c.chan].cutSweepB); + break; + } + break; + } + case DIV_CMD_SU_SWEEP_ENABLE: { + switch (c.value) { + case 0: + chan[c.chan].freqSweepV=c.value2; + chan[c.chan].freqSweep=(c.value2>0); + chWrite(c.chan,0x12,chan[c.chan].freqSweepV); + break; + case 1: + chan[c.chan].volSweepV=c.value2; + chan[c.chan].volSweep=(c.value2>0); + chWrite(c.chan,0x16,chan[c.chan].volSweepV); + break; + case 2: + chan[c.chan].cutSweepV=c.value2; + chan[c.chan].cutSweep=(c.value2>0); + chWrite(c.chan,0x1a,chan[c.chan].cutSweepV); + break; + } + writeControlUpper(c.chan); + break; + } + case DIV_CMD_SU_SYNC_PERIOD_LOW: + chan[c.chan].syncTimer=(chan[c.chan].syncTimer&0xff00)|c.value; + chan[c.chan].timerSync=(chan[c.chan].syncTimer>0); + chWrite(c.chan,0x1e,chan[c.chan].syncTimer&0xff); + chWrite(c.chan,0x1f,chan[c.chan].syncTimer>>8); + writeControlUpper(c.chan); + break; + case DIV_CMD_SU_SYNC_PERIOD_HIGH: + chan[c.chan].syncTimer=(chan[c.chan].syncTimer&0xff)|(c.value<<8); + chan[c.chan].timerSync=(chan[c.chan].syncTimer>0); + chWrite(c.chan,0x1e,chan[c.chan].syncTimer&0xff); + chWrite(c.chan,0x1f,chan[c.chan].syncTimer>>8); + writeControlUpper(c.chan); + break; + case DIV_CMD_C64_FINE_CUTOFF: + chan[c.chan].baseCutoff=c.value; + if (!chan[c.chan].std.ex1.has) { + chan[c.chan].cutoff=chan[c.chan].baseCutoff; + chWrite(c.chan,0x06,chan[c.chan].cutoff&0xff); + chWrite(c.chan,0x07,chan[c.chan].cutoff>>8); + } break; case DIV_CMD_NOTE_PORTA: { int destFreq=NOTE_FREQUENCY(c.value2); @@ -323,6 +438,10 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) { chWrite(c.chan,0x03,chan[c.chan].pan); break; } + case DIV_CMD_SAMPLE_POS: + chan[c.chan].hasOffset=c.value; + chan[c.chan].keyOn=true; + break; case DIV_CMD_LEGATO: chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].freqChanged=true; diff --git a/src/engine/platform/su.h b/src/engine/platform/su.h index 22ea1e78d..857ae7251 100644 --- a/src/engine/platform/su.h +++ b/src/engine/platform/su.h @@ -28,11 +28,15 @@ class DivPlatformSoundUnit: public DivDispatch { struct Channel { int freq, baseFreq, pitch, pitch2, note; - int ins, cutoff, res, control; + int ins, cutoff, baseCutoff, res, control, hasOffset; signed char pan; unsigned char duty; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, noise, pcm, phaseReset, filterPhaseReset; bool pcmLoop, timerSync, freqSweep, volSweep, cutSweep; + unsigned short freqSweepP, volSweepP, cutSweepP; + unsigned char freqSweepB, volSweepB, cutSweepB; + unsigned char freqSweepV, volSweepV, cutSweepV; + unsigned short syncTimer; signed char vol, outVol, wave; DivMacroInt std; void macroInit(DivInstrument* which) { @@ -46,9 +50,11 @@ class DivPlatformSoundUnit: public DivDispatch { pitch2(0), note(0), ins(-1), - cutoff(65535), + cutoff(16383), + baseCutoff(16380), res(0), control(0), + hasOffset(0), pan(0), duty(63), active(false), @@ -66,6 +72,16 @@ class DivPlatformSoundUnit: public DivDispatch { freqSweep(false), volSweep(false), cutSweep(false), + freqSweepP(0), + volSweepP(0), + cutSweepP(0), + freqSweepB(0), + volSweepB(0), + cutSweepB(0), + freqSweepV(0), + volSweepV(0), + cutSweepV(0), + syncTimer(0), vol(127), outVol(127), wave(0) {} diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 0667522bb..f8c3847f6 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -171,6 +171,13 @@ const char* cmdName[]={ "N163_GLOBAL_WAVE_LOADLEN", "N163_GLOBAL_WAVE_LOADMODE", + "DIV_CMD_SU_SWEEP_PERIOD_LOW", + "DIV_CMD_SU_SWEEP_PERIOD_HIGH", + "DIV_CMD_SU_SWEEP_BOUND", + "DIV_CMD_SU_SWEEP_ENABLE", + "DIV_CMD_SU_SYNC_PERIOD_LOW", + "DIV_CMD_SU_SYNC_PERIOD_HIGH", + "ALWAYS_SET_VOLUME" }; diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 10f8907f4..a60ccf179 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -17,6 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "dispatch.h" #include "engine.h" #include "song.h" #include "../ta-log.h" @@ -1862,7 +1863,75 @@ void DivEngine::registerSystems() { {"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"}, {DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, {DIV_INS_SU, DIV_INS_SU, DIV_INS_SU, DIV_INS_SU, DIV_INS_SU, DIV_INS_SU, DIV_INS_SU, DIV_INS_SU}, - {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA} + {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, + [](int,unsigned char,unsigned char) -> bool {return false;}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x10: // waveform + dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); + break; + case 0x12: // duty cycle + dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); + break; + case 0x13: // resonance + dispatchCmd(DivCommand(DIV_CMD_C64_RESONANCE,ch,effectVal)); + break; + case 0x14: // filter mode + dispatchCmd(DivCommand(DIV_CMD_C64_FILTER_MODE,ch,effectVal)); + break; + case 0x15: // freq sweep + dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_PERIOD_LOW,ch,0,effectVal)); + break; + case 0x16: // freq sweep + dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_PERIOD_HIGH,ch,0,effectVal)); + break; + case 0x17: // vol sweep + dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_PERIOD_LOW,ch,1,effectVal)); + break; + case 0x18: // vol sweep + dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_PERIOD_HIGH,ch,1,effectVal)); + break; + case 0x19: // cut sweep + dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_PERIOD_LOW,ch,2,effectVal)); + break; + case 0x1a: // cut sweep + dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_PERIOD_HIGH,ch,2,effectVal)); + break; + case 0x1b: // freq sweep bound + dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_BOUND,ch,0,effectVal)); + break; + case 0x1c: // vol sweep bound + dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_BOUND,ch,1,effectVal)); + break; + case 0x1d: // cut sweep bound + dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_BOUND,ch,2,effectVal)); + break; + case 0x1e: // sync low + dispatchCmd(DivCommand(DIV_CMD_SU_SYNC_PERIOD_LOW,ch,effectVal)); + break; + case 0x1f: // sync high + dispatchCmd(DivCommand(DIV_CMD_SU_SYNC_PERIOD_HIGH,ch,effectVal)); + break; + case 0x20: // freq sweep enable + dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_ENABLE,ch,0,effectVal)); + break; + case 0x21: // vol sweep enable + dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_ENABLE,ch,1,effectVal)); + break; + case 0x22: // cut sweep enable + dispatchCmd(DivCommand(DIV_CMD_SU_SWEEP_ENABLE,ch,2,effectVal)); + break; + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: // cutoff + dispatchCmd(DivCommand(DIV_CMD_C64_FINE_CUTOFF,ch,(((effect&0x0f)<<8)|effectVal)*4)); + break; + default: + return false; + } + return true; + } ); sysDefs[DIV_SYSTEM_MSM6295]=new DivSysDef(