tracktion-engine 3.0-10-g034fdde4aa5
Tracktion Engine — High level data model for audio applications

« « « Anklang Documentation
Loading...
Searching...
No Matches
tracktion_NodePlayerUtilities.h
Go to the documentation of this file.
1 /*
2 ,--. ,--. ,--. ,--.
3 ,-' '-.,--.--.,--,--.,---.| |,-.,-' '-.`--' ,---. ,--,--, Copyright 2024
4 '-. .-'| .--' ,-. | .--'| /'-. .-',--.| .-. || \ Tracktion Software
5 | | | | \ '-' \ `--.| \ \ | | | |' '-' '| || | Corporation
6 `---' `--' `--`--'`---'`--'`--' `---' `--' `---' `--''--' www.tracktion.com
7
8 Tracktion Engine uses a GPL/commercial licence - see LICENCE.md for details.
9*/
10
11#pragma once
12
13
14namespace tracktion { inline namespace graph
15{
16
17namespace node_player_utils
18{
20 static inline bool areNodeIDsUnique (Node& node, bool ignoreZeroIDs)
21 {
22 std::vector<size_t> nodeIDs;
23 visitNodes (node, [&] (Node& n) { nodeIDs.push_back (n.getNodeProperties().nodeID); }, false);
24 std::sort (nodeIDs.begin(), nodeIDs.end());
25
26 if (ignoreZeroIDs)
27 nodeIDs.erase (std::remove_if (nodeIDs.begin(), nodeIDs.end(),
28 [] (auto nID) { return nID == 0; }),
29 nodeIDs.end());
30
31 auto uniqueEnd = std::unique (nodeIDs.begin(), nodeIDs.end());
32 return uniqueEnd == nodeIDs.end();
33 }
34
36 static inline bool areThereAnyCycles (const std::vector<Node*>& orderedNodes)
37 {
38 size_t numCycles = 0;
39
40 // Iterate from the first node to the last
41 // Find each input of the Node
42 // Ensure that the input is in a lower position than the current
43 for (auto iter = orderedNodes.begin(); iter != orderedNodes.end(); ++iter)
44 {
45 auto node = *iter;
46 auto position = std::distance (orderedNodes.begin(), iter);
47
48 for (auto inputNode : node->getDirectInputNodes())
49 {
50 const auto inputPosition = std::distance (orderedNodes.begin(),
51 std::find (orderedNodes.begin(), orderedNodes.end(), inputNode));
52
53 if (inputPosition > position)
54 ++numCycles;
55 }
56 }
57
58 return numCycles > 0;
59 }
60
62 static std::unique_ptr<NodeGraph> prepareToPlay (std::unique_ptr<Node> node, NodeGraph* oldGraph,
63 double sampleRate, int blockSize,
64 std::function<NodeBuffer (choc::buffer::Size)> allocateAudioBuffer = nullptr,
65 std::function<void (NodeBuffer&&)> deallocateAudioBuffer = nullptr,
66 bool nodeMemorySharingEnabled = false)
67 {
68 if (node == nullptr)
69 return {};
70
71 // First give the Nodes a chance to transform
72 auto nodeGraph = createNodeGraph (std::move (node));
73 assert (! areThereAnyCycles (nodeGraph->orderedNodes));
74
75 // Next, initialise all the nodes, this will call prepareToPlay on them
76 const PlaybackInitialisationInfo info { sampleRate, blockSize,
77 *nodeGraph, oldGraph,
78 allocateAudioBuffer, deallocateAudioBuffer,
79 nodeMemorySharingEnabled };
80
81 for (auto n : nodeGraph->orderedNodes)
82 n->initialise (info);
83
84 return nodeGraph;
85 }
86
87 inline void reserveAudioBufferPool (Node* rootNode, const std::vector<Node*>& allNodes,
88 AudioBufferPool& audioBufferPool, size_t numThreads, int blockSize)
89 {
90 if (rootNode == nullptr)
91 return;
92
93 // To find the number of buffers required:
94 // - Find the maximum buffer::Size in the graph
95 // - Multiply it by the maximum number of inputs any Node has
96 // - Then multiply that by the number of threads that will be used (or the num leaf Nodes if that’s smaller)
97 // - Add one for the root node so the ouput can be retained
98 [[ maybe_unused ]] size_t maxNumChannels = 0, maxNumInputs = 0, numLeafNodes = 0;
99
100 // However, this algorithm is too pessimistic as it assumes there can be
101 // numThreads * maxNumInputs which is unlikely to be true.
102 // It's probably better to stack up numThreads maxNumInputs and use the min of that size and numThreads
103
104 for (auto n : allNodes)
105 {
106 const auto numInputs = n->getDirectInputNodes().size();
107 const auto props = n->getNodeProperties();
108 maxNumInputs = std::max (maxNumInputs, numInputs);
109 maxNumChannels = std::max (maxNumChannels, (size_t) props.numberOfChannels);
110
111 if (numInputs == 0)
112 ++numLeafNodes;
113 }
114
115 const size_t numBuffersRequired = std::max ((size_t) 2, std::min (allNodes.size(), 1 + numThreads));
116 audioBufferPool.reserve (numBuffersRequired, choc::buffer::Size::create (maxNumChannels, blockSize));
117 }
118}
119
120}}
assert
T begin(T... args)
T distance(T... args)
T end(T... args)
T erase(T... args)
T find(T... args)
T max(T... args)
T min(T... args)
void visitNodes(Node &, Visitor &&, bool preordering)
Should call the visitor for any direct inputs to the node exactly once.
std::unique_ptr< NodeGraph > createNodeGraph(std::unique_ptr< Node >)
Transforms a Node and then returns a NodeGraph of it ready to be initialised.
T push_back(T... args)
T remove_if(T... args)
T size(T... args)
T sort(T... args)
T unique(T... args)