Fixes for new fx-chain.

pull/32/head
Holger Wirtz 4 years ago
parent 9c3f85c695
commit 6edbba5ed6
  1. 54
      MicroDexed.ino
  2. 12
      UI.hpp
  3. 2
      doc/MicroDexed-Audio-FlowChart.drawio
  4. BIN
      doc/MicroDexed-Audio-FlowChart.png

@ -45,8 +45,12 @@ AudioSourceMicroDexed* MicroDexed[NUM_DEXED];
AudioAmplifier* dexed_level[NUM_DEXED];
#if defined(USE_FX)
AudioSynthWaveform* chorus_modulator[NUM_DEXED];
#if MOD_FILTER_OUTPUT != MOD_NO_FILTER_OUTPUT
AudioFilterBiquad* modchorus_filter[NUM_DEXED];
#endif
AudioEffectModulatedDelay* modchorus[NUM_DEXED];
AudioMixer4* chorus_mixer[NUM_DEXED];
AudioMixer4* delay_fb_mixer[NUM_DEXED];
AudioEffectDelay* delay_fx[NUM_DEXED];
AudioMixer4* delay_mixer[NUM_DEXED];
#endif
@ -57,7 +61,8 @@ AudioAnalyzePeak microdexed_peak;
#if defined(USE_FX)
AudioMixer4 reverb_mixer_r;
AudioMixer4 reverb_mixer_l;
AudioEffectFreeverbStereo freeverbs;
AudioEffectFreeverb freeverb_r;
AudioEffectFreeverb freeverb_l;
#endif
AudioMixer4 master_mixer_r;
AudioMixer4 master_mixer_l;
@ -67,20 +72,12 @@ AudioEffectStereoMono stereo2mono;
AudioAnalyzePeak master_peak_r;
AudioAnalyzePeak master_peak_l;
/*
#if MOD_FILTER_OUTPUT != MOD_NO_FILTER_OUTPUT
AudioConnection patchCord14(modchorus_r, modchorus_filter_r);
#endif
AudioConnection patchCord15(reverb_send_mixer_r, freeverb_r);
#endif
*/
// Audio chain tail
#if defined(USE_FX)
AudioConnection patchCord0(reverb_mixer_r, 0, freeverbs, 0);
AudioConnection patchCord1(reverb_mixer_l, 0, freeverbs, 1);
AudioConnection patchCord2(freeverbs, 0, master_mixer_r, 3);
AudioConnection patchCord3(freeverbs, 1, master_mixer_l, 3);
AudioConnection patchCord0(reverb_mixer_r, freeverb_r);
AudioConnection patchCord1(reverb_mixer_l, freeverb_l);
AudioConnection patchCord2(freeverb_r, 0, master_mixer_r, 3);
AudioConnection patchCord3(freeverb_l, 0, master_mixer_l, 3);
#endif
AudioConnection patchCord4(master_mixer_r, volume_r);
AudioConnection patchCord5(master_mixer_l, volume_l);
@ -129,8 +126,10 @@ AudioConnection patchCord13(stereo2mono, 1, dacOut, 1);
// Dynamic patching of MicroDexed objects
//
uint8_t nDynamic = 0;
#if defined(USE_FX)
AudioConnection * dynamicConnections[NUM_DEXED * 15];
#if defined(USE_FX) && MOD_FILTER_OUTPUT != MOD_NO_FILTER_OUTPUT
AudioConnection * dynamicConnections[NUM_DEXED * 19];
#elif defined(USE_FX) && MOD_FILTER_OUTPUT == MOD_NO_FILTER_OUTPUT
AudioConnection * dynamicConnections[NUM_DEXED * 17];
#else
AudioConnection * dynamicConnections[NUM_DEXED * 5];
#endif
@ -141,8 +140,12 @@ void create_audio_engine_chain(uint8_t instance_id)
mono2stereo[instance_id] = new AudioEffectMonoStereo();
#if defined(USE_FX)
chorus_modulator[instance_id] = new AudioSynthWaveform();
#if MOD_FILTER_OUTPUT != MOD_NO_FILTER_OUTPUT
modchorus_filter[instance_id] = new AudioFilterBiquad();
#endif
modchorus[instance_id] = new AudioEffectModulatedDelay();
chorus_mixer[instance_id] = new AudioMixer4();
delay_fb_mixer[instance_id] = new AudioMixer4();
delay_fx[instance_id] = new AudioEffectDelay();
delay_mixer[instance_id] = new AudioMixer4();
#endif
@ -153,12 +156,19 @@ void create_audio_engine_chain(uint8_t instance_id)
#if defined(USE_FX)
dynamicConnections[nDynamic++] = new AudioConnection(*dexed_level[instance_id], 0, *chorus_mixer[instance_id], 0);
dynamicConnections[nDynamic++] = new AudioConnection(*dexed_level[instance_id], 0, *modchorus[instance_id], 0);
#if MOD_FILTER_OUTPUT != MOD_NO_FILTER_OUTPUT
dynamicConnections[nDynamic++] = new AudioConnection(*chorus_modulator[instance_id], 0, *modchorus_filter[instance_id], 0);
dynamicConnections[nDynamic++] = new AudioConnection(*modchorus_filter[instance_id], 0, *modchorus[instance_id], 1);
#else
dynamicConnections[nDynamic++] = new AudioConnection(*chorus_modulator[instance_id], 0, *modchorus[instance_id], 1);
#endif
dynamicConnections[nDynamic++] = new AudioConnection(*modchorus[instance_id], 0, *chorus_mixer[instance_id], 1);
dynamicConnections[nDynamic++] = new AudioConnection(*chorus_mixer[instance_id], 0, *delay_fb_mixer[instance_id], 0);
dynamicConnections[nDynamic++] = new AudioConnection(*chorus_mixer[instance_id], 0, *delay_mixer[instance_id], 0);
dynamicConnections[nDynamic++] = new AudioConnection(*delay_fb_mixer[instance_id], 0, *delay_fx[instance_id], 0);
dynamicConnections[nDynamic++] = new AudioConnection(*delay_fx[instance_id], 0, *delay_mixer[instance_id], 1);
dynamicConnections[nDynamic++] = new AudioConnection(*delay_mixer[instance_id], 0, *delay_fx[instance_id], 0);
dynamicConnections[nDynamic++] = new AudioConnection(*delay_mixer[instance_id], 0, *mono2stereo[instance_id], 0);
dynamicConnections[nDynamic++] = new AudioConnection(*delay_mixer[instance_id], 0, *delay_fb_mixer[instance_id], 1);
dynamicConnections[nDynamic++] = new AudioConnection(*mono2stereo[instance_id], 0, reverb_mixer_r, instance_id);
dynamicConnections[nDynamic++] = new AudioConnection(*mono2stereo[instance_id], 1, reverb_mixer_l, instance_id);
#else
@ -1665,14 +1675,20 @@ void set_fx_params(void)
// DELAY
delay_fx[instance_id]->delay(0, mapfloat(configuration.fx.delay_time[instance_id] * 10, DELAY_TIME_MIN, DELAY_TIME_MAX, 0.0, float(DELAY_TIME_MAX)));
delay_mixer[instance_id]->gain(0, 1.0);
delay_mixer[instance_id]->gain(1, mapfloat(configuration.fx.delay_feedback[instance_id], DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX, 0.0, 1.0));
delay_mixer[instance_id]->gain(1, mapfloat(configuration.fx.delay_level[instance_id], DELAY_LEVEL_MIN, DELAY_LEVEL_MAX, 0.0, 1.0));
delay_fb_mixer[instance_id]->gain(0, 1.0);
delay_fb_mixer[instance_id]->gain(1, mapfloat(configuration.fx.delay_feedback[instance_id], DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX, 0.0, 1.0));
// REVERB
reverb_mixer_r.gain(instance_id, configuration.fx.reverb_level / 100.0);
reverb_mixer_l.gain(instance_id, configuration.fx.reverb_level / 100.0);
}
freeverbs.roomsize(mapfloat(configuration.fx.reverb_roomsize, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX, 0.0, 1.0));
freeverbs.damping(mapfloat(configuration.fx.reverb_damping, REVERB_DAMPING_MIN, REVERB_DAMPING_MAX, 0.0, 1.0));
// REVERB
freeverb_r.roomsize(mapfloat(configuration.fx.reverb_roomsize, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX, 0.0, 1.0));
freeverb_r.damping(mapfloat(configuration.fx.reverb_damping, REVERB_DAMPING_MIN, REVERB_DAMPING_MAX, 0.0, 1.0));
freeverb_l.roomsize(mapfloat(configuration.fx.reverb_roomsize, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX, 0.0, 1.0));
freeverb_l.damping(mapfloat(configuration.fx.reverb_damping, REVERB_DAMPING_MIN, REVERB_DAMPING_MAX, 0.0, 1.0));
#endif
}

