1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

AudioProcessorGraph: Allow triggering manual rebuild, and avoid rebuilding if nothing has changed

This commit is contained in:
reuk 2023-01-19 13:14:04 +00:00
parent c56102f50a
commit eaa6dfc3ee
No known key found for this signature in database
GPG key ID: 9ADCD339CFC98A11
2 changed files with 72 additions and 10 deletions

View file

@ -351,14 +351,14 @@ public:
/* Called from prepareToPlay and releaseResources with the PrepareSettings that should be
used next time the graph is rebuilt.
*/
void setState (Optional<PrepareSettings> newSettings)
void setState (std::optional<PrepareSettings> newSettings)
{
const std::lock_guard<std::mutex> lock (mutex);
next = newSettings;
}
/* Call from the audio thread only. */
Optional<PrepareSettings> getLastRequestedSettings() const { return next; }
std::optional<PrepareSettings> getLastRequestedSettings() const { return next; }
/* Call from the main thread only!
@ -375,7 +375,7 @@ public:
Returns the settings that were applied to the nodes.
*/
Optional<PrepareSettings> applySettings (const Nodes& n)
std::optional<PrepareSettings> applySettings (const Nodes& n)
{
const auto settingsChanged = [this]
{
@ -411,7 +411,7 @@ public:
preparedNodes.clear();
}
if (current.hasValue())
if (current.has_value())
{
for (const auto& node : n.getNodes())
{
@ -433,7 +433,7 @@ public:
private:
std::mutex mutex;
std::set<NodeID> preparedNodes;
Optional<PrepareSettings> current, next;
std::optional<PrepareSettings> current, next;
};
//==============================================================================
@ -1447,6 +1447,40 @@ private:
int latencySamples = 0;
};
//==============================================================================
/** Holds information about a particular graph configuration, without sharing ownership of any
graph nodes. Can be checked for equality with other RenderSequenceSignature instances to see
whether two graph configurations match.
*/
class RenderSequenceSignature
{
auto tie() const { return std::tie (settings, connections, nodes); }
public:
RenderSequenceSignature (const PrepareSettings s, const Nodes& n, const Connections& c)
: settings (s), connections (c), nodes (getNodeIDs (n)) {}
bool operator== (const RenderSequenceSignature& other) const { return tie() == other.tie(); }
bool operator!= (const RenderSequenceSignature& other) const { return tie() != other.tie(); }
private:
static std::vector<AudioProcessorGraph::NodeID> getNodeIDs (const Nodes& n)
{
const auto& nodeRefs = n.getNodes();
std::vector<AudioProcessorGraph::NodeID> result;
result.reserve ((size_t) nodeRefs.size());
for (const auto& node : nodeRefs)
result.push_back (node->nodeID);
return result;
}
PrepareSettings settings;
Connections connections;
std::vector<AudioProcessorGraph::NodeID> nodes;
};
//==============================================================================
/* Facilitates wait-free render-sequence updates.
@ -1687,6 +1721,14 @@ public:
topologyChanged (UpdateKind::sync);
}
void rebuild()
{
if (MessageManager::getInstance()->isThisTheMessageThread())
handleAsyncUpdate();
else
triggerAsyncUpdate();
}
void reset()
{
for (auto* n : getNodes())
@ -1757,22 +1799,30 @@ private:
for (const auto node : nodes.getNodes())
setParentGraph (node->getProcessor());
auto sequence = std::make_unique<RenderSequence> (*newSettings, nodes, connections);
owner->setLatencySamples (sequence->getLatencySamples());
renderSequenceExchange.set (std::move (sequence));
const RenderSequenceSignature newSignature (*newSettings, nodes, connections);
if (std::exchange (lastBuiltSequence, newSignature) != newSignature)
{
auto sequence = std::make_unique<RenderSequence> (*newSettings, nodes, connections);
owner->setLatencySamples (sequence->getLatencySamples());
renderSequenceExchange.set (std::move (sequence));
}
}
else
{
lastBuiltSequence.reset();
renderSequenceExchange.set (nullptr);
}
}
AudioProcessorGraph* owner = nullptr;
Nodes nodes;
Connections connections;
NodeStates nodeStates;
RenderSequenceExchange renderSequenceExchange;
NodeID lastNodeID;
std::optional<RenderSequenceSignature> lastBuiltSequence;
};
//==============================================================================
@ -1799,6 +1849,7 @@ AudioProcessorGraph::Node* AudioProcessorGraph::getNodeForId (NodeID x) const
bool AudioProcessorGraph::disconnectNode (NodeID nodeID, UpdateKind updateKind) { return pimpl->disconnectNode (nodeID, updateKind); }
void AudioProcessorGraph::releaseResources() { return pimpl->releaseResources(); }
bool AudioProcessorGraph::removeIllegalConnections (UpdateKind updateKind) { return pimpl->removeIllegalConnections (updateKind); }
void AudioProcessorGraph::rebuild() { return pimpl->rebuild(); }
void AudioProcessorGraph::reset() { return pimpl->reset(); }
bool AudioProcessorGraph::canConnect (const Connection& c) const { return pimpl->canConnect (c); }
bool AudioProcessorGraph::isConnected (const Connection& c) const noexcept { return pimpl->isConnected (c); }

View file

@ -210,8 +210,11 @@ public:
*/
enum class UpdateKind
{
sync, ///< Indicates that the graph should be rebuilt immediately after modification.
async ///< Indicates that the graph rebuild should be deferred.
sync, ///< Graph should be rebuilt immediately after modification.
async, ///< Graph rebuild should be delayed. If you make several changes to the graph
///< inside the same call stack, these changes will be applied in one go.
none ///< Graph should not be rebuilt automatically. Use rebuild() to trigger a graph
///< rebuild.
};
//==============================================================================
@ -312,6 +315,14 @@ public:
*/
bool removeIllegalConnections (UpdateKind = UpdateKind::sync);
/** Rebuilds the graph if necessary.
This function will only ever rebuild the graph on the main thread. If this function is
called from another thread, the rebuild request will be dispatched asynchronously to the
main thread.
*/
void rebuild();
//==============================================================================
/** A special type of AudioProcessor that can live inside an AudioProcessorGraph
in order to use the audio that comes into and out of the graph itself.