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

« « « Anklang Documentation
Loading...
Searching...
No Matches
tracktion_MultiThreadedNodePlayer.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
14namespace tracktion { inline namespace engine
15{
16
17//==============================================================================
18//==============================================================================
23{
24public:
27 : playHeadState (processStateToUse.playHeadState),
28 processState (processStateToUse)
29 {
30 }
31
34 ProcessState& processStateToUse,
35 double sampleRate, int blockSize)
36 : MultiThreadedNodePlayer (processStateToUse)
37 {
38 nodePlayer.setNode (std::move (node), sampleRate, blockSize);
39 }
40
45 void setNumThreads (size_t numThreads)
46 {
47 nodePlayer.setNumThreads (numThreads);
48 }
49
50 tracktion::graph::Node* getNode()
51 {
52 return nodePlayer.getNode();
53 }
54
55 void setNode (std::unique_ptr<tracktion::graph::Node> newNode)
56 {
57 nodePlayer.setNode (std::move (newNode));
58 }
59
60 void setNode (std::unique_ptr<tracktion::graph::Node> newNode, double sampleRateToUse, int blockSizeToUse)
61 {
62 nodePlayer.setNode (std::move (newNode), sampleRateToUse, blockSizeToUse);
63 }
64
65 void prepareToPlay (double sampleRateToUse, int blockSizeToUse)
66 {
67 nodePlayer.prepareToPlay (sampleRateToUse, blockSizeToUse);
68 }
69
74 {
75 int numMisses = 0;
76 playHeadState.playHead.setReferenceSampleRange (pc.referenceSampleRange);
77
78 // Check to see if the timeline needs to be processed in two halves due to looping
79 const auto splitTimelineRange = referenceSampleRangeToSplitTimelineRange (playHeadState.playHead, pc.referenceSampleRange);
80
81 if (splitTimelineRange.isSplit)
82 {
83 const auto firstProportion = splitTimelineRange.timelineRange1.getLength() / (double) pc.referenceSampleRange.getLength();
84
85 const auto firstReferenceRange = pc.referenceSampleRange.withEnd (pc.referenceSampleRange.getStart() + (int64_t) std::llround (pc.referenceSampleRange.getLength() * firstProportion));
86 const auto secondReferenceRange = juce::Range<int64_t> (firstReferenceRange.getEnd(), pc.referenceSampleRange.getEnd());
87 jassert (firstReferenceRange.getLength() + secondReferenceRange.getLength() == pc.referenceSampleRange.getLength());
88
89 const auto firstNumSamples = (choc::buffer::FrameCount) std::llround (pc.numSamples * firstProportion);
90 const auto secondNumSamples = pc.numSamples - firstNumSamples;
91 jassert (firstNumSamples + secondNumSamples == pc.numSamples);
92
93 {
94 auto destAudio = pc.buffers.audio.getStart (firstNumSamples);
95 auto& destMidi = pc.buffers.midi;
96
97 processState.update (nodePlayer.getSampleRate(), firstReferenceRange, ProcessState::UpdateContinuityFlags::yes);
98 tracktion::graph::Node::ProcessContext pc1 { firstNumSamples, firstReferenceRange, { destAudio , destMidi } };
99 numMisses += nodePlayer.process (pc1);
100 }
101
102 {
103 const auto firstDuration = processState.editTimeRange.getLength();
104
105 auto destAudio = pc.buffers.audio.getFrameRange ({ firstNumSamples, firstNumSamples + secondNumSamples });
106 scratchMidi.clear();
107
108 tracktion::graph::Node::ProcessContext pc2 { secondNumSamples, secondReferenceRange, { destAudio, scratchMidi } };
109 processState.update (nodePlayer.getSampleRate(), secondReferenceRange, ProcessState::UpdateContinuityFlags::yes);
110 numMisses += nodePlayer.process (pc2);
111
112 // Merge back MIDI from end of block
113 pc.buffers.midi.mergeFromWithOffset (scratchMidi, firstDuration.inSeconds());
114 }
115 }
116 else
117 {
118 processState.update (nodePlayer.getSampleRate(), pc.referenceSampleRange, ProcessState::UpdateContinuityFlags::yes);
119 numMisses += nodePlayer.process (pc);
120 }
121
122 return numMisses;
123 }
124
127 {
128 nodePlayer.clearNode();
129 }
130
132 double getSampleRate() const
133 {
134 return nodePlayer.getSampleRate();
135 }
136
137private:
138 tracktion::graph::PlayHeadState& playHeadState;
139 ProcessState& processState;
140 MidiMessageArray scratchMidi;
142};
143
144}} // namespace tracktion { inline namespace engine
constexpr ValueType getStart() const noexcept
constexpr ValueType getEnd() const noexcept
constexpr Range withEnd(const ValueType newEnd) const noexcept
constexpr ValueType getLength() const noexcept
Plays back a Node with PlayHeadState and ProcessState.
MultiThreadedNodePlayer(ProcessState &processStateToUse)
Creates an NodePlayer to process a Node.
MultiThreadedNodePlayer(std::unique_ptr< tracktion::graph::Node > node, ProcessState &processStateToUse, double sampleRate, int blockSize)
Creates an NodePlayer to process a Node.
double getSampleRate() const
Returns the current sample rate.
int process(const tracktion::graph::Node::ProcessContext &pc)
Processes a block of audio and MIDI data.
void setNumThreads(size_t numThreads)
Sets the number of threads to use for rendering.
double getSampleRate() const
Returns the current sample rate.
int process(const Node::ProcessContext &)
Process a block of the Node.
void setNode(std::unique_ptr< Node >)
Sets the Node to process.
void prepareToPlay(double sampleRateToUse, int blockSizeToUse)
Prepares the current Node to be played.
void setNumThreads(size_t)
Sets the number of threads to use for rendering.
Main graph Node processor class.
Struct to describe a single iteration of a process call.
Determines how this block releates to other previous render blocks and if the play head has jumped in...
void setReferenceSampleRange(juce::Range< int64_t > sampleRange)
Sets the reference sample count, adjusting the timeline if the play head is playing.
#define jassert(expression)
typedef double
SplitTimelineRange referenceSampleRangeToSplitTimelineRange(const PlayHead &playHead, juce::Range< int64_t > referenceSampleRange)
Converts a reference sample range to a TimelinePositionWindow which could have two time ranges if the...
T llround(T... args)
typedef int64_t
Holds the state of a process call.
void update(double sampleRate, juce::Range< int64_t > referenceSampleRange, UpdateContinuityFlags)
Updates the internal state based on a reference sample range.