13namespace tracktion {
inline namespace graph
26 : sequence (std::move (sequenceToPlay))
32 return {
false,
true, 0 };
42 sampleRate = info.sampleRate;
47 const int numSamples = (
int) pc.referenceSampleRange.
getLength();
48 const double blockDuration = numSamples / sampleRate;
51 for (
int index = sequence.
getNextIndexAtTime (timeRange.getStart()); index >= 0; ++index)
57 if (! timeRange.contains (
time))
60 pc.buffers.midi.addMidiMessage (eventHolder->message,
time - timeRange.getStart(),
61 tracktion_engine::MidiMessageArray::notMPE);
69 lastTime = timeRange.getEnd();
74 double sampleRate = 0.0, lastTime = 0.0;
83 SinNode (
float frequencyToUse,
int numChannelsToUse = 1,
size_t nodeIDToUse = 0)
84 : numChannels (numChannelsToUse), nodeID (nodeIDToUse), frequency (frequencyToUse)
91 props.hasAudio =
true;
92 props.hasMidi =
false;
93 props.numberOfChannels = numChannels;
94 props.nodeID = nodeID;
106 oscillator.reset (frequency, info.sampleRate);
111 setAllFrames (pc.buffers.audio, [&] { return oscillator.getNext(); });
115 const int numChannels;
131 : numChannels (numChannelsToUse)
134 AllocateAudioBuffer::no });
140 props.hasAudio =
true;
141 props.hasMidi =
false;
142 props.numberOfChannels = numChannels;
154 audioBuffer.resize (choc::buffer::Size::create ((choc::buffer::ChannelCount) numChannels,
155 (choc::buffer::FrameCount) info.blockSize));
161 pc.buffers.midi.clear();
162 setAudioOutput (
nullptr, audioBuffer.getView().getStart (pc.buffers.audio.getNumFrames()));
166 const int numChannels;
167 choc::buffer::ChannelArrayBuffer<float> audioBuffer;
177 : nodes (std::move (inputs))
184 props.hasAudio =
false;
185 props.hasMidi =
false;
186 props.numberOfChannels = 0;
188 for (
auto& node : nodes)
190 auto nodeProps = node->getNodeProperties();
191 props.hasAudio = props.hasAudio || nodeProps.hasAudio;
192 props.hasMidi = props.hasMidi || nodeProps.hasMidi;
193 props.numberOfChannels =
std::max (props.numberOfChannels, nodeProps.numberOfChannels);
203 for (
auto& node : nodes)
211 for (
auto& node : nodes)
212 if (! node->hasProcessed())
220 const auto numChannels = pc.buffers.audio.getNumChannels();
223 for (
auto& node : nodes)
225 auto inputFromNode = node->getProcessedOutput();
227 if (
auto numChannelsToAdd =
std::min (inputFromNode.audio.getNumChannels(), numChannels))
228 add (pc.buffers.audio.getFirstChannels (numChannelsToAdd),
229 inputFromNode.audio.getFirstChannels (numChannelsToAdd));
231 pc.buffers.midi.mergeFrom (inputFromNode.midi);
245 for (
auto node : nodes)
246 nodeVector.push_back (
std::unique_ptr<
Node> (node));
259 : node (std::move (input)),
260 function (std::move (fn))
267 return node->getNodeProperties();
272 return { node.get() };
277 return node->hasProcessed();
282 auto inputBuffer = node->getProcessedOutput().audio;
284 auto numFrames = pc.referenceSampleRange.
getLength();
285 const auto numChannels =
std::min (inputBuffer.getNumChannels(), pc.buffers.audio.getNumChannels());
286 jassert (inputBuffer.getNumFrames() == numFrames);
288 for (choc::buffer::ChannelCount c = 0; c < numChannels; ++c)
290 auto destIter = pc.buffers.audio.getIterator (c);
291 auto sourceIter = inputBuffer.getIterator (c);
293 for (choc::buffer::FrameCount i = 0; i < numFrames; ++i)
294 *destIter++ = function (*sourceIter++);
307 return makeNode<FunctionNode> (std::move (input), [gain] (
float s) {
return s * gain; });
317 : input (inputNode), gainFunction (
std::move (gainFunc))
319 assert (input !=
nullptr);
321 lastGain = gainFunction();
326 : ownedInput (
std::move (inputNode)), input (ownedInput.get()),
327 gainFunction (
std::move (gainFunc))
329 assert (ownedInput !=
nullptr);
330 assert (input !=
nullptr);
332 lastGain = gainFunction();
337 auto props = input->getNodeProperties();
338 constexpr size_t gainNodeMagicHash =
size_t (0x6761696e4e6f6465);
340 if (props.nodeID != 0)
341 hash_combine (props.nodeID, gainNodeMagicHash);
353 return input->hasProcessed();
358 jassert (pc.buffers.audio.getNumChannels() == input->getProcessedOutput().audio.getNumChannels());
361 copy (pc.buffers.audio, input->getProcessedOutput().audio);
362 pc.buffers.midi.mergeFrom (input->getProcessedOutput().midi);
364 float gain = gainFunction();
366 if (gain == lastGain)
369 pc.buffers.audio.clear();
370 else if (gain != 1.0f)
371 applyGain (pc.buffers.audio, gain);
377 smoother.
reset ((
int) pc.buffers.audio.getNumFrames());
378 applyGainPerFrame (pc.buffers.audio, [&] { return smoother.getNextValue(); });
386 Node* input =
nullptr;
388 float lastGain = 0.0f;
398 : input (std::move (inputNode)), busID (busIDToUse),
399 gainFunction (std::move (getGainFunc))
402 AllocateAudioBuffer::no });
417 auto props = input->getNodeProperties();
418 constexpr size_t sendNodeMagicHash =
size_t (0x73656e644e6f6465);
420 if (props.nodeID != 0)
421 hash_combine (props.nodeID, sendNodeMagicHash);
428 return { input.
get() };
433 return input->hasProcessed();
438 auto source = input->getProcessedOutput();
439 jassert (pc.buffers.audio.getSize() == source.audio.getSize());
446 if (input->numOutputNodes == 1)
447 pc.buffers.midi.swapWith (source.midi);
449 pc.buffers.midi.copyFrom (source.midi);
468 AllocateAudioBuffer::yes });
472 : input (std::move (inputNode)), busID (busIDToUse)
475 AllocateAudioBuffer::yes });
481 props.hasAudio =
false;
482 props.hasMidi =
false;
483 props.numberOfChannels = 0;
487 auto nodeProps = node->getNodeProperties();
488 props.hasAudio = props.hasAudio || nodeProps.hasAudio;
489 props.hasMidi = props.hasMidi || nodeProps.hasMidi;
490 props.numberOfChannels =
std::max (props.numberOfChannels, nodeProps.numberOfChannels);
491 props.latencyNumSamples =
std::max (props.latencyNumSamples, nodeProps.latencyNumSamples);
492 hash_combine (props.nodeID, nodeProps.nodeID);
495 constexpr size_t returnNodeMagicHash =
size_t (0x72657475726e);
497 if (props.nodeID != 0)
498 hash_combine (props.nodeID, returnNodeMagicHash);
508 return { input.
get() };
513 if (! hasInitialised)
515 findSendNodes (rootNode, postOrderedNodes, cache);
516 return TransformResult::connectionsMade;
519 return TransformResult::none;
527 if (! info.enableNodeMemorySharing)
530 if (input->numOutputNodes > 1)
533 const auto inputNumChannels = input->getNodeProperties().numberOfChannels;
536 if (inputNumChannels >= desiredNumChannels)
538 canUseSourceBuffers =
true;
540 tracktion::graph::AllocateAudioBuffer::no });
546 return ! input || input->hasProcessed();
551 if (canUseSourceBuffers)
560 pc.buffers.midi.clear();
561 pc.buffers.audio.clear();
566 auto source = input->getProcessedOutput();
567 jassert (pc.buffers.audio.getSize() == source.audio.getSize());
571 pc.buffers.midi.copyFrom (source.midi);
577 bool hasInitialised =
false, canUseSourceBuffers =
false;
589 constexpr size_t cacheKey = 3399892065;
593 allSends = *cachedVec;
597 for (
auto n : postOrderedNodes)
599 allSends.push_back (
send);
601 cache.cacheProperty (cacheKey, allSends);
606 for (
auto send : allSends)
607 if (
send->getBusID() == busID)
608 sends.push_back (
send);
613 for (
auto send : sends)
624 [&] (
auto n) { return std::find (sendsToRemove.begin(), sendsToRemove.end(), n) != sendsToRemove.end(); }),
628 if (sends.
size() > 0)
633 ownedNodes.
push_back (std::move (input));
636 for (
int i = (
int) sends.
size(); --i >= 0;)
638 auto gainFunction = sends[(
size_t) i]->getGainFunction();
643 ownedNodes.
push_back (makeNode<GainNode> (std::move (sends[(
size_t) i]), std::move (gainFunction)));
651 hasInitialised =
true;
664 bool passMidiThrough)
665 : input (std::move (inputNode)),
666 channelMap (std::move (channelMapToUse)),
667 passMIDI (passMidiThrough)
675 props.hasAudio = ! channelMap.
empty();
676 props.hasMidi = passMIDI;
677 props.numberOfChannels = 0;
679 const auto inputProps = input->getNodeProperties();
680 props.latencyNumSamples = inputProps.latencyNumSamples;
682 props.nodeID = inputProps.nodeID;
683 hash_combine (props.nodeID, passMIDI);
686 for (
auto channel : channelMap)
688 hash_combine (props.nodeID, channel.first);
689 hash_combine (props.nodeID, channel.second);
691 props.numberOfChannels =
std::max (props.numberOfChannels, channel.second + 1);
694 constexpr size_t channelNodeMagicHash =
size_t (0x6368616e6e656c);
696 if (props.nodeID != 0)
697 hash_combine (props.nodeID, channelNodeMagicHash);
704 return { input.
get() };
709 return input->hasProcessed();
714 auto inputBuffers = input->getProcessedOutput();
718 pc.buffers.midi.mergeFrom (inputBuffers.midi);
721 for (
auto channel : channelMap)
722 if (channel.first < (
int) inputBuffers.audio.getNumChannels())
723 add (pc.buffers.audio.getChannel ((choc::buffer::ChannelCount) channel.second),
724 inputBuffers.audio.getChannel ((choc::buffer::ChannelCount) channel.first));
739 for (
auto channelPair : sourceDestChannelIndicies)
740 map.push_back (channelPair);
752 : input (std::move (inputNode))
759 constexpr size_t sinkNodeMagicHash =
size_t (0x95ab5e9dcd);
760 auto props = input->getNodeProperties();
761 hash_combine (props.nodeID, sinkNodeMagicHash);
768 return { input.
get() };
773 return input->hasProcessed();
800 nodePtr = std::move (inputNode);
805 auto props = input->getNodeProperties();
806 hash_combine (props.nodeID, nodeID);
818 return input->hasProcessed();
823 auto inputBuffers = input->getProcessedOutput();
824 copy (pc.buffers.audio, inputBuffers.audio);
825 pc.buffers.midi.copyFrom (inputBuffers.midi);
double getEventTime(int index) const noexcept
int getNextIndexAtTime(double timeStamp) const noexcept
MidiEventHolder * getEventPointer(int index) const noexcept
static Random & getSystemRandom() noexcept
static Range withStartAndLength(const ValueType startValue, const ValueType length) noexcept
constexpr ValueType getLength() const noexcept
void reset(double sampleRate, double rampLengthInSeconds) noexcept
void setTargetValue(FloatType newValue) noexcept
std::vector< Node * > getDirectInputNodes() override
Should return all the inputs directly feeding in to this node.
bool isReadyToProcess() override
Should return true when this node is ready to be processed.
NodeProperties getNodeProperties() override
Should return the properties of the node.
void process(ProcessContext &pc) override
Called when the node is to be processed.
Maps channels from one to another.
void process(ProcessContext &pc) override
Called when the node is to be processed.
std::vector< Node * > getDirectInputNodes() override
Should return all the inputs directly feeding in to this node.
NodeProperties getNodeProperties() override
Should return the properties of the node.
bool isReadyToProcess() override
Should return true when this node is ready to be processed.
Takes a non-owning input node and simply forwards its outputs on.
void process(ProcessContext &pc) override
Called when the node is to be processed.
tracktion::graph::NodeProperties getNodeProperties() override
Should return the properties of the node.
std::vector< tracktion::graph::Node * > getDirectInputNodes() override
Should return all the inputs directly feeding in to this node.
bool isReadyToProcess() override
Should return true when this node is ready to be processed.
void process(ProcessContext &pc) override
Called when the node is to be processed.
std::vector< Node * > getDirectInputNodes() override
Should return all the inputs directly feeding in to this node.
NodeProperties getNodeProperties() override
Should return the properties of the node.
bool isReadyToProcess() override
Should return true when this node is ready to be processed.
GainNode(std::unique_ptr< Node > inputNode, std::function< float()> gainFunc)
Creates a GainNode that owns its input.
GainNode(Node *inputNode, std::function< float()> gainFunc)
Creates a GainNode that doesn't own its input.
std::vector< Node * > getDirectInputNodes() override
Should return all the inputs directly feeding in to this node.
NodeProperties getNodeProperties() override
Should return the properties of the node.
bool isReadyToProcess() override
Should return true when this node is ready to be processed.
void process(ProcessContext &pc) override
Called when the node is to be processed.
Plays back a MIDI sequence.
void prepareToPlay(const PlaybackInitialisationInfo &info) override
Called once before playback begins for each node.
bool isReadyToProcess() override
Should return true when this node is ready to be processed.
NodeProperties getNodeProperties() override
Should return the properties of the node.
void process(ProcessContext &pc) override
Called when the node is to be processed.
Main graph Node processor class.
void setAudioOutput(Node *sourceNode, const choc::buffer::ChannelArrayView< float > &)
This can be called during your process function to set a view to the output.
void setOptimisations(NodeOptimisations)
This can be called to provide some hints about allocating or playing back a Node to improve efficienc...
void setBufferViewToUse(Node *sourceNode, const choc::buffer::ChannelArrayView< float > &)
This can be called during prepareToPlay to set a BufferView to use which can improve efficiency.
Struct to describe a single iteration of a process call.
TransformResult transform(Node &rootNode, const std::vector< Node * > &postOrderedNodes, TransformCache &cache) override
Called after construction to give the node a chance to modify its topology.
std::vector< Node * > getDirectInputNodes() override
Should return all the inputs directly feeding in to this node.
NodeProperties getNodeProperties() override
Should return the properties of the node.
bool isReadyToProcess() override
Should return true when this node is ready to be processed.
void preProcess(choc::buffer::FrameCount, juce::Range< int64_t >) override
Called when the node is to be processed, just before process.
void process(ProcessContext &pc) override
Called when the node is to be processed.
void prepareToPlay(const tracktion::graph::PlaybackInitialisationInfo &info) override
Called once before playback begins for each node.
void process(ProcessContext &pc) override
Called when the node is to be processed.
std::vector< Node * > getDirectInputNodes() override
Should return all the inputs directly feeding in to this node.
bool isReadyToProcess() override
Should return true when this node is ready to be processed.
NodeProperties getNodeProperties() override
Should return the properties of the node.
Just a simple audio node that doesn't take any input so can be used as a stub.
void process(ProcessContext &pc) override
Called when the node is to be processed.
bool isReadyToProcess() override
Should return true when this node is ready to be processed.
void prepareToPlay(const PlaybackInitialisationInfo &info) override
Called once before playback begins for each node.
NodeProperties getNodeProperties() override
Should return the properties of the node.
NodeProperties getNodeProperties() override
Should return the properties of the node.
bool isReadyToProcess() override
Should return true when this node is ready to be processed.
void prepareToPlay(const PlaybackInitialisationInfo &info) override
Called once before playback begins for each node.
void process(ProcessContext &pc) override
Called when the node is to be processed.
Blocks audio and MIDI input from reaching the outputs.
NodeProperties getNodeProperties() override
Should return the properties of the node.
bool isReadyToProcess() override
Should return true when this node is ready to be processed.
void process(ProcessContext &) override
Called when the node is to be processed.
std::vector< Node * > getDirectInputNodes() override
Should return all the inputs directly feeding in to this node.
TransformResult
Enum to signify the result of the transform function.
Holds some really basic properties of a node.
Passed into Nodes when they are being initialised, to give them useful contextual information that th...