Updated the buffering audio source from the new JUCE code that removed the use of volatile

This commit is contained in:
xenakios 2018-05-01 15:11:45 +03:00
parent c4b2ead50d
commit 9afca36d64
2 changed files with 66 additions and 63 deletions

View File

@ -24,20 +24,14 @@
MyBufferingAudioSource::MyBufferingAudioSource(PositionableAudioSource* s, MyBufferingAudioSource::MyBufferingAudioSource(PositionableAudioSource* s,
TimeSliceThread& thread, TimeSliceThread& thread,
const bool deleteSourceWhenDeleted, bool deleteSourceWhenDeleted,
const int bufferSizeSamples, int bufferSizeSamples,
const int numChannels, int numChannels,
bool prefillBufferOnPrepareToPlay) bool prefillBufferOnPrepareToPlay)
: source (s, deleteSourceWhenDeleted), : source (s, deleteSourceWhenDeleted),
backgroundThread (thread), backgroundThread (thread),
numberOfSamplesToBuffer (jmax (1024, bufferSizeSamples)), numberOfSamplesToBuffer (jmax (1024, bufferSizeSamples)),
numberOfChannels (numChannels), numberOfChannels (numChannels),
bufferValidStart (0),
bufferValidEnd (0),
nextPlayPos (0),
sampleRate (0),
wasSourceLooping (false),
isPrepared (false),
prefillBuffer (prefillBufferOnPrepareToPlay) prefillBuffer (prefillBufferOnPrepareToPlay)
{ {
jassert (source != nullptr); jassert (source != nullptr);
@ -54,7 +48,7 @@ MyBufferingAudioSource::~MyBufferingAudioSource()
//============================================================================== //==============================================================================
void MyBufferingAudioSource::prepareToPlay (int samplesPerBlockExpected, double newSampleRate) void MyBufferingAudioSource::prepareToPlay (int samplesPerBlockExpected, double newSampleRate)
{ {
const int bufferSizeNeeded = jmax (samplesPerBlockExpected * 2, numberOfSamplesToBuffer); auto bufferSizeNeeded = jmax (samplesPerBlockExpected * 2, numberOfSamplesToBuffer);
if (newSampleRate != sampleRate if (newSampleRate != sampleRate
|| bufferSizeNeeded != buffer.getNumSamples() || bufferSizeNeeded != buffer.getNumSamples()
@ -103,8 +97,12 @@ void MyBufferingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& in
{ {
const ScopedLock sl (bufferStartPosLock); const ScopedLock sl (bufferStartPosLock);
const int validStart = (int) (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos) - nextPlayPos); auto start = bufferValidStart.load();
const int validEnd = (int) (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos + info.numSamples) - nextPlayPos); auto end = bufferValidEnd.load();
auto pos = nextPlayPos.load();
auto validStart = (int) (jlimit (start, end, pos) - pos);
auto validEnd = (int) (jlimit (start, end, pos + info.numSamples) - pos);
if (validStart == validEnd) if (validStart == validEnd)
{ {
@ -125,8 +123,8 @@ void MyBufferingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& in
for (int chan = jmin (numberOfChannels, info.buffer->getNumChannels()); --chan >= 0;) for (int chan = jmin (numberOfChannels, info.buffer->getNumChannels()); --chan >= 0;)
{ {
jassert (buffer.getNumSamples() > 0); jassert (buffer.getNumSamples() > 0);
const int startBufferIndex = (int) ((validStart + nextPlayPos) % buffer.getNumSamples()); auto startBufferIndex = (int) ((validStart + nextPlayPos) % buffer.getNumSamples());
const int endBufferIndex = (int) ((validEnd + nextPlayPos) % buffer.getNumSamples()); auto endBufferIndex = (int) ((validEnd + nextPlayPos) % buffer.getNumSamples());
if (startBufferIndex < endBufferIndex) if (startBufferIndex < endBufferIndex)
{ {
@ -137,7 +135,7 @@ void MyBufferingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& in
} }
else else
{ {
const int initialSize = buffer.getNumSamples() - startBufferIndex; auto initialSize = buffer.getNumSamples() - startBufferIndex;
info.buffer->copyFrom (chan, info.startSample + validStart, info.buffer->copyFrom (chan, info.startSample + validStart,
buffer, buffer,
@ -156,7 +154,7 @@ void MyBufferingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& in
} }
} }
bool MyBufferingAudioSource::waitForNextAudioBlockReady (const AudioSourceChannelInfo& info, const uint32 timeout) bool MyBufferingAudioSource::waitForNextAudioBlockReady (const AudioSourceChannelInfo& info, uint32 timeout)
{ {
if (!source || source->getTotalLength() <= 0) if (!source || source->getTotalLength() <= 0)
return false; return false;
@ -167,10 +165,10 @@ bool MyBufferingAudioSource::waitForNextAudioBlockReady (const AudioSourceChanne
if (! isLooping() && nextPlayPos > getTotalLength()) if (! isLooping() && nextPlayPos > getTotalLength())
return true; return true;
uint32 now = Time::getMillisecondCounter(); auto now = Time::getMillisecondCounter();
const uint32 startTime = now; auto startTime = now;
uint32 elapsed = (now >= startTime ? now - startTime auto elapsed = (now >= startTime ? now - startTime
: (std::numeric_limits<uint32>::max() - startTime) + now); : (std::numeric_limits<uint32>::max() - startTime) + now);
while (elapsed <= timeout) while (elapsed <= timeout)
@ -178,15 +176,17 @@ bool MyBufferingAudioSource::waitForNextAudioBlockReady (const AudioSourceChanne
{ {
const ScopedLock sl (bufferStartPosLock); const ScopedLock sl (bufferStartPosLock);
const int validStart = static_cast<int> (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos) - nextPlayPos); auto start = bufferValidStart.load();
const int validEnd = static_cast<int> (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos + info.numSamples) - nextPlayPos); auto end = bufferValidEnd.load();
auto pos = nextPlayPos.load();
auto validStart = static_cast<int> (jlimit (start, end, pos) - pos);
auto validEnd = static_cast<int> (jlimit (start, end, pos + info.numSamples) - pos);
if (validStart <= 0 && validStart < validEnd && validEnd >= info.numSamples) if (validStart <= 0 && validStart < validEnd && validEnd >= info.numSamples)
return true; return true;
} }
if (elapsed < timeout && (! bufferReadyEvent.wait (static_cast<int> (timeout - elapsed)))) if (elapsed < timeout && (! bufferReadyEvent.wait (static_cast<int> (timeout - elapsed))))
return false; return false;
@ -198,21 +198,14 @@ bool MyBufferingAudioSource::waitForNextAudioBlockReady (const AudioSourceChanne
return false; return false;
} }
double MyBufferingAudioSource::getPercentReady()
{
if (bufferValidEnd == bufferValidStart)
return 0.0;
if (numberOfSamplesToBuffer == 0)
return 0.0;
return 1.0 / numberOfSamplesToBuffer * (bufferValidEnd - bufferValidStart);
}
int64 MyBufferingAudioSource::getNextReadPosition() const int64 MyBufferingAudioSource::getNextReadPosition() const
{ {
jassert (source->getTotalLength() > 0); jassert (source->getTotalLength() > 0);
auto pos = nextPlayPos.load();
return (source->isLooping() && nextPlayPos > 0) return (source->isLooping() && nextPlayPos > 0)
? nextPlayPos % source->getTotalLength() ? pos % source->getTotalLength()
: nextPlayPos; : pos;
} }
void MyBufferingAudioSource::setNextReadPosition (int64 newPosition) void MyBufferingAudioSource::setNextReadPosition (int64 newPosition)
@ -237,7 +230,7 @@ bool MyBufferingAudioSource::readNextBufferChunk()
bufferValidEnd = 0; bufferValidEnd = 0;
} }
newBVS = jmax ((int64) 0, nextPlayPos); newBVS = jmax ((int64) 0, nextPlayPos.load());
newBVE = newBVS + buffer.getNumSamples() - 4; newBVE = newBVS + buffer.getNumSamples() - 4;
sectionToReadStart = 0; sectionToReadStart = 0;
sectionToReadEnd = 0; sectionToReadEnd = 0;
@ -263,7 +256,7 @@ bool MyBufferingAudioSource::readNextBufferChunk()
sectionToReadEnd = newBVE; sectionToReadEnd = newBVE;
bufferValidStart = newBVS; bufferValidStart = newBVS;
bufferValidEnd = jmin (bufferValidEnd, newBVE); bufferValidEnd = jmin (bufferValidEnd.load(), newBVE);
} }
} }
@ -271,8 +264,8 @@ bool MyBufferingAudioSource::readNextBufferChunk()
return false; return false;
jassert (buffer.getNumSamples() > 0); jassert (buffer.getNumSamples() > 0);
const int bufferIndexStart = (int) (sectionToReadStart % buffer.getNumSamples()); auto bufferIndexStart = (int) (sectionToReadStart % buffer.getNumSamples());
const int bufferIndexEnd = (int) (sectionToReadEnd % buffer.getNumSamples()); auto bufferIndexEnd = (int) (sectionToReadEnd % buffer.getNumSamples());
if (bufferIndexStart < bufferIndexEnd) if (bufferIndexStart < bufferIndexEnd)
{ {
@ -282,7 +275,7 @@ bool MyBufferingAudioSource::readNextBufferChunk()
} }
else else
{ {
const int initialSize = buffer.getNumSamples() - bufferIndexStart; auto initialSize = buffer.getNumSamples() - bufferIndexStart;
readBufferSection (sectionToReadStart, readBufferSection (sectionToReadStart,
initialSize, initialSize,
@ -301,11 +294,10 @@ bool MyBufferingAudioSource::readNextBufferChunk()
} }
bufferReadyEvent.signal(); bufferReadyEvent.signal();
return true; return true;
} }
void MyBufferingAudioSource::readBufferSection (const int64 start, const int length, const int bufferOffset) void MyBufferingAudioSource::readBufferSection (int64 start, int length, int bufferOffset)
{ {
if (source->getNextReadPosition() != start) if (source->getNextReadPosition() != start)
source->setNextReadPosition (start); source->setNextReadPosition (start);
@ -319,4 +311,13 @@ int MyBufferingAudioSource::useTimeSlice()
return readNextBufferChunk() ? 1 : 100; return readNextBufferChunk() ? 1 : 100;
} }
double MyBufferingAudioSource::getPercentReady()
{
if (bufferValidEnd == bufferValidStart)
return 0.0;
if (numberOfSamplesToBuffer == 0)
return 0.0;
return 1.0 / numberOfSamplesToBuffer * (bufferValidEnd - bufferValidStart);
}

View File

@ -1,25 +1,28 @@
/* /*
============================================================================== ==============================================================================
This file is part of the JUCE library. This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd. Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source JUCE is an open source library subject to commercial or open-source
licensing. licensing.
The code included in this file is provided under the terms of the ISC license The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies. this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED. DISCLAIMED.
============================================================================== ==============================================================================
*/ */
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
//============================================================================== //==============================================================================
/** /**
An AudioSource which takes another source as input, and buffers it using a thread. An AudioSource which takes another source as input, and buffers it using a thread.
@ -29,11 +32,10 @@
directly, or use it indirectly using an AudioTransportSource. directly, or use it indirectly using an AudioTransportSource.
@see PositionableAudioSource, AudioTransportSource @see PositionableAudioSource, AudioTransportSource
@tags{Audio}
*/ */
class JUCE_API MyBufferingAudioSource : public PositionableAudioSource,
#include "../JuceLibraryCode/JuceHeader.h"
class MyBufferingAudioSource : public PositionableAudioSource,
private TimeSliceClient private TimeSliceClient
{ {
public: public:
@ -104,9 +106,9 @@ private:
AudioBuffer<float> buffer; AudioBuffer<float> buffer;
CriticalSection bufferStartPosLock; CriticalSection bufferStartPosLock;
WaitableEvent bufferReadyEvent; WaitableEvent bufferReadyEvent;
int64 volatile bufferValidStart, bufferValidEnd, nextPlayPos; std::atomic<int64> bufferValidStart { 0 }, bufferValidEnd { 0 }, nextPlayPos { 0 };
double volatile sampleRate; double sampleRate = 0;
bool wasSourceLooping, isPrepared, prefillBuffer; bool wasSourceLooping = false, isPrepared = false, prefillBuffer;
bool readNextBufferChunk(); bool readNextBufferChunk();
void readBufferSection (int64 start, int length, int bufferOffset); void readBufferSection (int64 start, int length, int bufferOffset);