Add initial bits for Qt6 support
[carla.git] / source / modules / water / processors / AudioProcessorGraph.cpp
blobe82d0a92d7fa9e5a258bcd75dc22e56280f2015d
1 /*
2 ==============================================================================
4 This file is part of the Water library.
5 Copyright (c) 2015 ROLI Ltd.
6 Copyright (C) 2017-2022 Filipe Coelho <falktx@falktx.com>
8 Permission is granted to use this software under the terms of the GNU
9 General Public License as published by the Free Software Foundation;
10 either version 2 of the License, or any later version.
12 This program is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 For a full copy of the GNU General Public License see the doc/GPL.txt file.
18 ==============================================================================
21 #include "AudioProcessorGraph.h"
22 #include "../containers/SortedSet.h"
24 namespace water {
26 //==============================================================================
27 namespace GraphRenderingOps
30 struct AudioGraphRenderingOpBase
32 AudioGraphRenderingOpBase() noexcept {}
33 virtual ~AudioGraphRenderingOpBase() {}
35 virtual void perform (AudioSampleBuffer& sharedAudioBufferChans,
36 AudioSampleBuffer& sharedCVBufferChans,
37 const OwnedArray<MidiBuffer>& sharedMidiBuffers,
38 const int numSamples) = 0;
41 // use CRTP
42 template <class Child>
43 struct AudioGraphRenderingOp : public AudioGraphRenderingOpBase
45 void perform (AudioSampleBuffer& sharedAudioBufferChans,
46 AudioSampleBuffer& sharedCVBufferChans,
47 const OwnedArray<MidiBuffer>& sharedMidiBuffers,
48 const int numSamples) override
50 static_cast<Child*> (this)->perform (sharedAudioBufferChans,
51 sharedCVBufferChans,
52 sharedMidiBuffers,
53 numSamples);
57 //==============================================================================
58 struct ClearChannelOp : public AudioGraphRenderingOp<ClearChannelOp>
60 ClearChannelOp (const int channel, const bool cv) noexcept
61 : channelNum (channel), isCV (cv) {}
63 void perform (AudioSampleBuffer& sharedAudioBufferChans,
64 AudioSampleBuffer& sharedCVBufferChans,
65 const OwnedArray<MidiBuffer>&,
66 const int numSamples)
68 if (isCV)
69 sharedCVBufferChans.clear (channelNum, 0, numSamples);
70 else
71 sharedAudioBufferChans.clear (channelNum, 0, numSamples);
74 const int channelNum;
75 const bool isCV;
77 CARLA_DECLARE_NON_COPYABLE (ClearChannelOp)
80 //==============================================================================
81 struct CopyChannelOp : public AudioGraphRenderingOp<CopyChannelOp>
83 CopyChannelOp (const int srcChan, const int dstChan, const bool cv) noexcept
84 : srcChannelNum (srcChan), dstChannelNum (dstChan), isCV (cv) {}
86 void perform (AudioSampleBuffer& sharedAudioBufferChans,
87 AudioSampleBuffer& sharedCVBufferChans,
88 const OwnedArray<MidiBuffer>&,
89 const int numSamples)
91 if (isCV)
92 sharedCVBufferChans.copyFrom (dstChannelNum, 0, sharedCVBufferChans, srcChannelNum, 0, numSamples);
93 else
94 sharedAudioBufferChans.copyFrom (dstChannelNum, 0, sharedAudioBufferChans, srcChannelNum, 0, numSamples);
97 const int srcChannelNum, dstChannelNum;
98 const bool isCV;
100 CARLA_DECLARE_NON_COPYABLE (CopyChannelOp)
103 //==============================================================================
104 struct AddChannelOp : public AudioGraphRenderingOp<AddChannelOp>
106 AddChannelOp (const int srcChan, const int dstChan, const bool cv) noexcept
107 : srcChannelNum (srcChan), dstChannelNum (dstChan), isCV (cv) {}
109 void perform (AudioSampleBuffer& sharedAudioBufferChans,
110 AudioSampleBuffer& sharedCVBufferChans,
111 const OwnedArray<MidiBuffer>&,
112 const int numSamples)
114 if (isCV)
115 sharedCVBufferChans.addFrom (dstChannelNum, 0, sharedCVBufferChans, srcChannelNum, 0, numSamples);
116 else
117 sharedAudioBufferChans.addFrom (dstChannelNum, 0, sharedAudioBufferChans, srcChannelNum, 0, numSamples);
120 const int srcChannelNum, dstChannelNum;
121 const bool isCV;
123 CARLA_DECLARE_NON_COPYABLE (AddChannelOp)
126 //==============================================================================
127 struct ClearMidiBufferOp : public AudioGraphRenderingOp<ClearMidiBufferOp>
129 ClearMidiBufferOp (const int buffer) noexcept : bufferNum (buffer) {}
131 void perform (AudioSampleBuffer&, AudioSampleBuffer&,
132 const OwnedArray<MidiBuffer>& sharedMidiBuffers,
133 const int)
135 sharedMidiBuffers.getUnchecked (bufferNum)->clear();
138 const int bufferNum;
140 CARLA_DECLARE_NON_COPYABLE (ClearMidiBufferOp)
143 //==============================================================================
144 struct CopyMidiBufferOp : public AudioGraphRenderingOp<CopyMidiBufferOp>
146 CopyMidiBufferOp (const int srcBuffer, const int dstBuffer) noexcept
147 : srcBufferNum (srcBuffer), dstBufferNum (dstBuffer)
150 void perform (AudioSampleBuffer&, AudioSampleBuffer&,
151 const OwnedArray<MidiBuffer>& sharedMidiBuffers,
152 const int)
154 *sharedMidiBuffers.getUnchecked (dstBufferNum) = *sharedMidiBuffers.getUnchecked (srcBufferNum);
157 const int srcBufferNum, dstBufferNum;
159 CARLA_DECLARE_NON_COPYABLE (CopyMidiBufferOp)
162 //==============================================================================
163 struct AddMidiBufferOp : public AudioGraphRenderingOp<AddMidiBufferOp>
165 AddMidiBufferOp (const int srcBuffer, const int dstBuffer)
166 : srcBufferNum (srcBuffer), dstBufferNum (dstBuffer)
169 void perform (AudioSampleBuffer&, AudioSampleBuffer&,
170 const OwnedArray<MidiBuffer>& sharedMidiBuffers,
171 const int numSamples)
173 sharedMidiBuffers.getUnchecked (dstBufferNum)
174 ->addEvents (*sharedMidiBuffers.getUnchecked (srcBufferNum), 0, numSamples, 0);
177 const int srcBufferNum, dstBufferNum;
179 CARLA_DECLARE_NON_COPYABLE (AddMidiBufferOp)
182 //==============================================================================
183 struct DelayChannelOp : public AudioGraphRenderingOp<DelayChannelOp>
185 DelayChannelOp (const int chan, const int delaySize, const bool cv)
186 : channel (chan),
187 bufferSize (delaySize + 1),
188 readIndex (0), writeIndex (delaySize),
189 isCV (cv)
191 buffer.calloc ((size_t) bufferSize);
194 void perform (AudioSampleBuffer& sharedAudioBufferChans,
195 AudioSampleBuffer& sharedCVBufferChans,
196 const OwnedArray<MidiBuffer>&,
197 const int numSamples)
199 float* data = isCV
200 ? sharedCVBufferChans.getWritePointer (channel, 0)
201 : sharedAudioBufferChans.getWritePointer (channel, 0);
202 HeapBlock<float>& block = buffer;
204 for (int i = numSamples; --i >= 0;)
206 block [writeIndex] = *data;
207 *data++ = block [readIndex];
209 if (++readIndex >= bufferSize) readIndex = 0;
210 if (++writeIndex >= bufferSize) writeIndex = 0;
214 private:
215 HeapBlock<float> buffer;
216 const int channel, bufferSize;
217 int readIndex, writeIndex;
218 const bool isCV;
220 CARLA_DECLARE_NON_COPYABLE (DelayChannelOp)
223 //==============================================================================
224 struct ProcessBufferOp : public AudioGraphRenderingOp<ProcessBufferOp>
226 ProcessBufferOp (const AudioProcessorGraph::Node::Ptr& n,
227 const Array<uint>& audioChannelsUsed,
228 const uint totalNumChans,
229 const Array<uint>& cvInChannelsUsed,
230 const Array<uint>& cvOutChannelsUsed,
231 const int midiBuffer)
232 : node (n),
233 processor (n->getProcessor()),
234 audioChannelsToUse (audioChannelsUsed),
235 cvInChannelsToUse (cvInChannelsUsed),
236 cvOutChannelsToUse (cvOutChannelsUsed),
237 totalAudioChans (jmax (1U, totalNumChans)),
238 totalCVIns (cvInChannelsUsed.size()),
239 totalCVOuts (cvOutChannelsUsed.size()),
240 midiBufferToUse (midiBuffer)
242 audioChannels.calloc (totalAudioChans);
243 cvInChannels.calloc (totalCVIns);
244 cvOutChannels.calloc (totalCVOuts);
246 while (audioChannelsToUse.size() < static_cast<int>(totalAudioChans))
247 audioChannelsToUse.add (0);
250 void perform (AudioSampleBuffer& sharedAudioBufferChans,
251 AudioSampleBuffer& sharedCVBufferChans,
252 const OwnedArray<MidiBuffer>& sharedMidiBuffers,
253 const int numSamples)
255 HeapBlock<float*>& audioChannelsCopy = audioChannels;
256 HeapBlock<float*>& cvInChannelsCopy = cvInChannels;
257 HeapBlock<float*>& cvOutChannelsCopy = cvOutChannels;
259 for (uint i = 0; i < totalAudioChans; ++i)
260 audioChannelsCopy[i] = sharedAudioBufferChans.getWritePointer (audioChannelsToUse.getUnchecked (i), 0);
262 for (uint i = 0; i < totalCVIns; ++i)
263 cvInChannels[i] = sharedCVBufferChans.getWritePointer (cvInChannelsToUse.getUnchecked (i), 0);
265 for (uint i = 0; i < totalCVOuts; ++i)
266 cvOutChannels[i] = sharedCVBufferChans.getWritePointer (cvOutChannelsToUse.getUnchecked (i), 0);
268 AudioSampleBuffer audioBuffer (audioChannelsCopy, totalAudioChans, numSamples);
269 AudioSampleBuffer cvInBuffer (cvInChannelsCopy, totalCVIns, numSamples);
270 AudioSampleBuffer cvOutBuffer (cvOutChannelsCopy, totalCVOuts, numSamples);
272 if (processor->isSuspended())
274 audioBuffer.clear();
275 cvOutBuffer.clear();
277 else
279 const CarlaRecursiveMutexLocker cml (processor->getCallbackLock());
281 callProcess (audioBuffer, cvInBuffer, cvOutBuffer, *sharedMidiBuffers.getUnchecked (midiBufferToUse));
285 void callProcess (AudioSampleBuffer& audioBuffer,
286 AudioSampleBuffer& cvInBuffer,
287 AudioSampleBuffer& cvOutBuffer,
288 MidiBuffer& midiMessages)
290 processor->processBlockWithCV (audioBuffer, cvInBuffer, cvOutBuffer, midiMessages);
293 const AudioProcessorGraph::Node::Ptr node;
294 AudioProcessor* const processor;
296 private:
297 Array<uint> audioChannelsToUse;
298 Array<uint> cvInChannelsToUse;
299 Array<uint> cvOutChannelsToUse;
300 HeapBlock<float*> audioChannels;
301 HeapBlock<float*> cvInChannels;
302 HeapBlock<float*> cvOutChannels;
303 AudioSampleBuffer tempBuffer;
304 const uint totalAudioChans;
305 const uint totalCVIns;
306 const uint totalCVOuts;
307 const int midiBufferToUse;
309 CARLA_DECLARE_NON_COPYABLE (ProcessBufferOp)
312 //==============================================================================
313 /** Used to calculate the correct sequence of rendering ops needed, based on
314 the best re-use of shared buffers at each stage.
316 struct RenderingOpSequenceCalculator
318 RenderingOpSequenceCalculator (AudioProcessorGraph& g,
319 const Array<AudioProcessorGraph::Node*>& nodes,
320 Array<void*>& renderingOps)
321 : graph (g),
322 orderedNodes (nodes),
323 totalLatency (0)
325 audioNodeIds.add ((uint32) zeroNodeID); // first buffer is read-only zeros
326 audioChannels.add (0);
328 cvNodeIds.add ((uint32) zeroNodeID);
329 cvChannels.add (0);
331 midiNodeIds.add ((uint32) zeroNodeID);
333 for (int i = 0; i < orderedNodes.size(); ++i)
335 createRenderingOpsForNode (*orderedNodes.getUnchecked(i), renderingOps, i);
336 markAnyUnusedBuffersAsFree (i);
339 graph.setLatencySamples (totalLatency);
342 int getNumAudioBuffersNeeded() const noexcept { return audioNodeIds.size(); }
343 int getNumCVBuffersNeeded() const noexcept { return cvNodeIds.size(); }
344 int getNumMidiBuffersNeeded() const noexcept { return midiNodeIds.size(); }
346 private:
347 //==============================================================================
348 AudioProcessorGraph& graph;
349 const Array<AudioProcessorGraph::Node*>& orderedNodes;
350 Array<uint> audioChannels, cvChannels;
351 Array<uint32> audioNodeIds, cvNodeIds, midiNodeIds;
353 enum { freeNodeID = 0xffffffff, zeroNodeID = 0xfffffffe, anonymousNodeID = 0xfffffffd };
355 static bool isNodeBusy (uint32 nodeID) noexcept { return nodeID != freeNodeID; }
357 Array<uint32> nodeDelayIDs;
358 Array<int> nodeDelays;
359 int totalLatency;
361 int getNodeDelay (const uint32 nodeID) const { return nodeDelays [nodeDelayIDs.indexOf (nodeID)]; }
363 void setNodeDelay (const uint32 nodeID, const int latency)
365 const int index = nodeDelayIDs.indexOf (nodeID);
367 if (index >= 0)
369 nodeDelays.set (index, latency);
371 else
373 nodeDelayIDs.add (nodeID);
374 nodeDelays.add (latency);
378 int getInputLatencyForNode (const uint32 nodeID) const
380 int maxLatency = 0;
382 for (int i = graph.getNumConnections(); --i >= 0;)
384 const AudioProcessorGraph::Connection* const c = graph.getConnection (i);
386 if (c->destNodeId == nodeID)
387 maxLatency = jmax (maxLatency, getNodeDelay (c->sourceNodeId));
390 return maxLatency;
393 //==============================================================================
394 void createRenderingOpsForNode (AudioProcessorGraph::Node& node,
395 Array<void*>& renderingOps,
396 const int ourRenderingIndex)
398 AudioProcessor& processor = *node.getProcessor();
399 const uint numAudioIns = processor.getTotalNumInputChannels(AudioProcessor::ChannelTypeAudio);
400 const uint numAudioOuts = processor.getTotalNumOutputChannels(AudioProcessor::ChannelTypeAudio);
401 const uint numCVIns = processor.getTotalNumInputChannels(AudioProcessor::ChannelTypeCV);
402 const uint numCVOuts = processor.getTotalNumOutputChannels(AudioProcessor::ChannelTypeCV);
403 const uint totalAudioChans = jmax (numAudioIns, numAudioOuts);
405 Array<uint> audioChannelsToUse, cvInChannelsToUse, cvOutChannelsToUse;
406 int midiBufferToUse = -1;
408 int maxLatency = getInputLatencyForNode (node.nodeId);
410 for (uint inputChan = 0; inputChan < numAudioIns; ++inputChan)
412 // get a list of all the inputs to this node
413 Array<uint32> sourceNodes;
414 Array<uint> sourceOutputChans;
416 for (int i = graph.getNumConnections(); --i >= 0;)
418 const AudioProcessorGraph::Connection* const c = graph.getConnection (i);
420 if (c->destNodeId == node.nodeId
421 && c->destChannelIndex == inputChan
422 && c->channelType == AudioProcessor::ChannelTypeAudio)
424 sourceNodes.add (c->sourceNodeId);
425 sourceOutputChans.add (c->sourceChannelIndex);
429 int bufIndex = -1;
431 if (sourceNodes.size() == 0)
433 // unconnected input channel
434 bufIndex = getFreeBuffer (AudioProcessor::ChannelTypeAudio);
435 renderingOps.add (new ClearChannelOp (bufIndex, false));
437 else if (sourceNodes.size() == 1)
439 // channel with a straightforward single input..
440 const uint32 srcNode = sourceNodes.getUnchecked(0);
441 const uint srcChan = sourceOutputChans.getUnchecked(0);
443 bufIndex = getBufferContaining (AudioProcessor::ChannelTypeAudio, srcNode, srcChan);
445 if (bufIndex < 0)
447 // if not found, this is probably a feedback loop
448 bufIndex = getReadOnlyEmptyBuffer();
449 wassert (bufIndex >= 0);
452 if (inputChan < numAudioOuts
453 && isBufferNeededLater (AudioProcessor::ChannelTypeAudio,
454 ourRenderingIndex,
455 inputChan,
456 srcNode, srcChan))
458 // can't mess up this channel because it's needed later by another node, so we
459 // need to use a copy of it..
460 const int newFreeBuffer = getFreeBuffer (AudioProcessor::ChannelTypeAudio);
462 renderingOps.add (new CopyChannelOp (bufIndex, newFreeBuffer, false));
464 bufIndex = newFreeBuffer;
467 const int nodeDelay = getNodeDelay (srcNode);
469 if (nodeDelay < maxLatency)
470 renderingOps.add (new DelayChannelOp (bufIndex, maxLatency - nodeDelay, false));
472 else
474 // channel with a mix of several inputs..
476 // try to find a re-usable channel from our inputs..
477 int reusableInputIndex = -1;
479 for (int i = 0; i < sourceNodes.size(); ++i)
481 const int sourceBufIndex = getBufferContaining (AudioProcessor::ChannelTypeAudio,
482 sourceNodes.getUnchecked(i),
483 sourceOutputChans.getUnchecked(i));
485 if (sourceBufIndex >= 0
486 && ! isBufferNeededLater (AudioProcessor::ChannelTypeAudio,
487 ourRenderingIndex,
488 inputChan,
489 sourceNodes.getUnchecked(i),
490 sourceOutputChans.getUnchecked(i)))
492 // we've found one of our input chans that can be re-used..
493 reusableInputIndex = i;
494 bufIndex = sourceBufIndex;
496 const int nodeDelay = getNodeDelay (sourceNodes.getUnchecked (i));
497 if (nodeDelay < maxLatency)
498 renderingOps.add (new DelayChannelOp (sourceBufIndex, maxLatency - nodeDelay, false));
500 break;
504 if (reusableInputIndex < 0)
506 // can't re-use any of our input chans, so get a new one and copy everything into it..
507 bufIndex = getFreeBuffer (AudioProcessor::ChannelTypeAudio);
508 wassert (bufIndex != 0);
510 markBufferAsContaining (AudioProcessor::ChannelTypeAudio,
511 bufIndex, static_cast<uint32> (anonymousNodeID), 0);
513 const int srcIndex = getBufferContaining (AudioProcessor::ChannelTypeAudio,
514 sourceNodes.getUnchecked (0),
515 sourceOutputChans.getUnchecked (0));
516 if (srcIndex < 0)
518 // if not found, this is probably a feedback loop
519 renderingOps.add (new ClearChannelOp (bufIndex, false));
521 else
523 renderingOps.add (new CopyChannelOp (srcIndex, bufIndex, false));
526 reusableInputIndex = 0;
527 const int nodeDelay = getNodeDelay (sourceNodes.getFirst());
529 if (nodeDelay < maxLatency)
530 renderingOps.add (new DelayChannelOp (bufIndex, maxLatency - nodeDelay, false));
533 for (int j = 0; j < sourceNodes.size(); ++j)
535 if (j != reusableInputIndex)
537 int srcIndex = getBufferContaining (AudioProcessor::ChannelTypeAudio,
538 sourceNodes.getUnchecked(j),
539 sourceOutputChans.getUnchecked(j));
540 if (srcIndex >= 0)
542 const int nodeDelay = getNodeDelay (sourceNodes.getUnchecked (j));
544 if (nodeDelay < maxLatency)
546 if (! isBufferNeededLater (AudioProcessor::ChannelTypeAudio,
547 ourRenderingIndex, inputChan,
548 sourceNodes.getUnchecked(j),
549 sourceOutputChans.getUnchecked(j)))
551 renderingOps.add (new DelayChannelOp (srcIndex, maxLatency - nodeDelay, false));
553 else // buffer is reused elsewhere, can't be delayed
555 const int bufferToDelay = getFreeBuffer (AudioProcessor::ChannelTypeAudio);
556 renderingOps.add (new CopyChannelOp (srcIndex, bufferToDelay, false));
557 renderingOps.add (new DelayChannelOp (bufferToDelay, maxLatency - nodeDelay, false));
558 srcIndex = bufferToDelay;
562 renderingOps.add (new AddChannelOp (srcIndex, bufIndex, false));
568 CARLA_SAFE_ASSERT_CONTINUE (bufIndex >= 0);
569 audioChannelsToUse.add (bufIndex);
571 if (inputChan < numAudioOuts)
572 markBufferAsContaining (AudioProcessor::ChannelTypeAudio, bufIndex, node.nodeId, inputChan);
575 for (uint outputChan = numAudioIns; outputChan < numAudioOuts; ++outputChan)
577 const int bufIndex = getFreeBuffer (AudioProcessor::ChannelTypeAudio);
578 CARLA_SAFE_ASSERT_CONTINUE (bufIndex > 0);
579 audioChannelsToUse.add (bufIndex);
580 markBufferAsContaining (AudioProcessor::ChannelTypeAudio, bufIndex, node.nodeId, outputChan);
583 for (uint inputChan = 0; inputChan < numCVIns; ++inputChan)
585 // get a list of all the inputs to this node
586 Array<uint32> sourceNodes;
587 Array<uint> sourceOutputChans;
589 for (int i = graph.getNumConnections(); --i >= 0;)
591 const AudioProcessorGraph::Connection* const c = graph.getConnection (i);
593 if (c->destNodeId == node.nodeId
594 && c->destChannelIndex == inputChan
595 && c->channelType == AudioProcessor::ChannelTypeCV)
597 sourceNodes.add (c->sourceNodeId);
598 sourceOutputChans.add (c->sourceChannelIndex);
602 int bufIndex = -1;
604 if (sourceNodes.size() == 0)
606 // unconnected input channel
607 bufIndex = getFreeBuffer (AudioProcessor::ChannelTypeCV);
608 renderingOps.add (new ClearChannelOp (bufIndex, true));
610 else if (sourceNodes.size() == 1)
612 // channel with a straightforward single input..
613 const uint32 srcNode = sourceNodes.getUnchecked(0);
614 const uint srcChan = sourceOutputChans.getUnchecked(0);
616 bufIndex = getBufferContaining (AudioProcessor::ChannelTypeCV, srcNode, srcChan);
618 if (bufIndex < 0)
620 // if not found, this is probably a feedback loop
621 bufIndex = getReadOnlyEmptyBuffer();
622 wassert (bufIndex >= 0);
625 const int newFreeBuffer = getFreeBuffer (AudioProcessor::ChannelTypeCV);
627 renderingOps.add (new CopyChannelOp (bufIndex, newFreeBuffer, true));
629 bufIndex = newFreeBuffer;
631 const int nodeDelay = getNodeDelay (srcNode);
633 if (nodeDelay < maxLatency)
634 renderingOps.add (new DelayChannelOp (bufIndex, maxLatency - nodeDelay, true));
636 else
638 // channel with a mix of several inputs..
641 bufIndex = getFreeBuffer (AudioProcessor::ChannelTypeCV);
642 wassert (bufIndex != 0);
644 const int srcIndex = getBufferContaining (AudioProcessor::ChannelTypeCV,
645 sourceNodes.getUnchecked (0),
646 sourceOutputChans.getUnchecked (0));
647 if (srcIndex < 0)
649 // if not found, this is probably a feedback loop
650 renderingOps.add (new ClearChannelOp (bufIndex, true));
652 else
654 renderingOps.add (new CopyChannelOp (srcIndex, bufIndex, true));
657 const int nodeDelay = getNodeDelay (sourceNodes.getFirst());
659 if (nodeDelay < maxLatency)
660 renderingOps.add (new DelayChannelOp (bufIndex, maxLatency - nodeDelay, true));
663 for (int j = 1; j < sourceNodes.size(); ++j)
665 int srcIndex = getBufferContaining (AudioProcessor::ChannelTypeCV,
666 sourceNodes.getUnchecked(j),
667 sourceOutputChans.getUnchecked(j));
668 if (srcIndex >= 0)
670 const int nodeDelay = getNodeDelay (sourceNodes.getUnchecked (j));
672 if (nodeDelay < maxLatency)
674 const int bufferToDelay = getFreeBuffer (AudioProcessor::ChannelTypeCV);
675 renderingOps.add (new CopyChannelOp (srcIndex, bufferToDelay, true));
676 renderingOps.add (new DelayChannelOp (bufferToDelay, maxLatency - nodeDelay, true));
677 srcIndex = bufferToDelay;
680 renderingOps.add (new AddChannelOp (srcIndex, bufIndex, true));
685 CARLA_SAFE_ASSERT_CONTINUE (bufIndex >= 0);
686 cvInChannelsToUse.add (bufIndex);
687 markBufferAsContaining (AudioProcessor::ChannelTypeCV, bufIndex, node.nodeId, inputChan);
690 for (uint outputChan = 0; outputChan < numCVOuts; ++outputChan)
692 const int bufIndex = getFreeBuffer (AudioProcessor::ChannelTypeCV);
693 CARLA_SAFE_ASSERT_CONTINUE (bufIndex > 0);
694 cvOutChannelsToUse.add (bufIndex);
695 markBufferAsContaining (AudioProcessor::ChannelTypeCV, bufIndex, node.nodeId, outputChan);
698 // Now the same thing for midi..
699 Array<uint32> midiSourceNodes;
701 for (int i = graph.getNumConnections(); --i >= 0;)
703 const AudioProcessorGraph::Connection* const c = graph.getConnection (i);
705 if (c->destNodeId == node.nodeId && c->channelType == AudioProcessor::ChannelTypeMIDI)
706 midiSourceNodes.add (c->sourceNodeId);
709 if (midiSourceNodes.size() == 0)
711 // No midi inputs..
712 midiBufferToUse = getFreeBuffer (AudioProcessor::ChannelTypeMIDI); // need to pick a buffer even if the processor doesn't use midi
714 if (processor.acceptsMidi() || processor.producesMidi())
715 renderingOps.add (new ClearMidiBufferOp (midiBufferToUse));
717 else if (midiSourceNodes.size() == 1)
719 // One midi input..
720 midiBufferToUse = getBufferContaining (AudioProcessor::ChannelTypeMIDI,
721 midiSourceNodes.getUnchecked(0),
723 if (midiBufferToUse >= 0)
725 if (isBufferNeededLater (AudioProcessor::ChannelTypeMIDI,
726 ourRenderingIndex, 0,
727 midiSourceNodes.getUnchecked(0), 0))
729 // can't mess up this channel because it's needed later by another node, so we
730 // need to use a copy of it..
731 const int newFreeBuffer = getFreeBuffer (AudioProcessor::ChannelTypeMIDI);
732 renderingOps.add (new CopyMidiBufferOp (midiBufferToUse, newFreeBuffer));
733 midiBufferToUse = newFreeBuffer;
736 else
738 // probably a feedback loop, so just use an empty one..
739 midiBufferToUse = getFreeBuffer (AudioProcessor::ChannelTypeMIDI); // need to pick a buffer even if the processor doesn't use midi
742 else
744 // More than one midi input being mixed..
745 int reusableInputIndex = -1;
747 for (int i = 0; i < midiSourceNodes.size(); ++i)
749 const int sourceBufIndex = getBufferContaining (AudioProcessor::ChannelTypeMIDI,
750 midiSourceNodes.getUnchecked(i),
753 if (sourceBufIndex >= 0
754 && ! isBufferNeededLater (AudioProcessor::ChannelTypeMIDI,
755 ourRenderingIndex, 0,
756 midiSourceNodes.getUnchecked(i), 0))
758 // we've found one of our input buffers that can be re-used..
759 reusableInputIndex = i;
760 midiBufferToUse = sourceBufIndex;
761 break;
765 if (reusableInputIndex < 0)
767 // can't re-use any of our input buffers, so get a new one and copy everything into it..
768 midiBufferToUse = getFreeBuffer (AudioProcessor::ChannelTypeMIDI);
769 wassert (midiBufferToUse >= 0);
771 const int srcIndex = getBufferContaining (AudioProcessor::ChannelTypeMIDI,
772 midiSourceNodes.getUnchecked(0),
774 if (srcIndex >= 0)
775 renderingOps.add (new CopyMidiBufferOp (srcIndex, midiBufferToUse));
776 else
777 renderingOps.add (new ClearMidiBufferOp (midiBufferToUse));
779 reusableInputIndex = 0;
782 for (int j = 0; j < midiSourceNodes.size(); ++j)
784 if (j != reusableInputIndex)
786 const int srcIndex = getBufferContaining (AudioProcessor::ChannelTypeMIDI,
787 midiSourceNodes.getUnchecked(j),
789 if (srcIndex >= 0)
790 renderingOps.add (new AddMidiBufferOp (srcIndex, midiBufferToUse));
795 if (processor.producesMidi())
796 markBufferAsContaining (AudioProcessor::ChannelTypeMIDI,
797 midiBufferToUse, node.nodeId,
800 setNodeDelay (node.nodeId, maxLatency + processor.getLatencySamples());
802 if (numAudioOuts == 0)
803 totalLatency = maxLatency;
805 renderingOps.add (new ProcessBufferOp (&node,
806 audioChannelsToUse,
807 totalAudioChans,
808 cvInChannelsToUse,
809 cvOutChannelsToUse,
810 midiBufferToUse));
813 //==============================================================================
814 int getFreeBuffer (const AudioProcessor::ChannelType channelType)
816 switch (channelType)
818 case AudioProcessor::ChannelTypeAudio:
819 for (int i = 1; i < audioNodeIds.size(); ++i)
820 if (audioNodeIds.getUnchecked(i) == freeNodeID)
821 return i;
823 audioNodeIds.add ((uint32) freeNodeID);
824 audioChannels.add (0);
825 return audioNodeIds.size() - 1;
827 case AudioProcessor::ChannelTypeCV:
828 for (int i = 1; i < cvNodeIds.size(); ++i)
829 if (cvNodeIds.getUnchecked(i) == freeNodeID)
830 return i;
832 cvNodeIds.add ((uint32) freeNodeID);
833 cvChannels.add (0);
834 return cvNodeIds.size() - 1;
836 case AudioProcessor::ChannelTypeMIDI:
837 for (int i = 1; i < midiNodeIds.size(); ++i)
838 if (midiNodeIds.getUnchecked(i) == freeNodeID)
839 return i;
841 midiNodeIds.add ((uint32) freeNodeID);
842 return midiNodeIds.size() - 1;
845 return -1;
848 int getReadOnlyEmptyBuffer() const noexcept
850 return 0;
853 int getBufferContaining (const AudioProcessor::ChannelType channelType,
854 const uint32 nodeId,
855 const uint outputChannel) const noexcept
857 switch (channelType)
859 case AudioProcessor::ChannelTypeAudio:
860 for (int i = audioNodeIds.size(); --i >= 0;)
861 if (audioNodeIds.getUnchecked(i) == nodeId && audioChannels.getUnchecked(i) == outputChannel)
862 return i;
863 break;
865 case AudioProcessor::ChannelTypeCV:
866 for (int i = cvNodeIds.size(); --i >= 0;)
867 if (cvNodeIds.getUnchecked(i) == nodeId && cvChannels.getUnchecked(i) == outputChannel)
868 return i;
869 break;
871 case AudioProcessor::ChannelTypeMIDI:
872 for (int i = midiNodeIds.size(); --i >= 0;)
874 if (midiNodeIds.getUnchecked(i) == nodeId)
875 return i;
877 break;
880 return -1;
883 void markAnyUnusedBuffersAsFree (const int stepIndex)
885 for (int i = 0; i < audioNodeIds.size(); ++i)
887 if (isNodeBusy (audioNodeIds.getUnchecked(i))
888 && ! isBufferNeededLater (AudioProcessor::ChannelTypeAudio,
889 stepIndex, -1,
890 audioNodeIds.getUnchecked(i),
891 audioChannels.getUnchecked(i)))
893 audioNodeIds.set (i, (uint32) freeNodeID);
897 // NOTE: CV skipped on purpose
899 for (int i = 0; i < midiNodeIds.size(); ++i)
901 if (isNodeBusy (midiNodeIds.getUnchecked(i))
902 && ! isBufferNeededLater (AudioProcessor::ChannelTypeMIDI,
903 stepIndex, -1,
904 midiNodeIds.getUnchecked(i), 0))
906 midiNodeIds.set (i, (uint32) freeNodeID);
911 bool isBufferNeededLater (const AudioProcessor::ChannelType channelType,
912 int stepIndexToSearchFrom,
913 uint inputChannelOfIndexToIgnore,
914 const uint32 nodeId,
915 const uint outputChanIndex) const
917 while (stepIndexToSearchFrom < orderedNodes.size())
919 const AudioProcessorGraph::Node* const node = (const AudioProcessorGraph::Node*) orderedNodes.getUnchecked (stepIndexToSearchFrom);
921 for (uint i = 0; i < node->getProcessor()->getTotalNumInputChannels(channelType); ++i)
922 if (i != inputChannelOfIndexToIgnore
923 && graph.getConnectionBetween (channelType,
924 nodeId, outputChanIndex,
925 node->nodeId, i) != nullptr)
926 return true;
928 inputChannelOfIndexToIgnore = (uint)-1;
929 ++stepIndexToSearchFrom;
932 return false;
935 void markBufferAsContaining (const AudioProcessor::ChannelType channelType,
936 int bufferNum, uint32 nodeId, int outputIndex)
938 switch (channelType)
940 case AudioProcessor::ChannelTypeAudio:
941 CARLA_SAFE_ASSERT_BREAK (bufferNum >= 0 && bufferNum < audioNodeIds.size());
942 audioNodeIds.set (bufferNum, nodeId);
943 audioChannels.set (bufferNum, outputIndex);
944 break;
946 case AudioProcessor::ChannelTypeCV:
947 CARLA_SAFE_ASSERT_BREAK (bufferNum >= 0 && bufferNum < cvNodeIds.size());
948 cvNodeIds.set (bufferNum, nodeId);
949 cvChannels.set (bufferNum, outputIndex);
950 break;
952 case AudioProcessor::ChannelTypeMIDI:
953 CARLA_SAFE_ASSERT_BREAK (bufferNum > 0 && bufferNum < midiNodeIds.size());
954 midiNodeIds.set (bufferNum, nodeId);
955 break;
959 CARLA_DECLARE_NON_COPYABLE (RenderingOpSequenceCalculator)
962 //==============================================================================
963 // Holds a fast lookup table for checking which nodes are inputs to others.
964 class ConnectionLookupTable
966 public:
967 explicit ConnectionLookupTable (const OwnedArray<AudioProcessorGraph::Connection>& connections)
969 for (int i = 0; i < static_cast<int>(connections.size()); ++i)
971 const AudioProcessorGraph::Connection* const c = connections.getUnchecked(i);
973 int index;
974 Entry* entry = findEntry (c->destNodeId, index);
976 if (entry == nullptr)
978 entry = new Entry (c->destNodeId);
979 entries.insert (index, entry);
982 entry->srcNodes.add (c->sourceNodeId);
986 bool isAnInputTo (const uint32 possibleInputId,
987 const uint32 possibleDestinationId) const noexcept
989 return isAnInputToRecursive (possibleInputId, possibleDestinationId, entries.size());
992 private:
993 //==============================================================================
994 struct Entry
996 explicit Entry (const uint32 destNodeId_) noexcept : destNodeId (destNodeId_) {}
998 const uint32 destNodeId;
999 SortedSet<uint32> srcNodes;
1001 CARLA_DECLARE_NON_COPYABLE (Entry)
1004 OwnedArray<Entry> entries;
1006 bool isAnInputToRecursive (const uint32 possibleInputId,
1007 const uint32 possibleDestinationId,
1008 int recursionCheck) const noexcept
1010 int index;
1012 if (const Entry* const entry = findEntry (possibleDestinationId, index))
1014 const SortedSet<uint32>& srcNodes = entry->srcNodes;
1016 if (srcNodes.contains (possibleInputId))
1017 return true;
1019 if (--recursionCheck >= 0)
1021 for (int i = 0; i < srcNodes.size(); ++i)
1022 if (isAnInputToRecursive (possibleInputId, srcNodes.getUnchecked(i), recursionCheck))
1023 return true;
1027 return false;
1030 Entry* findEntry (const uint32 destNodeId, int& insertIndex) const noexcept
1032 Entry* result = nullptr;
1034 int start = 0;
1035 int end = entries.size();
1037 for (;;)
1039 if (start >= end)
1041 break;
1043 else if (destNodeId == entries.getUnchecked (start)->destNodeId)
1045 result = entries.getUnchecked (start);
1046 break;
1048 else
1050 const int halfway = (start + end) / 2;
1052 if (halfway == start)
1054 if (destNodeId >= entries.getUnchecked (halfway)->destNodeId)
1055 ++start;
1057 break;
1059 else if (destNodeId >= entries.getUnchecked (halfway)->destNodeId)
1060 start = halfway;
1061 else
1062 end = halfway;
1066 insertIndex = start;
1067 return result;
1070 CARLA_DECLARE_NON_COPYABLE (ConnectionLookupTable)
1073 //==============================================================================
1074 struct ConnectionSorter
1076 static int compareElements (const AudioProcessorGraph::Connection* const first,
1077 const AudioProcessorGraph::Connection* const second) noexcept
1079 if (first->sourceNodeId < second->sourceNodeId) return -1;
1080 if (first->sourceNodeId > second->sourceNodeId) return 1;
1081 if (first->destNodeId < second->destNodeId) return -1;
1082 if (first->destNodeId > second->destNodeId) return 1;
1083 if (first->sourceChannelIndex < second->sourceChannelIndex) return -1;
1084 if (first->sourceChannelIndex > second->sourceChannelIndex) return 1;
1085 if (first->destChannelIndex < second->destChannelIndex) return -1;
1086 if (first->destChannelIndex > second->destChannelIndex) return 1;
1088 return 0;
1094 //==============================================================================
1095 AudioProcessorGraph::Connection::Connection (ChannelType ct,
1096 const uint32 sourceID, const uint sourceChannel,
1097 const uint32 destID, const uint destChannel) noexcept
1098 : channelType (ct),
1099 sourceNodeId (sourceID), sourceChannelIndex (sourceChannel),
1100 destNodeId (destID), destChannelIndex (destChannel)
1104 //==============================================================================
1105 AudioProcessorGraph::Node::Node (const uint32 nodeID, AudioProcessor* const p) noexcept
1106 : nodeId (nodeID), processor (p), isPrepared (false)
1108 wassert (processor != nullptr);
1111 void AudioProcessorGraph::Node::prepare (const double newSampleRate, const int newBlockSize,
1112 AudioProcessorGraph* const graph)
1114 if (! isPrepared)
1116 setParentGraph (graph);
1118 processor->setRateAndBufferSizeDetails (newSampleRate, newBlockSize);
1119 processor->prepareToPlay (newSampleRate, newBlockSize);
1120 isPrepared = true;
1124 void AudioProcessorGraph::Node::unprepare()
1126 if (isPrepared)
1128 isPrepared = false;
1129 processor->releaseResources();
1133 void AudioProcessorGraph::Node::setParentGraph (AudioProcessorGraph* const graph) const
1135 if (AudioProcessorGraph::AudioGraphIOProcessor* const ioProc
1136 = dynamic_cast<AudioProcessorGraph::AudioGraphIOProcessor*> (processor.get()))
1137 ioProc->setParentGraph (graph);
1140 //==============================================================================
1141 struct AudioProcessorGraph::AudioProcessorGraphBufferHelpers
1143 AudioProcessorGraphBufferHelpers() noexcept
1144 : currentAudioInputBuffer (nullptr),
1145 currentCVInputBuffer (nullptr) {}
1147 void setRenderingBufferSize (int newNumAudioChannels, int newNumCVChannels, int newNumSamples) noexcept
1149 renderingAudioBuffers.setSize (newNumAudioChannels, newNumSamples);
1150 renderingAudioBuffers.clear();
1152 renderingCVBuffers.setSize (newNumCVChannels, newNumSamples);
1153 renderingCVBuffers.clear();
1156 void release() noexcept
1158 renderingAudioBuffers.setSize (1, 1);
1159 currentAudioInputBuffer = nullptr;
1160 currentCVInputBuffer = nullptr;
1161 currentAudioOutputBuffer.setSize (1, 1);
1162 currentCVOutputBuffer.setSize (1, 1);
1164 renderingCVBuffers.setSize (1, 1);
1167 void prepareInOutBuffers (int newNumAudioChannels, int newNumCVChannels, int newNumSamples) noexcept
1169 currentAudioInputBuffer = nullptr;
1170 currentCVInputBuffer = nullptr;
1171 currentAudioOutputBuffer.setSize (newNumAudioChannels, newNumSamples);
1172 currentCVOutputBuffer.setSize (newNumCVChannels, newNumSamples);
1175 AudioSampleBuffer renderingAudioBuffers;
1176 AudioSampleBuffer renderingCVBuffers;
1177 AudioSampleBuffer* currentAudioInputBuffer;
1178 const AudioSampleBuffer* currentCVInputBuffer;
1179 AudioSampleBuffer currentAudioOutputBuffer;
1180 AudioSampleBuffer currentCVOutputBuffer;
1183 //==============================================================================
1184 AudioProcessorGraph::AudioProcessorGraph()
1185 : lastNodeId (0), audioAndCVBuffers (new AudioProcessorGraphBufferHelpers),
1186 currentMidiInputBuffer (nullptr), isPrepared (false), needsReorder (false)
1190 AudioProcessorGraph::~AudioProcessorGraph()
1192 clearRenderingSequence();
1193 clear();
1196 const String AudioProcessorGraph::getName() const
1198 return "Audio Graph";
1201 //==============================================================================
1202 void AudioProcessorGraph::clear()
1204 nodes.clear();
1205 connections.clear();
1206 needsReorder = true;
1209 AudioProcessorGraph::Node* AudioProcessorGraph::getNodeForId (const uint32 nodeId) const
1211 for (int i = nodes.size(); --i >= 0;)
1212 if (nodes.getUnchecked(i)->nodeId == nodeId)
1213 return nodes.getUnchecked(i);
1215 return nullptr;
1218 AudioProcessorGraph::Node* AudioProcessorGraph::addNode (AudioProcessor* const newProcessor, uint32 nodeId)
1220 CARLA_SAFE_ASSERT_RETURN (newProcessor != nullptr && newProcessor != this, nullptr);
1222 for (int i = nodes.size(); --i >= 0;)
1224 CARLA_SAFE_ASSERT_RETURN (nodes.getUnchecked(i)->getProcessor() != newProcessor, nullptr);
1227 if (nodeId == 0)
1229 nodeId = ++lastNodeId;
1231 else
1233 // you can't add a node with an id that already exists in the graph..
1234 CARLA_SAFE_ASSERT_RETURN (getNodeForId (nodeId) == nullptr, nullptr);
1235 removeNode (nodeId);
1237 if (nodeId > lastNodeId)
1238 lastNodeId = nodeId;
1241 Node* const n = new Node (nodeId, newProcessor);
1242 nodes.add (n);
1244 if (isPrepared)
1245 needsReorder = true;
1247 n->setParentGraph (this);
1248 return n;
1251 bool AudioProcessorGraph::removeNode (const uint32 nodeId)
1253 disconnectNode (nodeId);
1255 for (int i = nodes.size(); --i >= 0;)
1257 if (nodes.getUnchecked(i)->nodeId == nodeId)
1259 nodes.remove (i);
1261 if (isPrepared)
1262 needsReorder = true;
1264 return true;
1268 return false;
1271 bool AudioProcessorGraph::removeNode (Node* node)
1273 CARLA_SAFE_ASSERT_RETURN(node != nullptr, false);
1275 return removeNode (node->nodeId);
1278 //==============================================================================
1279 const AudioProcessorGraph::Connection* AudioProcessorGraph::getConnectionBetween (const ChannelType ct,
1280 const uint32 sourceNodeId,
1281 const uint sourceChannelIndex,
1282 const uint32 destNodeId,
1283 const uint destChannelIndex) const
1285 const Connection c (ct, sourceNodeId, sourceChannelIndex, destNodeId, destChannelIndex);
1286 GraphRenderingOps::ConnectionSorter sorter;
1287 return connections [connections.indexOfSorted (sorter, &c)];
1290 bool AudioProcessorGraph::isConnected (const uint32 possibleSourceNodeId,
1291 const uint32 possibleDestNodeId) const
1293 for (int i = connections.size(); --i >= 0;)
1295 const Connection* const c = connections.getUnchecked(i);
1297 if (c->sourceNodeId == possibleSourceNodeId
1298 && c->destNodeId == possibleDestNodeId)
1300 return true;
1304 return false;
1307 bool AudioProcessorGraph::canConnect (ChannelType ct,
1308 const uint32 sourceNodeId,
1309 const uint sourceChannelIndex,
1310 const uint32 destNodeId,
1311 const uint destChannelIndex) const
1313 if (sourceNodeId == destNodeId)
1314 return false;
1316 const Node* const source = getNodeForId (sourceNodeId);
1318 if (source == nullptr
1319 || (ct != ChannelTypeMIDI && sourceChannelIndex >= source->processor->getTotalNumOutputChannels(ct))
1320 || (ct == ChannelTypeMIDI && ! source->processor->producesMidi()))
1321 return false;
1323 const Node* const dest = getNodeForId (destNodeId);
1325 if (dest == nullptr
1326 || (ct != ChannelTypeMIDI && destChannelIndex >= dest->processor->getTotalNumInputChannels(ct))
1327 || (ct == ChannelTypeMIDI && ! dest->processor->acceptsMidi()))
1328 return false;
1330 return getConnectionBetween (ct,
1331 sourceNodeId, sourceChannelIndex,
1332 destNodeId, destChannelIndex) == nullptr;
1335 bool AudioProcessorGraph::addConnection (const ChannelType ct,
1336 const uint32 sourceNodeId,
1337 const uint sourceChannelIndex,
1338 const uint32 destNodeId,
1339 const uint destChannelIndex)
1341 if (! canConnect (ct, sourceNodeId, sourceChannelIndex, destNodeId, destChannelIndex))
1342 return false;
1344 GraphRenderingOps::ConnectionSorter sorter;
1345 connections.addSorted (sorter, new Connection (ct,
1346 sourceNodeId, sourceChannelIndex,
1347 destNodeId, destChannelIndex));
1349 if (isPrepared)
1350 needsReorder = true;
1352 return true;
1355 void AudioProcessorGraph::removeConnection (const int index)
1357 connections.remove (index);
1359 if (isPrepared)
1360 needsReorder = true;
1363 bool AudioProcessorGraph::removeConnection (const ChannelType ct,
1364 const uint32 sourceNodeId, const uint sourceChannelIndex,
1365 const uint32 destNodeId, const uint destChannelIndex)
1367 bool doneAnything = false;
1369 for (int i = connections.size(); --i >= 0;)
1371 const Connection* const c = connections.getUnchecked(i);
1373 if (c->channelType == ct
1374 && c->sourceNodeId == sourceNodeId
1375 && c->destNodeId == destNodeId
1376 && c->sourceChannelIndex == sourceChannelIndex
1377 && c->destChannelIndex == destChannelIndex)
1379 removeConnection (i);
1380 doneAnything = true;
1384 return doneAnything;
1387 bool AudioProcessorGraph::disconnectNode (const uint32 nodeId)
1389 bool doneAnything = false;
1391 for (int i = connections.size(); --i >= 0;)
1393 const Connection* const c = connections.getUnchecked(i);
1395 if (c->sourceNodeId == nodeId || c->destNodeId == nodeId)
1397 removeConnection (i);
1398 doneAnything = true;
1402 return doneAnything;
1405 bool AudioProcessorGraph::isConnectionLegal (const Connection* const c) const
1407 CARLA_SAFE_ASSERT_RETURN (c != nullptr, false);
1409 const Node* const source = getNodeForId (c->sourceNodeId);
1410 const Node* const dest = getNodeForId (c->destNodeId);
1412 return source != nullptr
1413 && dest != nullptr
1414 && (c->channelType != ChannelTypeMIDI ? (c->sourceChannelIndex < source->processor->getTotalNumOutputChannels(c->channelType))
1415 : source->processor->producesMidi())
1416 && (c->channelType != ChannelTypeMIDI ? (c->destChannelIndex < dest->processor->getTotalNumInputChannels(c->channelType))
1417 : dest->processor->acceptsMidi());
1420 bool AudioProcessorGraph::removeIllegalConnections()
1422 bool doneAnything = false;
1424 for (int i = connections.size(); --i >= 0;)
1426 if (! isConnectionLegal (connections.getUnchecked(i)))
1428 removeConnection (i);
1429 doneAnything = true;
1433 return doneAnything;
1436 //==============================================================================
1437 static void deleteRenderOpArray (Array<void*>& ops)
1439 for (int i = ops.size(); --i >= 0;)
1440 delete static_cast<GraphRenderingOps::AudioGraphRenderingOpBase*> (ops.getUnchecked(i));
1443 void AudioProcessorGraph::clearRenderingSequence()
1445 Array<void*> oldOps;
1448 const CarlaRecursiveMutexLocker cml (getCallbackLock());
1449 renderingOps.swapWith (oldOps);
1452 deleteRenderOpArray (oldOps);
1455 bool AudioProcessorGraph::isAnInputTo (const uint32 possibleInputId,
1456 const uint32 possibleDestinationId,
1457 const int recursionCheck) const
1459 if (recursionCheck > 0)
1461 for (int i = connections.size(); --i >= 0;)
1463 const AudioProcessorGraph::Connection* const c = connections.getUnchecked (i);
1465 if (c->destNodeId == possibleDestinationId
1466 && (c->sourceNodeId == possibleInputId
1467 || isAnInputTo (possibleInputId, c->sourceNodeId, recursionCheck - 1)))
1468 return true;
1472 return false;
1475 void AudioProcessorGraph::buildRenderingSequence()
1477 Array<void*> newRenderingOps;
1478 int numAudioRenderingBuffersNeeded = 2;
1479 int numCVRenderingBuffersNeeded = 0;
1480 int numMidiBuffersNeeded = 1;
1483 const CarlaRecursiveMutexLocker cml (reorderMutex);
1485 Array<Node*> orderedNodes;
1488 const GraphRenderingOps::ConnectionLookupTable table (connections);
1490 for (int i = 0; i < nodes.size(); ++i)
1492 Node* const node = nodes.getUnchecked(i);
1494 node->prepare (getSampleRate(), getBlockSize(), this);
1496 int j = 0;
1497 for (; j < orderedNodes.size(); ++j)
1498 if (table.isAnInputTo (node->nodeId, ((Node*) orderedNodes.getUnchecked(j))->nodeId))
1499 break;
1501 orderedNodes.insert (j, node);
1505 GraphRenderingOps::RenderingOpSequenceCalculator calculator (*this, orderedNodes, newRenderingOps);
1507 numAudioRenderingBuffersNeeded = calculator.getNumAudioBuffersNeeded();
1508 numCVRenderingBuffersNeeded = calculator.getNumCVBuffersNeeded();
1509 numMidiBuffersNeeded = calculator.getNumMidiBuffersNeeded();
1513 // swap over to the new rendering sequence..
1514 const CarlaRecursiveMutexLocker cml (getCallbackLock());
1516 audioAndCVBuffers->setRenderingBufferSize (numAudioRenderingBuffersNeeded,
1517 numCVRenderingBuffersNeeded,
1518 getBlockSize());
1520 for (int i = static_cast<int>(midiBuffers.size()); --i >= 0;)
1521 midiBuffers.getUnchecked(i)->clear();
1523 while (static_cast<int>(midiBuffers.size()) < numMidiBuffersNeeded)
1524 midiBuffers.add (new MidiBuffer());
1526 renderingOps.swapWith (newRenderingOps);
1529 // delete the old ones..
1530 deleteRenderOpArray (newRenderingOps);
1533 //==============================================================================
1534 void AudioProcessorGraph::prepareToPlay (double sampleRate, int estimatedSamplesPerBlock)
1536 setRateAndBufferSizeDetails(sampleRate, estimatedSamplesPerBlock);
1538 audioAndCVBuffers->prepareInOutBuffers(jmax(1U, getTotalNumOutputChannels(AudioProcessor::ChannelTypeAudio)),
1539 jmax(1U, getTotalNumOutputChannels(AudioProcessor::ChannelTypeCV)),
1540 estimatedSamplesPerBlock);
1542 currentMidiInputBuffer = nullptr;
1543 currentMidiOutputBuffer.clear();
1545 clearRenderingSequence();
1546 buildRenderingSequence();
1548 isPrepared = true;
1551 void AudioProcessorGraph::releaseResources()
1553 isPrepared = false;
1555 for (int i = 0; i < nodes.size(); ++i)
1556 nodes.getUnchecked(i)->unprepare();
1558 audioAndCVBuffers->release();
1559 midiBuffers.clear();
1561 currentMidiInputBuffer = nullptr;
1562 currentMidiOutputBuffer.clear();
1565 void AudioProcessorGraph::reset()
1567 const CarlaRecursiveMutexLocker cml (getCallbackLock());
1569 for (int i = 0; i < nodes.size(); ++i)
1570 nodes.getUnchecked(i)->getProcessor()->reset();
1573 void AudioProcessorGraph::setNonRealtime (bool isProcessingNonRealtime) noexcept
1575 const CarlaRecursiveMutexLocker cml (getCallbackLock());
1577 AudioProcessor::setNonRealtime (isProcessingNonRealtime);
1579 for (int i = 0; i < nodes.size(); ++i)
1580 nodes.getUnchecked(i)->getProcessor()->setNonRealtime (isProcessingNonRealtime);
1584 void AudioProcessorGraph::processAudio (AudioSampleBuffer& audioBuffer, MidiBuffer& midiMessages)
1586 AudioSampleBuffer*& currentAudioInputBuffer = audioAndCVBuffers->currentAudioInputBuffer;
1587 AudioSampleBuffer& currentAudioOutputBuffer = audioAndCVBuffers->currentAudioOutputBuffer;
1588 AudioSampleBuffer& renderingAudioBuffers = audioAndCVBuffers->renderingAudioBuffers;
1589 AudioSampleBuffer& renderingCVBuffers = audioAndCVBuffers->renderingCVBuffers;
1591 const int numSamples = audioBuffer.getNumSamples();
1593 if (! audioAndCVBuffers->currentAudioOutputBuffer.setSizeRT(numSamples))
1594 return;
1595 if (! audioAndCVBuffers->renderingAudioBuffers.setSizeRT(numSamples))
1596 return;
1597 if (! audioAndCVBuffers->renderingCVBuffers.setSizeRT(numSamples))
1598 return;
1600 currentAudioInputBuffer = &audioBuffer;
1601 currentAudioOutputBuffer.clear();
1602 currentMidiInputBuffer = &midiMessages;
1603 currentMidiOutputBuffer.clear();
1605 for (int i = 0; i < renderingOps.size(); ++i)
1607 GraphRenderingOps::AudioGraphRenderingOpBase* const op
1608 = (GraphRenderingOps::AudioGraphRenderingOpBase*) renderingOps.getUnchecked(i);
1610 op->perform (renderingAudioBuffers, renderingCVBuffers, midiBuffers, numSamples);
1613 for (uint32_t i = 0; i < audioBuffer.getNumChannels(); ++i)
1614 audioBuffer.copyFrom (i, 0, currentAudioOutputBuffer, i, 0, numSamples);
1616 midiMessages.clear();
1617 midiMessages.addEvents (currentMidiOutputBuffer, 0, audioBuffer.getNumSamples(), 0);
1621 void AudioProcessorGraph::processAudioAndCV (AudioSampleBuffer& audioBuffer,
1622 const AudioSampleBuffer& cvInBuffer,
1623 AudioSampleBuffer& cvOutBuffer,
1624 MidiBuffer& midiMessages)
1626 AudioSampleBuffer*& currentAudioInputBuffer = audioAndCVBuffers->currentAudioInputBuffer;
1627 const AudioSampleBuffer*& currentCVInputBuffer = audioAndCVBuffers->currentCVInputBuffer;
1628 AudioSampleBuffer& currentAudioOutputBuffer = audioAndCVBuffers->currentAudioOutputBuffer;
1629 AudioSampleBuffer& currentCVOutputBuffer = audioAndCVBuffers->currentCVOutputBuffer;
1630 AudioSampleBuffer& renderingAudioBuffers = audioAndCVBuffers->renderingAudioBuffers;
1631 AudioSampleBuffer& renderingCVBuffers = audioAndCVBuffers->renderingCVBuffers;
1633 const int numSamples = audioBuffer.getNumSamples();
1635 if (! audioAndCVBuffers->currentAudioOutputBuffer.setSizeRT(numSamples))
1636 return;
1637 if (! audioAndCVBuffers->currentCVOutputBuffer.setSizeRT(numSamples))
1638 return;
1639 if (! audioAndCVBuffers->renderingAudioBuffers.setSizeRT(numSamples))
1640 return;
1641 if (! audioAndCVBuffers->renderingCVBuffers.setSizeRT(numSamples))
1642 return;
1644 currentAudioInputBuffer = &audioBuffer;
1645 currentCVInputBuffer = &cvInBuffer;
1646 currentMidiInputBuffer = &midiMessages;
1647 currentAudioOutputBuffer.clear();
1648 currentCVOutputBuffer.clear();
1649 currentMidiOutputBuffer.clear();
1651 for (int i = 0; i < renderingOps.size(); ++i)
1653 GraphRenderingOps::AudioGraphRenderingOpBase* const op
1654 = (GraphRenderingOps::AudioGraphRenderingOpBase*) renderingOps.getUnchecked(i);
1656 op->perform (renderingAudioBuffers, renderingCVBuffers, midiBuffers, numSamples);
1659 for (uint32_t i = 0; i < audioBuffer.getNumChannels(); ++i)
1660 audioBuffer.copyFrom (i, 0, currentAudioOutputBuffer, i, 0, numSamples);
1662 for (uint32_t i = 0; i < cvOutBuffer.getNumChannels(); ++i)
1663 cvOutBuffer.copyFrom (i, 0, currentCVOutputBuffer, i, 0, numSamples);
1665 midiMessages.clear();
1666 midiMessages.addEvents (currentMidiOutputBuffer, 0, audioBuffer.getNumSamples(), 0);
1669 bool AudioProcessorGraph::acceptsMidi() const { return true; }
1670 bool AudioProcessorGraph::producesMidi() const { return true; }
1673 void AudioProcessorGraph::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
1675 processAudio (buffer, midiMessages);
1679 void AudioProcessorGraph::processBlockWithCV (AudioSampleBuffer& audioBuffer,
1680 const AudioSampleBuffer& cvInBuffer,
1681 AudioSampleBuffer& cvOutBuffer,
1682 MidiBuffer& midiMessages)
1684 processAudioAndCV (audioBuffer, cvInBuffer, cvOutBuffer, midiMessages);
1687 void AudioProcessorGraph::reorderNowIfNeeded()
1689 if (needsReorder)
1691 needsReorder = false;
1692 buildRenderingSequence();
1696 const CarlaRecursiveMutex& AudioProcessorGraph::getReorderMutex() const
1698 return reorderMutex;
1701 //==============================================================================
1702 AudioProcessorGraph::AudioGraphIOProcessor::AudioGraphIOProcessor (const IODeviceType deviceType)
1703 : type (deviceType), graph (nullptr)
1707 AudioProcessorGraph::AudioGraphIOProcessor::~AudioGraphIOProcessor()
1711 const String AudioProcessorGraph::AudioGraphIOProcessor::getName() const
1713 switch (type)
1715 case audioOutputNode: return "Audio Output";
1716 case audioInputNode: return "Audio Input";
1717 case cvOutputNode: return "CV Output";
1718 case cvInputNode: return "CV Input";
1719 case midiOutputNode: return "Midi Output";
1720 case midiInputNode: return "Midi Input";
1721 default: break;
1724 return String();
1727 void AudioProcessorGraph::AudioGraphIOProcessor::prepareToPlay (double, int)
1729 CARLA_SAFE_ASSERT (graph != nullptr);
1732 void AudioProcessorGraph::AudioGraphIOProcessor::releaseResources()
1736 void AudioProcessorGraph::AudioGraphIOProcessor::processAudioAndCV (AudioSampleBuffer& audioBuffer,
1737 const AudioSampleBuffer& cvInBuffer,
1738 AudioSampleBuffer& cvOutBuffer,
1739 MidiBuffer& midiMessages)
1741 CARLA_SAFE_ASSERT_RETURN(graph != nullptr,);
1743 switch (type)
1745 case audioOutputNode:
1747 AudioSampleBuffer& currentAudioOutputBuffer =
1748 graph->audioAndCVBuffers->currentAudioOutputBuffer;
1750 for (int i = jmin (currentAudioOutputBuffer.getNumChannels(),
1751 audioBuffer.getNumChannels()); --i >= 0;)
1753 currentAudioOutputBuffer.addFrom (i, 0, audioBuffer, i, 0, audioBuffer.getNumSamples());
1756 break;
1759 case audioInputNode:
1761 AudioSampleBuffer*& currentAudioInputBuffer =
1762 graph->audioAndCVBuffers->currentAudioInputBuffer;
1764 for (int i = jmin (currentAudioInputBuffer->getNumChannels(),
1765 audioBuffer.getNumChannels()); --i >= 0;)
1767 audioBuffer.copyFrom (i, 0, *currentAudioInputBuffer, i, 0, audioBuffer.getNumSamples());
1770 break;
1773 case cvOutputNode:
1775 AudioSampleBuffer& currentCVOutputBuffer =
1776 graph->audioAndCVBuffers->currentCVOutputBuffer;
1778 for (int i = jmin (currentCVOutputBuffer.getNumChannels(),
1779 cvInBuffer.getNumChannels()); --i >= 0;)
1781 currentCVOutputBuffer.addFrom (i, 0, cvInBuffer, i, 0, cvInBuffer.getNumSamples());
1784 break;
1787 case cvInputNode:
1789 const AudioSampleBuffer*& currentCVInputBuffer =
1790 graph->audioAndCVBuffers->currentCVInputBuffer;
1792 for (int i = jmin (currentCVInputBuffer->getNumChannels(),
1793 cvOutBuffer.getNumChannels()); --i >= 0;)
1795 cvOutBuffer.copyFrom (i, 0, *currentCVInputBuffer, i, 0, cvOutBuffer.getNumSamples());
1798 break;
1801 case midiOutputNode:
1802 graph->currentMidiOutputBuffer.addEvents (midiMessages, 0, audioBuffer.getNumSamples(), 0);
1803 break;
1805 case midiInputNode:
1806 midiMessages.addEvents (*graph->currentMidiInputBuffer, 0, audioBuffer.getNumSamples(), 0);
1807 break;
1809 default:
1810 break;
1814 void AudioProcessorGraph::AudioGraphIOProcessor::processBlockWithCV (AudioSampleBuffer& audioBuffer,
1815 const AudioSampleBuffer& cvInBuffer,
1816 AudioSampleBuffer& cvOutBuffer,
1817 MidiBuffer& midiMessages)
1819 processAudioAndCV (audioBuffer, cvInBuffer, cvOutBuffer, midiMessages);
1822 bool AudioProcessorGraph::AudioGraphIOProcessor::acceptsMidi() const
1824 return type == midiOutputNode;
1827 bool AudioProcessorGraph::AudioGraphIOProcessor::producesMidi() const
1829 return type == midiInputNode;
1832 bool AudioProcessorGraph::AudioGraphIOProcessor::isInput() const noexcept
1834 return type == audioInputNode || type == cvInputNode || type == midiInputNode;
1837 bool AudioProcessorGraph::AudioGraphIOProcessor::isOutput() const noexcept
1839 return type == audioOutputNode || type == cvOutputNode || type == midiOutputNode;
1842 void AudioProcessorGraph::AudioGraphIOProcessor::setParentGraph (AudioProcessorGraph* const newGraph)
1844 graph = newGraph;
1846 if (graph != nullptr)
1848 setPlayConfigDetails (type == audioOutputNode
1849 ? graph->getTotalNumOutputChannels(AudioProcessor::ChannelTypeAudio)
1850 : 0,
1851 type == audioInputNode
1852 ? graph->getTotalNumInputChannels(AudioProcessor::ChannelTypeAudio)
1853 : 0,
1854 type == cvOutputNode
1855 ? graph->getTotalNumOutputChannels(AudioProcessor::ChannelTypeCV)
1856 : 0,
1857 type == cvInputNode
1858 ? graph->getTotalNumInputChannels(AudioProcessor::ChannelTypeCV)
1859 : 0,
1860 type == midiOutputNode
1861 ? graph->getTotalNumOutputChannels(AudioProcessor::ChannelTypeMIDI)
1862 : 0,
1863 type == midiInputNode
1864 ? graph->getTotalNumInputChannels(AudioProcessor::ChannelTypeMIDI)
1865 : 0,
1866 getSampleRate(),
1867 getBlockSize());