Updated the buffering audio source from the new JUCE code that removed the use of volatile
This commit is contained in:
		@@ -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,26 +165,28 @@ 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)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            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);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user