mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-30 00:13:03 +00:00
initial filters functionality (without connection matrix control yet!)
This commit is contained in:
parent
1a67453b99
commit
441e3e0b56
7 changed files with 433 additions and 36 deletions
|
@ -266,7 +266,6 @@ bool DivInstrumentSID3::operator==(const DivInstrumentSID3& other) {
|
|||
_C(specialWaveOn) &&
|
||||
_C(oneBitNoise) &&
|
||||
_C(special_wave) &&
|
||||
_C(filter_matrix) &&
|
||||
_C(filt[0]) &&
|
||||
_C(filt[1]) &&
|
||||
_C(filt[2]) &&
|
||||
|
@ -281,7 +280,9 @@ bool DivInstrumentSID3::Filter::operator==(const DivInstrumentSID3::Filter& othe
|
|||
_C(output_volume) &&
|
||||
_C(distortion_level) &&
|
||||
_C(mode) &&
|
||||
_C(enabled)
|
||||
_C(enabled) &&
|
||||
_C(init) &&
|
||||
_C(filter_matrix)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -872,8 +872,6 @@ struct DivInstrumentSID3
|
|||
bool oneBitNoise;
|
||||
unsigned char special_wave;
|
||||
|
||||
unsigned int filter_matrix;
|
||||
|
||||
struct Filter
|
||||
{
|
||||
unsigned short cutoff;
|
||||
|
@ -882,6 +880,8 @@ struct DivInstrumentSID3
|
|||
unsigned char distortion_level;
|
||||
unsigned char mode;
|
||||
bool enabled;
|
||||
bool init;
|
||||
unsigned char filter_matrix;
|
||||
|
||||
bool operator==(const Filter& other);
|
||||
bool operator!=(const Filter& other)
|
||||
|
@ -894,7 +894,9 @@ struct DivInstrumentSID3
|
|||
output_volume(0),
|
||||
distortion_level(0),
|
||||
mode(0),
|
||||
enabled(false) {}
|
||||
enabled(false),
|
||||
init(false),
|
||||
filter_matrix(0) {}
|
||||
} filt[4];
|
||||
|
||||
bool operator==(const DivInstrumentSID3& other);
|
||||
|
@ -912,8 +914,11 @@ struct DivInstrumentSID3
|
|||
sync_source(0),
|
||||
specialWaveOn(false),
|
||||
oneBitNoise(false),
|
||||
special_wave(0),
|
||||
filter_matrix(0) {}
|
||||
special_wave(0)
|
||||
{
|
||||
filt[0].mode = 16 | 32; //default settings so filter just works, connect to input and channel output
|
||||
filt[0].output_volume = 0xff;
|
||||
}
|
||||
};
|
||||
|
||||
struct DivInstrument {
|
||||
|
|
|
@ -78,7 +78,7 @@ void DivPlatformSID3::acquire(short** buf, size_t len)
|
|||
if (!writes.empty())
|
||||
{
|
||||
QueuedWrite w=writes.front();
|
||||
sid3_write(sid3, w.addr,w.val);
|
||||
sid3_write(sid3, w.addr, w.val);
|
||||
regPool[w.addr % SID3_NUM_REGISTERS]=w.val;
|
||||
writes.pop();
|
||||
}
|
||||
|
@ -112,11 +112,27 @@ void DivPlatformSID3::updateFlags(int channel, bool gate)
|
|||
(chan[channel].oneBitNoise ? SID3_CHAN_1_BIT_NOISE : 0));
|
||||
}
|
||||
|
||||
void DivPlatformSID3::updateFilter(int channel)
|
||||
void DivPlatformSID3::updateFilter(int channel, int filter)
|
||||
{
|
||||
//rWrite(0x15 + 3 * channel,(chan[channel].filtCut&15) | ((chan[channel].filtControl & 7) << 4) | (chan[channel].filter << 7));
|
||||
//rWrite(0x16 + 3 * channel,(chan[channel].filtCut >> 4));
|
||||
//rWrite(0x17 + 3 * channel,chan[channel].filtRes);
|
||||
rWrite(SID3_REGISTER_FILT_MODE + filter * SID3_REGISTERS_PER_FILTER + channel*SID3_REGISTERS_PER_CHANNEL,
|
||||
chan[channel].filt[filter].mode | (chan[channel].filt[filter].enabled ? SID3_FILTER_ENABLE : 0));
|
||||
|
||||
rWrite(SID3_REGISTER_FILT_CUTOFF_HIGH + filter * SID3_REGISTERS_PER_FILTER + channel*SID3_REGISTERS_PER_CHANNEL,
|
||||
chan[channel].filt[filter].cutoff >> 8);
|
||||
rWrite(SID3_REGISTER_FILT_CUTOFF_LOW + filter * SID3_REGISTERS_PER_FILTER + channel*SID3_REGISTERS_PER_CHANNEL,
|
||||
chan[channel].filt[filter].cutoff & 0xff);
|
||||
|
||||
rWrite(SID3_REGISTER_FILT_RESONANCE + filter * SID3_REGISTERS_PER_FILTER + channel*SID3_REGISTERS_PER_CHANNEL,
|
||||
chan[channel].filt[filter].resonance);
|
||||
|
||||
rWrite(SID3_REGISTER_FILT_DISTORTION + filter * SID3_REGISTERS_PER_FILTER + channel*SID3_REGISTERS_PER_CHANNEL,
|
||||
chan[channel].filt[filter].distortion_level);
|
||||
|
||||
rWrite(SID3_REGISTER_FILT_CONNECTION + filter * SID3_REGISTERS_PER_FILTER + channel*SID3_REGISTERS_PER_CHANNEL,
|
||||
chan[channel].filt[filter].filter_matrix);
|
||||
|
||||
rWrite(SID3_REGISTER_FILT_OUTPUT_VOLUME + filter * SID3_REGISTERS_PER_FILTER + channel*SID3_REGISTERS_PER_CHANNEL,
|
||||
chan[channel].filt[filter].output_volume);
|
||||
}
|
||||
|
||||
void DivPlatformSID3::updateFreq(int channel)
|
||||
|
@ -252,6 +268,21 @@ int DivPlatformSID3::dispatch(DivCommand c) {
|
|||
|
||||
chan[c.chan].ringSrc = ins->sid3.ring_mod_source;
|
||||
chan[c.chan].syncSrc = ins->sid3.sync_source;
|
||||
|
||||
for(int j = 0; j < SID3_NUM_FILTERS; j++)
|
||||
{
|
||||
if(ins->sid3.filt[j].init)
|
||||
{
|
||||
chan[c.chan].filt[j].cutoff = ins->sid3.filt[j].cutoff;
|
||||
chan[c.chan].filt[j].resonance = ins->sid3.filt[j].resonance;
|
||||
chan[c.chan].filt[j].distortion_level = ins->sid3.filt[j].distortion_level;
|
||||
chan[c.chan].filt[j].enabled = ins->sid3.filt[j].enabled;
|
||||
chan[c.chan].filt[j].filter_matrix = ins->sid3.filt[j].filter_matrix;
|
||||
chan[c.chan].filt[j].mode = ins->sid3.filt[j].mode;
|
||||
chan[c.chan].filt[j].output_volume = ins->sid3.filt[j].output_volume;
|
||||
updateFilter(c.chan, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[c.chan].insChanged || chan[c.chan].resetFilter) {
|
||||
/*chan[c.chan].filter=ins->c64.toFilter;
|
||||
|
@ -377,7 +408,7 @@ void DivPlatformSID3::forceIns() {
|
|||
chan[i].keyOn=true;
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
updateFilter(i);
|
||||
//updateFilter(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -438,13 +469,11 @@ void DivPlatformSID3::reset() {
|
|||
chan[i].std.setEngine(parent);
|
||||
chan[i].vol = SID3_MAX_VOL;
|
||||
|
||||
/*chan[i].filtControl = 7;
|
||||
chan[i].filtRes = 0;
|
||||
chan[i].filtCut = 4095;
|
||||
|
||||
chan[i].noise_mode = 0;*/
|
||||
|
||||
//rWrite(0x3 + 7 * i,0xf0);
|
||||
for(int j = 0; j < SID3_NUM_FILTERS; j++)
|
||||
{
|
||||
chan[i].filt[j].enabled = false;
|
||||
updateFilter(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
sid3_reset(sid3);
|
||||
|
|
|
@ -36,6 +36,27 @@ class DivPlatformSID3: public DivDispatch {
|
|||
unsigned char mix_mode;
|
||||
unsigned char ringSrc, syncSrc, phaseSrc;
|
||||
int filtCut;
|
||||
|
||||
struct Filter
|
||||
{
|
||||
unsigned short cutoff;
|
||||
unsigned char resonance;
|
||||
unsigned char output_volume;
|
||||
unsigned char distortion_level;
|
||||
unsigned char mode;
|
||||
bool enabled;
|
||||
unsigned char filter_matrix;
|
||||
|
||||
Filter():
|
||||
cutoff(0),
|
||||
resonance(0),
|
||||
output_volume(0),
|
||||
distortion_level(0),
|
||||
mode(0),
|
||||
enabled(false),
|
||||
filter_matrix(0) {}
|
||||
} filt[SID3_NUM_FILTERS];
|
||||
|
||||
Channel():
|
||||
SharedChannel<signed short>(SID3_MAX_VOL),
|
||||
prevFreq(0x1ffff),
|
||||
|
@ -69,10 +90,10 @@ class DivPlatformSID3: public DivDispatch {
|
|||
Channel chan[SID3_NUM_CHANNELS];
|
||||
DivDispatchOscBuffer* oscBuf[SID3_NUM_CHANNELS];
|
||||
struct QueuedWrite {
|
||||
unsigned char addr;
|
||||
unsigned short addr;
|
||||
unsigned char val;
|
||||
QueuedWrite(): addr(0), val(0) {}
|
||||
QueuedWrite(unsigned char a, unsigned char v): addr(a), val(v) {}
|
||||
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v) {}
|
||||
};
|
||||
FixedQueue<QueuedWrite,SID3_NUM_REGISTERS * 4> writes;
|
||||
|
||||
|
@ -87,7 +108,7 @@ class DivPlatformSID3: public DivDispatch {
|
|||
friend void putDispatchChan(void*,int,int);
|
||||
|
||||
void updateFlags(int channel, bool gate);
|
||||
void updateFilter(int channel);
|
||||
void updateFilter(int channel, int filter);
|
||||
void updateFreq(int channel);
|
||||
void updateDuty(int channel);
|
||||
void updateEnvelope(int channel);
|
||||
|
|
|
@ -2497,7 +2497,22 @@ int32_t sid3_adsr_output(sid3_channel_adsr* adsr, int32_t input)
|
|||
return (int32_t)((int64_t)input * (int64_t)adsr->envelope_counter / (int64_t)0x7f0000 / (int64_t)8 * (int64_t)adsr->vol / (int64_t)SID3_MAX_VOL); //"/ (int64_t)8" so that there's enough amplitude for all 7 chans!
|
||||
}
|
||||
|
||||
void sid3_write(SID3* sid3, uint8_t address, uint8_t data)
|
||||
void sid3_set_filter_settings(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 / 6.0; // "/ 12.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*16000.0) / 500000.0;
|
||||
filt->w0_ceil_1 = filt->w0 <= w0_max_1 ? filt->w0 : w0_max_1;
|
||||
|
||||
filt->_1024_div_Q = (1.0/(0.707 + 3.0*(float)filt->resonance/(float)0x0ff));
|
||||
}
|
||||
|
||||
void sid3_write(SID3* sid3, uint16_t address, uint8_t data)
|
||||
{
|
||||
SAFETY_HEADER
|
||||
|
||||
|
@ -2725,6 +2740,137 @@ void sid3_write(SID3* sid3, uint8_t address, uint8_t data)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case SID3_REGISTER_FILT_MODE:
|
||||
case SID3_REGISTER_FILT_MODE + 1 * SID3_REGISTERS_PER_FILTER:
|
||||
case SID3_REGISTER_FILT_MODE + 2 * SID3_REGISTERS_PER_FILTER:
|
||||
case SID3_REGISTER_FILT_MODE + 3 * SID3_REGISTERS_PER_FILTER:
|
||||
{
|
||||
uint8_t filter = ((address % SID3_REGISTERS_PER_CHANNEL) - SID3_REGISTER_FILT_MODE) / SID3_REGISTERS_PER_FILTER;
|
||||
|
||||
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;
|
||||
}
|
||||
case SID3_REGISTER_FILT_CUTOFF_HIGH:
|
||||
case SID3_REGISTER_FILT_CUTOFF_HIGH + 1 * SID3_REGISTERS_PER_FILTER:
|
||||
case SID3_REGISTER_FILT_CUTOFF_HIGH + 2 * SID3_REGISTERS_PER_FILTER:
|
||||
case SID3_REGISTER_FILT_CUTOFF_HIGH + 3 * SID3_REGISTERS_PER_FILTER:
|
||||
{
|
||||
uint8_t filter = ((address % SID3_REGISTERS_PER_CHANNEL) - SID3_REGISTER_FILT_MODE) / SID3_REGISTERS_PER_FILTER;
|
||||
|
||||
if(channel != SID3_NUM_CHANNELS - 1)
|
||||
{
|
||||
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]);
|
||||
}
|
||||
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]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SID3_REGISTER_FILT_CUTOFF_LOW:
|
||||
case SID3_REGISTER_FILT_CUTOFF_LOW + 1 * SID3_REGISTERS_PER_FILTER:
|
||||
case SID3_REGISTER_FILT_CUTOFF_LOW + 2 * SID3_REGISTERS_PER_FILTER:
|
||||
case SID3_REGISTER_FILT_CUTOFF_LOW + 3 * SID3_REGISTERS_PER_FILTER:
|
||||
{
|
||||
uint8_t filter = ((address % SID3_REGISTERS_PER_CHANNEL) - SID3_REGISTER_FILT_MODE) / SID3_REGISTERS_PER_FILTER;
|
||||
|
||||
if(channel != SID3_NUM_CHANNELS - 1)
|
||||
{
|
||||
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]);
|
||||
}
|
||||
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]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SID3_REGISTER_FILT_RESONANCE:
|
||||
case SID3_REGISTER_FILT_RESONANCE + 1 * SID3_REGISTERS_PER_FILTER:
|
||||
case SID3_REGISTER_FILT_RESONANCE + 2 * SID3_REGISTERS_PER_FILTER:
|
||||
case SID3_REGISTER_FILT_RESONANCE + 3 * SID3_REGISTERS_PER_FILTER:
|
||||
{
|
||||
uint8_t filter = ((address % SID3_REGISTERS_PER_CHANNEL) - SID3_REGISTER_FILT_MODE) / SID3_REGISTERS_PER_FILTER;
|
||||
|
||||
if(channel != SID3_NUM_CHANNELS - 1)
|
||||
{
|
||||
sid3->chan[channel].filt.filt[filter].resonance = data;
|
||||
sid3_set_filter_settings(&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]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SID3_REGISTER_FILT_DISTORTION:
|
||||
case SID3_REGISTER_FILT_DISTORTION + 1 * SID3_REGISTERS_PER_FILTER:
|
||||
case SID3_REGISTER_FILT_DISTORTION + 2 * SID3_REGISTERS_PER_FILTER:
|
||||
case SID3_REGISTER_FILT_DISTORTION + 3 * SID3_REGISTERS_PER_FILTER:
|
||||
{
|
||||
uint8_t filter = ((address % SID3_REGISTERS_PER_CHANNEL) - SID3_REGISTER_FILT_MODE) / SID3_REGISTERS_PER_FILTER;
|
||||
|
||||
if(channel != SID3_NUM_CHANNELS - 1)
|
||||
{
|
||||
sid3->chan[channel].filt.filt[filter].distortion_level = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
sid3->wave_chan.filt.filt[filter].distortion_level = data;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SID3_REGISTER_FILT_CONNECTION:
|
||||
case SID3_REGISTER_FILT_CONNECTION + 1 * SID3_REGISTERS_PER_FILTER:
|
||||
case SID3_REGISTER_FILT_CONNECTION + 2 * SID3_REGISTERS_PER_FILTER:
|
||||
case SID3_REGISTER_FILT_CONNECTION + 3 * SID3_REGISTERS_PER_FILTER:
|
||||
{
|
||||
uint8_t filter = ((address % SID3_REGISTERS_PER_CHANNEL) - SID3_REGISTER_FILT_MODE) / SID3_REGISTERS_PER_FILTER;
|
||||
|
||||
if(channel != SID3_NUM_CHANNELS - 1)
|
||||
{
|
||||
sid3->chan[channel].filt.connection_matrix[filter] = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
sid3->wave_chan.filt.connection_matrix[filter] = data;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SID3_REGISTER_FILT_OUTPUT_VOLUME:
|
||||
case SID3_REGISTER_FILT_OUTPUT_VOLUME + 1 * SID3_REGISTERS_PER_FILTER:
|
||||
case SID3_REGISTER_FILT_OUTPUT_VOLUME + 2 * SID3_REGISTERS_PER_FILTER:
|
||||
case SID3_REGISTER_FILT_OUTPUT_VOLUME + 3 * SID3_REGISTERS_PER_FILTER:
|
||||
{
|
||||
uint8_t filter = ((address % SID3_REGISTERS_PER_CHANNEL) - SID3_REGISTER_FILT_MODE) / SID3_REGISTERS_PER_FILTER;
|
||||
|
||||
if(channel != SID3_NUM_CHANNELS - 1)
|
||||
{
|
||||
sid3->chan[channel].filt.filt[filter].output_volume = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
sid3->wave_chan.filt.filt[filter].output_volume = data;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
@ -3016,6 +3162,90 @@ int32_t sid3_get_waveform(SID3* sid3, sid3_channel* ch)
|
|||
return wave;
|
||||
}
|
||||
|
||||
int32_t sid3_process_filters_block(sid3_channel* ch)
|
||||
{
|
||||
int32_t output = 0;
|
||||
|
||||
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 = (ch->filt.filt[i].Vbp * ch->filt.filt[i]._1024_div_Q) - ch->filt.filt[i].Vlp - Vi;
|
||||
|
||||
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
|
||||
|
@ -3066,10 +3296,25 @@ void sid3_clock(SID3* sid3)
|
|||
}
|
||||
|
||||
sid3_adsr_clock(&ch->adsr);
|
||||
sid3->output_l += sid3_adsr_output(&ch->adsr, waveform);
|
||||
sid3->output_r += sid3_adsr_output(&ch->adsr, waveform);
|
||||
|
||||
sid3->channel_output[i] = sid3_adsr_output(&ch->adsr, waveform);
|
||||
ch->output_before_filter = sid3_adsr_output(&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);
|
||||
}
|
||||
else
|
||||
{
|
||||
output = ch->output_before_filter;
|
||||
}
|
||||
|
||||
sid3->output_l += output;
|
||||
sid3->output_r += output;
|
||||
|
||||
sid3->channel_output[i] = output;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ extern "C" {
|
|||
#define SID3_NUM_CHANNELS 7
|
||||
#define SID3_NUM_FILTERS 4
|
||||
#define SID3_REGISTERS_PER_CHANNEL 64
|
||||
#define SID3_REGISTERS_PER_FILTER 8
|
||||
#define SID3_NUM_REGISTERS (SID3_NUM_CHANNELS * SID3_REGISTERS_PER_CHANNEL)
|
||||
#define SID3_MAX_VOL 255
|
||||
|
||||
|
@ -57,6 +58,19 @@ enum Mixmodes
|
|||
SID3_MIX_SUM = 4,
|
||||
};
|
||||
|
||||
enum Filter_modes
|
||||
{
|
||||
SID3_FILTER_LP = 1,
|
||||
SID3_FILTER_HP = 2,
|
||||
SID3_FILTER_BP = 4,
|
||||
|
||||
SID3_FILTER_MODES_MASK = 7,
|
||||
|
||||
SID3_FILTER_ENABLE = 8,
|
||||
SID3_FILTER_CHANNEL_INPUT = 16, //add channel input to filter input
|
||||
SID3_FILTER_OUTPUT = 32, //output sound from this filter to channel output
|
||||
};
|
||||
|
||||
enum Registers
|
||||
{
|
||||
SID3_REGISTER_FLAGS = 0,
|
||||
|
@ -84,6 +98,15 @@ enum Registers
|
|||
|
||||
SID3_REGISTER_RING_MOD_SRC = 15,
|
||||
SID3_REGISTER_SYNC_SRC = 16,
|
||||
|
||||
SID3_REGISTER_FILT_BASE = 17,
|
||||
SID3_REGISTER_FILT_MODE = 17,
|
||||
SID3_REGISTER_FILT_CUTOFF_HIGH = 18,
|
||||
SID3_REGISTER_FILT_CUTOFF_LOW = 19,
|
||||
SID3_REGISTER_FILT_RESONANCE = 20,
|
||||
SID3_REGISTER_FILT_DISTORTION = 21,
|
||||
SID3_REGISTER_FILT_CONNECTION = 22,
|
||||
SID3_REGISTER_FILT_OUTPUT_VOLUME = 23,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
@ -107,14 +130,12 @@ typedef struct
|
|||
uint8_t mode;
|
||||
|
||||
uint8_t output_volume;
|
||||
|
||||
bool channel_output; //output to the channel master output
|
||||
} sid3_filter;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
sid3_filter filt[SID3_NUM_FILTERS];
|
||||
uint32_t connection_matrix;
|
||||
uint8_t connection_matrix[SID3_NUM_FILTERS];
|
||||
} sid3_filters_block;
|
||||
|
||||
typedef struct
|
||||
|
@ -158,6 +179,8 @@ typedef struct
|
|||
|
||||
uint8_t panning_left, panning_right;
|
||||
bool invert_left, invert_right; //invert channel signal
|
||||
|
||||
int32_t output_before_filter;
|
||||
} sid3_channel;
|
||||
|
||||
typedef struct
|
||||
|
@ -184,6 +207,8 @@ typedef struct
|
|||
|
||||
uint8_t panning_left, panning_right;
|
||||
bool invert_left, invert_right; //invert channel signal
|
||||
|
||||
int32_t output_before_filter;
|
||||
} sid3_wavetable_chan;
|
||||
|
||||
typedef struct
|
||||
|
@ -204,7 +229,7 @@ typedef struct
|
|||
|
||||
SID3* sid3_create();
|
||||
void sid3_reset(SID3* sid3);
|
||||
void sid3_write(SID3* sid3, uint8_t address, uint8_t data);
|
||||
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_free(SID3* sid3);
|
||||
|
|
|
@ -5631,19 +5631,19 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
|
|||
ins->c64.ringMod=ringMod;
|
||||
}
|
||||
|
||||
char buffer[20];
|
||||
char buffer[40];
|
||||
|
||||
if(ins->sid3.ring_mod_source == SID3_NUM_CHANNELS)
|
||||
{
|
||||
snprintf(buffer, 20, _("Self"));
|
||||
snprintf(buffer, 40, _("Self"));
|
||||
}
|
||||
else if(ins->sid3.ring_mod_source == SID3_NUM_CHANNELS - 1)
|
||||
{
|
||||
snprintf(buffer, 20, _("PCM channel"));
|
||||
snprintf(buffer, 40, _("PCM channel"));
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(buffer, 20, "%d", ins->sid3.ring_mod_source + 1);
|
||||
snprintf(buffer, 40, "%d", ins->sid3.ring_mod_source + 1);
|
||||
}
|
||||
|
||||
P(CWSliderScalar(_("Ring mod source channel"),ImGuiDataType_U8,&ins->sid3.ring_mod_source,&_ZERO,&_SID3_NUM_CHANNELS,buffer));
|
||||
|
@ -5653,7 +5653,7 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
|
|||
ins->c64.oscSync=oscSync;
|
||||
}
|
||||
|
||||
snprintf(buffer, 20, "%d", ins->sid3.sync_source + 1);
|
||||
snprintf(buffer, 40, "%d", ins->sid3.sync_source + 1);
|
||||
P(CWSliderScalar(_("Sync source channel"),ImGuiDataType_U8,&ins->sid3.sync_source,&_ZERO,&_SID3_NUM_CHANNELS_MINUS_ONE));
|
||||
|
||||
bool phaseMod=ins->sid3.phase_mod;
|
||||
|
@ -5661,6 +5661,77 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
|
|||
ins->sid3.phase_mod=phaseMod;
|
||||
}
|
||||
|
||||
for(int i = 0; i < SID3_NUM_FILTERS; i++)
|
||||
{
|
||||
DivInstrumentSID3::Filter* filt = &ins->sid3.filt[i];
|
||||
|
||||
bool enable=filt->enabled;
|
||||
snprintf(buffer, 40, _("Enable filter %d"), i + 1);
|
||||
if (ImGui::Checkbox(buffer,&enable)) { PARAMETER
|
||||
filt->enabled=enable;
|
||||
}
|
||||
|
||||
if(filt->enabled)
|
||||
{
|
||||
bool init=filt->init;
|
||||
snprintf(buffer, 40, _("Initialize filter %d"), i + 1);
|
||||
if (ImGui::Checkbox(buffer,&init)) { PARAMETER
|
||||
filt->init=init;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
snprintf(buffer, 40, _("Connect to channel input##contoinput%d"), i + 1);
|
||||
bool toInput=filt->mode & SID3_FILTER_CHANNEL_INPUT;
|
||||
if (ImGui::Checkbox(buffer,&toInput)) { PARAMETER
|
||||
filt->mode ^= SID3_FILTER_CHANNEL_INPUT;
|
||||
}
|
||||
|
||||
snprintf(buffer, 40, _("Cutoff##fcut%d"), i + 1);
|
||||
P(CWSliderScalar(buffer,ImGuiDataType_U16,&filt->cutoff,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable
|
||||
snprintf(buffer, 40, _("Resonance##fres%d"), i + 1);
|
||||
P(CWSliderScalar(buffer,ImGuiDataType_U8,&filt->resonance,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable
|
||||
snprintf(buffer, 40, _("Output volume##foutvol%d"), i + 1);
|
||||
P(CWSliderScalar(buffer,ImGuiDataType_U8,&filt->output_volume,&_ZERO,&_TWO_HUNDRED_FIFTY_FIVE)); rightClickable
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text(_("Filter Mode"));
|
||||
ImGui::SameLine();
|
||||
|
||||
bool lp=filt->mode & SID3_FILTER_LP;
|
||||
pushToggleColors(lp);
|
||||
snprintf(buffer, 40, _("low##flow%d"), i + 1);
|
||||
if (ImGui::Button(buffer)) { PARAMETER
|
||||
filt->mode ^= SID3_FILTER_LP;
|
||||
}
|
||||
popToggleColors();
|
||||
ImGui::SameLine();
|
||||
|
||||
bool bp=filt->mode & SID3_FILTER_BP;
|
||||
pushToggleColors(bp);
|
||||
snprintf(buffer, 40, _("band##fband%d"), i + 1);
|
||||
if (ImGui::Button(buffer)) { PARAMETER
|
||||
filt->mode ^= SID3_FILTER_BP;
|
||||
}
|
||||
popToggleColors();
|
||||
ImGui::SameLine();
|
||||
|
||||
bool hp=filt->mode & SID3_FILTER_HP;
|
||||
pushToggleColors(hp);
|
||||
snprintf(buffer, 40, _("high##fhigh%d"), i + 1);
|
||||
if (ImGui::Button(buffer)) { PARAMETER
|
||||
filt->mode ^= SID3_FILTER_HP;
|
||||
}
|
||||
popToggleColors();
|
||||
|
||||
|
||||
ImGui::SameLine();
|
||||
snprintf(buffer, 40, _("Connect to channel output##contooutput%d"), i + 1);
|
||||
bool toOutput=filt->mode & SID3_FILTER_OUTPUT;
|
||||
if (ImGui::Checkbox(buffer,&toOutput)) { PARAMETER
|
||||
filt->mode ^= SID3_FILTER_OUTPUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue