From 01d51a860a4a3933c0e8844e67e265eaa7f0cedb Mon Sep 17 00:00:00 2001 From: reuk Date: Thu, 21 Jul 2022 15:24:32 +0100 Subject: [PATCH] Graph: Modify the RenderSequenceBuilder so that it only needs a const ref to the graph during building --- .../processors/juce_AudioProcessorGraph.cpp | 92 ++++++++++++------- 1 file changed, 59 insertions(+), 33 deletions(-) diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp b/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp index 6b7a33416e..a5fa8d7ff5 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp @@ -316,7 +316,14 @@ public: { auto sequence = std::make_unique(); const RenderSequenceBuilder builder (g, *sequence); - return sequence; + + struct SequenceAndLatency + { + std::unique_ptr sequence; + int latencySamples = 0; + }; + + return SequenceAndLatency { std::move (sequence), builder.totalLatency }; } private: @@ -324,8 +331,6 @@ private: using Node = AudioProcessorGraph::Node; using NodeID = AudioProcessorGraph::NodeID; - AudioProcessorGraph& graph; - const Array orderedNodes; struct AssignedBuffer @@ -366,7 +371,7 @@ private: return delays[nodeID.uid]; } - int getInputLatencyForNode (NodeID nodeID) const + int getInputLatencyForNode (const AudioProcessorGraph& graph, NodeID nodeID) const { int maxLatency = 0; @@ -430,13 +435,17 @@ private: } template - int findBufferForInputAudioChannel (RenderSequence& sequence, Node& node, const int inputChan, - const int ourRenderingIndex, const int maxLatency) + int findBufferForInputAudioChannel (const AudioProcessorGraph& graph, + RenderSequence& sequence, + Node& node, + const int inputChan, + const int ourRenderingIndex, + const int maxLatency) { auto& processor = *node.getProcessor(); auto numOuts = processor.getTotalNumOutputChannels(); - auto sources = getSourcesForChannel (node, inputChan); + auto sources = getSourcesForChannel (graph, node, inputChan); // Handle an unconnected input channel... if (sources.isEmpty()) @@ -465,7 +474,7 @@ private: } if (inputChan < numOuts - && isBufferNeededLater (ourRenderingIndex, inputChan, src)) + && isBufferNeededLater (graph, ourRenderingIndex, inputChan, src)) { // can't mess up this channel because it's needed later by another node, // so we need to use a copy of it.. @@ -491,7 +500,7 @@ private: auto src = sources.getReference(i); auto sourceBufIndex = getBufferContaining (src); - if (sourceBufIndex >= 0 && ! isBufferNeededLater (ourRenderingIndex, inputChan, src)) + if (sourceBufIndex >= 0 && ! isBufferNeededLater (graph, ourRenderingIndex, inputChan, src)) { // we've found one of our input chans that can be re-used.. reusableInputIndex = i; @@ -541,7 +550,7 @@ private: if (nodeDelay < maxLatency) { - if (! isBufferNeededLater (ourRenderingIndex, inputChan, src)) + if (! isBufferNeededLater (graph, ourRenderingIndex, inputChan, src)) { sequence.addDelayChannelOp (srcIndex, maxLatency - nodeDelay); } @@ -563,10 +572,13 @@ private: } template - int findBufferForInputMidiChannel (RenderSequence& sequence, Node& node, int ourRenderingIndex) + int findBufferForInputMidiChannel (const AudioProcessorGraph& graph, + RenderSequence& sequence, + Node& node, + int ourRenderingIndex) { auto& processor = *node.getProcessor(); - auto sources = getSourcesForChannel (node, AudioProcessorGraph::midiChannelIndex); + auto sources = getSourcesForChannel (graph, node, AudioProcessorGraph::midiChannelIndex); // No midi inputs.. if (sources.isEmpty()) @@ -587,7 +599,7 @@ private: if (midiBufferToUse >= 0) { - if (isBufferNeededLater (ourRenderingIndex, AudioProcessorGraph::midiChannelIndex, src)) + if (isBufferNeededLater (graph, ourRenderingIndex, AudioProcessorGraph::midiChannelIndex, src)) { // can't mess up this channel because it's needed later by another node, so we // need to use a copy of it.. @@ -615,7 +627,7 @@ private: auto sourceBufIndex = getBufferContaining (src); if (sourceBufIndex >= 0 - && ! isBufferNeededLater (ourRenderingIndex, AudioProcessorGraph::midiChannelIndex, src)) + && ! isBufferNeededLater (graph, ourRenderingIndex, AudioProcessorGraph::midiChannelIndex, src)) { // we've found one of our input buffers that can be re-used.. reusableInputIndex = i; @@ -655,7 +667,10 @@ private: } template - void createRenderingOpsForNode (RenderSequence& sequence, Node& node, const int ourRenderingIndex) + void createRenderingOpsForNode (const AudioProcessorGraph& graph, + RenderSequence& sequence, + Node& node, + const int ourRenderingIndex) { auto& processor = *node.getProcessor(); auto numIns = processor.getTotalNumInputChannels(); @@ -663,12 +678,17 @@ private: auto totalChans = jmax (numIns, numOuts); Array audioChannelsToUse; - auto maxLatency = getInputLatencyForNode (node.nodeID); + auto maxLatency = getInputLatencyForNode (graph, node.nodeID); for (int inputChan = 0; inputChan < numIns; ++inputChan) { // get a list of all the inputs to this node - auto index = findBufferForInputAudioChannel (sequence, node, inputChan, ourRenderingIndex, maxLatency); + auto index = findBufferForInputAudioChannel (graph, + sequence, + node, + inputChan, + ourRenderingIndex, + maxLatency); jassert (index >= 0); audioChannelsToUse.add (index); @@ -686,7 +706,7 @@ private: audioBuffers.getReference (index).channel = { node.nodeID, outputChan }; } - auto midiBufferToUse = findBufferForInputMidiChannel (sequence, node, ourRenderingIndex); + auto midiBufferToUse = findBufferForInputMidiChannel (graph, sequence, node, ourRenderingIndex); if (processor.producesMidi()) midiBuffers.getReference (midiBufferToUse).channel = { node.nodeID, AudioProcessorGraph::midiChannelIndex }; @@ -700,7 +720,9 @@ private: } //============================================================================== - Array getSourcesForChannel (Node& node, int inputChannelIndex) + Array getSourcesForChannel (const AudioProcessorGraph& graph, + Node& node, + int inputChannelIndex) { Array results; AudioProcessorGraph::NodeAndChannel nc { node.nodeID, inputChannelIndex }; @@ -737,14 +759,17 @@ private: return -1; } - void markAnyUnusedBuffersAsFree (Array& buffers, const int stepIndex) + void markAnyUnusedBuffersAsFree (const AudioProcessorGraph& graph, + Array& buffers, + const int stepIndex) { for (auto& b : buffers) - if (b.isAssigned() && ! isBufferNeededLater (stepIndex, -1, b.channel)) + if (b.isAssigned() && ! isBufferNeededLater (graph, stepIndex, -1, b.channel)) b.setFree(); } - bool isBufferNeededLater (int stepIndexToSearchFrom, + bool isBufferNeededLater (const AudioProcessorGraph& graph, + int stepIndexToSearchFrom, int inputChannelOfIndexToIgnore, AudioProcessorGraph::NodeAndChannel output) const { @@ -774,21 +799,19 @@ private: } template - RenderSequenceBuilder (AudioProcessorGraph& g, RenderSequence& sequence) - : graph (g), orderedNodes (createOrderedNodeList (graph)) + RenderSequenceBuilder (const AudioProcessorGraph& graph, RenderSequence& sequence) + : orderedNodes (createOrderedNodeList (graph)) { audioBuffers.add (AssignedBuffer::createReadOnlyEmpty()); // first buffer is read-only zeros midiBuffers .add (AssignedBuffer::createReadOnlyEmpty()); for (int i = 0; i < orderedNodes.size(); ++i) { - createRenderingOpsForNode (sequence, *orderedNodes.getUnchecked(i), i); - markAnyUnusedBuffersAsFree (audioBuffers, i); - markAnyUnusedBuffersAsFree (midiBuffers, i); + createRenderingOpsForNode (graph, sequence, *orderedNodes.getUnchecked(i), i); + markAnyUnusedBuffersAsFree (graph, audioBuffers, i); + markAnyUnusedBuffersAsFree (graph, midiBuffers, i); } - graph.setLatencySamples (totalLatency); - sequence.numBuffersNeeded = audioBuffers.size(); sequence.numMidiBuffersNeeded = midiBuffers.size(); } @@ -1249,8 +1272,11 @@ void AudioProcessorGraph::handleAsyncUpdate() const ScopedLock sl (getCallbackLock()); const auto currentBlockSize = getBlockSize(); - newSequenceF->prepareBuffers (currentBlockSize); - newSequenceD->prepareBuffers (currentBlockSize); + newSequenceF.sequence->prepareBuffers (currentBlockSize); + newSequenceD.sequence->prepareBuffers (currentBlockSize); + + jassert (newSequenceF.latencySamples == newSequenceD.latencySamples); + setLatencySamples (newSequenceF.latencySamples); if (anyNodesNeedPreparing()) { @@ -1263,8 +1289,8 @@ void AudioProcessorGraph::handleAsyncUpdate() isPrepared = 1; - std::swap (renderSequenceFloat, newSequenceF); - std::swap (renderSequenceDouble, newSequenceD); + renderSequenceFloat = std::move (newSequenceF.sequence); + renderSequenceDouble = std::move (newSequenceD.sequence); } //==============================================================================