Skip to content

Commit

Permalink
sweet sidechain magic
Browse files Browse the repository at this point in the history
  • Loading branch information
Mrugalla committed Jul 15, 2022
1 parent ee86d90 commit bc4ba63
Show file tree
Hide file tree
Showing 15 changed files with 631 additions and 89 deletions.
4 changes: 3 additions & 1 deletion Project.jucer
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
pluginCharacteristicsValue="pluginWantsMidiIn" pluginDesc="Absorbs a sidechain-input's signal in creative ways."
pluginManufacturer="Mrugalla" pluginManufacturerCode="Mrug" pluginCode="ID29"
pluginVSTNumMidiInputs="1" pluginVST3Category="Distortion,Fx"
cppLanguageStandard="latest" pluginName="Absorb" defines="PPDEditorWidth=774
PPDEditorHeight=448

PPDHasEditor=true
PPDHasPatchBrowser=true

PPDHasSidechain=true

PPDHasGainIn=true
PPDHasHQ=true
PPDHasUnityGain=true && PPDHasGainIn
PPDHasStereoConfig=true
PPDHasPolarity=true

PPDEqualLoudnessMix=false

PPDFPSKnobs=30
PPDFPSMeters=30
PPDFPSTextEditor=3

PPDFPSValueBubble=24
PPDValueBubbleVisibleTimeMs=1500

PPDMetersUseRMS=false

PPD_GainIn_Min=-12
PPD_GainIn_Max=12
PPD_GainOut_Min=-24
PPD_GainOut_Max=24
PPD_UnityGainDefault=true

PPD_DebugFormularParser=false

PPDPitchShifterSizeMs=1000
PPDPitchShifterNumVoices=7

JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP=0">
cppLanguageStandard="latest" pluginName="Absorb" defines="PPDEditorWidth=774
PPDEditorHeight=448

PPDHasEditor=true
PPDHasPatchBrowser=true

PPDHasSidechain=true

PPDHasGainIn=false
PPDHasHQ=true
PPDHasUnityGain=false
PPDHasStereoConfig=false
PPDHasPolarity=false

PPDEqualLoudnessMix=false

PPDFPSKnobs=60
PPDFPSMeters=30
PPDFPSTextEditor=3

PPDMetersUseRMS=false

PPD_GainIn_Min=-12
PPD_GainIn_Max=12
PPD_GainOut_Min=-32
PPD_GainOut_Max=32
PPD_UnityGainDefault=true

PPD_DebugFormularParser=false

PPDPitchShifterSizeMs=1000
PPDPitchShifterNumVoices=7">
<MAINGROUP id="c82PPq" name="Absorb">
<GROUP id="{329F0704-CF49-5A90-357A-72806BBA6C7A}" name="Source">
<GROUP id="{C3E83797-8352-773C-9028-12ECA83F553B}" name="svg">
Expand Down Expand Up @@ -97,6 +97,8 @@
<FILE id="XInD6O" name="Utils.h" compile="0" resource="0" file="Source/gui/Utils.h"/>
</GROUP>
<GROUP id="{6A8CB2D6-E6E3-8D1E-1148-21BD24558A7A}" name="audio">
<FILE id="pJY5N1" name="AbsorbProcessor.h" compile="0" resource="0"
file="Source/audio/AbsorbProcessor.h"/>
<FILE id="SX6ccp" name="AudioUtils.h" compile="0" resource="0" file="Source/audio/AudioUtils.h"/>
<FILE id="DT8T5u" name="Bitcrusher.h" compile="0" resource="0" file="Source/audio/Bitcrusher.h"/>
<FILE id="gCh4Uk" name="DryWetMix.cpp" compile="1" resource="0" file="Source/audio/DryWetMix.cpp"/>
Expand Down
60 changes: 32 additions & 28 deletions Source/Processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ namespace audio
state(),
params(*this, state),
macroProcessor(params),
midiLearn(params, state),
midiManager(params, state),
#if PPDHasHQ
oversampler(),
#endif
Expand Down Expand Up @@ -115,13 +115,13 @@ namespace audio
void ProcessorBackEnd::savePatch()
{
params.savePatch(props);
midiLearn.savePatch();
midiManager.savePatch();
}

void ProcessorBackEnd::loadPatch()
{
params.loadPatch(props);
midiLearn.loadPatch();
midiManager.loadPatch();
forcePrepareToPlay();
}

Expand Down Expand Up @@ -185,7 +185,8 @@ namespace audio
// PROCESSOR

Processor::Processor() :
ProcessorBackEnd()
ProcessorBackEnd(),
absorb()
{
}

Expand All @@ -195,13 +196,15 @@ namespace audio
#if PPDHasHQ
oversampler.setEnabled(params[PID::HQ]->getValMod() > .5f);
oversampler.prepare(sampleRate, maxBlockSize);
//const auto sampleRateUp = oversampler.getFsUp();
//const auto sampleRateUpF = static_cast<float>(sampleRateUp);
//const auto blockSizeUp = oversampler.getBlockSizeUp();
const auto sampleRateUp = oversampler.getFsUp();
const auto sampleRateUpF = static_cast<float>(sampleRateUp);
const auto blockSizeUp = oversampler.getBlockSizeUp();
latency = oversampler.getLatency();
#endif
const auto sampleRateF = static_cast<float>(sampleRate);

