wavetables and samples for SID3! (unfinished)

This commit is contained in:
LTVA1 2024-08-09 14:30:45 +03:00
parent 2a322bff4f
commit 6bf391b4bc
9 changed files with 522 additions and 86 deletions

View file

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

View file

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

View file

@ -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; i<SID3_NUM_CHANNELS; i++)
@ -221,8 +273,18 @@ void DivPlatformSID3::tick(bool sysTick)
updateDuty(i);
}
if (chan[i].std.wave.had) {
chan[i].wave = chan[i].std.wave.val & 0xff;
rWrite(SID3_REGISTER_WAVEFORM + i * SID3_REGISTERS_PER_CHANNEL, chan[i].wave);
DivInstrument* ins=parent->getIns(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].dacSample<parent->song.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].dacSample<parent->song.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; i<SID3_NUM_CHANNELS; i++) {
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
@ -854,6 +1001,9 @@ void DivPlatformSID3::reset() {
chan[i].noiseLFSRMask = (1 << 29) | (1 << 5) | (1 << 3) | 1; //https://docs.amd.com/v/u/en-US/xapp052 for 30 bits: 30, 6, 4, 1
}
ws.setEngine(parent);
ws.init(NULL,256,255,false);
sid3_reset(sid3);
memset(regPool,0,SID3_NUM_REGISTERS);
}

View file

@ -22,6 +22,7 @@
#include "../dispatch.h"
#include "../../fixedQueue.h"
#include "../waveSynth.h"
#include "sound/sid3.h"
class DivPlatformSID3: public DivDispatch {
@ -68,6 +69,13 @@ class DivPlatformSID3: public DivDispatch {
bool noise_hasArp;
bool noise_hasPitch;
bool pcm;
int wavetable;
long long dacPeriod, dacRate, dacOut;
unsigned long long dacPos;
int dacSample;
void handleArpNoise(int offset=0)
{
DivMacroStruct& m = this->std.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<QueuedWrite,SID3_NUM_REGISTERS * 4> 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);

View file

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

View file

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

View file

@ -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},
{},
{},

View file

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

View file

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