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

« « « Anklang Documentation
Loading...
Searching...
No Matches
tracktion_AudioNode.h
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
11#pragma once
12
13#include "tracktion_PlayHead.h"
15
16namespace tracktion { inline namespace engine
17{
18
19class AudioNode;
20
21
24{
25 bool hasAudio;
26 bool hasMidi;
27 int numberOfChannels;
28};
29
30//==============================================================================
35{
36 double startTime;
37 double sampleRate;
38 int blockSizeSamples;
39 const juce::Array<AudioNode*>* rootNodes;
40 PlayHead& playhead;
41};
42
43//==============================================================================
48{
49 const juce::Array<Clip*>* allowedClips = nullptr;
50 const juce::BigInteger* allowedTracks = nullptr;
51 AudioNode* audioNodeToBeReplaced = nullptr;
52 bool forRendering = false;
53 bool includePlugins = true;
54 bool addAntiDenormalisationNoise = false;
55};
56
57//==============================================================================
71{
72 //==============================================================================
73 inline AudioRenderContext (PlayHead& ph, legacy::EditTimeRange stream,
75 const juce::AudioChannelSet& bufferChannels,
76 int bufferStart, int bufferSize,
77 MidiMessageArray* midiBuffer, double midiOffset,
78 int continuityFlags, bool rendering) noexcept
79 : playhead (ph), streamTime (stream),
80 destBuffer (buffer), destBufferChannels (bufferChannels),
81 bufferStartSample (bufferStart), bufferNumSamples (bufferSize),
82 bufferForMidiMessages (midiBuffer), midiBufferOffset (midiOffset),
83 continuity (continuityFlags), isRendering (rendering)
84 {}
85
86 AudioRenderContext (const AudioRenderContext&) = default;
88 AudioRenderContext& operator= (const AudioRenderContext&) = delete;
89 AudioRenderContext& operator= (AudioRenderContext&&) = delete;
90
91 //==============================================================================
96
103
108
111
114
117
122
125
128 {
129 contiguous = 1,
130 playheadJumped = 2,
131 lastBlockBeforeLoop = 4,
132 firstBlockOfLoop = 8
133 };
134
139
140 bool isContiguousWithPreviousBlock() const noexcept { return (continuity & contiguous) != 0; }
141 bool isFirstBlockOfLoop() const noexcept { return (continuity & firstBlockOfLoop) != 0; }
142 bool isLastBlockOfLoop() const noexcept { return (continuity & lastBlockBeforeLoop) != 0; }
143 bool didPlayheadJump() const noexcept { return (continuity & playheadJumped) != 0; }
144
147
148 //==============================================================================
151
153 void clearAudioBuffer() const noexcept;
155 void clearMidiBuffer() const noexcept;
157 void clearAll() const noexcept;
159 void addAntiDenormalisationNoise() const noexcept;
160
162 void sanityCheck() const
163 {
164 jassert (destBuffer == nullptr || bufferStartSample + bufferNumSamples <= destBuffer->getNumSamples());
165 }
166};
167
168//==============================================================================
173{
174public:
175 //==============================================================================
176 AudioNode();
177 virtual ~AudioNode();
178
179 //==============================================================================
180 virtual void getAudioNodeProperties (AudioNodeProperties&) = 0;
181
186
191 virtual bool purgeSubNodes (bool keepAudio, bool keepMidi) = 0;
192
195 virtual void releaseAudioNodeResources() = 0;
196
197 //==============================================================================
198 using VisitorFn = std::function<void(AudioNode&)>;
199 virtual void visitNodes (const VisitorFn&) = 0;
200
201 virtual juce::ReferenceCountedObjectPtr<Plugin> getPlugin() const { return {}; }
202
203 // called before renderOver/Adding, to allow prefetching, etc
204 virtual void prepareForNextBlock (const AudioRenderContext&) {}
205 virtual bool isReadyToRender() = 0;
206
207 virtual void renderOver (const AudioRenderContext&) = 0;
208 virtual void renderAdding (const AudioRenderContext&) = 0;
209
210 void callRenderAdding (const AudioRenderContext&);
211 void callRenderOver (const AudioRenderContext&);
212
213 //==============================================================================
214 template <typename CallbackType>
215 static void invokeSplitRender (const AudioRenderContext& rc, CallbackType& target)
216 {
217 const PlayHead::EditTimeWindow editTime (rc.getEditTime());
218
219 if (editTime.isSplit)
220 {
221 AudioRenderContext rc2 (rc);
222
223 auto firstLen = editTime.editRange1.getLength();
224 auto firstSamps = juce::jmin (rc.bufferNumSamples,
225 (int) (firstLen * rc.bufferNumSamples / rc.streamTime.getLength()));
226
227 rc2.streamTime = rc2.streamTime.withLength (firstLen);
228 rc2.bufferNumSamples = firstSamps;
229 rc2.continuity |= AudioRenderContext::lastBlockBeforeLoop;
230
231 target.renderSection (rc2, editTime.editRange1);
232
233 rc2.streamTime = { rc2.streamTime.getEnd(), rc.streamTime.getEnd() };
234 rc2.bufferStartSample += firstSamps;
235 rc2.bufferNumSamples = rc.bufferNumSamples - firstSamps;
236 rc2.midiBufferOffset += firstLen;
237 rc2.continuity = AudioRenderContext::firstBlockOfLoop;
238
239 target.renderSection (rc2, editTime.editRange2);
240 }
241 else if (rc.playhead.isLooping() && ! rc.playhead.isRollingIntoLoop())
242 {
243 // In the case where looping happens to line up exactly with the audio
244 // blocks being rendered, set the proper continuity flags
245 AudioRenderContext rc2(rc);
246
247 auto loop = rc.playhead.getLoopTimes();
248
249 auto s = editTime.editRange1.getStart();
250 auto e = editTime.editRange1.getEnd();
251
252 if (e >= loop.getEnd() - 0.000001)
253 rc2.continuity |= AudioRenderContext::lastBlockBeforeLoop;
254 if (s <= loop.getStart() + 0.000001)
255 rc2.continuity = AudioRenderContext::firstBlockOfLoop;
256
257 target.renderSection (rc2, editTime.editRange1);
258 }
259 else
260 {
261 target.renderSection (rc, editTime.editRange1);
262 }
263 }
264
265private:
266 void callRenderOverForMidi (const AudioRenderContext&);
267
269};
270
271//==============================================================================
273{
274public:
276
277 void getAudioNodeProperties (AudioNodeProperties&) override;
278 void visitNodes (const VisitorFn&) override;
280 juce::ReferenceCountedObjectPtr<Plugin> getPlugin() const override;
281 bool isReadyToRender() override;
282 bool purgeSubNodes (bool keepAudio, bool keepMidi) override;
283 void releaseAudioNodeResources() override;
284 void prepareForNextBlock (const AudioRenderContext&) override;
285 void renderOver (const AudioRenderContext&) override;
286 void renderAdding (const AudioRenderContext&) override;
287
288 const std::unique_ptr<AudioNode> input;
289
290private:
291 SingleInputAudioNode() = delete;
293};
294
295//==============================================================================
297{
298 MuteAudioNode (AudioNode* source) : SingleInputAudioNode (source) {}
299
300 void renderOver (const AudioRenderContext& rc) override
301 {
302 input->renderAdding (rc);
303 rc.clearAll();
304 }
305
306 void renderAdding (const AudioRenderContext& rc) override
307 {
308 callRenderOver (rc);
309 }
310};
311
312}} // namespace tracktion { inline namespace engine
Base class for nodes in an audio playback graph.
virtual void releaseAudioNodeResources()=0
tells the node that play has stopped, and it can free up anything it no longer needs.
virtual bool purgeSubNodes(bool keepAudio, bool keepMidi)=0
Tells the node to delete any sub-nodes that don't produce the required type of output.
virtual void prepareAudioNodeToPlay(const PlaybackInitialisationInfo &)=0
tells the node to initialise itself ready for playing from the given time.
void prepareAudioNodeToPlay(const PlaybackInitialisationInfo &) override
tells the node to initialise itself ready for playing from the given time.
void releaseAudioNodeResources() override
tells the node that play has stopped, and it can free up anything it no longer needs.
bool purgeSubNodes(bool keepAudio, bool keepMidi) override
Tells the node to delete any sub-nodes that don't produce the required type of output.
#define jassert(expression)
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
constexpr Type jmin(Type a, Type b)
Holds some really basic properties of a node.
A collection of settings that are generally needed when asking edit model objects to create AudioNode...
Passed into AudioNodes when they are being initialised, to give them useful contextual information th...
juce::AudioChannelSet destBufferChannels
A description of the type of channels in each of the channels in destBuffer.
bool isRendering
True if the rendering is happening as part of an offline render rather than live playback.
int bufferNumSamples
The number of samples to write into the audio buffer.
void addAntiDenormalisationNoise() const noexcept
Applies low-level noise to the audio buffer.
MidiMessageArray * bufferForMidiMessages
A buffer of MIDI events to process.
void clearAll() const noexcept
Clears the active section of all channels in the audio and MIDI buffers.
int bufferStartSample
The index of the start point in the audio buffer from which data must be written.
void sanityCheck() const
Does a quick check on the bounds of various values in the structure.
PlayHead & playhead
The playhead provides information about current time, tempo etc at the block being rendered.
juce::AudioBuffer< float > * destBuffer
The target audio buffer which needs to be filled.
void clearAudioBuffer() const noexcept
Clears the active section of all channels in the audio buffer.
double midiBufferOffset
A time offset to add to the timestamp of any events in the MIDI buffer.
PlayHead::EditTimeWindow getEditTime() const
Returns the section of the edit that needs to be rendered by this block.
void clearMidiBuffer() const noexcept
Clears the active section of the MIDI buffer.
int continuity
A set of flags to indicate what the relationship is between this block and the previous one.
ContinuityFlags
Values used in the AudioRenderContext::continuity variable.
legacy::EditTimeRange streamTime
The time window which needs to be rendered into the current block.