Skip to content

Commit 2a87bd3

Browse files
Allocating input buffers from arena
1 parent 8156d96 commit 2a87bd3

File tree

17 files changed

+240
-97
lines changed

17 files changed

+240
-97
lines changed

modules/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ target_compile_definitions(juce_plugin_modules
7474
JucePlugin_VersionString="${CMAKE_PROJECT_VERSION}"
7575
JucePlugin_Name="${CMAKE_PROJECT_NAME}"
7676
JUCE_MODAL_LOOPS_PERMITTED=1
77+
CHOWDSP_BUFFER_MAX_NUM_CHANNELS=2
7778
INTERFACE
7879
$<TARGET_PROPERTY:juce_plugin_modules,COMPILE_DEFINITIONS>
7980
)

modules/chowdsp_utils

Submodule chowdsp_utils updated 366 files

src/gui/pedalboard/cables/CubicBezier.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ struct CubicBezier
3636
using namespace chowdsp::Polynomials;
3737

3838
/* calculate the curve point at parameter value t */
39-
auto xVal = estrin<3> ({ ax, bx, cx, p1x }, t);
40-
auto yVal = estrin<3> ({ ay, by, cy, p1y }, t);
39+
auto xVal = estrin<3> (chowdsp::Polynomial<float, 3> { { ax, bx, cx, p1x } }, t);
40+
auto yVal = estrin<3> (chowdsp::Polynomial<float, 3> { { ay, by, cy, p1y } }, t);
4141

4242
return juce::Point { xVal, yVal };
4343
}

