Exchanged double to float data types in PluginFX.

Removed Teensy filter (is replaced by the Dexed internal filter) and antialias filter.
pull/4/head
Holger Wirtz 6 years ago
parent 5c164ccf27
commit ba84fbc9d6
  1. 34
      MicroDexed.ino
  2. 326
      PluginFx.cpp
  3. 6
      PluginFx.h
  4. 9
      UI.cpp
  5. 1
      UI.h

@ -51,21 +51,14 @@ uint8_t ui_main_state = UI_MAIN_VOICE;
AudioPlayQueue queue1; AudioPlayQueue queue1;
AudioAnalyzePeak peak1; AudioAnalyzePeak peak1;
AudioFilterStateVariable filter1;
AudioEffectDelay delay1; AudioEffectDelay delay1;
AudioMixer4 mixer1; AudioMixer4 mixer1;
AudioMixer4 mixer2; AudioMixer4 mixer2;
AudioFilterBiquad antialias;
AudioConnection patchCord0(queue1, peak1); AudioConnection patchCord0(queue1, peak1);
AudioConnection patchCord1(queue1, antialias); AudioConnection patchCord9(queue1, 0, mixer1, 0);
AudioConnection patchCord2(antialias, 0, filter1, 0);
AudioConnection patchCord3(filter1, 0, delay1, 0);
AudioConnection patchCord4(filter1, 0, mixer1, 0);
AudioConnection patchCord5(filter1, 0, mixer2, 0);
AudioConnection patchCord6(delay1, 0, mixer1, 1); AudioConnection patchCord6(delay1, 0, mixer1, 1);
AudioConnection patchCord7(delay1, 0, mixer2, 2); AudioConnection patchCord7(delay1, 0, mixer2, 2);
AudioConnection patchCord8(mixer1, delay1); AudioConnection patchCord8(mixer1, delay1);
AudioConnection patchCord9(queue1, 0, mixer1, 3); // for disabling the filter
AudioConnection patchCord10(mixer1, 0, mixer2, 1); AudioConnection patchCord10(mixer1, 0, mixer2, 1);
#if defined(TEENSY_AUDIO_BOARD) #if defined(TEENSY_AUDIO_BOARD)
AudioOutputI2S i2s1; AudioOutputI2S i2s1;
@ -225,25 +218,18 @@ void setup()
#endif #endif
// Init effects // Init effects
antialias.setLowpass(0, 6000, 0.707);
filter1.frequency(EXP_FUNC((float)map(effect_filter_frq, 0, ENC_FILTER_FRQ_STEPS, 0, 1024) / 150.0) * 10.0 + 80.0);
//filter1.resonance(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0));
filter1.resonance(EXP_FUNC(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0)) * 0.044 + 0.61);
filter1.octaveControl(mapfloat(effect_filter_octave, 0, ENC_FILTER_OCT_STEPS, 0.0, 7.0));
delay1.delay(0, mapfloat(effect_delay_feedback, 0, ENC_DELAY_TIME_STEPS, 0.0, DELAY_MAX_TIME)); delay1.delay(0, mapfloat(effect_delay_feedback, 0, ENC_DELAY_TIME_STEPS, 0.0, DELAY_MAX_TIME));
// mixer1 is the feedback-adding mixer, mixer2 the whole delay (with/without feedback) mixer // mixer1 is the feedback-adding mixer, mixer2 the whole delay (with/without feedback) mixer
mixer1.gain(0, 1.0); // original signal mixer1.gain(0, 1.0); // original signal
mixer1.gain(1, mapfloat(effect_delay_feedback, 0, ENC_DELAY_FB_STEPS, 0.0, 1.0)); // amount of feedback mixer1.gain(1, mapfloat(effect_delay_feedback, 0, ENC_DELAY_FB_STEPS, 0.0, 1.0)); // amount of feedback
mixer1.gain(0, 0.0); // filtered signal off
mixer1.gain(3, 1.0); // original signal on
mixer2.gain(0, 1.0 - mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // original signal mixer2.gain(0, 1.0 - mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // original signal
mixer2.gain(1, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // delayed signal (including feedback) mixer2.gain(1, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // delayed signal (including feedback)
mixer2.gain(2, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // only delayed signal (without feedback) mixer2.gain(2, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // only delayed signal (without feedback)
// just for testing: // just for testing:
dexed->fx.uiReso = 0.5; dexed->fx.Reso = 0.5;
dexed->fx.uiGain = 0.5; dexed->fx.Gain = 0.5;
dexed->fx.uiCutoff = 0.5; dexed->fx.Cutoff = 0.5;
// load default SYSEX data // load default SYSEX data
load_sysex(configuration.bank, configuration.voice); load_sysex(configuration.bank, configuration.voice);
@ -433,7 +419,7 @@ void handleControlChange(byte inChannel, byte inCtrl, byte inValue)
} }
break; break;
case 102: // CC 102: filter frequency case 102: // CC 102: filter frequency
effect_filter_frq = map(inValue, 0, 127, 0, ENC_FILTER_FRQ_STEPS); /* effect_filter_frq = map(inValue, 0, 127, 0, ENC_FILTER_FRQ_STEPS);
if (effect_filter_frq == ENC_FILTER_FRQ_STEPS) if (effect_filter_frq == ENC_FILTER_FRQ_STEPS)
{ {
// turn "off" filter // turn "off" filter
@ -447,17 +433,17 @@ void handleControlChange(byte inChannel, byte inCtrl, byte inValue)
mixer1.gain(3, 0.0); // original signal off mixer1.gain(3, 0.0); // original signal off
} }
filter1.frequency(EXP_FUNC((float)map(effect_filter_frq, 0, ENC_FILTER_FRQ_STEPS, 0, 1024) / 150.0) * 10.0 + 80.0); filter1.frequency(EXP_FUNC((float)map(effect_filter_frq, 0, ENC_FILTER_FRQ_STEPS, 0, 1024) / 150.0) * 10.0 + 80.0);
handle_ui(); handle_ui(); */
break; break;
case 103: // CC 103: filter resonance case 103: // CC 103: filter resonance
effect_filter_resonance = map(inValue, 0, 127, 0, ENC_FILTER_RES_STEPS); /* effect_filter_resonance = map(inValue, 0, 127, 0, ENC_FILTER_RES_STEPS);
filter1.resonance(EXP_FUNC(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0)) * 0.044 + 0.61); filter1.resonance(EXP_FUNC(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0)) * 0.044 + 0.61);
handle_ui(); handle_ui(); */
break; break;
case 104: // CC 104: filter octave case 104: // CC 104: filter octave
effect_filter_octave = map(inValue, 0, 127, 0, ENC_FILTER_OCT_STEPS); /* effect_filter_octave = map(inValue, 0, 127, 0, ENC_FILTER_OCT_STEPS);
filter1.octaveControl(mapfloat(effect_filter_octave, 0, ENC_FILTER_OCT_STEPS, 0.0, 7.0)); filter1.octaveControl(mapfloat(effect_filter_octave, 0, ENC_FILTER_OCT_STEPS, 0.0, 7.0));
handle_ui(); handle_ui(); */
break; break;
case 105: // CC 105: delay time case 105: // CC 105: delay time
effect_delay_time = map(inValue, 0, 127, 0, ENC_DELAY_TIME_STEPS); effect_delay_time = map(inValue, 0, 127, 0, ENC_DELAY_TIME_STEPS);

@ -1,26 +1,26 @@
/** /**
*
* Copyright (c) 2013-2014 Pascal Gauthier. Copyright (c) 2013-2014 Pascal Gauthier.
* Copyright (c) 2013-2014 Filatov Vadim. Copyright (c) 2013-2014 Filatov Vadim.
*
* Filter taken from the Obxd project : Filter taken from the Obxd project :
* https://github.com/2DaT/Obxd https://github.com/2DaT/Obxd
*
* This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version. (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/ */
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
#include <math.h> #include <math.h>
@ -28,189 +28,189 @@
const float dc = 1e-18; const float dc = 1e-18;
inline static float tptpc(float& state,float inp,float cutoff) { inline static float tptpc(float& state, float inp, float cutoff) {
double v = (inp - state) * cutoff / (1 + cutoff); float v = (inp - state) * cutoff / (1 + cutoff);
double res = v + state; float res = v + state;
state = res + v; state = res + v;
return res; return res;
} }
inline static float tptlpupw(float & state , float inp , float cutoff , float srInv) { inline static float tptlpupw(float & state , float inp , float cutoff , float srInv) {
cutoff = (cutoff * srInv)*M_PI; cutoff = (cutoff * srInv) * M_PI;
double v = (inp - state) * cutoff / (1 + cutoff); float v = (inp - state) * cutoff / (1 + cutoff);
double res = v + state; float res = v + state;
state = res + v; state = res + v;
return res; return res;
} }
//static float linsc(float param,const float min,const float max) { //static float linsc(float param,const float min,const float max) {
// return (param) * (max - min) + min; // return (param) * (max - min) + min;
//} //}
static float logsc(float param, const float min,const float max,const float rolloff = 19.0f) { static float logsc(float param, const float min, const float max, const float rolloff = 19.0f) {
return ((expf(param * logf(rolloff+1)) - 1.0f) / (rolloff)) * (max-min) + min; return ((expf(param * logf(rolloff + 1)) - 1.0f) / (rolloff)) * (max - min) + min;
} }
PluginFx::PluginFx() { PluginFx::PluginFx() {
uiCutoff = 1; Cutoff = 1;
uiReso = 0; Reso = 0;
uiGain = 1; Gain = 1;
} }
void PluginFx::init(int sr) { void PluginFx::init(int sr) {
mm=0; mm = 0;
s1=s2=s3=s4=c=d=0; s1 = s2 = s3 = s4 = c = d = 0;
R24=0; R24 = 0;
mmch = (int)(mm * 3); mmch = (int)(mm * 3);
mmt = mm*3-mmch; mmt = mm * 3 - mmch;
sampleRate = sr; sampleRate = sr;
sampleRateInv = 1/sampleRate; sampleRateInv = 1 / sampleRate;
float rcrate =sqrt((44000/sampleRate)); float rcrate = sqrt((44000 / sampleRate));
rcor24 = (970.0 / 44000)*rcrate; rcor24 = (970.0 / 44000) * rcrate;
rcor24Inv = 1 / rcor24; rcor24Inv = 1 / rcor24;
bright = tan((sampleRate*0.5f-10) * M_PI * sampleRateInv); bright = tanf((sampleRate * 0.5f - 10) * M_PI * sampleRateInv);
R = 1; R = 1;
rcor = (480.0 / 44000)*rcrate; rcor = (480.0 / 44000) * rcrate;
rcorInv = 1 / rcor; rcorInv = 1 / rcor;
bandPassSw = false; bandPassSw = false;
pCutoff = -1; pCutoff = -1;
pReso = -1; pReso = -1;
dc_r = 1.0-(126.0/sr); dc_r = 1.0 - (126.0 / sr);
dc_id = 0; dc_id = 0;
dc_od = 0; dc_od = 0;
} }
inline float PluginFx::NR24(float sample,float g,float lpc) { inline float PluginFx::NR24(float sample, float g, float lpc) {
float ml = 1 / (1+g); float ml = 1 / (1 + g);
float S = (lpc*(lpc*(lpc*s1 + s2) + s3) +s4)*ml; float S = (lpc * (lpc * (lpc * s1 + s2) + s3) + s4) * ml;
float G = lpc*lpc*lpc*lpc; float G = lpc * lpc * lpc * lpc;
float y = (sample - R24 * S) / (1 + R24*G); float y = (sample - R24 * S) / (1 + R24 * G);
return y + 1e-8; return y + 1e-8;
}; };
inline float PluginFx::NR(float sample, float g) { inline float PluginFx::NR(float sample, float g) {
float y = ((sample- R * s1*2 - g*s1 - s2)/(1+ g*(2*R + g))) + dc; float y = ((sample - R * s1 * 2 - g * s1 - s2) / (1 + g * (2 * R + g))) + dc;
return y; return y;
} }
void PluginFx::process(float *work, int sampleSize) { void PluginFx::process(float *work, int sampleSize) {
// very basic DC filter // very basic DC filter
float t_fd = work[0]; float t_fd = work[0];
work[0] = work[0] - dc_id + dc_r * dc_od; work[0] = work[0] - dc_id + dc_r * dc_od;
dc_id = t_fd;
for (int i = 1; i < sampleSize; i++) {
t_fd = work[i];
work[i] = work[i] - dc_id + dc_r * work[i - 1];
dc_id = t_fd; dc_id = t_fd;
for (int i=1; i<sampleSize; i++) {
t_fd = work[i];
work[i] = work[i] - dc_id + dc_r * work[i-1];
dc_id = t_fd;
}
dc_od = work[sampleSize-1];
if ( uiGain != 1 ) {
for(int i=0; i < sampleSize; i++ )
work[i] *= uiGain;
}
// don't apply the LPF if the cutoff is to maximum
if ( uiCutoff == 1 )
return;
if ( uiCutoff != pCutoff || uiReso != pReso ) { }
rReso = (0.991-logsc(1-uiReso,0,0.991)); dc_od = work[sampleSize - 1];
R24 = 3.5 * rReso;
if ( Gain != 1 ) {
float cutoffNorm = logsc(uiCutoff,60,19000); for (int i = 0; i < sampleSize; i++ )
rCutoff = (float)tan(cutoffNorm * sampleRateInv * M_PI); work[i] *= Gain;
}
pCutoff = uiCutoff;
pReso = uiReso; // don't apply the LPF if the cutoff is to maximum
if ( Cutoff == 1 )
R = 1 - rReso; return;
if ( Cutoff != pCutoff || Reso != pReso ) {
rReso = (0.991 - logsc(1 - Reso, 0, 0.991));
R24 = 3.5 * rReso;
float cutoffNorm = logsc(Cutoff, 60, 19000);
rCutoff = (float)tanf(cutoffNorm * sampleRateInv * M_PI);
pCutoff = Cutoff;
pReso = Reso;
R = 1 - rReso;
}
// THIS IS MY FAVORITE 4POLE OBXd filter
// maybe smooth this value
float g = rCutoff;
float lpc = g / (1 + g);
for (int i = 0; i < sampleSize; i++ ) {
float s = work[i];
s = s - 0.45 * tptlpupw(c, s, 15, sampleRateInv);
s = tptpc(d, s, bright);
float y0 = NR24(s, g, lpc);
//first low pass in cascade
float v = (y0 - s1) * lpc;
float res = v + s1;
s1 = res + v;
//damping
s1 = atanf(s1 * rcor24) * rcor24Inv;
float y1 = res;
float y2 = tptpc(s2, y1, g);
float y3 = tptpc(s3, y2, g);
float y4 = tptpc(s4, y3, g);
float mc = 0.0;
switch (mmch) {
case 0:
mc = ((1 - mmt) * y4 + (mmt) * y3);
break;
case 1:
mc = ((1 - mmt) * y3 + (mmt) * y2);
break;
case 2:
mc = ((1 - mmt) * y2 + (mmt) * y1);
break;
case 3:
mc = y1;
break;
} }
// THIS IS MY FAVORITE 4POLE OBXd filter //half volume comp
work[i] = mc * (1 + R24 * 0.45);
// maybe smooth this value }
float g = rCutoff;
float lpc = g / (1 + g);
for(int i=0; i < sampleSize; i++ ) {
float s = work[i];
s = s - 0.45*tptlpupw(c,s,15,sampleRateInv);
s = tptpc(d,s,bright);
float y0 = NR24(s,g,lpc);
//first low pass in cascade
double v = (y0 - s1) * lpc;
double res = v + s1;
s1 = res + v;
//damping
s1 =atan(s1*rcor24)*rcor24Inv;
float y1= res;
float y2 = tptpc(s2,y1,g);
float y3 = tptpc(s3,y2,g);
float y4 = tptpc(s4,y3,g);
float mc=0.0;
switch(mmch) {
case 0:
mc = ((1 - mmt) * y4 + (mmt) * y3);
break;
case 1:
mc = ((1 - mmt) * y3 + (mmt) * y2);
break;
case 2:
mc = ((1 - mmt) * y2 + (mmt) * y1);
break;
case 3:
mc = y1;
break;
}
//half volume comp
work[i] = mc * (1 + R24 * 0.45);
}
} }
/* /*
// THIS IS THE 2POLE FILTER // THIS IS THE 2POLE FILTER
for(int i=0; i < sampleSize; i++ ) { for(int i=0; i < sampleSize; i++ ) {
float s = work[i]; float s = work[i];
s = s - 0.45*tptlpupw(c,s,15,sampleRateInv); s = s - 0.45*tptlpupw(c,s,15,sampleRateInv);
s = tptpc(d,s,bright); s = tptpc(d,s,bright);
//float v = ((sample- R * s1*2 - g2*s1 - s2)/(1+ R*g1*2 + g1*g2)); //float v = ((sample- R * s1*2 - g2*s1 - s2)/(1+ R*g1*2 + g1*g2));
float v = NR(s,g); float v = NR(s,g);
float y1 = v*g + s1; float y1 = v*g + s1;
//damping //damping
s1 = atan(s1 * rcor) * rcorInv; s1 = atanf(s1 * rcor) * rcorInv;
float y2 = y1*g + s2; float y2 = y1*g + s2;
s2 = y2 + y1*g; s2 = y2 + y1*g;
double mc; float mc;
if(!bandPassSw) if(!bandPassSw)
mc = (1-mm)*y2 + (mm)*v; mc = (1-mm)*y2 + (mm)*v;
else else
{ {
mc =2 * ( mm < 0.5 ? mc =2 * ( mm < 0.5 ?
((0.5 - mm) * y2 + (mm) * y1): ((0.5 - mm) * y2 + (mm) * y1):
((1-mm) * y1 + (mm-0.5) * v) ((1-mm) * y1 + (mm-0.5) * v)
); );
} }
work[i] = mc; work[i] = mc;
} }
*/ */

@ -61,9 +61,9 @@ class PluginFx {
PluginFx(); PluginFx();
// this is set directly by the ui / parameter // this is set directly by the ui / parameter
float uiCutoff; float Cutoff;
float uiReso; float Reso;
float uiGain; float Gain;
void init(int sampleRate); void init(int sampleRate);
void process(float *work, int sampleSize); void process(float *work, int sampleSize);

@ -292,7 +292,7 @@ void handle_ui(void)
switch (ui_main_state) switch (ui_main_state)
{ {
case UI_MAIN_FILTER_FRQ: case UI_MAIN_FILTER_FRQ:
if (enc[i].read() <= 0) /* if (enc[i].read() <= 0)
enc[i].write(0); enc[i].write(0);
else if (enc[i].read() > ENC_FILTER_FRQ_STEPS) else if (enc[i].read() > ENC_FILTER_FRQ_STEPS)
enc[i].write(ENC_FILTER_FRQ_STEPS); enc[i].write(ENC_FILTER_FRQ_STEPS);
@ -314,9 +314,10 @@ void handle_ui(void)
Serial.print(F("Setting filter frequency to: ")); Serial.print(F("Setting filter frequency to: "));
Serial.println(EXP_FUNC((float)map(effect_filter_frq, 0, ENC_FILTER_FRQ_STEPS, 0, 1024) / 150.0) * 10.0 + 80.0, DEC); Serial.println(EXP_FUNC((float)map(effect_filter_frq, 0, ENC_FILTER_FRQ_STEPS, 0, 1024) / 150.0) * 10.0 + 80.0, DEC);
#endif #endif
*/
break; break;
case UI_MAIN_FILTER_RES: case UI_MAIN_FILTER_RES:
if (enc[i].read() <= 0) /* if (enc[i].read() <= 0)
enc[i].write(0); enc[i].write(0);
else if (enc[i].read() > ENC_FILTER_RES_STEPS) else if (enc[i].read() > ENC_FILTER_RES_STEPS)
enc[i].write(ENC_FILTER_RES_STEPS); enc[i].write(ENC_FILTER_RES_STEPS);
@ -328,9 +329,10 @@ void handle_ui(void)
Serial.print(F("Setting filter resonance to: ")); Serial.print(F("Setting filter resonance to: "));
Serial.println(EXP_FUNC(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0)) * 0.044 + 0.61, 2); Serial.println(EXP_FUNC(mapfloat(effect_filter_resonance, 0, ENC_FILTER_RES_STEPS, 0.7, 5.0)) * 0.044 + 0.61, 2);
#endif #endif
*/
break; break;
case UI_MAIN_FILTER_OCT: case UI_MAIN_FILTER_OCT:
if (enc[i].read() <= 0) /* if (enc[i].read() <= 0)
enc[i].write(0); enc[i].write(0);
else if (enc[i].read() > ENC_FILTER_OCT_STEPS) else if (enc[i].read() > ENC_FILTER_OCT_STEPS)
enc[i].write(ENC_FILTER_OCT_STEPS); enc[i].write(ENC_FILTER_OCT_STEPS);
@ -340,6 +342,7 @@ void handle_ui(void)
Serial.print(F("Setting filter octave control to: ")); Serial.print(F("Setting filter octave control to: "));
Serial.println(mapfloat(effect_filter_octave, 0, ENC_FILTER_OCT_STEPS, 0.0, 7.0), 2); Serial.println(mapfloat(effect_filter_octave, 0, ENC_FILTER_OCT_STEPS, 0.0, 7.0), 2);
#endif #endif
*/
break; break;
} }
ui_show_effects_filter(); ui_show_effects_filter();

@ -54,7 +54,6 @@ extern uint8_t effect_delay_time;
extern uint8_t effect_delay_feedback; extern uint8_t effect_delay_feedback;
extern uint8_t effect_delay_volume; extern uint8_t effect_delay_volume;
extern bool effect_delay_sync; extern bool effect_delay_sync;
extern AudioFilterStateVariable filter1;
extern AudioEffectDelay delay1; extern AudioEffectDelay delay1;
extern AudioMixer4 mixer1; extern AudioMixer4 mixer1;
extern AudioMixer4 mixer2; extern AudioMixer4 mixer2;

Loading…
Cancel
Save