From 6bf391b4bc13bcd589395222df2da0d4730c73f1 Mon Sep 17 00:00:00 2001 From: LTVA1 <87536432+LTVA1@users.noreply.github.com> Date: Fri, 9 Aug 2024 14:30:45 +0300 Subject: [PATCH] wavetables and samples for SID3! (unfinished) --- src/engine/instrument.cpp | 3 +- src/engine/instrument.h | 4 +- src/engine/platform/sid3.cpp | 216 +++++++++++++++++++++++++----- src/engine/platform/sid3.h | 20 ++- src/engine/platform/sound/sid3.c | 220 ++++++++++++++++++++++++++++++- src/engine/platform/sound/sid3.h | 3 + src/engine/sysDef.cpp | 13 +- src/gui/guiConst.cpp | 64 ++++----- src/gui/insEdit.cpp | 65 +++++++-- 9 files changed, 522 insertions(+), 86 deletions(-) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 7c850d28e..b30f7a9e5 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -268,6 +268,7 @@ bool DivInstrumentSID3::operator==(const DivInstrumentSID3& other) { _C(oneBitNoise) && _C(separateNoisePitch) && _C(special_wave) && + _C(doWavetable) && _C(filt[0]) && _C(filt[1]) && _C(filt[2]) && @@ -1254,7 +1255,7 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song, bo if (sid2!=defaultIns.sid2) { featureS2=true; } - if (sid3!=defaultIns.sid3) { + if (sid3!=defaultIns.sid3 || type == DIV_INS_SID3) { featureS3=true; } } diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 5f1cdd8ed..a736694df 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -873,6 +873,7 @@ struct DivInstrumentSID3 bool oneBitNoise; bool separateNoisePitch; unsigned char special_wave; + bool doWavetable; struct Filter { @@ -938,7 +939,8 @@ struct DivInstrumentSID3 specialWaveOn(false), oneBitNoise(false), separateNoisePitch(false), - special_wave(0) + special_wave(0), + doWavetable(false) { filt[0].mode = 16 | 32; //default settings so filter just works, connect to input and channel output filt[0].output_volume = 0xff; diff --git a/src/engine/platform/sid3.cpp b/src/engine/platform/sid3.cpp index 44f01cc08..f5335aec3 100644 --- a/src/engine/platform/sid3.cpp +++ b/src/engine/platform/sid3.cpp @@ -26,6 +26,7 @@ #define rWrite(a,v) if (!skipRegisterWrites) {writes.push(QueuedWrite(a,v)); if (dumpWrites) {addWrite(a,v);} } #define CHIP_FREQBASE 524288 +#define CHIP_DIVIDER 1 const char* regCheatSheetSID3[]={ "FreqL0", "00", @@ -82,6 +83,43 @@ void DivPlatformSID3::acquire(short** buf, size_t len) regPool[w.addr % SID3_NUM_REGISTERS]=w.val; writes.pop(); } + + if (chan[SID3_NUM_CHANNELS - 1].pcm && chan[SID3_NUM_CHANNELS - 1].dacSample!=-1) + { + chan[SID3_NUM_CHANNELS - 1].dacPeriod+=chan[SID3_NUM_CHANNELS - 1].dacRate; + if (chan[SID3_NUM_CHANNELS - 1].dacPeriod>rate) + { + DivSample* s=parent->getSample(chan[SID3_NUM_CHANNELS - 1].dacSample); + if (s->samples<=0 || chan[SID3_NUM_CHANNELS - 1].dacPos>=s->samples) + { + chan[SID3_NUM_CHANNELS - 1].dacSample=-1; + continue; + } + + 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); + } + chan[SID3_NUM_CHANNELS - 1].dacPos++; + if (s->isLoopable() && chan[SID3_NUM_CHANNELS - 1].dacPos>=(unsigned int)s->loopEnd) + { + chan[SID3_NUM_CHANNELS - 1].dacPos=s->loopStart; + } + else if (chan[SID3_NUM_CHANNELS - 1].dacPos>=s->samples) + { + chan[SID3_NUM_CHANNELS - 1].dacSample=-1; + } + chan[SID3_NUM_CHANNELS - 1].dacPeriod-=rate; + } + } sid3_clock(sid3); @@ -92,10 +130,12 @@ void DivPlatformSID3::acquire(short** buf, size_t len) { writeOscBuf=0; - for(int j = 0; j < SID3_NUM_CHANNELS; j++) + for(int j = 0; j < SID3_NUM_CHANNELS - 1; j++) { oscBuf[j]->data[oscBuf[j]->needle++] = sid3->muted[j] ? 0 : (sid3->channel_output[j] / 4); } + + oscBuf[SID3_NUM_CHANNELS - 1]->data[oscBuf[SID3_NUM_CHANNELS - 1]->needle++] = sid3->muted[SID3_NUM_CHANNELS - 1] ? 0 : (sid3->wave_channel_output / 4); } } } @@ -178,6 +218,18 @@ void DivPlatformSID3::updatePanning(int channel) rWrite(SID3_REGISTER_PAN_RIGHT + channel*SID3_REGISTERS_PER_CHANNEL,chan[channel].panRight); } +void DivPlatformSID3::updateWave() +{ + int channel = SID3_NUM_CHANNELS - 1; + + for(int i = 0; i < 256; i++) + { + uint8_t val = ws.output[i & 255]; + rWrite(SID3_REGISTER_PW_HIGH + channel*SID3_REGISTERS_PER_CHANNEL,i); + rWrite(SID3_REGISTER_PW_LOW + channel*SID3_REGISTERS_PER_CHANNEL,val); + } +} + void DivPlatformSID3::tick(bool sysTick) { for (int i=0; igetIns(chan[i].ins,DIV_INS_SID3); + + if(i == SID3_NUM_CHANNELS - 1 && ins->sid3.doWavetable) + { + chan[i].wavetable = chan[i].std.wave.val & 0xff; + ws.changeWave1(chan[i].wave); + } + else + { + chan[i].wave = chan[i].std.wave.val & 0xff; + rWrite(SID3_REGISTER_WAVEFORM + i * SID3_REGISTERS_PER_CHANNEL, chan[i].wave); + } } if (chan[i].std.alg.had) { //special wave chan[i].special_wave = chan[i].std.alg.val & 0xff; @@ -275,6 +337,15 @@ void DivPlatformSID3::tick(bool sysTick) { flagsChanged = true; } + + if (chan[i].pcm) + { + if (chan[i].active && chan[i].dacSample>=0 && chan[i].dacSamplesong.sampleLen) + { + chan[i].dacPos=0; + chan[i].dacPeriod=0; + } + } } if (chan[i].std.op[1].am.had) { //noise phase reset chan[i].phaseResetNoise = chan[i].std.op[1].am.val & 1; @@ -410,12 +481,26 @@ void DivPlatformSID3::tick(bool sysTick) if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE * 64); - //if (chan[i].freq<0) chan[i].freq=0; - //if (chan[i].freq>0x1ffff) chan[i].freq=0x1ffff; if (chan[i].keyOn) - { - rWrite(SID3_REGISTER_WAVEFORM + i * SID3_REGISTERS_PER_CHANNEL, chan[i].wave); //waveform + { + DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SID3); + if(i == SID3_NUM_CHANNELS - 1) + { + if(ins->sid3.doWavetable) + { + rWrite(SID3_REGISTER_WAVEFORM + i * SID3_REGISTERS_PER_CHANNEL, 0); //wave channel mode + } + else + { + rWrite(SID3_REGISTER_WAVEFORM + i * SID3_REGISTERS_PER_CHANNEL, 1); //wave channel mode + } + } + else + { + rWrite(SID3_REGISTER_WAVEFORM + i * SID3_REGISTERS_PER_CHANNEL, chan[i].wave); + } + rWrite(SID3_REGISTER_SPECIAL_WAVE + i * SID3_REGISTERS_PER_CHANNEL, chan[i].special_wave); //special wave rWrite(SID3_REGISTER_ADSR_VOL + i * SID3_REGISTERS_PER_CHANNEL, chan[i].outVol); //set volume @@ -442,6 +527,19 @@ void DivPlatformSID3::tick(bool sysTick) updateFreq(i); + if (chan[i].pcm && i == SID3_NUM_CHANNELS - 1) { + double off=1.0; + if (chan[i].dacSample>=0 && chan[i].dacSamplesong.sampleLen) { + DivSample* s=parent->getSample(chan[i].dacSample); + if (s->centerRate<1) { + off=1.0; + } else { + off=(double)s->centerRate/8363.0; + } + } + chan[i].dacRate=chan[i].freq*(off / 32.0); + } + chan[i].noiseFreqChanged = true; if(chan[i].independentNoiseFreq) @@ -449,10 +547,6 @@ void DivPlatformSID3::tick(bool sysTick) chan[i].noise_pitch2 = chan[i].pitch2; } - //rWrite(i*7,chan[i].freq&0xff); - //rWrite(i*7+1,chan[i].freq>>8); - //rWrite(0x1e, (chan[0].noise_mode) | (chan[1].noise_mode << 2) | (chan[2].noise_mode << 4) | ((chan[0].freq >> 16) << 6) | ((chan[1].freq >> 16) << 7)); - //rWrite(0x1f, (chan[0].mix_mode) | (chan[1].mix_mode << 2) | (chan[2].mix_mode << 4) | ((chan[2].freq >> 16) << 6)); if (chan[i].keyOn) chan[i].keyOn=false; if (chan[i].keyOff) chan[i].keyOff=false; chan[i].freqChanged=false; @@ -477,6 +571,14 @@ void DivPlatformSID3::tick(bool sysTick) chan[i].noiseFreqChanged = false; } } + + if (chan[SID3_NUM_CHANNELS - 1].active && !chan[SID3_NUM_CHANNELS - 1].pcm) + { + if (ws.tick()) + { + updateWave(); + } + } } int DivPlatformSID3::dispatch(DivCommand c) { @@ -495,23 +597,53 @@ int DivPlatformSID3::dispatch(DivCommand c) { chan[c.chan].active=true; chan[c.chan].keyOn=true; - if (chan[c.chan].insChanged || chan[c.chan].resetDuty || ins->std.waveMacro.len>0) { - //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)); + if (ins->amiga.useSample) + { + chan[c.chan].pcm=true; + } + else + { + chan[c.chan].pcm=false; } - if (chan[c.chan].insChanged) { - /*chan[c.chan].wave = (ins->c64.noiseOn << 3) | (ins->c64.pulseOn << 2) | (ins->c64.sawOn << 1) | (int)(ins->c64.triOn); - chan[c.chan].attack=ins->c64.a; - chan[c.chan].decay=(ins->c64.s==15)?0:ins->c64.d; - chan[c.chan].sustain=ins->c64.s; - chan[c.chan].release=ins->c64.r; - chan[c.chan].ring=ins->c64.ringMod; - chan[c.chan].sync=ins->c64.oscSync; - chan[c.chan].noise_mode = ins->sid3.noiseMode; - chan[c.chan].mix_mode = ins->sid3.mixMode;*/ + if (chan[c.chan].pcm && c.chan == SID3_NUM_CHANNELS - 1) + { + if (ins->amiga.useSample) + { + if (skipRegisterWrites) break; + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].dacSample=ins->amiga.getSample(c.value); + chan[c.chan].sampleNote=c.value; + c.value=ins->amiga.getFreq(c.value); + chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; + } else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) { + chan[c.chan].dacSample=ins->amiga.getSample(chan[c.chan].sampleNote); + c.value=ins->amiga.getFreq(chan[c.chan].sampleNote); + } + if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen) + { + chan[c.chan].dacSample=-1; + break; + } + chan[c.chan].dacPos=0; + chan[c.chan].dacPeriod=0; + if (c.value!=DIV_NOTE_NULL) + { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + chan[c.chan].freqChanged=true; + chan[c.chan].note=c.value; + } + chan[c.chan].active=true; + chan[c.chan].macroInit(ins); + if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + } + //chan[c.chan].keyOn=true; + } + } + 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].special_wave = ins->sid3.special_wave; //special wave @@ -556,15 +688,15 @@ int DivPlatformSID3::dispatch(DivCommand c) { updateFilter(c.chan, j); } } - } - if (chan[c.chan].insChanged || chan[c.chan].resetFilter) { - /*chan[c.chan].filter=ins->c64.toFilter; - if (ins->c64.initFilter) { - chan[c.chan].filtCut=ins->c64.cut; - chan[c.chan].filtRes=ins->c64.res; - chan[c.chan].filtControl=(int)(ins->c64.lp)|(ins->c64.bp<<1)|(ins->c64.hp<<2); + + if(c.chan == SID3_NUM_CHANNELS - 1) + { + if(!chan[c.chan].pcm) + { + ws.changeWave1(chan[c.chan].wavetable, false); + ws.init(ins,256,255,chan[c.chan].insChanged); + } } - updateFilter(c.chan);*/ } if (chan[c.chan].insChanged) { chan[c.chan].insChanged=false; @@ -747,6 +879,12 @@ int DivPlatformSID3::dispatch(DivCommand c) { chan[c.chan].filt[c.value2].cutoff = (c.value & 0xfff) << 4; updateFilter(c.chan, c.value2); break; + case DIV_CMD_C64_RESONANCE: + chan[c.chan].filt[c.value2].resonance = c.value & 0xff; + updateFilter(c.chan, c.value2); + break; + case DIV_CMD_SAMPLE_POS: + chan[c.chan].dacPos=c.value; case DIV_CMD_MACRO_OFF: chan[c.chan].std.mask(c.value,true); break; @@ -791,6 +929,15 @@ void DivPlatformSID3::notifyInsChange(int ins) { } } +void DivPlatformSID3::notifyWaveChange(int wave) +{ + if (chan[SID3_NUM_CHANNELS - 1].wavetable==wave) + { + ws.changeWave1(wave, false); + updateWave(); + } +} + void DivPlatformSID3::notifyInsDeletion(void* ins) { for (int i=0; istd.op[3].am; @@ -156,7 +164,14 @@ class DivPlatformSID3: public DivDispatch { panRight(0xff), noiseFreq(0), independentNoiseFreq(false), - noiseLFSRMask((1 << 29) | (1 << 5) | (1 << 3) | 1) {} //https://docs.amd.com/v/u/en-US/xapp052 for 30 bits: 30, 6, 4, 1 + noiseLFSRMask((1 << 29) | (1 << 5) | (1 << 3) | 1), + pcm(false), + wavetable(-1), + dacPeriod(0), + dacRate(0), + dacOut(0), + dacPos(0), + dacSample(-1) {} //https://docs.amd.com/v/u/en-US/xapp052 for 30 bits: 30, 6, 4, 1 }; Channel chan[SID3_NUM_CHANNELS]; DivDispatchOscBuffer* oscBuf[SID3_NUM_CHANNELS]; @@ -167,6 +182,7 @@ class DivPlatformSID3: public DivDispatch { QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v) {} }; FixedQueue writes; + DivWaveSynth ws; unsigned char writeOscBuf; @@ -186,6 +202,7 @@ class DivPlatformSID3: public DivDispatch { void updateDuty(int channel); void updateEnvelope(int channel); void updatePanning(int channel); + void updateWave(); public: void acquire(short** buf, size_t len); @@ -200,6 +217,7 @@ class DivPlatformSID3: public DivDispatch { void muteChannel(int ch, bool mute); void setFlags(const DivConfig& flags); void notifyInsChange(int ins); + void notifyWaveChange(int wave); float getPostAmp(); bool getDCOffRequired(); DivMacroInt* getChanMacroInt(int ch); diff --git a/src/engine/platform/sound/sid3.c b/src/engine/platform/sound/sid3.c index fe07e9b9c..1f1e84cfb 100644 --- a/src/engine/platform/sound/sid3.c +++ b/src/engine/platform/sound/sid3.c @@ -2879,6 +2879,105 @@ int32_t sid3_process_filters_block(sid3_channel* ch) return output; } +int32_t sid3_process_wave_channel_filters_block(sid3_wavetable_chan* ch) +{ + int32_t output = 0; + + ch->clock_filter++; + + if(ch->clock_filter & 1) + { + for(uint8_t i = 0; i < SID3_NUM_FILTERS; i++) + { + if(ch->filt.filt[i].mode & SID3_FILTER_OUTPUT) + { + output += ch->filt.filt[i].output; + } + } + + return output; + } + + for(uint8_t i = 0; i < SID3_NUM_FILTERS; i++) + { + ch->filt.filt[i].input = 0; + } + + for(uint8_t i = 0; i < SID3_NUM_FILTERS; i++) + { + if(ch->filt.filt[i].mode & SID3_FILTER_CHANNEL_INPUT) + { + ch->filt.filt[i].input += ch->output_before_filter; + } + + for(uint8_t j = 0; j < SID3_NUM_FILTERS; j++) + { + if(ch->filt.connection_matrix[i] & (1 << j)) + { + ch->filt.filt[i].input += ch->filt.filt[j].output; + } + } + } + + for(uint8_t i = 0; i < SID3_NUM_FILTERS; i++) + { + if(ch->filt.filt[i].mode & SID3_FILTER_ENABLE) + { + float Vi = ch->filt.filt[i].input; + + float dVbp = (ch->filt.filt[i].w0_ceil_1 * ch->filt.filt[i].Vhp); + float dVlp = (ch->filt.filt[i].w0_ceil_1 * ch->filt.filt[i].Vbp); + ch->filt.filt[i].Vbp += dVbp; + ch->filt.filt[i].Vlp += dVlp; + ch->filt.filt[i].Vhp = Vi - ch->filt.filt[i].Vlp - (ch->filt.filt[i].Vbp * ch->filt.filt[i]._1024_div_Q); + + float Vo; + + switch(ch->filt.filt[i].mode & SID3_FILTER_MODES_MASK) + { + case 0x0: + default: + Vo = 0; + break; + case SID3_FILTER_LP: + Vo = ch->filt.filt[i].Vlp; + break; + case SID3_FILTER_HP: + Vo = ch->filt.filt[i].Vhp; + break; + case SID3_FILTER_LP | SID3_FILTER_HP: + Vo = ch->filt.filt[i].Vlp + ch->filt.filt[i].Vhp; + break; + case SID3_FILTER_BP: + Vo = ch->filt.filt[i].Vbp; + break; + case SID3_FILTER_BP | SID3_FILTER_LP: + Vo = ch->filt.filt[i].Vlp + ch->filt.filt[i].Vbp; + break; + case SID3_FILTER_BP | SID3_FILTER_HP: + Vo = ch->filt.filt[i].Vhp + ch->filt.filt[i].Vbp; + break; + case SID3_FILTER_BP | SID3_FILTER_HP | SID3_FILTER_LP: + Vo = ch->filt.filt[i].Vlp + ch->filt.filt[i].Vbp + ch->filt.filt[i].Vhp; + break; + } + + ch->filt.filt[i].output = Vo * ch->filt.filt[i].output_volume / 0xff; + } + else + { + ch->filt.filt[i].output = 0; + } + + if(ch->filt.filt[i].mode & SID3_FILTER_OUTPUT) + { + output += ch->filt.filt[i].output; + } + } + + return output; +} + void sid3_clock(SID3* sid3) { //SAFETY_HEADER @@ -2978,6 +3077,94 @@ void sid3_clock(SID3* sid3) sid3->channel_output[i] = output; } + + //wavetable/streamed PCM sample channel: + + sid3_wavetable_chan* ch = &sid3->wave_chan; + + uint32_t prev_acc = ch->accumulator; + + ch->accumulator += ch->frequency; + + ch->sync_bit = 0; + + if(ch->accumulator & (1 << SID3_ACC_BITS)) + { + ch->sync_bit = 1; + } + + if(ch->flags & SID3_CHAN_ENABLE_HARD_SYNC) + { + if(ch->hard_sync_src == SID3_NUM_CHANNELS - 1) //wave chan + { + if(sid3->wave_chan.sync_bit) + { + ch->accumulator = 0; + } + } + else + { + if(sid3->chan[ch->hard_sync_src].sync_bit) + { + ch->accumulator = 0; + } + } + } + + 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 << 18) : ((uint64_t)sid3->channel_output[ch->phase_mod_source] << 18); + } + + ch->accumulator &= SID3_ACC_MASK; + + int32_t waveform; + + 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! + } + + 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_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; + sid3->output_r += output * ch->panning_right / 0x8f0; + } + + sid3->wave_channel_output = output; } void sid3_write(SID3* sid3, uint16_t address, uint8_t data) @@ -3027,7 +3214,7 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data) } else { - uint8_t prev_flags = sid3->chan[channel].flags; + uint8_t prev_flags = sid3->wave_chan.flags; sid3->wave_chan.flags = data; if((prev_flags & SID3_CHAN_ENABLE_GATE) != (sid3->wave_chan.flags & SID3_CHAN_ENABLE_GATE)) @@ -3035,6 +3222,19 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data) sid3_gate_bit(sid3, sid3->wave_chan.flags & SID3_CHAN_ENABLE_GATE, &sid3->wave_chan.adsr); } + if(sid3->wave_chan.flags & SID3_CHAN_ENV_RESET) + { + sid3->wave_chan.adsr.envelope_counter = 0; + sid3->wave_chan.adsr.state = ATTACK; + sid3->wave_chan.adsr.envelope_speed = envspd_a(sid3->wave_chan.adsr.a); + sid3->wave_chan.adsr.hold_zero = false; + } + + if(sid3->wave_chan.flags & SID3_CHAN_PHASE_RESET) + { + sid3->wave_chan.accumulator = 0; + } + sid3->wave_chan.flags &= ~(SID3_CHAN_ENV_RESET | SID3_CHAN_NOISE_PHASE_RESET | SID3_CHAN_PHASE_RESET); } break; @@ -3477,6 +3677,24 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data) } break; } + case SID3_REGISTER_STREAMED_SAMPLE_HIGH: + { + if(channel == SID3_NUM_CHANNELS - 1) + { + sid3->wave_chan.streamed_sample &= 0x00ff; + sid3->wave_chan.streamed_sample |= data << 8; + } + break; + } + case SID3_REGISTER_STREAMED_SAMPLE_LOW: + { + if(channel == SID3_NUM_CHANNELS - 1) + { + sid3->wave_chan.streamed_sample &= 0xff00; + sid3->wave_chan.streamed_sample |= data; + } + break; + } default: break; } } diff --git a/src/engine/platform/sound/sid3.h b/src/engine/platform/sound/sid3.h index a68a9bb5d..ce0c6c21b 100644 --- a/src/engine/platform/sound/sid3.h +++ b/src/engine/platform/sound/sid3.h @@ -124,6 +124,9 @@ enum Registers SID3_REGISTER_NOISE_LFSR_HIGH = SID3_REGISTER_AFTER_FILT_1ST_REG + 7, SID3_REGISTER_NOISE_LFSR_MID = SID3_REGISTER_AFTER_FILT_1ST_REG + 8, SID3_REGISTER_NOISE_LFSR_LOW = SID3_REGISTER_AFTER_FILT_1ST_REG + 9, + + SID3_REGISTER_STREAMED_SAMPLE_HIGH = SID3_REGISTER_AFTER_FILT_1ST_REG + 10, + SID3_REGISTER_STREAMED_SAMPLE_LOW = SID3_REGISTER_AFTER_FILT_1ST_REG + 11, }; typedef struct diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index c87654ddc..6ee2a1323 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -713,7 +713,12 @@ void DivEngine::registerSystems() { {0x6F, {DIV_CMD_SID3_LFSR_FEEDBACK_BITS, _("6Fxx: Set noise LFSR feedback bits (higher byte)"), effectVal, constVal<2>}}, {0x70, {DIV_CMD_SID3_LFSR_FEEDBACK_BITS, _("70xx: Set noise LFSR feedback bits (highest bits, 0-3F)"), effectVal, constVal<3>}}, - {0x71, {DIV_CMD_SID3_1_BIT_NOISE, _("71xx: Set noise mode (0: usual noise, 1: 1-bit noise (PCM mode on wave channel))")}}, + {0x71, {DIV_CMD_C64_RESONANCE, _("71xx: Set filter 1 resonance"), effectVal, constVal<0>}}, + {0x72, {DIV_CMD_C64_RESONANCE, _("72xx: Set filter 2 resonance"), effectVal, constVal<1>}}, + {0x73, {DIV_CMD_C64_RESONANCE, _("73xx: Set filter 3 resonance"), effectVal, constVal<2>}}, + {0x74, {DIV_CMD_C64_RESONANCE, _("74xx: Set filter 4 resonance"), effectVal, constVal<3>}}, + + {0x75, {DIV_CMD_SID3_1_BIT_NOISE, _("75xx: Set noise mode (0: usual noise, 1: 1-bit noise (PCM mode on wave channel))")}}, }; const EffectHandler SID3FineDutyHandler(DIV_CMD_C64_FINE_DUTY, _("5xxx: Set pulse width (0 to FFF)"), effectValLong<12>); @@ -2185,9 +2190,9 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_SID3]=new DivSysDef( _("SID3"), NULL, 0xf5, 0, 7, false, true, 0, false, (1U << DIV_SAMPLE_DEPTH_8BIT) | (1U << DIV_SAMPLE_DEPTH_16BIT), 256, 256, _("a fantasy sound chip created by LTVA. it is a big rework of SID chip with probably too much features added on top."), - {_("Channel 1"), _("Channel 2"), _("Channel 3"), _("Channel 4"), _("Channel 5"), _("Channel 6"), _("Sample")}, - {"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "PCM"}, - {DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, + {_("Channel 1"), _("Channel 2"), _("Channel 3"), _("Channel 4"), _("Channel 5"), _("Channel 6"), _("Wave")}, + {"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "WA"}, + {DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_WAVE}, {DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3}, {}, {}, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index fea86adfd..cebfcd0e0 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -345,40 +345,40 @@ const FurnaceGUIColors fxColors[256]={ GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, // 60-6F - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, // 70-7F - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, + GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY, // 80-8F GUI_COLOR_PATTERN_EFFECT_PANNING, diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index d0c8d1554..d7be80389 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -3273,7 +3273,8 @@ void FurnaceGUI::insTabSample(DivInstrument* ins) { ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_VRC6 || ins->type==DIV_INS_SU || - ins->type==DIV_INS_NDS) { + ins->type==DIV_INS_NDS || + ins->type==DIV_INS_SID3) { P(ImGui::Checkbox(_("Use sample"),&ins->amiga.useSample)); if (ins->type==DIV_INS_X1_010) { if (ImGui::InputInt(_("Sample bank slot##BANKSLOT"),&ins->x1_010.bankSlot,1,4)) { PARAMETER @@ -5893,9 +5894,23 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins) P(CWSliderScalar(_("Special wave"),ImGuiDataType_U8,&ins->sid3.special_wave,&_ZERO,&_SID3_SPECIAL_WAVES,sid3SpecialWaveforms[ins->sid3.special_wave % SID3_NUM_SPECIAL_WAVES])); rightClickable + if(ImGui::Checkbox(_("Wavetable channel"),&ins->sid3.doWavetable)) + { + PARAMETER; + ins->std.waveMacro.vZoom=-1; + for(int i = 0; i < 256; i++) + { + ins->std.waveMacro.val[i]=0; + } + } + if (ImGui::IsItemHovered()) + { + ImGui::SetTooltip(_("Forces waveform macro to control wavetable index.")); + } + ImGui::TableNextColumn(); - drawWaveformSID3(ins->sid3.special_wave,ImVec2(80.0f * dpiScale, 60.0f * dpiScale)); + drawWaveformSID3(ins->sid3.special_wave,ImVec2(160.0f * dpiScale, 110.0f * dpiScale)); ImGui::EndTable(); } @@ -6174,8 +6189,14 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins) ImGui::EndTabItem(); } - insTabWavetable(ins); - insTabSample(ins); + if(!ins->amiga.useSample) + { + insTabWavetable(ins); + } + if(!ins->sid3.doWavetable) + { + insTabSample(ins); + } std::vector macroList; @@ -6209,12 +6230,19 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins) macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val)); macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); - macroList.push_back(FurnaceGUIMacroDesc(_("Duty"),&ins->std.dutyMacro,ins->c64.dutyIsAbs?0:-65535,65535,160,uiColors[GUI_COLOR_MACRO_OTHER])); + if(ins->sid3.doWavetable) + { + int waveCount=MAX(1,e->song.waveLen-1); + macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL)); + } + 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(_("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)); + } - 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)); - - if(ins->sid3.separateNoisePitch) + if(ins->sid3.separateNoisePitch && !ins->sid3.doWavetable) { macroList.push_back(FurnaceGUIMacroDesc(_("Noise Arpeggio"),&ins->std.opMacros[3].amMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.opMacros[3].amMacro.val,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Noise Pitch"),&ins->std.opMacros[0].arMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode,NULL,false,NULL,false,NULL,false,true)); @@ -6232,7 +6260,11 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins) macroList.push_back(FurnaceGUIMacroDesc(_("Phase Mod Source"),&ins->std.fbMacro,0,SID3_NUM_CHANNELS - 1,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroSID3SourceChan)); macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(_("Noise Phase Reset"),&ins->std.opMacros[1].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + + if(!ins->sid3.doWavetable) + { + macroList.push_back(FurnaceGUIMacroDesc(_("Noise Phase Reset"),&ins->std.opMacros[1].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + } macroList.push_back(FurnaceGUIMacroDesc(_("Envelope Reset"),&ins->std.opMacros[2].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(_("Attack"),&ins->std.ex2Macro,0,255,160,uiColors[GUI_COLOR_MACRO_ENVELOPE])); @@ -6241,9 +6273,16 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins) macroList.push_back(FurnaceGUIMacroDesc(_("Sustain Rate"),&ins->std.ex5Macro,0,255,160,uiColors[GUI_COLOR_MACRO_ENVELOPE])); macroList.push_back(FurnaceGUIMacroDesc(_("Release"),&ins->std.ex6Macro,0,255,160,uiColors[GUI_COLOR_MACRO_ENVELOPE])); - macroList.push_back(FurnaceGUIMacroDesc(_("Noise LFSR bits"),&ins->std.ex7Macro,0,29,16 * 30,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(_("1-Bit Noise/Sample Mode"),&ins->std.opMacros[1].arMacro,0,1,32,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(_("Wave Mix"),&ins->std.ex8Macro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroSID3WaveMixMode)); + if(!ins->sid3.doWavetable) + { + macroList.push_back(FurnaceGUIMacroDesc(_("Noise LFSR bits"),&ins->std.ex7Macro,0,29,16 * 30,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(_("1-Bit Noise"),&ins->std.opMacros[1].arMacro,0,1,32,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(_("Wave Mix"),&ins->std.ex8Macro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroSID3WaveMixMode)); + } + else + { + macroList.push_back(FurnaceGUIMacroDesc(_("Sample Mode"),&ins->std.opMacros[1].arMacro,0,1,32,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true)); + } drawMacros(macroList,macroEditStateMacros);