Removed OpenAudio test code.

Added midi-clock-handler code for syncing delay towards the midi clock.
pull/44/head
Holger Wirtz 3 years ago
parent 07f232fd30
commit cb2b538478
  1. 84
      MicroDexed.ino
  2. 3
      UI.hpp
  3. 7
      config.h
  4. 3
      dexed_sd.h
  5. 63
      synth_dexed.cpp
  6. 47
      synth_dexed.h

@ -24,7 +24,6 @@
#include <limits.h> #include <limits.h>
#include "config.h" #include "config.h"
#include <Audio.h> #include <Audio.h>
#include <OpenAudio_ArduinoLibrary.h>
#include <Wire.h> #include <Wire.h>
#include <MIDI.h> #include <MIDI.h>
#include <EEPROM.h> #include <EEPROM.h>
@ -44,9 +43,7 @@
#include "UI.hpp" #include "UI.hpp"
// Audio engines // Audio engines
//AudioSynthDexed* MicroDexed[NUM_DEXED]; AudioSynthDexed* MicroDexed[NUM_DEXED];
AudioSynthDexed_F32* MicroDexed[NUM_DEXED];
AudioConvert_F32toI16* convertf32toi16[NUM_DEXED];
#if defined(USE_FX) #if defined(USE_FX)
AudioSynthWaveform* chorus_modulator[NUM_DEXED]; AudioSynthWaveform* chorus_modulator[NUM_DEXED];
#if MOD_FILTER_OUTPUT != MOD_NO_FILTER_OUTPUT #if MOD_FILTER_OUTPUT != MOD_NO_FILTER_OUTPUT
@ -179,9 +176,7 @@ AudioConnection * dynamicConnections[NUM_DEXED * 5];
#endif #endif
void create_audio_engine_chain(uint8_t instance_id) void create_audio_engine_chain(uint8_t instance_id)
{ {
//MicroDexed[instance_id] = new AudioSynthDexed(SAMPLE_RATE); MicroDexed[instance_id] = new AudioSynthDexed(SAMPLE_RATE);
MicroDexed[instance_id] = new AudioSynthDexed_F32(SAMPLE_RATE);
convertf32toi16[instance_id] = new AudioConvert_F32toI16();
mono2stereo[instance_id] = new AudioEffectMonoStereo(); mono2stereo[instance_id] = new AudioEffectMonoStereo();
#if defined(USE_FX) #if defined(USE_FX)
chorus_modulator[instance_id] = new AudioSynthWaveform(); chorus_modulator[instance_id] = new AudioSynthWaveform();
@ -196,14 +191,10 @@ void create_audio_engine_chain(uint8_t instance_id)
#endif #endif
dynamicConnections[nDynamic++] = new AudioConnection(*MicroDexed[instance_id], 0, microdexed_peak_mixer, instance_id); dynamicConnections[nDynamic++] = new AudioConnection(*MicroDexed[instance_id], 0, microdexed_peak_mixer, instance_id);
//dynamicConnections[nDynamic++] = new AudioConnection(*MicroDexed[instance_id], 0, *convertf32toi16[instance_id], 0);
//dynamicConnections[nDynamic++] = new AudioConnection(*convertf32toi16[instance_id], 0, microdexed_peak_mixer, instance_id);
#if defined(USE_FX) #if defined(USE_FX)
dynamicConnections[nDynamic++] = new AudioConnection(*MicroDexed[instance_id], 0, *chorus_mixer[instance_id], 0); dynamicConnections[nDynamic++] = new AudioConnection(*MicroDexed[instance_id], 0, *chorus_mixer[instance_id], 0);
dynamicConnections[nDynamic++] = new AudioConnection(*MicroDexed[instance_id], 0, *modchorus[instance_id], 0); dynamicConnections[nDynamic++] = new AudioConnection(*MicroDexed[instance_id], 0, *modchorus[instance_id], 0);
//dynamicConnections[nDynamic++] = new AudioConnection(*convertf32toi16[instance_id], 0, *chorus_mixer[instance_id], 0);
//dynamicConnections[nDynamic++] = new AudioConnection(*convertf32toi16[instance_id], 0, *modchorus[instance_id], 0);
#if MOD_FILTER_OUTPUT != MOD_NO_FILTER_OUTPUT #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(*chorus_modulator[instance_id], 0, *modchorus_filter[instance_id], 0);
dynamicConnections[nDynamic++] = new AudioConnection(*modchorus_filter[instance_id], 0, *modchorus[instance_id], 1); dynamicConnections[nDynamic++] = new AudioConnection(*modchorus_filter[instance_id], 0, *modchorus[instance_id], 1);
@ -220,8 +211,7 @@ void create_audio_engine_chain(uint8_t instance_id)
dynamicConnections[nDynamic++] = new AudioConnection(*mono2stereo[instance_id], 0, reverb_mixer_r, instance_id); 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); dynamicConnections[nDynamic++] = new AudioConnection(*mono2stereo[instance_id], 1, reverb_mixer_l, instance_id);
#else #else
//dynamicConnections[nDynamic++] = new AudioConnection(*MicroDexed[instance_id], 0, *mono2stereo[instance_id], 0); dynamicConnections[nDynamic++] = new AudioConnection(*MicroDexed[instance_id], 0, *mono2stereo[instance_id], 0);
dynamicConnections[nDynamic++] = new AudioConnection(*convertf32toi16[instance_id], 0, *mono2stereo[instance_id], 0);
#endif #endif
dynamicConnections[nDynamic++] = new AudioConnection(*mono2stereo[instance_id], 0, master_mixer_r, instance_id); dynamicConnections[nDynamic++] = new AudioConnection(*mono2stereo[instance_id], 0, master_mixer_r, instance_id);
dynamicConnections[nDynamic++] = new AudioConnection(*mono2stereo[instance_id], 1, master_mixer_l, instance_id); dynamicConnections[nDynamic++] = new AudioConnection(*mono2stereo[instance_id], 1, master_mixer_l, instance_id);
@ -230,9 +220,13 @@ void create_audio_engine_chain(uint8_t instance_id)
uint8_t sd_card = 0; uint8_t sd_card = 0;
Sd2Card card; Sd2Card card;
SdVolume volume; SdVolume volume;
uint8_t midi_timing_counter = 0; // 24 per qarter uint8_t midi_ticks[10] = {0, 6, 9, 12, 18, 24, 36, 48, 72, 96};
elapsedMillis midi_timing_timestep; uint8_t midi_bpm_counter = 0;
uint16_t midi_timing_quarter = 0; elapsedMillis midi_bpm;
#ifdef USE_FX
uint8_t midi_timing_counter[NUM_DEXED];
elapsedMillis midi_timing_timer[NUM_DEXED];
#endif
elapsedMillis long_button_pressed; elapsedMillis long_button_pressed;
elapsedMillis control_rate; elapsedMillis control_rate;
uint8_t active_voices[NUM_DEXED]; uint8_t active_voices[NUM_DEXED];
@ -327,7 +321,6 @@ void setup()
setup_midi_devices(); setup_midi_devices();
// Start audio system // Start audio system
AudioMemory_F32(AUDIO_MEM_F32, {44117.0, 128});
AudioMemory(AUDIO_MEM); AudioMemory(AUDIO_MEM);
#if defined(TEENSY_AUDIO_BOARD) #if defined(TEENSY_AUDIO_BOARD)
@ -467,7 +460,6 @@ void setup()
// Initialize processor and memory measurements // Initialize processor and memory measurements
AudioProcessorUsageMaxReset(); AudioProcessorUsageMaxReset();
AudioMemoryUsageMaxReset(); AudioMemoryUsageMaxReset();
AudioMemoryUsageMaxReset_F32();
#ifdef DEBUG #ifdef DEBUG
for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++)
@ -1382,21 +1374,49 @@ void handleTuneRequest(void)
void handleClock(void) void handleClock(void)
{ {
midi_timing_counter++;
if (midi_timing_counter % 24 == 0)
{
midi_timing_quarter = midi_timing_timestep;
midi_timing_counter = 0;
midi_timing_timestep = 0;
// Adjust delay control here
#ifdef DEBUG #ifdef DEBUG
if (midi_bpm_counter % 24 == 0)
{
Serial.print(F("MIDI Clock: ")); Serial.print(F("MIDI Clock: "));
Serial.print(60000 / midi_timing_quarter, DEC); Serial.print(60000.0f / midi_bpm, 2);
Serial.print(F("bpm (")); Serial.print(F("bpm ("));
Serial.print(midi_timing_quarter, DEC); Serial.print(midi_bpm, DEC);
Serial.println(F("ms per quarter)")); Serial.println(F("ms per quarter)"));
midi_bpm = 0;
midi_bpm_counter = 0;
}
midi_bpm_counter++;
#endif #endif
#ifdef USE_FX
for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++)
{
if (midi_ticks[configuration.fx.delay_sync[instance_id]] > 0)
{
/*
1 1/16 = 6 ticks
2 1/16T = 9 ticks
3 1/8 = 12 ticks
4 1/8T = 18 ticks
5 1/4 = 24 ticks
6 1/4T = 36 ticks
7 1/2 = 48 ticks
8 1/2T = 72 ticks
9 1/1 = 96 ticks
*/
if (midi_timing_counter[instance_id] % midi_ticks[configuration.fx.delay_sync[instance_id]] == 0)
{
int32_t t = midi_timing_timer[instance_id];
delay_fx[instance_id]->delay(0, constrain(t, DELAY_TIME_MIN, DELAY_TIME_MAX));
midi_timing_counter[instance_id] = 0;
midi_timing_timer[instance_id] = 0;
}
midi_timing_counter[instance_id]++;
}
} }
#else
;
#endif
} }
void handleStart(void) void handleStart(void)
@ -1645,6 +1665,7 @@ void check_configuration(void)
configuration.fx.delay_time[instance_id] = constrain(configuration.fx.delay_time[instance_id], DELAY_TIME_MIN, DELAY_TIME_MAX); configuration.fx.delay_time[instance_id] = constrain(configuration.fx.delay_time[instance_id], DELAY_TIME_MIN, DELAY_TIME_MAX);
configuration.fx.delay_feedback[instance_id] = constrain(configuration.fx.delay_feedback[instance_id], DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX); configuration.fx.delay_feedback[instance_id] = constrain(configuration.fx.delay_feedback[instance_id], DELAY_FEEDBACK_MIN, DELAY_FEEDBACK_MAX);
configuration.fx.delay_level[instance_id] = constrain(configuration.fx.delay_level[instance_id], DELAY_LEVEL_MIN, DELAY_LEVEL_MAX); configuration.fx.delay_level[instance_id] = constrain(configuration.fx.delay_level[instance_id], DELAY_LEVEL_MIN, DELAY_LEVEL_MAX);
configuration.fx.delay_sync[instance_id] = constrain(configuration.fx.delay_sync[instance_id], DELAY_SYNC_MIN, DELAY_SYNC_MAX);
configuration.fx.reverb_send[instance_id] = constrain(configuration.fx.reverb_send[instance_id], REVERB_SEND_MIN, REVERB_SEND_MAX); configuration.fx.reverb_send[instance_id] = constrain(configuration.fx.reverb_send[instance_id], REVERB_SEND_MIN, REVERB_SEND_MAX);
} }
} }
@ -1721,6 +1742,7 @@ void init_configuration(void)
configuration.fx.delay_time[instance_id] = DELAY_TIME_DEFAULT / 10; configuration.fx.delay_time[instance_id] = DELAY_TIME_DEFAULT / 10;
configuration.fx.delay_feedback[instance_id] = DELAY_FEEDBACK_DEFAULT; configuration.fx.delay_feedback[instance_id] = DELAY_FEEDBACK_DEFAULT;
configuration.fx.delay_level[instance_id] = DELAY_LEVEL_DEFAULT; configuration.fx.delay_level[instance_id] = DELAY_LEVEL_DEFAULT;
configuration.fx.delay_sync[instance_id] = DELAY_SYNC_DEFAULT;
configuration.fx.reverb_send[instance_id] = REVERB_SEND_DEFAULT; configuration.fx.reverb_send[instance_id] = REVERB_SEND_DEFAULT;
configuration.performance.bank[instance_id] = SYSEXBANK_DEFAULT; configuration.performance.bank[instance_id] = SYSEXBANK_DEFAULT;
@ -2241,12 +2263,6 @@ void show_cpu_and_mem_usage(void)
Serial.print(AudioProcessorUsageMax(), 2); Serial.print(AudioProcessorUsageMax(), 2);
Serial.print(F("%|CPUMAXCNT:")); Serial.print(F("%|CPUMAXCNT:"));
Serial.print(cpumax, DEC); Serial.print(cpumax, DEC);
Serial.print(F("|MEM_F32:"));
Serial.print(AudioMemoryUsage_F32(), DEC);
Serial.print(F("|MEMMAX_F32:"));
Serial.print(AudioMemoryUsageMax_F32(), DEC);
Serial.print(F("|AUDIO_MEM_MAX_F32:"));
Serial.print(AUDIO_MEM_F32, DEC);
Serial.print(F("|MEM:")); Serial.print(F("|MEM:"));
Serial.print(AudioMemoryUsage(), DEC); Serial.print(AudioMemoryUsage(), DEC);
Serial.print(F("|MEMMAX:")); Serial.print(F("|MEMMAX:"));
@ -2283,7 +2299,6 @@ void show_cpu_and_mem_usage(void)
#endif #endif
AudioProcessorUsageMaxReset(); AudioProcessorUsageMaxReset();
AudioMemoryUsageMaxReset(); AudioMemoryUsageMaxReset();
AudioMemoryUsageMaxReset_F32();
} }
#endif #endif
@ -2325,6 +2340,7 @@ void show_configuration(void)
Serial.print(F(" Delay Time ")); Serial.println(configuration.fx.delay_time[instance_id], DEC); Serial.print(F(" Delay Time ")); Serial.println(configuration.fx.delay_time[instance_id], DEC);
Serial.print(F(" Delay Feedback ")); Serial.println(configuration.fx.delay_feedback[instance_id], DEC); Serial.print(F(" Delay Feedback ")); Serial.println(configuration.fx.delay_feedback[instance_id], DEC);
Serial.print(F(" Delay Level ")); Serial.println(configuration.fx.delay_level[instance_id], DEC); Serial.print(F(" Delay Level ")); Serial.println(configuration.fx.delay_level[instance_id], DEC);
Serial.print(F(" Delay Sync ")); Serial.println(configuration.fx.delay_sync[instance_id], DEC);
Serial.print(F(" Reverb Send ")); Serial.println(configuration.fx.reverb_send[instance_id], DEC); Serial.print(F(" Reverb Send ")); Serial.println(configuration.fx.reverb_send[instance_id], DEC);
Serial.print(F(" Sound Intensity ")); Serial.println(configuration.dexed[instance_id].sound_intensity, DEC); Serial.print(F(" Sound Intensity ")); Serial.println(configuration.dexed[instance_id].sound_intensity, DEC);
Serial.print(F(" Panorama ")); Serial.println(configuration.dexed[instance_id].pan, DEC); Serial.print(F(" Panorama ")); Serial.println(configuration.dexed[instance_id].pan, DEC);

