Skip to content

Commit bc4ba63

Browse files
committed
sweet sidechain magic
1 parent ee86d90 commit bc4ba63

15 files changed

Lines changed: 631 additions & 89 deletions

Project.jucer

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
pluginCharacteristicsValue="pluginWantsMidiIn" pluginDesc="Absorbs a sidechain-input's signal in creative ways."
77
pluginManufacturer="Mrugalla" pluginManufacturerCode="Mrug" pluginCode="ID29"
88
pluginVSTNumMidiInputs="1" pluginVST3Category="Distortion,Fx"
9-
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">
9+
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">
1010
<MAINGROUP id="c82PPq" name="Absorb">
1111
<GROUP id="{329F0704-CF49-5A90-357A-72806BBA6C7A}" name="Source">
1212
<GROUP id="{C3E83797-8352-773C-9028-12ECA83F553B}" name="svg">
@@ -97,6 +97,8 @@
9797
<FILE id="XInD6O" name="Utils.h" compile="0" resource="0" file="Source/gui/Utils.h"/>
9898
</GROUP>
9999
<GROUP id="{6A8CB2D6-E6E3-8D1E-1148-21BD24558A7A}" name="audio">
100+
<FILE id="pJY5N1" name="AbsorbProcessor.h" compile="0" resource="0"
101+
file="Source/audio/AbsorbProcessor.h"/>
100102
<FILE id="SX6ccp" name="AudioUtils.h" compile="0" resource="0" file="Source/audio/AudioUtils.h"/>
101103
<FILE id="DT8T5u" name="Bitcrusher.h" compile="0" resource="0" file="Source/audio/Bitcrusher.h"/>
102104
<FILE id="gCh4Uk" name="DryWetMix.cpp" compile="1" resource="0" file="Source/audio/DryWetMix.cpp"/>

Source/Processor.cpp

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ namespace audio
2929
state(),
3030
params(*this, state),
3131
macroProcessor(params),
32-
midiLearn(params, state),
32+
midiManager(params, state),
3333
#if PPDHasHQ
3434
oversampler(),
3535
#endif
@@ -115,13 +115,13 @@ namespace audio
115115
void ProcessorBackEnd::savePatch()
116116
{
117117
params.savePatch(props);
118-
midiLearn.savePatch();
118+
midiManager.savePatch();
119119
}
120120

121121
void ProcessorBackEnd::loadPatch()
122122
{
123123
params.loadPatch(props);
124-
midiLearn.loadPatch();
124+
midiManager.loadPatch();
125125
forcePrepareToPlay();
126126
}
127127

@@ -185,7 +185,8 @@ namespace audio
185185
// PROCESSOR
186186

187187
Processor::Processor() :
188-
ProcessorBackEnd()
188+
ProcessorBackEnd(),
189+
absorb()
189190
{
190191
}
191192

@@ -195,13 +196,15 @@ namespace audio
195196
#if PPDHasHQ
196197
oversampler.setEnabled(params[PID::HQ]->getValMod() > .5f);
197198
oversampler.prepare(sampleRate, maxBlockSize);
198-
//const auto sampleRateUp = oversampler.getFsUp();
199-
//const auto sampleRateUpF = static_cast<float>(sampleRateUp);
200-
//const auto blockSizeUp = oversampler.getBlockSizeUp();
199+
const auto sampleRateUp = oversampler.getFsUp();
200+
const auto sampleRateUpF = static_cast<float>(sampleRateUp);
201+
const auto blockSizeUp = oversampler.getBlockSizeUp();
201202
latency = oversampler.getLatency();
202203
#endif
203204
const auto sampleRateF = static_cast<float>(sampleRate);
204205

206+
absorb.prepare(sampleRateUpF, blockSizeUp);
207+
205208
dryWetMix.prepare(sampleRateF, maxBlockSize, latency);
206209