@ -67,6 +67,7 @@ extern AudioAmplifier* dexed_level[NUM_DEXED];
extern AudioSynthWaveform* chorus_modulator[NUM_DEXED];
extern AudioEffectModulatedDelay* modchorus[NUM_DEXED];
extern AudioMixer4* chorus_mixer[NUM_DEXED];
extern AudioMixer4* delay_fb_mixer[NUM_DEXED];
extern AudioEffectDelay* delay_fx[NUM_DEXED];
extern AudioMixer4* delay_mixer[NUM_DEXED];
#endif
@ -77,7 +78,8 @@ extern AudioAnalyzePeak microdexed_peak;
#if defined(USE_FX)
extern AudioMixer4 reverb_mixer_r;
extern AudioMixer4 reverb_mixer_l;
extern AudioEffectFreeverbStereo freeverbs;
extern AudioEffectFreeverb freeverb_r;
extern AudioEffectFreeverb freeverb_l;
#endif
extern AudioMixer4 master_mixer_r;
extern AudioMixer4 master_mixer_l;
@ -892,7 +894,8 @@ void UI_func_reverb_roomsize(uint8_t param)
}
lcd_display_bar_int("Reverb Room", configuration.fx.reverb_roomsize, 1.0, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX, 3, false, false, false, false);
freeverbs.roomsize(mapfloat(configuration.fx.reverb_roomsize, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX, 0.0, 1.0));
freeverb_r.roomsize(mapfloat(configuration.fx.reverb_roomsize, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX, 0.0, 1.0));
freeverb_l.roomsize(mapfloat(configuration.fx.reverb_roomsize, REVERB_ROOMSIZE_MIN, REVERB_ROOMSIZE_MAX, 0.0, 1.0));
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
@ -925,7 +928,8 @@ void UI_func_reverb_damping(uint8_t param)
lcd_display_bar_int("Reverb Damp.", configuration.fx.reverb_damping, 1.0, REVERB_DAMPING_MIN, REVERB_DAMPING_MAX, 3, false, false, false, false);
freeverbs.damping(mapfloat(configuration.fx.reverb_damping, REVERB_DAMPING_MIN, REVERB_DAMPING_MAX, 0.0, 1.0));
freeverb_l.damping(mapfloat(configuration.fx.reverb_damping, REVERB_DAMPING_MIN, REVERB_DAMPING_MAX, 0.0, 1.0));
freeverb_r.damping(mapfloat(configuration.fx.reverb_damping, REVERB_DAMPING_MIN, REVERB_DAMPING_MAX, 0.0, 1.0));
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
@ -1221,7 +1225,7 @@ void UI_func_delay_feedback(uint8_t param)
lcd_display_bar_int("Delay Feedb.", configuration.fx.delay_feedback[instance_id], 1.0, DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX, 3, false, false, false, false);
delay_mixer[instance_id]->gain(1, configuration.fx.delay_feedback[instance_id] / 100.0); // amount of feedback
delay_fb_mixer[instance_id]->gain(1, configuration.fx.delay_feedback[instance_id] / 100.0); // amount of feedback
}
if (LCDML.FUNC_close()) // ****** STABLE END *********

@ -1 +1 @@
<mxfile host="app.diagrams.net" modified="2020-05-06T13:25:40.348Z" agent="5.0 (X11)" etag="gF525EnR2EZGPOSkNUPX" version="13.0.8" type="device"><diagram id="7c-kAhelgARxgBjdLmgF" name="Page-1">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</diagram></mxfile>
<mxfile host="app.diagrams.net" modified="2020-05-07T06:46:11.238Z" agent="5.0 (X11)" etag="qHCBIrCcC9J0hP5IfsDD" version="13.0.8" type="device"><diagram id="7c-kAhelgARxgBjdLmgF" name="Page-1">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</diagram></mxfile>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 101 KiB

Loading…
Cancel
Save