From ae301b85b950cca67e240fd070501af865d39b1a Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Thu, 5 Dec 2019 13:35:23 +0100 Subject: [PATCH] Exchanged pan effect (simpler implementation). Fixed small errors. Fixed maximum of concurrent voices. --- Disp_Plus.h | 1 - MicroDexed.ino | 81 +++++++++++++++++++++--------------------- UI.hpp | 2 +- config.h | 13 ++++--- effect_auto_pan.cpp | 77 +++++++++++++++++++++++++++++++++++++++ effect_auto_pan.h | 54 ++++++++++++++++++++++++++++ effect_mono_stereo.cpp | 40 ++++++++++----------- effect_mono_stereo.h | 11 +++--- pan | 0 9 files changed, 204 insertions(+), 75 deletions(-) create mode 100644 effect_auto_pan.cpp create mode 100644 effect_auto_pan.h create mode 100644 pan diff --git a/Disp_Plus.h b/Disp_Plus.h index 64fb38f..851c044 100644 --- a/Disp_Plus.h +++ b/Disp_Plus.h @@ -62,7 +62,6 @@ class Disp_Plus : public T memset(tmp, '0', field_size); else memset(tmp, 0x20, field_size); // blank - tmp[field_size+1]='\0'; if (l > field_size) l = field_size; diff --git a/MicroDexed.ino b/MicroDexed.ino index a0fb186..7a1b88a 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -43,69 +43,70 @@ // Audio engines AudioSourceMicroDexed* MicroDexed[NUM_DEXED]; AudioEffectMonoStereo* mono2stereo[NUM_DEXED]; -AudioSynthWaveformDc* pan[NUM_DEXED]; - -// single used objects AudioAnalyzePeak microdexed_peak; AudioMixer4 microdexed_peak_mixer; AudioSynthWaveform chorus_modulator; AudioAmplifier modchorus_inverter; - -// FX chain left +AudioMixer4 dexed_mixer_r; +AudioMixer4 dexed_mixer_l; +AudioMixer4 master_mixer_r; +AudioMixer4 master_mixer_l; +AudioAmplifier volume_r; +AudioAmplifier volume_l; +AudioEffectStereoMono stereo2mono; +AudioAnalyzePeak master_peak_r; +AudioAnalyzePeak master_peak_l; +AudioMixer4 delay_send_mixer_r; AudioMixer4 delay_send_mixer_l; +AudioMixer4 delay_fb_mixer_r; AudioMixer4 delay_fb_mixer_l; +AudioEffectDelay delay_r; AudioEffectDelay delay_l; +AudioMixer4 chorus_send_mixer_r; +AudioMixer4 chorus_send_mixer_l; +AudioEffectModulatedDelay modchorus_r; +AudioEffectModulatedDelay modchorus_l; +#if MOD_FILTER_OUTPUT != MOD_NO_FILTER_OUTPUT +AudioFilterBiquad modchorus_filter_r; +AudioFilterBiquad modchorus_filter_l; +#endif +#if defined(USE_REVERB) +AudioMixer4 reverb_send_mixer_r; +AudioMixer4 reverb_send_mixer_l; +AudioEffectFreeverb freeverb_l; +AudioEffectFreeverb freeverb_r; +#endif + +// FX chain left AudioConnection patchCord1(delay_send_mixer_l, 0, delay_fb_mixer_l, 0); AudioConnection patchCord2(delay_fb_mixer_l, delay_l); AudioConnection patchCord3(delay_l, 0, delay_fb_mixer_l, 1); // feedback-loop -AudioMixer4 chorus_send_mixer_l; -AudioEffectModulatedDelay modchorus_l; AudioConnection patchCord4(chorus_send_mixer_l, 0, modchorus_l, 0); AudioConnection patchCord5(chorus_modulator, 0, modchorus_l, 1); #if MOD_FILTER_OUTPUT != MOD_NO_FILTER_OUTPUT -AudioFilterBiquad modchorus_filter_l; AudioConnection patchCord6(modchorus_l, modchorus_filter_l); AudioConnection patchCord7(modchorus_filter_l, modchorus_inverter); #else AudioConnection patchCord6(modchorus_l, modchorus_inverter); #endif #if defined(USE_REVERB) -AudioMixer4 reverb_send_mixer_l; -AudioEffectFreeverb freeverb_l; AudioConnection patchCord8(reverb_send_mixer_l, freeverb_l); #endif // FX chain right -AudioMixer4 delay_send_mixer_r; -AudioMixer4 delay_fb_mixer_r; -AudioEffectDelay delay_r; AudioConnection patchCord9(delay_send_mixer_r, 0, delay_fb_mixer_r, 0); AudioConnection patchCord10(delay_fb_mixer_r, delay_r); AudioConnection patchCord11(delay_r, 0, delay_fb_mixer_r, 1); // feedback-loop -AudioMixer4 chorus_send_mixer_r; AudioConnection patchCord12(chorus_send_mixer_r, modchorus_r); -AudioEffectModulatedDelay modchorus_r; AudioConnection patchCord13(chorus_modulator, 0, modchorus_r, 1); #if MOD_FILTER_OUTPUT != MOD_NO_FILTER_OUTPUT -AudioFilterBiquad modchorus_filter_r; AudioConnection patchCord14(modchorus_r, modchorus_filter_r); #endif #if defined(USE_REVERB) -AudioMixer4 reverb_send_mixer_r; -AudioEffectFreeverb freeverb_r; AudioConnection patchCord15(reverb_send_mixer_r, freeverb_r); #endif // FX chain tail -AudioMixer4 dexed_mixer_r; -AudioMixer4 dexed_mixer_l; -AudioMixer4 master_mixer_r; -AudioMixer4 master_mixer_l; -AudioAmplifier volume_r; -AudioAmplifier volume_l; -AudioEffectStereoMono stereo2mono; -AudioAnalyzePeak master_peak_r; -AudioAnalyzePeak master_peak_l; AudioConnection patchCord16(delay_fb_mixer_r, 0, master_mixer_r, DELAY); AudioConnection patchCord17(delay_fb_mixer_l, 0, master_mixer_l, DELAY); #if MOD_FILTER_OUTPUT != MOD_NO_FILTER_OUTPUT @@ -170,18 +171,17 @@ AudioConnection patchCord34(stereo2mono, 1, dacOut, 1); // uint8_t nDynamic = 0; #if defined(USE_REVERB) -AudioConnection * dynamicConnections[NUM_DEXED * 11]; +AudioConnection * dynamicConnections[NUM_DEXED * 10]; #else -AudioConnection * dynamicConnections[NUM_DEXED * 9]; +AudioConnection * dynamicConnections[NUM_DEXED * 8]; #endif -void create_audio_connections(AudioSourceMicroDexed &dexed, AudioEffectMonoStereo &mono2stereo, AudioSynthWaveformDc &pan, uint8_t instance_id) +void create_audio_connections(AudioSourceMicroDexed &dexed, AudioEffectMonoStereo &mono2stereo, uint8_t instance_id) { Serial.print(F("Connecting Dexed ")); Serial.print(instance_id, DEC); Serial.println(F(":")); dynamicConnections[nDynamic++] = new AudioConnection(dexed, 0, microdexed_peak_mixer, instance_id); dynamicConnections[nDynamic++] = new AudioConnection(dexed, 0, mono2stereo, 0); - dynamicConnections[nDynamic++] = new AudioConnection(pan, 0, mono2stereo, 1); Serial.println(F(" -> Peakmeter")); dynamicConnections[nDynamic++] = new AudioConnection(mono2stereo, 0, dexed_mixer_r, instance_id); dynamicConnections[nDynamic++] = new AudioConnection(mono2stereo, 1, dexed_mixer_l, instance_id); @@ -290,8 +290,7 @@ void setup() Serial.println(instance_id, DEC); MicroDexed[instance_id] = new AudioSourceMicroDexed(SAMPLE_RATE); mono2stereo[instance_id] = new AudioEffectMonoStereo(); - pan[instance_id] = new AudioSynthWaveformDc(); - create_audio_connections(*MicroDexed[instance_id], *mono2stereo[instance_id], *pan[instance_id], instance_id); + create_audio_connections(*MicroDexed[instance_id], *mono2stereo[instance_id], instance_id); } else { @@ -478,7 +477,7 @@ void setup() MicroDexed[instance_id]->doRefreshVoice(); // PANORAMA - pan[instance_id]->amplitude(mapfloat(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); + mono2stereo[instance_id]->panorama(mapfloat(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); } // DELAY @@ -608,7 +607,7 @@ void loop() } } -#if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC) +#if defined (SHOW_CPU_LOAD_MSEC) if (cpu_mem_millis >= SHOW_CPU_LOAD_MSEC) { if (master_peak_r.available()) @@ -720,7 +719,7 @@ void handleControlChange(byte inChannel, byte inCtrl, byte inValue) Serial.println(F("PANORAMA CC")); #endif configuration.dexed[instance_id].pan = map(inValue, 0, 0x7f, PANORAMA_MIN, PANORAMA_MAX); - pan[instance_id]->amplitude(mapfloat(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); + mono2stereo[instance_id]->panorama(mapfloat(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); eeprom_write(); break; case 32: // BankSelect LSB @@ -1217,7 +1216,7 @@ void set_volume(uint8_t v, uint8_t m) for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) { configuration.dexed[instance_id].pan = 0.0; - pan[instance_id]->amplitude(mapfloat(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); + mono2stereo[instance_id]->panorama(mapfloat(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); } modchorus_inverter.gain(1.0); // stereo mode break; @@ -1227,7 +1226,7 @@ void set_volume(uint8_t v, uint8_t m) for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) { configuration.dexed[instance_id].pan = 1.0; - pan[instance_id]->amplitude(mapfloat(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); + mono2stereo[instance_id]->panorama(mapfloat(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); } modchorus_inverter.gain(1.0); // stereo mode break; @@ -1524,7 +1523,7 @@ void set_master_mixer_gain(uint8_t type, float level) DEBUG HELPER ******************************************************************************/ -#if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC) +#if defined (SHOW_CPU_LOAD_MSEC) void show_cpu_and_mem_usage(void) { uint32_t sum_xrun = 0; @@ -1544,13 +1543,13 @@ void show_cpu_and_mem_usage(void) Serial.print(F("*")); } else - Serial.print(F("")); + Serial.print(F(" ")); Serial.print(F("CPU:")); Serial.print(AudioProcessorUsage(), 2); Serial.print(F("%|CPUMAX:")); Serial.print(AudioProcessorUsageMax(), 2); Serial.print(F("%|CPUMAXCNT:")); - Serial.print(cpumax,DEC); + Serial.print(cpumax, DEC); Serial.print(F("|MEM:")); Serial.print(AudioMemoryUsage(), DEC); Serial.print(F("|MEMMAX:")); diff --git a/UI.hpp b/UI.hpp index 22ab2e5..7c1104a 100644 --- a/UI.hpp +++ b/UI.hpp @@ -2016,7 +2016,7 @@ void UI_func_panorama(uint8_t param) { lcd.setCursor(0, 1); lcd_display_int(configuration.dexed[instance_id].pan - 20, 2, false, true, true); - pan[instance_id]->amplitude(mapfloat(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); + mono2stereo[instance_id]->panorama(mapfloat(configuration.dexed[instance_id].pan, PANORAMA_MIN, PANORAMA_MAX, -1.0, 1.0)); } } diff --git a/config.h b/config.h index c07e9f5..7a6f72d 100644 --- a/config.h +++ b/config.h @@ -149,8 +149,7 @@ //* DEBUG OUTPUT SETTINGS //************************************************************************************************* #define DEBUG 1 -//#define SERIAL_SPEED 230400 -#define SERIAL_SPEED 9600 +#define SERIAL_SPEED 230400 #define SHOW_XRUN 1 #define SHOW_CPU_LOAD_MSEC 5000 @@ -213,7 +212,7 @@ #define MAX_DEXED 2 #define NORMALIZE_DX_VELOCITY 1 -enum { DEXED, REVERB, DELAY, CHORUS }; +enum { DEXED, CHORUS, DELAY, REVERB}; // MIDI #ifdef MIDI_DEVICE_USB @@ -229,7 +228,11 @@ enum { DEXED, REVERB, DELAY, CHORUS }; // Teensy-3.6 settings #define MIDI_DEVICE_USB_HOST 1 #if defined(USE_REVERB) -#define MAX_NOTES 12 +#if defined(DEBUG) +#define MAX_NOTES 10 +#else +#define MAX_NOTES 11 +#endif #else #define MAX_NOTES 14 #endif @@ -238,7 +241,7 @@ enum { DEXED, REVERB, DELAY, CHORUS }; #if defined (__MK64FX512__) // Teensy-3.5 settings #undef MIDI_DEVICE_USB_HOST -#define MAX_NOTES 10 +#define MAX_NOTES 6 #undef USE_REVERB #endif diff --git a/effect_auto_pan.cpp b/effect_auto_pan.cpp new file mode 100644 index 0000000..ca4f141 --- /dev/null +++ b/effect_auto_pan.cpp @@ -0,0 +1,77 @@ +/* + Copyright (c) 2019, Holger Wirtz + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include +#include +#include "effect_auto_pan.h" + +/*************************************************************************/ +// A u d i o E f f e c t A u t o P a n +// Written by Holger Wirtz +// 20191205 - initial version + +void AudioEffectAutoPan::update(void) +{ + audio_block_t *in; + audio_block_t *mod; + audio_block_t *out[2]; + + in = receiveReadOnly(0); + mod = receiveReadOnly(1); + + out[0] = allocate(); + out[1] = allocate(); + + if (in && mod && out[0] && out[1]) + { + arm_q15_to_float(in->data, in_f, AUDIO_BLOCK_SAMPLES); + arm_q15_to_float(mod->data, pan_f, AUDIO_BLOCK_SAMPLES); + arm_offset_f32(pan_f, 1.0, pan_f, AUDIO_BLOCK_SAMPLES); + arm_scale_f32(pan_f, PI / 4.0, pan_f, AUDIO_BLOCK_SAMPLES); // PI/4 + + // right + for (uint8_t n = 0; n < AUDIO_BLOCK_SAMPLES; n++) + out_f[0][n] = in_f[n] * _pseudo_log * arm_sin_f32(pan_f[n]); + arm_float_to_q15 (out_f[0], out[0]->data, AUDIO_BLOCK_SAMPLES); + // left + for (uint8_t n = 0; n < AUDIO_BLOCK_SAMPLES; n++) + out_f[1][n] = in_f[n] * _pseudo_log * arm_cos_f32(pan_f[n]); + arm_float_to_q15 (out_f[1], out[1]->data, AUDIO_BLOCK_SAMPLES); + + if (in) + { + release(in); + } + if (mod) + { + release(mod); + } + for (uint8_t i = 0; i < 2; i++) + { + if (out[i]) + { + transmit(out[i], i); + release(out[i]); + } + } + } +} diff --git a/effect_auto_pan.h b/effect_auto_pan.h new file mode 100644 index 0000000..4259f7d --- /dev/null +++ b/effect_auto_pan.h @@ -0,0 +1,54 @@ +/* + Copyright (c) 2019, Holger Wirtz + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef effect_auto_pan_h_ +#define effect_auto_pan_h_ + +#include "Arduino.h" +#include "AudioStream.h" + +/*************************************************************************/ +// A u d i o E f f e c t A u t o P a n +// Written by Holger Wirtz +// 20191205 - inital version + +class AudioEffectAutoPan : public AudioStream +{ + public: + AudioEffectAutoPan(void): + AudioStream(2, inputQueueArray) + { + ; + } + + virtual void update(void); + + private: + audio_block_t *inputQueueArray[2]; + audio_block_t *out[2]; + float in_f[AUDIO_BLOCK_SAMPLES]; + float out_f[2][AUDIO_BLOCK_SAMPLES]; + float pan_f[AUDIO_BLOCK_SAMPLES]; + const float _pseudo_log = 1048575 / (float)(1 << 20); +}; + +#endif diff --git a/effect_mono_stereo.cpp b/effect_mono_stereo.cpp index 9816ffb..8d9dea7 100644 --- a/effect_mono_stereo.cpp +++ b/effect_mono_stereo.cpp @@ -22,6 +22,7 @@ #include #include +#include "limits.h" #include "effect_mono_stereo.h" /*************************************************************************/ @@ -37,49 +38,46 @@ inline float mapfloat(float val, float in_min, float in_max, float out_min, floa } #endif +void AudioEffectMonoStereo::panorama(float p) +{ + pan = mapfloat(p, -1.0, 1.0, 0.0, 1.0); +} + void AudioEffectMonoStereo::update(void) { audio_block_t *in; - audio_block_t *mod; audio_block_t *out[2]; in = receiveReadOnly(0); - mod = receiveReadOnly(1); out[0] = allocate(); out[1] = allocate(); - if (in && mod && out[0] && out[1]) + if (in && out[0] && out[1]) { arm_q15_to_float(in->data, in_f, AUDIO_BLOCK_SAMPLES); - arm_q15_to_float(mod->data, pan_f, AUDIO_BLOCK_SAMPLES); - arm_offset_f32(pan_f, 1.0, pan_f_tmp, AUDIO_BLOCK_SAMPLES); - arm_scale_f32(pan_f_tmp, PI / 4.0, pan_f, AUDIO_BLOCK_SAMPLES); // PI/4 - // right + float f = pan * PI / 2.0; + int16_t* out_p[2] = {out[0]->data, out[1]->data}; for (uint8_t n = 0; n < AUDIO_BLOCK_SAMPLES; n++) - out_f[0][n] = in_f[n] * _pseudo_log * arm_sin_f32(pan_f[n]); - arm_float_to_q15 (out_f[0], out[0]->data, AUDIO_BLOCK_SAMPLES); - // left - for (uint8_t n = 0; n < AUDIO_BLOCK_SAMPLES; n++) - out_f[1][n] = in_f[n] * _pseudo_log * arm_cos_f32(pan_f[n]); - arm_float_to_q15 (out_f[1], out[1]->data, AUDIO_BLOCK_SAMPLES); + { + *out_p[0]++ = int16_t(in_f[n] * _pseudo_log * arm_sin_f32(f) * SHRT_MAX); + *out_p[1]++ = int16_t(in_f[n] * _pseudo_log * arm_cos_f32(f) * SHRT_MAX); + } if (in) { release(in); } - if (mod) + if (out[0]) { - release(mod); + transmit(out[0], 0); + release(out[0]); } - for (uint8_t i = 0; i < 2; i++) + if (out[1]) { - if (out[i]) - { - transmit(out[i], i); - release(out[i]); - } + transmit(out[1], 1); + release(out[1]); } } } diff --git a/effect_mono_stereo.h b/effect_mono_stereo.h index 538d283..fe1f699 100644 --- a/effect_mono_stereo.h +++ b/effect_mono_stereo.h @@ -35,20 +35,19 @@ class AudioEffectMonoStereo : public AudioStream { public: AudioEffectMonoStereo(void): - AudioStream(2, inputQueueArray) + AudioStream(1, inputQueueArray) { - ; + pan = 0.5; } virtual void update(void); + virtual void panorama(float p); private: - audio_block_t *inputQueueArray[2]; + audio_block_t *inputQueueArray[1]; audio_block_t *out[2]; float in_f[AUDIO_BLOCK_SAMPLES]; - float out_f[2][AUDIO_BLOCK_SAMPLES]; - float pan_f[AUDIO_BLOCK_SAMPLES]; - float pan_f_tmp[AUDIO_BLOCK_SAMPLES]; + float pan; const float _pseudo_log = 1048575 / (float)(1 << 20); }; diff --git a/pan b/pan new file mode 100644 index 0000000..e69de29