diff --git a/MicroDexed.ino b/MicroDexed.ino index 9d70815..a542b5c 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -24,7 +24,6 @@ #include #include "config.h" #include -#include #include #include #include @@ -44,9 +43,7 @@ #include "UI.hpp" // Audio engines -//AudioSynthDexed* MicroDexed[NUM_DEXED]; -AudioSynthDexed_F32* MicroDexed[NUM_DEXED]; -AudioConvert_F32toI16* convertf32toi16[NUM_DEXED]; +AudioSynthDexed* MicroDexed[NUM_DEXED]; #if defined(USE_FX) AudioSynthWaveform* chorus_modulator[NUM_DEXED]; #if MOD_FILTER_OUTPUT != MOD_NO_FILTER_OUTPUT @@ -179,9 +176,7 @@ AudioConnection * dynamicConnections[NUM_DEXED * 5]; #endif void create_audio_engine_chain(uint8_t instance_id) { - //MicroDexed[instance_id] = new AudioSynthDexed(SAMPLE_RATE); - MicroDexed[instance_id] = new AudioSynthDexed_F32(SAMPLE_RATE); - convertf32toi16[instance_id] = new AudioConvert_F32toI16(); + MicroDexed[instance_id] = new AudioSynthDexed(SAMPLE_RATE); mono2stereo[instance_id] = new AudioEffectMonoStereo(); #if defined(USE_FX) chorus_modulator[instance_id] = new AudioSynthWaveform(); @@ -196,14 +191,10 @@ void create_audio_engine_chain(uint8_t instance_id) #endif 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) 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(*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 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); @@ -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], 1, reverb_mixer_l, instance_id); #else - //dynamicConnections[nDynamic++] = new AudioConnection(*MicroDexed[instance_id], 0, *mono2stereo[instance_id], 0); - dynamicConnections[nDynamic++] = new AudioConnection(*convertf32toi16[instance_id], 0, *mono2stereo[instance_id], 0); + dynamicConnections[nDynamic++] = new AudioConnection(*MicroDexed[instance_id], 0, *mono2stereo[instance_id], 0); #endif 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); @@ -230,9 +220,13 @@ void create_audio_engine_chain(uint8_t instance_id) uint8_t sd_card = 0; Sd2Card card; SdVolume volume; -uint8_t midi_timing_counter = 0; // 24 per qarter -elapsedMillis midi_timing_timestep; -uint16_t midi_timing_quarter = 0; +uint8_t midi_ticks[10] = {0, 6, 9, 12, 18, 24, 36, 48, 72, 96}; +uint8_t midi_bpm_counter = 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 control_rate; uint8_t active_voices[NUM_DEXED]; @@ -327,7 +321,6 @@ void setup() setup_midi_devices(); // Start audio system - AudioMemory_F32(AUDIO_MEM_F32, {44117.0, 128}); AudioMemory(AUDIO_MEM); #if defined(TEENSY_AUDIO_BOARD) @@ -467,7 +460,6 @@ void setup() // Initialize processor and memory measurements AudioProcessorUsageMaxReset(); AudioMemoryUsageMaxReset(); - AudioMemoryUsageMaxReset_F32(); #ifdef DEBUG for (uint8_t instance_id = 0; instance_id < NUM_DEXED; instance_id++) @@ -1382,21 +1374,49 @@ void handleTuneRequest(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 + if (midi_bpm_counter % 24 == 0) + { 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(midi_timing_quarter, DEC); + Serial.print(midi_bpm, DEC); Serial.println(F("ms per quarter)")); + midi_bpm = 0; + midi_bpm_counter = 0; + } + midi_bpm_counter++; #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) @@ -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_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_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); } } @@ -1721,6 +1742,7 @@ void init_configuration(void) configuration.fx.delay_time[instance_id] = DELAY_TIME_DEFAULT / 10; configuration.fx.delay_feedback[instance_id] = DELAY_FEEDBACK_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.performance.bank[instance_id] = SYSEXBANK_DEFAULT; @@ -2241,12 +2263,6 @@ void show_cpu_and_mem_usage(void) Serial.print(AudioProcessorUsageMax(), 2); Serial.print(F("%|CPUMAXCNT:")); 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(AudioMemoryUsage(), DEC); Serial.print(F("|MEMMAX:")); @@ -2283,7 +2299,6 @@ void show_cpu_and_mem_usage(void) #endif AudioProcessorUsageMaxReset(); AudioMemoryUsageMaxReset(); - AudioMemoryUsageMaxReset_F32(); } #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 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 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(" Sound Intensity ")); Serial.println(configuration.dexed[instance_id].sound_intensity, DEC); Serial.print(F(" Panorama ")); Serial.println(configuration.dexed[instance_id].pan, DEC); diff --git a/UI.hpp b/UI.hpp index bc663e7..85bea83 100644 --- a/UI.hpp +++ b/UI.hpp @@ -70,8 +70,7 @@ extern void change_disp_sd(bool d); #endif extern AudioControlSGTL5000 sgtl5000_1; -//extern AudioSynthDexed* MicroDexed[NUM_DEXED]; -extern AudioSynthDexed_F32* MicroDexed[NUM_DEXED]; +extern AudioSynthDexed* MicroDexed[NUM_DEXED]; #if defined(USE_FX) extern AudioSynthWaveform* chorus_modulator[NUM_DEXED]; extern AudioEffectModulatedDelay* modchorus[NUM_DEXED]; diff --git a/config.h b/config.h index 01b1749..ffe9815 100644 --- a/config.h +++ b/config.h @@ -351,7 +351,7 @@ // HELPER MACROS #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 #define MOD_NO_FILTER_OUTPUT 0 #define MOD_BUTTERWORTH_FILTER_OUTPUT 1 @@ -418,6 +418,10 @@ #define DELAY_LEVEL_MAX 100 #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_MAX 100 #define REVERB_ROOMSIZE_DEFAULT 0 @@ -643,6 +647,7 @@ typedef struct fx_s { uint8_t delay_time[MAX_DEXED]; uint8_t delay_feedback[MAX_DEXED]; uint8_t delay_level[MAX_DEXED]; + uint8_t delay_sync[MAX_DEXED]; uint8_t reverb_send[MAX_DEXED]; uint8_t reverb_roomsize; uint8_t reverb_damping; diff --git a/dexed_sd.h b/dexed_sd.h index 7720bce..33f4a5e 100644 --- a/dexed_sd.h +++ b/dexed_sd.h @@ -30,8 +30,7 @@ #define DEXED_SYSEX_H_INCLUDED extern uint8_t sd_card; -//extern AudioSynthDexed* MicroDexed[NUM_DEXED]; -extern AudioSynthDexed_F32* MicroDexed[NUM_DEXED]; +extern AudioSynthDexed* MicroDexed[NUM_DEXED]; extern void show_patch(uint8_t instance_id); extern void send_sysex_voice(uint8_t midi_channel, uint8_t* data); diff --git a/synth_dexed.cpp b/synth_dexed.cpp index 26db1f7..f57ec2d 100644 --- a/synth_dexed.cpp +++ b/synth_dexed.cpp @@ -398,69 +398,6 @@ void Dexed::getSamples(uint16_t n_samples, int16_t* buffer) 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 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(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) { if ( velo == 0 ) { keyup(pitch); diff --git a/synth_dexed.h b/synth_dexed.h index 1046095..2fd961f 100644 --- a/synth_dexed.h +++ b/synth_dexed.h @@ -1214,50 +1214,3 @@ class AudioSynthDexed : public AudioStream, public Dexed { private: 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; -};