src/processors/BaseProcessor.cpp

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,6 @@ void BaseProcessor::prepareProcessing (double sampleRate, int numSamples)
4747
{
4848
prepare (sampleRate, numSamples);
4949

50-
for (auto& b : inputBuffers)
51-
{
52-
b.setSize (2, numSamples);
53-
b.clear();
54-
}
55-
5650
for (auto& mag : portMagnitudes)
5751
{
5852
mag.smoother.prepare ({ sampleRate, (uint32) numSamples, 1 });
@@ -64,21 +58,18 @@ void BaseProcessor::prepareProcessing (double sampleRate, int numSamples)
6458
void BaseProcessor::freeInternalMemory()
6559
{
6660
releaseMemory();
67-
for (auto& b : inputBuffers)
68-
b.setSize (0, 0);
6961
}
7062

7163
void BaseProcessor::processAudioBlock (AudioBuffer<float>& buffer)
7264
{
73-
auto updateBufferMag = [&] (const AudioBuffer<float>& inBuffer, int inputIndex)
65+
auto updateBufferMag = [&] (const chowdsp::BufferView<const float>& inBuffer, int inputIndex)
7466
{
7567
const auto inBufferNumChannels = inBuffer.getNumChannels();
7668
const auto inBufferNumSamples = inBuffer.getNumSamples();
7769

7870
auto rmsAvg = 0.0f;
7971
for (int ch = 0; ch < inBufferNumChannels; ++ch)
80-
rmsAvg += Decibels::gainToDecibels (inBuffer.getRMSLevel (ch, 0, inBufferNumSamples)); // @TODO: not sure if getRMSLevel is optimized enough...
81-
72+
rmsAvg += Decibels::gainToDecibels (chowdsp::BufferMath::getRMSLevel (inBuffer, ch));
8273
rmsAvg /= (float) inBufferNumChannels;
8374

8475
auto& portMag = portMagnitudes[(size_t) inputIndex];
@@ -97,7 +88,12 @@ void BaseProcessor::processAudioBlock (AudioBuffer<float>& buffer)
9788
else if (numInputs > 1)
9889
{
9990
for (int i = 0; i < numInputs; ++i)
100-
updateBufferMag (getInputBuffer (i), i);
91+
{
92+
if (inputBuffers.getReference (i).getNumSamples() > 0)
93+
updateBufferMag (inputBuffers[i], i);
94+
else if (inputsConnected.contains (i))
95+
updateBufferMag (buffer, i);
96+
}
10197
}
10298
}
10399

@@ -232,7 +228,6 @@ void BaseProcessor::removeConnection (const ConnectionInfo& info)
232228
{
233229
connections.remove (cIdx);
234230
info.endProc->inputsConnected.removeFirstMatchingValue (info.endPort);
235-
info.endProc->inputBuffers[info.endPort].clear();
236231
info.endProc->inputConnectionChanged (info.endPort, false);
237232
break;
238233
}

src/processors/BaseProcessor.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,19 @@ static PortTypesVector initialisePortTypes (PortMapper mapper)
6767
}
6868
} // namespace base_processor_detail
6969

70+
struct DSPArena : chowdsp::ArenaAllocator<std::span<std::byte>>
71+
{
72+
chowdsp::BufferView<float> alloc_buffer (int num_channels, int num_samples)
73+
{
74+
return chowdsp::make_temp_buffer<float> (*this, num_channels, num_samples);
75+
}
76+
77+
chowdsp::BufferView<float> alloc_buffer (const chowdsp::BufferView<const float>& buffer)
78+
{
79+
return alloc_buffer (buffer.getNumChannels(), buffer.getNumSamples());
80+
}
81+
};
82+
7083
class BaseProcessor : private JuceProcWrapper
7184
{
7285
public:
@@ -160,8 +173,9 @@ class BaseProcessor : private JuceProcWrapper
160173
/** Returns the netlist circuit quantities, or nullptr if the processor has no circuit quantities. */
161174
auto* getNetlistCircuitQuantities() { return netlistCircuitQuantities.get(); }
162175

163-
const AudioBuffer<float>& getInputBuffer (int idx = 0) const { return inputBuffers.getReference (idx); }
164-
AudioBuffer<float>& getInputBufferNonConst (int idx = 0) { return inputBuffers.getReference (idx); } // Most derived classes should never use this!
176+
chowdsp::BufferView<float>& getInputBufferView (int idx = 0) { return inputBuffers.getReference (idx); }
177+
AudioBuffer<float> getInputBuffer (int idx = 0) const { return inputBuffers.getReference (idx).toAudioBuffer(); }
178+
AudioBuffer<float> getInputBufferNonConst (int idx = 0) { return inputBuffers.getReference (idx).toAudioBuffer(); } // Most derived classes should never use this!
165179
AudioBuffer<float>* getOutputBuffer (int idx = 0) { return outputBuffers[idx]; }
166180
const ConnectionInfo& getOutputConnection (int portIdx, int connectionIdx) const { return outputConnections[(size_t) portIdx].getReference (connectionIdx); }
167181

@@ -283,7 +297,7 @@ class BaseProcessor : private JuceProcWrapper
283297
const int numOutputs {};
284298

285299
std::vector<Array<ConnectionInfo>> outputConnections;
286-
Array<AudioBuffer<float>> inputBuffers;
300+
Array<chowdsp::BufferView<float>> inputBuffers;
287301
int numInputsReady = 0;
288302

289303
juce::Point<float> editorPosition;

src/processors/chain/ProcessorChain.cpp

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ void ProcessorChain::initializeProcessors()
7171
if (auto* proc = procs[i])
7272
proc->prepareProcessing (osSampleRate, osSamplesPerBlock);
7373
}
74+
75+
deallocArena (arena.get_memory_resource());
76+
arena.get_memory_resource() = allocArena (getRequiredArenaSizeBytes());
7477
}
7578

