Updated the buffering audio source from the new JUCE code that removed the use of volatile
This commit is contained in:
parent
c4b2ead50d
commit
9afca36d64
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user