From 08a1d68a0d91ed9c23664c83e7904219f270b1ff Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Tue, 21 Dec 2021 17:19:58 +0100 Subject: [PATCH] Added stereo modulated delay. --- MicroDexed.ino | 2 +- UI.hpp | 1 + UI_FX_T3_6.h | 1 + UI_FX_T4.h | 1 + UI_NO_FX.h | 1 + config.h | 1 + control_sgtl5000plus.cpp | 1 + control_sgtl5000plus.h | 1 + dexed_sd.cpp | 1 + dexed_sd.h | 1 + disp_plus.h | 3 +- drums.h | 1 + drumset.h | 6 +- effect_freeverb_simd.cpp | 3 +- effect_modulated_delay.cpp | 152 +++++++++++++++++++++++++++++++++++++ effect_modulated_delay.h | 20 +++++ 16 files changed, 190 insertions(+), 6 deletions(-) diff --git a/MicroDexed.ino b/MicroDexed.ino index 31420f6..79d5c90 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -5,7 +5,7 @@ Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android (c)2018-2021 H. Wirtz - (c)2021 M. Koslowski + (c)2021 H. Wirtz , M. Koslowski This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/UI.hpp b/UI.hpp index 0bb40d5..51a5bd6 100644 --- a/UI.hpp +++ b/UI.hpp @@ -6,6 +6,7 @@ Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android (c)2018-2021 H. Wirtz + (c)2021 H. Wirtz , M. Koslowski This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/UI_FX_T3_6.h b/UI_FX_T3_6.h index 6a02b4d..5c0cd61 100644 --- a/UI_FX_T3_6.h +++ b/UI_FX_T3_6.h @@ -6,6 +6,7 @@ Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android (c)2018-2021 H. Wirtz + (c)2021 H. Wirtz , M. Koslowski This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/UI_FX_T4.h b/UI_FX_T4.h index 55bdccc..738ae1e 100644 --- a/UI_FX_T4.h +++ b/UI_FX_T4.h @@ -6,6 +6,7 @@ Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android (c)2018-2021 H. Wirtz + (c)2021 H. Wirtz , M. Koslowski This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/UI_NO_FX.h b/UI_NO_FX.h index 206ad19..ac4e5c1 100644 --- a/UI_NO_FX.h +++ b/UI_NO_FX.h @@ -6,6 +6,7 @@ Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android (c)2018-2021 H. Wirtz + (c)2021 H. Wirtz , M. Koslowski This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/config.h b/config.h index a4d8e2d..579aa43 100644 --- a/config.h +++ b/config.h @@ -6,6 +6,7 @@ Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android (c)2018-2021 H. Wirtz + (c)2021 H. Wirtz , M. Koslowski This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/control_sgtl5000plus.cpp b/control_sgtl5000plus.cpp index 2d6aaa1..579c1c3 100644 --- a/control_sgtl5000plus.cpp +++ b/control_sgtl5000plus.cpp @@ -6,6 +6,7 @@ Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android (c)2018-2021 H. Wirtz + (c)2021 H. Wirtz , M. Koslowski This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/control_sgtl5000plus.h b/control_sgtl5000plus.h index 8fb759a..33eb18e 100644 --- a/control_sgtl5000plus.h +++ b/control_sgtl5000plus.h @@ -6,6 +6,7 @@ Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android (c)2018-2021 H. Wirtz + (c)2021 H. Wirtz , M. Koslowski This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/dexed_sd.cpp b/dexed_sd.cpp index e75dce4..e7aab60 100644 --- a/dexed_sd.cpp +++ b/dexed_sd.cpp @@ -6,6 +6,7 @@ Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android (c)2018-2021 H. Wirtz + (c)2021 H. Wirtz , M. Koslowski This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/dexed_sd.h b/dexed_sd.h index 697eef5..bd03072 100644 --- a/dexed_sd.h +++ b/dexed_sd.h @@ -6,6 +6,7 @@ Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android (c)2018-2021 H. Wirtz + (c)2021 H. Wirtz , M. Koslowski This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/disp_plus.h b/disp_plus.h index 7103fba..dacda2c 100644 --- a/disp_plus.h +++ b/disp_plus.h @@ -5,7 +5,8 @@ (https://github.com/asb2m10/dexed) for the Teensy-3.5/3.6/4.x/4.x with audio shield. Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android - (c)2018 H. Wirtz + (c)2018-2021 H. Wirtz + (c)2021 H. Wirtz , M. Koslowski This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/drums.h b/drums.h index d1793b4..96dec3b 100644 --- a/drums.h +++ b/drums.h @@ -6,6 +6,7 @@ droid (c)2018-2021 H. Wirtz + (c)2021 H. Wirtz , M. Koslowski Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/drumset.h b/drumset.h index 0148c32..9c5f720 100644 --- a/drumset.h +++ b/drumset.h @@ -5,9 +5,9 @@ (https://github.com/asb2m10/dexed) for the Teensy-3.5/3.6/4.x with audio shield. Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android - (c)2018-2021 M. Koslowski - H. Wirtz - + (c)2018-2021 H. Wirtz + (c)2021 H. Wirtz , M. Koslowski + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by (at your option) any later version. diff --git a/effect_freeverb_simd.cpp b/effect_freeverb_simd.cpp index e42d70c..4a73b63 100644 --- a/effect_freeverb_simd.cpp +++ b/effect_freeverb_simd.cpp @@ -7,7 +7,8 @@ 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 + in the Software without restriction (c)2021 H. Wirtz , M. Koslowski +, 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: diff --git a/effect_modulated_delay.cpp b/effect_modulated_delay.cpp index 4cb0c58..e2eb001 100644 --- a/effect_modulated_delay.cpp +++ b/effect_modulated_delay.cpp @@ -164,3 +164,155 @@ void AudioEffectModulatedDelay::update(void) release(block); } } + +boolean AudioEffectModulatedDelayStereo::begin(short *delayline_l, short *delayline_r, uint16_t d_length) +{ +#if 0 + Serial.print(F("AudioEffectModulatedDelayStereo.begin(modulated-delay line length = ")); + Serial.print(d_length); + Serial.println(F(")")); +#endif + + _delay_length = 0; + + _delayline[0] = NULL; + _cb_index[0] = 0; + _delay_offset[0] = 0; + + _delayline[1] = NULL; + _cb_index[1] = 0; + _delay_offset[1] = 0; + + if (delayline_r == NULL) + return (false); + if (delayline_l == NULL) + return (false); + if (d_length < 10) + return (false); + + _delay_length = d_length; + + _delayline[0] = delayline_l; + memset(_delayline[0], 0, _delay_length * sizeof(int16_t)); + _delay_offset[0] = _delay_length >> 1 ; + + _delayline[1] = delayline_r; + memset(_delayline[1], 0, _delay_length * sizeof(int16_t)); + _delay_offset[1] = _delay_length >> 1 ; + + return (true); +} + +uint16_t AudioEffectModulatedDelayStereo::get_delay_length(void) +{ + return (_delay_length); +} + +void AudioEffectModulatedDelayStereo::update(void) +{ + audio_block_t *block[2]; + audio_block_t *modulation; + + if (_delayline == NULL) + return; + + block[0] = receiveWritable(0); + if (!block[0]) + block[0] = (audio_block_t*)&zeroblock; + + block[1] = receiveWritable(1); + if (!block[1]) + block[1] = (audio_block_t*)&zeroblock; + + modulation = receiveReadOnly(2); + if (!modulation) + modulation = (audio_block_t*)&zeroblock; + + if (block[0] && block[1] && modulation) + { + int16_t *bp[2]; + int16_t cb_mod_index_neighbor[2]; + float *mp; + float mod_index; + float mod_number; + float mod_fraction; + float modulation_f32[AUDIO_BLOCK_SAMPLES]; + + bp[0] = block[0]->data; + bp[1] = block[1]->data; + + arm_q15_to_float(modulation->data, modulation_f32, AUDIO_BLOCK_SAMPLES); + mp = modulation_f32; + + for (uint16_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++) + { + // LEFT + // calculate the modulation-index as a floating point number for interpolation + mod_index = *mp * _delay_offset[0]; + mod_fraction = modff(mod_index, &mod_number); // split float of mod_index into integer (= mod_number) and fraction part + + // write data into circular buffer (delayline) + if (_cb_index[0] >= _delay_length) + _cb_index[0] = 0; + _delayline[0][_cb_index[0]] = *bp[0]; + + // calculate modulation index into circular buffer + cb_mod_index[0] = _cb_index[0] - (_delay_offset[0] + mod_number); + if (cb_mod_index[0] < 0) // check for negative offsets and correct them + cb_mod_index[0] += _delay_length; + + if (cb_mod_index[0] == _delay_length - 1) + cb_mod_index_neighbor[0] = 0; + else + cb_mod_index_neighbor[0] = cb_mod_index[0] + 1; + + *bp[0] = round(float(_delayline[0][cb_mod_index[0]]) * mod_fraction + float(_delayline[0][cb_mod_index_neighbor[0]]) * (1.0 - mod_fraction)); + + // push the pointers forward + bp[0]++; // next audio data + _cb_index[0]++; // next circular buffer index + + // RIGHT + // calculate the modulation-index as a floating point number for interpolation + mod_index = -1.0 * *mp * _delay_offset[0]; + mod_fraction = modff(mod_index, &mod_number); // split float of mod_index into integer (= mod_number) and fraction part + + // write data into circular buffer (delayline) + if (_cb_index[1] >= _delay_length) + _cb_index[1] = 0; + _delayline[1][_cb_index[1]] = *bp[1]; + + // calculate modulation index into circular buffer + cb_mod_index[1] = _cb_index[1] - (_delay_offset[1] + mod_number); + if (cb_mod_index[1] < 0) // check for negative offsets and correct them + cb_mod_index[1] += _delay_length; + + if (cb_mod_index[1] == _delay_length - 1) + cb_mod_index_neighbor[1] = 0; + else + cb_mod_index_neighbor[1] = cb_mod_index[1] + 1; + + *bp[1] = round(float(_delayline[1][cb_mod_index[1]]) * mod_fraction + float(_delayline[1][cb_mod_index_neighbor[1]]) * (1.0 - mod_fraction)); + + // push the pointers forward + bp[1]++; // next audio data + _cb_index[1]++; // next circular buffer index + + mp++; // next modulation data + } + } + + if (modulation != (audio_block_t*)&zeroblock) + release(modulation); + + if (block[0] != (audio_block_t*)&zeroblock) + { + transmit(block[0], 0); + release(block[0]); + } + if (block[1] != (audio_block_t*)&zeroblock) + { + transmit(block[1], 0); + release(block[1]); + } +} diff --git a/effect_modulated_delay.h b/effect_modulated_delay.h index bf80a21..624b671 100644 --- a/effect_modulated_delay.h +++ b/effect_modulated_delay.h @@ -55,4 +55,24 @@ class AudioEffectModulatedDelay : uint16_t _delay_offset; }; +class AudioEffectModulatedDelayStereo : + public AudioStream +{ + public: + AudioEffectModulatedDelayStereo(void): + AudioStream(3, inputQueueArray) + { } + + boolean begin(short *delayline_l, short *delayline_r, uint16_t delay_length); + virtual void update(void); + virtual uint16_t get_delay_length(void); + + private: + audio_block_t *inputQueueArray[3]; + int16_t *_delayline[2]; // pointer for the circular buffer + uint16_t _cb_index[2]; // current write pointer of the circular buffer + uint16_t _delay_length; // calculated number of samples of the delay + int16_t cb_mod_index[2]; // current read pointer with modulation for the circular buffer + uint16_t _delay_offset[2]; +}; #endif