7679
void ProcessorChain::prepare (double sampleRate, int samplesPerBlock)
@@ -142,14 +145,18 @@ void ProcessorChain::runProcessor (BaseProcessor* proc, AudioBuffer<float>& buff
142145
}
143146
else if (nextNumProcs > 1 && nextNumInputs == 1)
144147
{
145-
auto& copyNextBuffer = nextProc->getInputBufferNonConst();
146-
copyNextBuffer.makeCopyOf (nextBuffer, true);
148+
auto bufferView = arena.alloc_buffer (nextBuffer);
149+
chowdsp::BufferMath::copyBufferData (nextBuffer, bufferView);
150+
nextProc->getInputBufferView() = bufferView;
151+
auto copyNextBuffer = bufferView.toAudioBuffer();
147152
runProcessor (nextProc, copyNextBuffer, outProcessed);
148153
}
149154
else
150155
{
151-
auto& copyNextBuffer = nextProc->getInputBufferNonConst (inputIndex);
152-
copyNextBuffer.makeCopyOf (nextBuffer, true);
156+
auto bufferView = arena.alloc_buffer (nextBuffer);
157+
chowdsp::BufferMath::copyBufferData (nextBuffer, bufferView);
158+
nextProc->getInputBufferView (inputIndex) = bufferView;
159+
auto copyNextBuffer = bufferView.toAudioBuffer();
153160

154161
nextProc->incrementNumInputsReady();
155162
if (nextProc->getNumInputsReady() < nextProc->getNumInputConnections())
@@ -242,6 +249,8 @@ void ProcessorChain::processAudio (AudioBuffer<float>& buffer, const MidiBuffer&
242249
else
243250
jassertfalse; // output buffer is null after output was processed?
244251
}
252+
253+
arena.clear();
245254
}
246255

247256
void ProcessorChain::parameterChanged (const juce::String& /*parameterID*/, float /*newValue*/)
@@ -254,3 +263,52 @@ void ProcessorChain::parameterChanged (const juce::String& /*parameterID*/, floa
254263
presetManager->setIsDirty (true); },
255264
true);
256265
}
266+
267+
size_t ProcessorChain::getRequiredArenaSizeBytes()
268+
{
269+
const auto osFactor = ioProcessor.getOversamplingFactor();
270+
const int osSamplesPerBlock = mySamplesPerBlock * osFactor;
271+
const auto osSamplesPerBlockPadded = chowdsp::Math::round_to_next_multiple (osSamplesPerBlock, 4);
272+
const auto bufferSizeBytes = osSamplesPerBlockPadded * 2 * sizeof (float);
273+
274+
const auto numIOBuffers = chowdsp::Math::round_to_next_multiple (connectionsCount + 1, 10);
275+
const auto ioBufferBytes = numIOBuffers * bufferSizeBytes;
276+
277+
static constexpr size_t blockSize = 8192;
278+
const auto totalNumBytes = chowdsp::Math::round_to_next_multiple (ioBufferBytes, blockSize);
279+
280+
return totalNumBytes;
281+
}
282+
283+
bool ProcessorChain::needsNewArena (size_t requiredBytes) const
284+
{
285+
const auto currentArenaBytes = arena.get_memory_resource().size();
286+
287+
// If the current arena is too small then we need a new one
288+
if (currentArenaBytes < requiredBytes)
289+
return true;
290+
291+
// If the current arena if way too big (more than 20%), then we need a new one
292+
if (currentArenaBytes * 4 / 5 > requiredBytes)
293+
return true;
294+
295+
return false;
296+
}
297+
298+
std::span<std::byte> ProcessorChain::allocArena (size_t bytes)
299+
{
300+
juce::Logger::writeToLog ("Allocating arena of size: " + juce::String { bytes });
301+
return {
302+
(std::byte*) chowdsp::aligned_alloc (16, bytes),
303+
bytes,
304+
};
305+
}
306+
307+
void ProcessorChain::deallocArena (std::span<std::byte> bytes)
308+
{
309+
if (bytes.empty())
310+
return;
311+
312+
juce::Logger::writeToLog ("De-allocating arena of size: " + juce::String { bytes.size() });
313+
chowdsp::aligned_free (bytes.data());
314+
}

src/processors/chain/ProcessorChain.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,5 +83,12 @@ class ProcessorChain : private AudioProcessorValueTreeState::Listener
8383
MidiBuffer internalMidiBuffer;
8484
PlayheadHelpers playheadHelper;
8585

86+
size_t getRequiredArenaSizeBytes();
87+
bool needsNewArena (size_t requiredBytes) const;
88+
static std::span<std::byte> allocArena (size_t bytes);
89+
static void deallocArena (std::span<std::byte> bytes);
90+
int connectionsCount {};
91+
DSPArena arena {};
92+
8693
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProcessorChain)
8794
};

