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 (newSampleRate != sampleRate
61 sampleRate = newSampleRate;
63 source->prepareToPlay (samplesPerBlockExpected, newSampleRate);
65 buffer.
setSize (numberOfChannels, bufferSizeNeeded);
79 && (bufferValidEnd - bufferValidStart < jmin (((
int) newSampleRate) / 4, buffer.
getNumSamples() / 2)));
88 buffer.
setSize (numberOfChannels, 0);
94 source->releaseResources();
101 auto start = bufferValidStart.load();
102 auto end = bufferValidEnd.load();
103 auto pos = nextPlayPos.load();
105 auto validStart = (int) (jlimit (start, end, pos) - pos);
106 auto validEnd = (int) (jlimit (start, end, pos + info.
numSamples) - pos);
108 if (validStart == validEnd)
122 if (validStart < validEnd)
127 auto startBufferIndex = (int) ((validStart + nextPlayPos) % buffer.
getNumSamples());
128 auto endBufferIndex = (int) ((validEnd + nextPlayPos) % buffer.
getNumSamples());
130 if (startBufferIndex < endBufferIndex)
134 chan, startBufferIndex,
135 validEnd - validStart);
139 auto initialSize = buffer.
getNumSamples() - startBufferIndex;
143 chan, startBufferIndex,
149 (validEnd - validStart) - initialSize);
160 if (!source || source->getTotalLength() <= 0)
170 auto startTime = now;
172 auto elapsed = (now >= startTime ? now - startTime
173 : (std::numeric_limits<uint32>::max() - startTime) + now);
175 while (elapsed <= timeout)
180 auto start = bufferValidStart.load();
181 auto end = bufferValidEnd.load();
182 auto pos = nextPlayPos.load();
184 auto validStart =
static_cast<int> (jlimit (start, end, pos) - pos);
185 auto validEnd =
static_cast<int> (jlimit (start, end, pos + info.
numSamples) - pos);
187 if (validStart <= 0 && validStart < validEnd && validEnd >= info.
numSamples)
191 if (elapsed < timeout && (! bufferReadyEvent.
wait (
static_cast<int> (timeout - elapsed))))
195 elapsed = (now >= startTime ? now - startTime
196 : (std::numeric_limits<uint32>::max() - startTime) + now);
204 jassert (source->getTotalLength() > 0);
205 auto pos = nextPlayPos.load();
207 return (source->isLooping() && nextPlayPos > 0)
208 ? pos % source->getTotalLength()
216 nextPlayPos = newPosition;
220bool BufferingAudioSource::readNextBufferChunk()
222 int64 newBVS, newBVE, sectionToReadStart, sectionToReadEnd;
230 bufferValidStart = 0;
234 newBVS = jmax ((int64) 0, nextPlayPos.load());
236 sectionToReadStart = 0;
237 sectionToReadEnd = 0;
239 const int maxChunkSize = 2048;
241 if (newBVS < bufferValidStart || newBVS >= bufferValidEnd)
243 newBVE = jmin (newBVE, newBVS + maxChunkSize);
245 sectionToReadStart = newBVS;
246 sectionToReadEnd = newBVE;
248 bufferValidStart = 0;
251 else if (std::abs ((
int) (newBVS - bufferValidStart)) > 512
252 || std::abs ((
int) (newBVE - bufferValidEnd)) > 512)
254 newBVE = jmin (newBVE, bufferValidEnd + maxChunkSize);
256 sectionToReadStart = bufferValidEnd;
257 sectionToReadEnd = newBVE;
259 bufferValidStart = newBVS;
260 bufferValidEnd = jmin (bufferValidEnd.load(), newBVE);
264 if (sectionToReadStart == sectionToReadEnd)
268 auto bufferIndexStart = (int) (sectionToReadStart % buffer.
getNumSamples());
269 auto bufferIndexEnd = (int) (sectionToReadEnd % buffer.
getNumSamples());
271 if (bufferIndexStart < bufferIndexEnd)
273 readBufferSection (sectionToReadStart,
274 (
int) (sectionToReadEnd - sectionToReadStart),
279 auto initialSize = buffer.
getNumSamples() - bufferIndexStart;
281 readBufferSection (sectionToReadStart,
285 readBufferSection (sectionToReadStart + initialSize,
286 (
int) (sectionToReadEnd - sectionToReadStart) - initialSize,
291 const ScopedLock sl2 (bufferStartPosLock);
293 bufferValidStart = newBVS;
294 bufferValidEnd = newBVE;
297 bufferReadyEvent.
signal();
301void BufferingAudioSource::readBufferSection (int64 start,
int length,
int bufferOffset)
303 if (source->getNextReadPosition() != start)
304 source->setNextReadPosition (start);
306 AudioSourceChannelInfo info (&buffer, bufferOffset, length);
307 source->getNextAudioBlock (info);
310int BufferingAudioSource::useTimeSlice()
312 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 isLooping() const override
void releaseResources() override
bool waitForNextAudioBlockReady(const AudioSourceChannelInfo &info, const uint32 timeout)
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(int timeOutMilliseconds=-1) const
void clearActiveBufferRegion() const
AudioBuffer< float > * buffer