28 bool deleteSourceWhenDeleted,
29 int bufferSizeSamples,
31 bool prefillBufferOnPrepareToPlay)
32 : source (s, deleteSourceWhenDeleted),
33 backgroundThread (thread),
34 numberOfSamplesToBuffer (jmax (1024, bufferSizeSamples)),
35 numberOfChannels (numChannels),
36 prefillBuffer (prefillBufferOnPrepareToPlay)
38 jassert (source !=
nullptr);
40 jassert (numberOfSamplesToBuffer > 1024);
52 auto bufferSizeNeeded = jmax (samplesPerBlockExpected * 2, numberOfSamplesToBuffer);
54 if (! approximatelyEqual (newSampleRate, sampleRate)
61 sampleRate = newSampleRate;
63 source->prepareToPlay (samplesPerBlockExpected, newSampleRate);
65 buffer.
setSize (numberOfChannels, bufferSizeNeeded);
83 && (bufferValidEnd - bufferValidStart < jmin (((
int) newSampleRate) / 4, buffer.
getNumSamples() / 2)));
92 buffer.
setSize (numberOfChannels, 0);
98 source->releaseResources();
103 const auto bufferRange = getValidBufferRange (info.
numSamples);
105 if (bufferRange.isEmpty())
112 const auto validStart = bufferRange.getStart();
113 const auto validEnd = bufferRange.getEnd();
124 if (validStart < validEnd)
130 const auto startBufferIndex = (int) ((validStart + nextPlayPos) % buffer.
getNumSamples());
131 const auto endBufferIndex = (int) ((validEnd + nextPlayPos) % buffer.
getNumSamples());
133 if (startBufferIndex < endBufferIndex)
137 chan, startBufferIndex,
138 validEnd - validStart);
142 const auto initialSize = buffer.
getNumSamples() - startBufferIndex;
146 chan, startBufferIndex,
152 (validEnd - validStart) - initialSize);
162 if (source ==
nullptr || source->getTotalLength() <= 0)
170 auto now = startTime;
172 auto elapsed = (now >= startTime ? now - startTime
173 : (std::numeric_limits<uint32>::max() - startTime) + now);
175 while (elapsed <= timeout)
177 const auto bufferRange = getValidBufferRange (info.
numSamples);
179 const auto validStart = bufferRange.getStart();
180 const auto validEnd = bufferRange.getEnd();
183 && validStart < validEnd
189 if (elapsed < timeout
190 && ! bufferReadyEvent.
wait (
static_cast<int> (timeout - elapsed)))
196 elapsed = (now >= startTime ? now - startTime
197 : (std::numeric_limits<uint32>::max() - startTime) + now);
205 jassert (source->getTotalLength() > 0);
206 const auto pos = nextPlayPos.load();
208 return (source->isLooping() && nextPlayPos > 0)
209 ? pos % source->getTotalLength()
217 nextPlayPos = newPosition;
221Range<int> BufferingAudioSource::getValidBufferRange (
int numSamples)
const
225 const auto pos = nextPlayPos.load();
227 return { (int) (jlimit (bufferValidStart, bufferValidEnd, pos) - pos),
228 (int) (jlimit (bufferValidStart, bufferValidEnd, pos + numSamples) - pos) };
231bool BufferingAudioSource::readNextBufferChunk()
233 int64 newBVS, newBVE, sectionToReadStart, sectionToReadEnd;
236 const ScopedLock sl (bufferRangeLock);
241 bufferValidStart = 0;
245 newBVS = jmax ((int64) 0, nextPlayPos.load());
247 sectionToReadStart = 0;
248 sectionToReadEnd = 0;
250 constexpr int maxChunkSize = 2048;
252 if (newBVS < bufferValidStart || newBVS >= bufferValidEnd)
254 newBVE = jmin (newBVE, newBVS + maxChunkSize);
256 sectionToReadStart = newBVS;
257 sectionToReadEnd = newBVE;
259 bufferValidStart = 0;
262 else if (std::abs ((
int) (newBVS - bufferValidStart)) > 512
263 || std::abs ((
int) (newBVE - bufferValidEnd)) > 512)
265 newBVE = jmin (newBVE, bufferValidEnd + maxChunkSize);
267 sectionToReadStart = bufferValidEnd;
268 sectionToReadEnd = newBVE;
270 bufferValidStart = newBVS;
271 bufferValidEnd = jmin (bufferValidEnd, newBVE);
275 if (sectionToReadStart == sectionToReadEnd)
280 const auto bufferIndexStart = (int) (sectionToReadStart % buffer.
getNumSamples());
281 const auto bufferIndexEnd = (int) (sectionToReadEnd % buffer.
getNumSamples());
283 if (bufferIndexStart < bufferIndexEnd)
285 readBufferSection (sectionToReadStart,
286 (
int) (sectionToReadEnd - sectionToReadStart),
291 const auto initialSize = buffer.
getNumSamples() - bufferIndexStart;
293 readBufferSection (sectionToReadStart,
297 readBufferSection (sectionToReadStart + initialSize,
298 (
int) (sectionToReadEnd - sectionToReadStart) - initialSize,
303 const ScopedLock sl2 (bufferRangeLock);
305 bufferValidStart = newBVS;
306 bufferValidEnd = newBVE;
309 bufferReadyEvent.
signal();
313void BufferingAudioSource::readBufferSection (int64 start,
int length,
int bufferOffset)
315 if (source->getNextReadPosition() != start)
316 source->setNextReadPosition (start);
318 AudioSourceChannelInfo info (&buffer, bufferOffset, length);
320 const ScopedLock sl (callbackLock);
321 source->getNextAudioBlock (info);
324int BufferingAudioSource::useTimeSlice()
326 return readNextBufferChunk() ? 1 : 100;
void setSize(int newNumChannels, int newNumSamples, bool keepExistingContent=false, bool clearExtraSpace=false, bool avoidReallocating=false)
int getNumChannels() const noexcept
int getNumSamples() const noexcept
void copyFrom(int destChannel, int destStartSample, const AudioBuffer &source, int sourceChannel, int sourceStartSample, int numSamples) noexcept
void getNextAudioBlock(const AudioSourceChannelInfo &) override
void setNextReadPosition(int64 newPosition) override
int64 getTotalLength() const override
~BufferingAudioSource() override
BufferingAudioSource(PositionableAudioSource *source, TimeSliceThread &backgroundThread, bool deleteSourceWhenDeleted, int numberOfSamplesToBuffer, int numberOfChannels=2, bool prefillBufferOnPrepareToPlay=true)
bool waitForNextAudioBlockReady(const AudioSourceChannelInfo &info, uint32 timeout)
bool isLooping() const override
void releaseResources() override
int64 getNextReadPosition() const override
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(double timeOutMilliseconds=-1.0) const
void clearActiveBufferRegion() const
AudioBuffer< float > * buffer