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

@ -20,6 +20,9 @@
============================================================================== ==============================================================================
*/ */
#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);