initial filters functionality (without connection matrix control yet!)

This commit is contained in:
LTVA1 2024-08-02 14:18:13 +03:00
parent 1a67453b99
commit 441e3e0b56
7 changed files with 433 additions and 36 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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