From d52b4e68f8773a501f5dbb440e313af019d04903 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Sun, 15 Oct 2023 15:19:58 -0400 Subject: [PATCH 01/38] add env follower mode to sidechain compressor --- src/definitions_cxx.hpp | 1 + src/deluge/dsp/compressor/compressor.cpp | 21 +++++++++++++++++---- src/deluge/dsp/compressor/compressor.h | 2 +- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/definitions_cxx.hpp b/src/definitions_cxx.hpp index b5ad645c65..145d77e149 100644 --- a/src/definitions_cxx.hpp +++ b/src/definitions_cxx.hpp @@ -326,6 +326,7 @@ enum class EnvelopeStage : uint8_t { SUSTAIN, RELEASE, FAST_RELEASE, + HOLD, OFF, }; constexpr int32_t kNumEnvelopeStages = util::to_underlying(EnvelopeStage::OFF) + 1; diff --git a/src/deluge/dsp/compressor/compressor.cpp b/src/deluge/dsp/compressor/compressor.cpp index 6460a9bd89..fcc55aca24 100644 --- a/src/deluge/dsp/compressor/compressor.cpp +++ b/src/deluge/dsp/compressor/compressor.cpp @@ -26,6 +26,7 @@ Compressor::Compressor() { status = EnvelopeStage::OFF; lastValue = 2147483647; pos = 0; + follower = false; attack = getParamFromUserValue(Param::Static::COMPRESSOR_ATTACK, 7); release = getParamFromUserValue(Param::Static::COMPRESSOR_RELEASE, 28); pendingHitStrength = 0; @@ -47,6 +48,7 @@ Compressor::Compressor() { } void Compressor::cloneFrom(Compressor* other) { + follower = other->follower; attack = other->attack; release = other->release; syncLevel = other->syncLevel; @@ -142,17 +144,28 @@ int32_t Compressor::render(uint16_t numSamples, int32_t shapeValue) { envelopeHeight = lastValue - envelopeOffset; pos = 0; } + //or if we're working in follower mode, in which case we want to start releasing whenever the current hit strength is below the envelope level + else if (follower) { + envelopeOffset = newOffset; + goto prepareForRelease; + } } if (status == EnvelopeStage::ATTACK) { pos += numSamples * getActualAttackRate(); if (pos >= 8388608) { + if (!follower) { prepareForRelease: - pos = 0; - status = EnvelopeStage::RELEASE; - envelopeHeight = ONE_Q31 - envelopeOffset; - goto doRelease; + pos = 0; + status = EnvelopeStage::RELEASE; + envelopeHeight = ONE_Q31 - envelopeOffset; + goto doRelease; + } + else { + pos = 0; + status = EnvelopeStage::OFF; + } } //lastValue = (multiply_32x32_rshift32(envelopeHeight, decayTable4[pos >> 13]) << 1) + envelopeOffset; // Goes down quickly at first. Bad //lastValue = (multiply_32x32_rshift32(envelopeHeight, 2147483647 - (pos << 8)) << 1) + envelopeOffset; // Straight line diff --git a/src/deluge/dsp/compressor/compressor.h b/src/deluge/dsp/compressor/compressor.h index c48cc96040..b9c81d9309 100644 --- a/src/deluge/dsp/compressor/compressor.h +++ b/src/deluge/dsp/compressor/compressor.h @@ -26,7 +26,7 @@ class Compressor { public: Compressor(); void cloneFrom(Compressor* other); - + bool follower; EnvelopeStage status; uint32_t pos; int32_t lastValue; From db22570af62864ffe939a28deb8186621321e590 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Sun, 15 Oct 2023 18:22:34 -0400 Subject: [PATCH 02/38] use hold in comp --- src/deluge/dsp/compressor/compressor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deluge/dsp/compressor/compressor.cpp b/src/deluge/dsp/compressor/compressor.cpp index fcc55aca24..0eb50b382a 100644 --- a/src/deluge/dsp/compressor/compressor.cpp +++ b/src/deluge/dsp/compressor/compressor.cpp @@ -164,7 +164,7 @@ int32_t Compressor::render(uint16_t numSamples, int32_t shapeValue) { } else { pos = 0; - status = EnvelopeStage::OFF; + status = EnvelopeStage::HOLD; } } //lastValue = (multiply_32x32_rshift32(envelopeHeight, decayTable4[pos >> 13]) << 1) + envelopeOffset; // Goes down quickly at first. Bad From eae5f04ab141bac85a89e9e4649488d39b1a4396 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Mon, 16 Oct 2023 01:28:46 -0400 Subject: [PATCH 03/38] barebones working --- src/deluge/dsp/compressor/compressor.cpp | 4 +- .../master_compressor/master_compressor.cpp | 99 ++++++---- .../dsp/master_compressor/master_compressor.h | 34 ++-- src/deluge/gui/views/arranger_view.cpp | 12 +- src/deluge/gui/views/session_view.cpp | 176 +----------------- src/deluge/model/song/song.cpp | 30 ++- .../processing/engines/audio_engine.cpp | 2 +- 7 files changed, 100 insertions(+), 257 deletions(-) diff --git a/src/deluge/dsp/compressor/compressor.cpp b/src/deluge/dsp/compressor/compressor.cpp index 0eb50b382a..714c4ac9dd 100644 --- a/src/deluge/dsp/compressor/compressor.cpp +++ b/src/deluge/dsp/compressor/compressor.cpp @@ -48,7 +48,6 @@ Compressor::Compressor() { } void Compressor::cloneFrom(Compressor* other) { - follower = other->follower; attack = other->attack; release = other->release; syncLevel = other->syncLevel; @@ -145,7 +144,7 @@ int32_t Compressor::render(uint16_t numSamples, int32_t shapeValue) { pos = 0; } //or if we're working in follower mode, in which case we want to start releasing whenever the current hit strength is below the envelope level - else if (follower) { + else if (follower && newOffset > lastValue) { envelopeOffset = newOffset; goto prepareForRelease; } @@ -155,6 +154,7 @@ int32_t Compressor::render(uint16_t numSamples, int32_t shapeValue) { pos += numSamples * getActualAttackRate(); if (pos >= 8388608) { + //if we're in follower mode then we just hold the value if (!follower) { prepareForRelease: pos = 0; diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 82ce3aa798..6124e27173 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -19,55 +19,76 @@ #include "dsp/stereo_sample.h" MasterCompressor::MasterCompressor() { - compressor.setSampleRate(kSampleRate); - compressor.initRuntime(); - compressor.setAttack(10.0); - compressor.setRelease(100.0); - compressor.setThresh(0.0); //threshold (dB) 0...-69 - compressor.setRatio(1.0 / 4.00); //ratio (compression: < 1 ; expansion: > 1) - makeup = 1.0; //value; - gr = 0.0; - wet = 1.0; + //compressor.setAttack((float)attack / 100.0); + attack = attackRateTable[7] << 1; + release = releaseRateTable[35]; + //compressor.setRelease((float)release / 100.0); + //compressor.setThresh((float)threshold / 100.0); + //compressor.setRatio(1.0 / ((float)ratio / 100.0)); + shape = -601295438; + threshold = 1 * 21474836; + follower = true; + amount = 25 * 85899345; + currentVolume = 0; } //with floats baseline is 60-90us -void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, int32_t masterVolumeAdjustmentL, - int32_t masterVolumeAdjustmentR) { +void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { + meanVolume = calc_rms(buffer, numSamples); + over = log(meanVolume + 1) * (1 << 25); + registerHit(over); + out = Compressor::render(numSamples, shape); + //copied from global effectable + int32_t positivePatchedValue = multiply_32x32_rshift32(out, amount) + 536870912; + finalVolume = multiply_32x32_rshift32(positivePatchedValue, positivePatchedValue) << 4; + + amplitudeIncrement = (int32_t)(finalVolume - currentVolume) / numSamples; StereoSample* thisSample = buffer; StereoSample* bufferEnd = buffer + numSamples; - if (compressor.getThresh() < -0.001) { - do { - //correct for input level - float l = lshiftAndSaturate<5>(thisSample->l) / (float)ONE_Q31; - float r = lshiftAndSaturate<5>(thisSample->r) / (float)ONE_Q31; - float rawl = l; - float rawr = r; - compressor.process(l, r); - if (thisSample == bufferEnd - 1 && fabs(rawl) > 0.00000001 && fabs(rawr) > 0.00000001) { - gr = chunkware_simple::lin2dB(l / rawl); - gr = std::min(gr, chunkware_simple::lin2dB(r / rawr)); - } - l = l * makeup; - r = r * makeup; + do { + + currentVolume += amplitudeIncrement; + + // Apply post-fx and post-reverb-send volume + thisSample->l = multiply_32x32_rshift32(thisSample->l, currentVolume) << 1; + thisSample->r = multiply_32x32_rshift32(thisSample->r, currentVolume) << 1; - if (wet < 0.9999) { - l = rawl * (1.0 - wet) + l * wet; - r = rawr * (1.0 - wet) + r * wet; - } + } while (++thisSample != bufferEnd); + //for LEDs + gr = 4 * (clz(currentVolume) - 1); +} - thisSample->l = l * ONE_Q31 / (1 << 5); - thisSample->r = r * ONE_Q31 / (1 << 5); +q31_t MasterCompressor::calc_rms(StereoSample* buffer, uint16_t numSamples) { + StereoSample* thisSample = buffer; + StereoSample* bufferEnd = buffer + numSamples; + q31_t sum = 0; + do { + q31_t s = std::max(0, std::abs(thisSample->l) + std::abs(thisSample->r)); + sum += s; - } while (++thisSample != bufferEnd); - } + } while (++thisSample != bufferEnd); + return sum / numSamples; } + void MasterCompressor::setup(int32_t attack, int32_t release, int32_t threshold, int32_t ratio, int32_t makeup, int32_t mix) { - compressor.setAttack((float)attack / 100.0); - compressor.setRelease((float)release / 100.0); - compressor.setThresh((float)threshold / 100.0); - compressor.setRatio(1.0 / ((float)ratio / 100.0)); - setMakeup((float)makeup / 100.0); - wet = (float)makeup / 100.0; + //compressor.setAttack((float)attack / 100.0); + // attack = attackRateTable[attack] << 2; + // release = attackRateTable[attack] << 2; + // //compressor.setRelease((float)release / 100.0); + // //compressor.setThresh((float)threshold / 100.0); + // //compressor.setRatio(1.0 / ((float)ratio / 100.0)); + // amount = ratio * 21474836; + // threshold = threshold * 21474836; } + +/* + masterCompressorAttack = 7; + masterCompressorRelease = 10; + masterCompressorThresh = 10; + masterCompressorRatio = 10; + masterCompressorMakeup = 0; + masterCompressorWet = 50; + +*/ diff --git a/src/deluge/dsp/master_compressor/master_compressor.h b/src/deluge/dsp/master_compressor/master_compressor.h index 4b9afa1d7c..526a940094 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.h +++ b/src/deluge/dsp/master_compressor/master_compressor.h @@ -17,8 +17,9 @@ #pragma once -#include "chunkware_simplecomp.h" #include "definitions_cxx.hpp" +#include "dsp/compressor/compressor.h" +#include "util/functions.h" #define INLINE inline #include // for min(), max() @@ -26,26 +27,21 @@ #include #include -class MasterCompressor { +class MasterCompressor : public Compressor { public: MasterCompressor(); void setup(int32_t attack, int32_t release, int32_t threshold, int32_t ratio, int32_t makeup, int32_t mix); - void render(StereoSample* buffer, uint16_t numSamples, int32_t masterVolumeAdjustmentL, - int32_t masterVolumeAdjustmentR); - float makeup; - float gr; - float wet; - inline void setMakeup(float dB) { - makeup = pow(10.0, (dB / 20.0)); - if (fabs(1.0 - makeup) < 0.0001) - makeup = 1.0; - if (makeup > 20.0) - makeup = 20.0; - if (makeup < 0.0001) - makeup = 0.0; - } - inline float getMakeup() { return 20.0 * log10(makeup); } - - chunkware_simple::SimpleComp compressor; + void render(StereoSample* buffer, uint16_t numSamples); + q31_t calc_rms(StereoSample* buffer, uint16_t numSamples); + q31_t gr; + q31_t threshold; + q31_t shape; + q31_t amount; + q31_t out; + q31_t meanVolume; + q31_t over; + q31_t finalVolume; + q31_t currentVolume; + q31_t amplitudeIncrement; }; diff --git a/src/deluge/gui/views/arranger_view.cpp b/src/deluge/gui/views/arranger_view.cpp index 3efae8511e..8e04a7f3cb 100644 --- a/src/deluge/gui/views/arranger_view.cpp +++ b/src/deluge/gui/views/arranger_view.cpp @@ -2916,14 +2916,10 @@ void ArrangerView::graphicsRoutine() { modKnobMode = *modKnobModePointer; } - if (modKnobMode == 4 && abs(AudioEngine::mastercompressor.compressor.getThresh()) > 0.001) { //upper - double gr = AudioEngine::mastercompressor.gr; - if (gr >= 0) - gr = 0; - if (gr <= -12) - gr = -12.0; - gr = abs(gr); - indicator_leds::setKnobIndicatorLevel(1, int32_t(gr / 12.0 * 128)); //Gain Reduction LED + if (modKnobMode == 4) { //upper + int32_t gr = AudioEngine::mastercompressor.gr; + + indicator_leds::setKnobIndicatorLevel(1, gr); //Gain Reduction LED } } diff --git a/src/deluge/gui/views/session_view.cpp b/src/deluge/gui/views/session_view.cpp index f9776b5643..64719d09fa 100644 --- a/src/deluge/gui/views/session_view.cpp +++ b/src/deluge/gui/views/session_view.cpp @@ -1978,14 +1978,10 @@ void SessionView::graphicsRoutine() { if (modKnobModePointer) modKnobMode = *modKnobModePointer; } - if (modKnobMode == 4 && abs(AudioEngine::mastercompressor.compressor.getThresh()) > 0.001) { //upper - double gr = AudioEngine::mastercompressor.gr; - if (gr >= 0) - gr = 0; - if (gr <= -12) - gr = -12.0; - gr = abs(gr); - indicator_leds::setKnobIndicatorLevel(1, int32_t(gr / 12.0 * 128)); //Gain Reduction LED + if (modKnobMode == 4) { //upper + int32_t gr = AudioEngine::mastercompressor.gr; + + indicator_leds::setKnobIndicatorLevel(1, gr); //Gain Reduction LED } } @@ -2717,170 +2713,6 @@ void SessionView::modEncoderAction(int32_t whichModEncoder, int32_t offset) { if (modKnobModePointer) modKnobMode = *modKnobModePointer; } - if (modKnobMode == 4 && whichModEncoder == 1) { //upper encoder - - if (masterCompEditMode == 0) { //Thresh DB - double thresh = AudioEngine::mastercompressor.compressor.getThresh(); - thresh = thresh - (offset * .2); - if (thresh >= 0) - thresh = 0; - if (thresh < -69) - thresh = -69; - AudioEngine::mastercompressor.compressor.setThresh(thresh); - if (display->have7SEG()) { - char buffer[6]; - strcpy(buffer, ""); - floatToString(thresh, buffer + strlen(buffer), 1, 1); - if (abs(thresh) < 0.01) - strcpy(buffer, "OFF"); - display->displayPopup(buffer); - } - } - else if (masterCompEditMode == 1) { //Makeup DB - double makeup = AudioEngine::mastercompressor.getMakeup(); - makeup = makeup + (offset * 0.1); - if (makeup < 0) - makeup = 0; - if (makeup > 20) - makeup = 20; - AudioEngine::mastercompressor.setMakeup(makeup); - if (display->have7SEG()) { - char buffer[6]; - strcpy(buffer, ""); - floatToString(makeup, buffer + strlen(buffer), 1, 1); - display->displayPopup(buffer); - } - } - else if (masterCompEditMode == 2) { //Attack ms - double atk = AudioEngine::mastercompressor.compressor.getAttack(); - atk = atk + offset * 0.1; - if (atk <= 0.1) - atk = 0.1; - if (atk >= 30.0) - atk = 30.0; - AudioEngine::mastercompressor.compressor.setAttack(atk); - if (display->have7SEG()) { - char buffer[5]; - strcpy(buffer, ""); - floatToString(atk, buffer + strlen(buffer), 1, 1); - display->displayPopup(buffer); - } - } - else if (masterCompEditMode == 3) { //Release ms - double rel = AudioEngine::mastercompressor.compressor.getRelease(); - rel = rel + offset * 100.0; - if (rel <= 100) - rel = 100.0; - if (rel >= 1200.0) - rel = 1200.0; - AudioEngine::mastercompressor.compressor.setRelease(rel); - if (display->have7SEG()) { - char buffer[6]; - strcpy(buffer, ""); - intToString(int32_t(rel), buffer + strlen(buffer)); - display->displayPopup(buffer); - } - } - else if (masterCompEditMode == 4) { //Ratio R:1 - double ratio = 1.0 / AudioEngine::mastercompressor.compressor.getRatio(); - ratio = ratio + offset * 0.1; - if (ratio <= 2.0) - ratio = 2.0; - if (ratio >= 10.0) - ratio = 10.0; - AudioEngine::mastercompressor.compressor.setRatio(1.0 / ratio); - if (display->have7SEG()) { - char buffer[5]; - strcpy(buffer, ""); - floatToString(ratio, buffer + strlen(buffer), 1, 1); - display->displayPopup(buffer); - } - } - else if (masterCompEditMode == 5) { //Wet 0.0 - 1.0 - double wet = AudioEngine::mastercompressor.wet; - wet += offset * 0.01; - if (wet <= 0.0) - wet = 0.0; - if (wet >= 1.0) - wet = 1.0; - AudioEngine::mastercompressor.wet = wet; - if (display->have7SEG()) { - char buffer[6]; - strcpy(buffer, ""); - intToString(int32_t(wet * 100), buffer + strlen(buffer)); - display->displayPopup(buffer); - } - } - - if (display->haveOLED()) { //Master Compressor OLED UI - double thresh = AudioEngine::mastercompressor.compressor.getThresh(); - double makeup = AudioEngine::mastercompressor.getMakeup(); - double atk = AudioEngine::mastercompressor.compressor.getAttack(); - double rel = AudioEngine::mastercompressor.compressor.getRelease(); - double ratio = 1.0 / AudioEngine::mastercompressor.compressor.getRatio(); - double wet = AudioEngine::mastercompressor.wet; - int32_t paddingLeft = 4 + 3; - int32_t paddingTop = OLED_MAIN_TOPMOST_PIXEL + 2; - - deluge::hid::display::OLED::setupPopup(OLED_MAIN_WIDTH_PIXELS - 2, OLED_MAIN_VISIBLE_HEIGHT - 2); - char buffer[18]; - strcpy(buffer, "MASTER COMP"); - deluge::hid::display::OLED::drawStringCentred( - buffer, paddingTop + kTextSpacingY * 0 - 1, deluge::hid::display::OLED::oledMainPopupImage[0], - OLED_MAIN_WIDTH_PIXELS - 2, kTextSpacingX + 1, kTextSpacingY); - deluge::hid::display::OLED::drawStringCentred( - buffer, paddingTop + kTextSpacingY * 0 - 1, deluge::hid::display::OLED::oledMainPopupImage[0], - OLED_MAIN_WIDTH_PIXELS - 2, kTextSpacingX + 1, kTextSpacingY, (OLED_MAIN_WIDTH_PIXELS >> 1) + 1); - strcpy(buffer, "THR GAI"); - deluge::hid::display::OLED::drawString(buffer, paddingLeft, paddingTop + kTextSpacingY * 1, - deluge::hid::display::OLED::oledMainPopupImage[0], - OLED_MAIN_WIDTH_PIXELS - 2, kTextSpacingX, kTextSpacingY); - strcpy(buffer, "ATK REL"); - deluge::hid::display::OLED::drawString(buffer, paddingLeft, paddingTop + kTextSpacingY * 2, - deluge::hid::display::OLED::oledMainPopupImage[0], - OLED_MAIN_WIDTH_PIXELS - 2, kTextSpacingX, kTextSpacingY); - strcpy(buffer, "RAT MIX"); - deluge::hid::display::OLED::drawString(buffer, paddingLeft, paddingTop + kTextSpacingY * 3, - deluge::hid::display::OLED::oledMainPopupImage[0], - OLED_MAIN_WIDTH_PIXELS - 2, kTextSpacingX, kTextSpacingY); - - floatToString(thresh, buffer, 1, 1); - if (abs(thresh) < 0.01) - strcpy(buffer, "OFF"); - deluge::hid::display::OLED::drawStringAlignRight( - buffer, paddingTop + kTextSpacingY * 1, deluge::hid::display::OLED::oledMainPopupImage[0], - OLED_MAIN_WIDTH_PIXELS - 2, kTextSpacingX, kTextSpacingY, paddingLeft + kTextSpacingX * 9); - floatToString(makeup, buffer, 1, 1); - deluge::hid::display::OLED::drawStringAlignRight( - buffer, paddingTop + kTextSpacingY * 1, deluge::hid::display::OLED::oledMainPopupImage[0], - OLED_MAIN_WIDTH_PIXELS - 2, kTextSpacingX, kTextSpacingY, paddingLeft + kTextSpacingX * 19); - floatToString(atk, buffer, 1, 1); - deluge::hid::display::OLED::drawStringAlignRight( - buffer, paddingTop + kTextSpacingY * 2, deluge::hid::display::OLED::oledMainPopupImage[0], - OLED_MAIN_WIDTH_PIXELS - 2, kTextSpacingX, kTextSpacingY, paddingLeft + kTextSpacingX * 9); - intToString(int32_t(rel), buffer); - deluge::hid::display::OLED::drawStringAlignRight( - buffer, paddingTop + kTextSpacingY * 2, deluge::hid::display::OLED::oledMainPopupImage[0], - OLED_MAIN_WIDTH_PIXELS - 2, kTextSpacingX, kTextSpacingY, paddingLeft + kTextSpacingX * 19); - floatToString(ratio, buffer, 1, 1); - deluge::hid::display::OLED::drawStringAlignRight( - buffer, paddingTop + kTextSpacingY * 3, deluge::hid::display::OLED::oledMainPopupImage[0], - OLED_MAIN_WIDTH_PIXELS - 2, kTextSpacingX, kTextSpacingY, paddingLeft + kTextSpacingX * 9); - intToString(int32_t(wet * 100), buffer); - strcpy(buffer + strlen(buffer), "%"); - deluge::hid::display::OLED::drawStringAlignRight( - buffer, paddingTop + kTextSpacingY * 3, deluge::hid::display::OLED::oledMainPopupImage[0], - OLED_MAIN_WIDTH_PIXELS - 2, kTextSpacingX, kTextSpacingY, paddingLeft + kTextSpacingX * 19); - - deluge::hid::display::OLED::invertArea( - (kTextSpacingX * 10) * (masterCompEditMode % 2) + paddingLeft, kTextSpacingX * 9, - kTextSpacingY * (int32_t)(masterCompEditMode / 2 + 1) + paddingTop, - kTextSpacingY * (int32_t)(masterCompEditMode / 2 + 2) + paddingTop, - deluge::hid::display::OLED::oledMainPopupImage); - deluge::hid::display::OLED::sendMainImage(); - uiTimerManager.setTimer(TIMER_DISPLAY, 1500); - } - } } if (getCurrentUI() == this) { //This routine may also be called from the Arranger view ClipNavigationTimelineView::modEncoderAction(whichModEncoder, offset); diff --git a/src/deluge/model/song/song.cpp b/src/deluge/model/song/song.cpp index 1dc7f90c13..edd1aefeea 100644 --- a/src/deluge/model/song/song.cpp +++ b/src/deluge/model/song/song.cpp @@ -136,12 +136,12 @@ Song::Song() : backedUpParamManagers(sizeof(BackedUpParamManager)) { reverbCompressorShape = -601295438; reverbCompressorSync = SYNC_LEVEL_8TH; - masterCompressorAttack = 10.0; - masterCompressorRelease = 100.0; - masterCompressorThresh = 0.0; - masterCompressorRatio = 1.0 / 4.0; - masterCompressorMakeup = 0.0; - masterCompressorWet = 1.0; + masterCompressorAttack = 7; + masterCompressorRelease = 10; + masterCompressorThresh = 10; + masterCompressorRatio = 10; + masterCompressorMakeup = 0; + masterCompressorWet = 50; AudioEngine::mastercompressor.gr = 0.0; dirPath.set("SONGS"); @@ -1126,18 +1126,16 @@ void Song::writeToFile() { if (runtimeFeatureSettings.get(RuntimeFeatureSettingType::MasterCompressorFx) == RuntimeFeatureStateToggle::On) { storageManager.writeOpeningTagBeginning("masterCompressor"); - int32_t attack = AudioEngine::mastercompressor.compressor.getAttack() * 100; - int32_t release = AudioEngine::mastercompressor.compressor.getRelease() * 100; - int32_t thresh = AudioEngine::mastercompressor.compressor.getThresh() * 100.0; - int32_t ratio = 1.0 / AudioEngine::mastercompressor.compressor.getRatio() * 100; - int32_t makeup = AudioEngine::mastercompressor.getMakeup() * 100; - int32_t wet = AudioEngine::mastercompressor.wet * 100; + int32_t attack = AudioEngine::mastercompressor.attack; + int32_t release = AudioEngine::mastercompressor.release; + int32_t thresh = AudioEngine::mastercompressor.threshold; + int32_t ratio = AudioEngine::mastercompressor.amount; + storageManager.writeAttribute("attack", attack); storageManager.writeAttribute("release", release); storageManager.writeAttribute("thresh", thresh); storageManager.writeAttribute("ratio", ratio); - storageManager.writeAttribute("makeup", makeup); - storageManager.writeAttribute("wet", wet); + storageManager.closeTag(); } @@ -2687,7 +2685,7 @@ int32_t Song::getCurrentPresetScale() { // If we're here, must be this one! return p; -notThisOne : {} +notThisOne: {} } return 255; @@ -4576,7 +4574,7 @@ Instrument* Song::changeInstrumentType(Instrument* oldInstrument, InstrumentType return NULL; } -gotAnInstrument : {} +gotAnInstrument: {} } // Synth or Kit diff --git a/src/deluge/processing/engines/audio_engine.cpp b/src/deluge/processing/engines/audio_engine.cpp index 625d9675e6..0952cc2f4d 100644 --- a/src/deluge/processing/engines/audio_engine.cpp +++ b/src/deluge/processing/engines/audio_engine.cpp @@ -754,7 +754,7 @@ void routine() { } } logAction("mastercomp start"); - mastercompressor.render(renderingBuffer, numSamples, masterVolumeAdjustmentL, masterVolumeAdjustmentR); + mastercompressor.render(renderingBuffer, numSamples); masterVolumeAdjustmentL <<= 2; masterVolumeAdjustmentR <<= 2; logAction("mastercomp end"); From a43066e9e3e821dff0c1eaef49b81ae6c839820a Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Mon, 16 Oct 2023 11:20:26 -0400 Subject: [PATCH 04/38] working comp, no controls --- src/deluge/dsp/compressor/compressor.cpp | 5 +++- .../master_compressor/master_compressor.cpp | 23 +++++++++++-------- .../dsp/master_compressor/master_compressor.h | 3 ++- src/deluge/gui/views/session_view.cpp | 5 ++-- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/deluge/dsp/compressor/compressor.cpp b/src/deluge/dsp/compressor/compressor.cpp index 714c4ac9dd..af0b773b17 100644 --- a/src/deluge/dsp/compressor/compressor.cpp +++ b/src/deluge/dsp/compressor/compressor.cpp @@ -136,6 +136,7 @@ int32_t Compressor::render(uint16_t numSamples, int32_t shapeValue) { // If attack is all the way down, jump directly to release stage if (attack == attackRateTable[0] << 2) { + envelopeHeight = ONE_Q31 - envelopeOffset; goto prepareForRelease; } @@ -146,6 +147,7 @@ int32_t Compressor::render(uint16_t numSamples, int32_t shapeValue) { //or if we're working in follower mode, in which case we want to start releasing whenever the current hit strength is below the envelope level else if (follower && newOffset > lastValue) { envelopeOffset = newOffset; + envelopeHeight = envelopeOffset - lastValue; goto prepareForRelease; } } @@ -156,10 +158,11 @@ int32_t Compressor::render(uint16_t numSamples, int32_t shapeValue) { if (pos >= 8388608) { //if we're in follower mode then we just hold the value if (!follower) { + envelopeHeight = ONE_Q31 - envelopeOffset; prepareForRelease: pos = 0; status = EnvelopeStage::RELEASE; - envelopeHeight = ONE_Q31 - envelopeOffset; + goto doRelease; } else { diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 6124e27173..4b46e2c1c4 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -20,26 +20,26 @@ MasterCompressor::MasterCompressor() { //compressor.setAttack((float)attack / 100.0); - attack = attackRateTable[7] << 1; - release = releaseRateTable[35]; + attack = attackRateTable[7] << 2; + release = releaseRateTable[35] >> 1; //compressor.setRelease((float)release / 100.0); //compressor.setThresh((float)threshold / 100.0); //compressor.setRatio(1.0 / ((float)ratio / 100.0)); - shape = -601295438; - threshold = 1 * 21474836; + shape = 0; + threshold = 8 * 1 << 25; follower = true; amount = 25 * 85899345; + syncLevel = SyncLevel::SYNC_LEVEL_NONE; currentVolume = 0; } //with floats baseline is 60-90us void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { meanVolume = calc_rms(buffer, numSamples); - over = log(meanVolume + 1) * (1 << 25); - registerHit(over); + registerHit(std::max(0, meanVolume - threshold)); out = Compressor::render(numSamples, shape); //copied from global effectable int32_t positivePatchedValue = multiply_32x32_rshift32(out, amount) + 536870912; - finalVolume = multiply_32x32_rshift32(positivePatchedValue, positivePatchedValue) << 4; + finalVolume = lshiftAndSaturate<5>(multiply_32x32_rshift32(positivePatchedValue, positivePatchedValue)); amplitudeIncrement = (int32_t)(finalVolume - currentVolume) / numSamples; @@ -56,7 +56,8 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { } while (++thisSample != bufferEnd); //for LEDs - gr = 4 * (clz(currentVolume) - 1); + + gr = (ONE_Q31 - currentVolume) >> 24; } q31_t MasterCompressor::calc_rms(StereoSample* buffer, uint16_t numSamples) { @@ -64,11 +65,13 @@ q31_t MasterCompressor::calc_rms(StereoSample* buffer, uint16_t numSamples) { StereoSample* bufferEnd = buffer + numSamples; q31_t sum = 0; do { - q31_t s = std::max(0, std::abs(thisSample->l) + std::abs(thisSample->r)); + q31_t s = std::max(std::abs(thisSample->l), std::abs(thisSample->r)); sum += s; } while (++thisSample != bufferEnd); - return sum / numSamples; + mean = sum / numSamples + mean >> 3; + //16 is 0dB + return (log(mean + 1)) * (1 << 25); } void MasterCompressor::setup(int32_t attack, int32_t release, int32_t threshold, int32_t ratio, int32_t makeup, diff --git a/src/deluge/dsp/master_compressor/master_compressor.h b/src/deluge/dsp/master_compressor/master_compressor.h index 526a940094..61b0fc6f7a 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.h +++ b/src/deluge/dsp/master_compressor/master_compressor.h @@ -34,7 +34,7 @@ class MasterCompressor : public Compressor { void render(StereoSample* buffer, uint16_t numSamples); q31_t calc_rms(StereoSample* buffer, uint16_t numSamples); - q31_t gr; + uint8_t gr; q31_t threshold; q31_t shape; q31_t amount; @@ -44,4 +44,5 @@ class MasterCompressor : public Compressor { q31_t finalVolume; q31_t currentVolume; q31_t amplitudeIncrement; + q31_t mean; }; diff --git a/src/deluge/gui/views/session_view.cpp b/src/deluge/gui/views/session_view.cpp index 64719d09fa..7a8a9ad831 100644 --- a/src/deluge/gui/views/session_view.cpp +++ b/src/deluge/gui/views/session_view.cpp @@ -1979,9 +1979,10 @@ void SessionView::graphicsRoutine() { modKnobMode = *modKnobModePointer; } if (modKnobMode == 4) { //upper - int32_t gr = AudioEngine::mastercompressor.gr; - + uint8_t gr = AudioEngine::mastercompressor.gr; + uint8_t mv = AudioEngine::mastercompressor.meanVolume >> 22; indicator_leds::setKnobIndicatorLevel(1, gr); //Gain Reduction LED + indicator_leds::setKnobIndicatorLevel(0, mv); //Gain Reduction LED } } From 6fd19d992ed2cd693ee799794a490bd2f6418108 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Mon, 16 Oct 2023 15:34:47 -0400 Subject: [PATCH 05/38] scaled appropriately --- src/deluge/dsp/compressor/compressor.cpp | 30 +++++++++++-------- .../master_compressor/master_compressor.cpp | 19 +++++++----- src/deluge/gui/views/session_view.cpp | 2 +- src/deluge/processing/sound/sound.cpp | 10 ++++--- 4 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/deluge/dsp/compressor/compressor.cpp b/src/deluge/dsp/compressor/compressor.cpp index af0b773b17..cf73e5645e 100644 --- a/src/deluge/dsp/compressor/compressor.cpp +++ b/src/deluge/dsp/compressor/compressor.cpp @@ -125,11 +125,11 @@ int32_t Compressor::getActualReleaseRate() { int32_t Compressor::render(uint16_t numSamples, int32_t shapeValue) { // Initial hit detected... - if (pendingHitStrength != 0) { + if (pendingHitStrength != 0 || follower) { int32_t newOffset = ONE_Q31 - pendingHitStrength; pendingHitStrength = 0; - + //envelope offset is the value we're attack/decaying to // Only actually do anything if this hit is going to cause a bigger dip than we're already currently experiencing if (newOffset < lastValue) { envelopeOffset = newOffset; @@ -137,21 +137,26 @@ int32_t Compressor::render(uint16_t numSamples, int32_t shapeValue) { // If attack is all the way down, jump directly to release stage if (attack == attackRateTable[0] << 2) { envelopeHeight = ONE_Q31 - envelopeOffset; - goto prepareForRelease; + pos = 0; + status = EnvelopeStage::RELEASE; + } + if (status != EnvelopeStage::ATTACK) { + status = EnvelopeStage::ATTACK; + pos = 0; } - status = EnvelopeStage::ATTACK; envelopeHeight = lastValue - envelopeOffset; - pos = 0; } //or if we're working in follower mode, in which case we want to start releasing whenever the current hit strength is below the envelope level - else if (follower && newOffset > lastValue) { + else if (follower && newOffset > envelopeOffset) { envelopeOffset = newOffset; - envelopeHeight = envelopeOffset - lastValue; - goto prepareForRelease; + envelopeHeight = newOffset - lastValue; + if (status != EnvelopeStage::RELEASE) { + pos = 0; + status = EnvelopeStage::RELEASE; + } } } - if (status == EnvelopeStage::ATTACK) { pos += numSamples * getActualAttackRate(); @@ -159,6 +164,7 @@ int32_t Compressor::render(uint16_t numSamples, int32_t shapeValue) { //if we're in follower mode then we just hold the value if (!follower) { envelopeHeight = ONE_Q31 - envelopeOffset; + envelopeOffset = ONE_Q31; prepareForRelease: pos = 0; status = EnvelopeStage::RELEASE; @@ -166,8 +172,8 @@ int32_t Compressor::render(uint16_t numSamples, int32_t shapeValue) { goto doRelease; } else { - pos = 0; status = EnvelopeStage::HOLD; + goto doOff; } } //lastValue = (multiply_32x32_rshift32(envelopeHeight, decayTable4[pos >> 13]) << 1) + envelopeOffset; // Goes down quickly at first. Bad @@ -207,7 +213,7 @@ int32_t Compressor::render(uint16_t numSamples, int32_t shapeValue) { preValue = straightness * (pos >> 8) + (getDecay8(8388608 - pos, 23) >> 16) * curvedness16; } - lastValue = ONE_Q31 - envelopeHeight + (multiply_32x32_rshift32(preValue, envelopeHeight) << 1); + lastValue = envelopeOffset - envelopeHeight + (multiply_32x32_rshift32(preValue, envelopeHeight) << 1); //lastValue = 2147483647 - (multiply_32x32_rshift32(decayTable8[pos >> 13], envelopeHeight) << 1); // Upside down exponential curve //lastValue = 2147483647 - (((int64_t)((sineWave[((pos >> 14) + 256) & 1023] >> 1) + 1073741824) * (int64_t)envelopeHeight) >> 31); // Sine wave. Not great @@ -215,7 +221,7 @@ int32_t Compressor::render(uint16_t numSamples, int32_t shapeValue) { } else { // Off doOff: - lastValue = ONE_Q31; + lastValue = envelopeOffset; } return lastValue - ONE_Q31; diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 4b46e2c1c4..a68ae5230b 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -17,16 +17,16 @@ #include "dsp/master_compressor/master_compressor.h" #include "dsp/stereo_sample.h" - +#include "util/fast_fixed_math.h" MasterCompressor::MasterCompressor() { //compressor.setAttack((float)attack / 100.0); - attack = attackRateTable[7] << 2; - release = releaseRateTable[35] >> 1; + attack = attackRateTable[4] << 2; + release = releaseRateTable[3] << 2; //compressor.setRelease((float)release / 100.0); //compressor.setThresh((float)threshold / 100.0); //compressor.setRatio(1.0 / ((float)ratio / 100.0)); shape = 0; - threshold = 8 * 1 << 25; + threshold = 1 << 24; follower = true; amount = 25 * 85899345; syncLevel = SyncLevel::SYNC_LEVEL_NONE; @@ -35,8 +35,10 @@ MasterCompressor::MasterCompressor() { //with floats baseline is 60-90us void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { meanVolume = calc_rms(buffer, numSamples); - registerHit(std::max(0, meanVolume - threshold)); + q31_t over = std::max(0, meanVolume - threshold); + registerHit(over); out = Compressor::render(numSamples, shape); + q31_t expout = -getExp(16, -out); //copied from global effectable int32_t positivePatchedValue = multiply_32x32_rshift32(out, amount) + 536870912; finalVolume = lshiftAndSaturate<5>(multiply_32x32_rshift32(positivePatchedValue, positivePatchedValue)); @@ -57,7 +59,7 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { } while (++thisSample != bufferEnd); //for LEDs - gr = (ONE_Q31 - currentVolume) >> 24; + gr = 126 - (std::log(float(currentVolume)) * 6.0); } q31_t MasterCompressor::calc_rms(StereoSample* buffer, uint16_t numSamples) { @@ -69,9 +71,10 @@ q31_t MasterCompressor::calc_rms(StereoSample* buffer, uint16_t numSamples) { sum += s; } while (++thisSample != bufferEnd); - mean = sum / numSamples + mean >> 3; + mean = sum / numSamples; + //mean = float(std::sqrt(float(mean) / ONE_Q31)) * ONE_Q31; //16 is 0dB - return (log(mean + 1)) * (1 << 25); + return std::log(float(mean + 1)) * float(1 << 25); } void MasterCompressor::setup(int32_t attack, int32_t release, int32_t threshold, int32_t ratio, int32_t makeup, diff --git a/src/deluge/gui/views/session_view.cpp b/src/deluge/gui/views/session_view.cpp index 7a8a9ad831..7554173c87 100644 --- a/src/deluge/gui/views/session_view.cpp +++ b/src/deluge/gui/views/session_view.cpp @@ -1980,7 +1980,7 @@ void SessionView::graphicsRoutine() { } if (modKnobMode == 4) { //upper uint8_t gr = AudioEngine::mastercompressor.gr; - uint8_t mv = AudioEngine::mastercompressor.meanVolume >> 22; + uint8_t mv = AudioEngine::mastercompressor.meanVolume >> 23; indicator_leds::setKnobIndicatorLevel(1, gr); //Gain Reduction LED indicator_leds::setKnobIndicatorLevel(0, mv); //Gain Reduction LED } diff --git a/src/deluge/processing/sound/sound.cpp b/src/deluge/processing/sound/sound.cpp index 97e1110312..76486c83d4 100644 --- a/src/deluge/processing/sound/sound.cpp +++ b/src/deluge/processing/sound/sound.cpp @@ -2313,10 +2313,12 @@ void Sound::stopSkippingRendering(ArpeggiatorSettings* arpSettings) { // Do sidechain compressor //if (paramManager->getPatchCableSet()->isSourcePatchedToSomething(PatchSource::COMPRESSOR)) { - compressor.registerHitRetrospectively(AudioEngine::sizeLastSideChainHit, - AudioEngine::audioSampleTimer - AudioEngine::timeLastSideChainHit); - //} - + if (AudioEngine::sizeLastSideChainHit) { + compressor.registerHitRetrospectively(AudioEngine::sizeLastSideChainHit, + AudioEngine::audioSampleTimer + - AudioEngine::timeLastSideChainHit); + //} + } // Special state to make it grab the actual value the first time it's rendered postReverbVolumeLastTime = -1; From dfe2914a43adb409b7a724db2181d5553962d417 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Tue, 17 Oct 2023 01:00:58 -0400 Subject: [PATCH 06/38] editable ratio and threshold --- .../master_compressor/master_compressor.cpp | 70 ++++++++----------- .../dsp/master_compressor/master_compressor.h | 6 +- src/deluge/gui/views/session_view.cpp | 43 ++++-------- .../global_effectable/global_effectable.cpp | 33 ++++++++- .../global_effectable/global_effectable.h | 5 +- .../model/mod_controllable/mod_controllable.h | 1 + src/deluge/model/song/song.cpp | 2 +- .../processing/engines/audio_engine.cpp | 7 +- src/deluge/processing/engines/audio_engine.h | 1 + src/deluge/util/fixedpoint.h | 1 + 10 files changed, 93 insertions(+), 76 deletions(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index a68ae5230b..e7c618190b 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -20,27 +20,33 @@ #include "util/fast_fixed_math.h" MasterCompressor::MasterCompressor() { //compressor.setAttack((float)attack / 100.0); - attack = attackRateTable[4] << 2; - release = releaseRateTable[3] << 2; + attack = attackRateTable[2] << 2; + release = releaseRateTable[5] << 2; //compressor.setRelease((float)release / 100.0); //compressor.setThresh((float)threshold / 100.0); //compressor.setRatio(1.0 / ((float)ratio / 100.0)); - shape = 0; - threshold = 1 << 24; + shape = getParamFromUserValue(Param::Unpatched::COMPRESSOR_SHAPE, 25); + //an appropriate range is 0-50*one q 15 + threshold = 15 * ONE_Q15; follower = true; - amount = 25 * 85899345; + //this is about a 1:1 ratio + ratio = ONE_Q31 >> 3; syncLevel = SyncLevel::SYNC_LEVEL_NONE; currentVolume = 0; } //with floats baseline is 60-90us void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { meanVolume = calc_rms(buffer, numSamples); - q31_t over = std::max(0, meanVolume - threshold); - registerHit(over); + //shift up by 10 to make it a q31, where one is max possible output + q31_t over = std::max(0, meanVolume - threshold) << 11; + if (over > 0) { + registerHit(over); + } out = Compressor::render(numSamples, shape); - q31_t expout = -getExp(16, -out); + //base is arbitrary for scale, important part is the shape + //copied from global effectable - int32_t positivePatchedValue = multiply_32x32_rshift32(out, amount) + 536870912; + int32_t positivePatchedValue = multiply_32x32_rshift32(out, ratio) + 536870912; finalVolume = lshiftAndSaturate<5>(multiply_32x32_rshift32(positivePatchedValue, positivePatchedValue)); amplitudeIncrement = (int32_t)(finalVolume - currentVolume) / numSamples; @@ -51,50 +57,36 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { do { currentVolume += amplitudeIncrement; - // Apply post-fx and post-reverb-send volume thisSample->l = multiply_32x32_rshift32(thisSample->l, currentVolume) << 1; thisSample->r = multiply_32x32_rshift32(thisSample->r, currentVolume) << 1; } while (++thisSample != bufferEnd); //for LEDs - - gr = 126 - (std::log(float(currentVolume)) * 6.0); + //9 converts to dB, quadrupled for display range since a 30db reduction is basically killing the signal + gr = std::clamp(-(std::log(float(currentVolume + 1) / ONE_Q31f) * 9.0) * 4, 0, 128); } q31_t MasterCompressor::calc_rms(StereoSample* buffer, uint16_t numSamples) { StereoSample* thisSample = buffer; StereoSample* bufferEnd = buffer + numSamples; q31_t sum = 0; + q31_t offset = 0; //to remove dc offset + q31_t last_mean = mean; do { - q31_t s = std::max(std::abs(thisSample->l), std::abs(thisSample->r)); - sum += s; + q31_t s = std::abs(thisSample->l) + std::abs(thisSample->r); + sum += multiply_32x32_rshift32(s, s) << 1; + offset += thisSample->l; } while (++thisSample != bufferEnd); - mean = sum / numSamples; - //mean = float(std::sqrt(float(mean) / ONE_Q31)) * ONE_Q31; - //16 is 0dB - return std::log(float(mean + 1)) * float(1 << 25); -} + float ns = float(numSamples); + float rms = ONE_Q31 * sqrt((float(sum) / ONE_Q31f) / ns); + float dc = std::abs(offset) / ns; + //warning this is not good math but it's pretty close and way cheaper than doing it properly + mean = rms - dc / 1.4f; + mean = std::max(mean, 1.0f); + float logmean = std::log(mean); -void MasterCompressor::setup(int32_t attack, int32_t release, int32_t threshold, int32_t ratio, int32_t makeup, - int32_t mix) { - //compressor.setAttack((float)attack / 100.0); - // attack = attackRateTable[attack] << 2; - // release = attackRateTable[attack] << 2; - // //compressor.setRelease((float)release / 100.0); - // //compressor.setThresh((float)threshold / 100.0); - // //compressor.setRatio(1.0 / ((float)ratio / 100.0)); - // amount = ratio * 21474836; - // threshold = threshold * 21474836; + //max value is 21 so this avoids clipping + return logmean * float(ONE_Q15); } - -/* - masterCompressorAttack = 7; - masterCompressorRelease = 10; - masterCompressorThresh = 10; - masterCompressorRatio = 10; - masterCompressorMakeup = 0; - masterCompressorWet = 50; - -*/ diff --git a/src/deluge/dsp/master_compressor/master_compressor.h b/src/deluge/dsp/master_compressor/master_compressor.h index 61b0fc6f7a..c020231544 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.h +++ b/src/deluge/dsp/master_compressor/master_compressor.h @@ -30,19 +30,19 @@ class MasterCompressor : public Compressor { public: MasterCompressor(); - void setup(int32_t attack, int32_t release, int32_t threshold, int32_t ratio, int32_t makeup, int32_t mix); + void setup(int32_t attack, int32_t release, int32_t threshold, int32_t ratio, int32_t makeup, int32_t mix){}; void render(StereoSample* buffer, uint16_t numSamples); q31_t calc_rms(StereoSample* buffer, uint16_t numSamples); uint8_t gr; q31_t threshold; q31_t shape; - q31_t amount; + q31_t ratio; q31_t out; q31_t meanVolume; q31_t over; q31_t finalVolume; q31_t currentVolume; q31_t amplitudeIncrement; - q31_t mean; + float mean; }; diff --git a/src/deluge/gui/views/session_view.cpp b/src/deluge/gui/views/session_view.cpp index 7554173c87..99ac7b85e8 100644 --- a/src/deluge/gui/views/session_view.cpp +++ b/src/deluge/gui/views/session_view.cpp @@ -157,30 +157,6 @@ void SessionView::focusRegained() { ActionResult SessionView::buttonAction(deluge::hid::Button b, bool on, bool inCardRoutine) { using namespace deluge::hid::button; - if (runtimeFeatureSettings.get(RuntimeFeatureSettingType::MasterCompressorFx) == RuntimeFeatureStateToggle::On - && currentUIMode == UI_MODE_NONE) { //master compressor - int32_t modKnobMode = -1; - if (view.activeModControllableModelStack.modControllable) { - uint8_t* modKnobModePointer = view.activeModControllableModelStack.modControllable->getModKnobMode(); - if (modKnobModePointer) - modKnobMode = *modKnobModePointer; - } - const char* paramLabels[] = {"THRE", "MAKE", "ATTK", "REL", "RATI", "MIX"}; - - if (modKnobMode == 4 && b == MOD_ENCODER_1 && on) { - masterCompEditMode++; - masterCompEditMode = masterCompEditMode % 6; //toggle master compressor setting - - if (display->haveOLED()) { - modEncoderAction(1, 0); - } - else { - display->displayPopup(paramLabels[masterCompEditMode]); - } - return ActionResult::DEALT_WITH; - } - } - InstrumentType newInstrumentType; // Clip-view button @@ -1970,19 +1946,26 @@ void SessionView::cloneClip(uint8_t yDisplayFrom, uint8_t yDisplayTo) { } void SessionView::graphicsRoutine() { + static int counter = 0; if (runtimeFeatureSettings.get(RuntimeFeatureSettingType::MasterCompressorFx) == RuntimeFeatureStateToggle::On && currentUIMode == UI_MODE_NONE) { int32_t modKnobMode = -1; + bool editingComp = false; if (view.activeModControllableModelStack.modControllable) { uint8_t* modKnobModePointer = view.activeModControllableModelStack.modControllable->getModKnobMode(); - if (modKnobModePointer) + if (modKnobModePointer) { modKnobMode = *modKnobModePointer; + editingComp = view.activeModControllableModelStack.modControllable->isEditingComp(); + } } - if (modKnobMode == 4) { //upper - uint8_t gr = AudioEngine::mastercompressor.gr; - uint8_t mv = AudioEngine::mastercompressor.meanVolume >> 23; - indicator_leds::setKnobIndicatorLevel(1, gr); //Gain Reduction LED - indicator_leds::setKnobIndicatorLevel(0, mv); //Gain Reduction LED + if (modKnobMode == 4 && editingComp) { //upper + counter = (counter + 1) % 5; + if (counter == 0) { + uint8_t gr = AudioEngine::mastercompressor.gr; + uint8_t mv = AudioEngine::mastercompressor.meanVolume >> 14; + indicator_leds::setKnobIndicatorLevel(1, gr); //Gain Reduction LED + indicator_leds::setKnobIndicatorLevel(0, mv); //Gain Reduction LED + } } } diff --git a/src/deluge/model/global_effectable/global_effectable.cpp b/src/deluge/model/global_effectable/global_effectable.cpp index 3a1a2335df..8d0508ae7e 100644 --- a/src/deluge/model/global_effectable/global_effectable.cpp +++ b/src/deluge/model/global_effectable/global_effectable.cpp @@ -21,6 +21,7 @@ #include "gui/views/view.h" #include "hid/buttons.h" #include "hid/display/display.h" +#include "hid/led/indicator_leds.h" #include "hid/matrix/matrix_driver.h" #include "memory/general_memory_allocator.h" #include "model/action/action_logger.h" @@ -47,6 +48,7 @@ GlobalEffectable::GlobalEffectable() { memset(allpassMemory, 0, sizeof(allpassMemory)); memset(&phaserMemory, 0, sizeof(phaserMemory)); + editingComp = false; } void GlobalEffectable::cloneFrom(ModControllableAudio* other) { @@ -268,12 +270,41 @@ bool GlobalEffectable::modEncoderButtonAction(uint8_t whichModEncoder, bool on, view.cycleThroughReverbPresets(); } } + else { + if (on) { + editingComp = !editingComp; + } + } return false; } return false; // Some cases could lead here } +ActionResult GlobalEffectable::modEncoderActionForNonExistentParam(int32_t offset, int32_t whichModEncoder, + ModelStackWithAutoParam* modelStack) { + if (*getModKnobMode() == 4) { + if (whichModEncoder == 1) { + int current = AudioEngine::mastercompressor.threshold >> 15; + current -= offset; + current = std::clamp(current, 2, 50); + indicator_leds::setKnobIndicatorLevel(1, std::max(0, 128 - 3 * (current - 2))); + AudioEngine::mastercompressor.threshold = current << 15; + + return ActionResult::DEALT_WITH; + } + else if (whichModEncoder == 0) { + int current = AudioEngine::mastercompressor.ratio >> 27; + current += offset; + current = std::clamp(current, 0, 8); + indicator_leds::setKnobIndicatorLevel(0, std::max(0, current << 4)); + AudioEngine::mastercompressor.ratio = lshiftAndSaturate<27>(current); + + return ActionResult::DEALT_WITH; + } + } + return ActionResult::NOT_DEALT_WITH; +} // Always check this doesn't return NULL! int32_t GlobalEffectable::getParameterFromKnob(int32_t whichModEncoder) { @@ -323,7 +354,7 @@ int32_t GlobalEffectable::getParameterFromKnob(int32_t whichModEncoder) { } else if (modKnobMode == 4) { - if (whichModEncoder == 0) { + if (whichModEncoder == 0 && !editingComp) { return Param::Unpatched::GlobalEffectable::REVERB_SEND_AMOUNT; } } diff --git a/src/deluge/model/global_effectable/global_effectable.h b/src/deluge/model/global_effectable/global_effectable.h index 1d13aae904..e9f8815ef2 100644 --- a/src/deluge/model/global_effectable/global_effectable.h +++ b/src/deluge/model/global_effectable/global_effectable.h @@ -54,10 +54,13 @@ class GlobalEffectable : public ModControllableAudio { int32_t stringToParam(char const* string); void setupDelayWorkingState(DelayWorkingState* delayWorkingState, ParamManager* paramManager, bool shouldLimitDelayFeedback = false); - + bool isEditingComp() override { return editingComp; } + ActionResult modEncoderActionForNonExistentParam(int32_t offset, int32_t whichModEncoder, + ModelStackWithAutoParam* modelStack) override; dsp::filter::FilterSet filterSet; ModFXParam currentModFXParam; FilterType currentFilterType; + bool editingComp; protected: virtual int32_t getParameterFromKnob(int32_t whichModEncoder); diff --git a/src/deluge/model/mod_controllable/mod_controllable.h b/src/deluge/model/mod_controllable/mod_controllable.h index 2631e60bd1..8e51ae6be0 100644 --- a/src/deluge/model/mod_controllable/mod_controllable.h +++ b/src/deluge/model/mod_controllable/mod_controllable.h @@ -47,6 +47,7 @@ class ModControllable { ModelStackWithThreeMainThings* modelStack); // Check that autoParam isn't NULL, after calling this virtual uint8_t* getModKnobMode(); // Return NULL if different modes not supported virtual bool isKit() { return false; } + virtual bool isEditingComp() { return false; } virtual int32_t getKnobPosForNonExistentParam( int32_t whichModEncoder, ModelStackWithAutoParam* modelStack); // modelStack->autoParam will be NULL in this rare case!! diff --git a/src/deluge/model/song/song.cpp b/src/deluge/model/song/song.cpp index edd1aefeea..1501ac6173 100644 --- a/src/deluge/model/song/song.cpp +++ b/src/deluge/model/song/song.cpp @@ -1129,7 +1129,7 @@ void Song::writeToFile() { int32_t attack = AudioEngine::mastercompressor.attack; int32_t release = AudioEngine::mastercompressor.release; int32_t thresh = AudioEngine::mastercompressor.threshold; - int32_t ratio = AudioEngine::mastercompressor.amount; + int32_t ratio = AudioEngine::mastercompressor.ratio; storageManager.writeAttribute("attack", attack); storageManager.writeAttribute("release", release); diff --git a/src/deluge/processing/engines/audio_engine.cpp b/src/deluge/processing/engines/audio_engine.cpp index 0952cc2f4d..cce6eec201 100644 --- a/src/deluge/processing/engines/audio_engine.cpp +++ b/src/deluge/processing/engines/audio_engine.cpp @@ -390,10 +390,15 @@ void routine() { } #ifdef REPORT_CPU_USAGE - if (numSamples < (NUM_SAMPLES_FOR_CPU_USAGE_REPORT)) { +#define MIN_SAMPLES NUM_SAMPLES_FOR_CPU_USAGE_REPORT +#else +#define MINSAMPLES 8 +#endif + if (numSamples < (MINSAMPLES)) { audioRoutineLocked = false; return; } +#ifdef REPORT_CPU_USAGE numSamples = NUM_SAMPLES_FOR_CPU_USAGE_REPORT; int32_t unadjustedNumSamplesBeforeLappingPlayHead = numSamples; #else diff --git a/src/deluge/processing/engines/audio_engine.h b/src/deluge/processing/engines/audio_engine.h index 70cb25f265..5f68877847 100644 --- a/src/deluge/processing/engines/audio_engine.h +++ b/src/deluge/processing/engines/audio_engine.h @@ -18,6 +18,7 @@ #pragma once #include "definitions_cxx.hpp" +#include "dsp/master_compressor/master_compressor.h" #include extern "C" { diff --git a/src/deluge/util/fixedpoint.h b/src/deluge/util/fixedpoint.h index bd95ae1824..0182f5dadf 100644 --- a/src/deluge/util/fixedpoint.h +++ b/src/deluge/util/fixedpoint.h @@ -22,6 +22,7 @@ typedef int32_t q31_t; #define ONE_Q31 2147483647 +#define ONE_Q31f float(ONE_Q31) #define ONE_Q15 65536 #define NEGATIVE_ONE_Q31 -2147483648 #define ONE_OVER_SQRT2_Q31 1518500250 From 0359f898b6f7ef0640ad64ae0484c0cc4fe5a6dc Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Tue, 17 Oct 2023 19:25:52 -0400 Subject: [PATCH 07/38] better shape --- .../dsp/master_compressor/master_compressor.cpp | 16 ++++++++++++---- src/deluge/processing/engines/audio_engine.cpp | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index e7c618190b..566366f8c7 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -37,17 +37,20 @@ MasterCompressor::MasterCompressor() { //with floats baseline is 60-90us void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { meanVolume = calc_rms(buffer, numSamples); - //shift up by 10 to make it a q31, where one is max possible output + //shift up by 11 to make it a q31, where one is max possible output (21) q31_t over = std::max(0, meanVolume - threshold) << 11; if (over > 0) { registerHit(over); } out = Compressor::render(numSamples, shape); + out = multiply_32x32_rshift32(out, ratio) << 1; + //21 is the max output from logmean + finalVolume = exp(21 * (out / ONE_Q31f)) * ONE_Q31; //base is arbitrary for scale, important part is the shape //copied from global effectable - int32_t positivePatchedValue = multiply_32x32_rshift32(out, ratio) + 536870912; - finalVolume = lshiftAndSaturate<5>(multiply_32x32_rshift32(positivePatchedValue, positivePatchedValue)); + //int32_t positivePatchedValue = multiply_32x32_rshift32(out, ratio) + 536870912; + //finalVolume = lshiftAndSaturate<5>(multiply_32x32_rshift32(positivePatchedValue, positivePatchedValue)); amplitudeIncrement = (int32_t)(finalVolume - currentVolume) / numSamples; @@ -67,6 +70,8 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { gr = std::clamp(-(std::log(float(currentVolume + 1) / ONE_Q31f) * 9.0) * 4, 0, 128); } +//output range is 0-21 (2^31) +//dac clipping is at 16 q31_t MasterCompressor::calc_rms(StereoSample* buffer, uint16_t numSamples) { StereoSample* thisSample = buffer; StereoSample* bufferEnd = buffer + numSamples; @@ -79,14 +84,17 @@ q31_t MasterCompressor::calc_rms(StereoSample* buffer, uint16_t numSamples) { offset += thisSample->l; } while (++thisSample != bufferEnd); + //we don't care about the low bits and they make visual noise + sum = (sum >> 8) << 8; + offset = (offset >> 8) << 8; float ns = float(numSamples); float rms = ONE_Q31 * sqrt((float(sum) / ONE_Q31f) / ns); float dc = std::abs(offset) / ns; //warning this is not good math but it's pretty close and way cheaper than doing it properly mean = rms - dc / 1.4f; mean = std::max(mean, 1.0f); + float logmean = std::log(mean); - //max value is 21 so this avoids clipping return logmean * float(ONE_Q15); } diff --git a/src/deluge/processing/engines/audio_engine.cpp b/src/deluge/processing/engines/audio_engine.cpp index cce6eec201..24f7490c4b 100644 --- a/src/deluge/processing/engines/audio_engine.cpp +++ b/src/deluge/processing/engines/audio_engine.cpp @@ -316,7 +316,7 @@ void routineWithClusterLoading(bool mayProcessUserActionsBetween) { } } -#define DO_AUDIO_LOG 0 // For advavnced debugging printouts. +#define DO_AUDIO_LOG 1 // For advavnced debugging printouts. #define AUDIO_LOG_SIZE 64 #if DO_AUDIO_LOG From 70732460baa945336da91b25b3b951fb754c54d1 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Fri, 20 Oct 2023 01:25:47 -0400 Subject: [PATCH 08/38] working attack and release controls --- .../master_compressor/master_compressor.cpp | 2 -- src/deluge/gui/views/session_view.cpp | 2 +- .../global_effectable/global_effectable.cpp | 26 +++++++++++++++++-- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 566366f8c7..23ac1a1915 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -85,8 +85,6 @@ q31_t MasterCompressor::calc_rms(StereoSample* buffer, uint16_t numSamples) { } while (++thisSample != bufferEnd); //we don't care about the low bits and they make visual noise - sum = (sum >> 8) << 8; - offset = (offset >> 8) << 8; float ns = float(numSamples); float rms = ONE_Q31 * sqrt((float(sum) / ONE_Q31f) / ns); float dc = std::abs(offset) / ns; diff --git a/src/deluge/gui/views/session_view.cpp b/src/deluge/gui/views/session_view.cpp index 99ac7b85e8..964abd9fae 100644 --- a/src/deluge/gui/views/session_view.cpp +++ b/src/deluge/gui/views/session_view.cpp @@ -1964,7 +1964,7 @@ void SessionView::graphicsRoutine() { uint8_t gr = AudioEngine::mastercompressor.gr; uint8_t mv = AudioEngine::mastercompressor.meanVolume >> 14; indicator_leds::setKnobIndicatorLevel(1, gr); //Gain Reduction LED - indicator_leds::setKnobIndicatorLevel(0, mv); //Gain Reduction LED + indicator_leds::setKnobIndicatorLevel(0, mv); //Input level LED } } } diff --git a/src/deluge/model/global_effectable/global_effectable.cpp b/src/deluge/model/global_effectable/global_effectable.cpp index 8d0508ae7e..968f819f58 100644 --- a/src/deluge/model/global_effectable/global_effectable.cpp +++ b/src/deluge/model/global_effectable/global_effectable.cpp @@ -284,7 +284,7 @@ bool GlobalEffectable::modEncoderButtonAction(uint8_t whichModEncoder, bool on, ActionResult GlobalEffectable::modEncoderActionForNonExistentParam(int32_t offset, int32_t whichModEncoder, ModelStackWithAutoParam* modelStack) { if (*getModKnobMode() == 4) { - if (whichModEncoder == 1) { + if (whichModEncoder == 1) { //sidechain (threshold) int current = AudioEngine::mastercompressor.threshold >> 15; current -= offset; current = std::clamp(current, 2, 50); @@ -293,7 +293,7 @@ ActionResult GlobalEffectable::modEncoderActionForNonExistentParam(int32_t offse return ActionResult::DEALT_WITH; } - else if (whichModEncoder == 0) { + else if (whichModEncoder == 0) { //reverb (we can only get here in comp editing mode) int current = AudioEngine::mastercompressor.ratio >> 27; current += offset; current = std::clamp(current, 0, 8); @@ -303,6 +303,28 @@ ActionResult GlobalEffectable::modEncoderActionForNonExistentParam(int32_t offse return ActionResult::DEALT_WITH; } } + else if (*getModKnobMode() == 2) { + if (whichModEncoder == 1) { //attack + int current = getLookupIndexFromValue(AudioEngine::mastercompressor.attack >> 2, attackRateTable, 50); + current += offset; + current = std::clamp(current, 0, 50); + indicator_leds::setKnobIndicatorLevel(1, (current * 128) / 50); + AudioEngine::mastercompressor.attack = attackRateTable[current] << 2; + ; + + return ActionResult::DEALT_WITH; + } + if (whichModEncoder == 0) { //attack + int current = getLookupIndexFromValue(AudioEngine::mastercompressor.release >> 2, releaseRateTable, 50); + current += offset; + current = std::clamp(current, 0, 50); + indicator_leds::setKnobIndicatorLevel(0, (current * 128) / 50); + AudioEngine::mastercompressor.release = releaseRateTable[current] << 2; + + return ActionResult::DEALT_WITH; + } + } + return ActionResult::NOT_DEALT_WITH; } From dec6b92e4e66a6b87386d9d387d4c747f0737183 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Fri, 20 Oct 2023 01:28:18 -0400 Subject: [PATCH 09/38] tweak attack and release minimums --- src/deluge/model/global_effectable/global_effectable.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/deluge/model/global_effectable/global_effectable.cpp b/src/deluge/model/global_effectable/global_effectable.cpp index 968f819f58..f293c2bf1f 100644 --- a/src/deluge/model/global_effectable/global_effectable.cpp +++ b/src/deluge/model/global_effectable/global_effectable.cpp @@ -307,7 +307,7 @@ ActionResult GlobalEffectable::modEncoderActionForNonExistentParam(int32_t offse if (whichModEncoder == 1) { //attack int current = getLookupIndexFromValue(AudioEngine::mastercompressor.attack >> 2, attackRateTable, 50); current += offset; - current = std::clamp(current, 0, 50); + current = std::clamp(current, 1, 50); indicator_leds::setKnobIndicatorLevel(1, (current * 128) / 50); AudioEngine::mastercompressor.attack = attackRateTable[current] << 2; ; @@ -317,7 +317,7 @@ ActionResult GlobalEffectable::modEncoderActionForNonExistentParam(int32_t offse if (whichModEncoder == 0) { //attack int current = getLookupIndexFromValue(AudioEngine::mastercompressor.release >> 2, releaseRateTable, 50); current += offset; - current = std::clamp(current, 0, 50); + current = std::clamp(current, 1, 50); indicator_leds::setKnobIndicatorLevel(0, (current * 128) / 50); AudioEngine::mastercompressor.release = releaseRateTable[current] << 2; From 8b87d104daf37295b76492a07330fc3c0920a850 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Fri, 20 Oct 2023 02:28:45 -0400 Subject: [PATCH 10/38] auto makeup gain --- .../dsp/master_compressor/master_compressor.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 23ac1a1915..f9725aaffe 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -39,18 +39,19 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { meanVolume = calc_rms(buffer, numSamples); //shift up by 11 to make it a q31, where one is max possible output (21) q31_t over = std::max(0, meanVolume - threshold) << 11; + if (over > 0) { registerHit(over); } out = Compressor::render(numSamples, shape); out = multiply_32x32_rshift32(out, ratio) << 1; + + //auto make up gain + float er = 0.33 * std::max(0, (50 - (threshold >> 15))) * (float(ratio) / ONE_Q31f); + //21 is the max output from logmean - finalVolume = exp(21 * (out / ONE_Q31f)) * ONE_Q31; //base is arbitrary for scale, important part is the shape - - //copied from global effectable - //int32_t positivePatchedValue = multiply_32x32_rshift32(out, ratio) + 536870912; - //finalVolume = lshiftAndSaturate<5>(multiply_32x32_rshift32(positivePatchedValue, positivePatchedValue)); + finalVolume = exp(er + 21 * (out / ONE_Q31f)) * ONE_Q31; amplitudeIncrement = (int32_t)(finalVolume - currentVolume) / numSamples; @@ -84,7 +85,7 @@ q31_t MasterCompressor::calc_rms(StereoSample* buffer, uint16_t numSamples) { offset += thisSample->l; } while (++thisSample != bufferEnd); - //we don't care about the low bits and they make visual noise + float ns = float(numSamples); float rms = ONE_Q31 * sqrt((float(sum) / ONE_Q31f) / ns); float dc = std::abs(offset) / ns; From 7b5637e5e37f3750472a426b52672d0a64509a4f Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Fri, 20 Oct 2023 09:22:26 -0400 Subject: [PATCH 11/38] clean up auto makeup gain --- src/deluge/dsp/master_compressor/master_compressor.cpp | 10 +++++++--- src/deluge/dsp/master_compressor/master_compressor.h | 2 ++ .../model/global_effectable/global_effectable.cpp | 4 ++-- src/deluge/processing/engines/audio_engine.cpp | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index f9725aaffe..3f15ff8b5b 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -33,7 +33,14 @@ MasterCompressor::MasterCompressor() { ratio = ONE_Q31 >> 3; syncLevel = SyncLevel::SYNC_LEVEL_NONE; currentVolume = 0; + //auto make up gain + updateER(); +} + +void MasterCompressor::updateER() { + er = 0.33 * std::max(0, (50 - (threshold >> 15))) * (float(ratio) / ONE_Q31f); } + //with floats baseline is 60-90us void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { meanVolume = calc_rms(buffer, numSamples); @@ -46,9 +53,6 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { out = Compressor::render(numSamples, shape); out = multiply_32x32_rshift32(out, ratio) << 1; - //auto make up gain - float er = 0.33 * std::max(0, (50 - (threshold >> 15))) * (float(ratio) / ONE_Q31f); - //21 is the max output from logmean //base is arbitrary for scale, important part is the shape finalVolume = exp(er + 21 * (out / ONE_Q31f)) * ONE_Q31; diff --git a/src/deluge/dsp/master_compressor/master_compressor.h b/src/deluge/dsp/master_compressor/master_compressor.h index c020231544..624eb15255 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.h +++ b/src/deluge/dsp/master_compressor/master_compressor.h @@ -33,6 +33,7 @@ class MasterCompressor : public Compressor { void setup(int32_t attack, int32_t release, int32_t threshold, int32_t ratio, int32_t makeup, int32_t mix){}; void render(StereoSample* buffer, uint16_t numSamples); + void updateER(); q31_t calc_rms(StereoSample* buffer, uint16_t numSamples); uint8_t gr; q31_t threshold; @@ -45,4 +46,5 @@ class MasterCompressor : public Compressor { q31_t currentVolume; q31_t amplitudeIncrement; float mean; + float er; }; diff --git a/src/deluge/model/global_effectable/global_effectable.cpp b/src/deluge/model/global_effectable/global_effectable.cpp index f293c2bf1f..f88afdd18e 100644 --- a/src/deluge/model/global_effectable/global_effectable.cpp +++ b/src/deluge/model/global_effectable/global_effectable.cpp @@ -290,7 +290,7 @@ ActionResult GlobalEffectable::modEncoderActionForNonExistentParam(int32_t offse current = std::clamp(current, 2, 50); indicator_leds::setKnobIndicatorLevel(1, std::max(0, 128 - 3 * (current - 2))); AudioEngine::mastercompressor.threshold = current << 15; - + AudioEngine::mastercompressor.updateER(); return ActionResult::DEALT_WITH; } else if (whichModEncoder == 0) { //reverb (we can only get here in comp editing mode) @@ -299,7 +299,7 @@ ActionResult GlobalEffectable::modEncoderActionForNonExistentParam(int32_t offse current = std::clamp(current, 0, 8); indicator_leds::setKnobIndicatorLevel(0, std::max(0, current << 4)); AudioEngine::mastercompressor.ratio = lshiftAndSaturate<27>(current); - + AudioEngine::mastercompressor.updateER(); return ActionResult::DEALT_WITH; } } diff --git a/src/deluge/processing/engines/audio_engine.cpp b/src/deluge/processing/engines/audio_engine.cpp index 24f7490c4b..cce6eec201 100644 --- a/src/deluge/processing/engines/audio_engine.cpp +++ b/src/deluge/processing/engines/audio_engine.cpp @@ -316,7 +316,7 @@ void routineWithClusterLoading(bool mayProcessUserActionsBetween) { } } -#define DO_AUDIO_LOG 1 // For advavnced debugging printouts. +#define DO_AUDIO_LOG 0 // For advavnced debugging printouts. #define AUDIO_LOG_SIZE 64 #if DO_AUDIO_LOG From b35eb3b5f67aabfc3aa0f2e153e5561fcc2b5e88 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Fri, 20 Oct 2023 10:09:37 -0400 Subject: [PATCH 12/38] saving and restoring parameters --- src/deluge/dsp/master_compressor/master_compressor.cpp | 10 +++++++++- src/deluge/dsp/master_compressor/master_compressor.h | 2 +- src/deluge/processing/engines/audio_engine.cpp | 5 ++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 3f15ff8b5b..181e7c5689 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -55,7 +55,8 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { //21 is the max output from logmean //base is arbitrary for scale, important part is the shape - finalVolume = exp(er + 21 * (out / ONE_Q31f)) * ONE_Q31; + float dbChange = er + 21 * (out / ONE_Q31f); + finalVolume = exp(dbChange) * ONE_Q31; amplitudeIncrement = (int32_t)(finalVolume - currentVolume) / numSamples; @@ -101,3 +102,10 @@ q31_t MasterCompressor::calc_rms(StereoSample* buffer, uint16_t numSamples) { return logmean * float(ONE_Q15); } + +void MasterCompressor::setup(int32_t a, int32_t r, int32_t t, int32_t rat) { + attack = a; + release = r; + threshold = t; + ratio = rat; +} diff --git a/src/deluge/dsp/master_compressor/master_compressor.h b/src/deluge/dsp/master_compressor/master_compressor.h index 624eb15255..8d50327e0d 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.h +++ b/src/deluge/dsp/master_compressor/master_compressor.h @@ -30,7 +30,7 @@ class MasterCompressor : public Compressor { public: MasterCompressor(); - void setup(int32_t attack, int32_t release, int32_t threshold, int32_t ratio, int32_t makeup, int32_t mix){}; + void setup(int32_t attack, int32_t release, int32_t threshold, int32_t ratio); void render(StereoSample* buffer, uint16_t numSamples); void updateER(); diff --git a/src/deluge/processing/engines/audio_engine.cpp b/src/deluge/processing/engines/audio_engine.cpp index cce6eec201..8a7deceef8 100644 --- a/src/deluge/processing/engines/audio_engine.cpp +++ b/src/deluge/processing/engines/audio_engine.cpp @@ -1196,9 +1196,8 @@ void getMasterCompressorParamsFromSong(Song* song) { int32_t r = song->masterCompressorRelease; int32_t t = song->masterCompressorThresh; int32_t rat = song->masterCompressorRatio; - int32_t m = song->masterCompressorMakeup; - int32_t w = song->masterCompressorWet; - mastercompressor.setup(a, r, t, rat, m, w); + + mastercompressor.setup(a, r, t, rat); } Voice* solicitVoice(Sound* forSound) { From 1f0d1a5acb233e1c4301095ed3e6620a1e72a0da Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Fri, 20 Oct 2023 14:07:48 -0400 Subject: [PATCH 13/38] working auto makeup gain --- .../master_compressor/master_compressor.cpp | 26 ++++++++++++------- .../dsp/master_compressor/master_compressor.h | 5 ++-- src/deluge/gui/views/session_view.cpp | 2 +- .../global_effectable/global_effectable.cpp | 8 +++--- .../processing/engines/audio_engine.cpp | 6 ++--- 5 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 181e7c5689..23898f41ed 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -25,7 +25,7 @@ MasterCompressor::MasterCompressor() { //compressor.setRelease((float)release / 100.0); //compressor.setThresh((float)threshold / 100.0); //compressor.setRatio(1.0 / ((float)ratio / 100.0)); - shape = getParamFromUserValue(Param::Unpatched::COMPRESSOR_SHAPE, 25); + shape = getParamFromUserValue(Param::Unpatched::COMPRESSOR_SHAPE, 1); //an appropriate range is 0-50*one q 15 threshold = 15 * ONE_Q15; follower = true; @@ -38,14 +38,16 @@ MasterCompressor::MasterCompressor() { } void MasterCompressor::updateER() { - er = 0.33 * std::max(0, (50 - (threshold >> 15))) * (float(ratio) / ONE_Q31f); + threshdb = 8 + 13 * (threshold / ONE_Q31f); + //14 is about the level of a single synth voice + er = std::clamp((14 - threshdb) * (float(ratio) / ONE_Q31f), 0, 4); } //with floats baseline is 60-90us void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { meanVolume = calc_rms(buffer, numSamples); - //shift up by 11 to make it a q31, where one is max possible output (21) - q31_t over = std::max(0, meanVolume - threshold) << 11; + + q31_t over = std::max(0, (meanVolume - threshdb) / 21) * ONE_Q31; if (over > 0) { registerHit(over); @@ -53,10 +55,13 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { out = Compressor::render(numSamples, shape); out = multiply_32x32_rshift32(out, ratio) << 1; - //21 is the max output from logmean + //21 is the max internal volume (i.e. one_q31) + //min ratio is 8 up to 1 (i.e. infinity/brick wall, 1 db reduction per db over) //base is arbitrary for scale, important part is the shape - float dbChange = er + 21 * (out / ONE_Q31f); - finalVolume = exp(dbChange) * ONE_Q31; + //this will be negative + float reduction = 21 * (out / ONE_Q31f); + //this lowers the volume so we'll increase the levels afterwards + finalVolume = exp(er + reduction) * float(1 << 26); amplitudeIncrement = (int32_t)(finalVolume - currentVolume) / numSamples; @@ -73,12 +78,12 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { } while (++thisSample != bufferEnd); //for LEDs //9 converts to dB, quadrupled for display range since a 30db reduction is basically killing the signal - gr = std::clamp(-(std::log(float(currentVolume + 1) / ONE_Q31f) * 9.0) * 4, 0, 128); + gr = -reduction * 9 * 4; } //output range is 0-21 (2^31) //dac clipping is at 16 -q31_t MasterCompressor::calc_rms(StereoSample* buffer, uint16_t numSamples) { +float MasterCompressor::calc_rms(StereoSample* buffer, uint16_t numSamples) { StereoSample* thisSample = buffer; StereoSample* bufferEnd = buffer + numSamples; q31_t sum = 0; @@ -100,7 +105,7 @@ q31_t MasterCompressor::calc_rms(StereoSample* buffer, uint16_t numSamples) { float logmean = std::log(mean); - return logmean * float(ONE_Q15); + return logmean; } void MasterCompressor::setup(int32_t a, int32_t r, int32_t t, int32_t rat) { @@ -108,4 +113,5 @@ void MasterCompressor::setup(int32_t a, int32_t r, int32_t t, int32_t rat) { release = r; threshold = t; ratio = rat; + updateER(); } diff --git a/src/deluge/dsp/master_compressor/master_compressor.h b/src/deluge/dsp/master_compressor/master_compressor.h index 8d50327e0d..9062e08a82 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.h +++ b/src/deluge/dsp/master_compressor/master_compressor.h @@ -34,17 +34,18 @@ class MasterCompressor : public Compressor { void render(StereoSample* buffer, uint16_t numSamples); void updateER(); - q31_t calc_rms(StereoSample* buffer, uint16_t numSamples); + float calc_rms(StereoSample* buffer, uint16_t numSamples); uint8_t gr; q31_t threshold; q31_t shape; q31_t ratio; q31_t out; - q31_t meanVolume; q31_t over; q31_t finalVolume; q31_t currentVolume; q31_t amplitudeIncrement; + float meanVolume; float mean; float er; + float threshdb; }; diff --git a/src/deluge/gui/views/session_view.cpp b/src/deluge/gui/views/session_view.cpp index 964abd9fae..69275a8e6e 100644 --- a/src/deluge/gui/views/session_view.cpp +++ b/src/deluge/gui/views/session_view.cpp @@ -1962,7 +1962,7 @@ void SessionView::graphicsRoutine() { counter = (counter + 1) % 5; if (counter == 0) { uint8_t gr = AudioEngine::mastercompressor.gr; - uint8_t mv = AudioEngine::mastercompressor.meanVolume >> 14; + uint8_t mv = int(6 * AudioEngine::mastercompressor.meanVolume); indicator_leds::setKnobIndicatorLevel(1, gr); //Gain Reduction LED indicator_leds::setKnobIndicatorLevel(0, mv); //Input level LED } diff --git a/src/deluge/model/global_effectable/global_effectable.cpp b/src/deluge/model/global_effectable/global_effectable.cpp index f88afdd18e..4cc84a8ccb 100644 --- a/src/deluge/model/global_effectable/global_effectable.cpp +++ b/src/deluge/model/global_effectable/global_effectable.cpp @@ -285,19 +285,19 @@ ActionResult GlobalEffectable::modEncoderActionForNonExistentParam(int32_t offse ModelStackWithAutoParam* modelStack) { if (*getModKnobMode() == 4) { if (whichModEncoder == 1) { //sidechain (threshold) - int current = AudioEngine::mastercompressor.threshold >> 15; + int current = AudioEngine::mastercompressor.threshold >> 25; current -= offset; current = std::clamp(current, 2, 50); indicator_leds::setKnobIndicatorLevel(1, std::max(0, 128 - 3 * (current - 2))); - AudioEngine::mastercompressor.threshold = current << 15; + AudioEngine::mastercompressor.threshold = lshiftAndSaturate<25>(current); AudioEngine::mastercompressor.updateER(); return ActionResult::DEALT_WITH; } else if (whichModEncoder == 0) { //reverb (we can only get here in comp editing mode) int current = AudioEngine::mastercompressor.ratio >> 27; current += offset; - current = std::clamp(current, 0, 8); - indicator_leds::setKnobIndicatorLevel(0, std::max(0, current << 4)); + current = std::clamp(current, 1, 16); + indicator_leds::setKnobIndicatorLevel(0, std::max(0, current << 3)); AudioEngine::mastercompressor.ratio = lshiftAndSaturate<27>(current); AudioEngine::mastercompressor.updateER(); return ActionResult::DEALT_WITH; diff --git a/src/deluge/processing/engines/audio_engine.cpp b/src/deluge/processing/engines/audio_engine.cpp index 8a7deceef8..5837205170 100644 --- a/src/deluge/processing/engines/audio_engine.cpp +++ b/src/deluge/processing/engines/audio_engine.cpp @@ -392,7 +392,7 @@ void routine() { #ifdef REPORT_CPU_USAGE #define MIN_SAMPLES NUM_SAMPLES_FOR_CPU_USAGE_REPORT #else -#define MINSAMPLES 8 +#define MINSAMPLES 16 #endif if (numSamples < (MINSAMPLES)) { audioRoutineLocked = false; @@ -760,8 +760,8 @@ void routine() { } logAction("mastercomp start"); mastercompressor.render(renderingBuffer, numSamples); - masterVolumeAdjustmentL <<= 2; - masterVolumeAdjustmentR <<= 2; + masterVolumeAdjustmentL <<= 3; + masterVolumeAdjustmentR <<= 3; logAction("mastercomp end"); metronome.render(renderingBuffer, numSamples); From ac0fdf76eab661eb2f0f8a532dd8fa6d5bb32f8b Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Fri, 20 Oct 2023 14:10:55 -0400 Subject: [PATCH 14/38] remove old comp --- .../chunkware_simplecomp.cpp | 88 -------- .../master_compressor/chunkware_simplecomp.h | 211 ------------------ 2 files changed, 299 deletions(-) delete mode 100644 src/deluge/dsp/master_compressor/chunkware_simplecomp.cpp delete mode 100644 src/deluge/dsp/master_compressor/chunkware_simplecomp.h diff --git a/src/deluge/dsp/master_compressor/chunkware_simplecomp.cpp b/src/deluge/dsp/master_compressor/chunkware_simplecomp.cpp deleted file mode 100644 index 686f0fdded..0000000000 --- a/src/deluge/dsp/master_compressor/chunkware_simplecomp.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright © 2014-2023 Synthstrom Audible Limited - * - * This file is part of The Synthstrom Audible Deluge Firmware. - * - * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software Foundation, - * either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. - * If not, see . -*/ - -#include "dsp/master_compressor/chunkware_simplecomp.h" -#include "dsp/stereo_sample.h" - -namespace chunkware_simple { -//------------------------------------------------------------- -// envelope detector -//------------------------------------------------------------- -EnvelopeDetector::EnvelopeDetector(float timeConstant, float sampleRate) { - assert(sampleRate > 0.0); - assert(timeConstant > 0.0); - sampleRate_ = sampleRate; - timeConstant_ = timeConstant; - setCoef(); -} -//------------------------------------------------------------- -void EnvelopeDetector::setTc(float timeConstant) { - assert(timeConstant > 0.0); - timeConstant_ = timeConstant; - setCoef(); -} -//------------------------------------------------------------- -void EnvelopeDetector::setSampleRate(float sampleRate) { - assert(sampleRate > 0.0); - sampleRate_ = sampleRate; - setCoef(); -} -//------------------------------------------------------------- -void EnvelopeDetector::setCoef(void) { - nSamplesInverse_ = exp(-1000.0 / (timeConstant_ * sampleRate_)); -} - -//------------------------------------------------------------- -// attack/release envelope -//------------------------------------------------------------- -AttRelEnvelope::AttRelEnvelope(float att_ms, float rel_ms, float sampleRate) - : attackEnvelope_(att_ms, sampleRate), releaseEnvelope_(rel_ms, sampleRate) { -} -//------------------------------------------------------------- -void AttRelEnvelope::setAttack(float ms) { - attackEnvelope_.setTc(ms); -} -//------------------------------------------------------------- -void AttRelEnvelope::setRelease(float ms) { - releaseEnvelope_.setTc(ms); -} -//------------------------------------------------------------- -void AttRelEnvelope::setSampleRate(float sampleRate) { - attackEnvelope_.setSampleRate(sampleRate); - releaseEnvelope_.setSampleRate(sampleRate); -} - -//------------------------------------------------------------- -// simple compressor -//------------------------------------------------------------- -SimpleComp::SimpleComp() : AttRelEnvelope(10.0, 100.0), threshdB_(0.0), ratio_(1.0), envdB_(DC_OFFSET) { -} -//------------------------------------------------------------- -void SimpleComp::setThresh(float dB) { - threshdB_ = dB; -} -//------------------------------------------------------------- -void SimpleComp::setRatio(float ratio) { - assert(ratio > 0.0); - ratio_ = ratio; -} -//------------------------------------------------------------- -void SimpleComp::initRuntime(void) { - envdB_ = DC_OFFSET; -} - -} // end namespace chunkware_simple diff --git a/src/deluge/dsp/master_compressor/chunkware_simplecomp.h b/src/deluge/dsp/master_compressor/chunkware_simplecomp.h deleted file mode 100644 index fd072c5c06..0000000000 --- a/src/deluge/dsp/master_compressor/chunkware_simplecomp.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright © 2014-2023 Synthstrom Audible Limited - * - * This file is part of The Synthstrom Audible Deluge Firmware. - * - * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software Foundation, - * either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. - * If not, see . -*/ - -#pragma once - -#include "definitions_cxx.hpp" - -#define INLINE inline -#include // for min(), max() -#include // for assert() -#include -#include - -class StereoSample; - -namespace chunkware_simple { -/* - * © 2006, ChunkWare Music Software, OPEN-SOURCE - * - * 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 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. - */ -//------------------------------------------------------------- -// gain functions -//------------------------------------------------------------- -// linear -> dB conversion -static INLINE float lin2dB(float lin) { - static const float LOG_2_DB = 8.6858896380650365530225783783321; // 20 / ln( 10 ) - return log(lin) * LOG_2_DB; -} -// dB -> linear conversion -static INLINE float dB2lin(float dB) { - static const float DB_2_LOG = 0.11512925464970228420089957273422; // ln( 10 ) / 20 - return exp(dB * DB_2_LOG); -} - -static const float DC_OFFSET = 1.0E-25; -//------------------------------------------------------------- -// envelope detector -//------------------------------------------------------------- -class EnvelopeDetector { -public: - EnvelopeDetector(float ms = 1.0, float sampleRate = static_cast(kSampleRate)); - virtual ~EnvelopeDetector() {} - - // time constant - virtual void setTc(float ms); - virtual float getTc(void) const { return timeConstant_; } - - // sample rate - virtual void setSampleRate(float sampleRate); - virtual float getSampleRate(void) const { return sampleRate_; } - - // runtime function - INLINE void run(float in, float& state) { state = in + nSamplesInverse_ * (state - in); } - -protected: - float sampleRate_; // sample rate - float timeConstant_; // time constant in ms - float nSamplesInverse_; // runtime coefficient - virtual void setCoef(void); // coef calculation - -}; // end SimpleComp class - -//------------------------------------------------------------- -// attack/release envelope -//------------------------------------------------------------- -class AttRelEnvelope { -public: - AttRelEnvelope(float att_ms = 10.0, float rel_ms = 100.0, float sampleRate = static_cast(kSampleRate)); - virtual ~AttRelEnvelope() {} - - // attack time constant - virtual void setAttack(float ms); - virtual float getAttack(void) const { return attackEnvelope_.getTc(); } - - // release time constant - virtual void setRelease(float ms); - virtual float getRelease(void) const { return releaseEnvelope_.getTc(); } - - // sample rate dependencies - virtual void setSampleRate(float sampleRate); - virtual float getSampleRate(void) const { return attackEnvelope_.getSampleRate(); } - - // runtime function - INLINE void run(float in, float& state) { - - /* assumes that: - * positive delta = attack - * negative delta = release - * good for linear & log values - */ - - if (in > state) - attackEnvelope_.run(in, state); // attack - else - releaseEnvelope_.run(in, state); // release - } - -private: - EnvelopeDetector attackEnvelope_; - EnvelopeDetector releaseEnvelope_; - -}; // end AttRelEnvelope class - -class SimpleComp : public AttRelEnvelope { -public: - SimpleComp(); - virtual ~SimpleComp() {} - - // parameters - virtual void setThresh(float dB); - virtual void setRatio(float dB); - - virtual float getThresh(void) const { return threshdB_; } - virtual float getRatio(void) const { return ratio_; } - - // runtime - virtual void initRuntime(void); // call before runtime (in resume()) - //void process(float& in1, float& in2); // compressor runtime process - //void process(float& in1, float& in2, float keyLinked); // with stereo-linked key in - - INLINE void process(float& in1, float& in2) { - // create sidechain - float rect1 = fabs(in1); // rectify input - float rect2 = fabs(in2); - - /* if desired, one could use another EnvelopeDetector to smooth - * the rectified signal. - */ - - float link = std::max(rect1, rect2); // link channels with greater of 2 - - process(in1, in2, link); // rest of process - } - - //------------------------------------------------------------- - INLINE void process(float& in1, float& in2, float keyLinked) { - keyLinked = fabs(keyLinked); // rectify (just in case) - - // convert key to dB - keyLinked += DC_OFFSET; // add DC offset to avoid log( 0 ) - float keydB = lin2dB(keyLinked); // convert linear -> dB - - // threshold - float overdB = keydB - threshdB_; // delta over threshold - if (overdB < 0.0) - overdB = 0.0; - - // attack/release - - overdB += DC_OFFSET; // add DC offset to avoid denormal - AttRelEnvelope::run(overdB, envdB_); // run attack/release envelope - overdB = envdB_ - DC_OFFSET; // subtract DC offset - - /* REGARDING THE DC OFFSET: In this case, since the offset is added before - * the attack/release processes, the envelope will never fall below the offset, - * thereby avoiding denormals. However, to prevent the offset from causing - * constant gain reduction, we must subtract it from the envelope, yielding - * a minimum value of 0dB. - */ - - // transfer function - float gr = overdB * (ratio_ - 1.0); // gain reduction (dB) - gr = dB2lin(gr); // convert dB -> linear - - // output gain - in1 *= gr; // apply gain reduction to input - in2 *= gr; - } - -private: - // transfer function - float threshdB_; // threshold (dB) - float ratio_; // ratio (compression: < 1 ; expansion: > 1) - - // runtime variables - float envdB_; // over-threshold envelope (dB) - -}; // end SimpleComp class - -} // end namespace chunkware_simple From c466fea9f4325796f059213fe8de8e06dc2f3325 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Fri, 20 Oct 2023 14:20:46 -0400 Subject: [PATCH 15/38] show mode popup and add to community features --- docs/community_features.md | 9 ++------- src/deluge/model/global_effectable/global_effectable.cpp | 1 + 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/docs/community_features.md b/docs/community_features.md index 4ff25c3e89..9892d55a12 100644 --- a/docs/community_features.md +++ b/docs/community_features.md @@ -45,13 +45,8 @@ Here is a list of features that have been added to the firmware as a list, group ### 4.1 - Song View Features #### 4.1.1 - Master Compressor -- ([#137]) In the Song view, select "AFFECT ENTIRE" and "SIDECHAIN" modulation button, and adjust the upper gold knob. Push the upper gold knob to switch to the next setting (Threshold (dB), Makeup Gain (dB), Attack (ms), Release (ms), Ratio, MIX). The LEDs next to the knob act as a gain reduction meter. +- ([#630]) In the Song view, select "AFFECT ENTIRE" and "SIDECHAIN" modulation button, and adjust the upper gold knob for a single knob compressor with auto makeup gain. For detailed editing, press the sidechain gold knob. The top LED will become a compression meter, and the bottom LED level will show the compressor input level. The bottom (reverb) knob will adjust the ratio in this mode, from 1:8 to infinity/brick wall. The compressor attack and release are editable on the affect entire attack and release buttons if desired. - - This feature can be turned ON/OFF in the Runtime Settings (Community Features) Menu (accessed by pressing "SHIFT" + "SELECT"). - -- Follow up PR's: - - ([#200]) Fixed master compressor. The masterVolumeAdjustment value is now considered in the process. With this change, threshold value are now displayed correctly. This modification affects songs that had saved master compressor settings. - - ([#220]) Fixed a bug in the song view that, when the "SIDECHAIN" knob was turned while holding down a clip pad, the "SIDECHAIN" value and the Master Compressor Threshold would change at the same time. #### 4.1.2 - Change Row Colour @@ -357,7 +352,7 @@ This list includes all preprocessor switches that can alter firmware behaviour a [#122]: https://github.com/SynthstromAudible/DelugeFirmware/pull/122 [#125]: https://github.com/SynthstromAudible/DelugeFirmware/pull/125 [#129]: https://github.com/SynthstromAudible/DelugeFirmware/pull/129 -[#137]: https://github.com/SynthstromAudible/DelugeFirmware/pull/137 +[#630]: https://github.com/SynthstromAudible/DelugeFirmware/pull/630 [#138]: https://github.com/SynthstromAudible/DelugeFirmware/pull/138 [#141]: https://github.com/SynthstromAudible/DelugeFirmware/pull/141 [#157]: https://github.com/SynthstromAudible/DelugeFirmware/pull/157 diff --git a/src/deluge/model/global_effectable/global_effectable.cpp b/src/deluge/model/global_effectable/global_effectable.cpp index 4cc84a8ccb..92024f1f1a 100644 --- a/src/deluge/model/global_effectable/global_effectable.cpp +++ b/src/deluge/model/global_effectable/global_effectable.cpp @@ -273,6 +273,7 @@ bool GlobalEffectable::modEncoderButtonAction(uint8_t whichModEncoder, bool on, else { if (on) { editingComp = !editingComp; + display->popupTextTemporary(editingComp ? "COMP" : "OFF"); } } From e7ebcefecedc636fd4acd1d5f7304ca41d661c75 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Fri, 20 Oct 2023 14:33:08 -0400 Subject: [PATCH 16/38] remove remaining old master comp references --- .../menu_item/runtime_feature/settings.cpp | 20 ++++-- src/deluge/gui/views/arranger_view.cpp | 64 +++++-------------- src/deluge/gui/views/session_view.cpp | 52 +-------------- .../settings/runtime_feature_settings.cpp | 4 -- .../model/settings/runtime_feature_settings.h | 1 - src/deluge/model/song/song.cpp | 35 ++++------ 6 files changed, 42 insertions(+), 134 deletions(-) diff --git a/src/deluge/gui/menu_item/runtime_feature/settings.cpp b/src/deluge/gui/menu_item/runtime_feature/settings.cpp index 640be62c18..f253ab0eba 100644 --- a/src/deluge/gui/menu_item/runtime_feature/settings.cpp +++ b/src/deluge/gui/menu_item/runtime_feature/settings.cpp @@ -33,7 +33,6 @@ namespace deluge::gui::menu_item::runtime_feature { // Generic menu item instances Setting menuDrumRandomizer(RuntimeFeatureSettingType::DrumRandomizer); -Setting menuMasterCompressorFx(RuntimeFeatureSettingType::MasterCompressorFx); Setting menuFineTempo(RuntimeFeatureSettingType::FineTempoKnob); Setting menuQuantize(RuntimeFeatureSettingType::Quantize); Setting menuPatchCableResolution(RuntimeFeatureSettingType::PatchCableResolution); @@ -63,10 +62,21 @@ Submenu subMenuAutomation{ }; std::array subMenuEntries{ - &menuDrumRandomizer, &menuMasterCompressorFx, &menuFineTempo, &menuQuantize, - &menuPatchCableResolution, &menuCatchNotes, &menuDeleteUnusedKitRows, &menuAltGoldenKnobDelayParams, - &menuQuantizedStutterRate, &subMenuAutomation, &menuDevSysexAllowed, &menuSyncScalingAction, - &menuHighlightIncomingNotes, &menuDisplayNornsLayout, &menuShiftIsSticky, &menuLightShiftLed, + &menuDrumRandomizer, + &menuFineTempo, + &menuQuantize, + &menuPatchCableResolution, + &menuCatchNotes, + &menuDeleteUnusedKitRows, + &menuAltGoldenKnobDelayParams, + &menuQuantizedStutterRate, + &subMenuAutomation, + &menuDevSysexAllowed, + &menuSyncScalingAction, + &menuHighlightIncomingNotes, + &menuDisplayNornsLayout, + &menuShiftIsSticky, + &menuLightShiftLed, }; Settings::Settings(l10n::String name, l10n::String title) : menu_item::Submenu(name, title, subMenuEntries) { diff --git a/src/deluge/gui/views/arranger_view.cpp b/src/deluge/gui/views/arranger_view.cpp index 8e04a7f3cb..711b2c1495 100644 --- a/src/deluge/gui/views/arranger_view.cpp +++ b/src/deluge/gui/views/arranger_view.cpp @@ -165,20 +165,6 @@ ActionResult ArrangerView::buttonAction(deluge::hid::Button b, bool on, bool inC InstrumentType newInstrumentType; - if (runtimeFeatureSettings.get(RuntimeFeatureSettingType::MasterCompressorFx) == RuntimeFeatureStateToggle::On - && currentUIMode == UI_MODE_NONE) { //master compressor - int32_t modKnobMode = -1; - if (view.activeModControllableModelStack.modControllable) { - uint8_t* modKnobModePointer = view.activeModControllableModelStack.modControllable->getModKnobMode(); - if (modKnobModePointer) - modKnobMode = *modKnobModePointer; - } - if (modKnobMode == 4 && b == MOD_ENCODER_1 && on) { - sessionView.buttonAction(b, on, inCardRoutine); - return ActionResult::DEALT_WITH; - } - } - // Song button if (b == SESSION_VIEW) { if (on) { @@ -910,20 +896,6 @@ ActionResult ArrangerView::padAction(int32_t x, int32_t y, int32_t velocity) { return ActionResult::REMIND_ME_OUTSIDE_CARD_ROUTINE; } - if (runtimeFeatureSettings.get(RuntimeFeatureSettingType::MasterCompressorFx) == RuntimeFeatureStateToggle::On - && currentUIMode == UI_MODE_NONE) { //master compressor - int32_t modKnobMode = -1; - if (view.activeModControllableModelStack.modControllable) { - uint8_t* modKnobModePointer = view.activeModControllableModelStack.modControllable->getModKnobMode(); - if (modKnobModePointer) - modKnobMode = *modKnobModePointer; - } - if (modKnobMode == 4 && Buttons::isShiftButtonPressed() && x == 10 && y < 6 && velocity) { - sessionView.padAction(x, y, velocity); - return ActionResult::DEALT_WITH; - } - } - Output* output = outputsOnScreen[y]; // Audition pad @@ -2387,18 +2359,7 @@ void ArrangerView::selectEncoderAction(int8_t offset) { } void ArrangerView::modEncoderAction(int32_t whichModEncoder, int32_t offset) { - if (runtimeFeatureSettings.get(RuntimeFeatureSettingType::MasterCompressorFx) == RuntimeFeatureStateToggle::On - && currentUIMode == UI_MODE_NONE) { - int32_t modKnobMode = -1; - if (view.activeModControllableModelStack.modControllable) { - uint8_t* modKnobModePointer = view.activeModControllableModelStack.modControllable->getModKnobMode(); - if (modKnobModePointer) - modKnobMode = *modKnobModePointer; - } - if (modKnobMode == 4 && whichModEncoder == 1) { //upper encoder - sessionView.modEncoderAction(whichModEncoder, offset); - } - } + TimelineView::modEncoderAction(whichModEncoder, offset); } @@ -2906,20 +2867,25 @@ static const uint32_t autoScrollUIModes[] = {UI_MODE_HOLDING_HORIZONTAL_ENCODER_ UI_MODE_HOLDING_ARRANGEMENT_ROW_AUDITION, UI_MODE_HORIZONTAL_ZOOM, 0}; void ArrangerView::graphicsRoutine() { - - if (runtimeFeatureSettings.get(RuntimeFeatureSettingType::MasterCompressorFx) == RuntimeFeatureStateToggle::On - && currentUIMode == UI_MODE_NONE) { + static int counter = 0; + if (currentUIMode == UI_MODE_NONE) { int32_t modKnobMode = -1; + bool editingComp = false; if (view.activeModControllableModelStack.modControllable) { uint8_t* modKnobModePointer = view.activeModControllableModelStack.modControllable->getModKnobMode(); - if (modKnobModePointer) + if (modKnobModePointer) { modKnobMode = *modKnobModePointer; + editingComp = view.activeModControllableModelStack.modControllable->isEditingComp(); + } } - - if (modKnobMode == 4) { //upper - int32_t gr = AudioEngine::mastercompressor.gr; - - indicator_leds::setKnobIndicatorLevel(1, gr); //Gain Reduction LED + if (modKnobMode == 4 && editingComp) { //upper + counter = (counter + 1) % 5; + if (counter == 0) { + uint8_t gr = AudioEngine::mastercompressor.gr; + uint8_t mv = int(6 * AudioEngine::mastercompressor.meanVolume); + indicator_leds::setKnobIndicatorLevel(1, gr); //Gain Reduction LED + indicator_leds::setKnobIndicatorLevel(0, mv); //Input level LED + } } } diff --git a/src/deluge/gui/views/session_view.cpp b/src/deluge/gui/views/session_view.cpp index 69275a8e6e..d6425dded8 100644 --- a/src/deluge/gui/views/session_view.cpp +++ b/src/deluge/gui/views/session_view.cpp @@ -575,46 +575,6 @@ ActionResult SessionView::padAction(int32_t xDisplay, int32_t yDisplay, int32_t return gridHandlePads(xDisplay, yDisplay, on); } - if (runtimeFeatureSettings.get(RuntimeFeatureSettingType::MasterCompressorFx) == RuntimeFeatureStateToggle::On - && currentUIMode == UI_MODE_NONE) { //master compressor - int32_t modKnobMode = -1; - if (view.activeModControllableModelStack.modControllable) { - uint8_t* modKnobModePointer = view.activeModControllableModelStack.modControllable->getModKnobMode(); - if (modKnobModePointer) - modKnobMode = *modKnobModePointer; - } - const char* paramLabels[] = {"THRE", "MAKE", "ATTK", "REL", "RATI", "MIX"}; - - if (modKnobMode == 4 && Buttons::isShiftButtonPressed() && xDisplay == 10 && yDisplay < 6 && on) { - if (yDisplay == 0) { //[RELEASE] - masterCompEditMode = 3; //REL - } - else if (yDisplay == 1) { //[SYNC] - masterCompEditMode = 1; //MAKE - } - else if (yDisplay == 2) { //[VOL DUCK] - masterCompEditMode = 0; //THRE - } - else if (yDisplay == 3) { //[ATTAK] - masterCompEditMode = 2; //ATTK - } - else if (yDisplay == 4) { //[SHAPE] - masterCompEditMode = 4; //RATI - } - else if (yDisplay == 5) { //[SEND] - masterCompEditMode = 5; //MIX - } - - if (display->haveOLED()) { - modEncoderAction(1, 0); - } - else { - display->displayPopup(paramLabels[masterCompEditMode]); - } - return ActionResult::DEALT_WITH; - } - } - Clip* clip = getClipOnScreen(yDisplay); int32_t clipIndex = yDisplay + currentSong->songViewYScroll; @@ -1947,8 +1907,7 @@ void SessionView::cloneClip(uint8_t yDisplayFrom, uint8_t yDisplayTo) { void SessionView::graphicsRoutine() { static int counter = 0; - if (runtimeFeatureSettings.get(RuntimeFeatureSettingType::MasterCompressorFx) == RuntimeFeatureStateToggle::On - && currentUIMode == UI_MODE_NONE) { + if (currentUIMode == UI_MODE_NONE) { int32_t modKnobMode = -1; bool editingComp = false; if (view.activeModControllableModelStack.modControllable) { @@ -2689,15 +2648,6 @@ void SessionView::midiLearnFlash() { void SessionView::modEncoderAction(int32_t whichModEncoder, int32_t offset) { performActionOnPadRelease = false; - if (runtimeFeatureSettings.get(RuntimeFeatureSettingType::MasterCompressorFx) == RuntimeFeatureStateToggle::On - && currentUIMode == UI_MODE_NONE) { - int32_t modKnobMode = -1; - if (view.activeModControllableModelStack.modControllable) { - uint8_t* modKnobModePointer = view.activeModControllableModelStack.modControllable->getModKnobMode(); - if (modKnobModePointer) - modKnobMode = *modKnobModePointer; - } - } if (getCurrentUI() == this) { //This routine may also be called from the Arranger view ClipNavigationTimelineView::modEncoderAction(whichModEncoder, offset); } diff --git a/src/deluge/model/settings/runtime_feature_settings.cpp b/src/deluge/model/settings/runtime_feature_settings.cpp index 4aa6b4bf21..0f8d1d24e0 100644 --- a/src/deluge/model/settings/runtime_feature_settings.cpp +++ b/src/deluge/model/settings/runtime_feature_settings.cpp @@ -83,10 +83,6 @@ void RuntimeFeatureSettings::init() { SetupOnOffSetting(settings[RuntimeFeatureSettingType::DrumRandomizer], deluge::l10n::getView(STRING_FOR_COMMUNITY_FEATURE_DRUM_RANDOMIZER), "drumRandomizer", RuntimeFeatureStateToggle::On); - // Master compressor - SetupOnOffSetting(settings[RuntimeFeatureSettingType::MasterCompressorFx], - deluge::l10n::getView(STRING_FOR_COMMUNITY_FEATURE_MASTER_COMPRESSOR), "masterCompressor", - RuntimeFeatureStateToggle::On); // Quantize SetupOnOffSetting(settings[RuntimeFeatureSettingType::Quantize], deluge::l10n::getView(STRING_FOR_COMMUNITY_FEATURE_QUANTIZE), "quantize", diff --git a/src/deluge/model/settings/runtime_feature_settings.h b/src/deluge/model/settings/runtime_feature_settings.h index 48c080db79..4f5fd2cdb3 100644 --- a/src/deluge/model/settings/runtime_feature_settings.h +++ b/src/deluge/model/settings/runtime_feature_settings.h @@ -39,7 +39,6 @@ enum RuntimeFeatureStateSyncScalingAction : uint32_t { SyncScaling = 0, Fill = 1 /// Every setting needs to be declared in here enum RuntimeFeatureSettingType : uint32_t { DrumRandomizer, - MasterCompressorFx, Quantize, FineTempoKnob, PatchCableResolution, diff --git a/src/deluge/model/song/song.cpp b/src/deluge/model/song/song.cpp index 1501ac6173..659bc12dc1 100644 --- a/src/deluge/model/song/song.cpp +++ b/src/deluge/model/song/song.cpp @@ -1124,20 +1124,18 @@ void Song::writeToFile() { storageManager.writeClosingTag("reverb"); - if (runtimeFeatureSettings.get(RuntimeFeatureSettingType::MasterCompressorFx) == RuntimeFeatureStateToggle::On) { - storageManager.writeOpeningTagBeginning("masterCompressor"); - int32_t attack = AudioEngine::mastercompressor.attack; - int32_t release = AudioEngine::mastercompressor.release; - int32_t thresh = AudioEngine::mastercompressor.threshold; - int32_t ratio = AudioEngine::mastercompressor.ratio; + storageManager.writeOpeningTagBeginning("masterCompressor"); + int32_t attack = AudioEngine::mastercompressor.attack; + int32_t release = AudioEngine::mastercompressor.release; + int32_t thresh = AudioEngine::mastercompressor.threshold; + int32_t ratio = AudioEngine::mastercompressor.ratio; - storageManager.writeAttribute("attack", attack); - storageManager.writeAttribute("release", release); - storageManager.writeAttribute("thresh", thresh); - storageManager.writeAttribute("ratio", ratio); + storageManager.writeAttribute("attack", attack); + storageManager.writeAttribute("release", release); + storageManager.writeAttribute("thresh", thresh); + storageManager.writeAttribute("ratio", ratio); - storageManager.closeTag(); - } + storageManager.closeTag(); globalEffectable.writeTagsToFile(NULL, false); @@ -1480,10 +1478,7 @@ int32_t Song::readFromFile() { storageManager.exitTag("affectEntire"); } - else if (!strcmp(tagName, "masterCompressor") - && runtimeFeatureSettings.get(RuntimeFeatureSettingType::MasterCompressorFx) - == RuntimeFeatureStateToggle::On) { - AudioEngine::mastercompressor.gr = 0.0; + else if (!strcmp(tagName, "masterCompressor")) { while (*(tagName = storageManager.readNextTagOrAttributeName())) { if (!strcmp(tagName, "attack")) { //ms masterCompressorAttack = storageManager.readTagOrAttributeValueInt(); @@ -1501,14 +1496,6 @@ int32_t Song::readFromFile() { masterCompressorRatio = storageManager.readTagOrAttributeValueInt(); storageManager.exitTag("ratio"); } - else if (!strcmp(tagName, "makeup")) { //db - masterCompressorMakeup = storageManager.readTagOrAttributeValueInt(); - storageManager.exitTag("makeup"); - } - else if (!strcmp(tagName, "wet")) { //0.0-1.0 - masterCompressorWet = storageManager.readTagOrAttributeValueInt(); - storageManager.exitTag("wet"); - } else { storageManager.exitTag(tagName); } From 955909ce9dd1534d88efed1fbf97f5d074684c17 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Fri, 20 Oct 2023 15:18:38 -0400 Subject: [PATCH 17/38] dbt format --- src/deluge/model/song/song.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/deluge/model/song/song.cpp b/src/deluge/model/song/song.cpp index 659bc12dc1..7d838f78ff 100644 --- a/src/deluge/model/song/song.cpp +++ b/src/deluge/model/song/song.cpp @@ -2672,7 +2672,7 @@ int32_t Song::getCurrentPresetScale() { // If we're here, must be this one! return p; -notThisOne: {} +notThisOne : {} } return 255; @@ -4561,7 +4561,7 @@ Instrument* Song::changeInstrumentType(Instrument* oldInstrument, InstrumentType return NULL; } -gotAnInstrument: {} +gotAnInstrument : {} } // Synth or Kit From 97e99ac77ec1e40e6c7c7dd182757948de4a39ce Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Fri, 20 Oct 2023 20:11:25 -0400 Subject: [PATCH 18/38] fix gain scaling --- src/deluge/dsp/master_compressor/master_compressor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 23898f41ed..3667b57a52 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -61,7 +61,8 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { //this will be negative float reduction = 21 * (out / ONE_Q31f); //this lowers the volume so we'll increase the levels afterwards - finalVolume = exp(er + reduction) * float(1 << 26); + + finalVolume = exp(std::max(er + reduction, 1)) * float(1 << 29); amplitudeIncrement = (int32_t)(finalVolume - currentVolume) / numSamples; From ed2fd93385e6e39441f40cb7b422d0c05e157a98 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Fri, 20 Oct 2023 20:13:47 -0400 Subject: [PATCH 19/38] fix gain scaling properly --- src/deluge/dsp/master_compressor/master_compressor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 3667b57a52..ae362c7126 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -62,7 +62,7 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { float reduction = 21 * (out / ONE_Q31f); //this lowers the volume so we'll increase the levels afterwards - finalVolume = exp(std::max(er + reduction, 1)) * float(1 << 29); + finalVolume = exp(std::min(er + reduction, 1)) * float(1 << 29); amplitudeIncrement = (int32_t)(finalVolume - currentVolume) / numSamples; From 85fe37e3ebba9549cc5b61752a37a19b6039a804 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Sat, 21 Oct 2023 11:58:44 -0400 Subject: [PATCH 20/38] improve parameter scaling and makeup --- .../dsp/master_compressor/master_compressor.cpp | 4 ++-- src/deluge/gui/views/arranger_view.cpp | 4 ++-- src/deluge/gui/views/session_view.cpp | 4 ++-- .../global_effectable/global_effectable.cpp | 17 +++++++++-------- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index ae362c7126..c585415c89 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -38,9 +38,9 @@ MasterCompressor::MasterCompressor() { } void MasterCompressor::updateER() { - threshdb = 8 + 13 * (threshold / ONE_Q31f); + threshdb = 16 * (threshold / ONE_Q31f); //14 is about the level of a single synth voice - er = std::clamp((14 - threshdb) * (float(ratio) / ONE_Q31f), 0, 4); + er = std::clamp((16 - threshdb) * (float(ratio) / ONE_Q31f), 0, 4); } //with floats baseline is 60-90us diff --git a/src/deluge/gui/views/arranger_view.cpp b/src/deluge/gui/views/arranger_view.cpp index 711b2c1495..1d9d36df24 100644 --- a/src/deluge/gui/views/arranger_view.cpp +++ b/src/deluge/gui/views/arranger_view.cpp @@ -2882,9 +2882,9 @@ void ArrangerView::graphicsRoutine() { counter = (counter + 1) % 5; if (counter == 0) { uint8_t gr = AudioEngine::mastercompressor.gr; - uint8_t mv = int(6 * AudioEngine::mastercompressor.meanVolume); + //uint8_t mv = int(6 * AudioEngine::mastercompressor.meanVolume); indicator_leds::setKnobIndicatorLevel(1, gr); //Gain Reduction LED - indicator_leds::setKnobIndicatorLevel(0, mv); //Input level LED + //indicator_leds::setKnobIndicatorLevel(0, mv); //Input level LED } } } diff --git a/src/deluge/gui/views/session_view.cpp b/src/deluge/gui/views/session_view.cpp index d6425dded8..f85c71a197 100644 --- a/src/deluge/gui/views/session_view.cpp +++ b/src/deluge/gui/views/session_view.cpp @@ -1921,9 +1921,9 @@ void SessionView::graphicsRoutine() { counter = (counter + 1) % 5; if (counter == 0) { uint8_t gr = AudioEngine::mastercompressor.gr; - uint8_t mv = int(6 * AudioEngine::mastercompressor.meanVolume); + //uint8_t mv = int(6 * AudioEngine::mastercompressor.meanVolume); indicator_leds::setKnobIndicatorLevel(1, gr); //Gain Reduction LED - indicator_leds::setKnobIndicatorLevel(0, mv); //Input level LED + //indicator_leds::setKnobIndicatorLevel(0, mv); //Input level LED } } } diff --git a/src/deluge/model/global_effectable/global_effectable.cpp b/src/deluge/model/global_effectable/global_effectable.cpp index 92024f1f1a..2481f2c9c7 100644 --- a/src/deluge/model/global_effectable/global_effectable.cpp +++ b/src/deluge/model/global_effectable/global_effectable.cpp @@ -286,20 +286,21 @@ ActionResult GlobalEffectable::modEncoderActionForNonExistentParam(int32_t offse ModelStackWithAutoParam* modelStack) { if (*getModKnobMode() == 4) { if (whichModEncoder == 1) { //sidechain (threshold) - int current = AudioEngine::mastercompressor.threshold >> 25; + int current = AudioEngine::mastercompressor.threshold >> 24; current -= offset; - current = std::clamp(current, 2, 50); + current = std::clamp(current, 1, 128); indicator_leds::setKnobIndicatorLevel(1, std::max(0, 128 - 3 * (current - 2))); - AudioEngine::mastercompressor.threshold = lshiftAndSaturate<25>(current); + AudioEngine::mastercompressor.threshold = lshiftAndSaturate<24>(current); AudioEngine::mastercompressor.updateER(); return ActionResult::DEALT_WITH; } - else if (whichModEncoder == 0) { //reverb (we can only get here in comp editing mode) - int current = AudioEngine::mastercompressor.ratio >> 27; + else if (whichModEncoder == 0) { //ratio/reverb (we can only get here in comp editing mode) + int current = AudioEngine::mastercompressor.ratio >> 24; current += offset; - current = std::clamp(current, 1, 16); - indicator_leds::setKnobIndicatorLevel(0, std::max(0, current << 3)); - AudioEngine::mastercompressor.ratio = lshiftAndSaturate<27>(current); + //this range is ratio of 2 to infinity + current = std::clamp(current, 64, 128); + indicator_leds::setKnobIndicatorLevel(0, (current - 64) * 2); + AudioEngine::mastercompressor.ratio = lshiftAndSaturate<24>(current); AudioEngine::mastercompressor.updateER(); return ActionResult::DEALT_WITH; } From 91032383bcc90a25de0b90247225cdfe57836fa9 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Sat, 21 Oct 2023 12:40:48 -0400 Subject: [PATCH 21/38] set better defaults --- .../dsp/master_compressor/master_compressor.cpp | 9 ++++----- .../model/global_effectable/global_effectable.cpp | 2 +- src/deluge/model/song/song.cpp | 14 ++++++-------- src/deluge/model/song/song.h | 2 -- src/deluge/processing/engines/audio_engine.cpp | 4 ++-- 5 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index c585415c89..7c12046c40 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -27,10 +27,10 @@ MasterCompressor::MasterCompressor() { //compressor.setRatio(1.0 / ((float)ratio / 100.0)); shape = getParamFromUserValue(Param::Unpatched::COMPRESSOR_SHAPE, 1); //an appropriate range is 0-50*one q 15 - threshold = 15 * ONE_Q15; + threshold = ONE_Q31; follower = true; //this is about a 1:1 ratio - ratio = ONE_Q31 >> 3; + ratio = ONE_Q31 >> 1; syncLevel = SyncLevel::SYNC_LEVEL_NONE; currentVolume = 0; //auto make up gain @@ -40,10 +40,9 @@ MasterCompressor::MasterCompressor() { void MasterCompressor::updateER() { threshdb = 16 * (threshold / ONE_Q31f); //14 is about the level of a single synth voice - er = std::clamp((16 - threshdb) * (float(ratio) / ONE_Q31f), 0, 4); + er = std::clamp((16 - threshdb) * (float(ratio) / ONE_Q31f), 0, 15); } -//with floats baseline is 60-90us void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { meanVolume = calc_rms(buffer, numSamples); @@ -79,7 +78,7 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { } while (++thisSample != bufferEnd); //for LEDs //9 converts to dB, quadrupled for display range since a 30db reduction is basically killing the signal - gr = -reduction * 9 * 4; + gr = std::clamp(-reduction * 9 * 4, 0, 127); } //output range is 0-21 (2^31) diff --git a/src/deluge/model/global_effectable/global_effectable.cpp b/src/deluge/model/global_effectable/global_effectable.cpp index 2481f2c9c7..9b102d96be 100644 --- a/src/deluge/model/global_effectable/global_effectable.cpp +++ b/src/deluge/model/global_effectable/global_effectable.cpp @@ -289,7 +289,7 @@ ActionResult GlobalEffectable::modEncoderActionForNonExistentParam(int32_t offse int current = AudioEngine::mastercompressor.threshold >> 24; current -= offset; current = std::clamp(current, 1, 128); - indicator_leds::setKnobIndicatorLevel(1, std::max(0, 128 - 3 * (current - 2))); + indicator_leds::setKnobIndicatorLevel(1, std::max(0, 128 - current)); AudioEngine::mastercompressor.threshold = lshiftAndSaturate<24>(current); AudioEngine::mastercompressor.updateER(); return ActionResult::DEALT_WITH; diff --git a/src/deluge/model/song/song.cpp b/src/deluge/model/song/song.cpp index 7d838f78ff..75ef604df9 100644 --- a/src/deluge/model/song/song.cpp +++ b/src/deluge/model/song/song.cpp @@ -136,12 +136,10 @@ Song::Song() : backedUpParamManagers(sizeof(BackedUpParamManager)) { reverbCompressorShape = -601295438; reverbCompressorSync = SYNC_LEVEL_8TH; - masterCompressorAttack = 7; - masterCompressorRelease = 10; - masterCompressorThresh = 10; - masterCompressorRatio = 10; - masterCompressorMakeup = 0; - masterCompressorWet = 50; + masterCompressorAttack = attackRateTable[2] << 2; + masterCompressorRelease = releaseRateTable[5] << 2; + masterCompressorThresh = ONE_Q31; + masterCompressorRatio = ONE_Q31 >> 1; AudioEngine::mastercompressor.gr = 0.0; dirPath.set("SONGS"); @@ -2672,7 +2670,7 @@ int32_t Song::getCurrentPresetScale() { // If we're here, must be this one! return p; -notThisOne : {} +notThisOne: {} } return 255; @@ -4561,7 +4559,7 @@ Instrument* Song::changeInstrumentType(Instrument* oldInstrument, InstrumentType return NULL; } -gotAnInstrument : {} +gotAnInstrument: {} } // Synth or Kit diff --git a/src/deluge/model/song/song.h b/src/deluge/model/song/song.h index 681ed88af9..5b6e312bfd 100644 --- a/src/deluge/model/song/song.h +++ b/src/deluge/model/song/song.h @@ -330,8 +330,6 @@ class Song final : public TimelineCounter { int32_t masterCompressorRelease; int32_t masterCompressorThresh; int32_t masterCompressorRatio; - int32_t masterCompressorMakeup; - int32_t masterCompressorWet; private: bool fillModeActive; diff --git a/src/deluge/processing/engines/audio_engine.cpp b/src/deluge/processing/engines/audio_engine.cpp index 5837205170..3c1c4193f6 100644 --- a/src/deluge/processing/engines/audio_engine.cpp +++ b/src/deluge/processing/engines/audio_engine.cpp @@ -760,8 +760,8 @@ void routine() { } logAction("mastercomp start"); mastercompressor.render(renderingBuffer, numSamples); - masterVolumeAdjustmentL <<= 3; - masterVolumeAdjustmentR <<= 3; + masterVolumeAdjustmentL <<= 2; + masterVolumeAdjustmentR <<= 2; logAction("mastercomp end"); metronome.render(renderingBuffer, numSamples); From 1340af7a28617055ae2ec1ed65a2b86465c9df92 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Sun, 22 Oct 2023 15:02:32 -0400 Subject: [PATCH 22/38] dbt format --- src/deluge/model/song/song.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/deluge/model/song/song.cpp b/src/deluge/model/song/song.cpp index 75ef604df9..31cf2bad02 100644 --- a/src/deluge/model/song/song.cpp +++ b/src/deluge/model/song/song.cpp @@ -2670,7 +2670,7 @@ int32_t Song::getCurrentPresetScale() { // If we're here, must be this one! return p; -notThisOne: {} +notThisOne : {} } return 255; @@ -4559,7 +4559,7 @@ Instrument* Song::changeInstrumentType(Instrument* oldInstrument, InstrumentType return NULL; } -gotAnInstrument: {} +gotAnInstrument : {} } // Synth or Kit From c0d1785436beb67284c814388d8697b4cc16b4e8 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Mon, 23 Oct 2023 15:56:09 -0400 Subject: [PATCH 23/38] gr to gainReduction --- src/deluge/dsp/master_compressor/master_compressor.cpp | 2 +- src/deluge/dsp/master_compressor/master_compressor.h | 2 +- src/deluge/gui/views/arranger_view.cpp | 2 +- src/deluge/gui/views/session_view.cpp | 2 +- src/deluge/model/song/song.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 7c12046c40..5a1d910dc5 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -78,7 +78,7 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { } while (++thisSample != bufferEnd); //for LEDs //9 converts to dB, quadrupled for display range since a 30db reduction is basically killing the signal - gr = std::clamp(-reduction * 9 * 4, 0, 127); + gainReduction = std::clamp(-reduction * 9 * 4, 0, 127); } //output range is 0-21 (2^31) diff --git a/src/deluge/dsp/master_compressor/master_compressor.h b/src/deluge/dsp/master_compressor/master_compressor.h index 9062e08a82..b71376d2c8 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.h +++ b/src/deluge/dsp/master_compressor/master_compressor.h @@ -35,7 +35,7 @@ class MasterCompressor : public Compressor { void render(StereoSample* buffer, uint16_t numSamples); void updateER(); float calc_rms(StereoSample* buffer, uint16_t numSamples); - uint8_t gr; + uint8_t gainReduction; q31_t threshold; q31_t shape; q31_t ratio; diff --git a/src/deluge/gui/views/arranger_view.cpp b/src/deluge/gui/views/arranger_view.cpp index 1d9d36df24..6800c14de2 100644 --- a/src/deluge/gui/views/arranger_view.cpp +++ b/src/deluge/gui/views/arranger_view.cpp @@ -2881,7 +2881,7 @@ void ArrangerView::graphicsRoutine() { if (modKnobMode == 4 && editingComp) { //upper counter = (counter + 1) % 5; if (counter == 0) { - uint8_t gr = AudioEngine::mastercompressor.gr; + uint8_t gr = AudioEngine::mastercompressor.gainReduction; //uint8_t mv = int(6 * AudioEngine::mastercompressor.meanVolume); indicator_leds::setKnobIndicatorLevel(1, gr); //Gain Reduction LED //indicator_leds::setKnobIndicatorLevel(0, mv); //Input level LED diff --git a/src/deluge/gui/views/session_view.cpp b/src/deluge/gui/views/session_view.cpp index f85c71a197..7c478c403d 100644 --- a/src/deluge/gui/views/session_view.cpp +++ b/src/deluge/gui/views/session_view.cpp @@ -1920,7 +1920,7 @@ void SessionView::graphicsRoutine() { if (modKnobMode == 4 && editingComp) { //upper counter = (counter + 1) % 5; if (counter == 0) { - uint8_t gr = AudioEngine::mastercompressor.gr; + uint8_t gr = AudioEngine::mastercompressor.gainReduction; //uint8_t mv = int(6 * AudioEngine::mastercompressor.meanVolume); indicator_leds::setKnobIndicatorLevel(1, gr); //Gain Reduction LED //indicator_leds::setKnobIndicatorLevel(0, mv); //Input level LED diff --git a/src/deluge/model/song/song.cpp b/src/deluge/model/song/song.cpp index 31cf2bad02..a3848ac583 100644 --- a/src/deluge/model/song/song.cpp +++ b/src/deluge/model/song/song.cpp @@ -140,7 +140,7 @@ Song::Song() : backedUpParamManagers(sizeof(BackedUpParamManager)) { masterCompressorRelease = releaseRateTable[5] << 2; masterCompressorThresh = ONE_Q31; masterCompressorRatio = ONE_Q31 >> 1; - AudioEngine::mastercompressor.gr = 0.0; + AudioEngine::mastercompressor.gainReduction = 0.0; dirPath.set("SONGS"); } From 69255f0cef49773e7c1bef6d6cd0653bd10cff50 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Mon, 23 Oct 2023 16:35:38 -0400 Subject: [PATCH 24/38] fix volume drop again --- src/deluge/dsp/master_compressor/master_compressor.cpp | 2 +- src/deluge/processing/engines/audio_engine.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 5a1d910dc5..956b24b579 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -61,7 +61,7 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { float reduction = 21 * (out / ONE_Q31f); //this lowers the volume so we'll increase the levels afterwards - finalVolume = exp(std::min(er + reduction, 1)) * float(1 << 29); + finalVolume = exp(std::min(1 - er + reduction, 1)) * float(1 << 29); amplitudeIncrement = (int32_t)(finalVolume - currentVolume) / numSamples; diff --git a/src/deluge/processing/engines/audio_engine.cpp b/src/deluge/processing/engines/audio_engine.cpp index 3c1c4193f6..5837205170 100644 --- a/src/deluge/processing/engines/audio_engine.cpp +++ b/src/deluge/processing/engines/audio_engine.cpp @@ -760,8 +760,8 @@ void routine() { } logAction("mastercomp start"); mastercompressor.render(renderingBuffer, numSamples); - masterVolumeAdjustmentL <<= 2; - masterVolumeAdjustmentR <<= 2; + masterVolumeAdjustmentL <<= 3; + masterVolumeAdjustmentR <<= 3; logAction("mastercomp end"); metronome.render(renderingBuffer, numSamples); From 64cf7a0db970fe27044f303719c5b0ff534556bf Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Mon, 23 Oct 2023 19:03:55 -0400 Subject: [PATCH 25/38] fix retroactive sidechain hits --- src/deluge/dsp/compressor/compressor.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/deluge/dsp/compressor/compressor.cpp b/src/deluge/dsp/compressor/compressor.cpp index cf73e5645e..b60ff38410 100644 --- a/src/deluge/dsp/compressor/compressor.cpp +++ b/src/deluge/dsp/compressor/compressor.cpp @@ -81,11 +81,14 @@ void Compressor::registerHitRetrospectively(int32_t strength, uint32_t numSample // If we're still in the release stage... if (numSamplesSinceRelease < releaseStageLengthInSamples) { pos = numSamplesSinceRelease * alteredRelease; + envelopeHeight = ONE_Q31 - envelopeOffset; + envelopeOffset = ONE_Q31; status = EnvelopeStage::RELEASE; } // Or if we're past the release stage... else { + envelopeOffset = ONE_Q31; status = EnvelopeStage::OFF; } } @@ -137,15 +140,18 @@ int32_t Compressor::render(uint16_t numSamples, int32_t shapeValue) { // If attack is all the way down, jump directly to release stage if (attack == attackRateTable[0] << 2) { envelopeHeight = ONE_Q31 - envelopeOffset; + envelopeOffset = ONE_Q31; pos = 0; status = EnvelopeStage::RELEASE; } - if (status != EnvelopeStage::ATTACK) { - status = EnvelopeStage::ATTACK; - pos = 0; - } + else { + if (status != EnvelopeStage::ATTACK) { + status = EnvelopeStage::ATTACK; + pos = 0; + } - envelopeHeight = lastValue - envelopeOffset; + envelopeHeight = lastValue - envelopeOffset; + } } //or if we're working in follower mode, in which case we want to start releasing whenever the current hit strength is below the envelope level else if (follower && newOffset > envelopeOffset) { From 2e9acef12f0596a432cf0e0794457334999062e1 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Tue, 24 Oct 2023 11:21:57 -0400 Subject: [PATCH 26/38] improve gain scaling --- src/deluge/dsp/compressor/compressor.cpp | 10 ++++- .../master_compressor/master_compressor.cpp | 41 ++++++++++++------- .../dsp/master_compressor/master_compressor.h | 12 ++++-- .../global_effectable/global_effectable.cpp | 4 +- .../processing/engines/audio_engine.cpp | 6 +-- 5 files changed, 48 insertions(+), 25 deletions(-) diff --git a/src/deluge/dsp/compressor/compressor.cpp b/src/deluge/dsp/compressor/compressor.cpp index b60ff38410..8043dbab70 100644 --- a/src/deluge/dsp/compressor/compressor.cpp +++ b/src/deluge/dsp/compressor/compressor.cpp @@ -145,10 +145,13 @@ int32_t Compressor::render(uint16_t numSamples, int32_t shapeValue) { status = EnvelopeStage::RELEASE; } else { - if (status != EnvelopeStage::ATTACK) { + if (status == EnvelopeStage::HOLD) { status = EnvelopeStage::ATTACK; pos = 0; } + else if (status != EnvelopeStage::ATTACK) { + status = EnvelopeStage::HOLD; + } envelopeHeight = lastValue - envelopeOffset; } @@ -157,10 +160,13 @@ int32_t Compressor::render(uint16_t numSamples, int32_t shapeValue) { else if (follower && newOffset > envelopeOffset) { envelopeOffset = newOffset; envelopeHeight = newOffset - lastValue; - if (status != EnvelopeStage::RELEASE) { + if (status == EnvelopeStage::HOLD) { pos = 0; status = EnvelopeStage::RELEASE; } + else if (status != EnvelopeStage::RELEASE) { + status = EnvelopeStage::HOLD; + } } } if (status == EnvelopeStage::ATTACK) { diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 956b24b579..9902856abc 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -17,6 +17,8 @@ #include "dsp/master_compressor/master_compressor.h" #include "dsp/stereo_sample.h" +#include "io/debug/print.h" +#include "processing/engines/audio_engine.h" #include "util/fast_fixed_math.h" MasterCompressor::MasterCompressor() { //compressor.setAttack((float)attack / 100.0); @@ -25,25 +27,27 @@ MasterCompressor::MasterCompressor() { //compressor.setRelease((float)release / 100.0); //compressor.setThresh((float)threshold / 100.0); //compressor.setRatio(1.0 / ((float)ratio / 100.0)); - shape = getParamFromUserValue(Param::Unpatched::COMPRESSOR_SHAPE, 1); + shape = getParamFromUserValue(Param::Unpatched::COMPRESSOR_SHAPE, 2); //an appropriate range is 0-50*one q 15 threshold = ONE_Q31; follower = true; //this is about a 1:1 ratio ratio = ONE_Q31 >> 1; syncLevel = SyncLevel::SYNC_LEVEL_NONE; - currentVolume = 0; + currentVolumeL = 0; + currentVolumeR = 0; //auto make up gain updateER(); } - +//16 is ln(1<<24) - 1, i.e. where we start clipping +//since this applies to output void MasterCompressor::updateER() { threshdb = 16 * (threshold / ONE_Q31f); //14 is about the level of a single synth voice - er = std::clamp((16 - threshdb) * (float(ratio) / ONE_Q31f), 0, 15); + er = std::clamp((16 - threshdb) * (float(ratio) / ONE_Q31f), 0, 18); } -void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { +void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t volAdjustL, q31_t volAdjustR) { meanVolume = calc_rms(buffer, numSamples); q31_t over = std::max(0, (meanVolume - threshdb) / 21) * ONE_Q31; @@ -52,6 +56,7 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { registerHit(over); } out = Compressor::render(numSamples, shape); + out = multiply_32x32_rshift32(out, ratio) << 1; //21 is the max internal volume (i.e. one_q31) @@ -59,26 +64,34 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples) { //base is arbitrary for scale, important part is the shape //this will be negative float reduction = 21 * (out / ONE_Q31f); - //this lowers the volume so we'll increase the levels afterwards + //So basically this limits the gain to not clip + //18 - meanVolume is the magic amount that makes sure the output + //won't exceed 1<<24 + float dbGain = std::min(2 + er + reduction, 18 - meanVolume); + + float gain = exp(dbGain); - finalVolume = exp(std::min(1 - er + reduction, 1)) * float(1 << 29); + finalVolumeL = gain * float(volAdjustL); + finalVolumeR = gain * float(volAdjustR); - amplitudeIncrement = (int32_t)(finalVolume - currentVolume) / numSamples; + amplitudeIncrementL = (int32_t)(finalVolumeL - currentVolumeL) / numSamples; + amplitudeIncrementR = (int32_t)(finalVolumeR - currentVolumeR) / numSamples; StereoSample* thisSample = buffer; StereoSample* bufferEnd = buffer + numSamples; do { - currentVolume += amplitudeIncrement; + currentVolumeL += amplitudeIncrementL; + currentVolumeR += amplitudeIncrementR; // Apply post-fx and post-reverb-send volume - thisSample->l = multiply_32x32_rshift32(thisSample->l, currentVolume) << 1; - thisSample->r = multiply_32x32_rshift32(thisSample->r, currentVolume) << 1; + thisSample->l = multiply_32x32_rshift32(thisSample->l, currentVolumeL) << 1; + thisSample->r = multiply_32x32_rshift32(thisSample->r, currentVolumeR) << 1; } while (++thisSample != bufferEnd); //for LEDs //9 converts to dB, quadrupled for display range since a 30db reduction is basically killing the signal - gainReduction = std::clamp(-reduction * 9 * 4, 0, 127); + gainReduction = std::clamp(-(2 + reduction) * 9 * 4, 0, 127); } //output range is 0-21 (2^31) @@ -88,7 +101,7 @@ float MasterCompressor::calc_rms(StereoSample* buffer, uint16_t numSamples) { StereoSample* bufferEnd = buffer + numSamples; q31_t sum = 0; q31_t offset = 0; //to remove dc offset - q31_t last_mean = mean; + float lastMean = mean; do { q31_t s = std::abs(thisSample->l) + std::abs(thisSample->r); sum += multiply_32x32_rshift32(s, s) << 1; @@ -103,7 +116,7 @@ float MasterCompressor::calc_rms(StereoSample* buffer, uint16_t numSamples) { mean = rms - dc / 1.4f; mean = std::max(mean, 1.0f); - float logmean = std::log(mean); + float logmean = std::log((mean + lastMean) / 2); return logmean; } diff --git a/src/deluge/dsp/master_compressor/master_compressor.h b/src/deluge/dsp/master_compressor/master_compressor.h index b71376d2c8..536351ff39 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.h +++ b/src/deluge/dsp/master_compressor/master_compressor.h @@ -32,18 +32,22 @@ class MasterCompressor : public Compressor { MasterCompressor(); void setup(int32_t attack, int32_t release, int32_t threshold, int32_t ratio); - void render(StereoSample* buffer, uint16_t numSamples); + void render(StereoSample* buffer, uint16_t numSamples, q31_t volAdjustL, q31_t volAdjustR); void updateER(); float calc_rms(StereoSample* buffer, uint16_t numSamples); uint8_t gainReduction; + bool dither; q31_t threshold; q31_t shape; q31_t ratio; q31_t out; q31_t over; - q31_t finalVolume; - q31_t currentVolume; - q31_t amplitudeIncrement; + q31_t finalVolumeL; + q31_t currentVolumeL; + q31_t finalVolumeR; + q31_t currentVolumeR; + q31_t amplitudeIncrementL; + q31_t amplitudeIncrementR; float meanVolume; float mean; float er; diff --git a/src/deluge/model/global_effectable/global_effectable.cpp b/src/deluge/model/global_effectable/global_effectable.cpp index 9b102d96be..0effb3d470 100644 --- a/src/deluge/model/global_effectable/global_effectable.cpp +++ b/src/deluge/model/global_effectable/global_effectable.cpp @@ -317,11 +317,11 @@ ActionResult GlobalEffectable::modEncoderActionForNonExistentParam(int32_t offse return ActionResult::DEALT_WITH; } if (whichModEncoder == 0) { //attack - int current = getLookupIndexFromValue(AudioEngine::mastercompressor.release >> 2, releaseRateTable, 50); + int current = getLookupIndexFromValue(AudioEngine::mastercompressor.release >> 1, releaseRateTable, 50); current += offset; current = std::clamp(current, 1, 50); indicator_leds::setKnobIndicatorLevel(0, (current * 128) / 50); - AudioEngine::mastercompressor.release = releaseRateTable[current] << 2; + AudioEngine::mastercompressor.release = releaseRateTable[current] << 1; return ActionResult::DEALT_WITH; } diff --git a/src/deluge/processing/engines/audio_engine.cpp b/src/deluge/processing/engines/audio_engine.cpp index 5837205170..364a4d90d3 100644 --- a/src/deluge/processing/engines/audio_engine.cpp +++ b/src/deluge/processing/engines/audio_engine.cpp @@ -759,9 +759,9 @@ void routine() { } } logAction("mastercomp start"); - mastercompressor.render(renderingBuffer, numSamples); - masterVolumeAdjustmentL <<= 3; - masterVolumeAdjustmentR <<= 3; + mastercompressor.render(renderingBuffer, numSamples, masterVolumeAdjustmentL, masterVolumeAdjustmentR); + masterVolumeAdjustmentL = ONE_Q31; + masterVolumeAdjustmentR = ONE_Q31; logAction("mastercomp end"); metronome.render(renderingBuffer, numSamples); From 2cb70a6f28244f5fe2eb6d8ded796ed4767090e8 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Tue, 24 Oct 2023 12:35:14 -0400 Subject: [PATCH 27/38] fix sidechain not releasing --- src/deluge/dsp/compressor/compressor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deluge/dsp/compressor/compressor.cpp b/src/deluge/dsp/compressor/compressor.cpp index 8043dbab70..d129f40113 100644 --- a/src/deluge/dsp/compressor/compressor.cpp +++ b/src/deluge/dsp/compressor/compressor.cpp @@ -145,7 +145,7 @@ int32_t Compressor::render(uint16_t numSamples, int32_t shapeValue) { status = EnvelopeStage::RELEASE; } else { - if (status == EnvelopeStage::HOLD) { + if (!follower || status == EnvelopeStage::HOLD) { status = EnvelopeStage::ATTACK; pos = 0; } From 5cf04efa5808fe80d655bd8f6cba9700cc9723fe Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Tue, 24 Oct 2023 12:35:26 -0400 Subject: [PATCH 28/38] tweak makeup gain again --- .../dsp/master_compressor/master_compressor.cpp | 14 +++++++------- .../dsp/master_compressor/master_compressor.h | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 9902856abc..7b5c3bc237 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -42,9 +42,9 @@ MasterCompressor::MasterCompressor() { //16 is ln(1<<24) - 1, i.e. where we start clipping //since this applies to output void MasterCompressor::updateER() { - threshdb = 16 * (threshold / ONE_Q31f); - //14 is about the level of a single synth voice - er = std::clamp((16 - threshdb) * (float(ratio) / ONE_Q31f), 0, 18); + threshdb = 18 * (threshold / ONE_Q31f); + //16 is about the level of a single synth voice at max volume + er = std::clamp((18 - threshdb) * (float(ratio >> 15) / ONE_Q15), 0, 18); } void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t volAdjustL, q31_t volAdjustR) { @@ -67,10 +67,10 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t v //So basically this limits the gain to not clip //18 - meanVolume is the magic amount that makes sure the output //won't exceed 1<<24 - float dbGain = std::min(2 + er + reduction, 18 - meanVolume); - - float gain = exp(dbGain); + float dbGain = std::min(0.5 + er + reduction, 18 - meanVolume); + float gain = exp((dbGain + lastGain) / 2); + lastGain = dbGain; finalVolumeL = gain * float(volAdjustL); finalVolumeR = gain * float(volAdjustR); @@ -91,7 +91,7 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t v } while (++thisSample != bufferEnd); //for LEDs //9 converts to dB, quadrupled for display range since a 30db reduction is basically killing the signal - gainReduction = std::clamp(-(2 + reduction) * 9 * 4, 0, 127); + gainReduction = std::clamp(-(reduction) * 9 * 4, 0, 127); } //output range is 0-21 (2^31) diff --git a/src/deluge/dsp/master_compressor/master_compressor.h b/src/deluge/dsp/master_compressor/master_compressor.h index 536351ff39..9f9b450ba8 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.h +++ b/src/deluge/dsp/master_compressor/master_compressor.h @@ -50,6 +50,7 @@ class MasterCompressor : public Compressor { q31_t amplitudeIncrementR; float meanVolume; float mean; + float lastGain; float er; float threshdb; }; From de3142325c24fa07598ec15544e6d22efee6fefd Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Tue, 24 Oct 2023 12:54:48 -0400 Subject: [PATCH 29/38] float division for speed and accuracy --- .../dsp/master_compressor/master_compressor.cpp | 11 ++++++----- src/deluge/dsp/master_compressor/master_compressor.h | 5 +---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 7b5c3bc237..52f393fb98 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -68,14 +68,15 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t v //18 - meanVolume is the magic amount that makes sure the output //won't exceed 1<<24 float dbGain = std::min(0.5 + er + reduction, 18 - meanVolume); - + //additionally this is the most gain available without overflow + dbGain = std::min(dbGain, 2.75f); float gain = exp((dbGain + lastGain) / 2); lastGain = dbGain; - finalVolumeL = gain * float(volAdjustL); - finalVolumeR = gain * float(volAdjustR); + float finalVolumeL = gain * float(volAdjustL); + float finalVolumeR = gain * float(volAdjustR); - amplitudeIncrementL = (int32_t)(finalVolumeL - currentVolumeL) / numSamples; - amplitudeIncrementR = (int32_t)(finalVolumeR - currentVolumeR) / numSamples; + q31_t amplitudeIncrementL = (int32_t)((finalVolumeL - currentVolumeL) / float(numSamples)); + q31_t amplitudeIncrementR = (int32_t)((finalVolumeR - currentVolumeR) / float(numSamples)); StereoSample* thisSample = buffer; StereoSample* bufferEnd = buffer + numSamples; diff --git a/src/deluge/dsp/master_compressor/master_compressor.h b/src/deluge/dsp/master_compressor/master_compressor.h index 9f9b450ba8..b1b107aff1 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.h +++ b/src/deluge/dsp/master_compressor/master_compressor.h @@ -42,12 +42,9 @@ class MasterCompressor : public Compressor { q31_t ratio; q31_t out; q31_t over; - q31_t finalVolumeL; q31_t currentVolumeL; - q31_t finalVolumeR; q31_t currentVolumeR; - q31_t amplitudeIncrementL; - q31_t amplitudeIncrementR; + float meanVolume; float mean; float lastGain; From 85a737de89ff24e06012738feb741326ccf22068 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Tue, 24 Oct 2023 12:55:03 -0400 Subject: [PATCH 30/38] adjust ratio range --- src/deluge/model/global_effectable/global_effectable.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/deluge/model/global_effectable/global_effectable.cpp b/src/deluge/model/global_effectable/global_effectable.cpp index 0effb3d470..4df43b7fae 100644 --- a/src/deluge/model/global_effectable/global_effectable.cpp +++ b/src/deluge/model/global_effectable/global_effectable.cpp @@ -298,8 +298,8 @@ ActionResult GlobalEffectable::modEncoderActionForNonExistentParam(int32_t offse int current = AudioEngine::mastercompressor.ratio >> 24; current += offset; //this range is ratio of 2 to infinity - current = std::clamp(current, 64, 128); - indicator_leds::setKnobIndicatorLevel(0, (current - 64) * 2); + current = std::clamp(current, 48, 112); + indicator_leds::setKnobIndicatorLevel(0, (current - 48) * 2); AudioEngine::mastercompressor.ratio = lshiftAndSaturate<24>(current); AudioEngine::mastercompressor.updateER(); return ActionResult::DEALT_WITH; From bba442690a918e2095c9666b970673e3db64f6f8 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Tue, 24 Oct 2023 14:37:52 -0400 Subject: [PATCH 31/38] tie threshold to song volume --- .../master_compressor/master_compressor.cpp | 33 ++++++++++++++----- .../global_effectable/global_effectable.cpp | 8 ++--- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 52f393fb98..51e2601760 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -18,6 +18,8 @@ #include "dsp/master_compressor/master_compressor.h" #include "dsp/stereo_sample.h" #include "io/debug/print.h" +#include "model/song/song.h" +#include "modulation/params/param_set.h" #include "processing/engines/audio_engine.h" #include "util/fast_fixed_math.h" MasterCompressor::MasterCompressor() { @@ -42,12 +44,27 @@ MasterCompressor::MasterCompressor() { //16 is ln(1<<24) - 1, i.e. where we start clipping //since this applies to output void MasterCompressor::updateER() { - threshdb = 18 * (threshold / ONE_Q31f); + + //int32_t volumePostFX = getParamNeutralValue(Param::Global::VOLUME_POST_FX); + float songVolume; + if (currentSong) { + int32_t volumePostFX = + getFinalParameterValueVolume( + 134217728, cableToLinearParamShortcut(currentSong->paramManager.getUnpatchedParamSet()->getValue( + Param::Unpatched::GlobalEffectable::VOLUME))) + >> 1; + songVolume = std::log(volumePostFX); + } + else { + songVolume = 16; + } + threshdb = songVolume * (threshold / ONE_Q31f); //16 is about the level of a single synth voice at max volume - er = std::clamp((18 - threshdb) * (float(ratio >> 15) / ONE_Q15), 0, 18); + er = (songVolume - threshdb) * (float(ratio) / ONE_Q31); } void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t volAdjustL, q31_t volAdjustR) { + updateER(); meanVolume = calc_rms(buffer, numSamples); q31_t over = std::max(0, (meanVolume - threshdb) / 21) * ONE_Q31; @@ -67,16 +84,16 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t v //So basically this limits the gain to not clip //18 - meanVolume is the magic amount that makes sure the output //won't exceed 1<<24 - float dbGain = std::min(0.5 + er + reduction, 18 - meanVolume); + float dbGain = std::min(1 + er + reduction, 18 - meanVolume); //additionally this is the most gain available without overflow - dbGain = std::min(dbGain, 2.75f); + dbGain = std::min(dbGain, 2.0f); float gain = exp((dbGain + lastGain) / 2); lastGain = dbGain; - float finalVolumeL = gain * float(volAdjustL); - float finalVolumeR = gain * float(volAdjustR); + float finalVolumeL = gain * float(volAdjustL >> 8); + float finalVolumeR = gain * float(volAdjustR >> 8); - q31_t amplitudeIncrementL = (int32_t)((finalVolumeL - currentVolumeL) / float(numSamples)); - q31_t amplitudeIncrementR = (int32_t)((finalVolumeR - currentVolumeR) / float(numSamples)); + q31_t amplitudeIncrementL = ((int32_t)((finalVolumeL - (currentVolumeL >> 8)) / float(numSamples))) << 8; + q31_t amplitudeIncrementR = ((int32_t)((finalVolumeR - (currentVolumeR >> 8)) / float(numSamples))) << 8; StereoSample* thisSample = buffer; StereoSample* bufferEnd = buffer + numSamples; diff --git a/src/deluge/model/global_effectable/global_effectable.cpp b/src/deluge/model/global_effectable/global_effectable.cpp index 4df43b7fae..90142abc97 100644 --- a/src/deluge/model/global_effectable/global_effectable.cpp +++ b/src/deluge/model/global_effectable/global_effectable.cpp @@ -291,7 +291,6 @@ ActionResult GlobalEffectable::modEncoderActionForNonExistentParam(int32_t offse current = std::clamp(current, 1, 128); indicator_leds::setKnobIndicatorLevel(1, std::max(0, 128 - current)); AudioEngine::mastercompressor.threshold = lshiftAndSaturate<24>(current); - AudioEngine::mastercompressor.updateER(); return ActionResult::DEALT_WITH; } else if (whichModEncoder == 0) { //ratio/reverb (we can only get here in comp editing mode) @@ -301,7 +300,6 @@ ActionResult GlobalEffectable::modEncoderActionForNonExistentParam(int32_t offse current = std::clamp(current, 48, 112); indicator_leds::setKnobIndicatorLevel(0, (current - 48) * 2); AudioEngine::mastercompressor.ratio = lshiftAndSaturate<24>(current); - AudioEngine::mastercompressor.updateER(); return ActionResult::DEALT_WITH; } } @@ -312,14 +310,12 @@ ActionResult GlobalEffectable::modEncoderActionForNonExistentParam(int32_t offse current = std::clamp(current, 1, 50); indicator_leds::setKnobIndicatorLevel(1, (current * 128) / 50); AudioEngine::mastercompressor.attack = attackRateTable[current] << 2; - ; - return ActionResult::DEALT_WITH; } - if (whichModEncoder == 0) { //attack + if (whichModEncoder == 0) { //release int current = getLookupIndexFromValue(AudioEngine::mastercompressor.release >> 1, releaseRateTable, 50); current += offset; - current = std::clamp(current, 1, 50); + current = std::clamp(current, 2, 50); indicator_leds::setKnobIndicatorLevel(0, (current * 128) / 50); AudioEngine::mastercompressor.release = releaseRateTable[current] << 1; From dd61480e35fee58bfa4e18146e17753a549870a6 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Tue, 24 Oct 2023 15:42:20 -0400 Subject: [PATCH 32/38] limiting rework --- .../master_compressor/master_compressor.cpp | 19 ++++++++++--------- .../processing/engines/audio_engine.cpp | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 51e2601760..112c574ac9 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -29,7 +29,7 @@ MasterCompressor::MasterCompressor() { //compressor.setRelease((float)release / 100.0); //compressor.setThresh((float)threshold / 100.0); //compressor.setRatio(1.0 / ((float)ratio / 100.0)); - shape = getParamFromUserValue(Param::Unpatched::COMPRESSOR_SHAPE, 2); + shape = getParamFromUserValue(Param::Unpatched::COMPRESSOR_SHAPE, 1); //an appropriate range is 0-50*one q 15 threshold = ONE_Q31; follower = true; @@ -68,26 +68,27 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t v meanVolume = calc_rms(buffer, numSamples); q31_t over = std::max(0, (meanVolume - threshdb) / 21) * ONE_Q31; + q31_t clip = std::max(0, (meanVolume - 18) / 21) * ONE_Q31; + //add some extra reduction if we're into clipping + over = (multiply_32x32_rshift32(over, ratio) << 1) + (multiply_32x32_rshift32(clip, ONE_Q31 - ratio)); if (over > 0) { registerHit(over); } out = Compressor::render(numSamples, shape); - out = multiply_32x32_rshift32(out, ratio) << 1; + //out = multiply_32x32_rshift32(out, ratio) << 1; //21 is the max internal volume (i.e. one_q31) //min ratio is 8 up to 1 (i.e. infinity/brick wall, 1 db reduction per db over) //base is arbitrary for scale, important part is the shape //this will be negative float reduction = 21 * (out / ONE_Q31f); - //So basically this limits the gain to not clip - //18 - meanVolume is the magic amount that makes sure the output - //won't exceed 1<<24 - float dbGain = std::min(1 + er + reduction, 18 - meanVolume); - //additionally this is the most gain available without overflow - dbGain = std::min(dbGain, 2.0f); - float gain = exp((dbGain + lastGain) / 2); + + //this is the most gain available without overflow + float dbGain = std::min(0.85 + er + reduction, 2.0f); + + float gain = exp((dbGain)); lastGain = dbGain; float finalVolumeL = gain * float(volAdjustL >> 8); float finalVolumeR = gain * float(volAdjustR >> 8); diff --git a/src/deluge/processing/engines/audio_engine.cpp b/src/deluge/processing/engines/audio_engine.cpp index 364a4d90d3..2fb9a6bc8b 100644 --- a/src/deluge/processing/engines/audio_engine.cpp +++ b/src/deluge/processing/engines/audio_engine.cpp @@ -316,7 +316,7 @@ void routineWithClusterLoading(bool mayProcessUserActionsBetween) { } } -#define DO_AUDIO_LOG 0 // For advavnced debugging printouts. +#define DO_AUDIO_LOG 1 // For advavnced debugging printouts. #define AUDIO_LOG_SIZE 64 #if DO_AUDIO_LOG From d91a33d5b8aaa49e5496acbd9b84f8cf72edd15f Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Tue, 24 Oct 2023 16:21:38 -0400 Subject: [PATCH 33/38] change popup --- src/deluge/model/global_effectable/global_effectable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deluge/model/global_effectable/global_effectable.cpp b/src/deluge/model/global_effectable/global_effectable.cpp index 90142abc97..7f0436323a 100644 --- a/src/deluge/model/global_effectable/global_effectable.cpp +++ b/src/deluge/model/global_effectable/global_effectable.cpp @@ -273,7 +273,7 @@ bool GlobalEffectable::modEncoderButtonAction(uint8_t whichModEncoder, bool on, else { if (on) { editingComp = !editingComp; - display->popupTextTemporary(editingComp ? "COMP" : "OFF"); + display->popupTextTemporary(editingComp ? "FULL" : "ONE"); } } From 87310c0adffe0ee4a0444a6844f4494bd0485917 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Tue, 24 Oct 2023 16:56:55 -0400 Subject: [PATCH 34/38] format and correct gain --- src/deluge/dsp/master_compressor/master_compressor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 112c574ac9..94893a4573 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -60,7 +60,7 @@ void MasterCompressor::updateER() { } threshdb = songVolume * (threshold / ONE_Q31f); //16 is about the level of a single synth voice at max volume - er = (songVolume - threshdb) * (float(ratio) / ONE_Q31); + er = std::max((songVolume - threshdb - 2) * (float(ratio) / ONE_Q31), 0); } void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t volAdjustL, q31_t volAdjustR) { @@ -86,7 +86,7 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t v float reduction = 21 * (out / ONE_Q31f); //this is the most gain available without overflow - float dbGain = std::min(0.85 + er + reduction, 2.0f); + float dbGain = std::min(0.85 + er + reduction, 2.7f); float gain = exp((dbGain)); lastGain = dbGain; @@ -110,7 +110,7 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t v } while (++thisSample != bufferEnd); //for LEDs //9 converts to dB, quadrupled for display range since a 30db reduction is basically killing the signal - gainReduction = std::clamp(-(reduction) * 9 * 4, 0, 127); + gainReduction = std::clamp(-(reduction)*9 * 4, 0, 127); } //output range is 0-21 (2^31) From a5ff85c6d1bfb8aa6bac0680996b67175d7a62e4 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Wed, 25 Oct 2023 00:03:46 -0400 Subject: [PATCH 35/38] slightly increase makeup gain to handle higher levels --- .../dsp/master_compressor/master_compressor.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 94893a4573..6c544021ed 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -86,12 +86,13 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t v float reduction = 21 * (out / ONE_Q31f); //this is the most gain available without overflow - float dbGain = std::min(0.85 + er + reduction, 2.7f); + float dbGain = 0.85 + er + reduction; float gain = exp((dbGain)); + gain = std::min(gain, 31); lastGain = dbGain; - float finalVolumeL = gain * float(volAdjustL >> 8); - float finalVolumeR = gain * float(volAdjustR >> 8); + float finalVolumeL = gain * float(volAdjustL >> 9); + float finalVolumeR = gain * float(volAdjustR >> 9); q31_t amplitudeIncrementL = ((int32_t)((finalVolumeL - (currentVolumeL >> 8)) / float(numSamples))) << 8; q31_t amplitudeIncrementR = ((int32_t)((finalVolumeR - (currentVolumeR >> 8)) / float(numSamples))) << 8; @@ -104,13 +105,13 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t v currentVolumeL += amplitudeIncrementL; currentVolumeR += amplitudeIncrementR; // Apply post-fx and post-reverb-send volume - thisSample->l = multiply_32x32_rshift32(thisSample->l, currentVolumeL) << 1; - thisSample->r = multiply_32x32_rshift32(thisSample->r, currentVolumeR) << 1; + thisSample->l = multiply_32x32_rshift32(thisSample->l, currentVolumeL) << 2; + thisSample->r = multiply_32x32_rshift32(thisSample->r, currentVolumeR) << 2; } while (++thisSample != bufferEnd); //for LEDs //9 converts to dB, quadrupled for display range since a 30db reduction is basically killing the signal - gainReduction = std::clamp(-(reduction)*9 * 4, 0, 127); + gainReduction = std::clamp(-(reduction) * 9 * 4, 0, 127); } //output range is 0-21 (2^31) From 94f9f2ecafac31a39866890a8a9ac012dceae48b Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Wed, 25 Oct 2023 10:04:59 -0400 Subject: [PATCH 36/38] move limiter post envelope --- src/deluge/dsp/master_compressor/master_compressor.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 6c544021ed..3f62a66610 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -70,13 +70,12 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t v q31_t over = std::max(0, (meanVolume - threshdb) / 21) * ONE_Q31; q31_t clip = std::max(0, (meanVolume - 18) / 21) * ONE_Q31; //add some extra reduction if we're into clipping - over = (multiply_32x32_rshift32(over, ratio) << 1) + (multiply_32x32_rshift32(clip, ONE_Q31 - ratio)); if (over > 0) { registerHit(over); } out = Compressor::render(numSamples, shape); - + out = (multiply_32x32_rshift32(out, ratio) << 1) + (multiply_32x32_rshift32(clip, ONE_Q31 - ratio)); //out = multiply_32x32_rshift32(out, ratio) << 1; //21 is the max internal volume (i.e. one_q31) From 9935fed657055f6be18e1841cd2159f3be99d642 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Wed, 25 Oct 2023 10:16:08 -0400 Subject: [PATCH 37/38] switch to feedback compression --- src/deluge/dsp/master_compressor/master_compressor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 3f62a66610..634ab92ea4 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -65,7 +65,6 @@ void MasterCompressor::updateER() { void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t volAdjustL, q31_t volAdjustR) { updateER(); - meanVolume = calc_rms(buffer, numSamples); q31_t over = std::max(0, (meanVolume - threshdb) / 21) * ONE_Q31; q31_t clip = std::max(0, (meanVolume - 18) / 21) * ONE_Q31; @@ -111,6 +110,8 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t v //for LEDs //9 converts to dB, quadrupled for display range since a 30db reduction is basically killing the signal gainReduction = std::clamp(-(reduction) * 9 * 4, 0, 127); + //calc compression for next round (feedback compressor) + meanVolume = calc_rms(buffer, numSamples); } //output range is 0-21 (2^31) From 5fcb22829a7512a79d615ef50c7b44828c872bf0 Mon Sep 17 00:00:00 2001 From: m-m-adams Date: Wed, 25 Oct 2023 10:31:52 -0400 Subject: [PATCH 38/38] format --- src/deluge/dsp/master_compressor/master_compressor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 634ab92ea4..1e402b037f 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -109,7 +109,7 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t v } while (++thisSample != bufferEnd); //for LEDs //9 converts to dB, quadrupled for display range since a 30db reduction is basically killing the signal - gainReduction = std::clamp(-(reduction) * 9 * 4, 0, 127); + gainReduction = std::clamp(-(reduction)*9 * 4, 0, 127); //calc compression for next round (feedback compressor) meanVolume = calc_rms(buffer, numSamples); }