absorb.prepare(sampleRateUpF, blockSizeUp);

dryWetMix.prepare(sampleRateF, maxBlockSize, latency);

meters.prepare(sampleRateF, maxBlockSize);
Expand All @@ -215,7 +218,7 @@ namespace audio
{
const ScopedNoDenormals noDenormals;

midiLearn(midi);
//midiLearn(midi);
macroProcessor();

auto mainBus = getBus(true, 0);
Expand All @@ -228,6 +231,8 @@ namespace audio
if (numSamples == 0)
return;

midiManager(midi, numSamples);

if (params[PID::Power]->getValMod() < .5f)
return processBlockBypassed(buffer, midi);

Expand Down Expand Up @@ -267,21 +272,22 @@ namespace audio
#else
auto resampledBuf = &buffer;
#endif
auto resampledMainBuf = mainBus->getBusBuffer(*resampledBuf);

#if PPDHasSidechain
if (wrapperType != wrapperType_Standalone)
{
const auto scBus = getBus(true, 1);
auto scBus = getBus(true, 1);
if (scBus != nullptr)
if(scBus->isEnabled())
{
const auto scBuffer = scBus->getBusBuffer(*resampledBuf);
auto scBuffer = scBus->getBusBuffer(*resampledBuf);

processBlockCustom(
resampledBuf->getArrayOfWritePointers(),
resampledBuf->getNumChannels(),
resampledBuf->getNumSamples(),
scBuffer.getArrayOfReadPointers(),
resampledMainBuf.getArrayOfWritePointers(),
resampledMainBuf.getNumChannels(),
resampledMainBuf.getNumSamples(),
scBuffer.getArrayOfWritePointers(),
scBuffer.getNumChannels()
);
}
Expand All @@ -292,9 +298,9 @@ namespace audio
}
#else
processBlockCustom(
resampledBuf->getArrayOfWritePointers(),
resampledBuf->getNumChannels(),
resampledBuf->getNumSamples()
resampledMainBuf.getArrayOfWritePointers(),
resampledMainBuf.getNumChannels(),
resampledMainBuf.getNumSamples()
);
#endif

Expand Down Expand Up @@ -329,20 +335,18 @@ namespace audio

void Processor::processBlockCustom(float** samples, int numChannels, int numSamples
#if PPDHasSidechain
, const float** samplesSC, int numChannelsSC
, float** samplesSC, int numChannelsSC
#endif
) noexcept
{
for (auto ch = 0; ch < numChannels; ++ch)
{
const auto chSC = ch % numChannelsSC;
const auto smplsSC = samplesSC[chSC];

auto smpls = samples[ch];

for (auto s = 0; s < numSamples; ++s)
smpls[s] *= smplsSC[s] * 2.f;
}
auto rm = params[PID::AbsorbRM]->getValModDenorm();
auto am = params[PID::AbsorbAM]->getValModDenorm();
auto shapr = params[PID::AbsorbShapr]->getValModDenorm();
auto crushr = params[PID::AbsorbCrushr]->getValModDenorm();
auto foldr = params[PID::AbsorbFoldr]->getValModDenorm();

absorb(samples, numChannels, numSamples, samplesSC, numChannelsSC,
rm, am, shapr, crushr, foldr);
}

void Processor::releaseResources() {}
Expand Down
12 changes: 7 additions & 5 deletions Source/Processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
#include <juce_audio_processors/juce_audio_processors.h>
#include <juce_events/juce_events.h>

#include "audio/MIDIManager.h"
#include "audio/MIDILearn.h"
#include "audio/ProcessSuspend.h"
#include "audio/DryWetMix.h"
#include "audio/MidSide.h"
#include "audio/Oversampling.h"
#include "audio/Meter.h"
#include "audio/Rectifier.h"
#include "audio/Bitcrusher.h"
#include "audio/NullNoiseSynth.h"

#include "audio/AbsorbProcessor.h"

#include "audio/AudioUtils.h"

Expand Down Expand Up @@ -61,7 +61,8 @@ namespace audio
State state;
Params params;
MacroProcessor macroProcessor;
MIDILearn midiLearn;
MIDIManager midiManager;
//MIDILearn midiLearn;

DryWetMix dryWetMix;
#if PPDHasHQ
Expand Down Expand Up @@ -94,7 +95,7 @@ namespace audio
/* samples,numChannels,numSamples,samplesSC,numChannelsSC */
void processBlockCustom(float**, int, int
#if PPDHasSidechain
, const float**, int
, float**, int
#endif
) noexcept;

Expand All @@ -106,5 +107,6 @@ namespace audio

juce::AudioProcessorEditor* createEditor() override;

AbsorbProcessor absorb;
};
}
105 changes: 105 additions & 0 deletions Source/audio/AbsorbProcessor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#pragma once
#include "AudioUtils.h"
#include "PRM.h"

