From 1bc268de7072ca04555555fdff25430d89e15149 Mon Sep 17 00:00:00 2001 From: reuk Date: Wed, 4 Jan 2023 20:27:09 +0000 Subject: [PATCH] AudioProcessorGraph: Cache render buffer pointers for improved performance --- .../processors/juce_AudioProcessorGraph.cpp | 241 +++++++++++++----- 1 file changed, 183 insertions(+), 58 deletions(-) diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp b/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp index d9ef6303d8..5e615433ab 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp @@ -444,8 +444,6 @@ struct GraphRenderSequence struct Context { - FloatType* const* audioBuffers; - MidiBuffer* midiBuffers; AudioPlayHead* audioPlayHead; int numSamples; }; @@ -484,10 +482,10 @@ struct GraphRenderSequence currentMidiOutputBuffer.clear(); { - const Context context { renderingBuffer.getArrayOfWritePointers(), midiBuffers.begin(), audioPlayHead, numSamples }; + const Context context { audioPlayHead, numSamples }; for (const auto& op : renderOps) - op (context); + op->process (context); } for (int i = 0; i < buffer.getNumChannels(); ++i) @@ -502,39 +500,189 @@ struct GraphRenderSequence void addClearChannelOp (int index) { - renderOps.push_back ([=] (const Context& c) { FloatVectorOperations::clear (c.audioBuffers[index], c.numSamples); }); + struct ClearOp : public RenderOp + { + explicit ClearOp (int indexIn) : index (indexIn) {} + + void prepare (FloatType* const* renderBuffer, MidiBuffer*) override + { + channelBuffer = renderBuffer[index]; + } + + void process (const Context& c) override + { + FloatVectorOperations::clear (channelBuffer, c.numSamples); + } + + FloatType* channelBuffer = nullptr; + int index = 0; + }; + + renderOps.push_back (std::make_unique (index)); } void addCopyChannelOp (int srcIndex, int dstIndex) { - renderOps.push_back ([=] (const Context& c) { FloatVectorOperations::copy (c.audioBuffers[dstIndex], c.audioBuffers[srcIndex], c.numSamples); }); + struct CopyOp : public RenderOp + { + explicit CopyOp (int fromIn, int toIn) : from (fromIn), to (toIn) {} + + void prepare (FloatType* const* renderBuffer, MidiBuffer*) override + { + fromBuffer = renderBuffer[from]; + toBuffer = renderBuffer[to]; + } + + void process (const Context& c) override + { + FloatVectorOperations::copy (toBuffer, fromBuffer, c.numSamples); + } + + FloatType* fromBuffer = nullptr; + FloatType* toBuffer = nullptr; + int from = 0, to = 0; + }; + + renderOps.push_back (std::make_unique (srcIndex, dstIndex)); } void addAddChannelOp (int srcIndex, int dstIndex) { - renderOps.push_back ([=] (const Context& c) { FloatVectorOperations::add (c.audioBuffers[dstIndex], c.audioBuffers[srcIndex], c.numSamples); }); + struct AddOp : public RenderOp + { + explicit AddOp (int fromIn, int toIn) : from (fromIn), to (toIn) {} + + void prepare (FloatType* const* renderBuffer, MidiBuffer*) override + { + fromBuffer = renderBuffer[from]; + toBuffer = renderBuffer[to]; + } + + void process (const Context& c) override + { + FloatVectorOperations::add (toBuffer, fromBuffer, c.numSamples); + } + + FloatType* fromBuffer = nullptr; + FloatType* toBuffer = nullptr; + int from = 0, to = 0; + }; + + renderOps.push_back (std::make_unique (srcIndex, dstIndex)); } JUCE_END_IGNORE_WARNINGS_MSVC void addClearMidiBufferOp (int index) { - renderOps.push_back ([=] (const Context& c) { c.midiBuffers[index].clear(); }); + struct ClearOp : public RenderOp + { + explicit ClearOp (int indexIn) : index (indexIn) {} + + void prepare (FloatType* const*, MidiBuffer* buffers) override + { + channelBuffer = buffers + index; + } + + void process (const Context&) override + { + channelBuffer->clear(); + } + + MidiBuffer* channelBuffer = nullptr; + int index = 0; + }; + + renderOps.push_back (std::make_unique (index)); } void addCopyMidiBufferOp (int srcIndex, int dstIndex) { - renderOps.push_back ([=] (const Context& c) { c.midiBuffers[dstIndex] = c.midiBuffers[srcIndex]; }); + struct CopyOp : public RenderOp + { + explicit CopyOp (int fromIn, int toIn) : from (fromIn), to (toIn) {} + + void prepare (FloatType* const*, MidiBuffer* buffers) override + { + fromBuffer = buffers + from; + toBuffer = buffers + to; + } + + void process (const Context&) override + { + *toBuffer = *fromBuffer; + } + + MidiBuffer* fromBuffer = nullptr; + MidiBuffer* toBuffer = nullptr; + int from = 0, to = 0; + }; + + renderOps.push_back (std::make_unique (srcIndex, dstIndex)); } void addAddMidiBufferOp (int srcIndex, int dstIndex) { - renderOps.push_back ([=] (const Context& c) { c.midiBuffers[dstIndex].addEvents (c.midiBuffers[srcIndex], 0, c.numSamples, 0); }); + struct AddOp : public RenderOp + { + explicit AddOp (int fromIn, int toIn) : from (fromIn), to (toIn) {} + + void prepare (FloatType* const*, MidiBuffer* buffers) override + { + fromBuffer = buffers + from; + toBuffer = buffers + to; + } + + void process (const Context& c) override + { + toBuffer->addEvents (*fromBuffer, 0, c.numSamples, 0); + } + + MidiBuffer* fromBuffer = nullptr; + MidiBuffer* toBuffer = nullptr; + int from = 0, to = 0; + }; + + renderOps.push_back (std::make_unique (srcIndex, dstIndex)); } void addDelayChannelOp (int chan, int delaySize) { - renderOps.push_back (DelayChannelOp { chan, delaySize }); + struct DelayChannelOp : public RenderOp + { + DelayChannelOp (int chan, int delaySize) + : buffer ((size_t) (delaySize + 1), (FloatType) 0), + channel (chan), + writeIndex (delaySize) + { + } + + void prepare (FloatType* const* renderBuffer, MidiBuffer*) override + { + channelBuffer = renderBuffer[channel]; + } + + void process (const Context& c) override + { + auto* data = channelBuffer; + + for (int i = c.numSamples; --i >= 0;) + { + buffer[(size_t) writeIndex] = *data; + *data++ = buffer[(size_t) readIndex]; + + if (++readIndex >= (int) buffer.size()) readIndex = 0; + if (++writeIndex >= (int) buffer.size()) writeIndex = 0; + } + } + + std::vector buffer; + FloatType* channelBuffer = nullptr; + const int channel; + int readIndex = 0, writeIndex; + }; + + renderOps.push_back (std::make_unique (chan, delaySize)); } void addProcessOp (const Node::Ptr& node, @@ -542,7 +690,7 @@ struct GraphRenderSequence int totalNumChans, int midiBuffer) { - renderOps.push_back (ProcessOp { node, audioChannelsUsed, totalNumChans, midiBuffer }); + renderOps.push_back (std::make_unique (node, audioChannelsUsed, totalNumChans, midiBuffer)); } void prepareBuffers (int blockSize) @@ -565,16 +713,9 @@ struct GraphRenderSequence for (auto&& m : midiBuffers) m.ensureSize (defaultMIDIBufferSize); - } - void releaseBuffers() - { - renderingBuffer.setSize (1, 1); - currentAudioOutputBuffer.setSize (1, 1); - currentAudioInputBuffer = nullptr; - currentMidiInputBuffer = nullptr; - currentMidiOutputBuffer.clear(); - midiBuffers.clear(); + for (const auto& op : renderOps) + op->prepare (renderingBuffer.getArrayOfWritePointers(), midiBuffers.data()); } int numBuffersNeeded = 0, numMidiBuffersNeeded = 0; @@ -590,59 +731,40 @@ struct GraphRenderSequence private: //============================================================================== - std::vector> renderOps; - - //============================================================================== - struct DelayChannelOp + struct RenderOp { - DelayChannelOp (int chan, int delaySize) - : buffer ((size_t) (delaySize + 1), (FloatType) 0), - channel (chan), - writeIndex (delaySize) - { - } - - void operator() (const Context& c) - { - auto* data = c.audioBuffers[channel]; - - for (int i = c.numSamples; --i >= 0;) - { - buffer[(size_t) writeIndex] = *data; - *data++ = buffer[(size_t) readIndex]; - - if (++readIndex >= (int) buffer.size()) readIndex = 0; - if (++writeIndex >= (int) buffer.size()) writeIndex = 0; - } - } - - std::vector buffer; - const int channel; - int readIndex = 0, writeIndex; + virtual ~RenderOp() = default; + virtual void prepare (FloatType* const*, MidiBuffer*) = 0; + virtual void process (const Context&) = 0; }; - //============================================================================== - struct ProcessOp + struct ProcessOp : public RenderOp { ProcessOp (const Node::Ptr& n, const Array& audioChannelsUsed, - int totalNumChans, int midiBuffer) + int totalNumChans, + int midiBufferIndex) : node (n), processor (*n->getProcessor()), audioChannelsToUse (audioChannelsUsed), audioChannels ((size_t) jmax (1, totalNumChans), nullptr), - midiBufferToUse (midiBuffer) + midiBufferToUse (midiBufferIndex) { while (audioChannelsToUse.size() < (int) audioChannels.size()) audioChannelsToUse.add (0); } - void operator() (const Context& c) + void prepare (FloatType* const* renderBuffer, MidiBuffer* buffers) override { - processor.setPlayHead (c.audioPlayHead); - for (size_t i = 0; i < audioChannels.size(); ++i) - audioChannels[i] = c.audioBuffers[audioChannelsToUse.getUnchecked ((int) i)]; + audioChannels[i] = renderBuffer[audioChannelsToUse.getUnchecked ((int) i)]; + + midiBuffer = buffers + midiBufferToUse; + } + + void process (const Context& c) override + { + processor.setPlayHead (c.audioPlayHead); auto numAudioChannels = [this] { @@ -660,7 +782,7 @@ private: if (processor.isSuspended()) buffer.clear(); else - callProcess (buffer, c.midiBuffers[midiBufferToUse]); + callProcess (buffer, *midiBuffer); } void callProcess (AudioBuffer& buffer, MidiBuffer& midi) @@ -702,12 +824,15 @@ private: const Node::Ptr node; AudioProcessor& processor; + MidiBuffer* midiBuffer = nullptr; Array audioChannelsToUse; std::vector audioChannels; AudioBuffer tempBufferFloat, tempBufferDouble; const int midiBufferToUse; }; + + std::vector> renderOps; }; //==============================================================================