migrating to the latest JUCE version
This commit is contained in:
		@@ -1,180 +1,180 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
   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
 | 
			
		||||
   this permission notice appear in all copies.
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
AudioSourcePlayer::AudioSourcePlayer()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AudioSourcePlayer::~AudioSourcePlayer()
 | 
			
		||||
{
 | 
			
		||||
    setSource (nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioSourcePlayer::setSource (AudioSource* newSource)
 | 
			
		||||
{
 | 
			
		||||
    if (source != newSource)
 | 
			
		||||
    {
 | 
			
		||||
        auto* oldSource = source;
 | 
			
		||||
 | 
			
		||||
        if (newSource != nullptr && bufferSize > 0 && sampleRate > 0)
 | 
			
		||||
            newSource->prepareToPlay (bufferSize, sampleRate);
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
            const ScopedLock sl (readLock);
 | 
			
		||||
            source = newSource;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (oldSource != nullptr)
 | 
			
		||||
            oldSource->releaseResources();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioSourcePlayer::setGain (const float newGain) noexcept
 | 
			
		||||
{
 | 
			
		||||
    gain = newGain;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioSourcePlayer::audioDeviceIOCallback (const float** inputChannelData,
 | 
			
		||||
                                               int totalNumInputChannels,
 | 
			
		||||
                                               float** outputChannelData,
 | 
			
		||||
                                               int totalNumOutputChannels,
 | 
			
		||||
                                               int numSamples)
 | 
			
		||||
{
 | 
			
		||||
    // these should have been prepared by audioDeviceAboutToStart()...
 | 
			
		||||
    jassert (sampleRate > 0 && bufferSize > 0);
 | 
			
		||||
 | 
			
		||||
    const ScopedLock sl (readLock);
 | 
			
		||||
 | 
			
		||||
    if (source != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        int numActiveChans = 0, numInputs = 0, numOutputs = 0;
 | 
			
		||||
 | 
			
		||||
        // messy stuff needed to compact the channels down into an array
 | 
			
		||||
        // of non-zero pointers..
 | 
			
		||||
        for (int i = 0; i < totalNumInputChannels; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            if (inputChannelData[i] != nullptr)
 | 
			
		||||
            {
 | 
			
		||||
                inputChans [numInputs++] = inputChannelData[i];
 | 
			
		||||
                if (numInputs >= numElementsInArray (inputChans))
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < totalNumOutputChannels; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            if (outputChannelData[i] != nullptr)
 | 
			
		||||
            {
 | 
			
		||||
                outputChans [numOutputs++] = outputChannelData[i];
 | 
			
		||||
                if (numOutputs >= numElementsInArray (outputChans))
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (numInputs > numOutputs)
 | 
			
		||||
        {
 | 
			
		||||
            // if there aren't enough output channels for the number of
 | 
			
		||||
            // inputs, we need to create some temporary extra ones (can't
 | 
			
		||||
            // use the input data in case it gets written to)
 | 
			
		||||
            tempBuffer.setSize (numInputs - numOutputs, numSamples,
 | 
			
		||||
                                false, false, true);
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < numOutputs; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                channels[numActiveChans] = outputChans[i];
 | 
			
		||||
                memcpy (channels[numActiveChans], inputChans[i], (size_t) numSamples * sizeof (float));
 | 
			
		||||
                ++numActiveChans;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            for (int i = numOutputs; i < numInputs; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                channels[numActiveChans] = tempBuffer.getWritePointer (i - numOutputs);
 | 
			
		||||
                memcpy (channels[numActiveChans], inputChans[i], (size_t) numSamples * sizeof (float));
 | 
			
		||||
                ++numActiveChans;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < numInputs; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                channels[numActiveChans] = outputChans[i];
 | 
			
		||||
                memcpy (channels[numActiveChans], inputChans[i], (size_t) numSamples * sizeof (float));
 | 
			
		||||
                ++numActiveChans;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            for (int i = numInputs; i < numOutputs; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                channels[numActiveChans] = outputChans[i];
 | 
			
		||||
                zeromem (channels[numActiveChans], (size_t) numSamples * sizeof (float));
 | 
			
		||||
                ++numActiveChans;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        AudioBuffer<float> buffer (channels, numActiveChans, numSamples);
 | 
			
		||||
 | 
			
		||||
        AudioSourceChannelInfo info (&buffer, 0, numSamples);
 | 
			
		||||
        source->getNextAudioBlock (info);
 | 
			
		||||
 | 
			
		||||
        for (int i = info.buffer->getNumChannels(); --i >= 0;)
 | 
			
		||||
            buffer.applyGainRamp (i, info.startSample, info.numSamples, lastGain, gain);
 | 
			
		||||
 | 
			
		||||
        lastGain = gain;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < totalNumOutputChannels; ++i)
 | 
			
		||||
            if (outputChannelData[i] != nullptr)
 | 
			
		||||
                zeromem (outputChannelData[i], (size_t) numSamples * sizeof (float));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioSourcePlayer::audioDeviceAboutToStart (AudioIODevice* device)
 | 
			
		||||
{
 | 
			
		||||
    prepareToPlay (device->getCurrentSampleRate(),
 | 
			
		||||
                   device->getCurrentBufferSizeSamples());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioSourcePlayer::prepareToPlay (double newSampleRate, int newBufferSize)
 | 
			
		||||
{
 | 
			
		||||
    sampleRate = newSampleRate;
 | 
			
		||||
    bufferSize = newBufferSize;
 | 
			
		||||
    zeromem (channels, sizeof (channels));
 | 
			
		||||
 | 
			
		||||
    if (source != nullptr)
 | 
			
		||||
        source->prepareToPlay (bufferSize, sampleRate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioSourcePlayer::audioDeviceStopped()
 | 
			
		||||
{
 | 
			
		||||
    if (source != nullptr)
 | 
			
		||||
        source->releaseResources();
 | 
			
		||||
 | 
			
		||||
    sampleRate = 0.0;
 | 
			
		||||
    bufferSize = 0;
 | 
			
		||||
 | 
			
		||||
    tempBuffer.setSize (2, 8);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
   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
 | 
			
		||||
   this permission notice appear in all copies.
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
AudioSourcePlayer::AudioSourcePlayer()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AudioSourcePlayer::~AudioSourcePlayer()
 | 
			
		||||
{
 | 
			
		||||
    setSource (nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioSourcePlayer::setSource (AudioSource* newSource)
 | 
			
		||||
{
 | 
			
		||||
    if (source != newSource)
 | 
			
		||||
    {
 | 
			
		||||
        auto* oldSource = source;
 | 
			
		||||
 | 
			
		||||
        if (newSource != nullptr && bufferSize > 0 && sampleRate > 0)
 | 
			
		||||
            newSource->prepareToPlay (bufferSize, sampleRate);
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
            const ScopedLock sl (readLock);
 | 
			
		||||
            source = newSource;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (oldSource != nullptr)
 | 
			
		||||
            oldSource->releaseResources();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioSourcePlayer::setGain (const float newGain) noexcept
 | 
			
		||||
{
 | 
			
		||||
    gain = newGain;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioSourcePlayer::audioDeviceIOCallback (const float** inputChannelData,
 | 
			
		||||
                                               int totalNumInputChannels,
 | 
			
		||||
                                               float** outputChannelData,
 | 
			
		||||
                                               int totalNumOutputChannels,
 | 
			
		||||
                                               int numSamples)
 | 
			
		||||
{
 | 
			
		||||
    // these should have been prepared by audioDeviceAboutToStart()...
 | 
			
		||||
    jassert (sampleRate > 0 && bufferSize > 0);
 | 
			
		||||
 | 
			
		||||
    const ScopedLock sl (readLock);
 | 
			
		||||
 | 
			
		||||
    if (source != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        int numActiveChans = 0, numInputs = 0, numOutputs = 0;
 | 
			
		||||
 | 
			
		||||
        // messy stuff needed to compact the channels down into an array
 | 
			
		||||
        // of non-zero pointers..
 | 
			
		||||
        for (int i = 0; i < totalNumInputChannels; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            if (inputChannelData[i] != nullptr)
 | 
			
		||||
            {
 | 
			
		||||
                inputChans [numInputs++] = inputChannelData[i];
 | 
			
		||||
                if (numInputs >= numElementsInArray (inputChans))
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < totalNumOutputChannels; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            if (outputChannelData[i] != nullptr)
 | 
			
		||||
            {
 | 
			
		||||
                outputChans [numOutputs++] = outputChannelData[i];
 | 
			
		||||
                if (numOutputs >= numElementsInArray (outputChans))
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (numInputs > numOutputs)
 | 
			
		||||
        {
 | 
			
		||||
            // if there aren't enough output channels for the number of
 | 
			
		||||
            // inputs, we need to create some temporary extra ones (can't
 | 
			
		||||
            // use the input data in case it gets written to)
 | 
			
		||||
            tempBuffer.setSize (numInputs - numOutputs, numSamples,
 | 
			
		||||
                                false, false, true);
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < numOutputs; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                channels[numActiveChans] = outputChans[i];
 | 
			
		||||
                memcpy (channels[numActiveChans], inputChans[i], (size_t) numSamples * sizeof (float));
 | 
			
		||||
                ++numActiveChans;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            for (int i = numOutputs; i < numInputs; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                channels[numActiveChans] = tempBuffer.getWritePointer (i - numOutputs);
 | 
			
		||||
                memcpy (channels[numActiveChans], inputChans[i], (size_t) numSamples * sizeof (float));
 | 
			
		||||
                ++numActiveChans;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < numInputs; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                channels[numActiveChans] = outputChans[i];
 | 
			
		||||
                memcpy (channels[numActiveChans], inputChans[i], (size_t) numSamples * sizeof (float));
 | 
			
		||||
                ++numActiveChans;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            for (int i = numInputs; i < numOutputs; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                channels[numActiveChans] = outputChans[i];
 | 
			
		||||
                zeromem (channels[numActiveChans], (size_t) numSamples * sizeof (float));
 | 
			
		||||
                ++numActiveChans;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        AudioBuffer<float> buffer (channels, numActiveChans, numSamples);
 | 
			
		||||
 | 
			
		||||
        AudioSourceChannelInfo info (&buffer, 0, numSamples);
 | 
			
		||||
        source->getNextAudioBlock (info);
 | 
			
		||||
 | 
			
		||||
        for (int i = info.buffer->getNumChannels(); --i >= 0;)
 | 
			
		||||
            buffer.applyGainRamp (i, info.startSample, info.numSamples, lastGain, gain);
 | 
			
		||||
 | 
			
		||||
        lastGain = gain;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < totalNumOutputChannels; ++i)
 | 
			
		||||
            if (outputChannelData[i] != nullptr)
 | 
			
		||||
                zeromem (outputChannelData[i], (size_t) numSamples * sizeof (float));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioSourcePlayer::audioDeviceAboutToStart (AudioIODevice* device)
 | 
			
		||||
{
 | 
			
		||||
    prepareToPlay (device->getCurrentSampleRate(),
 | 
			
		||||
                   device->getCurrentBufferSizeSamples());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioSourcePlayer::prepareToPlay (double newSampleRate, int newBufferSize)
 | 
			
		||||
{
 | 
			
		||||
    sampleRate = newSampleRate;
 | 
			
		||||
    bufferSize = newBufferSize;
 | 
			
		||||
    zeromem (channels, sizeof (channels));
 | 
			
		||||
 | 
			
		||||
    if (source != nullptr)
 | 
			
		||||
        source->prepareToPlay (bufferSize, sampleRate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioSourcePlayer::audioDeviceStopped()
 | 
			
		||||
{
 | 
			
		||||
    if (source != nullptr)
 | 
			
		||||
        source->releaseResources();
 | 
			
		||||
 | 
			
		||||
    sampleRate = 0.0;
 | 
			
		||||
    bufferSize = 0;
 | 
			
		||||
 | 
			
		||||
    tempBuffer.setSize (2, 8);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,114 +1,114 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
   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
 | 
			
		||||
   this permission notice appear in all copies.
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Wrapper class to continuously stream audio from an audio source to an
 | 
			
		||||
    AudioIODevice.
 | 
			
		||||
 | 
			
		||||
    This object acts as an AudioIODeviceCallback, so can be attached to an
 | 
			
		||||
    output device, and will stream audio from an AudioSource.
 | 
			
		||||
 | 
			
		||||
    @tags{Audio}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  AudioSourcePlayer  : public AudioIODeviceCallback
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates an empty AudioSourcePlayer. */
 | 
			
		||||
    AudioSourcePlayer();
 | 
			
		||||
 | 
			
		||||
    /** Destructor.
 | 
			
		||||
 | 
			
		||||
        Make sure this object isn't still being used by an AudioIODevice before
 | 
			
		||||
        deleting it!
 | 
			
		||||
    */
 | 
			
		||||
    ~AudioSourcePlayer() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the current audio source to play from.
 | 
			
		||||
 | 
			
		||||
        If the source passed in is already being used, this method will do nothing.
 | 
			
		||||
        If the source is not null, its prepareToPlay() method will be called
 | 
			
		||||
        before it starts being used for playback.
 | 
			
		||||
 | 
			
		||||
        If there's another source currently playing, its releaseResources() method
 | 
			
		||||
        will be called after it has been swapped for the new one.
 | 
			
		||||
 | 
			
		||||
        @param newSource                the new source to use - this will NOT be deleted
 | 
			
		||||
                                        by this object when no longer needed, so it's the
 | 
			
		||||
                                        caller's responsibility to manage it.
 | 
			
		||||
    */
 | 
			
		||||
    void setSource (AudioSource* newSource);
 | 
			
		||||
 | 
			
		||||
    /** Returns the source that's playing.
 | 
			
		||||
        May return nullptr if there's no source.
 | 
			
		||||
    */
 | 
			
		||||
    AudioSource* getCurrentSource() const noexcept      { return source; }
 | 
			
		||||
 | 
			
		||||
    /** Sets a gain to apply to the audio data.
 | 
			
		||||
        @see getGain
 | 
			
		||||
    */
 | 
			
		||||
    void setGain (float newGain) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the current gain.
 | 
			
		||||
        @see setGain
 | 
			
		||||
    */
 | 
			
		||||
    float getGain() const noexcept                      { return gain; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Implementation of the AudioIODeviceCallback method. */
 | 
			
		||||
    void audioDeviceIOCallback (const float** inputChannelData,
 | 
			
		||||
                                int totalNumInputChannels,
 | 
			
		||||
                                float** outputChannelData,
 | 
			
		||||
                                int totalNumOutputChannels,
 | 
			
		||||
                                int numSamples) override;
 | 
			
		||||
 | 
			
		||||
    /** Implementation of the AudioIODeviceCallback method. */
 | 
			
		||||
    void audioDeviceAboutToStart (AudioIODevice* device) override;
 | 
			
		||||
 | 
			
		||||
    /** Implementation of the AudioIODeviceCallback method. */
 | 
			
		||||
    void audioDeviceStopped() override;
 | 
			
		||||
 | 
			
		||||
    /** An alternative method for initialising the source without an AudioIODevice. */
 | 
			
		||||
    void prepareToPlay (double sampleRate, int blockSize);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    CriticalSection readLock;
 | 
			
		||||
    AudioSource* source = nullptr;
 | 
			
		||||
    double sampleRate = 0;
 | 
			
		||||
    int bufferSize = 0;
 | 
			
		||||
    float* channels[128];
 | 
			
		||||
    float* outputChans[128];
 | 
			
		||||
    const float* inputChans[128];
 | 
			
		||||
    AudioBuffer<float> tempBuffer;
 | 
			
		||||
    float lastGain = 1.0f;
 | 
			
		||||
    std::atomic<float> gain { 1.0f };
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioSourcePlayer)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
   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
 | 
			
		||||
   this permission notice appear in all copies.
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Wrapper class to continuously stream audio from an audio source to an
 | 
			
		||||
    AudioIODevice.
 | 
			
		||||
 | 
			
		||||
    This object acts as an AudioIODeviceCallback, so can be attached to an
 | 
			
		||||
    output device, and will stream audio from an AudioSource.
 | 
			
		||||
 | 
			
		||||
    @tags{Audio}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  AudioSourcePlayer  : public AudioIODeviceCallback
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates an empty AudioSourcePlayer. */
 | 
			
		||||
    AudioSourcePlayer();
 | 
			
		||||
 | 
			
		||||
    /** Destructor.
 | 
			
		||||
 | 
			
		||||
        Make sure this object isn't still being used by an AudioIODevice before
 | 
			
		||||
        deleting it!
 | 
			
		||||
    */
 | 
			
		||||
    ~AudioSourcePlayer() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the current audio source to play from.
 | 
			
		||||
 | 
			
		||||
        If the source passed in is already being used, this method will do nothing.
 | 
			
		||||
        If the source is not null, its prepareToPlay() method will be called
 | 
			
		||||
        before it starts being used for playback.
 | 
			
		||||
 | 
			
		||||
        If there's another source currently playing, its releaseResources() method
 | 
			
		||||
        will be called after it has been swapped for the new one.
 | 
			
		||||
 | 
			
		||||
        @param newSource                the new source to use - this will NOT be deleted
 | 
			
		||||
                                        by this object when no longer needed, so it's the
 | 
			
		||||
                                        caller's responsibility to manage it.
 | 
			
		||||
    */
 | 
			
		||||
    void setSource (AudioSource* newSource);
 | 
			
		||||
 | 
			
		||||
    /** Returns the source that's playing.
 | 
			
		||||
        May return nullptr if there's no source.
 | 
			
		||||
    */
 | 
			
		||||
    AudioSource* getCurrentSource() const noexcept      { return source; }
 | 
			
		||||
 | 
			
		||||
    /** Sets a gain to apply to the audio data.
 | 
			
		||||
        @see getGain
 | 
			
		||||
    */
 | 
			
		||||
    void setGain (float newGain) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the current gain.
 | 
			
		||||
        @see setGain
 | 
			
		||||
    */
 | 
			
		||||
    float getGain() const noexcept                      { return gain; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Implementation of the AudioIODeviceCallback method. */
 | 
			
		||||
    void audioDeviceIOCallback (const float** inputChannelData,
 | 
			
		||||
                                int totalNumInputChannels,
 | 
			
		||||
                                float** outputChannelData,
 | 
			
		||||
                                int totalNumOutputChannels,
 | 
			
		||||
                                int numSamples) override;
 | 
			
		||||
 | 
			
		||||
    /** Implementation of the AudioIODeviceCallback method. */
 | 
			
		||||
    void audioDeviceAboutToStart (AudioIODevice* device) override;
 | 
			
		||||
 | 
			
		||||
    /** Implementation of the AudioIODeviceCallback method. */
 | 
			
		||||
    void audioDeviceStopped() override;
 | 
			
		||||
 | 
			
		||||
    /** An alternative method for initialising the source without an AudioIODevice. */
 | 
			
		||||
    void prepareToPlay (double sampleRate, int blockSize);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    CriticalSection readLock;
 | 
			
		||||
    AudioSource* source = nullptr;
 | 
			
		||||
    double sampleRate = 0;
 | 
			
		||||
    int bufferSize = 0;
 | 
			
		||||
    float* channels[128];
 | 
			
		||||
    float* outputChans[128];
 | 
			
		||||
    const float* inputChans[128];
 | 
			
		||||
    AudioBuffer<float> tempBuffer;
 | 
			
		||||
    float lastGain = 1.0f;
 | 
			
		||||
    std::atomic<float> gain { 1.0f };
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioSourcePlayer)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,326 +1,283 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
   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
 | 
			
		||||
   this permission notice appear in all copies.
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
AudioTransportSource::AudioTransportSource()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AudioTransportSource::~AudioTransportSource()
 | 
			
		||||
{
 | 
			
		||||
    setSource (nullptr);
 | 
			
		||||
    releaseMasterResources();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::setSource (PositionableAudioSource* const newSource,
 | 
			
		||||
                                      int readAheadSize, TimeSliceThread* readAheadThread,
 | 
			
		||||
                                      double sourceSampleRateToCorrectFor, int maxNumChannels)
 | 
			
		||||
{
 | 
			
		||||
    if (source == newSource)
 | 
			
		||||
    {
 | 
			
		||||
        if (source == nullptr)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        setSource (nullptr, 0, nullptr); // deselect and reselect to avoid releasing resources wrongly
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    readAheadBufferSize = readAheadSize;
 | 
			
		||||
    sourceSampleRate = sourceSampleRateToCorrectFor;
 | 
			
		||||
 | 
			
		||||
    ResamplingAudioSource* newResamplerSource = nullptr;
 | 
			
		||||
    BufferingAudioSource* newBufferingSource = nullptr;
 | 
			
		||||
    PositionableAudioSource* newPositionableSource = nullptr;
 | 
			
		||||
    AudioSource* newMasterSource = nullptr;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<ResamplingAudioSource> oldResamplerSource (resamplerSource);
 | 
			
		||||
    std::unique_ptr<BufferingAudioSource> oldBufferingSource (bufferingSource);
 | 
			
		||||
    AudioSource* oldMasterSource = masterSource;
 | 
			
		||||
 | 
			
		||||
    if (newSource != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        newPositionableSource = newSource;
 | 
			
		||||
 | 
			
		||||
        if (readAheadSize > 0)
 | 
			
		||||
        {
 | 
			
		||||
            // If you want to use a read-ahead buffer, you must also provide a TimeSliceThread
 | 
			
		||||
            // for it to use!
 | 
			
		||||
            jassert (readAheadThread != nullptr);
 | 
			
		||||
 | 
			
		||||
            newPositionableSource = newBufferingSource
 | 
			
		||||
                = new BufferingAudioSource (newPositionableSource, *readAheadThread,
 | 
			
		||||
                                            false, readAheadSize, maxNumChannels);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        newPositionableSource->setNextReadPosition (0);
 | 
			
		||||
 | 
			
		||||
        if (sourceSampleRateToCorrectFor > 0)
 | 
			
		||||
            newMasterSource = newResamplerSource
 | 
			
		||||
                = new ResamplingAudioSource (newPositionableSource, false, maxNumChannels);
 | 
			
		||||
        else
 | 
			
		||||
            newMasterSource = newPositionableSource;
 | 
			
		||||
 | 
			
		||||
        if (isPrepared)
 | 
			
		||||
        {
 | 
			
		||||
            if (newResamplerSource != nullptr && sourceSampleRate > 0 && sampleRate > 0)
 | 
			
		||||
                newResamplerSource->setResamplingRatio (sourceSampleRate / sampleRate);
 | 
			
		||||
 | 
			
		||||
            newMasterSource->prepareToPlay (blockSize, sampleRate);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        const ScopedLock sl (callbackLock);
 | 
			
		||||
 | 
			
		||||
        source = newSource;
 | 
			
		||||
        resamplerSource = newResamplerSource;
 | 
			
		||||
        bufferingSource = newBufferingSource;
 | 
			
		||||
        masterSource = newMasterSource;
 | 
			
		||||
        positionableSource = newPositionableSource;
 | 
			
		||||
 | 
			
		||||
        inputStreamEOF = false;
 | 
			
		||||
        playing = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (oldMasterSource != nullptr)
 | 
			
		||||
        oldMasterSource->releaseResources();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::start()
 | 
			
		||||
{
 | 
			
		||||
    if ((! playing) && masterSource != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        {
 | 
			
		||||
            const ScopedLock sl (callbackLock);
 | 
			
		||||
            playing = true;
 | 
			
		||||
            stopped = false;
 | 
			
		||||
            inputStreamEOF = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        sendChangeMessage();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::stop()
 | 
			
		||||
{
 | 
			
		||||
    if (playing)
 | 
			
		||||
    {
 | 
			
		||||
        playing = false;
 | 
			
		||||
 | 
			
		||||
        int n = 500;
 | 
			
		||||
        while (--n >= 0 && ! stopped)
 | 
			
		||||
            Thread::sleep (2);
 | 
			
		||||
 | 
			
		||||
        sendChangeMessage();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::setPosition (double newPosition)
 | 
			
		||||
{
 | 
			
		||||
    if (sampleRate > 0.0)
 | 
			
		||||
        setNextReadPosition ((int64) (newPosition * sampleRate));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double AudioTransportSource::getCurrentPosition() const
 | 
			
		||||
{
 | 
			
		||||
    if (sampleRate > 0.0)
 | 
			
		||||
        return (double) getNextReadPosition() / sampleRate;
 | 
			
		||||
 | 
			
		||||
    return 0.0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double AudioTransportSource::getLengthInSeconds() const
 | 
			
		||||
{
 | 
			
		||||
    if (sampleRate > 0.0)
 | 
			
		||||
        return (double) getTotalLength() / sampleRate;
 | 
			
		||||
 | 
			
		||||
    return 0.0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::setNextReadPosition (int64 newPosition)
 | 
			
		||||
{
 | 
			
		||||
    if (positionableSource != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        if (sampleRate > 0 && sourceSampleRate > 0)
 | 
			
		||||
            newPosition = (int64) ((double) newPosition * sourceSampleRate / sampleRate);
 | 
			
		||||
 | 
			
		||||
        positionableSource->setNextReadPosition (newPosition);
 | 
			
		||||
 | 
			
		||||
        if (resamplerSource != nullptr)
 | 
			
		||||
            resamplerSource->flushBuffers();
 | 
			
		||||
 | 
			
		||||
        inputStreamEOF = false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64 AudioTransportSource::getNextReadPosition() const
 | 
			
		||||
{
 | 
			
		||||
    if (positionableSource != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        const double ratio = (sampleRate > 0 && sourceSampleRate > 0) ? sampleRate / sourceSampleRate : 1.0;
 | 
			
		||||
        return (int64) ((double) positionableSource->getNextReadPosition() * ratio);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64 AudioTransportSource::getTotalLength() const
 | 
			
		||||
{
 | 
			
		||||
    const ScopedLock sl (callbackLock);
 | 
			
		||||
 | 
			
		||||
    if (positionableSource != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        const double ratio = (sampleRate > 0 && sourceSampleRate > 0) ? sampleRate / sourceSampleRate : 1.0;
 | 
			
		||||
        return (int64) ((double) positionableSource->getTotalLength() * ratio);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AudioTransportSource::isLooping() const
 | 
			
		||||
{
 | 
			
		||||
    const ScopedLock sl (callbackLock);
 | 
			
		||||
    return positionableSource != nullptr && positionableSource->isLooping();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::setLooping(bool shouldLoop)
 | 
			
		||||
{
 | 
			
		||||
    const ScopedLock sl (callbackLock);
 | 
			
		||||
    if (positionableSource != nullptr) {
 | 
			
		||||
        positionableSource->setLooping(shouldLoop);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::getLoopRange (int64 & loopStart, int64 & loopLength) const
 | 
			
		||||
{
 | 
			
		||||
    const ScopedLock sl (callbackLock);
 | 
			
		||||
    if (positionableSource != nullptr) {
 | 
			
		||||
        const double ratio = (sampleRate > 0 && sourceSampleRate > 0) ? sampleRate / sourceSampleRate : 1.0;
 | 
			
		||||
 | 
			
		||||
        positionableSource->getLoopRange(loopStart, loopLength);
 | 
			
		||||
        loopStart = (int64) (loopStart * ratio);
 | 
			
		||||
        loopLength = (int64) (loopLength * ratio);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        loopStart = 0;
 | 
			
		||||
        loopLength = 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::setLoopRange (int64 loopStart, int64 loopLength)
 | 
			
		||||
{
 | 
			
		||||
    if (positionableSource != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        if (sampleRate > 0 && sourceSampleRate > 0) {
 | 
			
		||||
            loopStart = (int64) (loopStart * sourceSampleRate / sampleRate);
 | 
			
		||||
            loopLength = (int64) (loopLength * sourceSampleRate / sampleRate);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        positionableSource->setLoopRange(loopStart, loopLength);
 | 
			
		||||
        
 | 
			
		||||
        if (resamplerSource != nullptr)
 | 
			
		||||
            resamplerSource->flushBuffers();
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::setGain (const float newGain) noexcept
 | 
			
		||||
{
 | 
			
		||||
    gain = newGain;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::prepareToPlay (int samplesPerBlockExpected, double newSampleRate)
 | 
			
		||||
{
 | 
			
		||||
    const ScopedLock sl (callbackLock);
 | 
			
		||||
 | 
			
		||||
    sampleRate = newSampleRate;
 | 
			
		||||
    blockSize = samplesPerBlockExpected;
 | 
			
		||||
 | 
			
		||||
    if (masterSource != nullptr)
 | 
			
		||||
        masterSource->prepareToPlay (samplesPerBlockExpected, sampleRate);
 | 
			
		||||
 | 
			
		||||
    if (resamplerSource != nullptr && sourceSampleRate > 0)
 | 
			
		||||
        resamplerSource->setResamplingRatio (sourceSampleRate / sampleRate);
 | 
			
		||||
 | 
			
		||||
    inputStreamEOF = false;
 | 
			
		||||
    isPrepared = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::releaseMasterResources()
 | 
			
		||||
{
 | 
			
		||||
    const ScopedLock sl (callbackLock);
 | 
			
		||||
 | 
			
		||||
    if (masterSource != nullptr)
 | 
			
		||||
        masterSource->releaseResources();
 | 
			
		||||
 | 
			
		||||
    isPrepared = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::releaseResources()
 | 
			
		||||
{
 | 
			
		||||
    releaseMasterResources();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::getNextAudioBlock (const AudioSourceChannelInfo& info)
 | 
			
		||||
{
 | 
			
		||||
    const ScopedLock sl (callbackLock);
 | 
			
		||||
 | 
			
		||||
    if (masterSource != nullptr && ! stopped)
 | 
			
		||||
    {
 | 
			
		||||
        masterSource->getNextAudioBlock (info);
 | 
			
		||||
 | 
			
		||||
        if (! playing)
 | 
			
		||||
        {
 | 
			
		||||
            // just stopped playing, so fade out the last block..
 | 
			
		||||
            for (int i = info.buffer->getNumChannels(); --i >= 0;)
 | 
			
		||||
                info.buffer->applyGainRamp (i, info.startSample, jmin (256, info.numSamples), 1.0f, 0.0f);
 | 
			
		||||
 | 
			
		||||
            if (info.numSamples > 256)
 | 
			
		||||
                info.buffer->clear (info.startSample + 256, info.numSamples - 256);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (positionableSource->getNextReadPosition() > positionableSource->getTotalLength() + 1
 | 
			
		||||
              && ! positionableSource->isLooping())
 | 
			
		||||
        {
 | 
			
		||||
            playing = false;
 | 
			
		||||
            inputStreamEOF = true;
 | 
			
		||||
            sendChangeMessage();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        stopped = ! playing;
 | 
			
		||||
 | 
			
		||||
        for (int i = info.buffer->getNumChannels(); --i >= 0;)
 | 
			
		||||
            info.buffer->applyGainRamp (i, info.startSample, info.numSamples, lastGain, gain);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        info.clearActiveBufferRegion();
 | 
			
		||||
        stopped = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    lastGain = gain;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
   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
 | 
			
		||||
   this permission notice appear in all copies.
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
AudioTransportSource::AudioTransportSource()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AudioTransportSource::~AudioTransportSource()
 | 
			
		||||
{
 | 
			
		||||
    setSource (nullptr);
 | 
			
		||||
    releaseMasterResources();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::setSource (PositionableAudioSource* const newSource,
 | 
			
		||||
                                      int readAheadSize, TimeSliceThread* readAheadThread,
 | 
			
		||||
                                      double sourceSampleRateToCorrectFor, int maxNumChannels)
 | 
			
		||||
{
 | 
			
		||||
    if (source == newSource)
 | 
			
		||||
    {
 | 
			
		||||
        if (source == nullptr)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        setSource (nullptr, 0, nullptr); // deselect and reselect to avoid releasing resources wrongly
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ResamplingAudioSource* newResamplerSource = nullptr;
 | 
			
		||||
    BufferingAudioSource* newBufferingSource = nullptr;
 | 
			
		||||
    PositionableAudioSource* newPositionableSource = nullptr;
 | 
			
		||||
    AudioSource* newMasterSource = nullptr;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<ResamplingAudioSource> oldResamplerSource (resamplerSource);
 | 
			
		||||
    std::unique_ptr<BufferingAudioSource> oldBufferingSource (bufferingSource);
 | 
			
		||||
    AudioSource* oldMasterSource = masterSource;
 | 
			
		||||
 | 
			
		||||
    if (newSource != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        newPositionableSource = newSource;
 | 
			
		||||
 | 
			
		||||
        if (readAheadSize > 0)
 | 
			
		||||
        {
 | 
			
		||||
            // If you want to use a read-ahead buffer, you must also provide a TimeSliceThread
 | 
			
		||||
            // for it to use!
 | 
			
		||||
            jassert (readAheadThread != nullptr);
 | 
			
		||||
 | 
			
		||||
            newPositionableSource = newBufferingSource
 | 
			
		||||
                = new BufferingAudioSource (newPositionableSource, *readAheadThread,
 | 
			
		||||
                                            false, readAheadSize, maxNumChannels);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        newPositionableSource->setNextReadPosition (0);
 | 
			
		||||
 | 
			
		||||
        if (sourceSampleRateToCorrectFor > 0)
 | 
			
		||||
            newMasterSource = newResamplerSource
 | 
			
		||||
                = new ResamplingAudioSource (newPositionableSource, false, maxNumChannels);
 | 
			
		||||
        else
 | 
			
		||||
            newMasterSource = newPositionableSource;
 | 
			
		||||
 | 
			
		||||
        if (isPrepared)
 | 
			
		||||
        {
 | 
			
		||||
            if (newResamplerSource != nullptr && sourceSampleRateToCorrectFor > 0 && sampleRate > 0)
 | 
			
		||||
                newResamplerSource->setResamplingRatio (sourceSampleRateToCorrectFor / sampleRate);
 | 
			
		||||
 | 
			
		||||
            newMasterSource->prepareToPlay (blockSize, sampleRate);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        const ScopedLock sl (callbackLock);
 | 
			
		||||
 | 
			
		||||
        source = newSource;
 | 
			
		||||
        resamplerSource = newResamplerSource;
 | 
			
		||||
        bufferingSource = newBufferingSource;
 | 
			
		||||
        masterSource = newMasterSource;
 | 
			
		||||
        positionableSource = newPositionableSource;
 | 
			
		||||
        readAheadBufferSize = readAheadSize;
 | 
			
		||||
        sourceSampleRate = sourceSampleRateToCorrectFor;
 | 
			
		||||
 | 
			
		||||
        playing = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (oldMasterSource != nullptr)
 | 
			
		||||
        oldMasterSource->releaseResources();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::start()
 | 
			
		||||
{
 | 
			
		||||
    if ((! playing) && masterSource != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        {
 | 
			
		||||
            const ScopedLock sl (callbackLock);
 | 
			
		||||
            playing = true;
 | 
			
		||||
            stopped = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        sendChangeMessage();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::stop()
 | 
			
		||||
{
 | 
			
		||||
    if (playing)
 | 
			
		||||
    {
 | 
			
		||||
        playing = false;
 | 
			
		||||
 | 
			
		||||
        int n = 500;
 | 
			
		||||
        while (--n >= 0 && ! stopped)
 | 
			
		||||
            Thread::sleep (2);
 | 
			
		||||
 | 
			
		||||
        sendChangeMessage();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::setPosition (double newPosition)
 | 
			
		||||
{
 | 
			
		||||
    if (sampleRate > 0.0)
 | 
			
		||||
        setNextReadPosition ((int64) (newPosition * sampleRate));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double AudioTransportSource::getCurrentPosition() const
 | 
			
		||||
{
 | 
			
		||||
    if (sampleRate > 0.0)
 | 
			
		||||
        return (double) getNextReadPosition() / sampleRate;
 | 
			
		||||
 | 
			
		||||
    return 0.0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double AudioTransportSource::getLengthInSeconds() const
 | 
			
		||||
{
 | 
			
		||||
    if (sampleRate > 0.0)
 | 
			
		||||
        return (double) getTotalLength() / sampleRate;
 | 
			
		||||
 | 
			
		||||
    return 0.0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AudioTransportSource::hasStreamFinished() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return positionableSource->getNextReadPosition() > positionableSource->getTotalLength() + 1
 | 
			
		||||
              && ! positionableSource->isLooping();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::setNextReadPosition (int64 newPosition)
 | 
			
		||||
{
 | 
			
		||||
    if (positionableSource != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        if (sampleRate > 0 && sourceSampleRate > 0)
 | 
			
		||||
            newPosition = (int64) ((double) newPosition * sourceSampleRate / sampleRate);
 | 
			
		||||
 | 
			
		||||
        positionableSource->setNextReadPosition (newPosition);
 | 
			
		||||
 | 
			
		||||
        if (resamplerSource != nullptr)
 | 
			
		||||
            resamplerSource->flushBuffers();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64 AudioTransportSource::getNextReadPosition() const
 | 
			
		||||
{
 | 
			
		||||
    const ScopedLock sl (callbackLock);
 | 
			
		||||
 | 
			
		||||
    if (positionableSource != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        const double ratio = (sampleRate > 0 && sourceSampleRate > 0) ? sampleRate / sourceSampleRate : 1.0;
 | 
			
		||||
        return (int64) ((double) positionableSource->getNextReadPosition() * ratio);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64 AudioTransportSource::getTotalLength() const
 | 
			
		||||
{
 | 
			
		||||
    const ScopedLock sl (callbackLock);
 | 
			
		||||
 | 
			
		||||
    if (positionableSource != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        const double ratio = (sampleRate > 0 && sourceSampleRate > 0) ? sampleRate / sourceSampleRate : 1.0;
 | 
			
		||||
        return (int64) ((double) positionableSource->getTotalLength() * ratio);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AudioTransportSource::isLooping() const
 | 
			
		||||
{
 | 
			
		||||
    const ScopedLock sl (callbackLock);
 | 
			
		||||
    return positionableSource != nullptr && positionableSource->isLooping();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::setGain (const float newGain) noexcept
 | 
			
		||||
{
 | 
			
		||||
    gain = newGain;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::prepareToPlay (int samplesPerBlockExpected, double newSampleRate)
 | 
			
		||||
{
 | 
			
		||||
    const ScopedLock sl (callbackLock);
 | 
			
		||||
 | 
			
		||||
    sampleRate = newSampleRate;
 | 
			
		||||
    blockSize = samplesPerBlockExpected;
 | 
			
		||||
 | 
			
		||||
    if (masterSource != nullptr)
 | 
			
		||||
        masterSource->prepareToPlay (samplesPerBlockExpected, sampleRate);
 | 
			
		||||
 | 
			
		||||
    if (resamplerSource != nullptr && sourceSampleRate > 0)
 | 
			
		||||
        resamplerSource->setResamplingRatio (sourceSampleRate / sampleRate);
 | 
			
		||||
 | 
			
		||||
    isPrepared = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::releaseMasterResources()
 | 
			
		||||
{
 | 
			
		||||
    const ScopedLock sl (callbackLock);
 | 
			
		||||
 | 
			
		||||
    if (masterSource != nullptr)
 | 
			
		||||
        masterSource->releaseResources();
 | 
			
		||||
 | 
			
		||||
    isPrepared = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::releaseResources()
 | 
			
		||||
{
 | 
			
		||||
    releaseMasterResources();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioTransportSource::getNextAudioBlock (const AudioSourceChannelInfo& info)
 | 
			
		||||
{
 | 
			
		||||
    const ScopedLock sl (callbackLock);
 | 
			
		||||
 | 
			
		||||
    if (masterSource != nullptr && ! stopped)
 | 
			
		||||
    {
 | 
			
		||||
        masterSource->getNextAudioBlock (info);
 | 
			
		||||
 | 
			
		||||
        if (! playing)
 | 
			
		||||
        {
 | 
			
		||||
            // just stopped playing, so fade out the last block..
 | 
			
		||||
            for (int i = info.buffer->getNumChannels(); --i >= 0;)
 | 
			
		||||
                info.buffer->applyGainRamp (i, info.startSample, jmin (256, info.numSamples), 1.0f, 0.0f);
 | 
			
		||||
 | 
			
		||||
            if (info.numSamples > 256)
 | 
			
		||||
                info.buffer->clear (info.startSample + 256, info.numSamples - 256);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (hasStreamFinished())
 | 
			
		||||
        {
 | 
			
		||||
            playing = false;
 | 
			
		||||
            sendChangeMessage();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        stopped = ! playing;
 | 
			
		||||
 | 
			
		||||
        for (int i = info.buffer->getNumChannels(); --i >= 0;)
 | 
			
		||||
            info.buffer->applyGainRamp (i, info.startSample, info.numSamples, lastGain, gain);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        info.clearActiveBufferRegion();
 | 
			
		||||
        stopped = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    lastGain = gain;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,190 +1,180 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
   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
 | 
			
		||||
   this permission notice appear in all copies.
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    An AudioSource that takes a PositionableAudioSource and allows it to be
 | 
			
		||||
    played, stopped, started, etc.
 | 
			
		||||
 | 
			
		||||
    This can also be told use a buffer and background thread to read ahead, and
 | 
			
		||||
    if can correct for different sample-rates.
 | 
			
		||||
 | 
			
		||||
    You may want to use one of these along with an AudioSourcePlayer and AudioIODevice
 | 
			
		||||
    to control playback of an audio file.
 | 
			
		||||
 | 
			
		||||
    @see AudioSource, AudioSourcePlayer
 | 
			
		||||
 | 
			
		||||
    @tags{Audio}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  AudioTransportSource  : public PositionableAudioSource,
 | 
			
		||||
                                        public ChangeBroadcaster
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates an AudioTransportSource.
 | 
			
		||||
        After creating one of these, use the setSource() method to select an input source.
 | 
			
		||||
    */
 | 
			
		||||
    AudioTransportSource();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~AudioTransportSource() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Sets the reader that is being used as the input source.
 | 
			
		||||
 | 
			
		||||
        This will stop playback, reset the position to 0 and change to the new reader.
 | 
			
		||||
 | 
			
		||||
        The source passed in will not be deleted by this object, so must be managed by
 | 
			
		||||
        the caller.
 | 
			
		||||
 | 
			
		||||
        @param newSource                        the new input source to use. This may be a nullptr
 | 
			
		||||
        @param readAheadBufferSize              a size of buffer to use for reading ahead. If this
 | 
			
		||||
                                                is zero, no reading ahead will be done; if it's
 | 
			
		||||
                                                greater than zero, a BufferingAudioSource will be used
 | 
			
		||||
                                                to do the reading-ahead. If you set a non-zero value here,
 | 
			
		||||
                                                you'll also need to set the readAheadThread parameter.
 | 
			
		||||
        @param readAheadThread                  if you set readAheadBufferSize to a non-zero value, then
 | 
			
		||||
                                                you'll also need to supply this TimeSliceThread object for
 | 
			
		||||
                                                the background reader to use. The thread object must not be
 | 
			
		||||
                                                deleted while the AudioTransport source is still using it.
 | 
			
		||||
        @param sourceSampleRateToCorrectFor     if this is non-zero, it specifies the sample
 | 
			
		||||
                                                rate of the source, and playback will be sample-rate
 | 
			
		||||
                                                adjusted to maintain playback at the correct pitch. If
 | 
			
		||||
                                                this is 0, no sample-rate adjustment will be performed
 | 
			
		||||
        @param maxNumChannels                   the maximum number of channels that may need to be played
 | 
			
		||||
    */
 | 
			
		||||
    void setSource (PositionableAudioSource* newSource,
 | 
			
		||||
                    int readAheadBufferSize = 0,
 | 
			
		||||
                    TimeSliceThread* readAheadThread = nullptr,
 | 
			
		||||
                    double sourceSampleRateToCorrectFor = 0.0,
 | 
			
		||||
                    int maxNumChannels = 2);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the current playback position in the source stream.
 | 
			
		||||
 | 
			
		||||
        The next time the getNextAudioBlock() method is called, this
 | 
			
		||||
        is the time from which it'll read data.
 | 
			
		||||
 | 
			
		||||
        @param newPosition    the new playback position in seconds
 | 
			
		||||
 | 
			
		||||
        @see getCurrentPosition
 | 
			
		||||
    */
 | 
			
		||||
    void setPosition (double newPosition);
 | 
			
		||||
 | 
			
		||||
    /** Returns the position that the next data block will be read from
 | 
			
		||||
        This is a time in seconds.
 | 
			
		||||
    */
 | 
			
		||||
    double getCurrentPosition() const;
 | 
			
		||||
 | 
			
		||||
    /** Returns the stream's length in seconds. */
 | 
			
		||||
    double getLengthInSeconds() const;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the player has stopped because its input stream ran out of data. */
 | 
			
		||||
    bool hasStreamFinished() const noexcept             { return inputStreamEOF; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Starts playing (if a source has been selected).
 | 
			
		||||
 | 
			
		||||
        If it starts playing, this will send a message to any ChangeListeners
 | 
			
		||||
        that are registered with this object.
 | 
			
		||||
    */
 | 
			
		||||
    void start();
 | 
			
		||||
 | 
			
		||||
    /** Stops playing.
 | 
			
		||||
 | 
			
		||||
        If it's actually playing, this will send a message to any ChangeListeners
 | 
			
		||||
        that are registered with this object.
 | 
			
		||||
    */
 | 
			
		||||
    void stop();
 | 
			
		||||
 | 
			
		||||
    /** Returns true if it's currently playing. */
 | 
			
		||||
    bool isPlaying() const noexcept     { return playing; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the gain to apply to the output.
 | 
			
		||||
        @param newGain  a factor by which to multiply the outgoing samples,
 | 
			
		||||
                        so 1.0 = 0dB, 0.5 = -6dB, 2.0 = 6dB, etc.
 | 
			
		||||
    */
 | 
			
		||||
    void setGain (float newGain) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the current gain setting.
 | 
			
		||||
        @see setGain
 | 
			
		||||
    */
 | 
			
		||||
    float getGain() const noexcept      { return gain; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Implementation of the AudioSource method. */
 | 
			
		||||
    void prepareToPlay (int samplesPerBlockExpected, double sampleRate) override;
 | 
			
		||||
 | 
			
		||||
    /** Implementation of the AudioSource method. */
 | 
			
		||||
    void releaseResources() override;
 | 
			
		||||
 | 
			
		||||
    /** Implementation of the AudioSource method. */
 | 
			
		||||
    void getNextAudioBlock (const AudioSourceChannelInfo&) override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Implements the PositionableAudioSource method. */
 | 
			
		||||
    void setNextReadPosition (int64 newPosition) override;
 | 
			
		||||
 | 
			
		||||
    /** Implements the PositionableAudioSource method. */
 | 
			
		||||
    int64 getNextReadPosition() const override;
 | 
			
		||||
 | 
			
		||||
    /** Implements the PositionableAudioSource method. */
 | 
			
		||||
    int64 getTotalLength() const override;
 | 
			
		||||
 | 
			
		||||
    /** Implements the PositionableAudioSource method. */
 | 
			
		||||
    bool isLooping() const override;
 | 
			
		||||
 | 
			
		||||
    /** Implements the PositionableAudioSource method. */
 | 
			
		||||
    void setLooping(bool shouldLoop) override;
 | 
			
		||||
 | 
			
		||||
    /** Implements the PositionableAudioSource method. */
 | 
			
		||||
    void setLoopRange (int64 loopStart, int64 loopLength) override;
 | 
			
		||||
 | 
			
		||||
    /** Implements the PositionableAudioSource method. */
 | 
			
		||||
    void getLoopRange (int64 & loopStart, int64 & loopLength) const override;
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    PositionableAudioSource* source = nullptr;
 | 
			
		||||
    ResamplingAudioSource* resamplerSource = nullptr;
 | 
			
		||||
    BufferingAudioSource* bufferingSource = nullptr;
 | 
			
		||||
    PositionableAudioSource* positionableSource = nullptr;
 | 
			
		||||
    AudioSource* masterSource = nullptr;
 | 
			
		||||
 | 
			
		||||
    CriticalSection callbackLock;
 | 
			
		||||
    float gain = 1.0f, lastGain = 1.0f;
 | 
			
		||||
    std::atomic<bool> playing { false }, stopped { true };
 | 
			
		||||
    double sampleRate = 44100.0, sourceSampleRate = 0;
 | 
			
		||||
    int blockSize = 128, readAheadBufferSize = 0;
 | 
			
		||||
    bool isPrepared = false, inputStreamEOF = false;
 | 
			
		||||
 | 
			
		||||
    void releaseMasterResources();
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioTransportSource)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
   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
 | 
			
		||||
   this permission notice appear in all copies.
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    An AudioSource that takes a PositionableAudioSource and allows it to be
 | 
			
		||||
    played, stopped, started, etc.
 | 
			
		||||
 | 
			
		||||
    This can also be told use a buffer and background thread to read ahead, and
 | 
			
		||||
    if can correct for different sample-rates.
 | 
			
		||||
 | 
			
		||||
    You may want to use one of these along with an AudioSourcePlayer and AudioIODevice
 | 
			
		||||
    to control playback of an audio file.
 | 
			
		||||
 | 
			
		||||
    @see AudioSource, AudioSourcePlayer
 | 
			
		||||
 | 
			
		||||
    @tags{Audio}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  AudioTransportSource  : public PositionableAudioSource,
 | 
			
		||||
                                        public ChangeBroadcaster
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates an AudioTransportSource.
 | 
			
		||||
        After creating one of these, use the setSource() method to select an input source.
 | 
			
		||||
    */
 | 
			
		||||
    AudioTransportSource();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~AudioTransportSource() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Sets the reader that is being used as the input source.
 | 
			
		||||
 | 
			
		||||
        This will stop playback, reset the position to 0 and change to the new reader.
 | 
			
		||||
 | 
			
		||||
        The source passed in will not be deleted by this object, so must be managed by
 | 
			
		||||
        the caller.
 | 
			
		||||
 | 
			
		||||
        @param newSource                        the new input source to use. This may be a nullptr
 | 
			
		||||
        @param readAheadBufferSize              a size of buffer to use for reading ahead. If this
 | 
			
		||||
                                                is zero, no reading ahead will be done; if it's
 | 
			
		||||
                                                greater than zero, a BufferingAudioSource will be used
 | 
			
		||||
                                                to do the reading-ahead. If you set a non-zero value here,
 | 
			
		||||
                                                you'll also need to set the readAheadThread parameter.
 | 
			
		||||
        @param readAheadThread                  if you set readAheadBufferSize to a non-zero value, then
 | 
			
		||||
                                                you'll also need to supply this TimeSliceThread object for
 | 
			
		||||
                                                the background reader to use. The thread object must not be
 | 
			
		||||
                                                deleted while the AudioTransport source is still using it.
 | 
			
		||||
        @param sourceSampleRateToCorrectFor     if this is non-zero, it specifies the sample
 | 
			
		||||
                                                rate of the source, and playback will be sample-rate
 | 
			
		||||
                                                adjusted to maintain playback at the correct pitch. If
 | 
			
		||||
                                                this is 0, no sample-rate adjustment will be performed
 | 
			
		||||
        @param maxNumChannels                   the maximum number of channels that may need to be played
 | 
			
		||||
    */
 | 
			
		||||
    void setSource (PositionableAudioSource* newSource,
 | 
			
		||||
                    int readAheadBufferSize = 0,
 | 
			
		||||
                    TimeSliceThread* readAheadThread = nullptr,
 | 
			
		||||
                    double sourceSampleRateToCorrectFor = 0.0,
 | 
			
		||||
                    int maxNumChannels = 2);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the current playback position in the source stream.
 | 
			
		||||
 | 
			
		||||
        The next time the getNextAudioBlock() method is called, this
 | 
			
		||||
        is the time from which it'll read data.
 | 
			
		||||
 | 
			
		||||
        @param newPosition    the new playback position in seconds
 | 
			
		||||
 | 
			
		||||
        @see getCurrentPosition
 | 
			
		||||
    */
 | 
			
		||||
    void setPosition (double newPosition);
 | 
			
		||||
 | 
			
		||||
    /** Returns the position that the next data block will be read from
 | 
			
		||||
        This is a time in seconds.
 | 
			
		||||
    */
 | 
			
		||||
    double getCurrentPosition() const;
 | 
			
		||||
 | 
			
		||||
    /** Returns the stream's length in seconds. */
 | 
			
		||||
    double getLengthInSeconds() const;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the player has stopped because its input stream ran out of data. */
 | 
			
		||||
    bool hasStreamFinished() const noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Starts playing (if a source has been selected).
 | 
			
		||||
 | 
			
		||||
        If it starts playing, this will send a message to any ChangeListeners
 | 
			
		||||
        that are registered with this object.
 | 
			
		||||
    */
 | 
			
		||||
    void start();
 | 
			
		||||
 | 
			
		||||
    /** Stops playing.
 | 
			
		||||
 | 
			
		||||
        If it's actually playing, this will send a message to any ChangeListeners
 | 
			
		||||
        that are registered with this object.
 | 
			
		||||
    */
 | 
			
		||||
    void stop();
 | 
			
		||||
 | 
			
		||||
    /** Returns true if it's currently playing. */
 | 
			
		||||
    bool isPlaying() const noexcept     { return playing; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the gain to apply to the output.
 | 
			
		||||
        @param newGain  a factor by which to multiply the outgoing samples,
 | 
			
		||||
                        so 1.0 = 0dB, 0.5 = -6dB, 2.0 = 6dB, etc.
 | 
			
		||||
    */
 | 
			
		||||
    void setGain (float newGain) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the current gain setting.
 | 
			
		||||
        @see setGain
 | 
			
		||||
    */
 | 
			
		||||
    float getGain() const noexcept      { return gain; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Implementation of the AudioSource method. */
 | 
			
		||||
    void prepareToPlay (int samplesPerBlockExpected, double sampleRate) override;
 | 
			
		||||
 | 
			
		||||
    /** Implementation of the AudioSource method. */
 | 
			
		||||
    void releaseResources() override;
 | 
			
		||||
 | 
			
		||||
    /** Implementation of the AudioSource method. */
 | 
			
		||||
    void getNextAudioBlock (const AudioSourceChannelInfo&) override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Implements the PositionableAudioSource method. */
 | 
			
		||||
    void setNextReadPosition (int64 newPosition) override;
 | 
			
		||||
 | 
			
		||||
    /** Implements the PositionableAudioSource method. */
 | 
			
		||||
    int64 getNextReadPosition() const override;
 | 
			
		||||
 | 
			
		||||
    /** Implements the PositionableAudioSource method. */
 | 
			
		||||
    int64 getTotalLength() const override;
 | 
			
		||||
 | 
			
		||||
    /** Implements the PositionableAudioSource method. */
 | 
			
		||||
    bool isLooping() const override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    PositionableAudioSource* source = nullptr;
 | 
			
		||||
    ResamplingAudioSource* resamplerSource = nullptr;
 | 
			
		||||
    BufferingAudioSource* bufferingSource = nullptr;
 | 
			
		||||
    PositionableAudioSource* positionableSource = nullptr;
 | 
			
		||||
    AudioSource* masterSource = nullptr;
 | 
			
		||||
 | 
			
		||||
    CriticalSection callbackLock;
 | 
			
		||||
    float gain = 1.0f, lastGain = 1.0f;
 | 
			
		||||
    std::atomic<bool> playing { false }, stopped { true };
 | 
			
		||||
    double sampleRate = 44100.0, sourceSampleRate = 0;
 | 
			
		||||
    int blockSize = 128, readAheadBufferSize = 0;
 | 
			
		||||
    bool isPrepared = false;
 | 
			
		||||
 | 
			
		||||
    void releaseMasterResources();
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioTransportSource)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user