Skip to content

Commit

Permalink
add a sidechain HPF
Browse files Browse the repository at this point in the history
  • Loading branch information
m-m-adams committed Nov 9, 2023
1 parent c95ef24 commit 8179d41
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 21 deletions.
2 changes: 2 additions & 0 deletions src/definitions_cxx.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,8 @@ enum class CompParam {
RATIO,
ATTACK,
RELEASE,
SIDECHAIN,
LAST,
};

constexpr auto kNumModFXParams = util::to_underlying(ModFXParam::OFFSET) + 1;
Expand Down
16 changes: 10 additions & 6 deletions src/deluge/dsp/master_compressor/master_compressor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,15 @@ MasterCompressor::MasterCompressor() {
//an appropriate range is 0-50*one q 15

thresholdKnobPos = 0;

sideChainKnobPos = ONE_Q31 >> 1;
//this is 2:1
ratioKnobPos = 0;

currentVolumeL = 0;
currentVolumeR = 0;
//auto make up gain
updateER();
setSidechain(sideChainKnobPos);
}
//16 is ln(1<<24) - 1, i.e. where we start clipping
//since this applies to output
Expand All @@ -55,7 +56,7 @@ void MasterCompressor::updateER() {
}
threshdb = songVolume * threshold;
//16 is about the level of a single synth voice at max volume
er = std::max<float>((songVolume - threshdb - 2) * ratio, 0);
er = std::max<float>((songVolume - threshdb - 1) * ratio, 0);
}

