From d53388097b4865a3fa4b9285cc72389dacb10983 Mon Sep 17 00:00:00 2001 From: Tom Poole Date: Wed, 7 Jul 2021 11:30:13 +0100 Subject: [PATCH] AudioProcessorGraph: Improve performance when building large graphs --- .../format_types/juce_VST3PluginFormat.cpp | 2 - .../processors/juce_AudioProcessorGraph.cpp | 70 ++++++++++++++----- .../processors/juce_AudioProcessorGraph.h | 2 + .../juce_core/system/juce_StandardHeader.h | 1 + modules/juce_graphics/juce_graphics.cpp | 2 - .../native/x11/juce_linux_XWindowSystem.cpp | 2 - 6 files changed, 56 insertions(+), 23 deletions(-) diff --git a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp index d6ce353ef9..39d5bedf27 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp @@ -28,8 +28,6 @@ #include "juce_VST3Headers.h" #include "juce_VST3Common.h" -#include - namespace juce { diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp b/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp index 8b2435de40..b84b672902 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp @@ -337,10 +337,8 @@ template struct RenderSequenceBuilder { RenderSequenceBuilder (AudioProcessorGraph& g, RenderSequence& s) - : graph (g), sequence (s) + : graph (g), sequence (s), orderedNodes (createOrderedNodeList (graph)) { - createOrderedNodeList(); - audioBuffers.add (AssignedBuffer::createReadOnlyEmpty()); // first buffer is read-only zeros midiBuffers .add (AssignedBuffer::createReadOnlyEmpty()); @@ -358,12 +356,13 @@ struct RenderSequenceBuilder } //============================================================================== + using Node = AudioProcessorGraph::Node; using NodeID = AudioProcessorGraph::NodeID; AudioProcessorGraph& graph; RenderSequence& sequence; - Array orderedNodes; + const Array orderedNodes; struct AssignedBuffer { @@ -415,21 +414,58 @@ struct RenderSequenceBuilder } //============================================================================== - void createOrderedNodeList() + static void getAllParentsOfNode (const Node* child, + std::unordered_set& parents, + const std::unordered_map>& otherParents) { - for (auto* node : graph.getNodes()) + for (auto&& i : child->inputs) { - int j = 0; + auto* parentNode = i.otherNode; - for (; j < orderedNodes.size(); ++j) - if (graph.isAnInputTo (*node, *orderedNodes.getUnchecked(j))) - break; + if (parentNode == child) + continue; - orderedNodes.insert (j, node); + if (parents.insert (parentNode).second) + { + auto parentParents = otherParents.find (parentNode); + + if (parentParents != otherParents.end()) + { + parents.insert (parentParents->second.begin(), parentParents->second.end()); + continue; + } + + getAllParentsOfNode (i.otherNode, parents, otherParents); + } } } - int findBufferForInputAudioChannel (AudioProcessorGraph::Node& node, const int inputChan, + static auto createOrderedNodeList (const AudioProcessorGraph& graph) + { + Array result; + + std::unordered_map> nodeParents; + + for (auto* node : graph.getNodes()) + { + int insertionIndex = 0; + + for (; insertionIndex < result.size(); ++insertionIndex) + { + auto& parents = nodeParents[result.getUnchecked (insertionIndex)]; + + if (parents.find (node) != parents.end()) + break; + } + + result.insert (insertionIndex, node); + getAllParentsOfNode (node, nodeParents[node], nodeParents); + } + + return result; + } + + int findBufferForInputAudioChannel (Node& node, const int inputChan, const int ourRenderingIndex, const int maxLatency) { auto& processor = *node.getProcessor(); @@ -561,7 +597,7 @@ struct RenderSequenceBuilder return bufIndex; } - int findBufferForInputMidiChannel (AudioProcessorGraph::Node& node, int ourRenderingIndex) + int findBufferForInputMidiChannel (Node& node, int ourRenderingIndex) { auto& processor = *node.getProcessor(); auto sources = getSourcesForChannel (node, AudioProcessorGraph::midiChannelIndex); @@ -652,7 +688,7 @@ struct RenderSequenceBuilder return midiBufferToUse; } - void createRenderingOpsForNode (AudioProcessorGraph::Node& node, const int ourRenderingIndex) + void createRenderingOpsForNode (Node& node, const int ourRenderingIndex) { auto& processor = *node.getProcessor(); auto numIns = processor.getTotalNumInputChannels(); @@ -697,7 +733,7 @@ struct RenderSequenceBuilder } //============================================================================== - Array getSourcesForChannel (AudioProcessorGraph::Node& node, int inputChannelIndex) + Array getSourcesForChannel (Node& node, int inputChannelIndex) { Array results; AudioProcessorGraph::NodeAndChannel nc { node.nodeID, inputChannelIndex }; @@ -1339,7 +1375,7 @@ void AudioProcessorGraph::setNonRealtime (bool isProcessingNonRealtime) noexcept double AudioProcessorGraph::getTailLengthSeconds() const { return 0; } bool AudioProcessorGraph::acceptsMidi() const { return true; } bool AudioProcessorGraph::producesMidi() const { return true; } -void AudioProcessorGraph::getStateInformation (juce::MemoryBlock&) {} +void AudioProcessorGraph::getStateInformation (MemoryBlock&) {} void AudioProcessorGraph::setStateInformation (const void*, int) {} template @@ -1530,7 +1566,7 @@ void AudioProcessorGraph::AudioGraphIOProcessor::setCurrentProgram (int) const String AudioProcessorGraph::AudioGraphIOProcessor::getProgramName (int) { return {}; } void AudioProcessorGraph::AudioGraphIOProcessor::changeProgramName (int, const String&) {} -void AudioProcessorGraph::AudioGraphIOProcessor::getStateInformation (juce::MemoryBlock&) {} +void AudioProcessorGraph::AudioGraphIOProcessor::getStateInformation (MemoryBlock&) {} void AudioProcessorGraph::AudioGraphIOProcessor::setStateInformation (const void*, int) {} void AudioProcessorGraph::AudioGraphIOProcessor::setParentGraph (AudioProcessorGraph* const newGraph) diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h b/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h index a60e67d845..7b6ab003a3 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h @@ -133,6 +133,8 @@ public: friend class AudioProcessorGraph; template friend struct GraphRenderSequence; + template + friend struct RenderSequenceBuilder; struct Connection { diff --git a/modules/juce_core/system/juce_StandardHeader.h b/modules/juce_core/system/juce_StandardHeader.h index e473404663..a9f54cf3f1 100644 --- a/modules/juce_core/system/juce_StandardHeader.h +++ b/modules/juce_core/system/juce_StandardHeader.h @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include diff --git a/modules/juce_graphics/juce_graphics.cpp b/modules/juce_graphics/juce_graphics.cpp index fd45e45fbe..8c30c8c5fe 100644 --- a/modules/juce_graphics/juce_graphics.cpp +++ b/modules/juce_graphics/juce_graphics.cpp @@ -67,8 +67,6 @@ #include #endif - #include - JUCE_END_IGNORE_WARNINGS_MSVC #elif JUCE_IOS diff --git a/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp b/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp index 6b65e14c3e..115401b537 100644 --- a/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp +++ b/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp @@ -23,8 +23,6 @@ ============================================================================== */ -#include - namespace juce {