diff --git a/src/engine/platform/sid3.cpp b/src/engine/platform/sid3.cpp index 9bded7813..8b14febd2 100644 --- a/src/engine/platform/sid3.cpp +++ b/src/engine/platform/sid3.cpp @@ -94,7 +94,7 @@ void DivPlatformSID3::acquire(short** buf, size_t len) for(int j = 0; j < SID3_NUM_CHANNELS; j++) { - oscBuf[j]->data[oscBuf[j]->needle++] = sid3->channel_output[j]; + oscBuf[j]->data[oscBuf[j]->needle++] = sid3->muted[j] ? 0 : sid3->channel_output[j]; } } } @@ -157,6 +157,12 @@ void DivPlatformSID3::updateEnvelope(int channel) rWrite(SID3_REGISTER_ADSR_R + channel * SID3_REGISTERS_PER_CHANNEL, chan[channel].release); //release } +void DivPlatformSID3::updatePanning(int channel) +{ + rWrite(SID3_REGISTER_PAN_LEFT + channel*SID3_REGISTERS_PER_CHANNEL,chan[channel].panLeft); + rWrite(SID3_REGISTER_PAN_RIGHT + channel*SID3_REGISTERS_PER_CHANNEL,chan[channel].panRight); +} + void DivPlatformSID3::tick(bool sysTick) { for (int i=0; isong.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; + case DIV_CMD_PANNING: { + bool updPan = false; + if (!chan[c.chan].std.panL.has) + { + chan[c.chan].panLeft = c.value; + updPan = true; + } + if (!chan[c.chan].std.panR.has) + { + chan[c.chan].panRight = c.value2; + updPan = true; + } + if(updPan) + { + updatePanning(c.chan); + } + break; + } case DIV_CMD_GET_VOLMAX: return SID3_MAX_VOL; break; @@ -501,6 +534,9 @@ void DivPlatformSID3::reset() { chan[i].filt[j].enabled = false; updateFilter(i, j); } + + chan[i].panLeft = chan[i].panRight = 0xff; + updatePanning(i); } sid3_reset(sid3); diff --git a/src/engine/platform/sid3.h b/src/engine/platform/sid3.h index 8ddc2516b..1d918cb1b 100644 --- a/src/engine/platform/sid3.h +++ b/src/engine/platform/sid3.h @@ -35,7 +35,7 @@ class DivPlatformSID3: public DivDispatch { unsigned char noise_mode; unsigned char mix_mode; unsigned char ringSrc, syncSrc, phaseSrc; - int filtCut; + unsigned char panLeft, panRight; struct Filter { @@ -85,7 +85,8 @@ class DivPlatformSID3: public DivDispatch { ringSrc(0), syncSrc(0), phaseSrc(0), - filtCut(0) {} + panLeft(0xff), + panRight(0xff) {} }; Channel chan[SID3_NUM_CHANNELS]; DivDispatchOscBuffer* oscBuf[SID3_NUM_CHANNELS]; @@ -112,6 +113,7 @@ class DivPlatformSID3: public DivDispatch { void updateFreq(int channel); void updateDuty(int channel); void updateEnvelope(int channel); + void updatePanning(int channel); public: void acquire(short** buf, size_t len); int dispatch(DivCommand c); diff --git a/src/engine/platform/sound/sid3.c b/src/engine/platform/sound/sid3.c index 27730e7ee..cec277ab2 100644 --- a/src/engine/platform/sound/sid3.c +++ b/src/engine/platform/sound/sid3.c @@ -2927,6 +2927,13 @@ void sid3_clock(SID3* sid3) } } + uint32_t acc_state = ch->accumulator; + + if(ch->flags & SID3_CHAN_ENABLE_PHASE_MOD) + { + ch->accumulator += ch->phase_mod_source == SID3_NUM_CHANNELS - 1 ? ((uint64_t)sid3->wave_channel_output << 19) : ((uint64_t)sid3->channel_output[ch->phase_mod_source] << 19); + } + ch->accumulator &= SID3_ACC_MASK; if((prev_acc & ((uint32_t)1 << (SID3_ACC_BITS - 6))) != (ch->accumulator & ((uint32_t)1 << (SID3_ACC_BITS - 6)))) @@ -2934,17 +2941,17 @@ void sid3_clock(SID3* sid3) sid3_clock_lfsr(ch); } - //todo: phase mod - int32_t waveform = sid3_get_waveform(sid3, ch); + ch->accumulator = acc_state & SID3_ACC_MASK; + sid3->channel_signals_before_ADSR[i] = waveform; if(ch->flags & SID3_CHAN_ENABLE_RING_MOD) { uint8_t ring_mod_src = ch->ring_mod_src == SID3_NUM_CHANNELS ? i : ch->ring_mod_src; //SID3_NUM_CHANNELS = self-mod - waveform = waveform * sid3->channel_signals_before_ADSR[ring_mod_src] / (int32_t)0xffff; //ring modulation is just multiplication of two signals! + waveform = waveform * (ch->ring_mod_src == (SID3_NUM_CHANNELS - 1) ? sid3->wave_channel_signal_before_ADSR : sid3->channel_signals_before_ADSR[ring_mod_src]) / (int32_t)0xffff; //ring modulation is just multiplication of two signals! } sid3_adsr_clock(&ch->adsr); @@ -2963,8 +2970,11 @@ void sid3_clock(SID3* sid3) output = ch->output_before_filter; } - sid3->output_l += output; - sid3->output_r += output; + if(!sid3->muted[i]) + { + sid3->output_l += output * ch->panning_left / 0xff; + sid3->output_r += output * ch->panning_right / 0xff; + } sid3->channel_output[i] = output; } @@ -3329,6 +3339,30 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data) } break; } + case SID3_REGISTER_PAN_LEFT: + { + if(channel != SID3_NUM_CHANNELS - 1) + { + sid3->chan[channel].panning_left = data; + } + else + { + sid3->wave_chan.panning_left = data; + } + break; + } + case SID3_REGISTER_PAN_RIGHT: + { + if(channel != SID3_NUM_CHANNELS - 1) + { + sid3->chan[channel].panning_right = data; + } + else + { + sid3->wave_chan.panning_right = data; + } + break; + } default: break; } } @@ -3336,6 +3370,8 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data) void sid3_set_is_muted(SID3* sid3, uint8_t ch, bool mute) { SAFETY_HEADER + + sid3->muted[ch] = mute; } void sid3_free(SID3* sid3) diff --git a/src/engine/platform/sound/sid3.h b/src/engine/platform/sound/sid3.h index c043dc9cd..336c06d28 100644 --- a/src/engine/platform/sound/sid3.h +++ b/src/engine/platform/sound/sid3.h @@ -107,6 +107,11 @@ enum Registers SID3_REGISTER_FILT_DISTORTION = 21, SID3_REGISTER_FILT_CONNECTION = 22, SID3_REGISTER_FILT_OUTPUT_VOLUME = 23, + + SID3_REGISTER_AFTER_FILT_1ST_REG = SID3_REGISTER_FILT_BASE + SID3_REGISTERS_PER_FILTER * SID3_NUM_FILTERS, + SID3_REGISTER_PHASE_MOD_SRC = SID3_REGISTER_AFTER_FILT_1ST_REG, + SID3_REGISTER_PAN_LEFT = SID3_REGISTER_AFTER_FILT_1ST_REG + 1, + SID3_REGISTER_PAN_RIGHT = SID3_REGISTER_AFTER_FILT_1ST_REG + 2, }; typedef struct @@ -224,6 +229,8 @@ typedef struct int32_t channel_signals_before_ADSR[SID3_NUM_CHANNELS]; int32_t channel_output[SID3_NUM_CHANNELS]; + int32_t wave_channel_signal_before_ADSR; + int32_t wave_channel_output; //emulation-only helpers bool muted[SID3_NUM_CHANNELS]; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index ae0aead0c..9c4f11978 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -5646,21 +5646,30 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins) snprintf(buffer, 40, "%d", ins->sid3.ring_mod_source + 1); } - P(CWSliderScalar(_("Ring mod source channel"),ImGuiDataType_U8,&ins->sid3.ring_mod_source,&_ZERO,&_SID3_NUM_CHANNELS,buffer)); + ImGui::SameLine(); + + P(CWSliderScalar(_("Source channel##rmsrc"),ImGuiDataType_U8,&ins->sid3.ring_mod_source,&_ZERO,&_SID3_NUM_CHANNELS,buffer)); bool oscSync=ins->c64.oscSync; if (ImGui::Checkbox(_("Oscillator Sync"),&oscSync)) { PARAMETER ins->c64.oscSync=oscSync; } + ImGui::SameLine(); + snprintf(buffer, 40, "%d", ins->sid3.sync_source + 1); - P(CWSliderScalar(_("Sync source channel"),ImGuiDataType_U8,&ins->sid3.sync_source,&_ZERO,&_SID3_NUM_CHANNELS_MINUS_ONE)); + P(CWSliderScalar(_("Source channel##hssrc"),ImGuiDataType_U8,&ins->sid3.sync_source,&_ZERO,&_SID3_NUM_CHANNELS_MINUS_ONE)); bool phaseMod=ins->sid3.phase_mod; if (ImGui::Checkbox(_("Phase modulation"),&phaseMod)) { PARAMETER ins->sid3.phase_mod=phaseMod; } + ImGui::SameLine(); + + snprintf(buffer, 40, "%d", ins->sid3.phase_mod_source + 1); + P(CWSliderScalar(_("Source channel##pmsrc"),ImGuiDataType_U8,&ins->sid3.phase_mod_source,&_ZERO,&_SID3_NUM_CHANNELS_MINUS_ONE)); + for(int i = 0; i < SID3_NUM_FILTERS; i++) { DivInstrumentSID3::Filter* filt = &ins->sid3.filt[i];