@ -70,8 +70,7 @@ extern void change_disp_sd(bool d);
#endif #endif
extern AudioControlSGTL5000 sgtl5000_1; extern AudioControlSGTL5000 sgtl5000_1;
//extern AudioSynthDexed* MicroDexed[NUM_DEXED]; extern AudioSynthDexed* MicroDexed[NUM_DEXED];
extern AudioSynthDexed_F32* MicroDexed[NUM_DEXED];
#if defined(USE_FX) #if defined(USE_FX)
extern AudioSynthWaveform* chorus_modulator[NUM_DEXED]; extern AudioSynthWaveform* chorus_modulator[NUM_DEXED];
extern AudioEffectModulatedDelay* modchorus[NUM_DEXED]; extern AudioEffectModulatedDelay* modchorus[NUM_DEXED];

@ -351,7 +351,7 @@
// HELPER MACROS // HELPER MACROS
#define TIME_MS2SAMPLES(x) floor(uint32_t(x) * AUDIO_SAMPLE_RATE / 1000) * sizeof(int16_t) #define TIME_MS2SAMPLES(x) floor(uint32_t(x) * AUDIO_SAMPLE_RATE / 1000) * sizeof(int16_t)
#define SAMPLES2TIME_MS(x) float(uint32_t(x) * 1000 / AUDIO_SAMPLE_RATE * sizeof(int16_t) #define SAMPLES2TIME_MS(x) float(uint32_t(x) * 1000 / AUDIO_SAMPLE_RATE * sizeof(int16_t)
// Modulated delay options // Modulated delay options
#define MOD_NO_FILTER_OUTPUT 0 #define MOD_NO_FILTER_OUTPUT 0
#define MOD_BUTTERWORTH_FILTER_OUTPUT 1 #define MOD_BUTTERWORTH_FILTER_OUTPUT 1
@ -418,6 +418,10 @@
#define DELAY_LEVEL_MAX 100 #define DELAY_LEVEL_MAX 100
#define DELAY_LEVEL_DEFAULT 0 #define DELAY_LEVEL_DEFAULT 0
#define DELAY_SYNC_MIN 0
#define DELAY_SYNC_MAX 9
#define DELAY_SYNC_DEFAULT 0
#define REVERB_ROOMSIZE_MIN 0 #define REVERB_ROOMSIZE_MIN 0
#define REVERB_ROOMSIZE_MAX 100 #define REVERB_ROOMSIZE_MAX 100
#define REVERB_ROOMSIZE_DEFAULT 0 #define REVERB_ROOMSIZE_DEFAULT 0
@ -643,6 +647,7 @@ typedef struct fx_s {
uint8_t delay_time[MAX_DEXED]; uint8_t delay_time[MAX_DEXED];
uint8_t delay_feedback[MAX_DEXED]; uint8_t delay_feedback[MAX_DEXED];
uint8_t delay_level[MAX_DEXED]; uint8_t delay_level[MAX_DEXED];
uint8_t delay_sync[MAX_DEXED];
uint8_t reverb_send[MAX_DEXED]; uint8_t reverb_send[MAX_DEXED];
uint8_t reverb_roomsize; uint8_t reverb_roomsize;
uint8_t reverb_damping; uint8_t reverb_damping;

@ -30,8 +30,7 @@
#define DEXED_SYSEX_H_INCLUDED #define DEXED_SYSEX_H_INCLUDED
extern uint8_t sd_card; extern uint8_t sd_card;
//extern AudioSynthDexed* MicroDexed[NUM_DEXED]; extern AudioSynthDexed* MicroDexed[NUM_DEXED];
extern AudioSynthDexed_F32* MicroDexed[NUM_DEXED];
extern void show_patch(uint8_t instance_id); extern void show_patch(uint8_t instance_id);
extern void send_sysex_voice(uint8_t midi_channel, uint8_t* data); extern void send_sysex_voice(uint8_t midi_channel, uint8_t* data);

@ -398,69 +398,6 @@ void Dexed::getSamples(uint16_t n_samples, int16_t* buffer)
arm_float_to_q15(sumbuf, buffer, AUDIO_BLOCK_SAMPLES); arm_float_to_q15(sumbuf, buffer, AUDIO_BLOCK_SAMPLES);
} }
void Dexed::getSamples(uint16_t n_samples, float32_t* buffer)
{
uint16_t i, j;
uint8_t note;
float s;
const double decayFactor = 0.99992;
if (refreshVoice)
{
for (i = 0; i < max_notes; i++)
{
if (voices[i].live)
voices[i].dx7_note->update(data, voices[i].midi_note, voices[i].velocity, voices[i].porta, &controllers);
}
lfo.reset(data + 137);
refreshVoice = false;
}
for (i = 0; i < n_samples; i += _N_)
{
AlignedBuf<int32_t, _N_> audiobuf;
for (uint8_t j = 0; j < _N_; ++j)
{
audiobuf.get()[j] = 0;
buffer[i + j] = 0.0;
}
int32_t lfovalue = lfo.getsample();
int32_t lfodelay = lfo.getdelay();
for (note = 0; note < max_notes; note++)
{
if (voices[note].live)
{
voices[note].dx7_note->compute(audiobuf.get(), lfovalue, lfodelay, &controllers);
for (j = 0; j < _N_; ++j)
{
buffer[i + j] += static_cast<float>(audiobuf.get()[j]) / 32768.0f;
audiobuf.get()[j] = 0;
}
}
}
}
fx.process(buffer, n_samples); // Needed for fx.Gain()!!!
// mild compression
for (i = 0; i < n_samples; i++)
{
s = abs(buffer[i]);
if (s > vuSignal)
vuSignal = s;
else if (vuSignal > 0.001f)
vuSignal *= decayFactor;
else
vuSignal = 0;
}
arm_scale_f32(buffer, 0.00015, buffer, AUDIO_BLOCK_SAMPLES);
}
void Dexed::keydown(int16_t pitch, uint8_t velo) { void Dexed::keydown(int16_t pitch, uint8_t velo) {
if ( velo == 0 ) { if ( velo == 0 ) {
keyup(pitch); keyup(pitch);

@ -1214,50 +1214,3 @@ class AudioSynthDexed : public AudioStream, public Dexed {
private: private:
volatile bool in_update = false; volatile bool in_update = false;
}; };
class AudioSynthDexed_F32 : public AudioStream_F32, public Dexed {
public:
const uint16_t audio_block_time_us = 1000000 / (SAMPLE_RATE / AUDIO_BLOCK_SAMPLES);
uint32_t xrun = 0;
uint16_t render_time_max = 0;
AudioSynthDexed_F32(int sample_rate) : AudioStream_F32(0, NULL), Dexed(sample_rate) { };
void update(void)
{
if (in_update == true)
{
xrun++;
return;
}
else
in_update = true;
elapsedMicros render_time;
audio_block_f32_t *lblock;
lblock = allocate_f32();
if (!lblock)
{
in_update = false;
return;
}
getSamples(AUDIO_BLOCK_SAMPLES, lblock->data);
if (render_time > audio_block_time_us) // everything greater audio_block_time_us (2.9ms for buffer size of 128) is a buffer underrun!
xrun++;
if (render_time > render_time_max)
render_time_max = render_time;
transmit(lblock, 0);
release(lblock);
in_update = false;
};
private:
volatile bool in_update = false;
};

Loading…
Cancel
Save