separate noise frequency, almost all main macros, add wavetable size to sysdef, separate wavetable tab

This commit is contained in:
LTVA1 2024-08-05 12:28:22 +03:00
parent 2e321b66c2
commit 2fb518231a
9 changed files with 638 additions and 289 deletions

View file

@ -265,6 +265,7 @@ bool DivInstrumentSID3::operator==(const DivInstrumentSID3& other) {
_C(sync_source) &&
_C(specialWaveOn) &&
_C(oneBitNoise) &&
_C(separateNoisePitch) &&
_C(special_wave) &&
_C(filt[0]) &&
_C(filt[1]) &&

View file

@ -870,6 +870,7 @@ struct DivInstrumentSID3
unsigned char phase_mod_source, ring_mod_source, sync_source;
bool specialWaveOn;
bool oneBitNoise;
bool separateNoisePitch;
unsigned char special_wave;
struct Filter
@ -914,6 +915,7 @@ struct DivInstrumentSID3
sync_source(0),
specialWaveOn(false),
oneBitNoise(false),
separateNoisePitch(false),
special_wave(0)
{
filt[0].mode = 16 | 32; //default settings so filter just works, connect to input and channel output

View file

@ -142,6 +142,13 @@ void DivPlatformSID3::updateFreq(int channel)
rWrite(SID3_REGISTER_FREQ_LOW + channel*SID3_REGISTERS_PER_CHANNEL,chan[channel].freq & 0xff);
}
void DivPlatformSID3::updateNoiseFreq(int channel)
{
rWrite(SID3_REGISTER_NOISE_FREQ_HIGH + channel*SID3_REGISTERS_PER_CHANNEL,(chan[channel].noiseFreq >> 16) & 0xff);
rWrite(SID3_REGISTER_NOISE_FREQ_MID + channel*SID3_REGISTERS_PER_CHANNEL,(chan[channel].noiseFreq >> 8) & 0xff);
rWrite(SID3_REGISTER_NOISE_FREQ_LOW + channel*SID3_REGISTERS_PER_CHANNEL,chan[channel].noiseFreq & 0xff);
}
void DivPlatformSID3::updateDuty(int channel)
{
rWrite(SID3_REGISTER_PW_HIGH + channel*SID3_REGISTERS_PER_CHANNEL,(chan[channel].duty >> 8) & 0xff);
@ -170,6 +177,8 @@ void DivPlatformSID3::tick(bool sysTick)
chan[i].std.next();
bool panChanged = false;
bool flagsChanged = false;
bool envChanged = false;
if (chan[i].std.vol.had)
{
@ -203,6 +212,22 @@ void DivPlatformSID3::tick(bool sysTick)
chan[i].duty&=65535;
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);
}
if (chan[i].std.alg.had) { //special wave
chan[i].special_wave = chan[i].std.alg.val & 0xff;
rWrite(SID3_REGISTER_SPECIAL_WAVE + i * SID3_REGISTERS_PER_CHANNEL, chan[i].special_wave);
}
if (chan[i].std.op[3].am.had) { //noise arpeggio
chan[i].handleArpNoise(0);
chan[i].noiseFreqChanged = true;
}
if (chan[i].std.op[0].ar.had) { //noise pitch
chan[i].handlePitchNoise();
chan[i].noiseFreqChanged = true;
}
if (chan[i].std.panL.had) {
panChanged = true;
chan[i].panLeft = chan[i].std.panL.val & 0xff;
@ -211,21 +236,89 @@ void DivPlatformSID3::tick(bool sysTick)
panChanged = true;
chan[i].panRight = chan[i].std.panR.val & 0xff;
}
if (chan[i].std.op[0].am.had) { //key on/off
chan[i].gate = chan[i].std.op[0].am.val & 1;
flagsChanged = true;
}
if (chan[i].std.ex1.had) { //ring mod, hard sync, phase mod
chan[i].phase = chan[i].std.ex1.val & 1;
chan[i].sync = chan[i].std.ex1.val & 2;
chan[i].ring = chan[i].std.ex1.val & 4;
flagsChanged = true;
}
if (chan[i].std.ams.had) { //hard sync source
chan[i].syncSrc = chan[i].std.ams.val & 0xff;
rWrite(SID3_REGISTER_SYNC_SRC + i * SID3_REGISTERS_PER_CHANNEL, chan[i].syncSrc);
}
if (chan[i].std.fms.had) { //ring mod source
chan[i].ringSrc = chan[i].std.fms.val & 0xff;
rWrite(SID3_REGISTER_RING_MOD_SRC + i * SID3_REGISTERS_PER_CHANNEL, chan[i].ringSrc);
}
if (chan[i].std.fb.had) { //phase mod source
chan[i].phaseSrc = chan[i].std.fb.val & 0xff;
rWrite(SID3_REGISTER_PHASE_MOD_SRC + i * SID3_REGISTERS_PER_CHANNEL, chan[i].phaseSrc);
}
if (chan[i].std.phaseReset.had) {
chan[i].phaseReset = chan[i].std.phaseReset.val & 1;
if(chan[i].phaseReset)
{
updateFlags(i, chan[i].gate);
flagsChanged = true;
}
}
if (chan[i].std.op[1].am.had) { //noise phase reset
chan[i].phaseResetNoise = chan[i].std.op[1].am.val & 1;
chan[i].phaseReset = false;
if(chan[i].phaseResetNoise)
{
flagsChanged = true;
}
}
if (chan[i].std.op[2].am.had) { //envelope reset
chan[i].envReset = chan[i].std.op[2].am.val & 1;
if(chan[i].envReset)
{
flagsChanged = true;
}
}
if (chan[i].std.ex2.had) { //attack
chan[i].attack = chan[i].std.ex2.val & 0xff;
envChanged = true;
}
if (chan[i].std.ex3.had) { //decay
chan[i].decay = chan[i].std.ex3.val & 0xff;
envChanged = true;
}
if (chan[i].std.ex4.had) { //sustain
chan[i].sustain = chan[i].std.ex4.val & 0xff;
envChanged = true;
}
if (chan[i].std.ex5.had) { //sustain rate
chan[i].sr = chan[i].std.ex5.val & 0xff;
envChanged = true;
}
if (chan[i].std.ex6.had) { //release
chan[i].release = chan[i].std.ex6.val & 0xff;
envChanged = true;
}
if(panChanged)
{
updatePanning(i);
}
if(flagsChanged)
{
updateFlags(i, chan[i].gate);
chan[i].phaseReset = false;
chan[i].phaseResetNoise = false;
chan[i].envReset = false;
}
if(envChanged)
{
updateEnvelope(i);
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff)
{
@ -265,6 +358,11 @@ void DivPlatformSID3::tick(bool sysTick)
updateFreq(i);
if(!chan[i].independentNoiseFreq)
{
chan[i].noiseFreqChanged = true;
}
//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));
@ -273,6 +371,25 @@ void DivPlatformSID3::tick(bool sysTick)
if (chan[i].keyOff) chan[i].keyOff=false;
chan[i].freqChanged=false;
}
if(chan[i].noiseFreqChanged)
{
if(chan[i].independentNoiseFreq)
{
chan[i].noiseFreq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].noise_fixedArp?chan[i].noise_baseNoteOverride:chan[i].noise_arpOff,chan[i].noise_fixedArp,false,2,chan[i].noise_pitch2,chipClock,CHIP_FREQBASE * 64);
if (chan[i].noiseFreq<0) chan[i].noiseFreq=0;
if (chan[i].noiseFreq>0xffffff) chan[i].noiseFreq=0xffffff;
}
else
{
chan[i].noiseFreq = chan[i].freq;
}
updateNoiseFreq(i);
chan[i].noiseFreqChanged = false;
}
}
}
@ -330,6 +447,8 @@ int DivPlatformSID3::dispatch(DivCommand c) {
chan[c.chan].ringSrc = ins->sid3.ring_mod_source;
chan[c.chan].syncSrc = ins->sid3.sync_source;
chan[c.chan].independentNoiseFreq = ins->sid3.separateNoisePitch;
for(int j = 0; j < SID3_NUM_FILTERS; j++)
{
if(ins->sid3.filt[j].init)
@ -555,6 +674,8 @@ void DivPlatformSID3::reset() {
}
chan[i].panLeft = chan[i].panRight = 0xff;
chan[i].freq = chan[i].noiseFreq = 0;
updatePanning(i);
}

View file

@ -31,11 +31,14 @@ class DivPlatformSID3: public DivDispatch {
unsigned short duty;
bool resetMask, resetFilter, resetDuty, gate, ring, sync, phase, oneBitNoise;
bool phaseReset, envReset, phaseResetNoise;
bool noiseFreqChanged;
unsigned char vol;
unsigned char noise_mode;
unsigned char mix_mode;
unsigned char ringSrc, syncSrc, phaseSrc;
unsigned char panLeft, panRight;
unsigned int noiseFreq;
bool independentNoiseFreq;
struct Filter
{
@ -57,6 +60,68 @@ class DivPlatformSID3: public DivDispatch {
filter_matrix(0) {}
} filt[SID3_NUM_FILTERS];
int noise_baseNoteOverride;
bool noise_fixedArp;
int noise_arpOff;
int noise_pitch2;
bool noise_hasArp;
bool noise_hasPitch;
void handleArpNoise(int offset=0)
{
DivMacroStruct& m = this->std.op[3].am;
if (m.had) {
noise_hasArp=true;
if (m.val<0) {
if (!(m.val&0x40000000)) {
noise_baseNoteOverride=(m.val|0x40000000)+offset;
noise_fixedArp=true;
} else {
noise_arpOff=m.val;
noise_fixedArp=false;
}
} else {
if (m.val&0x40000000) {
noise_baseNoteOverride=(m.val&(~0x40000000))+offset;
noise_fixedArp=true;
} else {
noise_arpOff=m.val;
noise_fixedArp=false;
}
}
noiseFreqChanged=true;
}
else
{
noise_hasArp=false;
}
}
void handlePitchNoise()
{
DivMacroStruct& m = this->std.op[0].ar;
if (m.had) {
noise_hasPitch=true;
if (m.mode) {
noise_pitch2+=m.val;
CLAMP_VAR(noise_pitch2,-131071,131071);
} else {
noise_pitch2=m.val;
}
noiseFreqChanged=true;
}
else
{
noise_hasPitch=false;
}
}
Channel():
SharedChannel<signed short>(SID3_MAX_VOL),
prevFreq(0x1ffff),
@ -79,6 +144,7 @@ class DivPlatformSID3: public DivDispatch {
phaseReset(false),
envReset(false),
phaseResetNoise(false),
noiseFreqChanged(false),
vol(SID3_MAX_VOL),
noise_mode(0),
mix_mode(0),
@ -86,7 +152,9 @@ class DivPlatformSID3: public DivDispatch {
syncSrc(0),
phaseSrc(0),
panLeft(0xff),
panRight(0xff) {}
panRight(0xff),
noiseFreq(0),
independentNoiseFreq(false) {}
};
Channel chan[SID3_NUM_CHANNELS];
DivDispatchOscBuffer* oscBuf[SID3_NUM_CHANNELS];
@ -111,6 +179,7 @@ class DivPlatformSID3: public DivDispatch {
void updateFlags(int channel, bool gate);
void updateFilter(int channel, int filter);
void updateFreq(int channel);
void updateNoiseFreq(int channel);
void updateDuty(int channel);
void updateEnvelope(int channel);
void updatePanning(int channel);

View file

@ -2315,6 +2315,9 @@ SID3* sid3_create()
{
sid3->env_counter_to_exponential_output[i] = (exp(-2.0 + (double)i * 4.0 / (double)SID3_EXPONENTIAL_LUT_LENGTH) - min_val) * scale_factor;
}
sid3->env_counter_to_exponential_output[0] = 0; //just in case
for(uint32_t i = 0; i < SID3_EXPONENTIAL_LUT_LENGTH; i++)
{
sid3->exponential_output_to_envelope_counter[(uint64_t)sid3->env_counter_to_exponential_output[i] * (uint64_t)SID3_EXPONENTIAL_LUT_LENGTH / (uint64_t)0xffff] = i << 8;
@ -2362,6 +2365,8 @@ void sid3_reset(SID3* sid3)
}
//TODO: wavetable chan
memset(&sid3->wave_chan, 0, sizeof(sid3_wavetable_chan));
sid3->wave_chan.adsr.hold_zero = true;
}
void sid3_gate_bit(SID3* sid3, uint8_t gate, sid3_channel_adsr* adsr)
@ -2885,8 +2890,10 @@ void sid3_clock(SID3* sid3)
sid3_channel* ch = &sid3->chan[i];
uint32_t prev_acc = ch->accumulator;
uint32_t prev_noise_acc = ch->noise_accumulator;
ch->accumulator += ch->frequency;
ch->noise_accumulator += ch->noise_frequency;
ch->sync_bit = 0;
@ -2897,22 +2904,38 @@ void sid3_clock(SID3* sid3)
if(ch->flags & SID3_CHAN_ENABLE_HARD_SYNC)
{
if(sid3->chan[ch->hard_sync_src].sync_bit)
if(ch->hard_sync_src == SID3_NUM_CHANNELS - 1) //wave chan
{
ch->accumulator = 0;
if(sid3->wave_chan.sync_bit)
{
ch->accumulator = 0;
ch->noise_accumulator = 0;
ch->lfsr = 0x1;
}
}
else
{
if(sid3->chan[ch->hard_sync_src].sync_bit)
{
ch->accumulator = 0;
ch->noise_accumulator = 0;
ch->lfsr = 0x1;
}
}
}
uint32_t acc_state = ch->accumulator;
uint32_t noise_acc_state = ch->noise_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->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((prev_acc & ((uint32_t)1 << (SID3_ACC_BITS - 6))) != (ch->accumulator & ((uint32_t)1 << (SID3_ACC_BITS - 6))))
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);
}
@ -2920,6 +2943,7 @@ void sid3_clock(SID3* sid3)
int32_t waveform = sid3_get_waveform(sid3, ch);
ch->accumulator = acc_state & SID3_ACC_MASK;
ch->noise_accumulator = noise_acc_state & SID3_ACC_MASK;
sid3->channel_signals_before_ADSR[i] = waveform;
@ -2985,6 +3009,7 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data)
sid3->chan[channel].adsr.envelope_counter = 0;
sid3->chan[channel].adsr.state = ATTACK;
sid3->chan[channel].adsr.envelope_speed = envspd_a(sid3->chan[channel].adsr.a);
sid3->chan[channel].adsr.hold_zero = false;
}
if(sid3->chan[channel].flags & SID3_CHAN_PHASE_RESET)
@ -3381,6 +3406,33 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data)
}
break;
}
case SID3_REGISTER_NOISE_FREQ_HIGH:
{
if(channel != SID3_NUM_CHANNELS - 1)
{
sid3->chan[channel].noise_frequency &= 0x00ffff;
sid3->chan[channel].noise_frequency |= data << 16;
}
break;
}
case SID3_REGISTER_NOISE_FREQ_MID:
{
if(channel != SID3_NUM_CHANNELS - 1)
{
sid3->chan[channel].noise_frequency &= 0xff00ff;
sid3->chan[channel].noise_frequency |= data << 8;
}
break;
}
case SID3_REGISTER_NOISE_FREQ_LOW:
{
if(channel != SID3_NUM_CHANNELS - 1)
{
sid3->chan[channel].noise_frequency &= 0xffff00;
sid3->chan[channel].noise_frequency |= data;
}
break;
}
default: break;
}
}

View file

@ -112,8 +112,18 @@ enum Registers
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,
SID3_REGISTER_NOISE_FREQ_HIGH = SID3_REGISTER_AFTER_FILT_1ST_REG + 3,
SID3_REGISTER_NOISE_FREQ_MID = SID3_REGISTER_AFTER_FILT_1ST_REG + 4,
SID3_REGISTER_NOISE_FREQ_LOW = SID3_REGISTER_AFTER_FILT_1ST_REG + 5,
SID3_REGISTER_NOISE_LFSR_HIGHEST = SID3_REGISTER_AFTER_FILT_1ST_REG + 6,
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,
};
typedef struct

View file

@ -2160,7 +2160,7 @@ void DivEngine::registerSystems() {
);
sysDefs[DIV_SYSTEM_SID3]=new DivSysDef(
_("SID3"), NULL, 0xf5, 0, 7, false, true, 0, false, 0, 0, 0,
_("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"},