diff --git a/MicroMDAEPiano.ino b/MicroMDAEPiano.ino index 0eddd10..45622be 100644 --- a/MicroMDAEPiano.ino +++ b/MicroMDAEPiano.ino @@ -29,7 +29,6 @@ #include #include #include "mdaEPiano.h" -#include "effect_dynamics.h" #ifdef USE_XFADE_DATA #include "mdaEPianoDataXfade.h" #else @@ -56,43 +55,33 @@ Bounce but1 = Bounce(BUT1_PIN, 10); // 10 ms debounce // GUItool: begin automatically generated code AudioPlayQueue queue_r; //xy=494,404 AudioPlayQueue queue_l; //xy=494,404 -AudioAnalyzePeak peak_r; //xy=695,491 -AudioAnalyzePeak peak_l; //xy=695,491 -#ifdef USE_DYNAMICS -AudioEffectDynamics dyna_r; -AudioEffectDynamics dyna_l; -AudioConnection patchCord0(queue_r, dyna_r); -AudioConnection patchCord1(queue_l, dyna_l); -#endif +AudioAnalyzePeak peak_r; //xy=695,491 +AudioAnalyzePeak peak_l; //xy=695,491 +AudioEffectFreeverb freeverb_r; +AudioEffectFreeverb freeverb_l; +AudioMixer4 mixer_r; +AudioMixer4 mixer_l; +AudioConnection patchCord0(queue_r, peak_r); +AudioConnection patchCord1(queue_l, peak_l); +AudioConnection patchCord4(queue_r, freeverb_r); +AudioConnection patchCord5(queue_l, freeverb_l); +AudioConnection patchCord6(queue_r, 0, mixer_r, 0); +AudioConnection patchCord7(queue_l, 0, mixer_l, 0); +AudioConnection patchCord8(freeverb_r, 0, mixer_r, 1); +AudioConnection patchCord9(freeverb_l, 0, mixer_l, 1); #ifdef TEENSY_AUDIO_BOARD AudioOutputI2S i2s1; //xy=1072,364 -#ifdef USE_DYNAMICS -AudioConnection patchCord2(dyna_r, peak_r); -AudioConnection patchCord3(dyna_l, peak_l); -AudioConnection patchCord4(dyna_r, 0, i2s1, 0); -AudioConnection patchCord5(dyna_l, 0, i2s1, 1); -#else -AudioConnection patchCord2(queue_r, peak_r); -AudioConnection patchCord3(queue_l, peak_l); -AudioConnection patchCord4(queue_r, 0, i2s1, 0); -AudioConnection patchCord5(queue_l, 0, i2s1, 1); -#endif +AudioConnection patchCord110(mixer_r, 0, i2s1, 0); +AudioConnection patchCord111(mixer_l, 0, i2s1, 1); AudioControlSGTL5000 sgtl5000_1; //xy=700,536 #else AudioOutputPT8211 pt8211_1; //xy=1079,320 AudioAmplifier volume_r; //xy=818,370 AudioAmplifier volume_l; //xy=818,411 -#ifdef USE_DYNAMICS -AudioConnection patchCord2(dyna_r, volume_r); -AudioConnection patchCord3(dyna_l, volume_l); -#else -AudioConnection patchCord2(queue_r, volume_r); -AudioConnection patchCord3(queue_l, volume_l); -#endif -AudioConnection patchCord4(volume_r, peak_r); -AudioConnection patchCord5(volume_l, peak_l); -AudioConnection patchCord6(volume_r, 0, pt8211_1, 1); -AudioConnection patchCord7(volume_l, 0, pt8211_1, 0); +AudioConnection patchCord10(mixer_r, volume_r); +AudioConnection patchCord11(mixer_l, volume_l); +AudioConnection patchCord12(volume_r, 0, pt8211_1, 1); +AudioConnection patchCord13(volume_l, 0, pt8211_1, 0); #endif // GUItool: end automatically generated code @@ -224,15 +213,16 @@ void setup() ep->setParameter(STEREO, 0.7); ep->setParameter(OVERDRIVE, 0.3); -#ifdef USE_DYNAMICS - dyna_r.limit(-0.1f, 0.2, 0.2); - dyna_l.limit(-0.1f, 0.2, 0.2); - //dyna_r.compression(-10.0, MIN_T, MIN_T, 20.0, 2.0); - //dyna_l.compression(-10.0, MIN_T, MIN_T, 20.0, 2.0); -#endif + freeverb_r.roomsize(0.2); + freeverb_l.roomsize(0.2); + freeverb_r.damping(0.5); + freeverb_l.damping(0.5); + mixer_r.gain(0, 0.7); + mixer_l.gain(0, 0.7); + mixer_r.gain(1, 0.3); + mixer_l.gain(1, 0.3); Serial.println(F("")); - lcd.show(1, 0, 16, ""); #if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC) show_cpu_and_mem_usage(); @@ -295,6 +285,7 @@ void loop() audio_buffer_l[i] *= vol; } #endif + queue_r.playBuffer(); queue_l.playBuffer(); } diff --git a/config.h b/config.h index bbbfe9c..f52ac76 100644 --- a/config.h +++ b/config.h @@ -31,19 +31,19 @@ //#define TEENSY_AUDIO_BOARD 1 #define VOLUME 0.8 #define DEFAULT_MIDI_CHANNEL MIDI_CHANNEL_OMNI -#define AUDIO_MEM 16 +#define AUDIO_MEM 128 #define SAMPLE_RATE 44100 #define REDUCE_LOUDNESS 1 #define USE_XFADE_DATA 1 #if !defined(__MK66FX1M0__) // check for Teensy-3.6 #undef USE_ONBOARD_USB_HOST -#define NVOICES 64 -#else #define NVOICES 32 +#else +#define NVOICES 64 #endif #define USBCON 1 // enabling onboard MIDI via programing connector #define MIDI_MERGE_THRU 1 -//#define USE_DYNAMICS 1 + // Debug output #define SERIAL_SPEED 38400 diff --git a/effect_dynamics.cpp b/effect_dynamics.cpp deleted file mode 100644 index d2d9a03..0000000 --- a/effect_dynamics.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* Audio Library for Teensy 3.X - * Dynamics Processor (Gate, Compressor & Limiter) - * Copyright (c) 2017, Marc Paquette (marc@dacsystemes.com) - * Based on analyse_rms & mixer objects by Paul Stoffregen - * - * Development of this audio library was funded by PJRC.COM, LLC by sales of - * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop - * open source software by purchasing Teensy or other PJRC products. - * - * 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, development funding 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 "effect_dynamics.h" -#include "fast_log.h" -#include "utility/dspinst.h" -#include "utility/sqrt_integer.h" - -static float analyse_rms(int16_t *data) { - - uint32_t *p = (uint32_t *)data; - const uint32_t *end = p + AUDIO_BLOCK_SAMPLES / 2; - int64_t sum = 0; - do { - uint32_t n1 = *p++; - uint32_t n2 = *p++; - uint32_t n3 = *p++; - uint32_t n4 = *p++; - sum = multiply_accumulate_16tx16t_add_16bx16b(sum, n1, n1); - sum = multiply_accumulate_16tx16t_add_16bx16b(sum, n2, n2); - sum = multiply_accumulate_16tx16t_add_16bx16b(sum, n3, n3); - sum = multiply_accumulate_16tx16t_add_16bx16b(sum, n4, n4); - - } while (p < end); - - int32_t meansq = sum / AUDIO_BLOCK_SAMPLES; - return sqrt_uint32(meansq) / 32767.0f; -} - -static void applyGain(int16_t *data, int32_t mult1, int32_t mult2) { - - uint32_t *p = (uint32_t *)data; - const uint32_t *end = p + AUDIO_BLOCK_SAMPLES / 2; - int32_t inc = (mult2 - mult1) / (AUDIO_BLOCK_SAMPLES / 2); - - do { - uint32_t tmp32 = *p; // read 2 samples from *data - int32_t val1 = signed_multiply_32x16b(mult1, tmp32); - mult1 += inc; - int32_t val2 = signed_multiply_32x16t(mult1, tmp32); - mult1 += inc; - val1 = signed_saturate_rshift(val1, 16, 0); - val2 = signed_saturate_rshift(val2, 16, 0); - *p++ = pack_16b_16b(val2, val1); - } while (p < end); -} - -void AudioEffectDynamics::update(void) { - - audio_block_t *block; - - block = receiveWritable(0); - - if (!block) return; - - if (!gateEnabled && !compEnabled && !limiterEnabled) { - - //Transmit & release - transmit(block); - release(block); - return; - } - - //Analyze received block - float rms = analyse_rms(block->data); - - //Compute block RMS level in Db - float inputdb = MIN_DB; - if (rms > 0) inputdb = unitToDb(rms); - - //Gate - if (gateEnabled) { - if (inputdb >= gateThresholdOpen) gatedb = (aGateAttack * gatedb) + (aOneMinusGateAttack * MAX_DB); - else if (inputdb < gateThresholdClose) gatedb = (aGateRelease * gatedb) + (aOneMinusGateRelease * MIN_DB); - } - else gatedb = MAX_DB; - - //Compressor - if (compEnabled) { - float attdb = MAX_DB; //Below knee - if (inputdb >= aLowKnee) { - if(inputdb <= aHighKnee) { - //Knee transition - float knee = inputdb - aLowKnee; - attdb = aKneeRatio * knee * knee * aTwoKneeWidth; - } - else { - //Above knee - attdb = compThreshold + ((inputdb - compThreshold) * compRatio) - inputdb; - } - } - if (attdb <= compdb) compdb = (aCompAttack * compdb) + (aOneMinusCompAttack * attdb); - else compdb = (aCompRelease * compdb) + (aOneMinusCompRelease * attdb); - } - else compdb = MAX_DB; - - //Brickwall Limiter - if (limiterEnabled) { - float outdb = inputdb + compdb + makeupdb; - if (outdb >= limitThreshold) limitdb = (aLimitAttack * limitdb) + (aOneMinusLimitAttack * (limitThreshold - outdb)); - else limitdb *= aLimitRelease; - } - else limitdb = MAX_DB; - - //Compute linear gain - float totalGain = gatedb + compdb + makeupdb + limitdb; - int32_t mult = dbToUnit(totalGain) * 65536.0f; - - //Apply gain to block - applyGain(block->data, last_mult, mult); - last_mult = mult; - - //Transmit & release - transmit(block); - release(block); -} - - - diff --git a/effect_dynamics.h b/effect_dynamics.h deleted file mode 100644 index 9e011ac..0000000 --- a/effect_dynamics.h +++ /dev/null @@ -1,196 +0,0 @@ -/* Audio Library for Teensy 3.X - * Dynamics Processor (Gate, Compressor & Limiter) - * Copyright (c) 2018, Marc Paquette (marc@dacsystemes.com) - * Based on analyse_rms, effect_envelope & mixer objects by Paul Stoffregen - * - * Development of this audio library was funded by PJRC.COM, LLC by sales of - * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop - * open source software by purchasing Teensy or other PJRC products. - * - * 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, development funding 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_dynamics_h_ -#define effect_dynamics_h_ - -#include "Arduino.h" -#include "AudioStream.h" - -#define MIN_DB -110.0f -#define MAX_DB 0.0f - -#define MIN_T 0.03f //Roughly 1 block -#define MAX_T 4.00f - -#define RATIO_OFF 1.0f -#define RATIO_INFINITY 60.0f - -class AudioEffectDynamics : public AudioStream -{ -public: - AudioEffectDynamics(void) : AudioStream(1, inputQueueArray) { - - gate(); - compression(); - limit(); - autoMakeupGain(); - } - - //Sets the gate parameters. - //threshold is in dbFS - //attack & release are in seconds - void gate(float threshold = -50.0f, float attack = MIN_T, float release = 0.3f, float hysterisis = 6.0f) { - - gateEnabled = threshold > MIN_DB; - - gateThresholdOpen = constrain(threshold, MIN_DB, MAX_DB); - gateThresholdClose = gateThresholdOpen - constrain(hysterisis, 0.0f, 6.0f); - - float gateAttackTime = constrain(attack, MIN_T, MAX_T); - float gateReleaseTime = constrain(release, MIN_T, MAX_T); - - aGateAttack = timeToAlpha(gateAttackTime); - aOneMinusGateAttack = 1.0f - aGateAttack; - aGateRelease = timeToAlpha(gateReleaseTime); - aOneMinusGateRelease = 1.0f - aGateRelease; - - gatedb = MIN_DB; - } - - //Sets the compression parameters. - //threshold & kneeWidth are in db(FS) - //attack and release are in seconds - //ratio is expressed as x:1 i.e. 1 for no compression, 60 for brickwall limiting - //Set kneeWidth to 0 for hard knee - void compression(float threshold = -40.0f, float attack = MIN_T, float release = 0.5f, float ratio = 35.0f, float kneeWidth = 6.0f) { - - compEnabled = threshold < MAX_DB; - - compThreshold = constrain(threshold, MIN_DB, MAX_DB); - float compAttackTime = constrain(attack, MIN_T, MAX_T); - float compReleaseTime = constrain(release, MIN_T, MAX_T); - compRatio = 1.0f / constrain(abs(ratio), RATIO_OFF, RATIO_INFINITY); - float compKneeWidth = constrain(abs(kneeWidth), 0.0f, 32.0f); - computeMakeupGain(); - - aCompAttack = timeToAlpha(compAttackTime); - aOneMinusCompAttack = 1.0f - aCompAttack; - aCompRelease = timeToAlpha(compReleaseTime); - aOneMinusCompRelease = 1.0f - aCompRelease; - aHalfKneeWidth = compKneeWidth / 2.0f; - aTwoKneeWidth = 1.0f / (compKneeWidth * 2.0f); - aKneeRatio = compRatio - 1.0f; - aLowKnee = compThreshold - aHalfKneeWidth; - aHighKnee = compThreshold + aHalfKneeWidth; - - compdb = MIN_DB; - } - - //Sets the hard limiter parameters - //threshold is in dbFS - //attack & release are in seconds - void limit(float threshold = -3.0f, float attack = MIN_T, float release = MIN_T) { - - limiterEnabled = threshold < MAX_DB; - - limitThreshold = constrain(threshold, MIN_DB, MAX_DB); - float limitAttackTime = constrain(attack, MIN_T, MAX_T); - float limitReleaseTime = constrain(release, MIN_T, MAX_T); - - computeMakeupGain(); - - aLimitAttack = timeToAlpha(limitAttackTime); - aOneMinusLimitAttack = 1.0f - aLimitAttack; - aLimitRelease = timeToAlpha(limitReleaseTime); - - limitdb = MIN_DB; - } - - //Enables automatic makeup gain setting - //headroom is in dbFS - void autoMakeupGain(float headroom = 6.0f) { - - mgAutoEnabled = true; - mgHeadroom = constrain(headroom, 0.0f, 60.0f); - computeMakeupGain(); - } - - //Sets a fixed makeup gain value. - //gain is in dbFS - void makeupGain(float gain = 0.0f) { - - mgAutoEnabled = false; - makeupdb = constrain(gain, -12.0f, 24.0f); - } - -private: - audio_block_t *inputQueueArray[1]; - - bool gateEnabled = false; - float gateThresholdOpen; - float gateThresholdClose; - float gatedb; - - bool compEnabled = false; - float compThreshold; - float compRatio; - float compdb; - - bool limiterEnabled = false; - float limitThreshold; - float limitdb; - - bool mgAutoEnabled; - float mgHeadroom; - float makeupdb; - - float aGateAttack; - float aOneMinusGateAttack; - float aGateRelease; - float aOneMinusGateRelease; - float aHalfKneeWidth; - float aTwoKneeWidth; - float aKneeRatio; - float aLowKnee; - float aHighKnee; - float aCompAttack; - float aOneMinusCompAttack; - float aCompRelease; - float aOneMinusCompRelease; - float aLimitAttack; - float aOneMinusLimitAttack; - float aLimitRelease; - - int32_t last_mult; - - void computeMakeupGain() { - if (mgAutoEnabled) { - makeupdb = -compThreshold + (compThreshold * compRatio) + limitThreshold - mgHeadroom; - } - } - - //Computes smoothing time constants for a 10% to 90% change - float timeToAlpha(float time) { - return expf(-0.9542f / (((float)AUDIO_SAMPLE_RATE_EXACT / (float)AUDIO_BLOCK_SAMPLES) * time)); - } - - virtual void update(void); -}; - -#endif