namespace audio
{
class AbsorbProcessor
{
struct Textures
{
Textures() :
rm(0.f),
am(0.f),
shapr(0.f),
crushr(0.f),
foldr(0.f)
{}

void prepare(float sampleRate, int blockSize)
{
rm.prepare(sampleRate, blockSize, 10.f);
am.prepare(sampleRate, blockSize, 10.f);
shapr.prepare(sampleRate, blockSize, 10.f);
crushr.prepare(sampleRate, blockSize, 10.f);
foldr.prepare(sampleRate, blockSize, 10.f);
}

void operator()(float** samples, int numChannels, int numSamples,
float** samplesSC, int numChannelsSC,
float _rm, float _am, float _shapr, float _crushr, float _foldr) noexcept
{
auto rmBuf = rm(Decibels::decibelsToGain(_rm, -20.f), numSamples);
auto amBuf = am(Decibels::decibelsToGain(_am, -20.f), numSamples);
auto shaprBuf = shapr(Decibels::decibelsToGain(_shapr, -40.f), numSamples);
auto crushrBuf = crushr(Decibels::decibelsToGain(_crushr, -40.f), numSamples);
auto foldrBuf = foldr(Decibels::decibelsToGain(_foldr, -40.f), numSamples);

for (auto ch = 0; ch < numChannels; ++ch)
{
const auto chSC = ch % numChannelsSC;
const auto smplsSC = samplesSC[chSC];

auto smpls = samples[ch];

float A, B, C, D, E;

for (auto s = 0; s < numSamples; ++s)
{
const auto main = smpls[s];
const auto sc = smplsSC[s];

A = main * sc * rmBuf[s];

const auto scsc = sc * sc;
const auto scscSqrt = std::sqrt(scsc);

B = main * scscSqrt * amBuf[s];

if (sc == 0.f)
{
C = D = E = 0.f;
}
else
{
const auto mainInvSc = main / sc;

C = std::tanh(mainInvSc) * sc * shaprBuf[s];
D = std::rint(mainInvSc) * sc * crushrBuf[s];

E = std::fmod(main, sc) * sc * foldrBuf[s];
}

smpls[s] = A + B + C + D + E;
}
}
}

protected:
PRM rm, am, shapr, crushr, foldr;
};

public:
AbsorbProcessor() :
textures()
{
}

void prepare(float sampleRate, int blockSize)
{
textures.prepare(sampleRate, blockSize);
}

void operator()(float** samples, int numChannels, int numSamples,
float** samplesSC, int numChannelsSC,
float _rm, float _am, float _shapr, float _crushr, float _foldr) noexcept
{
textures(samples, numChannels, numSamples, samplesSC, numChannelsSC,
_rm, _am, _shapr, _crushr, _foldr);
}

protected:
Textures textures;
};

}
19 changes: 19 additions & 0 deletions Source/audio/AudioUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace audio
using MIDIRef = MIDIIt::reference;
using Decibels = juce::Decibels;
using ScopedNoDenormals = juce::ScopedNoDenormals;
using MidiMessage = juce::MidiMessage;

using Smooth = smooth::Smooth<float>;
using PID = param::PID;
Expand All @@ -37,6 +38,12 @@ namespace audio
return secsInSamples(ms * static_cast<Float>(.001), Fs);
}

template<typename Float>
inline Float freqHzInSamples(Float hz, Float Fs) noexcept
{
return Fs / hz;
}

template<typename Float>
inline float getRMS(const Float* ar, const int size) noexcept
{
Expand All @@ -47,4 +54,16 @@ namespace audio
return std::sqrt(rms);
}

template<typename Float>
inline Float noteInFreqHz(Float note, Float rootNote = 69.f, Float xen = 12.f, Float masterTune = 440.f) noexcept
{
return std::pow(2.f, (note - rootNote) / xen) * masterTune;
}

template<typename Float>
inline Float noteInFreqHz(Float note, Float rootNote = 69.f, Float masterTune = 440.f) noexcept
{
return std::pow(2.f, (note - rootNote) * .08333333333f) * masterTune;
}

}
3 changes: 2 additions & 1 deletion Source/audio/DryWetMix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,11 @@ namespace audio
auto mixBuf = bufs[MixW].data();
mixSmooth(mixBuf, mixP, numSamples);

gainP = Decibels::decibelsToGain(gainP);
#if PPDHasPolarity
gainP *= polarityP;
#endif
gainSmooth(bufs[Gain].data(), juce::Decibels::decibelsToGain(gainP), numSamples);
gainSmooth(bufs[Gain].data(), gainP, numSamples);

#if PPDEqualLoudnessMix
for (auto s = 0; s < numSamples; ++s)
Expand Down
Loading

0 comments on commit bc4ba63

Please sign in to comment.