|
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2013 - Raw Material Software Ltd.
-
- Permission is granted to use this software under the terms of either:
- a) the GPL v2 (or any later version)
- b) the Affero GPL v3
-
- Details of these licenses can be found at: www.gnu.org/licenses
-
- JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- ------------------------------------------------------------------------------
-
- To release a closed-source product which uses JUCE, commercial licenses are
- available: visit www.juce.com for more information.
-
- ==============================================================================
- */
-
- AudioTransportSource::AudioTransportSource()
- : source (nullptr),
- resamplerSource (nullptr),
- bufferingSource (nullptr),
- positionableSource (nullptr),
- masterSource (nullptr),
- gain (1.0f),
- lastGain (1.0f),
- playing (false),
- stopped (true),
- sampleRate (44100.0),
- sourceSampleRate (0.0),
- blockSize (128),
- readAheadBufferSize (0),
- isPrepared (false),
- inputStreamEOF (false)
- {
- }
-
- 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;
-
- ScopedPointer<ResamplingAudioSource> oldResamplerSource (resamplerSource);
- ScopedPointer<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)
- {
- {
- const ScopedLock sl (callbackLock);
- 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 getNextReadPosition() / sampleRate;
-
- return 0.0;
- }
-
- double AudioTransportSource::getLengthInSeconds() const
- {
- if (sampleRate > 0.0)
- return getTotalLength() / sampleRate;
-
- return 0.0;
- }
-
- void AudioTransportSource::setNextReadPosition (int64 newPosition)
- {
- if (positionableSource != nullptr)
- {
- if (sampleRate > 0 && sourceSampleRate > 0)
- newPosition = (int64) (newPosition * sourceSampleRate / sampleRate);
-
- positionableSource->setNextReadPosition (newPosition);
- inputStreamEOF = false;
- }
- }
-
- int64 AudioTransportSource::getNextReadPosition() const
- {
- if (positionableSource != nullptr)
- {
- const double ratio = (sampleRate > 0 && sourceSampleRate > 0) ? sampleRate / sourceSampleRate : 1.0;
- return (int64) (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) (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);
-
- 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;
- }
|