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"
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;
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
,
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
>&,
69 sharedCVBufferChans
.clear (channelNum
, 0, numSamples
);
71 sharedAudioBufferChans
.clear (channelNum
, 0, numSamples
);
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
>&,
92 sharedCVBufferChans
.copyFrom (dstChannelNum
, 0, sharedCVBufferChans
, srcChannelNum
, 0, numSamples
);
94 sharedAudioBufferChans
.copyFrom (dstChannelNum
, 0, sharedAudioBufferChans
, srcChannelNum
, 0, numSamples
);
97 const int srcChannelNum
, dstChannelNum
;
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
)
115 sharedCVBufferChans
.addFrom (dstChannelNum
, 0, sharedCVBufferChans
, srcChannelNum
, 0, numSamples
);
117 sharedAudioBufferChans
.addFrom (dstChannelNum
, 0, sharedAudioBufferChans
, srcChannelNum
, 0, numSamples
);
120 const int srcChannelNum
, dstChannelNum
;
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
,
135 sharedMidiBuffers
.getUnchecked (bufferNum
)->clear();
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
,
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
)
187 bufferSize (delaySize
+ 1),
188 readIndex (0), writeIndex (delaySize
),
191 buffer
.calloc ((size_t) bufferSize
);
194 void perform (AudioSampleBuffer
& sharedAudioBufferChans
,
195 AudioSampleBuffer
& sharedCVBufferChans
,
196 const OwnedArray
<MidiBuffer
>&,
197 const int numSamples
)
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;
215 HeapBlock
<float> buffer
;
216 const int channel
, bufferSize
;
217 int readIndex
, writeIndex
;
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
)
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())
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
;
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
)
322 orderedNodes (nodes
),
325 audioNodeIds
.add ((uint32
) zeroNodeID
); // first buffer is read-only zeros
326 audioChannels
.add (0);
328 cvNodeIds
.add ((uint32
) zeroNodeID
);
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(); }
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
;
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
);
369 nodeDelays
.set (index
, latency
);
373 nodeDelayIDs
.add (nodeID
);
374 nodeDelays
.add (latency
);
378 int getInputLatencyForNode (const uint32 nodeID
) const
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
));
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
);
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
);
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
,
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));
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
,
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));
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));
518 // if not found, this is probably a feedback loop
519 renderingOps
.add (new ClearChannelOp (bufIndex
, false));
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
));
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
);
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
);
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));
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));
649 // if not found, this is probably a feedback loop
650 renderingOps
.add (new ClearChannelOp (bufIndex
, true));
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
));
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)
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)
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
;
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
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
;
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),
775 renderingOps
.add (new CopyMidiBufferOp (srcIndex
, midiBufferToUse
));
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
),
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
,
813 //==============================================================================
814 int getFreeBuffer (const AudioProcessor::ChannelType channelType
)
818 case AudioProcessor::ChannelTypeAudio
:
819 for (int i
= 1; i
< audioNodeIds
.size(); ++i
)
820 if (audioNodeIds
.getUnchecked(i
) == freeNodeID
)
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
)
832 cvNodeIds
.add ((uint32
) freeNodeID
);
834 return cvNodeIds
.size() - 1;
836 case AudioProcessor::ChannelTypeMIDI
:
837 for (int i
= 1; i
< midiNodeIds
.size(); ++i
)
838 if (midiNodeIds
.getUnchecked(i
) == freeNodeID
)
841 midiNodeIds
.add ((uint32
) freeNodeID
);
842 return midiNodeIds
.size() - 1;
848 int getReadOnlyEmptyBuffer() const noexcept
853 int getBufferContaining (const AudioProcessor::ChannelType channelType
,
855 const uint outputChannel
) const noexcept
859 case AudioProcessor::ChannelTypeAudio
:
860 for (int i
= audioNodeIds
.size(); --i
>= 0;)
861 if (audioNodeIds
.getUnchecked(i
) == nodeId
&& audioChannels
.getUnchecked(i
) == outputChannel
)
865 case AudioProcessor::ChannelTypeCV
:
866 for (int i
= cvNodeIds
.size(); --i
>= 0;)
867 if (cvNodeIds
.getUnchecked(i
) == nodeId
&& cvChannels
.getUnchecked(i
) == outputChannel
)
871 case AudioProcessor::ChannelTypeMIDI
:
872 for (int i
= midiNodeIds
.size(); --i
>= 0;)
874 if (midiNodeIds
.getUnchecked(i
) == nodeId
)
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
,
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
,
904 midiNodeIds
.getUnchecked(i
), 0))
906 midiNodeIds
.set (i
, (uint32
) freeNodeID
);
911 bool isBufferNeededLater (const AudioProcessor::ChannelType channelType
,
912 int stepIndexToSearchFrom
,
913 uint inputChannelOfIndexToIgnore
,
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)
928 inputChannelOfIndexToIgnore
= (uint
)-1;
929 ++stepIndexToSearchFrom
;
935 void markBufferAsContaining (const AudioProcessor::ChannelType channelType
,
936 int bufferNum
, uint32 nodeId
, int outputIndex
)
940 case AudioProcessor::ChannelTypeAudio
:
941 CARLA_SAFE_ASSERT_BREAK (bufferNum
>= 0 && bufferNum
< audioNodeIds
.size());
942 audioNodeIds
.set (bufferNum
, nodeId
);
943 audioChannels
.set (bufferNum
, outputIndex
);
946 case AudioProcessor::ChannelTypeCV
:
947 CARLA_SAFE_ASSERT_BREAK (bufferNum
>= 0 && bufferNum
< cvNodeIds
.size());
948 cvNodeIds
.set (bufferNum
, nodeId
);
949 cvChannels
.set (bufferNum
, outputIndex
);
952 case AudioProcessor::ChannelTypeMIDI
:
953 CARLA_SAFE_ASSERT_BREAK (bufferNum
> 0 && bufferNum
< midiNodeIds
.size());
954 midiNodeIds
.set (bufferNum
, nodeId
);
959 CARLA_DECLARE_NON_COPYABLE (RenderingOpSequenceCalculator
)
962 //==============================================================================
963 // Holds a fast lookup table for checking which nodes are inputs to others.
964 class ConnectionLookupTable
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
);
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());
993 //==============================================================================
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
1012 if (const Entry
* const entry
= findEntry (possibleDestinationId
, index
))
1014 const SortedSet
<uint32
>& srcNodes
= entry
->srcNodes
;
1016 if (srcNodes
.contains (possibleInputId
))
1019 if (--recursionCheck
>= 0)
1021 for (int i
= 0; i
< srcNodes
.size(); ++i
)
1022 if (isAnInputToRecursive (possibleInputId
, srcNodes
.getUnchecked(i
), recursionCheck
))
1030 Entry
* findEntry (const uint32 destNodeId
, int& insertIndex
) const noexcept
1032 Entry
* result
= nullptr;
1035 int end
= entries
.size();
1043 else if (destNodeId
== entries
.getUnchecked (start
)->destNodeId
)
1045 result
= entries
.getUnchecked (start
);
1050 const int halfway
= (start
+ end
) / 2;
1052 if (halfway
== start
)
1054 if (destNodeId
>= entries
.getUnchecked (halfway
)->destNodeId
)
1059 else if (destNodeId
>= entries
.getUnchecked (halfway
)->destNodeId
)
1066 insertIndex
= start
;
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;
1094 //==============================================================================
1095 AudioProcessorGraph::Connection::Connection (ChannelType ct
,
1096 const uint32 sourceID
, const uint sourceChannel
,
1097 const uint32 destID
, const uint destChannel
) noexcept
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
)
1116 setParentGraph (graph
);
1118 processor
->setRateAndBufferSizeDetails (newSampleRate
, newBlockSize
);
1119 processor
->prepareToPlay (newSampleRate
, newBlockSize
);
1124 void AudioProcessorGraph::Node::unprepare()
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();
1196 const String
AudioProcessorGraph::getName() const
1198 return "Audio Graph";
1201 //==============================================================================
1202 void AudioProcessorGraph::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
);
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);
1229 nodeId
= ++lastNodeId
;
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
);
1245 needsReorder
= true;
1247 n
->setParentGraph (this);
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
)
1262 needsReorder
= true;
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
)
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
)
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()))
1323 const Node
* const dest
= getNodeForId (destNodeId
);
1326 || (ct
!= ChannelTypeMIDI
&& destChannelIndex
>= dest
->processor
->getTotalNumInputChannels(ct
))
1327 || (ct
== ChannelTypeMIDI
&& ! dest
->processor
->acceptsMidi()))
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
))
1344 GraphRenderingOps::ConnectionSorter sorter
;
1345 connections
.addSorted (sorter
, new Connection (ct
,
1346 sourceNodeId
, sourceChannelIndex
,
1347 destNodeId
, destChannelIndex
));
1350 needsReorder
= true;
1355 void AudioProcessorGraph::removeConnection (const int index
)
1357 connections
.remove (index
);
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
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)))
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);
1497 for (; j
< orderedNodes
.size(); ++j
)
1498 if (table
.isAnInputTo (node
->nodeId
, ((Node
*) orderedNodes
.getUnchecked(j
))->nodeId
))
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
,
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();
1551 void AudioProcessorGraph::releaseResources()
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))
1595 if (! audioAndCVBuffers->renderingAudioBuffers.setSizeRT(numSamples))
1597 if (! audioAndCVBuffers->renderingCVBuffers.setSizeRT(numSamples))
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
))
1637 if (! audioAndCVBuffers
->currentCVOutputBuffer
.setSizeRT(numSamples
))
1639 if (! audioAndCVBuffers
->renderingAudioBuffers
.setSizeRT(numSamples
))
1641 if (! audioAndCVBuffers
->renderingCVBuffers
.setSizeRT(numSamples
))
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()
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
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";
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,);
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());
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());
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());
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());
1801 case midiOutputNode
:
1802 graph
->currentMidiOutputBuffer
.addEvents (midiMessages
, 0, audioBuffer
.getNumSamples(), 0);
1806 midiMessages
.addEvents (*graph
->currentMidiInputBuffer
, 0, audioBuffer
.getNumSamples(), 0);
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
)
1846 if (graph
!= nullptr)
1848 setPlayConfigDetails (type
== audioOutputNode
1849 ? graph
->getTotalNumOutputChannels(AudioProcessor::ChannelTypeAudio
)
1851 type
== audioInputNode
1852 ? graph
->getTotalNumInputChannels(AudioProcessor::ChannelTypeAudio
)
1854 type
== cvOutputNode
1855 ? graph
->getTotalNumOutputChannels(AudioProcessor::ChannelTypeCV
)
1858 ? graph
->getTotalNumInputChannels(AudioProcessor::ChannelTypeCV
)
1860 type
== midiOutputNode
1861 ? graph
->getTotalNumOutputChannels(AudioProcessor::ChannelTypeMIDI
)
1863 type
== midiInputNode
1864 ? graph
->getTotalNumInputChannels(AudioProcessor::ChannelTypeMIDI
)