diff --git a/include/SFML/Audio/AlResource.hpp b/include/SFML/Audio/AlResource.hpp new file mode 100644 index 000000000..c4e34e050 --- /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 392b4617a..e8a502af9 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 733fd322b..67bacc8d4 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 f8ba48aaa..ea2800c43 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 1a7e4bb9d..0baa8303a 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 b31a031ed..30642a108 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 000000000..48c737ba5 --- /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 2c9b83370..3ad54b71d 100644 --- a/src/SFML/Audio/AudioDevice.cpp +++ b/src/SFML/Audio/AudioDevice.cpp @@ -29,12 +29,18 @@ #include #include #include +#include -namespace +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,13 @@ AudioDevice::~AudioDevice() //////////////////////////////////////////////////////////// bool AudioDevice::isExtensionSupported(const std::string& extension) { - ensureALInit(); + // Create a temporary audio device in case none exists yet. + // This device will not be used in this function and merely + // makes sure there is a valid OpenAL device for extension + // queries if none has been created yet. + std::auto_ptr device; + if (!audioDevice) + device.reset(new AudioDevice); if ((extension.length() > 2) && (extension.substr(0, 3) == "ALC")) return alcIsExtensionPresent(audioDevice, extension.c_str()) != AL_FALSE; @@ -98,7 +121,13 @@ bool AudioDevice::isExtensionSupported(const std::string& extension) //////////////////////////////////////////////////////////// int AudioDevice::getFormatFromChannelCount(unsigned int channelCount) { - ensureALInit(); + // Create a temporary audio device in case none exists yet. + // This device will not be used in this function and merely + // makes sure there is a valid OpenAL device for format + // queries if none has been created yet. + std::auto_ptr device; + if (!audioDevice) + device.reset(new AudioDevice); // Find the good format according to the number of channels int format = 0; @@ -120,6 +149,80 @@ int AudioDevice::getFormatFromChannelCount(unsigned int channelCount) return format; } + +//////////////////////////////////////////////////////////// +void AudioDevice::setGlobalVolume(float volume) +{ + if (audioContext) + alCheck(alListenerf(AL_GAIN, volume * 0.01f)); + + listenerVolume = volume; +} + + +//////////////////////////////////////////////////////////// +float AudioDevice::getGlobalVolume() +{ + return listenerVolume; +} + + +//////////////////////////////////////////////////////////// +void AudioDevice::setPosition(const Vector3f& position) +{ + 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 (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 (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 85c121b54..a8c5b48d0 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 ee7b7cbbf..528443155 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 ec0a32fde..ff0990ff9 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 0d8818c7d..3b971d784 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 51e7ef97f..3b3624a67 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 3129b2e93..f156cc8ef 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));