a couple corrections

SID3 will have data independent of C64 and SID2
This commit is contained in:
tildearrow 2024-09-13 23:08:25 -05:00
parent 1458ecc165
commit 0b0e6d5e13
10 changed files with 100 additions and 67 deletions

View file

@ -203,7 +203,7 @@ ex | FM | OPM | OPZ | OPLL | AY-3-8910 | AY8930 | Lynx
W | | LFO Shape | LFO Shape | Patch | Waveform | Waveform | | Waveform |
1 | | AMD | AMD | | | Duty | | FilterMode |
2 | | PMD | PMD | | Envelope | Envelope | | Resonance |
3 | LFOSpd | LFO Speed | LFO Speed | | AutoEnvNum | AutoEnvNum | | Filter toggle |
3 | LFOSpd | LFO Speed | LFO Speed | | AutoEnvNum | AutoEnvNum | | Filter Toggle |
A | ALG | ALG | ALG | | AutoEnvDen | AutoEnvDen | | Cutoff |
B | FB | FB | FB | | | Noise AND | | |
C | FMS | FMS | FMS | | | Noise OR | | |
@ -288,4 +288,4 @@ DT | Output volume |
DVB | Connect to channel input |
EGT | Connect to channel output |
KSL | Connection matrix row |
KSR | Filter mode |
KSR | Filter mode |

View file

@ -13,7 +13,8 @@ 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.
- **Reset duty on new note**: overwrite current duty value with the one that is specified in the instrument on new note.
- only useful when using relative duty macro.
- **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,7 +14,8 @@ 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.
- **Reset duty on new note**: overwrite current duty value with the one that is specified in the instrument on new note.
- only useful when using relative duty macro.
- **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

@ -40,7 +40,8 @@ the only differences are the lack of an "Use wavetable" option, and the presence
- **Wave Mix Mode**: dictates how different waves on the same channel are mixed together.
- **Duty**: specifies the width of a pulse wave (0 to 65535).
- **Feedback**: specifies the feedback level (0 to 255).
- **Reset duty on new note**: overwrite current duty value with the one that's specified in the instrument on new note.
- **Reset duty on new note**: overwrite current duty value with the one that is specified in the instrument on new note.
- only useful when using relative duty macro.
- **Absolute Duty Macro**: when enabled, the duty macro will go from 0 to 65535 (in other words, control the duty directly rather than being relative).
- **Ring Modulation**: when enabled, the channel's output will be multiplied with the source channel's.
- **Oscillator Sync**: enables oscillator hard sync. as the source 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

@ -62,10 +62,14 @@ two versions of aforementioned chip exist - 6581 (original chip) and 8580 (impro
- `21xy`: **set sustain/release.**
- `x` is the sustain.
- `y` is the release.
- `22xx`: **pulse width slide up.** `xx` is speed. `2200` stops the slide.
- `23xx`: **pulse width slide down.** `xx` is speed. `2300` stops the slide.
- `24xx`: **filter cutoff slide up.** `xx` is speed. `2400` stops the slide.
- `25xx`: **filter cutoff slide down.** `xx` is speed. `2500` stops the slide.
- `22xx`: **pulse width slide up.**
- `xx` is speed. if it is `00`, the slide is stopped.
- `23xx`: **pulse width slide down.**
- `xx` is speed. if it is `00`, the slide is stopped.
- `24xx`: **filter cutoff slide up.**
- `xx` is speed. if it is `00`, the slide is stopped.
- `25xx`: **filter cutoff slide down.**
- `xx` is speed. if it is `00`, the slide is stopped.
- `3xxx`: **set duty cycle.** `xxx` range is `000` to `FFF`.
- `4xxx`: **set cutoff.** `xxx` range is `000` to `7FF`.

View file

@ -46,10 +46,14 @@ each channel now has its own independent filter. filter cutoff and resonance ran
- `9`: phase reset (`y` is a discarded parameter and does not matter)
- `A`: envelope key on/key off (`y` is `0` (trigger envelope release) or `1` (restart envelope again))
- `B`: filter on/off (`y` is `0` (disable filter) or `1` (enable filter))
- `17xx`: **pulse width slide up.** `xx` is speed. `1700` stops the slide.
- `18xx`: **pulse width slide down.** `xx` is speed. `1800` stops the slide.
- `19xx`: **filter cutoff slide up.** `xx` is speed. `1900` stops the slide.
- `1Axx`: **filter cutoff slide down.** `xx` is speed. `1A00` stops the slide.
- `17xx`: **pulse width slide up.**
- `xx` is speed. if it is `00`, the slide is stopped.
- `18xx`: **pulse width slide down.**
- `xx` is speed. if it is `00`, the slide is stopped.
- `19xx`: **filter cutoff slide up.**
- `xx` is speed. if it is `00`, the slide is stopped.
- `1Axx`: **filter cutoff slide down.**
- `xx` is speed. if it is `00`, the slide is stopped.
- `3xxx`: **set duty cycle.** `xxx` range is `000` to `FFF`.
- `4xxx`: **set cutoff.** `xxx` range is `000` to `FFF`.

View file

@ -325,19 +325,19 @@ size | description
| - bit 2: band pass
| - bit 1: high pass
| - bit 0: low pass
1 | attack/decay (ignore the values if reading SID3 instrument)
1 | attack/decay
| - bit 4-7: attack
| - bit 0-3: decay
1 | sustain release (ignore the values if reading SID3 instrument)
1 | sustain release
| - bit 4-7: sustain
| - bit 0-3: release
2 | duty (0-4095 for C64/SID2, 0-65535 for SID3)
2 | duty
2 | cutoff/resonance
| - 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)
| - bit 4: reset duty on new note (>=222)
```
## C64 compatibility note (>=187)
@ -686,7 +686,7 @@ size | description
-----|------------------------------------
1 | parameters
| - bit 6-7: noise mode
| - bit 4-5: wave mix mode (ignore the value if reading SID3 instrument)
| - bit 4-5: wave mix mode
| - bit 0-3: volume
```