src/processors/chain/ProcessorChainActions.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,20 @@ class ProcChainActions
7171
+ String (info.startPort) + " to " + info.endProc->getName() + " port #"
7272
+ String (info.endPort));
7373

74+
chain.connectionsCount++;
75+
const auto arenaBytes = chain.getRequiredArenaSizeBytes();
76+
const auto needsNewArena = chain.needsNewArena (arenaBytes);
77+
std::span<std::byte> arenaData {};
78+
if (needsNewArena)
79+
arenaData = chain.allocArena (arenaBytes);
80+
7481
{
7582
SpinLock::ScopedLockType scopedProcessingLock { chain.processingLock };
7683
info.startProc->addConnection (ConnectionInfo (info));
84+
if (needsNewArena)
85+
std::swap (arenaData, chain.arena.get_memory_resource());
7786
}
87+
chain.deallocArena (arenaData);
7888
chain.connectionAddedBroadcaster (info);
7989
}
8090

@@ -84,10 +94,20 @@ class ProcChainActions
8494
+ String (info.startPort) + " to " + info.endProc->getName() + " port #"
8595
+ String (info.endPort));
8696

97+
chain.connectionsCount--;
98+
const auto arenaBytes = chain.getRequiredArenaSizeBytes();
99+
const auto needsNewArena = chain.needsNewArena (arenaBytes);
100+
std::span<std::byte> arenaData {};
101+
if (needsNewArena)
102+
arenaData = chain.allocArena (arenaBytes);
103+
87104
{
88105
SpinLock::ScopedLockType scopedProcessingLock { chain.processingLock };
89106
info.startProc->removeConnection (info);
107+
if (needsNewArena)
108+
std::swap (arenaData, chain.arena.get_memory_resource());
90109
}
110+
chain.deallocArena (arenaData);
91111
chain.connectionRemovedBroadcaster (info);
92112
}
93113

src/processors/drive/Warp.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ inline std::pair<float, float> newton_raphson (float x, float y1, float b, float
4545
*/
4646
constexpr float calcQ (float gainDB)
4747
{
48-
constexpr float adaptiveQCoeffs[] = { -7.75358366e-09f, 5.21182270e-23f, 2.70080663e-06f, -3.04753193e-20f, -3.29851878e-04f, 1.89860352e-18f, 2.59076683e-02f, -4.77485061e-17f, 3.78416236e-01f };
49-
return chowdsp::Polynomials::estrin<8> (adaptiveQCoeffs, gainDB);
48+
constexpr std::array<float, 9> adaptiveQCoeffs { -7.75358366e-09f, 5.21182270e-23f, 2.70080663e-06f, -3.04753193e-20f, -3.29851878e-04f, 1.89860352e-18f, 2.59076683e-02f, -4.77485061e-17f, 3.78416236e-01f };
49+
return chowdsp::Polynomials::estrin<8> (chowdsp::Polynomial<float, 8> { adaptiveQCoeffs }, gainDB);
5050
}
5151
} // namespace WarpFuncs
5252

src/processors/drive/waveshaper/SurgeWaveshapers.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ inline Vec4 Asym (QuadFilterWaveshaperState* __restrict, Vec4 in, Vec4 drive)
115115
auto x = in * drive + Vec4 (0.5f);
116116
auto isPos = x >= Vec4 (0.0f);
117117
auto pos = xsimd::tanh (x);
118-
auto neg = chowdsp::Polynomials::horner<3> ({ Vec4 (0.07f), Vec4 (0.0054f), Vec4 (1.0f), Vec4 (0.0f) }, x);
118+
auto neg = chowdsp::Polynomials::horner<3> (chowdsp::Polynomial<Vec4, 3> { { 0.07f, 0.0054f, 1.0f, 0.0f } }, x);
119119
neg = xsimd::max (neg, Vec4 (-10.0f));
120120

121121
return xsimd::select (isPos, pos, neg) - tanh0p5;

0 commit comments

Comments
 (0)