Exchanged pan effect (simpler implementation).

Fixed small errors.
Fixed maximum of concurrent voices.
pull/32/head
Holger Wirtz 5 years ago
parent 81ca62604c
commit ae301b85b9
  1. 1
      Disp_Plus.h
  2. 81
      MicroDexed.ino
  3. 2
      UI.hpp
  4. 13
      config.h
  5. 77
      effect_auto_pan.cpp
  6. 54
      effect_auto_pan.h
  7. 40
      effect_mono_stereo.cpp
  8. 11
      effect_mono_stereo.h
  9. 0
      pan

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

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

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

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

@ -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 <Arduino.h>
#include <Audio.h>
#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]);
}
}
}
}

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

@ -22,6 +22,7 @@
#include <Arduino.h>
#include <Audio.h>
#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]);
}
}
}

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

Loading…
Cancel
Save