void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t volAdjustL, q31_t volAdjustR) {
Expand Down Expand Up @@ -94,7 +95,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<int32_t>(-(reduction)*9 * 4, 0, 127);
gainReduction = std::clamp<int32_t>(-(reduction) * 9 * 4, 0, 127);
//calc compression for next round (feedback compressor)
rms = calc_rms(buffer, numSamples);
}
Expand All @@ -118,7 +119,9 @@ float MasterCompressor::calc_rms(StereoSample* buffer, uint16_t numSamples) {
q31_t offset = 0; //to remove dc offset
float lastMean = mean;
do {
q31_t s = std::max(std::abs(thisSample->l), std::abs(thisSample->r));
q31_t l = thisSample->l - hpfL.doFilter(thisSample->l, a);
q31_t r = thisSample->r - hpfL.doFilter(thisSample->r, a);
q31_t s = std::max(std::abs(l), std::abs(r));
sum += multiply_32x32_rshift32(s, s) << 1;

} while (++thisSample != bufferEnd);
Expand All @@ -136,10 +139,11 @@ float MasterCompressor::calc_rms(StereoSample* buffer, uint16_t numSamples) {

return logmean;
}

void MasterCompressor::setup(int32_t a, int32_t r, int32_t t, int32_t rat) {
//takes in knob positions in the range 0-ONE_Q31
void MasterCompressor::setup(q31_t a, q31_t r, q31_t t, q31_t rat, q31_t fc) {
setAttack(a);
setRelease(r);
setThreshold(t);
setRatio(rat);
setSidechain(fc);
}
24 changes: 20 additions & 4 deletions src/deluge/dsp/master_compressor/master_compressor.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,17 @@

#include "definitions_cxx.hpp"
#include "dsp/compressor/compressor.h"
#include "dsp/filter/ladder_components.h"
#include "util/functions.h"

#define INLINE inline
#include <algorithm> // for min(), max()
#include <cassert> // for assert()
#include <cmath>
#include <cstdint>

class MasterCompressor {
public:
MasterCompressor();
void setup(int32_t attack, int32_t release, int32_t threshold, int32_t ratio);
void setup(q31_t attack, q31_t release, q31_t threshold, q31_t ratio, q31_t sidechain_fc);

void render(StereoSample* buffer, uint16_t numSamples, q31_t volAdjustL, q31_t volAdjustR);
float runEnvelope(float in, float numSamples);
Expand Down Expand Up @@ -60,11 +59,23 @@ class MasterCompressor {
updateER();
}
q31_t getRatio() { return ratioKnobPos; }
q31_t setRatio(q31_t rat) {
int32_t setRatio(q31_t rat) {
ratioKnobPos = rat;
ratio = 0.5 + (float(ratioKnobPos) / ONE_Q31f) / 2;
return 1 / (1 - ratio);
}
q31_t getSidechain() { return sideChainKnobPos; }

int32_t setSidechain(q31_t f) {
sideChainKnobPos = f;
//this exp will be between 1 and 5ish, half the knob range is about 2
//the result will then be from 0 to 100hz with half the knob range at 60hz
float fc_hz = (exp(1.5 * float(f) / ONE_Q31f) - 1) * 30;
float fc = fc_hz / float(kSampleRate);
float wc = fc / (1 + fc);
a = wc * ONE_Q31;
return fc_hz;
}

void updateER();
float calc_rms(StereoSample* buffer, uint16_t numSamples);
Expand All @@ -78,6 +89,7 @@ class MasterCompressor {
float er;
float threshdb;
float threshold;
q31_t a;

//state
float state;
Expand All @@ -86,6 +98,9 @@ class MasterCompressor {
float rms;
float mean;

//sidechain filter
deluge::dsp::filter::BasicFilterComponent hpfL;
deluge::dsp::filter::BasicFilterComponent hpfR;
//for display
float attackMS;
float releaseMS;
Expand All @@ -95,4 +110,5 @@ class MasterCompressor {
q31_t ratioKnobPos;
q31_t attackKnobPos;
q31_t releaseKnobPos;
q31_t sideChainKnobPos;
};
15 changes: 14 additions & 1 deletion src/deluge/model/global_effectable/global_effectable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ bool GlobalEffectable::modEncoderButtonAction(uint8_t whichModEncoder, bool on,
else {
currentCompParam =
static_cast<CompParam>((util::to_underlying(currentCompParam) + 1) % maxCompParam);
const char* params[3] = {"ratio", "attack", "release"};
const char* params[util::to_underlying(CompParam::LAST)] = {"ratio", "attack", "release", "hpf"};
display->popupTextTemporary(params[int(currentCompParam)]);
}
}
Expand Down Expand Up @@ -319,6 +319,10 @@ int32_t GlobalEffectable::getKnobPosForNonExistentParam(int32_t whichModEncoder,
current = AudioEngine::mastercompressor.getRelease() >> 24;

break;

case CompParam::SIDECHAIN:
current = AudioEngine::mastercompressor.getSidechain() >> 24;
break;
}
}
}
Expand Down Expand Up @@ -372,6 +376,15 @@ ActionResult GlobalEffectable::modEncoderActionForNonExistentParam(int32_t offse

displayLevel = AudioEngine::mastercompressor.setRelease(lshiftAndSaturate<24>(current + 64));
break;

case CompParam::SIDECHAIN:
current = (AudioEngine::mastercompressor.getSidechain() >> 24) - 64;
current += offset;
current = std::clamp(current, -64, 64);
ledLevel = (64 + current);

displayLevel = AudioEngine::mastercompressor.setSidechain(lshiftAndSaturate<24>(current + 64));
break;
}
indicator_leds::setKnobIndicatorLevel(0, ledLevel);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@

GlobalEffectableForSong::GlobalEffectableForSong() {
modKnobMode = 1;
//attack and release can't go in the param manager so this keeps them from changing in clip comps
maxCompParam = 3;
//UI for kit compressors is TBD so they can only be accessed in song
maxCompParam = util::to_underlying(CompParam::LAST);
}
5 changes: 3 additions & 2 deletions src/deluge/model/song/song.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ Song::Song() : backedUpParamManagers(sizeof(BackedUpParamManager)) {
masterCompressorRelease = 20 << 24;
masterCompressorThresh = 0;
masterCompressorRatio = 0;
masterCompressorSidechainFC = ONE_Q31 >> 1;
AudioEngine::mastercompressor.gainReduction = 0.0;

dirPath.set("SONGS");
Expand Down Expand Up @@ -2670,7 +2671,7 @@ int32_t Song::getCurrentPresetScale() {
// If we're here, must be this one!
return p;

notThisOne : {}
notThisOne: {}
}

return 255;
Expand Down Expand Up @@ -4559,7 +4560,7 @@ Instrument* Song::changeInstrumentType(Instrument* oldInstrument, InstrumentType
return NULL;
}

gotAnInstrument : {}
gotAnInstrument: {}
}

// Synth or Kit
Expand Down
1 change: 1 addition & 0 deletions src/deluge/model/song/song.h
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ class Song final : public TimelineCounter {
int32_t masterCompressorRelease;
int32_t masterCompressorThresh;
int32_t masterCompressorRatio;
int32_t masterCompressorSidechainFC;

private:
bool fillModeActive;
Expand Down
12 changes: 6 additions & 6 deletions src/deluge/processing/engines/audio_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1197,12 +1197,12 @@ void getReverbParamsFromSong(Song* song) {
}

void getMasterCompressorParamsFromSong(Song* song) {
int32_t a = song->masterCompressorAttack;
int32_t r = song->masterCompressorRelease;
int32_t t = song->masterCompressorThresh;
int32_t rat = song->masterCompressorRatio;

mastercompressor.setup(a, r, t, rat);
q31_t a = song->masterCompressorAttack;
q31_t r = song->masterCompressorRelease;
q31_t t = song->masterCompressorThresh;
q31_t rat = song->masterCompressorRatio;
q31_t fc = song->masterCompressorSidechainFC;
mastercompressor.setup(a, r, t, rat, fc);
}

Voice* solicitVoice(Sound* forSound) {
Expand Down

0 comments on commit 8179d41

Please sign in to comment.