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

« « « Anklang Documentation
Loading...
Searching...
No Matches
tracktion_FadeInOutAudioNode.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
14FadeInOutAudioNode::FadeInOutAudioNode (AudioNode* inp,
15 legacy::EditTimeRange in, legacy::EditTimeRange out,
16 AudioFadeCurve::Type fadeInType_,
17 AudioFadeCurve::Type fadeOutType_,
18 bool clearSamplesOutsideFade)
19 : SingleInputAudioNode (inp),
20 fadeIn (in),
21 fadeOut (out),
22 fadeInType (fadeInType_),
23 fadeOutType (fadeOutType_),
24 clearExtraSamples (clearSamplesOutsideFade)
25{
26 jassert (! (fadeIn.isEmpty() && fadeOut.isEmpty()));
27}
28
29FadeInOutAudioNode::~FadeInOutAudioNode()
30{
31}
32
33int FadeInOutAudioNode::timeToSample (const AudioRenderContext& rc, legacy::EditTimeRange editTime, double t)
34{
35 return (int) (rc.bufferNumSamples * (t - editTime.getStart()) / editTime.getLength() + 0.5);
36}
37
38void FadeInOutAudioNode::renderSection (const AudioRenderContext& rc, legacy::EditTimeRange editTime)
39{
40 if (editTime.overlaps (fadeIn) && fadeIn.getLength() > 0.0)
41 {
42 double alpha1 = 0;
43 auto startSamp = timeToSample (rc, editTime, fadeIn.getStart());
44
45 if (startSamp > 0)
46 {
47 if (clearExtraSamples)
48 rc.destBuffer->clear (rc.bufferStartSample, startSamp);
49 }
50 else
51 {
52 alpha1 = (editTime.getStart() - fadeIn.getStart()) / fadeIn.getLength();
53 startSamp = 0;
54 }
55
56 int endSamp;
57 double alpha2;
58
59 if (editTime.getEnd() >= fadeIn.getEnd())
60 {
61 endSamp = timeToSample (rc, editTime, fadeIn.getEnd());
62 alpha2 = 1.0;
63 }
64 else
65 {
66 endSamp = rc.bufferNumSamples;
67 alpha2 = std::max (0.0, (editTime.getEnd() - fadeIn.getStart()) / fadeIn.getLength());
68 }
69
70 if (endSamp > startSamp)
71 AudioFadeCurve::applyCrossfadeSection (*rc.destBuffer,
72 rc.bufferStartSample + startSamp, endSamp - startSamp,
73 fadeInType,
74 (float) alpha1,
75 (float) alpha2);
76 }
77
78 if (editTime.overlaps (fadeOut) && fadeOut.getLength() > 0.0)
79 {
80 double alpha1 = 0;
81 auto startSamp = timeToSample (rc, editTime, fadeOut.getStart());
82
83 if (startSamp <= 0)
84 {
85 startSamp = 0;
86 alpha1 = (editTime.getStart() - fadeOut.getStart()) / fadeOut.getLength();
87 }
88
89 int endSamp;
90 double alpha2;
91
92 if (editTime.getEnd() >= fadeOut.getEnd())
93 {
94 endSamp = timeToSample (rc, editTime, fadeOut.getEnd());
95 alpha2 = 1.0;
96
97 if (clearExtraSamples && endSamp < rc.bufferNumSamples)
98 rc.destBuffer->clear (rc.bufferStartSample + endSamp,
99 rc.bufferNumSamples - endSamp);
100 }
101 else
102 {
103 endSamp = rc.bufferNumSamples;
104 alpha2 = (editTime.getEnd() - fadeOut.getStart()) / fadeOut.getLength();
105 }
106
107 if (endSamp > startSamp)
108 AudioFadeCurve::applyCrossfadeSection (*rc.destBuffer,
109 rc.bufferStartSample + startSamp, endSamp - startSamp,
110 fadeOutType,
111 juce::jlimit (0.0f, 1.0f, (float) (1.0 - alpha1)),
112 juce::jlimit (0.0f, 1.0f, (float) (1.0 - alpha2)));
113 }
114}
115
116bool FadeInOutAudioNode::renderingNeeded (const AudioRenderContext& rc) const
117{
118 if (rc.destBuffer == nullptr || ! rc.playhead.isPlaying())
119 return false;
120
121 auto editTime = rc.getEditTime();
122
123 if (editTime.isSplit)
124 {
125 return fadeIn.overlaps (editTime.editRange1)
126 || fadeIn.overlaps (editTime.editRange2)
127 || fadeOut.overlaps (editTime.editRange1)
128 || fadeOut.overlaps (editTime.editRange2);
129 }
130
131 return fadeIn.overlaps (editTime.editRange1)
132 || fadeOut.overlaps (editTime.editRange1);
133}
134
135void FadeInOutAudioNode::renderOver (const AudioRenderContext& rc)
136{
137 input->renderOver (rc);
138
139 if (renderingNeeded (rc))
140 invokeSplitRender (rc, *this);
141}
142
143void FadeInOutAudioNode::renderAdding (const AudioRenderContext& rc)
144{
145 if (renderingNeeded (rc))
146 callRenderOver (rc);
147 else
148 input->renderAdding (rc);
149}
150
151AudioNode* FadeInOutAudioNode::createForEdit (Edit& edit, AudioNode* source)
152{
153 if (edit.masterFadeIn.get() > 0s || edit.masterFadeOut.get() > 0s)
154 {
155 auto length = edit.getLength();
156
157 return new FadeInOutAudioNode (source,
158 { 0.0, edit.masterFadeIn.get().inSeconds() },
159 { length.inSeconds() - edit.masterFadeOut.get().inSeconds(), length.inSeconds() },
160 edit.masterFadeInType,
161 edit.masterFadeOutType);
162 }
163
164 return source;
165}
166
167}} // namespace tracktion { inline namespace engine
#define jassert(expression)
T max(T... args)
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Type
A enumeration of the curve classes available.