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

« « « Anklang Documentation
Loading...
Searching...
No Matches
tracktion_RackReturnNode.cpp
Go to the documentation of this file.
1 /*
2 ,--. ,--. ,--. ,--.
3 ,-' '-.,--.--.,--,--.,---.| |,-.,-' '-.`--' ,---. ,--,--, Copyright 2024
4 '-. .-'| .--' ,-. | .--'| /'-. .-',--.| .-. || \ Tracktion Software
5 | | | | \ '-' \ `--.| \ \ | | | |' '-' '| || | Corporation
6 `---' `--' `--`--'`---'`--'`--' `---' `--' `---' `--''--' www.tracktion.com
7
8 Tracktion Engine uses a GPL/commercial licence - see LICENCE.md for details.
9*/
10
11namespace tracktion { inline namespace engine
12{
13
15 std::function<float()> wetGainFunc,
16 Node* dryNode,
17 std::function<float()> dryGainFunc)
18 : wetInput (std::move (wetNode)),
19 dryInput (dryNode),
20 wetGainFunction (std::move (wetGainFunc)),
21 dryGainFunction (std::move (dryGainFunc))
22{
23 assert (wetInput);
24 assert (wetGainFunction);
25 assert (dryInput);
26 assert (dryGainFunction);
27
28 lastWetGain = wetGainFunction();
29 lastDryGain = dryGainFunction();
30}
31
33{
34 return { wetInput.get(), dryInput };
35}
36
38{
39 auto wetProps = wetInput->getNodeProperties();
40 auto dryProps = dryInput->getNodeProperties();
41
42 auto props = wetProps;
43 props.hasAudio = true;
44 props.numberOfChannels = std::max (wetProps.numberOfChannels, dryProps.numberOfChannels);
45 props.latencyNumSamples = std::max (wetProps.latencyNumSamples, dryProps.latencyNumSamples);
46 hash_combine (props.nodeID, dryProps.nodeID);
47
48 constexpr size_t rackReturnNodeMagicHash = size_t (0x726b52657475726e);
49
50 if (props.nodeID != 0)
51 hash_combine (props.nodeID, rackReturnNodeMagicHash);
52
53 return props;
54}
55
57{
58 if (hasTransformed)
59 return TransformResult::none;
60
61 hasTransformed = true;
62 auto wetProps = wetInput->getNodeProperties();
63 auto dryProps = dryInput->getNodeProperties();
64 assert (dryProps.latencyNumSamples <= wetProps.latencyNumSamples);
65
66 if (wetProps.latencyNumSamples > dryProps.latencyNumSamples)
67 {
68 const int numLatencySamples = wetProps.latencyNumSamples - dryProps.latencyNumSamples;
69 dryLatencyNode = tracktion::graph::makeNode<tracktion::graph::LatencyNode> (dryInput, numLatencySamples);
70 dryInput = dryLatencyNode.get();
71
72 return TransformResult::connectionsMade;
73 }
74
75 return TransformResult::none;
76}
77
79{
80 if (wetInput->numOutputNodes > 1)
81 return;
82
83 const auto inputNumChannels = wetInput->getNodeProperties().numberOfChannels;
84 const auto desiredNumChannels = getNodeProperties().numberOfChannels;
85
86 if (inputNumChannels >= desiredNumChannels)
87 {
88 canUseWetSourceBuffers = true;
89 setOptimisations ({ tracktion::graph::ClearBuffers::no,
90 tracktion::graph::AllocateAudioBuffer::no });
91 }
92}
93
95{
96 return wetInput->hasProcessed() && dryInput->hasProcessed();
97}
98
99void RackReturnNode::preProcess (choc::buffer::FrameCount, juce::Range<int64_t>)
100{
101 if (canUseWetSourceBuffers)
102 setBufferViewToUse (wetInput.get(), wetInput->getProcessedOutput().audio);
103}
104
106{
107 auto destAudio = pc.buffers.audio;
108
109 auto wetSource = wetInput->getProcessedOutput();
110 auto drySource = dryInput->getProcessedOutput();
111
112 assert (destAudio.getNumFrames() == wetSource.audio.getNumFrames());
113 assert (wetSource.audio.getNumFrames() == drySource.audio.getNumFrames());
114
115 const float wetGain = wetGainFunction();
116 const float dryGain = dryGainFunction();
117
118
119 // Always copy MIDI (N.B. MIDI is always the wet signal with no gain applied)
120 pc.buffers.midi.copyFrom (wetSource.midi);
121
122
123 // Copy wet audio applying gain
124 copyIfNotAliased (destAudio.getFirstChannels (wetSource.audio.getNumChannels()),
125 wetSource.audio);
126
127 if (wetGain == lastWetGain)
128 {
129 if (wetGain != 1.0f)
130 applyGain (destAudio, wetGain);
131 }
132 else
133 {
134 const auto step = (wetGain - lastWetGain) / destAudio.getNumFrames();
135 applyGainPerFrame (destAudio, [start = lastWetGain, step]() mutable { return start += step; });
136
137 lastWetGain = wetGain;
138 }
139
140
141 // Add dry audio applying gain
142 auto dryDestView = destAudio.getFirstChannels (drySource.audio.getNumChannels());
143
144 if (dryGain == lastDryGain)
145 {
146 if (dryGain == 1.0f)
147 add (dryDestView, drySource.audio);
148 else
149 tracktion::graph::add (dryDestView, drySource.audio, dryGain);
150 }
151 else
152 {
153 tracktion::graph::addApplyingGainRamp (dryDestView, drySource.audio, lastDryGain, dryGain);
154 lastDryGain = dryGain;
155 }
156}
157
158}} // namespace tracktion { inline namespace engine
assert
tracktion::graph::NodeProperties getNodeProperties() override
Should return the properties of the node.
void preProcess(choc::buffer::FrameCount, juce::Range< int64_t >) override
Called when the node is to be processed, just before process.
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.
RackReturnNode(std::unique_ptr< Node > wetNode, std::function< float()> wetGainFunc, Node *dryNode, std::function< float()> dryGainFunc)
Creates a RackInstanceNode that maps an input node channel to an output channel and applies a gain pa...
std::vector< Node * > getDirectInputNodes() override
Should return all the inputs directly feeding in to this node.
void prepareToPlay(const tracktion::graph::PlaybackInitialisationInfo &) override
Called once before playback begins for each node.
TransformResult transform(Node &, const std::vector< Node * > &, TransformCache &) override
Called after construction to give the node a chance to modify its topology.
Main graph Node processor class.
virtual NodeProperties getNodeProperties()=0
Should return the properties of the node.
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.
bool hasProcessed() const
Returns true if this node has processed and its outputs can be retrieved.
AudioAndMidiBuffer getProcessedOutput()
Returns the processed audio and MIDI output.
Struct to describe a single iteration of a process call.
T max(T... args)
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...
typedef size_t