mirror of
https://github.com/tildearrow/furnace.git
synced 2024-12-02 09:17:26 +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(specialWaveOn) &&
|
||||||
_C(oneBitNoise) &&
|
_C(oneBitNoise) &&
|
||||||
_C(special_wave) &&
|
_C(special_wave) &&
|
||||||
_C(filter_matrix) &&
|
|
||||||
_C(filt[0]) &&
|
_C(filt[0]) &&
|
||||||
_C(filt[1]) &&
|
_C(filt[1]) &&
|
||||||
_C(filt[2]) &&
|
_C(filt[2]) &&
|
||||||
|
@ -281,7 +280,9 @@ bool DivInstrumentSID3::Filter::operator==(const DivInstrumentSID3::Filter& othe
|
||||||
_C(output_volume) &&
|
_C(output_volume) &&
|
||||||
_C(distortion_level) &&
|
_C(distortion_level) &&
|
||||||
_C(mode) &&
|
_C(mode) &&
|
||||||
_C(enabled)
|
_C(enabled) &&
|
||||||
|
_C(init) &&
|
||||||
|
_C(filter_matrix)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -872,8 +872,6 @@ struct DivInstrumentSID3
|
||||||
bool oneBitNoise;
|
bool oneBitNoise;
|
||||||
unsigned char special_wave;
|
unsigned char special_wave;
|
||||||
|
|
||||||
unsigned int filter_matrix;
|
|
||||||
|
|
||||||
struct Filter
|
struct Filter
|
||||||
{
|
{
|
||||||
unsigned short cutoff;
|
unsigned short cutoff;
|
||||||
|
@ -882,6 +880,8 @@ struct DivInstrumentSID3
|
||||||
unsigned char distortion_level;
|
unsigned char distortion_level;
|
||||||
unsigned char mode;
|
unsigned char mode;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
|
bool init;
|
||||||
|
unsigned char filter_matrix;
|
||||||
|
|
||||||
bool operator==(const Filter& other);
|
bool operator==(const Filter& other);
|
||||||
bool operator!=(const Filter& other)
|
bool operator!=(const Filter& other)
|
||||||
|
@ -894,7 +894,9 @@ struct DivInstrumentSID3
|
||||||
output_volume(0),
|
output_volume(0),
|
||||||
distortion_level(0),
|
distortion_level(0),
|
||||||
mode(0),
|
mode(0),
|
||||||
enabled(false) {}
|
enabled(false),
|
||||||
|
init(false),
|
||||||
|
filter_matrix(0) {}
|
||||||
} filt[4];
|
} filt[4];
|
||||||
|
|
||||||
bool operator==(const DivInstrumentSID3& other);
|
bool operator==(const DivInstrumentSID3& other);
|
||||||
|
@ -912,8 +914,11 @@ struct DivInstrumentSID3
|
||||||
sync_source(0),
|
sync_source(0),
|
||||||
specialWaveOn(false),
|
specialWaveOn(false),
|
||||||
oneBitNoise(false),
|
oneBitNoise(false),
|
||||||
special_wave(0),
|
special_wave(0)
|
||||||
filter_matrix(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 {
|
struct DivInstrument {
|
||||||
|
|
|
@ -78,7 +78,7 @@ void DivPlatformSID3::acquire(short** buf, size_t len)
|
||||||
if (!writes.empty())
|
if (!writes.empty())
|
||||||
{
|
{
|
||||||
QueuedWrite w=writes.front();
|
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;
|
regPool[w.addr % SID3_NUM_REGISTERS]=w.val;
|
||||||
writes.pop();
|
writes.pop();
|
||||||
}
|
}
|
||||||
|
@ -112,11 +112,27 @@ void DivPlatformSID3::updateFlags(int channel, bool gate)
|
||||||
(chan[channel].oneBitNoise ? SID3_CHAN_1_BIT_NOISE : 0));
|
(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(SID3_REGISTER_FILT_MODE + filter * SID3_REGISTERS_PER_FILTER + channel*SID3_REGISTERS_PER_CHANNEL,
|
||||||
//rWrite(0x16 + 3 * channel,(chan[channel].filtCut >> 4));
|
chan[channel].filt[filter].mode | (chan[channel].filt[filter].enabled ? SID3_FILTER_ENABLE : 0));
|
||||||
//rWrite(0x17 + 3 * channel,chan[channel].filtRes);
|
|
||||||
|
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)
|
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].ringSrc = ins->sid3.ring_mod_source;
|
||||||
chan[c.chan].syncSrc = ins->sid3.sync_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) {
|
if (chan[c.chan].insChanged || chan[c.chan].resetFilter) {
|
||||||
/*chan[c.chan].filter=ins->c64.toFilter;
|
/*chan[c.chan].filter=ins->c64.toFilter;
|
||||||
|
@ -377,7 +408,7 @@ void DivPlatformSID3::forceIns() {
|
||||||
chan[i].keyOn=true;
|
chan[i].keyOn=true;
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
updateFilter(i);
|
//updateFilter(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,13 +469,11 @@ void DivPlatformSID3::reset() {
|
||||||
chan[i].std.setEngine(parent);
|
chan[i].std.setEngine(parent);
|
||||||
chan[i].vol = SID3_MAX_VOL;
|
chan[i].vol = SID3_MAX_VOL;
|
||||||
|
|
||||||
/*chan[i].filtControl = 7;
|
for(int j = 0; j < SID3_NUM_FILTERS; j++)
|
||||||
chan[i].filtRes = 0;
|
{
|
||||||
chan[i].filtCut = 4095;
|
chan[i].filt[j].enabled = false;
|
||||||
|
updateFilter(i, j);
|
||||||
chan[i].noise_mode = 0;*/
|
}
|
||||||
|
|
||||||
//rWrite(0x3 + 7 * i,0xf0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sid3_reset(sid3);
|
sid3_reset(sid3);
|
||||||
|
|
|
@ -36,6 +36,27 @@ class DivPlatformSID3: public DivDispatch {
|
||||||
unsigned char mix_mode;
|
unsigned char mix_mode;
|
||||||
unsigned char ringSrc, syncSrc, phaseSrc;
|
unsigned char ringSrc, syncSrc, phaseSrc;
|
||||||
int filtCut;
|
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():
|
Channel():
|
||||||
SharedChannel<signed short>(SID3_MAX_VOL),
|
SharedChannel<signed short>(SID3_MAX_VOL),
|
||||||
prevFreq(0x1ffff),
|
prevFreq(0x1ffff),
|
||||||
|
@ -69,10 +90,10 @@ class DivPlatformSID3: public DivDispatch {
|
||||||
Channel chan[SID3_NUM_CHANNELS];
|
Channel chan[SID3_NUM_CHANNELS];
|
||||||
DivDispatchOscBuffer* oscBuf[SID3_NUM_CHANNELS];
|
DivDispatchOscBuffer* oscBuf[SID3_NUM_CHANNELS];
|
||||||
struct QueuedWrite {
|
struct QueuedWrite {
|
||||||
unsigned char addr;
|
unsigned short addr;
|
||||||
unsigned char val;
|
unsigned char val;
|
||||||
QueuedWrite(): addr(0), val(0) {}
|
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;
|
FixedQueue<QueuedWrite,SID3_NUM_REGISTERS * 4> writes;
|
||||||
|
|
||||||
|
@ -87,7 +108,7 @@ class DivPlatformSID3: public DivDispatch {
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
void updateFlags(int channel, bool gate);
|
void updateFlags(int channel, bool gate);
|
||||||
void updateFilter(int channel);
|
void updateFilter(int channel, int filter);
|
||||||
void updateFreq(int channel);
|
void updateFreq(int channel);
|
||||||
void updateDuty(int channel);
|
void updateDuty(int channel);
|
||||||
void updateEnvelope(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!
|
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
|
SAFETY_HEADER
|
||||||
|
|
||||||
|
@ -2725,6 +2740,137 @@ void sid3_write(SID3* sid3, uint8_t address, uint8_t data)
|
||||||
}
|
}
|
||||||
break;
|
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;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3016,6 +3162,90 @@ int32_t sid3_get_waveform(SID3* sid3, sid3_channel* ch)
|
||||||
return wave;
|
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)
|
void sid3_clock(SID3* sid3)
|
||||||
{
|
{
|
||||||
//SAFETY_HEADER
|
//SAFETY_HEADER
|
||||||
|
@ -3066,10 +3296,25 @@ void sid3_clock(SID3* sid3)
|
||||||
}
|
}
|
||||||
|
|
||||||
sid3_adsr_clock(&ch->adsr);
|
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_CHANNELS 7
|
||||||
#define SID3_NUM_FILTERS 4
|
#define SID3_NUM_FILTERS 4
|
||||||
#define SID3_REGISTERS_PER_CHANNEL 64
|
#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_NUM_REGISTERS (SID3_NUM_CHANNELS * SID3_REGISTERS_PER_CHANNEL)
|
||||||
#define SID3_MAX_VOL 255
|
#define SID3_MAX_VOL 255
|
||||||
|
|
||||||
|
@ -57,6 +58,19 @@ enum Mixmodes
|
||||||
SID3_MIX_SUM = 4,
|
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
|
enum Registers
|
||||||
{
|
{
|
||||||
SID3_REGISTER_FLAGS = 0,
|
SID3_REGISTER_FLAGS = 0,
|
||||||
|
@ -84,6 +98,15 @@ enum Registers
|
||||||
|
|
||||||
SID3_REGISTER_RING_MOD_SRC = 15,
|
SID3_REGISTER_RING_MOD_SRC = 15,
|
||||||
SID3_REGISTER_SYNC_SRC = 16,
|
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
|
typedef struct
|
||||||
|
@ -107,14 +130,12 @@ typedef struct
|
||||||
uint8_t mode;
|
uint8_t mode;
|
||||||
|
|
||||||
uint8_t output_volume;
|
uint8_t output_volume;
|
||||||
|
|
||||||
bool channel_output; //output to the channel master output
|
|
||||||
} sid3_filter;
|
} sid3_filter;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
sid3_filter filt[SID3_NUM_FILTERS];
|
sid3_filter filt[SID3_NUM_FILTERS];
|
||||||
uint32_t connection_matrix;
|
uint8_t connection_matrix[SID3_NUM_FILTERS];
|
||||||
} sid3_filters_block;
|
} sid3_filters_block;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -158,6 +179,8 @@ typedef struct
|
||||||
|
|
||||||
uint8_t panning_left, panning_right;
|
uint8_t panning_left, panning_right;
|
||||||
bool invert_left, invert_right; //invert channel signal
|
bool invert_left, invert_right; //invert channel signal
|
||||||
|
|
||||||
|
int32_t output_before_filter;
|
||||||
} sid3_channel;
|
} sid3_channel;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -184,6 +207,8 @@ typedef struct
|
||||||
|
|
||||||
uint8_t panning_left, panning_right;
|
uint8_t panning_left, panning_right;
|
||||||
bool invert_left, invert_right; //invert channel signal
|
bool invert_left, invert_right; //invert channel signal
|
||||||
|
|
||||||
|
int32_t output_before_filter;
|
||||||
} sid3_wavetable_chan;
|
} sid3_wavetable_chan;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -204,7 +229,7 @@ typedef struct
|
||||||
|
|
||||||
SID3* sid3_create();
|
SID3* sid3_create();
|
||||||
void sid3_reset(SID3* sid3);
|
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_clock(SID3* sid3);
|
||||||
void sid3_set_is_muted(SID3* sid3, uint8_t ch, bool mute);
|
void sid3_set_is_muted(SID3* sid3, uint8_t ch, bool mute);
|
||||||
void sid3_free(SID3* sid3);
|
void sid3_free(SID3* sid3);
|
||||||
|
|
|
@ -5631,19 +5631,19 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
|
||||||
ins->c64.ringMod=ringMod;
|
ins->c64.ringMod=ringMod;
|
||||||
}
|
}
|
||||||
|
|
||||||
char buffer[20];
|
char buffer[40];
|
||||||
|
|
||||||
if(ins->sid3.ring_mod_source == SID3_NUM_CHANNELS)
|
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)
|
else if(ins->sid3.ring_mod_source == SID3_NUM_CHANNELS - 1)
|
||||||
{
|
{
|
||||||
snprintf(buffer, 20, _("PCM channel"));
|
snprintf(buffer, 40, _("PCM channel"));
|
||||||
}
|
}
|
||||||
else
|
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));
|
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;
|
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));
|
P(CWSliderScalar(_("Sync source channel"),ImGuiDataType_U8,&ins->sid3.sync_source,&_ZERO,&_SID3_NUM_CHANNELS_MINUS_ONE));
|
||||||
|
|
||||||
bool phaseMod=ins->sid3.phase_mod;
|
bool phaseMod=ins->sid3.phase_mod;
|
||||||
|
@ -5661,6 +5661,77 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
|
||||||
ins->sid3.phase_mod=phaseMod;
|
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();
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue