diff --git a/MicroMDAEPiano.ino b/MicroMDAEPiano.ino index 98a53af..2fc8596 100644 --- a/MicroMDAEPiano.ino +++ b/MicroMDAEPiano.ino @@ -3,7 +3,7 @@ MicroMDAEPiano is a port of the MDA-EPiano sound engine (https://sourceforge.net/projects/mda-vst/) for the Teensy-3.5/3.6 with audio shield. - + (c)2019 H. Wirtz This program is free software; you can redistribute it and/or modify @@ -43,6 +43,7 @@ #include #include #include "LiquidCrystalPlus_I2C.h" +#include //for AudioConvert_I16toF32, AudioConvert_F32toI16, and AudioEffectGain_F32 // [I2C] SCL: Pin 19, SDA: Pin 18 (https://www.pjrc.com/teensy/td_libs_Wire.html) #define LCD_I2C_ADDRESS 0x27 @@ -53,27 +54,35 @@ Encoder enc1(ENC1_PIN_A, ENC1_PIN_B); 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 +AudioPlayQueue_F32 queue_r; //xy=494,404 +AudioPlayQueue_F32 queue_l; //xy=494,404 +AudioEffectCompressor_F32 comp_r; +AudioEffectCompressor_F32 comp_l; +AudioConvert_F32toI16 float2Int_r; +AudioConvert_F32toI16 float2Int_l; AudioAnalyzePeak peak_r; //xy=695,491 AudioAnalyzePeak peak_l; //xy=695,491 -AudioConnection patchCord0(queue_l, peak_l); -AudioConnection patchCord1(queue_r, peak_r); +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); +AudioConnection patchCord4(float2Int_r, peak_r); +AudioConnection patchCord5(float2Int_l, peak_l); #ifdef TEENSY_AUDIO_BOARD AudioOutputI2S i2s1; //xy=1072,364 -AudioConnection patchCord2(queue_l, 0, i2s1, 0); -AudioConnection patchCord3(queue_r, 0, i2s1, 1); +AudioConnection patchCord6(float2Int_r, 0, i2s1, 0); +AudioConnection patchCord7(float2Int_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 -AudioConnection patchCord2(queue_l, volume_r); -AudioConnection patchCord3(queue_r, volume_l); -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 patchCord6(float2Int_r, volume_r); +AudioConnection patchCord7(float2Int_l, volume_l); +AudioConnection patchCord8(volume_r, peak_r); +AudioConnection patchCord9(volume_l, peak_l); +AudioConnection patchCord10(volume_r, 0, pt8211_1, 1); +AudioConnection patchCord11(volume_l, 0, pt8211_1, 0); #endif // GUItool: end automatically generated code @@ -164,6 +173,7 @@ void setup() // start audio card AudioMemory(AUDIO_MEM); + AudioMemory_F32(AUDIO_MEM_F32); #ifdef TEENSY_AUDIO_BOARD sgtl5000_1.enable(); @@ -205,6 +215,11 @@ void setup() // DECAY,RELEASE,HARDNESS,TREBLE,PAN_TREM,LFO_RATE,VELOCITY_SENSE,STEREO,MAX_POLY,TUNE,DETUNE,OVERDRIVE + // 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); + Serial.println(F("")); #if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC) @@ -215,8 +230,8 @@ void setup() void loop() { - 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) + float* audio_buffer_r; // pointer to AUDIO_BLOCK_SAMPLES * sizeof(float) + float* audio_buffer_l; // pointer to AUDIO_BLOCK_SAMPLES * sizeof(float) const uint16_t audio_block_time_ms = 1000000 / (SAMPLE_RATE / AUDIO_BLOCK_SAMPLES); // Main sound calculation @@ -255,12 +270,12 @@ void loop() render_time_max = t2; if (peak_r.available()) { - if (peak_r.read() > 0.99) + if (peak_r.read() > 1.00) peak++; } if (peak_l.available()) { - if (peak_l.read() > 0.99) + if (peak_l.read() > 1.00) peak++; } @@ -278,6 +293,17 @@ void loop() handle_input(); } +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); +} + void handle_input(void) { #ifdef USE_ONBOARD_USB_HOST @@ -315,7 +341,7 @@ void handle_input(void) if (but1.update()) ; // place handling of encoder and showing values on lcd here - + } #ifdef DEBUG diff --git a/config.h b/config.h index 6fe2f14..3d594e0 100644 --- a/config.h +++ b/config.h @@ -32,6 +32,7 @@ #define VOLUME 0.8 #define DEFAULT_MIDI_CHANNEL MIDI_CHANNEL_OMNI #define AUDIO_MEM 300 +#define AUDIO_MEM_F32 10 #define SAMPLE_RATE 44100 #define REDUCE_LOUDNESS 0 #define USE_XFADE_DATA 1 diff --git a/mdaEPiano.cpp b/mdaEPiano.cpp index 134ebda..74ea855 100644 --- a/mdaEPiano.cpp +++ b/mdaEPiano.cpp @@ -194,7 +194,7 @@ float mdaEPiano::getParameter(int32_t index) { return programs[curProgram].param[index]; } -void mdaEPiano::process(int16_t *outputs_r, int16_t *outputs_l) +void mdaEPiano::process(float *outputs_r, float *outputs_l) { int16_t v; float x, l, r, od = overdrive; @@ -237,8 +237,8 @@ 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? - outputs_l[frame] += static_cast((l * 0.5) * 0x7fff); - outputs_r[frame] += static_cast((r * 0.5) * 0x7fff); + outputs_l[frame] += l; + outputs_r[frame] += r; } if (fabs(tl) < 1.0e-10) tl = 0.0f; //anti-denormal diff --git a/mdaEPiano.h b/mdaEPiano.h index a47be3c..d432b4f 100644 --- a/mdaEPiano.h +++ b/mdaEPiano.h @@ -79,7 +79,7 @@ public: mdaEPiano(); // mdaEPiano(audioMasterCallback audioMaster); ~mdaEPiano(); - virtual void process(int16_t *outputs_r, int16_t *outputs_l); + virtual void process(float *outputs_r, float *outputs_l); 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);