207210
meters.prepare(sampleRateF, maxBlockSize);
@@ -215,7 +218,7 @@ namespace audio
215218
{
216219
const ScopedNoDenormals noDenormals;
217220

218-
midiLearn(midi);
221+
//midiLearn(midi);
219222
macroProcessor();
220223

221224
auto mainBus = getBus(true, 0);
@@ -228,6 +231,8 @@ namespace audio
228231
if (numSamples == 0)
229232
return;
230233

234+
midiManager(midi, numSamples);
235+
231236
if (params[PID::Power]->getValMod() < .5f)
232237
return processBlockBypassed(buffer, midi);
233238

@@ -267,21 +272,22 @@ namespace audio
267272
#else
268273
auto resampledBuf = &buffer;
269274
#endif
275+
auto resampledMainBuf = mainBus->getBusBuffer(*resampledBuf);
270276

271277
#if PPDHasSidechain
272278
if (wrapperType != wrapperType_Standalone)
273279
{
274-
const auto scBus = getBus(true, 1);
280+
auto scBus = getBus(true, 1);
275281
if (scBus != nullptr)
276282
if(scBus->isEnabled())
277283
{
278-
const auto scBuffer = scBus->getBusBuffer(*resampledBuf);
284+
auto scBuffer = scBus->getBusBuffer(*resampledBuf);
279285

280286
processBlockCustom(
281-
resampledBuf->getArrayOfWritePointers(),
282-
resampledBuf->getNumChannels(),
283-
resampledBuf->getNumSamples(),
284-
scBuffer.getArrayOfReadPointers(),
287+
resampledMainBuf.getArrayOfWritePointers(),
288+
resampledMainBuf.getNumChannels(),
289+
resampledMainBuf.getNumSamples(),
290+
scBuffer.getArrayOfWritePointers(),
285291
scBuffer.getNumChannels()
286292
);
287293
}
@@ -292,9 +298,9 @@ namespace audio
292298
}
293299
#else
294300
processBlockCustom(
295-
resampledBuf->getArrayOfWritePointers(),
296-
resampledBuf->getNumChannels(),
297-
resampledBuf->getNumSamples()
301+
resampledMainBuf.getArrayOfWritePointers(),
302+
resampledMainBuf.getNumChannels(),
303+
resampledMainBuf.getNumSamples()
298304
);
299305
#endif
300306

@@ -329,20 +335,18 @@ namespace audio
329335

330336
void Processor::processBlockCustom(float** samples, int numChannels, int numSamples
331337
#if PPDHasSidechain
332-
, const float** samplesSC, int numChannelsSC
338+
, float** samplesSC, int numChannelsSC
333339
#endif
334340
) noexcept
335341
{
336-
for (auto ch = 0; ch < numChannels; ++ch)
337-
{
338-
const auto chSC = ch % numChannelsSC;
339-
const auto smplsSC = samplesSC[chSC];
340-
341-
auto smpls = samples[ch];
342-
343-
for (auto s = 0; s < numSamples; ++s)
344-
smpls[s] *= smplsSC[s] * 2.f;
345-
}
342+
auto rm = params[PID::AbsorbRM]->getValModDenorm();
343+
auto am = params[PID::AbsorbAM]->getValModDenorm();
344+
auto shapr = params[PID::AbsorbShapr]->getValModDenorm();
345+
auto crushr = params[PID::AbsorbCrushr]->getValModDenorm();
346+
auto foldr = params[PID::AbsorbFoldr]->getValModDenorm();
347+
348+
absorb(samples, numChannels, numSamples, samplesSC, numChannelsSC,
349+
rm, am, shapr, crushr, foldr);
346350
}
347351

348352
void Processor::releaseResources() {}

Source/Processor.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
#include <juce_audio_processors/juce_audio_processors.h>
44
#include <juce_events/juce_events.h>
55

6+
#include "audio/MIDIManager.h"
67
#include "audio/MIDILearn.h"
78
#include "audio/ProcessSuspend.h"
89
#include "audio/DryWetMix.h"
910
#include "audio/MidSide.h"
1011
#include "audio/Oversampling.h"
1112
#include "audio/Meter.h"
12-
#include "audio/Rectifier.h"
13-
#include "audio/Bitcrusher.h"
14-
#include "audio/NullNoiseSynth.h"
13+
14+
#include "audio/AbsorbProcessor.h"
1515

1616
#include "audio/AudioUtils.h"
1717

@@ -61,7 +61,8 @@ namespace audio
6161
State state;
6262
Params params;
6363
MacroProcessor macroProcessor;
64-
MIDILearn midiLearn;
64+
MIDIManager midiManager;
65+
//MIDILearn midiLearn;
6566

6667
DryWetMix dryWetMix;
6768
#if PPDHasHQ
@@ -94,7 +95,7 @@ namespace audio
9495
/* samples,numChannels,numSamples,samplesSC,numChannelsSC */
9596
void processBlockCustom(float**, int, int
9697
#if PPDHasSidechain
97-
, const float**, int
98+
, float**, int
9899
#endif
99100
) noexcept;
100101

@@ -106,5 +107,6 @@ namespace audio
106107

107108
juce::AudioProcessorEditor* createEditor() override;
108109

110+
AbsorbProcessor absorb;
109111
};
110112
}

