tracktion-engine 3.0-10-g034fdde4aa5
Tracktion Engine — High level data model for audio applications

« « « Anklang Documentation
Loading...
Searching...
No Matches
tracktion_Reverb.cpp
Go to the documentation of this file.
1 /*
2 ,--. ,--. ,--. ,--.
3 ,-' '-.,--.--.,--,--.,---.| |,-.,-' '-.`--' ,---. ,--,--, Copyright 2024
4 '-. .-'| .--' ,-. | .--'| /'-. .-',--.| .-. || \ Tracktion Software
5 | | | | \ '-' \ `--.| \ \ | | | |' '-' '| || | Corporation
6 `---' `--' `--`--'`---'`--'`--' `---' `--' `---' `--''--' www.tracktion.com
7
8 Tracktion Engine uses a GPL/commercial licence - see LICENCE.md for details.
9*/
10
11namespace tracktion { inline namespace engine
12{
13
14static constexpr float scalewet = 3;
15static constexpr float scaledry = 2;
16static constexpr float freezemode = 0.5f;
17
18//==============================================================================
19ReverbPlugin::ReverbPlugin (PluginCreationInfo info) : Plugin (info)
20{
21 roomSizeParam = addParam ("room size", TRANS("Room Size"), { 0.0f, 1.0f },
22 [] (float value) { return juce::String (1 + (int) (10.0f * value)); },
23 [] (const juce::String& s) { return s.getFloatValue(); });
24
25 dampParam = addParam ("damping", TRANS("Damping"), { 0.0f, 1.0f },
26 [] (float value) { return juce::String ((int) (100.0f * value)) + "%"; },
27 [] (const juce::String& s) { return s.getFloatValue(); });
28
29 wetParam = addParam ("wet level", TRANS("Wet Level"), { 0.0f, 1.0f },
30 [] (float value) { return gainToDbString (scalewet * value); },
31 [] (const juce::String& s) { return s.getFloatValue(); });
32
33 dryParam = addParam ("dry level", TRANS("Dry Level"), { 0.0f, 1.0f },
34 [] (float value) { return gainToDbString (scaledry * value); },
35 [] (const juce::String& s) { return s.getFloatValue(); });
36
37 widthParam = addParam ("width", TRANS("Width"), { 0.0f, 1.0f },
38 [] (float value) { return juce::String ((int) (100.0f * value)) + "%"; },
39 [] (const juce::String& s) { return s.getFloatValue(); });
40
41 modeParam = addParam ("mode", TRANS("Freeze"), { 0.0f, 1.0f },
42 [] (float value) { return value >= freezemode ? TRANS("On") : TRANS("Off"); },
43 [] (const juce::String& s) { return s.getFloatValue(); });
44
45 auto um = getUndoManager();
46
47 roomSizeValue.referTo (state, IDs::roomSize, um, 0.3f);
48 dampValue.referTo (state, IDs::damp, um, 0.5f);
49 wetValue.referTo (state, IDs::wet, um, 1.0f / scalewet);
50 dryValue.referTo (state, IDs::dry, um, 0.5f);
51 widthValue.referTo (state, IDs::width, um, 1.0f);
52 modeValue.referTo (state, IDs::mode, um);
53
54 roomSizeParam->attachToCurrentValue (roomSizeValue);
55 dampParam->attachToCurrentValue (dampValue);
56 wetParam->attachToCurrentValue (wetValue);
57 dryParam->attachToCurrentValue (dryValue);
58 widthParam->attachToCurrentValue (widthValue);
59 modeParam->attachToCurrentValue (modeValue);
60}
61
62ReverbPlugin::~ReverbPlugin()
63{
64 notifyListenersOfDeletion();
65
66 roomSizeParam->detachFromCurrentValue();
67 dampParam->detachFromCurrentValue();
68 wetParam->detachFromCurrentValue();
69 dryParam->detachFromCurrentValue();
70 widthParam->detachFromCurrentValue();
71 modeParam->detachFromCurrentValue();
72}
73
74const char* ReverbPlugin::xmlTypeName = "reverb";
75
76void ReverbPlugin::initialise (const PluginInitialisationInfo& info)
77{
78 outputSilent = true;
79 reverb.setSampleRate (info.sampleRate);
80}
81
82void ReverbPlugin::deinitialise()
83{
84}
85
86void ReverbPlugin::reset()
87{
88 reverb.reset();
89}
90
91static bool isNotSilent (float v) noexcept
92{
93 const float zeroThresh = 1.0f / 8000.0f;
94 return v < -zeroThresh || v > zeroThresh;
95}
96
97static bool isSilent (const float* data, int num) noexcept
98{
99 if (isNotSilent (data[0]) || isNotSilent (data[num / 2]))
100 return false;
101
102 auto range = juce::FloatVectorOperations::findMinAndMax (data, num);
103
104 return ! (isNotSilent (range.getStart())
105 || isNotSilent (range.getEnd()));
106}
107
108void ReverbPlugin::applyToBuffer (const PluginRenderContext& fc)
109{
110 if (fc.destBuffer != nullptr)
111 {
112 SCOPED_REALTIME_CHECK
113
115 params.roomSize = roomSizeParam->getCurrentValue();
116 params.damping = dampParam->getCurrentValue();
117 params.wetLevel = wetParam->getCurrentValue();
118 params.dryLevel = dryParam->getCurrentValue();
119 params.width = widthParam->getCurrentValue();
120 params.freezeMode = modeParam->getCurrentValue();
121
122 if (memcmp (&params, &reverb.getParameters(), sizeof (params)) != 0)
123 reverb.setParameters (params);
124
125 const int num = fc.bufferNumSamples;
126 float* const left = fc.destBuffer->getWritePointer (0, fc.bufferStartSample);
127
128 if (fc.destBuffer->getNumChannels() >= 2)
129 {
130 clearChannels (*fc.destBuffer, 2, -1, fc.bufferStartSample, fc.bufferNumSamples);
131
132 float* const right = fc.destBuffer->getWritePointer (1, fc.bufferStartSample);
133
134 if (outputSilent && isSilent (left, num) && isSilent (right, num))
135 return;
136
137 reverb.processStereo (left, right, num);
138
139 outputSilent = isSilent (left, num) && isSilent (right, num);
140 }
141 else
142 {
143 if (outputSilent && isSilent (left, num))
144 return;
145
146 reverb.processMono (left, num);
147
148 outputSilent = isSilent (left, num);
149 }
150
151 zeroDenormalisedValuesIfNeeded (*fc.destBuffer);
152 }
153}
154
155void ReverbPlugin::restorePluginStateFromValueTree (const juce::ValueTree& v)
156{
157 copyPropertiesToCachedValues (v, roomSizeValue, dampValue, wetValue, dryValue, widthValue, modeValue);
158
159 for (auto p : getAutomatableParameters())
160 p->updateFromAttachedValue();
161}
162
163void ReverbPlugin::setRoomSize (float value) { roomSizeParam->setParameter (juce::jlimit (0.0f, 1.0f, value), juce::sendNotification); }
164float ReverbPlugin::getRoomSize() { return roomSizeParam->getCurrentValue(); }
165
166void ReverbPlugin::setDamp (float value) { dampParam->setParameter (juce::jlimit (0.0f, 1.0f, value), juce::sendNotification); }
167float ReverbPlugin::getDamp() { return dampParam->getCurrentValue(); }
168
169void ReverbPlugin::setWet (float value) { wetParam->setParameter (juce::jlimit (0.0f, 1.0f, value), juce::sendNotification); }
170float ReverbPlugin::getWet() { return wetParam->getCurrentValue(); }
171
172void ReverbPlugin::setDry (float value) { dryParam->setParameter (juce::jlimit (0.0f, 1.0f, value), juce::sendNotification); }
173float ReverbPlugin::getDry() { return dryParam->getCurrentValue(); }
174
175void ReverbPlugin::setWidth (float value) { widthParam->setParameter (juce::jlimit (0.0f, 1.0f, value), juce::sendNotification); }
176float ReverbPlugin::getWidth() { return widthParam->getCurrentValue(); }
177
178void ReverbPlugin::setMode (float value) { modeParam->setParameter (juce::jlimit (0.0f, 1.0f, value), juce::sendNotification); }
179float ReverbPlugin::getMode() { return modeParam->getCurrentValue(); }
180
181}} // namespace tracktion { inline namespace engine
Type * getWritePointer(int channelNumber) noexcept
int getNumChannels() const noexcept
float getFloatValue() const noexcept
#define TRANS(stringLiteral)
memcmp
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
sendNotification
Passed into Plugins when they are being initialised, to give them useful contextual information that ...
The context passed to plugin render methods to provide it with buffers to fill.
int bufferNumSamples
The number of samples to write into the audio buffer.
juce::AudioBuffer< float > * destBuffer
The target audio buffer which needs to be filled.
int bufferStartSample
The index of the start point in the audio buffer from which data must be written.