28 : ownedNodes (std::move (inputs))
30 for (
auto& ownedNode : ownedNodes)
31 nodes.push_back (ownedNode.get());
33 assert (
std::find (nodes.begin(), nodes.end(),
nullptr) == nodes.end());
37 : nodes (std::move (inputs))
39 assert (
std::find (nodes.begin(), nodes.end(),
nullptr) == nodes.end());
46 nodes.insert (nodes.begin(), referencedInputs.
begin(), referencedInputs.
end());
47 assert (
std::find (nodes.begin(), nodes.end(),
nullptr) == nodes.end());
54 assert (newInput !=
nullptr);
55 nodes.push_back (newInput.
get());
56 ownedNodes.push_back (std::move (newInput));
65 useDoublePrecision = shouldSumInDoublePrecision;
71 if (cachedNodeProperties)
72 return *cachedNodeProperties;
75 props.hasAudio =
false;
76 props.hasMidi =
false;
77 props.numberOfChannels = 0;
80 for (
auto& node : nodes)
82 auto nodeProps = node->getNodeProperties();
83 props.hasAudio = props.hasAudio || nodeProps.hasAudio;
84 props.hasMidi = props.hasMidi || nodeProps.hasMidi;
85 props.numberOfChannels =
std::max (props.numberOfChannels, nodeProps.numberOfChannels);
86 props.latencyNumSamples =
std::max (props.latencyNumSamples, nodeProps.latencyNumSamples);
87 hash_combine (props.nodeID, nodeProps.nodeID);
90 cachedNodeProperties = props;
102 const bool hasFlattened = flattenSummingNodes();
103 const bool hasCreatedLatency = createLatencyNodes();
106 return TransformResult::nodesDeleted;
108 if (hasCreatedLatency)
109 return TransformResult::connectionsMade;
111 return TransformResult::none;
116 useDoublePrecision = useDoublePrecision && nodes.size() > 1;
118 if (useDoublePrecision)
119 tempDoubleBuffer.resize ({ (choc::buffer::ChannelCount)
getNodeProperties().numberOfChannels,
120 (choc::buffer::FrameCount) info.blockSize });
127 for (
auto& node : nodes)
128 if (! node->hasProcessed())
136 if (useDoublePrecision)
137 processDoublePrecision (pc);
139 processSinglePrecision (pc);
148 bool isPrepared =
false;
150 bool useDoublePrecision =
false;
151 choc::buffer::ChannelArrayBuffer<double> tempDoubleBuffer;
157 auto t1 = a.getTimeStamp();
158 auto t2 = b.getTimeStamp();
162 if (a.isNoteOff() && b.isNoteOn()) return true;
163 if (a.isNoteOn() && b.isNoteOff()) return false;
172 const auto numChannels = pc.buffers.audio.getNumChannels();
174 int nodesWithMidi = pc.buffers.midi.isEmpty() ? 0 : 1;
177 for (
auto& node : nodes)
179 auto inputFromNode = node->getProcessedOutput();
181 if (
auto numChannelsToAdd =
std::min (inputFromNode.audio.getNumChannels(), numChannels))
182 add (pc.buffers.audio.getFirstChannels (numChannelsToAdd),
183 inputFromNode.audio.getFirstChannels (numChannelsToAdd));
185 if (inputFromNode.midi.isNotEmpty())
188 pc.buffers.midi.mergeFrom (inputFromNode.midi);
191 if (nodesWithMidi > 1)
192 sortByTimestampUnstable (pc.buffers.midi);
197 const auto numChannels = pc.buffers.audio.getNumChannels();
198 auto doubleView = tempDoubleBuffer.getView().getStart (pc.buffers.audio.getNumFrames());
201 int nodesWithMidi = pc.buffers.midi.isEmpty() ? 0 : 1;
204 for (
auto& node : nodes)
206 auto inputFromNode = node->getProcessedOutput();
208 if (
auto numChannelsToAdd =
std::min (inputFromNode.audio.getNumChannels(), numChannels))
209 add (doubleView.getFirstChannels (numChannelsToAdd),
210 inputFromNode.audio.getFirstChannels (numChannelsToAdd));
212 if (inputFromNode.midi.isNotEmpty())
215 pc.buffers.midi.mergeFrom (inputFromNode.midi);
218 assert (doubleView.getNumChannels() == (choc::buffer::ChannelCount) numChannels);
220 if (numChannels != 0)
221 add (pc.buffers.audio.getFirstChannels (numChannels), doubleView);
223 if (nodesWithMidi > 1)
224 sortByTimestampUnstable (pc.buffers.midi);
228 bool flattenSummingNodes()
230 bool hasChanged =
false;
235 for (
auto& n : ownedNodes)
237 if (
auto summingNode =
dynamic_cast<SummingNode*
> (n.get()))
239 for (
auto& ownedNodeToAdd : summingNode->ownedNodes)
240 ownedNodesToAdd.push_back (
std::
move (ownedNodeToAdd));
242 for (
auto& nodeToAdd : summingNode->nodes)
243 nodesToAdd.push_back (
std::
move (nodeToAdd));
250 for (
auto& n : ownedNodesToAdd)
251 ownedNodes.push_back (
std::
move (n));
253 for (
auto& n : nodesToAdd)
254 nodes.push_back (
std::
move (n));
256 ownedNodes.erase (
std::remove_if (ownedNodes.begin(), ownedNodes.end(),
257 [&] (
auto& n) { return std::find (nodesToErase.begin(), nodesToErase.end(), n.get()) != nodesToErase.end(); }),
261 [&] (
auto& n) { return std::find (nodesToErase.begin(), nodesToErase.end(), n) != nodesToErase.end(); }),
267 bool createLatencyNodes()
269 bool topologyChanged =
false;
270 const int maxLatency = getNodeProperties().latencyNumSamples;
273 for (
auto& node : nodes)
275 auto props = node->getNodeProperties();
276 const int nodeLatency = props.latencyNumSamples;
277 const int latencyToAdd =
subtractNoWrap (maxLatency, nodeLatency);
279 if (latencyToAdd <= 0)
282 auto getOwnedNode = [
this] (
auto nodeToFind)
284 for (
auto& ownedN : ownedNodes)
286 if (ownedN.get() == nodeToFind)
288 auto nodeToReturn = std::move (ownedN);
297 auto ownedNode = getOwnedNode (node);
298 auto latencyNode = ownedNode !=
nullptr ? makeNode<LatencyNode> (std::move (ownedNode), latencyToAdd)
299 :
makeNode<LatencyNode> (node, latencyToAdd);
300 ownedNodesToAdd.
push_back (std::move (latencyNode));
302 topologyChanged =
true;
307 for (
auto& newNode : ownedNodesToAdd)
309 nodes.push_back (newNode.get());
310 ownedNodes.push_back (std::move (newNode));
314 [] (
auto& n) { return n == nullptr; }),
317 ownedNodes.erase (
std::remove_if (ownedNodes.begin(), ownedNodes.end(),
318 [] (
auto& n) { return n == nullptr; }),
321 return topologyChanged;
Struct to describe a single iteration of a process call.