From 0ad401cc97e5577f594066d3c993daca803572e8 Mon Sep 17 00:00:00 2001 From: binary1248 Date: Sun, 18 May 2014 19:52:58 +0200 Subject: [PATCH] Made OpenAL context management more intelligent, in analogy to OpenGL context management. OpenAL contexts now only exist as long as AlResources require them and are destroyed when they are no longer required. Fixes #30. --- include/SFML/Audio/AlResource.hpp | 70 +++++++++++++++++ include/SFML/Audio/SoundBuffer.hpp | 3 +- include/SFML/Audio/SoundRecorder.hpp | 3 +- include/SFML/Audio/SoundSource.hpp | 3 +- src/SFML/Audio/ALCheck.cpp | 13 --- src/SFML/Audio/ALCheck.hpp | 6 -- src/SFML/Audio/AlResource.cpp | 78 ++++++++++++++++++ src/SFML/Audio/AudioDevice.cpp | 113 ++++++++++++++++++++++++++- src/SFML/Audio/AudioDevice.hpp | 101 ++++++++++++++++++++++++ src/SFML/Audio/CMakeLists.txt | 2 + src/SFML/Audio/Listener.cpp | 53 +++---------- src/SFML/Audio/SoundBuffer.cpp | 2 - src/SFML/Audio/SoundRecorder.cpp | 2 - src/SFML/Audio/SoundSource.cpp | 4 - 14 files changed, 377 insertions(+), 76 deletions(-) create mode 100644 include/SFML/Audio/AlResource.hpp create mode 100644 src/SFML/Audio/AlResource.cpp diff --git a/include/SFML/Audio/AlResource.hpp b/include/SFML/Audio/AlResource.hpp new file mode 100644 index 00000000..c4e34e05 --- /dev/null +++ b/include/SFML/Audio/AlResource.hpp @@ -0,0 +1,70 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_ALRESOURCE_HPP +#define SFML_ALRESOURCE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Base class for classes that require an OpenAL context +/// +//////////////////////////////////////////////////////////// +class SFML_AUDIO_API AlResource +{ +protected: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + AlResource(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~AlResource(); +}; + +} // namespace sf + + +#endif // SFML_ALRESOURCE_HPP + +//////////////////////////////////////////////////////////// +/// \class sf::AlResource +/// \ingroup audio +/// +/// This class is for internal use only, it must be the base +/// of every class that requires a valid OpenAL context in +/// order to work. +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Audio/SoundBuffer.hpp b/include/SFML/Audio/SoundBuffer.hpp index 392b4617..e8a502af 100644 --- a/include/SFML/Audio/SoundBuffer.hpp +++ b/include/SFML/Audio/SoundBuffer.hpp @@ -29,6 +29,7 @@ // Headers //////////////////////////////////////////////////////////// #include +#include #include #include #include @@ -49,7 +50,7 @@ class InputStream; /// \brief Storage for audio samples defining a sound /// //////////////////////////////////////////////////////////// -class SFML_AUDIO_API SoundBuffer +class SFML_AUDIO_API SoundBuffer : AlResource { public: diff --git a/include/SFML/Audio/SoundRecorder.hpp b/include/SFML/Audio/SoundRecorder.hpp index 733fd322..67bacc8d 100644 --- a/include/SFML/Audio/SoundRecorder.hpp +++ b/include/SFML/Audio/SoundRecorder.hpp @@ -29,6 +29,7 @@ // Headers //////////////////////////////////////////////////////////// #include +#include #include #include #include @@ -41,7 +42,7 @@ namespace sf /// \brief Abstract base class for capturing sound data /// //////////////////////////////////////////////////////////// -class SFML_AUDIO_API SoundRecorder +class SFML_AUDIO_API SoundRecorder : AlResource { public: diff --git a/include/SFML/Audio/SoundSource.hpp b/include/SFML/Audio/SoundSource.hpp index f8ba48aa..ea2800c4 100644 --- a/include/SFML/Audio/SoundSource.hpp +++ b/include/SFML/Audio/SoundSource.hpp @@ -29,6 +29,7 @@ // Headers //////////////////////////////////////////////////////////// #include +#include #include @@ -38,7 +39,7 @@ namespace sf /// \brief Base class defining a sound's properties /// //////////////////////////////////////////////////////////// -class SFML_AUDIO_API SoundSource +class SFML_AUDIO_API SoundSource : AlResource { public: diff --git a/src/SFML/Audio/ALCheck.cpp b/src/SFML/Audio/ALCheck.cpp index 1a7e4bb9..0baa8303 100644 --- a/src/SFML/Audio/ALCheck.cpp +++ b/src/SFML/Audio/ALCheck.cpp @@ -91,19 +91,6 @@ void alCheckError(const std::string& file, unsigned int line) } } - -//////////////////////////////////////////////////////////// -/// Make sure that OpenAL is initialized -//////////////////////////////////////////////////////////// -void ensureALInit() -{ - // The audio device is instantiated on demand rather than at global startup, - // which solves a lot of weird crashes and errors. - // It is destroyed at global exit which is fine. - - static AudioDevice globalDevice; -} - } // namespace priv } // namespace sf diff --git a/src/SFML/Audio/ALCheck.hpp b/src/SFML/Audio/ALCheck.hpp index b31a031e..30642a10 100644 --- a/src/SFML/Audio/ALCheck.hpp +++ b/src/SFML/Audio/ALCheck.hpp @@ -64,12 +64,6 @@ namespace priv //////////////////////////////////////////////////////////// void alCheckError(const std::string& file, unsigned int line); -//////////////////////////////////////////////////////////// -/// Make sure that OpenAL is initialized -/// -//////////////////////////////////////////////////////////// -void ensureALInit(); - } // namespace priv } // namespace sf diff --git a/src/SFML/Audio/AlResource.cpp b/src/SFML/Audio/AlResource.cpp new file mode 100644 index 00000000..48c737ba --- /dev/null +++ b/src/SFML/Audio/AlResource.cpp @@ -0,0 +1,78 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + + +namespace +{ + // OpenAL resources counter and its mutex + unsigned int count = 0; + sf::Mutex mutex; + + // The audio device is instantiated on demand rather than at global startup, + // which solves a lot of weird crashes and errors. + // It is destroyed when it is no longer needed. + sf::priv::AudioDevice* globalDevice; +} + + +namespace sf +{ +//////////////////////////////////////////////////////////// +AlResource::AlResource() +{ + // Protect from concurrent access + Lock lock(mutex); + + // If this is the very first resource, trigger the global device initialization + if (count == 0) + globalDevice = new priv::AudioDevice; + + // Increment the resources counter + count++; +} + + +//////////////////////////////////////////////////////////// +AlResource::~AlResource() +{ + // Protect from concurrent access + Lock lock(mutex); + + // Decrement the resources counter + count--; + + // If there's no more resource alive, we can destroy the device + if (count == 0) + delete globalDevice; +} + +} // namespace sf diff --git a/src/SFML/Audio/AudioDevice.cpp b/src/SFML/Audio/AudioDevice.cpp index 2c9b8337..a9ed0fbb 100644 --- a/src/SFML/Audio/AudioDevice.cpp +++ b/src/SFML/Audio/AudioDevice.cpp @@ -29,12 +29,18 @@ #include #include #include +#include namespace { ALCdevice* audioDevice = NULL; ALCcontext* audioContext = NULL; + + float listenerVolume = 100.f; + sf::Vector3f listenerPosition (0.f, 0.f, 0.f); + sf::Vector3f listenerDirection(0.f, 0.f, -1.f); + sf::Vector3f listenerUpVector (0.f, 1.f, 0.f); } namespace sf @@ -56,6 +62,17 @@ AudioDevice::AudioDevice() { // Set the context as the current one (we'll only need one) alcMakeContextCurrent(audioContext); + + // Apply the listener properties the user might have set + float orientation[] = {listenerDirection.x, + listenerDirection.y, + listenerDirection.z, + listenerUpVector.x, + listenerUpVector.y, + listenerUpVector.z}; + alCheck(alListenerf(AL_GAIN, listenerVolume * 0.01f)); + alCheck(alListener3f(AL_POSITION, listenerPosition.x, listenerPosition.y, listenerPosition.z)); + alCheck(alListenerfv(AL_ORIENTATION, orientation)); } else { @@ -86,7 +103,10 @@ AudioDevice::~AudioDevice() //////////////////////////////////////////////////////////// bool AudioDevice::isExtensionSupported(const std::string& extension) { - ensureALInit(); + // Create a temporary audio device in case none exists yet. + std::auto_ptr device; + if (!audioDevice) + device = std::auto_ptr(new AudioDevice); if ((extension.length() > 2) && (extension.substr(0, 3) == "ALC")) return alcIsExtensionPresent(audioDevice, extension.c_str()) != AL_FALSE; @@ -98,7 +118,10 @@ bool AudioDevice::isExtensionSupported(const std::string& extension) //////////////////////////////////////////////////////////// int AudioDevice::getFormatFromChannelCount(unsigned int channelCount) { - ensureALInit(); + // Create a temporary audio device in case none exists yet. + std::auto_ptr device; + if (!audioDevice) + device = std::auto_ptr(new AudioDevice); // Find the good format according to the number of channels int format = 0; @@ -120,6 +143,92 @@ int AudioDevice::getFormatFromChannelCount(unsigned int channelCount) return format; } + +//////////////////////////////////////////////////////////// +void AudioDevice::setGlobalVolume(float volume) +{ + if (volume != listenerVolume) + { + if (audioContext) + alCheck(alListenerf(AL_GAIN, volume * 0.01f)); + + listenerVolume = volume; + } +} + + +//////////////////////////////////////////////////////////// +float AudioDevice::getGlobalVolume() +{ + return listenerVolume; +} + + +//////////////////////////////////////////////////////////// +void AudioDevice::setPosition(const Vector3f& position) +{ + if (position != listenerPosition) + { + if (audioContext) + alCheck(alListener3f(AL_POSITION, position.x, position.y, position.z)); + + listenerPosition = position; + } +} + + +//////////////////////////////////////////////////////////// +Vector3f AudioDevice::getPosition() +{ + return listenerPosition; +} + + +//////////////////////////////////////////////////////////// +void AudioDevice::setDirection(const Vector3f& direction) +{ + if (direction != listenerDirection) + { + if (audioContext) + { + float orientation[] = {direction.x, direction.y, direction.z, listenerUpVector.x, listenerUpVector.y, listenerUpVector.z}; + alCheck(alListenerfv(AL_ORIENTATION, orientation)); + } + + listenerDirection = direction; + } +} + + +//////////////////////////////////////////////////////////// +Vector3f AudioDevice::getDirection() +{ + return listenerDirection; +} + + +//////////////////////////////////////////////////////////// +void AudioDevice::setUpVector(const Vector3f& upVector) +{ + if (upVector != listenerUpVector) + { + if (audioContext) + { + float orientation[] = {listenerDirection.x, listenerDirection.y, listenerDirection.z, upVector.x, upVector.y, upVector.z}; + alCheck(alListenerfv(AL_ORIENTATION, orientation)); + } + + listenerUpVector = upVector; + } +} + + +//////////////////////////////////////////////////////////// +Vector3f AudioDevice::getUpVector() +{ + return listenerUpVector; +} + } // namespace priv } // namespace sf diff --git a/src/SFML/Audio/AudioDevice.hpp b/src/SFML/Audio/AudioDevice.hpp index 85c121b5..a8c5b48d 100644 --- a/src/SFML/Audio/AudioDevice.hpp +++ b/src/SFML/Audio/AudioDevice.hpp @@ -28,6 +28,7 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// +#include #include #include @@ -81,6 +82,106 @@ public: /// //////////////////////////////////////////////////////////// static int getFormatFromChannelCount(unsigned int channelCount); + + //////////////////////////////////////////////////////////// + /// \brief Change the global volume of all the sounds and musics + /// + /// The volume is a number between 0 and 100; it is combined with + /// the individual volume of each sound / music. + /// The default value for the volume is 100 (maximum). + /// + /// \param volume New global volume, in the range [0, 100] + /// + /// \see getGlobalVolume + /// + //////////////////////////////////////////////////////////// + static void setGlobalVolume(float volume); + + //////////////////////////////////////////////////////////// + /// \brief Get the current value of the global volume + /// + /// \return Current global volume, in the range [0, 100] + /// + /// \see setGlobalVolume + /// + //////////////////////////////////////////////////////////// + static float getGlobalVolume(); + + //////////////////////////////////////////////////////////// + /// \brief Set the position of the listener in the scene + /// + /// The default listener's position is (0, 0, 0). + /// + /// \param position New listener's position + /// + /// \see getPosition, setDirection + /// + //////////////////////////////////////////////////////////// + static void setPosition(const Vector3f& position); + + //////////////////////////////////////////////////////////// + /// \brief Get the current position of the listener in the scene + /// + /// \return Listener's position + /// + /// \see setPosition + /// + //////////////////////////////////////////////////////////// + static Vector3f getPosition(); + + //////////////////////////////////////////////////////////// + /// \brief Set the forward vector of the listener in the scene + /// + /// The direction (also called "at vector") is the vector + /// pointing forward from the listener's perspective. Together + /// with the up vector, it defines the 3D orientation of the + /// listener in the scene. The direction vector doesn't + /// have to be normalized. + /// The default listener's direction is (0, 0, -1). + /// + /// \param direction New listener's direction + /// + /// \see getDirection, setUpVector, setPosition + /// + //////////////////////////////////////////////////////////// + static void setDirection(const Vector3f& direction); + + //////////////////////////////////////////////////////////// + /// \brief Get the current forward vector of the listener in the scene + /// + /// \return Listener's forward vector (not normalized) + /// + /// \see setDirection + /// + //////////////////////////////////////////////////////////// + static Vector3f getDirection(); + + //////////////////////////////////////////////////////////// + /// \brief Set the upward vector of the listener in the scene + /// + /// The up vector is the vector that points upward from the + /// listener's perspective. Together with the direction, it + /// defines the 3D orientation of the listener in the scene. + /// The up vector doesn't have to be normalized. + /// The default listener's up vector is (0, 1, 0). It is usually + /// not necessary to change it, especially in 2D scenarios. + /// + /// \param upVector New listener's up vector + /// + /// \see getUpVector, setDirection, setPosition + /// + //////////////////////////////////////////////////////////// + static void setUpVector(const Vector3f& upVector); + + //////////////////////////////////////////////////////////// + /// \brief Get the current upward vector of the listener in the scene + /// + /// \return Listener's upward vector (not normalized) + /// + /// \see setUpVector + /// + //////////////////////////////////////////////////////////// + static Vector3f getUpVector(); }; } // namespace priv diff --git a/src/SFML/Audio/CMakeLists.txt b/src/SFML/Audio/CMakeLists.txt index ee7b7cbb..52844315 100644 --- a/src/SFML/Audio/CMakeLists.txt +++ b/src/SFML/Audio/CMakeLists.txt @@ -6,6 +6,8 @@ set(SRCROOT ${PROJECT_SOURCE_DIR}/src/SFML/Audio) set(SRC ${SRCROOT}/ALCheck.cpp ${SRCROOT}/ALCheck.hpp + ${SRCROOT}/AlResource.cpp + ${INCROOT}/AlResource.hpp ${SRCROOT}/AudioDevice.cpp ${SRCROOT}/AudioDevice.hpp ${INCROOT}/Export.hpp diff --git a/src/SFML/Audio/Listener.cpp b/src/SFML/Audio/Listener.cpp index ec0a32fd..ff0990ff 100644 --- a/src/SFML/Audio/Listener.cpp +++ b/src/SFML/Audio/Listener.cpp @@ -26,16 +26,7 @@ // Headers //////////////////////////////////////////////////////////// #include -#include - - -namespace -{ - float listenerVolume = 100.f; - sf::Vector3f listenerPosition (0.f, 0.f, 0.f); - sf::Vector3f listenerDirection(0.f, 0.f, -1.f); - sf::Vector3f listenerUpVector (0.f, 1.f, 0.f); -} +#include namespace sf @@ -43,20 +34,14 @@ namespace sf //////////////////////////////////////////////////////////// void Listener::setGlobalVolume(float volume) { - if (volume != listenerVolume) - { - priv::ensureALInit(); - - alCheck(alListenerf(AL_GAIN, volume * 0.01f)); - listenerVolume = volume; - } + priv::AudioDevice::setGlobalVolume(volume); } //////////////////////////////////////////////////////////// float Listener::getGlobalVolume() { - return listenerVolume; + return priv::AudioDevice::getGlobalVolume(); } @@ -70,20 +55,14 @@ void Listener::setPosition(float x, float y, float z) //////////////////////////////////////////////////////////// void Listener::setPosition(const Vector3f& position) { - if (position != listenerPosition) - { - priv::ensureALInit(); - - alCheck(alListener3f(AL_POSITION, position.x, position.y, position.z)); - listenerPosition = position; - } + priv::AudioDevice::setPosition(position); } //////////////////////////////////////////////////////////// Vector3f Listener::getPosition() { - return listenerPosition; + return priv::AudioDevice::getPosition(); } @@ -97,21 +76,14 @@ void Listener::setDirection(float x, float y, float z) //////////////////////////////////////////////////////////// void Listener::setDirection(const Vector3f& direction) { - if (direction != listenerDirection) - { - priv::ensureALInit(); - - float orientation[] = {direction.x, direction.y, direction.z, listenerUpVector.x, listenerUpVector.y, listenerUpVector.z}; - alCheck(alListenerfv(AL_ORIENTATION, orientation)); - listenerDirection = direction; - } + priv::AudioDevice::setDirection(direction); } //////////////////////////////////////////////////////////// Vector3f Listener::getDirection() { - return listenerDirection; + return priv::AudioDevice::getDirection(); } @@ -125,21 +97,14 @@ void Listener::setUpVector(float x, float y, float z) //////////////////////////////////////////////////////////// void Listener::setUpVector(const Vector3f& upVector) { - if (upVector != listenerUpVector) - { - priv::ensureALInit(); - - float orientation[] = {listenerDirection.x, listenerDirection.y, listenerDirection.z, upVector.x, upVector.y, upVector.z}; - alCheck(alListenerfv(AL_ORIENTATION, orientation)); - listenerUpVector = upVector; - } + priv::AudioDevice::setUpVector(upVector); } //////////////////////////////////////////////////////////// Vector3f Listener::getUpVector() { - return listenerUpVector; + return priv::AudioDevice::getUpVector(); } } // namespace sf diff --git a/src/SFML/Audio/SoundBuffer.cpp b/src/SFML/Audio/SoundBuffer.cpp index 0d8818c7..3b971d78 100644 --- a/src/SFML/Audio/SoundBuffer.cpp +++ b/src/SFML/Audio/SoundBuffer.cpp @@ -41,8 +41,6 @@ SoundBuffer::SoundBuffer() : m_buffer (0), m_duration() { - priv::ensureALInit(); - // Create the buffer alCheck(alGenBuffers(1, &m_buffer)); } diff --git a/src/SFML/Audio/SoundRecorder.cpp b/src/SFML/Audio/SoundRecorder.cpp index 51e7ef97..3b3624a6 100644 --- a/src/SFML/Audio/SoundRecorder.cpp +++ b/src/SFML/Audio/SoundRecorder.cpp @@ -51,8 +51,6 @@ m_sampleRate (0), m_processingInterval(milliseconds(100)), m_isCapturing (false) { - priv::ensureALInit(); - // Set the device name to the default device m_deviceName = getDefaultDevice(); } diff --git a/src/SFML/Audio/SoundSource.cpp b/src/SFML/Audio/SoundSource.cpp index 3129b2e9..f156cc8e 100644 --- a/src/SFML/Audio/SoundSource.cpp +++ b/src/SFML/Audio/SoundSource.cpp @@ -34,8 +34,6 @@ namespace sf //////////////////////////////////////////////////////////// SoundSource::SoundSource() { - priv::ensureALInit(); - alCheck(alGenSources(1, &m_source)); alCheck(alSourcei(m_source, AL_BUFFER, 0)); } @@ -44,8 +42,6 @@ SoundSource::SoundSource() //////////////////////////////////////////////////////////// SoundSource::SoundSource(const SoundSource& copy) { - priv::ensureALInit(); - alCheck(alGenSources(1, &m_source)); alCheck(alSourcei(m_source, AL_BUFFER, 0));