diff --git a/MicroDexed.ino b/MicroDexed.ino index ad2e1e2..b3c29ae 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -1814,6 +1814,9 @@ void _softRestart(void) float pseudo_log_curve(float value) { +// ideas from here: https://forum.pjrc.com/threads/56015-Changing-Volume-Levels-based-on-pot-wheel + + const float _pseudo_log = 1048575 / (float)(1 << 20); /* #ifdef DEBUG diff --git a/config.h b/config.h index db59fd0..22b8fc9 100644 --- a/config.h +++ b/config.h @@ -84,7 +84,7 @@ //************************************************************************************************* //* DEBUG OUTPUT SETTINGS //************************************************************************************************* -#define DEBUG 1 +//#define DEBUG 1 #define SERIAL_SPEED 230400 #define SHOW_XRUN 1 #define SHOW_CPU_LOAD_MSEC 5000 diff --git a/dexed.cpp b/dexed.cpp index 1034cf8..233f15f 100644 --- a/dexed.cpp +++ b/dexed.cpp @@ -149,7 +149,7 @@ void Dexed::getSamples(uint16_t n_samples, int16_t* buffer) for (j = 0; j < _N_; ++j) { //sumbuf[i + j] += static_cast(signed_saturate_rshift(audiobuf.get()[j] >> 5, 24, 9)) / 0x8000; - sumbuf[i + j] += signed_saturate_rshift(audiobuf.get()[j] >> 4, 24, 9) / 32768.0; + sumbuf[i + j] += signed_saturate_rshift(audiobuf.get()[j] >> 5, 24, 9) / 32768.0; audiobuf.get()[j] = 0; } } @@ -800,3 +800,82 @@ void Dexed::setPortamentoMode(uint8_t portamento_mode, uint8_t portamento_glissa controllers.refresh(); } + +// https://www.musicdsp.org/en/latest/Effects/169-compressor.html# +void compress + ( + float* wav_in, // signal + int n, // N samples + double threshold, // threshold (percents) + double slope, // slope angle (percents) + int sr, // sample rate (smp/sec) + double tla, // lookahead (ms) + double twnd, // window time (ms) + double tatt, // attack time (ms) + double trel // release time (ms) + ) +{ + typedef float stereodata[2]; + stereodata* wav = (stereodata*) wav_in; // our stereo signal + threshold *= 0.01; // threshold to unity (0...1) + slope *= 0.01; // slope to unity + tla *= 1e-3; // lookahead time to seconds + twnd *= 1e-3; // window time to seconds + tatt *= 1e-3; // attack time to seconds + trel *= 1e-3; // release time to seconds + + // attack and release "per sample decay" + double att = (tatt == 0.0) ? (0.0) : exp (-1.0 / (sr * tatt)); + double rel = (trel == 0.0) ? (0.0) : exp (-1.0 / (sr * trel)); + + // envelope + double env = 0.0; + + // sample offset to lookahead wnd start + int lhsmp = (int) (sr * tla); + + // samples count in lookahead window + int nrms = (int) (sr * twnd); + + // for each sample... + for (int i = 0; i < n; ++i) + { + // now compute RMS + double summ = 0; + + // for each sample in window + for (int j = 0; j < nrms; ++j) + { + int lki = i + j + lhsmp; + double smp; + + // if we in bounds of signal? + // if so, convert to mono + if (lki < n) + smp = 0.5 * wav[lki][0] + 0.5 * wav[lki][1]; + else + smp = 0.0; // if we out of bounds we just get zero in smp + + summ += smp * smp; // square em.. + } + + double rms = sqrt (summ / nrms); // root-mean-square + + // dynamic selection: attack or release? + double theta = rms > env ? att : rel; + + // smoothing with capacitor, envelope extraction... + // here be aware of pIV denormal numbers glitch + env = (1.0 - theta) * rms + theta * env; + + // the very easy hard knee 1:N compressor + double gain = 1.0; + if (env > threshold) + gain = gain - (env - threshold) * slope; + + // result - two hard kneed compressed channels... + float leftchannel = wav[i][0] * gain; + float rightchannel = wav[i][1] * gain; + } +} +