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)
40 jassert (numberOfSamplesToBuffer > 1024);
52 auto bufferSizeNeeded =
jmax (samplesPerBlockExpected * 2, numberOfSamplesToBuffer);
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
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
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;
241 bufferValidStart = 0;
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,
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);
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)
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 and marks the buffer as cleared.
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 waitForNextAudioBlockReady(const AudioSourceChannelInfo &info, uint32 timeout)
A useful function to block until the next the buffer info can be filled.
bool isLooping() const override
Implements the PositionableAudioSource method.
void releaseResources() override
Implementation of the AudioSource method.
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.
Automatically unlocks and re-locks a mutex object.
A type of AudioSource which can be repositioned.
A general-purpose range object, that simply represents any linear range with a start and end point.
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).
void signal() const
Wakes up any threads that are currently waiting on this object.
bool wait(double timeOutMilliseconds=-1.0) const
Suspends the calling thread until the event has been signalled.
CriticalSection::ScopedLockType ScopedLock
Automatically locks and unlocks a CriticalSection object.
constexpr bool approximatelyEqual(Type a, Type b, Tolerance< Type > tolerance=Tolerance< Type >{} .withAbsolute(std::numeric_limits< Type >::min()) .withRelative(std::numeric_limits< Type >::epsilon()))
Returns true if the two floating-point numbers are approximately equal.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Constrains a value to keep it within a given range.
unsigned int uint32
A platform-independent 32-bit unsigned integer type.
long long int64
A platform-independent 64-bit integer type.
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.