frac32buffer filter input
frac32buffer in2
frac32 center
frac32 width
frac32 reso1
frac32 reso2
charptr32 filename
int32 preset
bool32 save table
bool32 load table
frac32buffer filter output
int32.mini mute or sends input 1 to filter 1 positively or inverted
int32.mini mute or sends input 2 to filter 1 positively or inverted
int32.mini use (inverted) lowpass of filter 1
int32.mini use (inverted) highpass of filter 1
int32.mini use (inverted) bandpass of filter 1
int32.mini use (inverted) notch of filter 1
int32.mini mix input 1 to filter 1 output (when opposite values are used for input/output mix, filter response is inverted for that channel)
int32.mini mix input 2 to filter 1 output (when opposite values are used for input/output mix, filter response is inverted for that channel)
int32.mini mute or sends input 1 to filter 2 input positively or inverted
int32.mini mute or sends input 2 to filter 2 input positively or inverted
int32.mini mute or sends mixed output of filter1 to filter 2 input positively or inverted
int32.mini mute or sends lowpass output of filter 1 to filter 2 input positively or inverted
int32.mini mute or sends highpass output of filter 1 to filter 2 input positively or inverted
int32.mini mute or sends bandpass output of filter 1 to filter 2 input positively or inverted
int32.mini mute or sends notch output of filter 1 to filter 2 input positively or inverted
int32.mini use (inverted) lowpass of filter 2
int32.mini use (inverted) highpass of filter 2
int32.mini use (inverted) bandpass of filter 2
int32.mini use (inverted) notch of filter 2
int32.mini mix input of filter 2 to filter 1 output (when opposite values are used for input/output mix, filter response is inverted for that channel)
int32.mini mix input 1 to filter 2 output (when opposite values are used for input/output mix, filter response is inverted for that channel)
int32.mini mix input 2 to filter 2 output (when opposite values are used for input/output mix, filter response is inverted for that channel)
int32.mini mix the mix of filter 1 to filter 1 output (when opposite values are used for input/output mix, filter response is inverted for that channel)
int32.mini mute or sends mixed output of filter 1 to the module's output positively or inverted
int32.mini mute or sends mixed output of filter 2 to the module's output positively or inverted
bool32.mom randomises all the configuration controls
int32 read/adjust preset in table
frac32.s.map.pitch sets the center frequency of the filter. Both filters' cutoff will be at either side of this frequency, depending on the "width" knob
frac32.s.map.pitch sets the offset frequency for both filters from center position (filter 1 responds inversely from filter 2)
frac32.u.map.filterq resonance amount of filter 1
frac32.u.map.filterq resonance amount of filter 2
bool32.tgl link cutoff frequency of filter 2 to filter 1
bool32.tgl sets filter 2 to on (when off, only filter 1 is used)
int32.hradio below controls are for selecting the inputs for filter 1
int32.hradio below controls are for selecting filter-mode outputs of filter 1 used for the "filter 1 mix"
int32.hradio below controls are for selecting the adding/subtracting the inputs from the filter 1 output to the "filter 1 mix" which can create inverted filter responses
int32.hradio below controls are for selecting the inputs for filter 2
int32.hradio below controls are for selecting filter-mode outputs of filter 2 used for the "filter 2 mix"
int32.hradio below controls are for selecting the adding/subtracting the inputs from the filter 2 output to the "filter 2 mix" which can create inverted filter responses
int32.hradio below controls are for selecting the adding/subtracting the "filter mixes" to the module's output
int32.hradio below controls are for quick-setting the configuration. either by randomisation or saved settings
combo presets
static const uint32_t LENGTHPOW = (attr_presets);
static const uint32_t LENGTH = (1 << attr_presets);
static const uint32_t LENGTHMASK = ((1 << attr_presets) - 1);
int32_t *array;
int ltrig;
int lltrig;
int strig;
int32_t filter[8];
int32_t freq[2];
int32_t Damp[2];
int i;
int rtrig;
// config algo
int32_t config(int32_t pitch, int32_t reso, int Inst) {
int32_t damp = (0x80 << 24) - (reso << 4);
damp = ___SMMUL(damp, damp);
Damp[Inst] = damp;
int32_t alpha;
MTOFEXTENDED(pitch, alpha);
SINE2TINTERP(alpha, freq[Inst]);
}
// filter algo
int32_t SVF(int32_t in, int32_t Freq, int32_t damp, int32_t Inst) {
filter[Inst * 4 + 2] = __SSAT(filter[Inst * 4 + 2], 28);
filter[Inst * 4 + 3] = in - (___SMMUL(damp, filter[Inst * 4 + 2]) << 1);
filter[Inst * 4] =
filter[Inst * 4] + (___SMMUL(Freq, filter[Inst * 4 + 2]) << 1);
filter[Inst * 4 + 1] = filter[Inst * 4 + 3] - filter[Inst * 4];
filter[Inst * 4 + 2] =
(___SMMUL(Freq, filter[Inst * 4 + 1]) << 1) + filter[Inst * 4 + 2];
}
// 0=LP1
// 1=HP1
// 2=BP1
// 3=NO1
// 4=LP2
// 5=HP2
// 6=BP2
// 7=NO2
int32_t prev;
static int32_t _array[LENGTH * 25] __attribute__((section(".sdram")));
array = &_array[0];
for (i = 0; i < (LENGTH * 25); i++) {
array[i] = 0;
}
for (i = 0; i < 8; i++) {
filter[i] = 0;
}
int32_t width = inlet_width + param_width;
config(inlet_center + param_center - (width >> 1),
__USAT(param_reso1 + inlet_reso1, 27), 0);
config(((width >> 1) + inlet_center + param_center) * param_link +
width * (1 - param_link),
__USAT(param_reso2 + inlet_reso2, 27), 1);
int32_t preset = ((inlet_preset + param_preset) & LENGTHMASK) * 25;
if ((inlet_save > 0) && !strig) {
strig = 1;
FIL FileObject;
FRESULT err;
UINT bytes_written;
err = f_open(&FileObject, inlet_filename, FA_WRITE | FA_CREATE_ALWAYS);
if (err != FR_OK) {
report_fatfs_error(err, "inlet_filename");
return;
}
int rem_sz = sizeof(*array) * LENGTH * 25;
int offset = 0;
while (rem_sz > 0) {
if (rem_sz > sizeof(fbuff)) {
memcpy((char *)fbuff, (char *)(&array[0]) + offset, sizeof(fbuff));
err = f_write(&FileObject, fbuff, sizeof(fbuff), &bytes_written);
rem_sz -= sizeof(fbuff);
offset += sizeof(fbuff);
} else {
memcpy((char *)fbuff, (char *)(&array[0]) + offset, rem_sz);
err = f_write(&FileObject, fbuff, rem_sz, &bytes_written);
rem_sz = 0;
}
}
if (err != FR_OK)
report_fatfs_error(err, "inlet_filename");
err = f_close(&FileObject);
if (err != FR_OK)
report_fatfs_error(err, "inlet_filename");
} else if (!(inlet_save > 0))
strig = 0;
if ((inlet_load > 0) && !ltrig) {
ltrig = 1;
FIL FileObject;
FRESULT err;
UINT bytes_read;
err = f_open(&FileObject, inlet_filename, FA_READ | FA_OPEN_EXISTING);
if (err != FR_OK) {
report_fatfs_error(err, inlet_filename);
return;
}
int rem_sz = sizeof(*array) * LENGTH * 25;
int offset = 0;
while (rem_sz > 0) {
if (rem_sz > sizeof(fbuff)) {
err = f_read(&FileObject, fbuff, sizeof(fbuff), &bytes_read);
if (bytes_read == 0)
break;
memcpy((char *)(&array[0]) + offset, (char *)fbuff, bytes_read);
rem_sz -= bytes_read;
offset += bytes_read;
} else {
err = f_read(&FileObject, fbuff, rem_sz, &bytes_read);
memcpy((char *)(&array[0]) + offset, (char *)fbuff, bytes_read);
rem_sz = 0;
}
}
if (err != FR_OK) {
report_fatfs_error(err, inlet_filename);
return;
};
err = f_close(&FileObject);
if (err != FR_OK) {
report_fatfs_error(err, inlet_filename);
return;
};
} else if (!(inlet_load > 0))
ltrig = 0;
if (((!(preset == prev)) || (inlet_load > 0)) && !lltrig) {
lltrig = 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_1to1],
array[0 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_2to1],
array[1 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_LP1],
array[2 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_HP1],
array[3 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_BP1],
array[4 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_NO1],
array[5 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_1mix1],
array[6 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_2mix1],
array[7 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_1to2],
array[8 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_2to2],
array[9 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_mixto2],
array[10 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_LPto2],
array[11 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_HPto2],
array[12 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_BPto2],
array[13 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_NOto2],
array[14 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_LP2],
array[15 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_HP2],
array[16 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_BP2],
array[17 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_NO2],
array[18 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_2IN2],
array[19 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_1mix2],
array[20 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_2mix2],
array[21 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_summix1],
array[22 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_outmix1],
array[23 + preset], 0xFFFD);
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_outmix2],
array[24 + preset], 0xFFFD);
} else if (!((!(preset == prev)) || (inlet_load > 0))) {
lltrig = 0;
}
array[0 + preset] = param_1to1;
array[1 + preset] = param_2to1;
array[2 + preset] = param_LP1;
array[3 + preset] = param_HP1;
array[4 + preset] = param_BP1;
array[5 + preset] = param_NO1;
array[6 + preset] = param_1mix1;
array[7 + preset] = param_2mix1;
array[8 + preset] = param_1to2;
array[9 + preset] = param_2to2;
array[10 + preset] = param_mixto2;
array[11 + preset] = param_LPto2;
array[12 + preset] = param_HPto2;
array[13 + preset] = param_BPto2;
array[14 + preset] = param_NOto2;
array[15 + preset] = param_LP2;
array[16 + preset] = param_HP2;
array[17 + preset] = param_BP2;
array[18 + preset] = param_NO2;
array[19 + preset] = param_2IN2;
array[20 + preset] = param_1mix2;
array[21 + preset] = param_2mix2;
array[22 + preset] = param_summix1;
array[23 + preset] = param_outmix1;
array[24 + preset] = param_outmix2;
prev = preset;
if ((param_rnd > 0) && !rtrig) {
rtrig = 1;
int tmp;
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_1to1], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_2to1], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_LP1], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_HP1], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_BP1], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_NO1], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_1mix1], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_2mix1], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_1to2], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_2to2], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_mixto2], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_LPto2], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_HPto2], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_BPto2], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_NOto2], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_LP2], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_HP2], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_BP2], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_NO2], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_2IN2], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_1mix2], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_2mix2], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_summix1], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = tmp > 0 ? tmp : -tmp;
tmp = tmp - (tmp / 3) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_outmix1], tmp,
0xFFFD);
tmp = (uint32_t)(GenerateRandomNumber());
tmp = (tmp & 1) * 3 - 1;
PExParameterChange(&parent->PExch[PARAM_INDEX_attr_legal_name_outmix2], tmp,
0xFFFD);
} else if (param_rnd == 0) {
rtrig = 0;
}
int32_t IN1;
int32_t IN2;
// input for filter 1
IN1 = inlet_in1 * param_1to1 + inlet_in2 * param_2to1;
// filter1
SVF(IN1, freq[0], Damp[0], 0);
int32_t mix1 = filter[0] * param_LP1 + filter[1] * param_HP1 +
filter[2] * param_BP1 + filter[3] * param_NO1 +
inlet_in1 * param_1mix1 + inlet_in2 * param_2mix1;
// drive
int32_t ts = __SSAT(mix1 >> 2, 28);
int32_t tsq31 = ts << 3;
int32_t tsq31p3 = ___SMMUL(tsq31, ___SMMUL(tsq31, tsq31));
mix1 = ts + (ts >> 1) - (tsq31p3);
int32_t mix2 = 0;
// mute filter2
if (param_ON2 > 0) {
// filter2
IN2 = inlet_in1 * param_1to2 + inlet_in2 * param_2to2 + mix1 * param_mixto2 +
filter[0] * param_LPto2 + filter[1] * param_HPto2 +
filter[2] * param_BPto2 + filter[3] * param_NOto2;
SVF(IN2, freq[1], Damp[1], 1);
mix2 = filter[4] * param_LP2 + filter[5] * param_HP2 + filter[6] * param_BP2 +
filter[7] * param_NO2 + inlet_in1 * param_1mix2 +
inlet_in2 * param_2mix2 + IN2 * param_2IN2 + mix1 * param_summix1;
}
ts = __SSAT(mix2 >> 2, 28);
tsq31 = ts << 3;
tsq31p3 = ___SMMUL(tsq31, ___SMMUL(tsq31, tsq31));
mix2 = ts + (ts >> 1) - (tsq31p3);
int32_t sum = mix1 * param_outmix1 + mix2 * param_outmix2;
ts = __SSAT(sum >> 2, 28);
tsq31 = ts << 3;
tsq31p3 = ___SMMUL(tsq31, ___SMMUL(tsq31, tsq31));
if (ts < 0) {
int32_t tm = ts > 0 ? ts : -ts;
tsq31p3 = ___SMMUL(tm << 3, tsq31) - (ts);
} else {
tsq31p3 -= (ts >> 1);
}
sum = ts - (tsq31p3);
outlet_out = sum;