@@ -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
7679void 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
247256void 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+ }
0 commit comments