OpenShot Audio Library | OpenShotAudio 0.3.2
Loading...
Searching...
No Matches
juce_BufferingAudioSource.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
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
23namespace juce
24{
25
27 TimeSliceThread& thread,
28 bool deleteSourceWhenDeleted,
30 int numChannels,
32 : source (s, deleteSourceWhenDeleted),
33 backgroundThread (thread),
34 numberOfSamplesToBuffer (jmax (1024, bufferSizeSamples)),
35 numberOfChannels (numChannels),
36 prefillBuffer (prefillBufferOnPrepareToPlay)
37{
38 jassert (source != nullptr);
39
40 jassert (numberOfSamplesToBuffer > 1024); // not much point using this class if you're
41 // not using a larger buffer..
42}
43
48
49//==============================================================================
51{
52 auto bufferSizeNeeded = jmax (samplesPerBlockExpected * 2, numberOfSamplesToBuffer);
53
54 if (newSampleRate != sampleRate
55 || bufferSizeNeeded != buffer.getNumSamples()
56 || ! isPrepared)
57 {
58 backgroundThread.removeTimeSliceClient (this);
59
60 isPrepared = true;
61 sampleRate = newSampleRate;
62
63 source->prepareToPlay (samplesPerBlockExpected, newSampleRate);
64
65 buffer.setSize (numberOfChannels, bufferSizeNeeded);
66 buffer.clear();
67
68 bufferValidStart = 0;
69 bufferValidEnd = 0;
70
71 backgroundThread.addTimeSliceClient (this);
72
73 do
74 {
75 backgroundThread.moveToFrontOfQueue (this);
76 Thread::sleep (5);
77 }
78 while (prefillBuffer
79 && (bufferValidEnd - bufferValidStart < jmin (((int) newSampleRate) / 4, buffer.getNumSamples() / 2)));
80 }
81}
82
84{
85 isPrepared = false;
86 backgroundThread.removeTimeSliceClient (this);
87
88 buffer.setSize (numberOfChannels, 0);
89
90 // MSVC2015 seems to need this if statement to not generate a warning during linking.
91 // As source is set in the constructor, there is no way that source could
92 // ever equal this, but it seems to make MSVC2015 happy.
93 if (source != this)
94 source->releaseResources();
95}
96
98{
99 const ScopedLock sl (bufferStartPosLock);
100
101 auto start = bufferValidStart.load();
102 auto end = bufferValidEnd.load();
103 auto pos = nextPlayPos.load();
104
105 auto validStart = (int) (jlimit (start, end, pos) - pos);
106 auto validEnd = (int) (jlimit (start, end, pos + info.numSamples) - pos);
107
108 if (validStart == validEnd)
109 {
110 // total cache miss
111 info.clearActiveBufferRegion();
112 }
113 else
114 {
115 if (validStart > 0)
116 info.buffer->clear (info.startSample, validStart); // partial cache miss at start
117
118 if (validEnd < info.numSamples)
119 info.buffer->clear (info.startSample + validEnd,
120 info.numSamples - validEnd); // partial cache miss at end
121
122 if (validStart < validEnd)
123 {
124 for (int chan = jmin (numberOfChannels, info.buffer->getNumChannels()); --chan >= 0;)
125 {
126 jassert (buffer.getNumSamples() > 0);
127 auto startBufferIndex = (int) ((validStart + nextPlayPos) % buffer.getNumSamples());
128 auto endBufferIndex = (int) ((validEnd + nextPlayPos) % buffer.getNumSamples());
129
131 {
132 info.buffer->copyFrom (chan, info.startSample + validStart,
133 buffer,
135 validEnd - validStart);
136 }
137 else
138 {
140
141 info.buffer->copyFrom (chan, info.startSample + validStart,
142 buffer,
145
146 info.buffer->copyFrom (chan, info.startSample + validStart + initialSize,
147 buffer,
148 chan, 0,
149 (validEnd - validStart) - initialSize);
150 }
151 }
152 }
153
154 nextPlayPos += info.numSamples;
155 }
156}
157
159{
160 if (!source || source->getTotalLength() <= 0)
161 return false;
162
163 if (nextPlayPos + info.numSamples < 0)
164 return true;
165
166 if (! isLooping() && nextPlayPos > getTotalLength())
167 return true;
168
170 auto startTime = now;
171
172 auto elapsed = (now >= startTime ? now - startTime
173 : (std::numeric_limits<uint32>::max() - startTime) + now);
174
175 while (elapsed <= timeout)
176 {
177 {
178 const ScopedLock sl (bufferStartPosLock);
179
180 auto start = bufferValidStart.load();
181 auto end = bufferValidEnd.load();
182 auto pos = nextPlayPos.load();
183
184 auto validStart = static_cast<int> (jlimit (start, end, pos) - pos);
185 auto validEnd = static_cast<int> (jlimit (start, end, pos + info.numSamples) - pos);
186
187 if (validStart <= 0 && validStart < validEnd && validEnd >= info.numSamples)
188 return true;
189 }
190
191 if (elapsed < timeout && (! bufferReadyEvent.wait (static_cast<int> (timeout - elapsed))))
192 return false;
193
195 elapsed = (now >= startTime ? now - startTime
196 : (std::numeric_limits<uint32>::max() - startTime) + now);
197 }
198
199 return false;
200}
201
203{
204 jassert (source->getTotalLength() > 0);
205 auto pos = nextPlayPos.load();
206
207 return (source->isLooping() && nextPlayPos > 0)
208 ? pos % source->getTotalLength()
209 : pos;
210}
211
213{
214 const ScopedLock sl (bufferStartPosLock);
215
216 nextPlayPos = newPosition;
217 backgroundThread.moveToFrontOfQueue (this);
218}
219
220bool BufferingAudioSource::readNextBufferChunk()
221{
223
224 {
225 const ScopedLock sl (bufferStartPosLock);
226
227 if (wasSourceLooping != isLooping())
228 {
229 wasSourceLooping = isLooping();
230 bufferValidStart = 0;
231 bufferValidEnd = 0;
232 }
233
234 newBVS = jmax ((int64) 0, nextPlayPos.load());
235 newBVE = newBVS + buffer.getNumSamples() - 4;
236 sectionToReadStart = 0;
237 sectionToReadEnd = 0;
238
239 const int maxChunkSize = 2048;
240
241 if (newBVS < bufferValidStart || newBVS >= bufferValidEnd)
242 {
243 newBVE = jmin (newBVE, newBVS + maxChunkSize);
244
245 sectionToReadStart = newBVS;
246 sectionToReadEnd = newBVE;
247
248 bufferValidStart = 0;
249 bufferValidEnd = 0;
250 }
251 else if (std::abs ((int) (newBVS - bufferValidStart)) > 512
252 || std::abs ((int) (newBVE - bufferValidEnd)) > 512)
253 {
254 newBVE = jmin (newBVE, bufferValidEnd + maxChunkSize);
255
256 sectionToReadStart = bufferValidEnd;
257 sectionToReadEnd = newBVE;
258
259 bufferValidStart = newBVS;
260 bufferValidEnd = jmin (bufferValidEnd.load(), newBVE);
261 }
262 }
263
264 if (sectionToReadStart == sectionToReadEnd)
265 return false;
266
267 jassert (buffer.getNumSamples() > 0);
268 auto bufferIndexStart = (int) (sectionToReadStart % buffer.getNumSamples());
269 auto bufferIndexEnd = (int) (sectionToReadEnd % buffer.getNumSamples());
270
271 if (bufferIndexStart < bufferIndexEnd)
272 {
273 readBufferSection (sectionToReadStart,
274 (int) (sectionToReadEnd - sectionToReadStart),
275 bufferIndexStart);
276 }
277 else
278 {
279 auto initialSize = buffer.getNumSamples() - bufferIndexStart;
280
281 readBufferSection (sectionToReadStart,
282 initialSize,
283 bufferIndexStart);
284
285 readBufferSection (sectionToReadStart + initialSize,
286 (int) (sectionToReadEnd - sectionToReadStart) - initialSize,
287 0);
288 }
289
290 {
291 const ScopedLock sl2 (bufferStartPosLock);
292
293 bufferValidStart = newBVS;
294 bufferValidEnd = newBVE;
295 }
296
297 bufferReadyEvent.signal();
298 return true;
299}
300
301void BufferingAudioSource::readBufferSection (int64 start, int length, int bufferOffset)
302{
303 if (source->getNextReadPosition() != start)
304 source->setNextReadPosition (start);
305
306 AudioSourceChannelInfo info (&buffer, bufferOffset, length);
307 source->getNextAudioBlock (info);
308}
309
310int BufferingAudioSource::useTimeSlice()
311{
312 return readNextBufferChunk() ? 1 : 100;
313}
314
315} // namespace juce
void clear()
Definition juce_Array.h:188
void setSize(int newNumChannels, int newNumSamples, bool keepExistingContent=false, bool clearExtraSpace=false, bool avoidReallocating=false)
int getNumSamples() const noexcept
void getNextAudioBlock(const AudioSourceChannelInfo &) override
void setNextReadPosition(int64 newPosition) override
int64 getTotalLength() const override
BufferingAudioSource(PositionableAudioSource *source, TimeSliceThread &backgroundThread, bool deleteSourceWhenDeleted, int numberOfSamplesToBuffer, int numberOfChannels=2, bool prefillBufferOnPrepareToPlay=true)
bool waitForNextAudioBlockReady(const AudioSourceChannelInfo &info, const uint32 timeout)
void prepareToPlay(int samplesPerBlockExpected, double sampleRate) override
static void JUCE_CALLTYPE sleep(int milliseconds)
void removeTimeSliceClient(TimeSliceClient *clientToRemove)
void addTimeSliceClient(TimeSliceClient *clientToAdd, int millisecondsBeforeStarting=0)
void moveToFrontOfQueue(TimeSliceClient *clientToMove)
static uint32 getMillisecondCounter() noexcept
bool wait(int timeOutMilliseconds=-1) const