From be8f93b9762c3ca702ee2f5d44a055fa00cc7fd6 Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Thu, 10 Jan 2019 10:24:03 +0100 Subject: [PATCH] Added compressor code. Fixes. --- MicroMDAEPiano.ino | 104 +++++++---------------- config.h | 3 +- effect_dynamics.cpp | 144 ++++++++++++++++++++++++++++++++ effect_dynamics.h | 196 ++++++++++++++++++++++++++++++++++++++++++++ fast_log.h | 50 +++++++++++ mdaEPiano.cpp | 21 ++--- mdaEPiano.h | 4 - 7 files changed, 429 insertions(+), 93 deletions(-) create mode 100644 effect_dynamics.cpp create mode 100644 effect_dynamics.h create mode 100644 fast_log.h diff --git a/MicroMDAEPiano.ino b/MicroMDAEPiano.ino index df24407..9019b7e 100644 --- a/MicroMDAEPiano.ino +++ b/MicroMDAEPiano.ino @@ -22,17 +22,14 @@ */ #include "config.h" -#ifdef USE_F32 -#include //for AudioConvert_I16toF32, AudioConvert_F32toI16, and AudioEffectGain_F32 -#else #include -#endif #include #include #include #include #include #include "mdaEPiano.h" +#include "effect_dynamics.h" #ifdef USE_XFADE_DATA #include "mdaEPianoDataXfade.h" #else @@ -57,37 +54,23 @@ Encoder enc1(ENC1_PIN_A, ENC1_PIN_B); Bounce but1 = Bounce(BUT1_PIN, 10); // 10 ms debounce // GUItool: begin automatically generated code -#ifdef USE_F32 -AudioPlayQueue_F32 queue_r; //xy=494,404 -AudioPlayQueue_F32 queue_l; //xy=494,404 -AudioConvert_F32toI16 float2Int_r; -AudioConvert_F32toI16 float2Int_l; -#else AudioPlayQueue queue_r; //xy=494,404 AudioPlayQueue queue_l; //xy=494,404 -#endif AudioAnalyzePeak peak_r; //xy=695,491 AudioAnalyzePeak peak_l; //xy=695,491 -#ifdef USE_F32 -#ifdef USE_COMP_F32 -AudioEffectCompressor_F32 comp_r; -AudioEffectCompressor_F32 comp_l; -AudioConnection_F32 patchCord0(queue_r, comp_r); -AudioConnection_F32 patchCord1(queue_l, comp_l); -AudioConnection_F32 patchCord2(comp_r, float2Int_r); -AudioConnection_F32 patchCord3(comp_l, float2Int_l); -#else -AudioConnection_F32 patchCord0(queue_r, float2Int_r); -AudioConnection_F32 patchCord1(queue_l, float2Int_l); -#endif +#ifdef USE_DYNAMICS +AudioEffectDynamics dyna_r; +AudioEffectDynamics dyna_l; +AudioConnection patchCord2(queue_r, dyna_r); +AudioConnection patchCord3(queue_l, dyna_l); #endif #ifdef TEENSY_AUDIO_BOARD AudioOutputI2S i2s1; //xy=1072,364 -#ifdef USE_F32 -AudioConnection patchCord4(float2Int_r, peak_r); -AudioConnection patchCord5(float2Int_l, peak_l); -AudioConnection patchCord6(float2Int_r, 0, i2s1, 0); -AudioConnection patchCord7(float2Int_l, 0, i2s1, 1); +#ifdef USE_DYNAMICS +AudioConnection patchCord4(dyna_r, peak_r); +AudioConnection patchCord5(dyna_l, peak_l); +AudioConnection patchCord6(dyna_r, 0, i2s1, 0); +AudioConnection patchCord7(dyna_l, 0, i2s1, 1); #else AudioConnection patchCord4(queue_r, peak_r); AudioConnection patchCord5(queue_l, peak_l); @@ -99,17 +82,17 @@ AudioControlSGTL5000 sgtl5000_1; //xy=700,536 AudioOutputPT8211 pt8211_1; //xy=1079,320 AudioAmplifier volume_r; //xy=818,370 AudioAmplifier volume_l; //xy=818,411 -#ifdef USE_F32 -AudioConnection patchCord4(float2Int_r, volume_r); -AudioConnection patchCord5(float2Int_l, volume_l); +#ifdef USE_DYNAMICS +AudioConnection patchCord2(dyna_r, volume_r); +AudioConnection patchCord3(dyna_l, volume_l); #else -AudioConnection patchCord4(queue_r, volume_r); -AudioConnection patchCord5(queue_l, volume_l); +AudioConnection patchCord2(queue_r, volume_r); +AudioConnection patchCord3(queue_l, volume_l); #endif -AudioConnection patchCord6(volume_r, peak_r); -AudioConnection patchCord7(volume_l, peak_l); -AudioConnection patchCord8(volume_r, 0, pt8211_1, 1); -AudioConnection patchCord9(volume_l, 0, pt8211_1, 0); +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); #endif // GUItool: end automatically generated code @@ -118,7 +101,6 @@ uint8_t midi_channel = DEFAULT_MIDI_CHANNEL; uint32_t xrun = 0; uint32_t overload = 0; uint32_t peak = 0; -uint32_t audio_buffer_problem = 0; uint16_t render_time_max = 0; float vol = VOLUME; float vol_right = 1.0; @@ -201,9 +183,6 @@ void setup() // start audio card AudioMemory(AUDIO_MEM); -#ifdef USE_F32 - AudioMemory_F32(AUDIO_MEM_F32); -#endif #ifdef TEENSY_AUDIO_BOARD sgtl5000_1.enable(); @@ -236,26 +215,27 @@ void setup() sched_note_off.begin(note_off, 6333333); #endif + ep->setParameter(DECAY, 0.5); + ep->setParameter(RELEASE, 0.5); ep->setParameter(HARDNESS, 0.7); ep->setParameter(TREBLE, 0.85); ep->setParameter(DETUNE, 0.1); - ep->setParameter(VELOCITY_SENSE, 0.2); + ep->setParameter(VELOCITY_SENSE, 1.0); ep->setParameter(STEREO, 0.7); ep->setParameter(MAX_POLY, 1.0); ep->setParameter(OVERDRIVE, 0.3); - // DECAY,RELEASE,HARDNESS,TREBLE,PAN_TREM,LFO_RATE,VELOCITY_SENSE,STEREO,MAX_POLY,TUNE,DETUNE,OVERDRIVE + // DECAY,RELEASE,HARDNESS,TREBLE,PAN_TREM,LFO_RATE,VELOCIT -#if defined(USE_F32) && defined(USE_COMP_F32) - // setup compressor as limiter - setup_compressor(true, -15.0f, 5.0f, 0.005f, 0.200f); - // setup compressor like an automatic volume control - //setup_compressor(true,-50.0,5.0,1.0,2.0); - comp_r.setPreGain_dB(0.0); - comp_l.setPreGain_dB(0.0); +#ifdef USE_DYNAMICS + //dyna_r.limit(); + //dyna_l.limit(); + 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 Serial.println(F("")); + lcd.show(1, 0, 16, ""); #if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC) show_cpu_and_mem_usage(); @@ -265,13 +245,8 @@ void setup() void loop() { -#if defined(USE_F32) - float* audio_buffer_r; // pointer to AUDIO_BLOCK_SAMPLES * sizeof(float) - float* audio_buffer_l; // pointer to AUDIO_BLOCK_SAMPLES * sizeof(float) -#else int16_t* audio_buffer_r; // pointer to AUDIO_BLOCK_SAMPLES * sizeof(int16_t) int16_t* audio_buffer_l; // pointer to AUDIO_BLOCK_SAMPLES * sizeof(int16_t) -#endif const uint16_t audio_block_time_ms = 1000000 / (SAMPLE_RATE / AUDIO_BLOCK_SAMPLES); // Main sound calculation @@ -326,27 +301,10 @@ void loop() queue_r.playBuffer(); queue_l.playBuffer(); } - else - { - audio_buffer_problem++; - } handle_input(); } -#if defined(USE_F32) && defined(USE_COMP_F32) -void setup_compressor(boolean use_HP_filter, float knee_dBFS, float comp_ratio, float attack_sec, float release_sec) -{ - comp_r.enableHPFilter(use_HP_filter); comp_l.enableHPFilter(use_HP_filter); - comp_r.setThresh_dBFS(knee_dBFS); comp_l.setThresh_dBFS(knee_dBFS); - comp_r.setCompressionRatio(comp_ratio); comp_l.setCompressionRatio(comp_ratio); - - float fs_Hz = AUDIO_SAMPLE_RATE; - comp_r.setAttack_sec(attack_sec, fs_Hz); comp_l.setAttack_sec(attack_sec, fs_Hz); - comp_r.setRelease_sec(release_sec, fs_Hz); comp_l.setRelease_sec(release_sec, fs_Hz); -} -#endif - void handle_input(void) { #ifdef USE_ONBOARD_USB_HOST @@ -579,8 +537,6 @@ void show_cpu_and_mem_usage(void) Serial.print(overload, DEC); Serial.print(F(" PEAK: ")); Serial.print(peak, DEC); - Serial.print(F(" AUDIO_BUF_ERR: ")); - Serial.print(audio_buffer_problem, DEC); Serial.println(); AudioProcessorUsageMaxReset(); AudioMemoryUsageMaxReset(); diff --git a/config.h b/config.h index 1ae996e..8364c0b 100644 --- a/config.h +++ b/config.h @@ -34,9 +34,8 @@ #define AUDIO_MEM 16 #define AUDIO_MEM_F32 16 #define SAMPLE_RATE 44100 -#define REDUCE_LOUDNESS 1 +#define REDUCE_LOUDNESS 0 #define USE_XFADE_DATA 1 -//#define USE_COMP_F32 1 #if !defined(__MK66FX1M0__) // check for Teensy-3.6 #undef USE_ONBOARD_USB_HOST #define NVOICES 32 diff --git a/effect_dynamics.cpp b/effect_dynamics.cpp new file mode 100644 index 0000000..d2d9a03 --- /dev/null +++ b/effect_dynamics.cpp @@ -0,0 +1,144 @@ +/* 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 new file mode 100644 index 0000000..9e011ac --- /dev/null +++ b/effect_dynamics.h @@ -0,0 +1,196 @@ +/* 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 diff --git a/fast_log.h b/fast_log.h new file mode 100644 index 0000000..3e2c24b --- /dev/null +++ b/fast_log.h @@ -0,0 +1,50 @@ +/* ---------------------------------------------------------------------- +* https://community.arm.com/tools/f/discussions/4292/cmsis-dsp-new-functionality-proposal/22621#22621 +* Fast approximation to the log2() function. It uses a two step +* process. First, it decomposes the floating-point number into +* a fractional component F and an exponent E. The fraction component +* is used in a polynomial approximation and then the exponent added +* to the result. A 3rd order polynomial is used and the result +* when computing db20() is accurate to 7.984884e-003 dB. +** ------------------------------------------------------------------- */ + +float log2f_approx_coeff[4] = {1.23149591368684f, -4.11852516267426f, 6.02197014179219f, -3.13396450166353f}; + +float log2f_approx(float X) +{ + float *C = &log2f_approx_coeff[0]; + float Y; + float F; + int E; + + // This is the approximation to log2() + F = frexpf(fabsf(X), &E); + + // Y = C[0]*F*F*F + C[1]*F*F + C[2]*F + C[3] + E; + Y = *C++; + Y *= F; + Y += (*C++); + Y *= F; + Y += (*C++); + Y *= F; + Y += (*C++); + Y += E; + return(Y); +} + +// https://codingforspeed.com/using-faster-exponential-approximation/ +inline float expf_approx(float x) { + x = 1.0f + x / 1024; + x *= x; x *= x; x *= x; x *= x; + x *= x; x *= x; x *= x; x *= x; + x *= x; x *= x; + return x; +} + +inline float unitToDb(float unit) { + return 6.02f * log2f_approx(unit); +} + +inline float dbToUnit(float db) { + return expf_approx(db * 2.302585092994046f * 0.05f); +} \ No newline at end of file diff --git a/mdaEPiano.cpp b/mdaEPiano.cpp index 7cff176..c2ebe56 100644 --- a/mdaEPiano.cpp +++ b/mdaEPiano.cpp @@ -171,10 +171,6 @@ void mdaEPiano::setParameter(int32_t index, float value) { programs[curProgram].param[index] = value; update(); - - //if(editor) editor->postUpdate(); ///For GUI - - guiUpdate = index + 0x100 + (guiUpdate & 0xFFFF00); } @@ -194,11 +190,7 @@ float mdaEPiano::getParameter(int32_t index) { return programs[curProgram].param[index]; } -#ifdef USE_F32 -void mdaEPiano::process(float* outputs_r, float* outputs_l) -#else void mdaEPiano::process(int16_t* outputs_r, int16_t* outputs_l) -#endif { int16_t v; float x, l, r, od = overdrive; @@ -241,13 +233,16 @@ void mdaEPiano::process(int16_t* outputs_r, int16_t* outputs_l) l += l * lmod * lfo1; r += r * rmod * lfo1; //worth making all these local variables? -#ifdef USE_F32 - outputs_l[frame] += l; - outputs_r[frame] += r; -#else + if (r > 1.0) + r = 1.0; + else if (r < -1.0) + r = -1.0; + if (l > 1.0) + l = 1.0; + else if (l < -1.0) + l = -1.0; outputs_l[frame] = static_cast(l * 0x7fff) >> REDUCE_LOUDNESS; outputs_r[frame] = static_cast(r * 0x7fff) >> REDUCE_LOUDNESS; -#endif } if (fabs(tl) < 1.0e-10) tl = 0.0f; //anti-denormal diff --git a/mdaEPiano.h b/mdaEPiano.h index 952dd35..e308833 100644 --- a/mdaEPiano.h +++ b/mdaEPiano.h @@ -79,11 +79,7 @@ class mdaEPiano //: public AudioEffectX mdaEPiano(); // mdaEPiano(audioMasterCallback audioMaster); ~mdaEPiano(); -#ifdef USE_F32 - virtual void process(float *outputs_r, float *outputs_l); -#else virtual void process(int16_t *outputs_r, int16_t *outputs_l); -#endif virtual bool processMidiMessage(uint8_t type, uint8_t data1, uint8_t data2); virtual void setProgram(int32_t program); virtual void setParameter(int32_t index, float value);