add flag to disable duty reset on new note for C64/SID2/SID3

This commit is contained in:
LTVA1 2024-08-06 09:00:16 +03:00
parent 7dd16ee7b1
commit 402ff627ae
11 changed files with 36 additions and 12 deletions

View file

@ -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.

View file

@ -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.

View file

@ -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)

View file

@ -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

View file

@ -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;

View file

@ -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),

View file

@ -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);

View file

@ -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));

View file

@ -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;

View file

@ -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

View file

@ -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