View file

@ -864,9 +864,13 @@ struct DivInstrumentSID2 {
noiseMode(0) {}
};
struct DivInstrumentSID3
struct DivInstrumentSID3
{
bool triOn, sawOn, pulseOn, noiseOn;
unsigned char a, d, s, r;
unsigned char sr;
unsigned short duty;
unsigned char ringMod, oscSync;
bool phase_mod;
unsigned char phase_mod_source, ring_mod_source, sync_source;
bool specialWaveOn;
@ -874,8 +878,11 @@ struct DivInstrumentSID3
bool separateNoisePitch;
unsigned char special_wave;
bool doWavetable;
bool dutyIsAbs;
bool resetDuty;
unsigned char phaseInv;
unsigned char feedback;
unsigned char mixMode;
struct Filter
{
@ -935,7 +942,18 @@ struct DivInstrumentSID3
return !(*this==other);
}
DivInstrumentSID3():
triOn(false),
sawOn(true),
pulseOn(false),
noiseOn(false),
a(0),
d(8),
s(0),
r(0),
sr(0),
duty(2048),
ringMod(0),
oscSync(0),
phase_mod(false),
phase_mod_source(0),
ring_mod_source(0),
@ -945,8 +963,11 @@ struct DivInstrumentSID3
separateNoisePitch(false),
special_wave(0),
doWavetable(false),
dutyIsAbs(true),
resetDuty(false),
phaseInv(0),
feedback(0)
feedback(0),
mixMode(0)
{
filt[0].mode = 16 | 32; //default settings so filter just works, connect to input and channel output
filt[0].output_volume = 0xff;

View file

@ -383,7 +383,7 @@ void DivPlatformSID3::tick(bool sysTick)
}
if (chan[i].std.duty.had) {
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SID3);
if (ins->c64.dutyIsAbs) {
if (ins->sid3.dutyIsAbs) {
chan[i].duty=chan[i].std.duty.val;
} else {
chan[i].duty-=chan[i].std.duty.val;
@ -846,28 +846,28 @@ int DivPlatformSID3::dispatch(DivCommand c) {
if (chan[c.chan].insChanged)
{
chan[c.chan].wave = (ins->c64.triOn ? SID3_WAVE_TRIANGLE : 0) | (ins->c64.sawOn ? SID3_WAVE_SAW : 0) |
(ins->c64.pulseOn ? SID3_WAVE_PULSE : 0) | (ins->c64.noiseOn ? SID3_WAVE_NOISE : 0) | (ins->sid3.specialWaveOn ? SID3_WAVE_SPECIAL : 0); //waveform
chan[c.chan].wave = (ins->sid3.triOn ? SID3_WAVE_TRIANGLE : 0) | (ins->sid3.sawOn ? SID3_WAVE_SAW : 0) |
(ins->sid3.pulseOn ? SID3_WAVE_PULSE : 0) | (ins->sid3.noiseOn ? SID3_WAVE_NOISE : 0) | (ins->sid3.specialWaveOn ? SID3_WAVE_SPECIAL : 0); //waveform
chan[c.chan].special_wave = ins->sid3.special_wave; //special wave
chan[c.chan].attack=ins->c64.a;
chan[c.chan].decay=ins->c64.d;
chan[c.chan].sustain=ins->c64.s;
chan[c.chan].attack=ins->sid3.a;
chan[c.chan].decay=ins->sid3.d;
chan[c.chan].sustain=ins->sid3.s;
chan[c.chan].sr=ins->sid3.sr;
chan[c.chan].release=ins->c64.r;
chan[c.chan].release=ins->sid3.r;
if(ins->c64.resetDuty)
if(ins->sid3.resetDuty)
{
chan[c.chan].duty=ins->c64.duty;
chan[c.chan].duty=ins->sid3.duty;
updateDuty(c.chan);
}
chan[c.chan].sync = ins->c64.oscSync;
chan[c.chan].ring = ins->c64.ringMod;
chan[c.chan].sync = ins->sid3.oscSync;
chan[c.chan].ring = ins->sid3.ringMod;
chan[c.chan].phase = ins->sid3.phase_mod;
chan[c.chan].oneBitNoise = ins->sid3.oneBitNoise;
chan[c.chan].mix_mode = ins->sid2.mixMode;
chan[c.chan].mix_mode = ins->sid3.mixMode;
chan[c.chan].ringSrc = ins->sid3.ring_mod_source;
chan[c.chan].syncSrc = ins->sid3.sync_source;
@ -1044,7 +1044,7 @@ int DivPlatformSID3::dispatch(DivCommand c) {
case DIV_CMD_C64_DUTY_RESET:
if (c.value&15) {
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SID3);
chan[c.chan].duty=ins->c64.duty;
chan[c.chan].duty=ins->sid3.duty;
updateDuty(c.chan);
}
chan[c.chan].resetDuty=c.value>>4;

View file

@ -5874,27 +5874,27 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
ImGui::AlignTextToFramePadding();
ImGui::Text(_("Waveform"));
ImGui::SameLine();
pushToggleColors(ins->c64.triOn);
pushToggleColors(ins->sid3.triOn);
if (ImGui::Button(_("tri"))) { PARAMETER
ins->c64.triOn=!ins->c64.triOn;
ins->sid3.triOn=!ins->sid3.triOn;
}
popToggleColors();
ImGui::SameLine();
pushToggleColors(ins->c64.sawOn);
pushToggleColors(ins->sid3.sawOn);
if (ImGui::Button(_("saw"))) { PARAMETER
ins->c64.sawOn=!ins->c64.sawOn;
ins->sid3.sawOn=!ins->sid3.sawOn;
}
popToggleColors();
ImGui::SameLine();
pushToggleColors(ins->c64.pulseOn);
pushToggleColors(ins->sid3.pulseOn);
if (ImGui::Button(_("pulse"))) { PARAMETER
ins->c64.pulseOn=!ins->c64.pulseOn;
ins->sid3.pulseOn=!ins->sid3.pulseOn;
}
popToggleColors();
ImGui::SameLine();
pushToggleColors(ins->c64.noiseOn);
pushToggleColors(ins->sid3.noiseOn);
if (ImGui::Button(_("noise"))) { PARAMETER
ins->c64.noiseOn=!ins->c64.noiseOn;
ins->sid3.noiseOn=!ins->sid3.noiseOn;
}
if (ImGui::IsItemHovered())
{
@ -5990,41 +5990,41 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
ImGui::TableNextRow();
ImGui::TableNextColumn();
P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->c64.a,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable
P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->sid3.a,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable
ImGui::TableNextColumn();
P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->c64.d,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable
P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->sid3.d,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable
ImGui::TableNextColumn();
P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->c64.s,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable
P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->sid3.s,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable
ImGui::TableNextColumn();
P(CWVSliderScalar("##SustainRate",sliderSize,ImGuiDataType_U8,&ins->sid3.sr,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable
ImGui::TableNextColumn();
P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->c64.r,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable
P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->sid3.r,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable
ImGui::TableNextColumn();
drawSID3Env(0,(ins->c64.a == 0 ? (255) : (256-ins->c64.a)),(ins->c64.d == 0 ? (255) : (256-ins->c64.d)),ins->sid3.sr,255-(ins->c64.r == 255 ? (ins->c64.r - 1) : ins->c64.r),255-ins->c64.s,0,0,0,255,256,255,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); //the (ins->c64.r == 15 ? (ins->c64.r - 1) : ins->c64.r) is used so release part never becomes horizontal (which isn't the case with SID3 envelope)
drawSID3Env(0,(ins->sid3.a == 0 ? (255) : (256-ins->sid3.a)),(ins->sid3.d == 0 ? (255) : (256-ins->sid3.d)),ins->sid3.sr,255-(ins->sid3.r == 255 ? (ins->sid3.r - 1) : ins->sid3.r),255-ins->sid3.s,0,0,0,255,256,255,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); //the (ins->sid3.r == 15 ? (ins->sid3.r - 1) : ins->sid3.r) is used so release part never becomes horizontal (which isn't the case with SID3 envelope)
ImGui::EndTable();
}
if(!ins->sid3.doWavetable)
{
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
strncpy(buffer,macroSID3WaveMixMode(0,(float)ins->sid3.mixMode,NULL).c_str(),40);
P(CWSliderScalar(_("Wave Mix Mode"),ImGuiDataType_U8,&ins->sid3.mixMode,&_ZERO,&_FOUR,buffer));
P(CWSliderScalar(_("Duty"),ImGuiDataType_U16,&ins->sid3.duty,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable
P(CWSliderScalar(_("Feedback"),ImGuiDataType_U8,&ins->sid3.feedback,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE));
bool resetDuty=ins->c64.resetDuty;
bool resetDuty=ins->sid3.resetDuty;
if (ImGui::Checkbox(_("Reset duty on new note"),&resetDuty))
{ PARAMETER
ins->c64.resetDuty=resetDuty;
ins->sid3.resetDuty=resetDuty;
}
if (ImGui::Checkbox(_("Absolute Duty Macro"),&ins->c64.dutyIsAbs)) {
if (ImGui::Checkbox(_("Absolute Duty Macro"),&ins->sid3.dutyIsAbs)) {
ins->std.dutyMacro.vZoom=-1;
PARAMETER;
}
}
bool ringMod=ins->c64.ringMod;
bool ringMod=ins->sid3.ringMod;
if (ImGui::Checkbox(_("Ring Modulation"),&ringMod)) { PARAMETER
ins->c64.ringMod=ringMod;
ins->sid3.ringMod=ringMod;
}
ImGui::SameLine();
@ -6032,9 +6032,9 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
strncpy(buffer,macroSID3SourceChan(0,(float)ins->sid3.ring_mod_source,NULL).c_str(),40);
P(CWSliderScalar(_("Source channel##rmsrc"),ImGuiDataType_U8,&ins->sid3.ring_mod_source,&_ZERO,&_SID3_NUM_CHANNELS,buffer));
bool oscSync=ins->c64.oscSync;
bool oscSync=ins->sid3.oscSync;
if (ImGui::Checkbox(_("Oscillator Sync"),&oscSync)) { PARAMETER
ins->c64.oscSync=oscSync;
ins->sid3.oscSync=oscSync;
}
ImGui::SameLine();
@ -6362,7 +6362,7 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
}
else
{
macroList.push_back(FurnaceGUIMacroDesc(_("Duty"),&ins->std.dutyMacro,ins->c64.dutyIsAbs?0:-65535,65535,160,uiColors[GUI_COLOR_MACRO_OTHER]));
macroList.push_back(FurnaceGUIMacroDesc(_("Duty"),&ins->std.dutyMacro,ins->sid3.dutyIsAbs?0:-65535,65535,160,uiColors[GUI_COLOR_MACRO_OTHER]));
macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,5,16 * 5,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,true,sid3ShapeBits));
macroList.push_back(FurnaceGUIMacroDesc(_("Special Wave"),&ins->std.algMacro,0,SID3_NUM_SPECIAL_WAVES - 1,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,macroSID3SpecialWaves));
}
@ -6581,26 +6581,27 @@ void FurnaceGUI::drawInsEdit() {
}
for (DivInstrumentType i: insTypeList) {
if (ImGui::Selectable(insTypes[i][0],insType==i)) {
DivInstrumentType prevType = ins->type;
//DivInstrumentType prevType = ins->type;
ins->type=i;
/* what is this?
//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->sid3.a = CLAMP(ins->sid3.a, 0, 15);
ins->sid3.d = CLAMP(ins->sid3.a, 0, 15);
ins->sid3.s = CLAMP(ins->sid3.a, 0, 15);
ins->sid3.r = CLAMP(ins->sid3.a, 0, 15);
ins->c64.duty = CLAMP(ins->c64.a, 0, 0xfff);
ins->sid3.duty = CLAMP(ins->sid3.a, 0, 0xfff);
ins->sid2.mixMode = CLAMP(ins->sid2.mixMode, 0, 3);
ins->sid3.mixMode = CLAMP(ins->sid3.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);
}
ins->sid3.cut = CLAMP(ins->sid3.cut, 0, 0x7ff);
ins->sid3.res = CLAMP(ins->sid3.res, 0, 0xf);
}*/
// reset macro zoom
ins->std.volMacro.vZoom=-1;