From 402ff627aebb8de4328620e718e48375d81d4b8e Mon Sep 17 00:00:00 2001 From: LTVA1 <87536432+LTVA1@users.noreply.github.com> Date: Tue, 6 Aug 2024 09:00:16 +0300 Subject: [PATCH] add flag to disable duty reset on new note for C64/SID2/SID3 --- doc/4-instrument/c64.md | 1 + doc/4-instrument/sid2.md | 1 + papers/newIns.md | 2 ++ src/engine/engine.h | 2 +- src/engine/instrument.cpp | 14 +++++++++++--- src/engine/instrument.h | 3 ++- src/engine/platform/c64.cpp | 2 +- src/engine/platform/sid2.cpp | 2 +- src/engine/platform/sid3.cpp | 9 +++++---- src/engine/sysDef.cpp | 2 +- src/gui/insEdit.cpp | 10 ++++++++++ 11 files changed, 36 insertions(+), 12 deletions(-) diff --git a/doc/4-instrument/c64.md b/doc/4-instrument/c64.md index 8442560bf..6d3e8d41b 100644 --- a/doc/4-instrument/c64.md +++ b/doc/4-instrument/c64.md @@ -13,6 +13,7 @@ the C64 instrument editor consists of two tabs: "C64" to control various paramet - **Sustain**: sets the volume level at which the sound stops decaying and holds steady (0 to 15). - **Release**: determines the rate at which the sound fades out after note off. the higher the value, the longer the release (0 to 15). - **Duty**: specifies the width of a pulse wave (0 to 4095). +- **Reset duty on new note**: overwrite current duty value with the one that's specified in the instrument on new note. - **Ring Modulation**: when enabled, the channel's output will be multiplied with the previous channel's. - **Oscillator Sync**: enables oscillator hard sync. as the previous channel's oscillator finishes a cycle, it resets the period of the channel's oscillator, forcing the latter to have the same base frequency. this can produce a harmonically rich sound, the timbre of which can be altered by varying the synchronized oscillator's frequency. diff --git a/doc/4-instrument/sid2.md b/doc/4-instrument/sid2.md index 33f67a1b2..c60257761 100644 --- a/doc/4-instrument/sid2.md +++ b/doc/4-instrument/sid2.md @@ -14,6 +14,7 @@ the SID2 instrument editor consists of two tabs: "SID2" to control various param - **Sustain**: sets the volume level at which the sound stops decaying and holds steady (0 to 15). - **Release**: determines the rate at which the sound fades out after note off. the higher the value, the longer the release (0 to 15). - **Duty**: specifies the width of a pulse wave (0 to 4095). +- **Reset duty on new note**: overwrite current duty value with the one that's specified in the instrument on new note. - **Ring Modulation**: when enabled, the channel's output will be multiplied with the previous channel's. - **Oscillator Sync**: enables oscillator hard sync. as the previous channel's oscillator finishes a cycle, it resets the period of the channel's oscillator, forcing the latter to have the same base frequency. this can produce a harmonically rich sound, the timbre of which can be altered by varying the synchronized oscillator's frequency. diff --git a/papers/newIns.md b/papers/newIns.md index 7ca9c349e..c7e76a2a3 100644 --- a/papers/newIns.md +++ b/papers/newIns.md @@ -335,6 +335,8 @@ size | description | - bit 12-15: resonance | - bit 0-10: cutoff (0-11 on SID2) 1 | upper nibble of resonance (for SID2) (>=199) + | - bits 0-3 hold this upper nibble + | - bit 4: reset duty on new note (>=217) ``` ## C64 compatibility note (>=187) diff --git a/src/engine/engine.h b/src/engine/engine.h index 2a7718c1d..6c2d67dda 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -55,7 +55,7 @@ class DivWorkPool; #define DIV_UNSTABLE #define DIV_VERSION "Import Test" -#define DIV_ENGINE_VERSION 216 +#define DIV_ENGINE_VERSION 217 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index eb680e203..7c850d28e 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -106,6 +106,7 @@ bool DivInstrumentC64::operator==(const DivInstrumentC64& other) { _C(dutyIsAbs) && _C(filterIsAbs) && _C(noTest) && + _C(resetDuty) && _C(res) && _C(cut) && _C(hp) && @@ -525,7 +526,7 @@ void DivInstrument::writeFeature64(SafeWriter* w) { w->writeS(c64.duty); w->writeS((unsigned short)((c64.cut&4095)|((c64.res&15)<<12))); - w->writeC((c64.res>>4)&15); + w->writeC(((c64.res>>4)&15) | (c64.resetDuty?0x10:0)); FEATURE_END; } @@ -1732,8 +1733,15 @@ void DivInstrument::readFeature64(SafeReader& reader, bool& volIsCutoff, short v c64.cut=cr&4095; c64.res=cr>>12; - if (version>=199) { - c64.res|=((unsigned char)reader.readC())<<4; + if (version>=199) + { + next = (unsigned char)reader.readC(); + c64.res|=(next & 0xf)<<4; + + if(version >= 217) + { + c64.resetDuty = (next & 0x10) ? true : false; + } } READ_FEAT_END; diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 9abaec35d..5f1cdd8ed 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -426,7 +426,7 @@ struct DivInstrumentC64 { unsigned char a, d, s, r; unsigned short duty; unsigned char ringMod, oscSync; - bool toFilter, initFilter, dutyIsAbs, filterIsAbs, noTest; + bool toFilter, initFilter, dutyIsAbs, filterIsAbs, noTest, resetDuty; unsigned char res; unsigned short cut; bool hp, lp, bp, ch3off; @@ -453,6 +453,7 @@ struct DivInstrumentC64 { dutyIsAbs(false), filterIsAbs(false), noTest(false), + resetDuty(true), res(0), cut(0), hp(false), diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index 52d87225f..04893e379 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -305,7 +305,7 @@ int DivPlatformC64::dispatch(DivCommand c) { chan[c.chan].active=true; chan[c.chan].keyOn=true; chan[c.chan].test=false; - if (chan[c.chan].insChanged || chan[c.chan].resetDuty || ins->std.waveMacro.len>0) { + if (((chan[c.chan].insChanged || chan[c.chan].resetDuty || ins->std.waveMacro.len>0) && ins->c64.resetDuty) || chan[c.chan].resetDuty) { chan[c.chan].duty=ins->c64.duty; rWrite(c.chan*7+2,chan[c.chan].duty&0xff); rWrite(c.chan*7+3,chan[c.chan].duty>>8); diff --git a/src/engine/platform/sid2.cpp b/src/engine/platform/sid2.cpp index cc0a13f5c..90b0edc06 100644 --- a/src/engine/platform/sid2.cpp +++ b/src/engine/platform/sid2.cpp @@ -297,7 +297,7 @@ int DivPlatformSID2::dispatch(DivCommand c) { chan[c.chan].keyOn=true; chan[c.chan].test=false; - if (chan[c.chan].insChanged || chan[c.chan].resetDuty || ins->std.waveMacro.len>0) { + if (((chan[c.chan].insChanged || chan[c.chan].resetDuty || ins->std.waveMacro.len>0) && ins->c64.resetDuty) || chan[c.chan].resetDuty) { chan[c.chan].duty=ins->c64.duty; rWrite(c.chan*7+2,chan[c.chan].duty&0xff); rWrite(c.chan*7+3,(chan[c.chan].duty>>8) | (chan[c.chan].outVol << 4)); diff --git a/src/engine/platform/sid3.cpp b/src/engine/platform/sid3.cpp index 881b0ffa3..6e6d1a63a 100644 --- a/src/engine/platform/sid3.cpp +++ b/src/engine/platform/sid3.cpp @@ -370,9 +370,6 @@ void DivPlatformSID3::tick(bool sysTick) updateEnvelope(i); - //chan[i].duty = 0x1000; - updateDuty(i); - updateFlags(i, false); //gate off TODO: make it properly? updateFlags(i, true); //gate on chan[i].gate = true; @@ -463,7 +460,11 @@ int DivPlatformSID3::dispatch(DivCommand c) { chan[c.chan].sr=ins->sid3.sr; chan[c.chan].release=ins->c64.r; - chan[c.chan].duty=ins->c64.duty; + if(ins->c64.resetDuty) + { + chan[c.chan].duty=ins->c64.duty; + updateDuty(c.chan); + } chan[c.chan].sync = ins->c64.oscSync; chan[c.chan].ring = ins->c64.ringMod; diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 4a134d33a..2e0ef1ee0 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -702,7 +702,7 @@ void DivEngine::registerSystems() { const EffectHandler SID3FineDutyHandler(DIV_CMD_C64_FINE_DUTY, _("3xxx: Set pulse width (0 to FFF)"), effectValLong<12>); const EffectHandler SID3FineCutoffHandler(DIV_CMD_C64_FINE_CUTOFF, _("4xxx: Set cutoff (0 to FFF)"), effectValLong<11>); for (int i=0; i<16; i++) SID3PostEffectHandlerMap.emplace(0x30+i,SID3FineDutyHandler); - for (int i=0; i<16; i++) SID2PostEffectHandlerMap.emplace(0x40+i,SID3FineCutoffHandler); + for (int i=0; i<16; i++) SID3PostEffectHandlerMap.emplace(0x40+i,SID3FineCutoffHandler); // SysDefs diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 8b724ff53..f73bafa30 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -5943,6 +5943,11 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins) strncpy(buffer,macroSID3WaveMixMode(0,(float)ins->sid2.mixMode,NULL).c_str(),40); P(CWSliderScalar(_("Wave Mix Mode"),ImGuiDataType_U8,&ins->sid2.mixMode,&_ZERO,&_FOUR,buffer)); P(CWSliderScalar(_("Duty"),ImGuiDataType_U16,&ins->c64.duty,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable + bool resetDuty=ins->c64.resetDuty; + if (ImGui::Checkbox(_("Reset duty on new note"),&resetDuty)) + { PARAMETER + ins->c64.resetDuty=resetDuty; + } bool ringMod=ins->c64.ringMod; if (ImGui::Checkbox(_("Ring Modulation"),&ringMod)) { PARAMETER @@ -6914,6 +6919,11 @@ void FurnaceGUI::drawInsEdit() { } P(CWSliderScalar(_("Duty"),ImGuiDataType_U16,&ins->c64.duty,&_ZERO,&_FOUR_THOUSAND_NINETY_FIVE)); rightClickable + bool resetDuty=ins->c64.resetDuty; + if (ImGui::Checkbox(_("Reset duty on new note"),&resetDuty)) + { PARAMETER + ins->c64.resetDuty=resetDuty; + } bool ringMod=ins->c64.ringMod; if (ImGui::Checkbox(_("Ring Modulation"),&ringMod)) { PARAMETER