Source/audio/AbsorbProcessor.h

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#pragma once
2+
#include "AudioUtils.h"
3+
#include "PRM.h"
4+
5+
namespace audio
6+
{
7+
class AbsorbProcessor
8+
{
9+
struct Textures
10+
{
11+
Textures() :
12+
rm(0.f),
13+
am(0.f),
14+
shapr(0.f),
15+
crushr(0.f),
16+
foldr(0.f)
17+
{}
18+
19+
void prepare(float sampleRate, int blockSize)
20+
{
21+
rm.prepare(sampleRate, blockSize, 10.f);
22+
am.prepare(sampleRate, blockSize, 10.f);
23+
shapr.prepare(sampleRate, blockSize, 10.f);
24+
crushr.prepare(sampleRate, blockSize, 10.f);
25+
foldr.prepare(sampleRate, blockSize, 10.f);
26+
}
27+
28+
void operator()(float** samples, int numChannels, int numSamples,
29+
float** samplesSC, int numChannelsSC,
30+
float _rm, float _am, float _shapr, float _crushr, float _foldr) noexcept
31+
{
32+
auto rmBuf = rm(Decibels::decibelsToGain(_rm, -20.f), numSamples);
33+
auto amBuf = am(Decibels::decibelsToGain(_am, -20.f), numSamples);
34+
auto shaprBuf = shapr(Decibels::decibelsToGain(_shapr, -40.f), numSamples);
35+
auto crushrBuf = crushr(Decibels::decibelsToGain(_crushr, -40.f), numSamples);
36+
auto foldrBuf = foldr(Decibels::decibelsToGain(_foldr, -40.f), numSamples);
37+
38+
for (auto ch = 0; ch < numChannels; ++ch)
39+
{
40+
const auto chSC = ch % numChannelsSC;
41+
const auto smplsSC = samplesSC[chSC];
42+
43+
auto smpls = samples[ch];
44+
45+
float A, B, C, D, E;
46+
47+
for (auto s = 0; s < numSamples; ++s)
48+
{
49+
const auto main = smpls[s];
50+
const auto sc = smplsSC[s];
51+
52+
A = main * sc * rmBuf[s];
53+
54+
const auto scsc = sc * sc;
55+
const auto scscSqrt = std::sqrt(scsc);
56+
57+
B = main * scscSqrt * amBuf[s];
58+
59+
if (sc == 0.f)
60+
{
61+
C = D = E = 0.f;
62+
}
63+
else
64+
{
65+
const auto mainInvSc = main / sc;
66+
67+
C = std::tanh(mainInvSc) * sc * shaprBuf[s];
68+
D = std::rint(mainInvSc) * sc * crushrBuf[s];
69+
70+
E = std::fmod(main, sc) * sc * foldrBuf[s];
71+
}
72+
73+
smpls[s] = A + B + C + D + E;
74+
}
75+
}
76+
}
77+
78+
protected:
79+
PRM rm, am, shapr, crushr, foldr;
80+
};
81+
82+
public:
83+
AbsorbProcessor() :
84+
textures()
85+
{
86+
}
87+
88+
void prepare(float sampleRate, int blockSize)
89+
{
90+
textures.prepare(sampleRate, blockSize);
91+
}
92+
93+
void operator()(float** samples, int numChannels, int numSamples,
94+
float** samplesSC, int numChannelsSC,
95+
float _rm, float _am, float _shapr, float _crushr, float _foldr) noexcept
96+
{
97+
textures(samples, numChannels, numSamples, samplesSC, numChannelsSC,
98+
_rm, _am, _shapr, _crushr, _foldr);
99+
}
100+
101+
protected:
102+
Textures textures;
103+
};
104+
105+
}

Source/audio/AudioUtils.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ namespace audio
1818
using MIDIRef = MIDIIt::reference;
1919
using Decibels = juce::Decibels;
2020
using ScopedNoDenormals = juce::ScopedNoDenormals;
21+
using MidiMessage = juce::MidiMessage;
2122

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

41+
template<typename Float>
42+
inline Float freqHzInSamples(Float hz, Float Fs) noexcept
43+
{
44+
return Fs / hz;
45+
}
46+
4047
template<typename Float>
4148
inline float getRMS(const Float* ar, const int size) noexcept
4249
{
@@ -47,4 +54,16 @@ namespace audio
4754
return std::sqrt(rms);
4855
}
4956

57+
template<typename Float>
58+
inline Float noteInFreqHz(Float note, Float rootNote = 69.f, Float xen = 12.f, Float masterTune = 440.f) noexcept
59+
{
60+
return std::pow(2.f, (note - rootNote) / xen) * masterTune;
61+
}
62+
63+
template<typename Float>
64+
inline Float noteInFreqHz(Float note, Float rootNote = 69.f, Float masterTune = 440.f) noexcept
65+
{
66+
return std::pow(2.f, (note - rootNote) * .08333333333f) * masterTune;
67+
}
68+
5069
}

Source/audio/DryWetMix.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,11 @@ namespace audio
113113
auto mixBuf = bufs[MixW].data();
114114
mixSmooth(mixBuf, mixP, numSamples);
115115

116+
gainP = Decibels::decibelsToGain(gainP);
116117
#if PPDHasPolarity
117118
gainP *= polarityP;
118119
#endif
119-
gainSmooth(bufs[Gain].data(), juce::Decibels::decibelsToGain(gainP), numSamples);
120+
gainSmooth(bufs[Gain].data(), gainP, numSamples);
120121

121122
#if PPDEqualLoudnessMix
122123
for (auto s = 0; s < numSamples; ++s)

0 commit comments

Comments
 (0)