diff --git a/src/engine/platform/sid3.cpp b/src/engine/platform/sid3.cpp index df9312019..222fecc01 100644 --- a/src/engine/platform/sid3.cpp +++ b/src/engine/platform/sid3.cpp @@ -90,16 +90,6 @@ void DivPlatformSID3::acquire(short** buf, size_t len) int dacData=s->data16[chan[SID3_NUM_CHANNELS - 1].dacPos] + 32767; chan[SID3_NUM_CHANNELS - 1].dacOut=CLAMP(dacData,0,65535); - /*if (!isMuted[SID3_NUM_CHANNELS - 1]) - { - sid3_write(sid3, SID3_REGISTER_STREAMED_SAMPLE_HIGH + (SID3_NUM_CHANNELS - 1) * SID3_REGISTERS_PER_CHANNEL, chan[SID3_NUM_CHANNELS - 1].dacOut >> 8); - sid3_write(sid3, SID3_REGISTER_STREAMED_SAMPLE_LOW + (SID3_NUM_CHANNELS - 1) * SID3_REGISTERS_PER_CHANNEL, chan[SID3_NUM_CHANNELS - 1].dacOut & 0xff); - } - else - { - sid3_write(sid3, SID3_REGISTER_STREAMED_SAMPLE_HIGH + (SID3_NUM_CHANNELS - 1) * SID3_REGISTERS_PER_CHANNEL, 32768 >> 8); - sid3_write(sid3, SID3_REGISTER_STREAMED_SAMPLE_LOW + (SID3_NUM_CHANNELS - 1) * SID3_REGISTERS_PER_CHANNEL, 32768 & 0xff); - }*/ updateSample = true; sampleTick = 0; @@ -1121,7 +1111,16 @@ void DivPlatformSID3::poke(std::vector& wlist) { void DivPlatformSID3::setFlags(const DivConfig& flags) { chipClock=1000000; CHECK_CUSTOM_CLOCK; + + quarterClock=flags.getBool("quarterClock",false); + + if(quarterClock && chipClock >= 1000000 && !parent->isExporting()) + { + chipClock /= 4; + } + rate=chipClock; + sid3_set_clock_rate(sid3, chipClock); for (int i=0; irate=rate/8; } diff --git a/src/engine/platform/sid3.h b/src/engine/platform/sid3.h index a89861a1f..402a1c636 100644 --- a/src/engine/platform/sid3.h +++ b/src/engine/platform/sid3.h @@ -198,6 +198,7 @@ class DivPlatformSID3: public DivDispatch { unsigned char sampleTick; //used to update streamed sample and not clash with other reg writes at high rate samples bool updateSample; + bool quarterClock; friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); diff --git a/src/engine/platform/sound/sid3.c b/src/engine/platform/sound/sid3.c index 66b794a56..6f1ae41f9 100644 --- a/src/engine/platform/sound/sid3.c +++ b/src/engine/platform/sound/sid3.c @@ -13,9 +13,9 @@ enum State { ATTACK, DECAY, SUSTAIN, RELEASE }; //for envelope #define envspd_factor_a_sr 10 #define envspd_factor_dr 15 -#define envspd_a(rate) ((uint64_t)0xff0000 / ((rate == 0 ? 1 : (rate * envspd_factor_a_sr)) * (rate == 0 ? 1 : (rate * envspd_factor_a_sr)))) -#define envspd_dr(rate) ((uint64_t)0xff0000 / ((rate == 0 ? 1 : (rate * envspd_factor_dr)) * (rate == 0 ? 1 : (rate * envspd_factor_dr)))) -#define envspd_sr(rate) (rate == 0 ? 0 : ((uint64_t)0xff0000 / ((256 - rate) * (256 - rate) * envspd_factor_a_sr * envspd_factor_a_sr))) +#define envspd_a(rate) ((uint64_t)0xff0000 / ((rate == 0 ? 1 : (rate * envspd_factor_a_sr)) * (rate == 0 ? 1 : (rate * envspd_factor_a_sr * ((float)sid3->clock_rate / 1000000.0))))) +#define envspd_dr(rate) ((uint64_t)0xff0000 / ((rate == 0 ? 1 : (rate * envspd_factor_dr)) * (rate == 0 ? 1 : (rate * envspd_factor_dr * ((float)sid3->clock_rate / 1000000.0))))) +#define envspd_sr(rate) (rate == 0 ? 0 : ((uint64_t)0xff0000 / ((256 - rate) * (256 - rate) * envspd_factor_a_sr * envspd_factor_a_sr * ((float)sid3->clock_rate / 1000000.0)))) //these 4 ones are util only double square(double x) { @@ -2352,21 +2352,27 @@ void sid3_reset(SID3* sid3) for(int32_t i = 0; i < SID3_NUM_CHANNELS - 1; i++) { memset(&sid3->chan[i], 0, sizeof(sid3_channel)); - /*sid3->chan[i].accumulator = 0; - sid3->chan[i].adsr.a = 0x20; - sid3->chan[i].adsr.d = 0x20; - sid3->chan[i].adsr.s = 0x80; - sid3->chan[i].adsr.r = 0x17; - sid3->chan[i].adsr.vol = 0xf0;*/ sid3->chan[i].adsr.hold_zero = true; sid3->chan[i].lfsr = 0x1; sid3->chan[i].lfsr_taps = (1 << 29) | (1 << 5) | (1 << 3) | 1; //https://docs.amd.com/v/u/en-US/xapp052 for 30 bits: 30, 6, 4, 1 - //.... + + for(int j = 0; j < SID3_NUM_FILTERS; j++) + { + sid3->chan[i].filt.filt[j].Vlp = 0; + sid3->chan[i].filt.filt[j].Vbp = 0; + sid3->chan[i].filt.filt[j].Vhp = 0; + } } - //TODO: wavetable chan memset(&sid3->wave_chan, 0, sizeof(sid3_wavetable_chan)); sid3->wave_chan.adsr.hold_zero = true; + + for(int j = 0; j < SID3_NUM_FILTERS; j++) + { + sid3->wave_chan.filt.filt[j].Vlp = 0; + sid3->wave_chan.filt.filt[j].Vbp = 0; + sid3->wave_chan.filt.filt[j].Vhp = 0; + } } void sid3_gate_bit(SID3* sid3, uint8_t gate, sid3_channel_adsr* adsr) @@ -2404,7 +2410,7 @@ void sid3_gate_bit(SID3* sid3, uint8_t gate, sid3_channel_adsr* adsr) if(adsr->envelope_counter > 0xff0000) adsr->envelope_counter = 0xff0000; } -void sid3_adsr_clock(sid3_channel_adsr* adsr) +void sid3_adsr_clock(SID3* sid3, sid3_channel_adsr* adsr) { // Check whether the envelope counter is frozen at zero. if (adsr->hold_zero) @@ -2478,16 +2484,16 @@ int32_t sid3_adsr_output(SID3* sid3, sid3_channel_adsr* adsr, int32_t input) } } -void sid3_set_filter_settings(sid3_filter* filt) +void sid3_set_filter_settings(SID3* sid3, sid3_filter* filt) { const double pi = 3.1415926535897932385; // Multiply with 1.048576 to facilitate division by 1 000 000 by right- // shifting 20 times (2 ^ 20 = 1048576). - filt->w0 = (2.0*pi*(float)filt->cutoff) / 500000.0 / 5.0; // "/ 5.0" bc we have 16 bit cutoff instead of 12-bit + filt->w0 = (2.0*pi*(float)filt->cutoff) / ((double)sid3->clock_rate / 2.0) / 5.0; // "/ 5.0" bc we have 16 bit cutoff instead of 12-bit // Limit f0 to 16kHz to keep 1 cycle filter stable. - const float w0_max_1 = (2.0*pi*20000.0) / 500000.0; + const float w0_max_1 = (2.0*pi*20000.0) / ((double)sid3->clock_rate / 2.0); filt->w0_ceil_1 = filt->w0 <= w0_max_1 ? filt->w0 : w0_max_1; filt->_1024_div_Q = (1.0/(0.707 + 4.0*(float)filt->resonance/(float)0x0ff)); @@ -3052,67 +3058,100 @@ void sid3_clock(SID3* sid3) } } - uint32_t acc_state = ch->accumulator; - uint32_t noise_acc_state = ch->noise_accumulator; + int32_t waveform = 0; - if(ch->flags & SID3_CHAN_ENABLE_PHASE_MOD) + if(!ch->adsr.hold_zero) { - ch->accumulator += ch->phase_mod_source == SID3_NUM_CHANNELS - 1 ? ((uint64_t)sid3->wave_channel_output << 18) : ((uint64_t)sid3->channel_output[ch->phase_mod_source] << 18); - ch->noise_accumulator += ch->phase_mod_source == SID3_NUM_CHANNELS - 1 ? ((uint64_t)sid3->wave_channel_output << 18) : ((uint64_t)sid3->channel_output[ch->phase_mod_source] << 18); - } + uint32_t acc_state = ch->accumulator; + uint32_t noise_acc_state = ch->noise_accumulator; - if(ch->feedback) - { - ch->accumulator += (ch->prev_output + ch->prev_output2) * ch->feedback; - } + if(ch->flags & SID3_CHAN_ENABLE_PHASE_MOD) + { + ch->accumulator += ch->phase_mod_source == SID3_NUM_CHANNELS - 1 ? ((uint64_t)sid3->wave_channel_output << 18) : ((uint64_t)sid3->channel_output[ch->phase_mod_source] << 18); + ch->noise_accumulator += ch->phase_mod_source == SID3_NUM_CHANNELS - 1 ? ((uint64_t)sid3->wave_channel_output << 18) : ((uint64_t)sid3->channel_output[ch->phase_mod_source] << 18); + } - ch->accumulator &= SID3_ACC_MASK; + if(ch->feedback) + { + ch->accumulator += (ch->prev_output + ch->prev_output2) * ch->feedback; + } - if((prev_noise_acc & ((uint32_t)1 << (SID3_ACC_BITS - 6))) != (ch->noise_accumulator & ((uint32_t)1 << (SID3_ACC_BITS - 6)))) - { - sid3_clock_lfsr(ch); - } + ch->accumulator &= SID3_ACC_MASK; + ch->noise_accumulator &= SID3_ACC_MASK; - int32_t waveform = sid3_get_waveform(sid3, ch); + if((prev_noise_acc & ((uint32_t)1 << (SID3_ACC_BITS - 6))) != (ch->noise_accumulator & ((uint32_t)1 << (SID3_ACC_BITS - 6)))) + { + sid3_clock_lfsr(ch); + } - ch->accumulator = acc_state & SID3_ACC_MASK; - ch->noise_accumulator = noise_acc_state & SID3_ACC_MASK; + waveform = sid3_get_waveform(sid3, ch); - sid3->channel_signals_before_ADSR[i] = waveform; + ch->accumulator = acc_state & SID3_ACC_MASK; + ch->noise_accumulator = noise_acc_state & SID3_ACC_MASK; - 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 + sid3->channel_signals_before_ADSR[i] = waveform; - 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! - } + 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 - sid3_adsr_clock(&ch->adsr); - - ch->output_before_filter = sid3_adsr_output(sid3, &ch->adsr, waveform); - - int32_t output = 0; - - if((ch->filt.filt[0].mode & SID3_FILTER_ENABLE) || (ch->filt.filt[1].mode & SID3_FILTER_ENABLE) || - (ch->filt.filt[2].mode & SID3_FILTER_ENABLE) || (ch->filt.filt[3].mode & SID3_FILTER_ENABLE)) - { - output = sid3_process_filters_block(ch); + 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! + } } else { - output = ch->output_before_filter; - } - - if(ch->feedback) - { - ch->prev_output2 = ch->prev_output; - ch->prev_output = output + 0xffff; + ch->accumulator &= SID3_ACC_MASK; + ch->noise_accumulator &= SID3_ACC_MASK; } - if(!sid3->muted[i]) + sid3_adsr_clock(sid3, &ch->adsr); + + int32_t output = 0; + + if(!ch->adsr.hold_zero) { - sid3->output_l += output * ch->panning_left / 0x8f0 * ((ch->phase_inv & SID3_INV_SIGNAL_LEFT) ? -1 : 1); - sid3->output_r += output * ch->panning_right / 0x8f0 * ((ch->phase_inv & SID3_INV_SIGNAL_RIGHT) ? -1 : 1); + ch->output_before_filter = sid3_adsr_output(sid3, &ch->adsr, waveform); + + if((ch->filt.filt[0].mode & SID3_FILTER_ENABLE) || (ch->filt.filt[1].mode & SID3_FILTER_ENABLE) || + (ch->filt.filt[2].mode & SID3_FILTER_ENABLE) || (ch->filt.filt[3].mode & SID3_FILTER_ENABLE)) + { + output = sid3_process_filters_block(ch); + } + else + { + output = ch->output_before_filter; + } + + if(ch->feedback) + { + ch->prev_output2 = ch->prev_output; + ch->prev_output = output + 0xffff; + } + + if(!sid3->muted[i]) + { + sid3->output_l += output * ch->panning_left / 0x8f0 * ((ch->phase_inv & SID3_INV_SIGNAL_LEFT) ? -1 : 1); + sid3->output_r += output * ch->panning_right / 0x8f0 * ((ch->phase_inv & SID3_INV_SIGNAL_RIGHT) ? -1 : 1); + } + } + else + { + ch->output_before_filter = 0; + + for(int j = 0; j < SID3_NUM_FILTERS; j++) + { + if(ch->filt.filt[j].mode & SID3_FILTER_ENABLE) + { + if(ch->filt.filt[j].output > 0) + { + ch->filt.filt[j].output--; + } + if(ch->filt.filt[j].output < 0) + { + ch->filt.filt[j].output++; + } + } + } } sid3->channel_output[i] = output; @@ -3151,57 +3190,86 @@ void sid3_clock(SID3* sid3) } } - uint32_t acc_state = ch->accumulator; + int32_t waveform = 0; - if(ch->flags & SID3_CHAN_ENABLE_PHASE_MOD) + if(!ch->adsr.hold_zero) { - ch->accumulator += ch->phase_mod_source == SID3_NUM_CHANNELS - 1 ? ((uint64_t)sid3->wave_channel_output << 18) : ((uint64_t)sid3->channel_output[ch->phase_mod_source] << 18); - } + uint32_t acc_state = ch->accumulator; - ch->accumulator &= SID3_ACC_MASK; + if(ch->flags & SID3_CHAN_ENABLE_PHASE_MOD) + { + ch->accumulator += ch->phase_mod_source == SID3_NUM_CHANNELS - 1 ? ((uint64_t)sid3->wave_channel_output << 18) : ((uint64_t)sid3->channel_output[ch->phase_mod_source] << 18); + } - int32_t waveform; + ch->accumulator &= SID3_ACC_MASK; - if(ch->mode) - { - waveform = (int32_t)ch->streamed_sample - 0x7fff; + if(ch->mode) + { + waveform = (int32_t)ch->streamed_sample - 0x7fff; + } + else + { + waveform = ((int32_t)ch->wavetable[(ch->accumulator & SID3_ACC_MASK) >> (SID3_ACC_BITS - 8)] << 8) - 0x7fff; + } + + ch->accumulator = acc_state & SID3_ACC_MASK; + + sid3->wave_channel_signal_before_ADSR = waveform; + + if(ch->flags & SID3_CHAN_ENABLE_RING_MOD) + { + uint8_t ring_mod_src = ch->ring_mod_src == SID3_NUM_CHANNELS ? 0xff : ch->ring_mod_src; //SID3_NUM_CHANNELS = self-mod + + waveform = waveform * (ch->ring_mod_src == 0xff ? 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! + } } else { - waveform = ((int32_t)ch->wavetable[(ch->accumulator & SID3_ACC_MASK) >> (SID3_ACC_BITS - 8)] << 8) - 0x7fff; + ch->accumulator &= SID3_ACC_MASK; } - ch->accumulator = acc_state & SID3_ACC_MASK; - - sid3->wave_channel_signal_before_ADSR = waveform; - - if(ch->flags & SID3_CHAN_ENABLE_RING_MOD) - { - uint8_t ring_mod_src = ch->ring_mod_src == SID3_NUM_CHANNELS ? 0xff : ch->ring_mod_src; //SID3_NUM_CHANNELS = self-mod - - waveform = waveform * (ch->ring_mod_src == 0xff ? 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); - - ch->output_before_filter = sid3_adsr_output(sid3, &ch->adsr, waveform); + sid3_adsr_clock(sid3, &ch->adsr); int32_t output = 0; - - if((ch->filt.filt[0].mode & SID3_FILTER_ENABLE) || (ch->filt.filt[1].mode & SID3_FILTER_ENABLE) || - (ch->filt.filt[2].mode & SID3_FILTER_ENABLE) || (ch->filt.filt[3].mode & SID3_FILTER_ENABLE)) + + if(!ch->adsr.hold_zero) { - output = sid3_process_wave_channel_filters_block(ch); + ch->output_before_filter = sid3_adsr_output(sid3, &ch->adsr, waveform); + + if((ch->filt.filt[0].mode & SID3_FILTER_ENABLE) || (ch->filt.filt[1].mode & SID3_FILTER_ENABLE) || + (ch->filt.filt[2].mode & SID3_FILTER_ENABLE) || (ch->filt.filt[3].mode & SID3_FILTER_ENABLE)) + { + output = sid3_process_wave_channel_filters_block(ch); + } + else + { + output = ch->output_before_filter; + } + + if(!sid3->muted[SID3_NUM_CHANNELS - 1]) + { + sid3->output_l += output * ch->panning_left / 0x8f0 * ((ch->phase_inv & SID3_INV_SIGNAL_LEFT) ? -1 : 1); + sid3->output_r += output * ch->panning_right / 0x8f0 * ((ch->phase_inv & SID3_INV_SIGNAL_RIGHT) ? -1 : 1); + } } else { - output = ch->output_before_filter; - } + ch->output_before_filter = 0; - if(!sid3->muted[SID3_NUM_CHANNELS - 1]) - { - sid3->output_l += output * ch->panning_left / 0x8f0 * ((ch->phase_inv & SID3_INV_SIGNAL_LEFT) ? -1 : 1); - sid3->output_r += output * ch->panning_right / 0x8f0 * ((ch->phase_inv & SID3_INV_SIGNAL_RIGHT) ? -1 : 1); + for(int j = 0; j < SID3_NUM_FILTERS; j++) + { + if(ch->filt.filt[j].mode & SID3_FILTER_ENABLE) + { + if(ch->filt.filt[j].output > 0) + { + ch->filt.filt[j].output--; + } + if(ch->filt.filt[j].output < 0) + { + ch->filt.filt[j].output++; + } + } + } } sid3->wave_channel_output = output; @@ -3501,12 +3569,10 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data) if(channel != SID3_NUM_CHANNELS - 1) { sid3->chan[channel].filt.filt[filter].mode = data; - //sid3_set_filter_settings(&sid3->chan[channel].filt.filt[filter]); } else { sid3->wave_chan.filt.filt[filter].mode = data; - //sid3_set_filter_settings(&sid3->wave_chan.filt.filt[filter]); } break; } @@ -3521,13 +3587,13 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data) { sid3->chan[channel].filt.filt[filter].cutoff &= 0x00ff; sid3->chan[channel].filt.filt[filter].cutoff |= data << 8; - sid3_set_filter_settings(&sid3->chan[channel].filt.filt[filter]); + sid3_set_filter_settings(sid3, &sid3->chan[channel].filt.filt[filter]); } else { sid3->wave_chan.filt.filt[filter].cutoff &= 0x00ff; sid3->wave_chan.filt.filt[filter].cutoff |= data << 8; - sid3_set_filter_settings(&sid3->wave_chan.filt.filt[filter]); + sid3_set_filter_settings(sid3, &sid3->wave_chan.filt.filt[filter]); } break; } @@ -3542,13 +3608,13 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data) { sid3->chan[channel].filt.filt[filter].cutoff &= 0xff00; sid3->chan[channel].filt.filt[filter].cutoff |= data; - sid3_set_filter_settings(&sid3->chan[channel].filt.filt[filter]); + sid3_set_filter_settings(sid3, &sid3->chan[channel].filt.filt[filter]); } else { sid3->wave_chan.filt.filt[filter].cutoff &= 0xff00; sid3->wave_chan.filt.filt[filter].cutoff |= data; - sid3_set_filter_settings(&sid3->wave_chan.filt.filt[filter]); + sid3_set_filter_settings(sid3, &sid3->wave_chan.filt.filt[filter]); } break; } @@ -3562,12 +3628,12 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data) if(channel != SID3_NUM_CHANNELS - 1) { sid3->chan[channel].filt.filt[filter].resonance = data; - sid3_set_filter_settings(&sid3->chan[channel].filt.filt[filter]); + sid3_set_filter_settings(sid3, &sid3->chan[channel].filt.filt[filter]); } else { sid3->wave_chan.filt.filt[filter].resonance = data; - sid3_set_filter_settings(&sid3->wave_chan.filt.filt[filter]); + sid3_set_filter_settings(sid3, &sid3->wave_chan.filt.filt[filter]); } break; } @@ -3581,12 +3647,12 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data) if(channel != SID3_NUM_CHANNELS - 1) { sid3->chan[channel].filt.filt[filter].distortion_level = data; - sid3_set_filter_settings(&sid3->chan[channel].filt.filt[filter]); + sid3_set_filter_settings(sid3, &sid3->chan[channel].filt.filt[filter]); } else { sid3->wave_chan.filt.filt[filter].distortion_level = data; - sid3_set_filter_settings(&sid3->wave_chan.filt.filt[filter]); + sid3_set_filter_settings(sid3, &sid3->wave_chan.filt.filt[filter]); } break; } @@ -3768,6 +3834,11 @@ void sid3_set_is_muted(SID3* sid3, uint8_t ch, bool mute) sid3->muted[ch] = mute; } +void sid3_set_clock_rate(SID3* sid3, uint32_t clock) +{ + sid3->clock_rate = clock; +} + void sid3_free(SID3* sid3) { SAFETY_HEADER diff --git a/src/engine/platform/sound/sid3.h b/src/engine/platform/sound/sid3.h index 2b517a516..65ca86661 100644 --- a/src/engine/platform/sound/sid3.h +++ b/src/engine/platform/sound/sid3.h @@ -268,6 +268,7 @@ typedef struct //emulation-only helpers bool muted[SID3_NUM_CHANNELS]; + uint32_t clock_rate; //in Hz. 1 MHz default } SID3; SID3* sid3_create(); @@ -275,6 +276,7 @@ void sid3_reset(SID3* sid3); void sid3_write(SID3* sid3, uint16_t address, uint8_t data); void sid3_clock(SID3* sid3); void sid3_set_is_muted(SID3* sid3, uint8_t ch, bool mute); +void sid3_set_clock_rate(SID3* sid3, uint32_t clock); void sid3_free(SID3* sid3); #ifdef __cplusplus diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 0875f25c1..1f8105284 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -2517,6 +2517,29 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl supportsCustomRate=false; ImGui::Text(_("nothing to configure")); break; + case DIV_SYSTEM_SID3: + { + bool quarterClock=flags.getBool("quarterClock",false); + if (ImGui::Checkbox(_("Quarter clock speed"),&quarterClock)) { + altered=true; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip(_("Decreases clock speed and CPU audio load by 4 times.\nCan be used if your CPU is too slow for the chip." + "\nDoes not affect clock speed during export!\n\n" + + "Warning! Filters may become unstable at high cutoff and resonance\nif this option or lower clock speed are used!\n" + "Also filters' timbre may be different near these values.\n\n" + + "Default clock speed is 1MHz (1000000Hz).")); + } + + if (altered) { + e->lockSave([&]() { + flags.set("quarterClock",(int)quarterClock); + }); + } + break; + } default: { bool sysPal=flags.getInt("clockSel",0);