diff --git a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp old mode 100755 new mode 100644 index 62c99379ba..cea7b9beb2 --- a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp +++ b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp @@ -86,71 +86,12 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallbackHandler) }; -//============================================================================== -// This is an AudioTransportSource which will own it's assigned source -struct AudioSourceOwningTransportSource : public AudioTransportSource -{ - AudioSourceOwningTransportSource (PositionableAudioSource* s) : source (s) - { - AudioTransportSource::setSource (s); - } - - ~AudioSourceOwningTransportSource() - { - setSource (nullptr); - } - -private: - ScopedPointer source; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioSourceOwningTransportSource) -}; - -//============================================================================== -// An AudioSourcePlayer which will remove itself from the AudioDeviceManager's -// callback list once it finishes playing its source -struct AutoRemovingSourcePlayer : public AudioSourcePlayer, - private Timer -{ - AutoRemovingSourcePlayer (AudioDeviceManager& dm, AudioTransportSource* ts, bool ownSource) - : manager (dm), transportSource (ts, ownSource) - { - jassert (ts != nullptr); - manager.addAudioCallback (this); - AudioSourcePlayer::setSource (transportSource); - startTimerHz (10); - } - - ~AutoRemovingSourcePlayer() - { - setSource (nullptr); - manager.removeAudioCallback (this); - } - - void timerCallback() override - { - if (getCurrentSource() == nullptr || ! transportSource->isPlaying()) - delete this; - } - - void audioDeviceStopped() override - { - AudioSourcePlayer::audioDeviceStopped(); - setSource (nullptr); - } - -private: - AudioDeviceManager& manager; - OptionalScopedPointer transportSource; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AutoRemovingSourcePlayer) -}; - //============================================================================== AudioDeviceManager::AudioDeviceManager() : numInputChansNeeded (0), numOutputChansNeeded (2), listNeedsScanning (true), + testSoundPosition (0), cpuUsageMs (0), timeToCpuScale (0) { @@ -161,10 +102,6 @@ AudioDeviceManager::~AudioDeviceManager() { currentAudioDevice = nullptr; defaultMidiOutput = nullptr; - - for (int i = 0; i < callbacks.size(); ++i) - if (AutoRemovingSourcePlayer* p = dynamic_cast (callbacks.getUnchecked(i))) - delete p; } //============================================================================== @@ -649,6 +586,8 @@ void AudioDeviceManager::stopDevice() { if (currentAudioDevice != nullptr) currentAudioDevice->stop(); + + testSound = nullptr; } void AudioDeviceManager::closeAudioDevice() @@ -797,6 +736,20 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat for (int i = 0; i < numOutputChannels; ++i) zeromem (outputChannelData[i], sizeof (float) * (size_t) numSamples); } + + if (testSound != nullptr) + { + const int numSamps = jmin (numSamples, testSound->getNumSamples() - testSoundPosition); + const float* const src = testSound->getReadPointer (0, testSoundPosition); + + for (int i = 0; i < numOutputChannels; ++i) + for (int j = 0; j < numSamps; ++j) + outputChannelData [i][j] += src[j]; + + testSoundPosition += numSamps; + if (testSoundPosition >= testSound->getNumSamples()) + testSound = nullptr; + } } void AudioDeviceManager::audioDeviceAboutToStartInt (AudioIODevice* const device) @@ -964,158 +917,6 @@ void AudioDeviceManager::setDefaultMidiOutput (const String& deviceName) } } -//============================================================================== -// An AudioSource which simply outputs a buffer -class AudioSampleBufferSource : public PositionableAudioSource -{ -public: - AudioSampleBufferSource (AudioSampleBuffer* audioBuffer, bool ownBuffer, bool playOnAllChannels) - : buffer (audioBuffer, ownBuffer), - position (0), looping (false), playAcrossAllChannels (playOnAllChannels) - {} - - //============================================================================== - void setNextReadPosition (int64 newPosition) override - { - jassert (newPosition >= 0); - - if (looping) - newPosition = newPosition % static_cast (buffer->getNumSamples()); - - position = jmin (buffer->getNumSamples(), static_cast (newPosition)); - } - - int64 getNextReadPosition() const override { return static_cast (position); } - int64 getTotalLength() const override { return static_cast (buffer->getNumSamples()); } - - bool isLooping() const override { return looping; } - void setLooping (bool shouldLoop) override { looping = shouldLoop; } - - //============================================================================== - void prepareToPlay (int, double) override {} - void releaseResources() override {} - - void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) override - { - bufferToFill.clearActiveBufferRegion(); - - const int bufferSize = buffer->getNumSamples(); - const int samplesNeeded = bufferToFill.numSamples; - const int samplesToCopy = jmin (bufferSize - position, samplesNeeded); - - if (samplesToCopy > 0) - { - int maxInChannels = buffer->getNumChannels(); - int maxOutChannels = bufferToFill.buffer->getNumChannels(); - - if (! playAcrossAllChannels) - maxOutChannels = jmin (maxOutChannels, maxInChannels); - - for (int i = 0; i < maxOutChannels; ++i) - bufferToFill.buffer->copyFrom (i, bufferToFill.startSample, *buffer, - i % maxInChannels, position, samplesToCopy); - } - - position += samplesNeeded; - - if (looping) - position %= bufferSize; - } - -private: - //============================================================================== - OptionalScopedPointer buffer; - int position; - bool looping, playAcrossAllChannels; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioSampleBufferSource) -}; - -void AudioDeviceManager::playSound (const File& file) -{ - if (file.existsAsFile()) - { - AudioFormatManager formatManager; - - formatManager.registerBasicFormats(); - playSound (formatManager.createReaderFor (file), true); - } -} - -void AudioDeviceManager::playSound (const void* resourceData, size_t resourceSize) -{ - if (resourceData != nullptr && resourceSize > 0) - { - AudioFormatManager formatManager; - formatManager.registerBasicFormats(); - MemoryInputStream* mem = new MemoryInputStream (resourceData, resourceSize, false); - playSound (formatManager.createReaderFor (mem), true); - } -} - -void AudioDeviceManager::playSound (AudioFormatReader* reader, bool deleteWhenFinished) -{ - if (reader != nullptr) - playSound (new AudioFormatReaderSource (reader, deleteWhenFinished), true); -} - -void AudioDeviceManager::playSound (AudioSampleBuffer* buffer, bool deleteWhenFinished, bool playOnAllOutputChannels) -{ - if (buffer != nullptr) - playSound (new AudioSampleBufferSource (buffer, deleteWhenFinished, playOnAllOutputChannels), true); -} - -void AudioDeviceManager::playSound (PositionableAudioSource* audioSource, bool deleteWhenFinished) -{ - if (audioSource != nullptr && currentAudioDevice != nullptr) - { - AudioTransportSource* transport = dynamic_cast (audioSource); - - if (transport == nullptr) - { - if (deleteWhenFinished) - { - transport = new AudioSourceOwningTransportSource (audioSource); - } - else - { - transport = new AudioTransportSource(); - transport->setSource (audioSource); - deleteWhenFinished = true; - } - } - - transport->start(); - new AutoRemovingSourcePlayer (*this, transport, deleteWhenFinished); - } - else - { - if (deleteWhenFinished) - delete audioSource; - } -} - -void AudioDeviceManager::playTestSound() -{ - const double sampleRate = currentAudioDevice->getCurrentSampleRate(); - const int soundLength = (int) sampleRate; - - const double frequency = 440.0; - const float amplitude = 0.5f; - - const double phasePerSample = double_Pi * 2.0 / (sampleRate / frequency); - - AudioSampleBuffer* newSound = new AudioSampleBuffer (1, soundLength); - - for (int i = 0; i < soundLength; ++i) - newSound->setSample (0, i, amplitude * (float) std::sin (i * phasePerSample)); - - newSound->applyGainRamp (0, 0, soundLength / 10, 0.0f, 1.0f); - newSound->applyGainRamp (0, soundLength - soundLength / 4, soundLength / 4, 1.0f, 0.0f); - - playSound (newSound, true, true); -} - //============================================================================== AudioDeviceManager::LevelMeter::LevelMeter() noexcept : level() {} @@ -1160,6 +961,42 @@ double AudioDeviceManager::LevelMeter::getCurrentLevel() const noexcept return level; } +void AudioDeviceManager::playTestSound() +{ + { // cunningly nested to swap, unlock and delete in that order. + ScopedPointer oldSound; + + { + const ScopedLock sl (audioCallbackLock); + oldSound = testSound; + } + } + + testSoundPosition = 0; + + if (currentAudioDevice != nullptr) + { + const double sampleRate = currentAudioDevice->getCurrentSampleRate(); + const int soundLength = (int) sampleRate; + + const double frequency = 440.0; + const float amplitude = 0.5f; + + const double phasePerSample = double_Pi * 2.0 / (sampleRate / frequency); + + AudioSampleBuffer* const newSound = new AudioSampleBuffer (1, soundLength); + + for (int i = 0; i < soundLength; ++i) + newSound->setSample (0, i, amplitude * (float) std::sin (i * phasePerSample)); + + newSound->applyGainRamp (0, 0, soundLength / 10, 0.0f, 1.0f); + newSound->applyGainRamp (0, soundLength - soundLength / 4, soundLength / 4, 1.0f, 0.0f); + + const ScopedLock sl (audioCallbackLock); + testSound = newSound; + } +} + double AudioDeviceManager::getCurrentInputLevel() const noexcept { return inputLevelMeter.getCurrentLevel(); } double AudioDeviceManager::getCurrentOutputLevel() const noexcept { return outputLevelMeter.getCurrentLevel(); } diff --git a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h index 59977c6339..9d90f5beb6 100644 --- a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h +++ b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h @@ -404,57 +404,6 @@ public: */ void playTestSound(); - /** Plays a sound from a file. */ - void playSound (const File& file); - - /** Convenient method to play sound from a JUCE resource. */ - void playSound (const void* resourceData, size_t resourceSize); - - /** Plays the sound from an audio format reader. - - If deleteWhenFinished is true then the format reader will be - automatically deleted once the sound has finished playing. - */ - void playSound (AudioFormatReader* buffer, bool deleteWhenFinished = false); - - /** Plays the sound from a positionable audio source. - - This will output the sound coming from a positionable audio source. - This gives you slightly more control over the sound playback compared - to the other playSound methods. For example, if you would like to - stop the sound prematurely you can call this method with a - TransportAudioSource and then call audioSource->stop. Note that, - you must call audioSource->start to start the playback, if your - audioSource is a TransportAudioSource. - - The audio device manager will not hold any references to this audio - source once the audio source has stopped playing for any reason, - for example when the sound has finished playing or when you have - called audioSource->stop. Therefore, calling audioSource->start() on - a finished audioSource will not restart the sound again. If this is - desired simply call playSound with the same audioSource again. - - @param audioSource the audio source to play - @param deleteWhenFinished If this is true then the audio source will - be deleted once the device manager has finished playing. - */ - void playSound (PositionableAudioSource* audioSource, bool deleteWhenFinished = false); - - /** Plays the sound from an audio sample buffer. - - This will output the sound contained in an audio sample buffer. If - deleteWhenFinished is true then the audio sample buffer will be - automatically deleted once the sound has finished playing. - - If playOnAllOutputChannels is true, then if there are more output channels - than buffer channels, then the ones that are available will be re-used on - multiple outputs so that something is sent to all output channels. If it - is false, then the buffer will just be played on the first output channels. - */ - void playSound (AudioSampleBuffer* buffer, - bool deleteWhenFinished = false, - bool playOnAllOutputChannels = false); - //============================================================================== /** Turns on level-measuring for input channels. @see getCurrentInputLevel() @@ -519,6 +468,9 @@ private: ScopedPointer defaultMidiOutput; CriticalSection audioCallbackLock, midiCallbackLock; + ScopedPointer testSound; + int testSoundPosition; + double cpuUsageMs, timeToCpuScale; struct LevelMeter diff --git a/modules/juce_audio_devices/juce_audio_devices.h b/modules/juce_audio_devices/juce_audio_devices.h index bdb0c24ecc..578cff6707 100644 --- a/modules/juce_audio_devices/juce_audio_devices.h +++ b/modules/juce_audio_devices/juce_audio_devices.h @@ -39,7 +39,7 @@ website: http://www.juce.com/juce license: GPL/Commercial - dependencies: juce_audio_basics, juce_audio_formats, juce_events + dependencies: juce_audio_basics, juce_events OSXFrameworks: CoreAudio CoreMIDI DiscRecording iOSFrameworks: CoreAudio CoreMIDI AudioToolbox AVFoundation linuxPackages: alsa diff --git a/modules/juce_audio_utils/juce_audio_utils.cpp b/modules/juce_audio_utils/juce_audio_utils.cpp index 7ab95e7964..3a3b10588c 100644 --- a/modules/juce_audio_utils/juce_audio_utils.cpp +++ b/modules/juce_audio_utils/juce_audio_utils.cpp @@ -49,6 +49,7 @@ namespace juce #include "gui/juce_AudioVisualiserComponent.cpp" #include "gui/juce_MidiKeyboardComponent.cpp" #include "gui/juce_AudioAppComponent.cpp" +#include "players/juce_SoundPlayer.cpp" #include "players/juce_AudioProcessorPlayer.cpp" #if JUCE_MAC diff --git a/modules/juce_audio_utils/juce_audio_utils.h b/modules/juce_audio_utils/juce_audio_utils.h index 9da124e203..5d6b922eaf 100644 --- a/modules/juce_audio_utils/juce_audio_utils.h +++ b/modules/juce_audio_utils/juce_audio_utils.h @@ -67,6 +67,7 @@ namespace juce #include "gui/juce_MidiKeyboardComponent.h" #include "gui/juce_AudioAppComponent.h" #include "gui/juce_BluetoothMidiDevicePairingDialogue.h" +#include "players/juce_SoundPlayer.h" #include "players/juce_AudioProcessorPlayer.h" } diff --git a/modules/juce_audio_utils/players/juce_SoundPlayer.cpp b/modules/juce_audio_utils/players/juce_SoundPlayer.cpp new file mode 100644 index 0000000000..cfcdd17469 --- /dev/null +++ b/modules/juce_audio_utils/players/juce_SoundPlayer.cpp @@ -0,0 +1,273 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2015 - ROLI 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. + + ============================================================================== +*/ + +//============================================================================== +// This is an AudioTransportSource which will own it's assigned source +struct AudioSourceOwningTransportSource : public AudioTransportSource +{ + AudioSourceOwningTransportSource (PositionableAudioSource* s) : source (s) + { + AudioTransportSource::setSource (s); + } + + ~AudioSourceOwningTransportSource() + { + setSource (nullptr); + } + +private: + ScopedPointer source; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioSourceOwningTransportSource) +}; + +//============================================================================== +// An AudioSourcePlayer which will remove itself from the AudioDeviceManager's +// callback list once it finishes playing its source +struct AutoRemovingTransportSource : public AudioTransportSource, private Timer +{ + AutoRemovingTransportSource (MixerAudioSource& mixerToUse, AudioTransportSource* ts, bool ownSource, + int samplesPerBlock, double sampleRate) + : mixer (mixerToUse), transportSource (ts, ownSource) + { + jassert (ts != nullptr); + + setSource (transportSource); + + prepareToPlay (samplesPerBlock, sampleRate); + start(); + + mixer.addInputSource (this, true); + startTimerHz (10); + } + + ~AutoRemovingTransportSource() + { + setSource (nullptr); + } + + void timerCallback() override + { + if (! transportSource->isPlaying()) + mixer.removeInputSource (this); + } + +private: + MixerAudioSource& mixer; + OptionalScopedPointer transportSource; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AutoRemovingTransportSource) +}; + +// An AudioSource which simply outputs a buffer +class AudioSampleBufferSource : public PositionableAudioSource +{ +public: + AudioSampleBufferSource (AudioSampleBuffer* audioBuffer, bool ownBuffer, bool playOnAllChannels) + : buffer (audioBuffer, ownBuffer), + position (0), looping (false), + playAcrossAllChannels (playOnAllChannels) + {} + + //============================================================================== + void setNextReadPosition (int64 newPosition) override + { + jassert (newPosition >= 0); + + if (looping) + newPosition = newPosition % static_cast (buffer->getNumSamples()); + + position = jmin (buffer->getNumSamples(), static_cast (newPosition)); + } + + int64 getNextReadPosition() const override { return static_cast (position); } + int64 getTotalLength() const override { return static_cast (buffer->getNumSamples()); } + + bool isLooping() const override { return looping; } + void setLooping (bool shouldLoop) override { looping = shouldLoop; } + + //============================================================================== + void prepareToPlay (int, double) override {} + void releaseResources() override {} + + void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) override + { + bufferToFill.clearActiveBufferRegion(); + + const int bufferSize = buffer->getNumSamples(); + const int samplesNeeded = bufferToFill.numSamples; + const int samplesToCopy = jmin (bufferSize - position, samplesNeeded); + + if (samplesToCopy > 0) + { + int maxInChannels = buffer->getNumChannels(); + int maxOutChannels = bufferToFill.buffer->getNumChannels(); + + if (! playAcrossAllChannels) + maxOutChannels = jmin (maxOutChannels, maxInChannels); + + for (int i = 0; i < maxOutChannels; ++i) + bufferToFill.buffer->copyFrom (i, bufferToFill.startSample, *buffer, + i % maxInChannels, position, samplesToCopy); + } + + position += samplesNeeded; + + if (looping) + position %= bufferSize; + } + +private: + //============================================================================== + OptionalScopedPointer buffer; + int position; + bool looping, playAcrossAllChannels; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioSampleBufferSource) +}; + +SoundPlayer::SoundPlayer() + : sampleRate (44100.0), bufferSize (512) +{ + formatManager.registerBasicFormats(); + player.setSource (&mixer); +} + +SoundPlayer::~SoundPlayer() +{ + mixer.removeAllInputs(); + player.setSource (nullptr); +} + +void SoundPlayer::play (const File& file) +{ + if (file.existsAsFile()) + play (formatManager.createReaderFor (file), true); +} + +void SoundPlayer::play (const void* resourceData, size_t resourceSize) +{ + if (resourceData != nullptr && resourceSize > 0) + { + MemoryInputStream* mem = new MemoryInputStream (resourceData, resourceSize, false); + play (formatManager.createReaderFor (mem), true); + } +} + +void SoundPlayer::play (AudioFormatReader* reader, bool deleteWhenFinished) +{ + if (reader != nullptr) + play (new AudioFormatReaderSource (reader, deleteWhenFinished), true); +} + +void SoundPlayer::play (AudioSampleBuffer* buffer, bool deleteWhenFinished, bool playOnAllOutputChannels) +{ + if (buffer != nullptr) + play (new AudioSampleBufferSource (buffer, deleteWhenFinished, playOnAllOutputChannels), true); +} + +void SoundPlayer::play (PositionableAudioSource* audioSource, bool deleteWhenFinished) +{ + if (audioSource != nullptr) + { + AudioTransportSource* transport = dynamic_cast (audioSource); + + if (transport == nullptr) + { + if (deleteWhenFinished) + { + transport = new AudioSourceOwningTransportSource (audioSource); + } + else + { + transport = new AudioTransportSource(); + transport->setSource (audioSource); + deleteWhenFinished = true; + } + } + + transport->start(); + transport->prepareToPlay (bufferSize, sampleRate); + + new AutoRemovingTransportSource (mixer, transport, deleteWhenFinished, bufferSize, sampleRate); + } + else + { + if (deleteWhenFinished) + delete audioSource; + } +} + +void SoundPlayer::playTestSound() +{ + const int soundLength = (int) sampleRate; + + const double frequency = 440.0; + const float amplitude = 0.5f; + + const double phasePerSample = double_Pi * 2.0 / (sampleRate / frequency); + + AudioSampleBuffer* newSound = new AudioSampleBuffer (1, soundLength); + + for (int i = 0; i < soundLength; ++i) + newSound->setSample (0, i, amplitude * (float) std::sin (i * phasePerSample)); + + newSound->applyGainRamp (0, 0, soundLength / 10, 0.0f, 1.0f); + newSound->applyGainRamp (0, soundLength - soundLength / 4, soundLength / 4, 1.0f, 0.0f); + + play (newSound, true, true); +} + +//============================================================================== +void SoundPlayer::audioDeviceIOCallback (const float** inputChannelData, + int numInputChannels, + float** outputChannelData, + int numOutputChannels, + int numSamples) +{ + player.audioDeviceIOCallback (inputChannelData, numInputChannels, + outputChannelData, numOutputChannels, + numSamples); +} + +void SoundPlayer::audioDeviceAboutToStart (AudioIODevice* device) +{ + if (device != nullptr) + { + sampleRate = device->getCurrentSampleRate(); + bufferSize = device->getCurrentBufferSizeSamples(); + } + + player.audioDeviceAboutToStart (device); +} + +void SoundPlayer::audioDeviceStopped() +{ + player.audioDeviceStopped(); +} + +void SoundPlayer::audioDeviceError (const String& errorMessage) +{ + player.audioDeviceError (errorMessage); +} diff --git a/modules/juce_audio_utils/players/juce_SoundPlayer.h b/modules/juce_audio_utils/players/juce_SoundPlayer.h new file mode 100644 index 0000000000..8620124bde --- /dev/null +++ b/modules/juce_audio_utils/players/juce_SoundPlayer.h @@ -0,0 +1,130 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2015 - ROLI 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. + + ============================================================================== +*/ + +#ifndef JUCE_SOUNDPLAYER_H_INCLUDED +#define JUCE_SOUNDPLAYER_H_INCLUDED + +//============================================================================== +/** + A simple sound player that you can add to the AudioDeviceManager to play + simple sounds. + + @see AudioProcessor, AudioProcessorGraph +*/ +class JUCE_API SoundPlayer : public AudioIODeviceCallback +{ +public: + //============================================================================== + SoundPlayer (); + + /** Destructor. */ + virtual ~SoundPlayer(); + + //============================================================================== + /** Plays a sound from a file. */ + void play (const File& file); + + /** Convenient method to play sound from a JUCE resource. */ + void play (const void* resourceData, size_t resourceSize); + + /** Plays the sound from an audio format reader. + + If deleteWhenFinished is true then the format reader will be + automatically deleted once the sound has finished playing. + */ + void play (AudioFormatReader* buffer, bool deleteWhenFinished = false); + + /** Plays the sound from a positionable audio source. + + This will output the sound coming from a positionable audio source. + This gives you slightly more control over the sound playback compared + to the other playSound methods. For example, if you would like to + stop the sound prematurely you can call this method with a + TransportAudioSource and then call audioSource->stop. Note that, + you must call audioSource->start to start the playback, if your + audioSource is a TransportAudioSource. + + The audio device manager will not hold any references to this audio + source once the audio source has stopped playing for any reason, + for example when the sound has finished playing or when you have + called audioSource->stop. Therefore, calling audioSource->start() on + a finished audioSource will not restart the sound again. If this is + desired simply call playSound with the same audioSource again. + + @param audioSource the audio source to play + @param deleteWhenFinished If this is true then the audio source will + be deleted once the device manager has finished + playing. + */ + void play (PositionableAudioSource* audioSource, bool deleteWhenFinished = false); + + /** Plays the sound from an audio sample buffer. + + This will output the sound contained in an audio sample buffer. If + deleteWhenFinished is true then the audio sample buffer will be + automatically deleted once the sound has finished playing. + + If playOnAllOutputChannels is true, then if there are more output channels + than buffer channels, then the ones that are available will be re-used on + multiple outputs so that something is sent to all output channels. If it + is false, then the buffer will just be played on the first output channels. + */ + void play (AudioSampleBuffer* buffer, + bool deleteWhenFinished = false, + bool playOnAllOutputChannels = false); + + /** Plays a beep through the current audio device. + + This is here to allow the audio setup UI panels to easily include a "test" + button so that the user can check where the audio is coming from. + */ + void playTestSound(); + + //============================================================================== + /** @internal */ + void audioDeviceIOCallback (const float**, int, float**, int, int) override; + /** @internal */ + void audioDeviceAboutToStart (AudioIODevice*) override; + /** @internal */ + void audioDeviceStopped() override; + /** @internal */ + void audioDeviceError (const String& errorMessage) override; + +private: + //============================================================================== + AudioFormatManager formatManager; + AudioSourcePlayer player; + MixerAudioSource mixer; + OwnedArray sources; + + //============================================================================== + double sampleRate; + int bufferSize; + + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SoundPlayer) +}; + + +#endif // JUCE_SOUNDPLAYER_H_INCLUDED