1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2020 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21 */
22
23 namespace juce
24 {
25
AudioTransportSource()26 AudioTransportSource::AudioTransportSource()
27 {
28 }
29
~AudioTransportSource()30 AudioTransportSource::~AudioTransportSource()
31 {
32 setSource (nullptr);
33 releaseMasterResources();
34 }
35
setSource(PositionableAudioSource * const newSource,int readAheadSize,TimeSliceThread * readAheadThread,double sourceSampleRateToCorrectFor,int maxNumChannels)36 void AudioTransportSource::setSource (PositionableAudioSource* const newSource,
37 int readAheadSize, TimeSliceThread* readAheadThread,
38 double sourceSampleRateToCorrectFor, int maxNumChannels)
39 {
40 if (source == newSource)
41 {
42 if (source == nullptr)
43 return;
44
45 setSource (nullptr, 0, nullptr); // deselect and reselect to avoid releasing resources wrongly
46 }
47
48 readAheadBufferSize = readAheadSize;
49 sourceSampleRate = sourceSampleRateToCorrectFor;
50
51 ResamplingAudioSource* newResamplerSource = nullptr;
52 BufferingAudioSource* newBufferingSource = nullptr;
53 PositionableAudioSource* newPositionableSource = nullptr;
54 AudioSource* newMasterSource = nullptr;
55
56 std::unique_ptr<ResamplingAudioSource> oldResamplerSource (resamplerSource);
57 std::unique_ptr<BufferingAudioSource> oldBufferingSource (bufferingSource);
58 AudioSource* oldMasterSource = masterSource;
59
60 if (newSource != nullptr)
61 {
62 newPositionableSource = newSource;
63
64 if (readAheadSize > 0)
65 {
66 // If you want to use a read-ahead buffer, you must also provide a TimeSliceThread
67 // for it to use!
68 jassert (readAheadThread != nullptr);
69
70 newPositionableSource = newBufferingSource
71 = new BufferingAudioSource (newPositionableSource, *readAheadThread,
72 false, readAheadSize, maxNumChannels);
73 }
74
75 newPositionableSource->setNextReadPosition (0);
76
77 if (sourceSampleRateToCorrectFor > 0)
78 newMasterSource = newResamplerSource
79 = new ResamplingAudioSource (newPositionableSource, false, maxNumChannels);
80 else
81 newMasterSource = newPositionableSource;
82
83 if (isPrepared)
84 {
85 if (newResamplerSource != nullptr && sourceSampleRate > 0 && sampleRate > 0)
86 newResamplerSource->setResamplingRatio (sourceSampleRate / sampleRate);
87
88 newMasterSource->prepareToPlay (blockSize, sampleRate);
89 }
90 }
91
92 {
93 const ScopedLock sl (callbackLock);
94
95 source = newSource;
96 resamplerSource = newResamplerSource;
97 bufferingSource = newBufferingSource;
98 masterSource = newMasterSource;
99 positionableSource = newPositionableSource;
100
101 inputStreamEOF = false;
102 playing = false;
103 }
104
105 if (oldMasterSource != nullptr)
106 oldMasterSource->releaseResources();
107 }
108
start()109 void AudioTransportSource::start()
110 {
111 if ((! playing) && masterSource != nullptr)
112 {
113 {
114 const ScopedLock sl (callbackLock);
115 playing = true;
116 stopped = false;
117 inputStreamEOF = false;
118 }
119
120 sendChangeMessage();
121 }
122 }
123
stop()124 void AudioTransportSource::stop()
125 {
126 if (playing)
127 {
128 playing = false;
129
130 int n = 500;
131 while (--n >= 0 && ! stopped)
132 Thread::sleep (2);
133
134 sendChangeMessage();
135 }
136 }
137
setPosition(double newPosition)138 void AudioTransportSource::setPosition (double newPosition)
139 {
140 if (sampleRate > 0.0)
141 setNextReadPosition ((int64) (newPosition * sampleRate));
142 }
143
getCurrentPosition() const144 double AudioTransportSource::getCurrentPosition() const
145 {
146 if (sampleRate > 0.0)
147 return (double) getNextReadPosition() / sampleRate;
148
149 return 0.0;
150 }
151
getLengthInSeconds() const152 double AudioTransportSource::getLengthInSeconds() const
153 {
154 if (sampleRate > 0.0)
155 return (double) getTotalLength() / sampleRate;
156
157 return 0.0;
158 }
159
setNextReadPosition(int64 newPosition)160 void AudioTransportSource::setNextReadPosition (int64 newPosition)
161 {
162 if (positionableSource != nullptr)
163 {
164 if (sampleRate > 0 && sourceSampleRate > 0)
165 newPosition = (int64) ((double) newPosition * sourceSampleRate / sampleRate);
166
167 positionableSource->setNextReadPosition (newPosition);
168
169 if (resamplerSource != nullptr)
170 resamplerSource->flushBuffers();
171
172 inputStreamEOF = false;
173 }
174 }
175
getNextReadPosition() const176 int64 AudioTransportSource::getNextReadPosition() const
177 {
178 if (positionableSource != nullptr)
179 {
180 const double ratio = (sampleRate > 0 && sourceSampleRate > 0) ? sampleRate / sourceSampleRate : 1.0;
181 return (int64) ((double) positionableSource->getNextReadPosition() * ratio);
182 }
183
184 return 0;
185 }
186
getTotalLength() const187 int64 AudioTransportSource::getTotalLength() const
188 {
189 const ScopedLock sl (callbackLock);
190
191 if (positionableSource != nullptr)
192 {
193 const double ratio = (sampleRate > 0 && sourceSampleRate > 0) ? sampleRate / sourceSampleRate : 1.0;
194 return (int64) ((double) positionableSource->getTotalLength() * ratio);
195 }
196
197 return 0;
198 }
199
isLooping() const200 bool AudioTransportSource::isLooping() const
201 {
202 const ScopedLock sl (callbackLock);
203 return positionableSource != nullptr && positionableSource->isLooping();
204 }
205
setGain(const float newGain)206 void AudioTransportSource::setGain (const float newGain) noexcept
207 {
208 gain = newGain;
209 }
210
prepareToPlay(int samplesPerBlockExpected,double newSampleRate)211 void AudioTransportSource::prepareToPlay (int samplesPerBlockExpected, double newSampleRate)
212 {
213 const ScopedLock sl (callbackLock);
214
215 sampleRate = newSampleRate;
216 blockSize = samplesPerBlockExpected;
217
218 if (masterSource != nullptr)
219 masterSource->prepareToPlay (samplesPerBlockExpected, sampleRate);
220
221 if (resamplerSource != nullptr && sourceSampleRate > 0)
222 resamplerSource->setResamplingRatio (sourceSampleRate / sampleRate);
223
224 inputStreamEOF = false;
225 isPrepared = true;
226 }
227
releaseMasterResources()228 void AudioTransportSource::releaseMasterResources()
229 {
230 const ScopedLock sl (callbackLock);
231
232 if (masterSource != nullptr)
233 masterSource->releaseResources();
234
235 isPrepared = false;
236 }
237
releaseResources()238 void AudioTransportSource::releaseResources()
239 {
240 releaseMasterResources();
241 }
242
getNextAudioBlock(const AudioSourceChannelInfo & info)243 void AudioTransportSource::getNextAudioBlock (const AudioSourceChannelInfo& info)
244 {
245 const ScopedLock sl (callbackLock);
246
247 if (masterSource != nullptr && ! stopped)
248 {
249 masterSource->getNextAudioBlock (info);
250
251 if (! playing)
252 {
253 // just stopped playing, so fade out the last block..
254 for (int i = info.buffer->getNumChannels(); --i >= 0;)
255 info.buffer->applyGainRamp (i, info.startSample, jmin (256, info.numSamples), 1.0f, 0.0f);
256
257 if (info.numSamples > 256)
258 info.buffer->clear (info.startSample + 256, info.numSamples - 256);
259 }
260
261 if (positionableSource->getNextReadPosition() > positionableSource->getTotalLength() + 1
262 && ! positionableSource->isLooping())
263 {
264 playing = false;
265 inputStreamEOF = true;
266 sendChangeMessage();
267 }
268
269 stopped = ! playing;
270
271 for (int i = info.buffer->getNumChannels(); --i >= 0;)
272 info.buffer->applyGainRamp (i, info.startSample, info.numSamples, lastGain, gain);
273 }
274 else
275 {
276 info.clearActiveBufferRegion();
277 stopped = true;
278 }
279
280 lastGain = gain;
281 }
282
283 } // namespace juce
284