diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 758fcb2fa..4c85ca138 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -279,6 +279,9 @@ enum DivDispatchCmds { DIV_CMD_SID3_FILTER_MATRIX, DIV_CMD_SID3_FILTER_ENABLE, + DIV_CMD_C64_PW_SLIDE, + DIV_CMD_C64_CUTOFF_SLIDE, + DIV_CMD_MAX }; diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index 04893e379..c394b2645 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -158,6 +158,24 @@ void DivPlatformC64::tick(bool sysTick) { int i=chanOrder[_i]; chan[i].std.next(); + + if(sysTick) + { + if(chan[i].pw_slide != 0) + { + chan[i].duty -= chan[i].pw_slide; + chan[i].duty = CLAMP(chan[i].duty, 0, 0xfff); + rWrite(i*7+2,chan[i].duty&0xff); + rWrite(i*7+3,(chan[i].duty>>8) | (chan[i].outVol << 4)); + } + if(cutoff_slide != 0) + { + filtCut += cutoff_slide; + filtCut = CLAMP(filtCut, 0, 0x7ff); + updateFilter(); + } + } + if (chan[i].std.vol.had) { vol=MIN(15,chan[i].std.vol.val); willUpdateFilter=true; @@ -535,6 +553,12 @@ int DivPlatformC64::dispatch(DivCommand c) { chan[c.chan].release=c.value&15; rWrite(c.chan*7+6,(chan[c.chan].sustain<<4)|(chan[c.chan].release)); break; + case DIV_CMD_C64_PW_SLIDE: + chan[c.chan].pw_slide = c.value * c.value2; + break; + case DIV_CMD_C64_CUTOFF_SLIDE: + cutoff_slide = c.value * c.value2; + break; case DIV_CMD_MACRO_OFF: chan[c.chan].std.mask(c.value,true); break; @@ -653,8 +677,11 @@ void DivPlatformC64::reset() { chan[i].std.setEngine(parent); fakeLow[i]=0; fakeBand[i]=0; + chan[i].pw_slide = 0; } + cutoff_slide = 0; + if (sidCore==2) { dSID_init(sid_d,chipClock,rate,sidIs6581?6581:8580,needInitTables); dSID_setMuteMask( diff --git a/src/engine/platform/c64.h b/src/engine/platform/c64.h index bd2e9d65e..cbc99ebc5 100644 --- a/src/engine/platform/c64.h +++ b/src/engine/platform/c64.h @@ -37,6 +37,7 @@ class DivPlatformC64: public DivDispatch { short duty; bool sweepChanged, filter; bool resetMask, resetFilter, resetDuty, gate, ring, sync, test; + short pw_slide; Channel(): SharedChannel(15), prevFreq(65535), @@ -56,7 +57,8 @@ class DivPlatformC64: public DivDispatch { gate(true), ring(false), sync(false), - test(false) {} + test(false), + pw_slide(0) {} }; Channel chan[3]; DivDispatchOscBuffer* oscBuf[3]; @@ -76,6 +78,7 @@ class DivPlatformC64: public DivDispatch { unsigned char writeOscBuf; unsigned char sidCore; int filtCut, resetTime, initResetTime; + short cutoff_slide; bool keyPriority, sidIs6581, needInitTables, no1EUpdate, multiplyRel, macroRace; unsigned char chanOrder[3]; diff --git a/src/engine/platform/sid2.cpp b/src/engine/platform/sid2.cpp index 90b0edc06..274dc7f3b 100644 --- a/src/engine/platform/sid2.cpp +++ b/src/engine/platform/sid2.cpp @@ -113,6 +113,24 @@ void DivPlatformSID2::tick(bool sysTick) { bool willUpdateFilter = false; chan[i].std.next(); + + if(sysTick) + { + if(chan[i].pw_slide != 0) + { + chan[i].duty -= chan[i].pw_slide; + chan[i].duty = CLAMP(chan[i].duty, 0, 0xfff); + rWrite(i*7+2,chan[i].duty&0xff); + rWrite(i*7+3,(chan[i].duty>>8) | (chan[i].outVol << 4)); + } + if(chan[i].cutoff_slide != 0) + { + chan[i].filtCut += chan[i].cutoff_slide; + chan[i].filtCut = CLAMP(chan[i].filtCut, 0, 0xfff); + updateFilter(i); + } + } + if (chan[i].std.vol.had) { chan[i].outVol=VOL_SCALE_LINEAR(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15); rWrite(i*7+3,(chan[i].duty>>8) | (chan[i].outVol << 4)); @@ -521,6 +539,12 @@ int DivPlatformSID2::dispatch(DivCommand c) { break; } break; + case DIV_CMD_C64_PW_SLIDE: + chan[c.chan].pw_slide = c.value * c.value2; + break; + case DIV_CMD_C64_CUTOFF_SLIDE: + chan[c.chan].cutoff_slide = c.value * c.value2; + break; case DIV_CMD_MACRO_OFF: chan[c.chan].std.mask(c.value,true); break; @@ -633,6 +657,9 @@ void DivPlatformSID2::reset() { chan[i].noise_mode = 0; rWrite(0x3 + 7 * i,0xf0); + + chan[i].cutoff_slide = 0; + chan[i].pw_slide = 0; } sid2->reset(); diff --git a/src/engine/platform/sid2.h b/src/engine/platform/sid2.h index f1dc71f3f..e44848f11 100644 --- a/src/engine/platform/sid2.h +++ b/src/engine/platform/sid2.h @@ -36,7 +36,8 @@ class DivPlatformSID2: public DivDispatch { unsigned char noise_mode; unsigned char mix_mode; int filtCut; - bool do_pw_sweep_writes, do_cutoff_sweep_writes; + short cutoff_slide; + short pw_slide; Channel(): SharedChannel(15), prevFreq(0x1ffff), @@ -60,8 +61,8 @@ class DivPlatformSID2: public DivDispatch { noise_mode(0), mix_mode(0), filtCut(0), - do_pw_sweep_writes(false), - do_cutoff_sweep_writes(false) {} + cutoff_slide(0), + pw_slide(0) {} }; Channel chan[3]; DivDispatchOscBuffer* oscBuf[3]; diff --git a/src/engine/platform/sid3.cpp b/src/engine/platform/sid3.cpp index 7e494c288..e18d977b0 100644 --- a/src/engine/platform/sid3.cpp +++ b/src/engine/platform/sid3.cpp @@ -276,6 +276,25 @@ void DivPlatformSID3::tick(bool sysTick) { chan[i].std.next(); + if(sysTick) + { + if(chan[i].pw_slide != 0) + { + chan[i].duty -= chan[i].pw_slide; + chan[i].duty = CLAMP(chan[i].duty, 0, 0xffff); + updateDuty(i); + } + for(int j = 0; j < SID3_NUM_FILTERS; j++) //filters' slides + { + if(chan[i].filt[j].cutoff_slide != 0) + { + chan[i].filt[j].cutoff += chan[i].filt[j].cutoff_slide; + chan[i].filt[j].cutoff = CLAMP(chan[i].filt[j].cutoff, 0, 0xffff); + updateFilter(i, j); + } + } + } + bool panChanged = false; bool flagsChanged = false; bool envChanged = false; @@ -644,6 +663,7 @@ int DivPlatformSID3::dispatch(DivCommand c) { bool updEnv = false; DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SID3); + int filter = 0; switch (c.cmd) { case DIV_CMD_NOTE_ON: { @@ -999,6 +1019,13 @@ int DivPlatformSID3::dispatch(DivCommand c) { chan[c.chan].filt[(c.value >> 4) & 3].enabled = c.value & 1; updateFilter(c.chan, (c.value >> 4) & 3); break; + case DIV_CMD_C64_PW_SLIDE: + chan[c.chan].pw_slide = c.value * c.value2 * 16; + break; + case DIV_CMD_C64_CUTOFF_SLIDE: + filter = abs(c.value2) - 1; + chan[c.chan].filt[filter].cutoff_slide = c.value * (c.value2 > 0 ? 1 : -1) * 16; + break; case DIV_CMD_SAMPLE_POS: chan[c.chan].dacPos=c.value; break; @@ -1108,6 +1135,8 @@ void DivPlatformSID3::reset() { { chan[i].filt[j].enabled = false; updateFilter(i, j); + + chan[i].filt[j].cutoff_slide = 0; } chan[i].panLeft = chan[i].panRight = 0xff; @@ -1116,6 +1145,8 @@ void DivPlatformSID3::reset() { updatePanning(i); chan[i].noiseLFSRMask = (1 << 29) | (1 << 5) | (1 << 3) | 1; //https://docs.amd.com/v/u/en-US/xapp052 for 30 bits: 30, 6, 4, 1 + + chan[i].pw_slide = 0; } sampleTick = 0; diff --git a/src/engine/platform/sid3.h b/src/engine/platform/sid3.h index 402a1c636..7216a5db0 100644 --- a/src/engine/platform/sid3.h +++ b/src/engine/platform/sid3.h @@ -29,7 +29,7 @@ class DivPlatformSID3: public DivDispatch { struct Channel: public SharedChannel { int prevFreq; unsigned char wave, special_wave, attack, decay, sustain, sr, release; - unsigned short duty; + int duty; bool resetMask, resetFilter, resetDuty, gate, ring, sync, phase, oneBitNoise; bool phaseReset, envReset, phaseResetNoise; bool noiseFreqChanged; @@ -44,7 +44,7 @@ class DivPlatformSID3: public DivDispatch { struct Filter { - unsigned short cutoff; + int cutoff; unsigned char resonance; unsigned char output_volume; unsigned char distortion_level; @@ -52,6 +52,8 @@ class DivPlatformSID3: public DivDispatch { bool enabled; unsigned char filter_matrix; + short cutoff_slide; + Filter(): cutoff(0), resonance(0), @@ -59,7 +61,8 @@ class DivPlatformSID3: public DivDispatch { distortion_level(0), mode(0), enabled(false), - filter_matrix(0) {} + filter_matrix(0), + cutoff_slide(0) {} } filt[SID3_NUM_FILTERS]; int noise_baseNoteOverride; @@ -79,6 +82,8 @@ class DivPlatformSID3: public DivDispatch { unsigned char phaseInv; unsigned char feedback; + short pw_slide; + void handleArpNoise(int offset=0) { DivMacroStruct& m = this->std.op[3].am; @@ -176,7 +181,8 @@ class DivPlatformSID3: public DivDispatch { dacPos(0), dacSample(-1), phaseInv(0), - feedback(0) {} + feedback(0), + pw_slide(0) {} }; Channel chan[SID3_NUM_CHANNELS]; DivDispatchOscBuffer* oscBuf[SID3_NUM_CHANNELS]; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 1455ff83c..62ea44820 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -278,6 +278,9 @@ const char* cmdName[]={ "SID3_FILTER_CONNECTION", "SID3_FILTER_MATRIX", "SID3_FILTER_ENABLE", + + "DIV_CMD_C64_PW_SLIDE", + "DIV_CMD_C64_CUTOFF_SLIDE", }; static_assert((sizeof(cmdName)/sizeof(void*))==DIV_CMD_MAX,"update cmdName!"); diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index efac5408f..b16cbb31b 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -612,6 +612,12 @@ void DivEngine::registerSystems() { {0x1e, {DIV_CMD_C64_EXTENDED, _("1Exy: Change other parameters (LEGACY)")}}, {0x20, {DIV_CMD_C64_AD, _("20xy: Set attack/decay (x: attack; y: decay)")}}, {0x21, {DIV_CMD_C64_SR, _("21xy: Set sustain/release (x: sustain; y: release)")}}, + + {0x22, {DIV_CMD_C64_PW_SLIDE, _("22xx: Pulse width slide up"), effectVal, constVal<1>}}, + {0x23, {DIV_CMD_C64_PW_SLIDE, _("23xx: Pulse width slide down"), effectVal, constVal<-1>}}, + + {0x24, {DIV_CMD_C64_CUTOFF_SLIDE, _("24xx: Filter cutoff slide up"), effectVal, constVal<1>}}, + {0x25, {DIV_CMD_C64_CUTOFF_SLIDE, _("25xx: Filter cutoff slide down"), effectVal, constVal<-1>}}, }; const EffectHandler c64FineDutyHandler(DIV_CMD_C64_FINE_DUTY, _("3xxx: Set pulse width (0 to FFF)"), effectValLong<12>); const EffectHandler c64FineCutoffHandler(DIV_CMD_C64_FINE_CUTOFF, _("4xxx: Set cutoff (0 to 7FF)"), effectValLong<11>); @@ -684,6 +690,12 @@ void DivEngine::registerSystems() { {0x14, {DIV_CMD_C64_FILTER_RESET, _("14xy: Reset cutoff (x: on new note; y: now)")}}, {0x15, {DIV_CMD_C64_DUTY_RESET, _("15xy: Reset pulse width (x: on new note; y: now)")}}, {0x16, {DIV_CMD_C64_EXTENDED, _("16xy: Change other parameters")}}, + + {0x17, {DIV_CMD_C64_PW_SLIDE, _("17xx: Pulse width slide up"), effectVal, constVal<1>}}, + {0x18, {DIV_CMD_C64_PW_SLIDE, _("18xx: Pulse width slide down"), effectVal, constVal<-1>}}, + + {0x19, {DIV_CMD_C64_CUTOFF_SLIDE, _("19xx: Filter cutoff slide up"), effectVal, constVal<1>}}, + {0x1A, {DIV_CMD_C64_CUTOFF_SLIDE, _("1Axx: Filter cutoff slide down"), effectVal, constVal<-1>}}, }; const EffectHandler SID2FineDutyHandler(DIV_CMD_C64_FINE_DUTY, _("3xxx: Set pulse width (0 to FFF)"), effectValLong<12>); const EffectHandler SID2FineCutoffHandler(DIV_CMD_C64_FINE_CUTOFF, _("4xxx: Set cutoff (0 to FFF)"), effectValLong<11>); @@ -737,6 +749,18 @@ void DivEngine::registerSystems() { {0xA1, {DIV_CMD_SID3_FILTER_CONNECTION, _("A1xy: Set filter connection (x: filter (0-3); y: bit 0: connect to channel input; bit 1: connect to channel output)")}}, {0xA2, {DIV_CMD_SID3_FILTER_MATRIX, _("A2xy: Set filter connection matrix (x: filter (0-3); y: bits 0-3: add filter 1-4 output to filter's input)")}}, {0xA3, {DIV_CMD_SID3_FILTER_ENABLE, _("A3xy: Enable filter (x: filter (0-3); y: enable)")}}, + + {0xA4, {DIV_CMD_C64_PW_SLIDE, _("A4xx: Pulse width slide up"), effectVal, constVal<1>}}, + {0xA5, {DIV_CMD_C64_PW_SLIDE, _("A5xx: Pulse width slide down"), effectVal, constVal<-1>}}, + + {0xA6, {DIV_CMD_C64_CUTOFF_SLIDE, _("A6xx: Filter 1 cutoff slide up"), effectVal, constVal<1>}}, + {0xA7, {DIV_CMD_C64_CUTOFF_SLIDE, _("A7xx: Filter 1 cutoff slide down"), effectVal, constVal<-1>}}, + {0xA8, {DIV_CMD_C64_CUTOFF_SLIDE, _("A8xx: Filter 2 cutoff slide up"), effectVal, constVal<2>}}, + {0xA9, {DIV_CMD_C64_CUTOFF_SLIDE, _("A9xx: Filter 2 cutoff slide down"), effectVal, constVal<-2>}}, + {0xAA, {DIV_CMD_C64_CUTOFF_SLIDE, _("AAxx: Filter 3 cutoff slide up"), effectVal, constVal<3>}}, + {0xAB, {DIV_CMD_C64_CUTOFF_SLIDE, _("ABxx: Filter 3 cutoff slide down"), effectVal, constVal<-3>}}, + {0xAC, {DIV_CMD_C64_CUTOFF_SLIDE, _("ACxx: Filter 4 cutoff slide up"), effectVal, constVal<4>}}, + {0xAD, {DIV_CMD_C64_CUTOFF_SLIDE, _("ADxx: Filter 4 cutoff slide down"), effectVal, constVal<-4>}}, }; const EffectHandler SID3FineDutyHandler(DIV_CMD_C64_FINE_DUTY, _("5xxx: Set pulse width (0 to FFF)"), effectValLong<12>); diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 473c6ea07..9a376aa85 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -421,16 +421,16 @@ const FurnaceGUIColors fxColors[256]={ GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, GUI_COLOR_PATTERN_EFFECT_INVALID, GUI_COLOR_PATTERN_EFFECT_INVALID, diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index a9152ccdf..79bcdbf0b 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -6486,8 +6486,27 @@ void FurnaceGUI::drawInsEdit() { } for (DivInstrumentType i: insTypeList) { if (ImGui::Selectable(insTypes[i][0],insType==i)) { + DivInstrumentType prevType = ins->type; ins->type=i; + //clamp some settings + if(prevType == DIV_INS_SID3) + { + ins->c64.a = CLAMP(ins->c64.a, 0, 15); + ins->c64.d = CLAMP(ins->c64.a, 0, 15); + ins->c64.s = CLAMP(ins->c64.a, 0, 15); + ins->c64.r = CLAMP(ins->c64.a, 0, 15); + + ins->c64.duty = CLAMP(ins->c64.a, 0, 0xfff); + + ins->sid2.mixMode = CLAMP(ins->sid2.mixMode, 0, 3); + } + if(prevType == DIV_INS_SID3 || prevType == DIV_INS_SID2) + { + ins->c64.cut = CLAMP(ins->c64.cut, 0, 0x7ff); + ins->c64.res = CLAMP(ins->c64.res, 0, 0xf); + } + // reset macro zoom ins->std.volMacro.vZoom=-1; ins->std.dutyMacro.vZoom=-1;