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