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)
Changes the buffer's size or number of channels.
int getNumChannels() const noexcept
Returns the number of channels of audio data that this buffer contains.
int getNumSamples() const noexcept
Returns the number of samples allocated in each of the buffer's channels.
void clear() noexcept
Clears all the samples in all channels.
void copyFrom(int destChannel, int destStartSample, const AudioBuffer &source, int sourceChannel, int sourceStartSample, int numSamples) noexcept
Copies samples from another buffer to this one.
void getNextAudioBlock(const AudioSourceChannelInfo &) override
Implementation of the AudioSource method.
void setNextReadPosition(int64 newPosition) override
Implements the PositionableAudioSource method.
int64 getTotalLength() const override
Implements the PositionableAudioSource method.
~BufferingAudioSource() override
Destructor.
BufferingAudioSource(PositionableAudioSource *source, TimeSliceThread &backgroundThread, bool deleteSourceWhenDeleted, int numberOfSamplesToBuffer, int numberOfChannels=2, bool prefillBufferOnPrepareToPlay=true)
Creates a BufferingAudioSource.
bool isLooping() const override
Implements the PositionableAudioSource method.
void releaseResources() override
Implementation of the AudioSource method.
bool waitForNextAudioBlockReady(const AudioSourceChannelInfo &info, const uint32 timeout)
A useful function to block until the next the buffer info can be filled.
int64 getNextReadPosition() const override
Implements the PositionableAudioSource method.
void prepareToPlay(int samplesPerBlockExpected, double sampleRate) override
Implementation of the AudioSource method.
Automatically locks and unlocks a mutex object.
A type of AudioSource which can be repositioned.
static void JUCE_CALLTYPE sleep(int milliseconds)
Suspends the execution of the current thread until the specified timeout period has elapsed (note tha...
A thread that keeps a list of clients, and calls each one in turn, giving them all a chance to run so...
void removeTimeSliceClient(TimeSliceClient *clientToRemove)
Removes a client from the list.
void addTimeSliceClient(TimeSliceClient *clientToAdd, int millisecondsBeforeStarting=0)
Adds a client to the list.
void moveToFrontOfQueue(TimeSliceClient *clientToMove)
If the given client is waiting in the queue, it will be moved to the front and given a time-slice as ...
static uint32 getMillisecondCounter() noexcept
Returns the number of millisecs since a fixed event (usually system startup).
bool wait(int timeOutMilliseconds=-1) const
Suspends the calling thread until the event has been signalled.
void signal() const
Wakes up any threads that are currently waiting on this object.
Used by AudioSource::getNextAudioBlock().
int numSamples
The number of samples in the buffer which the callback is expected to fill with data.
void clearActiveBufferRegion() const
Convenient method to clear the buffer if the source is not producing any data.
AudioBuffer< float > * buffer
The destination buffer to fill with audio data.
int startSample
The first sample in the buffer from which the callback is expected to write data.