diff options
Diffstat (limited to 'src/SFML/Audio')
-rw-r--r-- | src/SFML/Audio/ALCheck.cpp | 218 | ||||
-rw-r--r-- | src/SFML/Audio/ALCheck.hpp | 156 | ||||
-rw-r--r-- | src/SFML/Audio/AudioDevice.cpp | 250 | ||||
-rw-r--r-- | src/SFML/Audio/AudioDevice.hpp | 182 | ||||
-rw-r--r-- | src/SFML/Audio/CMakeLists.txt | 118 | ||||
-rw-r--r-- | src/SFML/Audio/Listener.cpp | 256 | ||||
-rw-r--r-- | src/SFML/Audio/Music.cpp | 302 | ||||
-rw-r--r-- | src/SFML/Audio/Sound.cpp | 396 | ||||
-rw-r--r-- | src/SFML/Audio/SoundBuffer.cpp | 561 | ||||
-rw-r--r-- | src/SFML/Audio/SoundBufferRecorder.cpp | 136 | ||||
-rw-r--r-- | src/SFML/Audio/SoundFile.cpp | 876 | ||||
-rw-r--r-- | src/SFML/Audio/SoundFile.hpp | 459 | ||||
-rw-r--r-- | src/SFML/Audio/SoundRecorder.cpp | 493 | ||||
-rw-r--r-- | src/SFML/Audio/SoundSource.cpp | 388 | ||||
-rw-r--r-- | src/SFML/Audio/SoundStream.cpp | 834 |
15 files changed, 2953 insertions, 2672 deletions
diff --git a/src/SFML/Audio/ALCheck.cpp b/src/SFML/Audio/ALCheck.cpp index 0558f11..1a7e4bb 100644 --- a/src/SFML/Audio/ALCheck.cpp +++ b/src/SFML/Audio/ALCheck.cpp @@ -1,109 +1,109 @@ -////////////////////////////////////////////////////////////
-//
-// SFML - Simple and Fast Multimedia Library
-// Copyright (C) 2007-2013 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 <SFML/Audio/ALCheck.hpp>
-#include <SFML/Audio/AudioDevice.hpp>
-#include <SFML/System/Err.hpp>
-
-
-namespace sf
-{
-namespace priv
-{
-////////////////////////////////////////////////////////////
-void alCheckError(const std::string& file, unsigned int line)
-{
- // Get the last error
- ALenum errorCode = alGetError();
-
- if (errorCode != AL_NO_ERROR)
- {
- std::string error, description;
-
- // Decode the error code
- switch (errorCode)
- {
- case AL_INVALID_NAME :
- {
- error = "AL_INVALID_NAME";
- description = "an unacceptable name has been specified";
- break;
- }
-
- case AL_INVALID_ENUM :
- {
- error = "AL_INVALID_ENUM";
- description = "an unacceptable value has been specified for an enumerated argument";
- break;
- }
-
- case AL_INVALID_VALUE :
- {
- error = "AL_INVALID_VALUE";
- description = "a numeric argument is out of range";
- break;
- }
-
- case AL_INVALID_OPERATION :
- {
- error = "AL_INVALID_OPERATION";
- description = "the specified operation is not allowed in the current state";
- break;
- }
-
- case AL_OUT_OF_MEMORY :
- {
- error = "AL_OUT_OF_MEMORY";
- description = "there is not enough memory left to execute the command";
- break;
- }
- }
-
- // Log the error
- err() << "An internal OpenAL call failed in "
- << file.substr(file.find_last_of("\\/") + 1) << " (" << line << ") : "
- << error << ", " << description
- << std::endl;
- }
-}
-
-
-////////////////////////////////////////////////////////////
-/// Make sure that OpenAL is initialized
-////////////////////////////////////////////////////////////
-void ensureALInit()
-{
- // The audio device is instanciated 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
+//////////////////////////////////////////////////////////// +// +// 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 <SFML/Audio/ALCheck.hpp> +#include <SFML/Audio/AudioDevice.hpp> +#include <SFML/System/Err.hpp> + + +namespace sf +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +void alCheckError(const std::string& file, unsigned int line) +{ + // Get the last error + ALenum errorCode = alGetError(); + + if (errorCode != AL_NO_ERROR) + { + std::string error, description; + + // Decode the error code + switch (errorCode) + { + case AL_INVALID_NAME: + { + error = "AL_INVALID_NAME"; + description = "an unacceptable name has been specified"; + break; + } + + case AL_INVALID_ENUM: + { + error = "AL_INVALID_ENUM"; + description = "an unacceptable value has been specified for an enumerated argument"; + break; + } + + case AL_INVALID_VALUE: + { + error = "AL_INVALID_VALUE"; + description = "a numeric argument is out of range"; + break; + } + + case AL_INVALID_OPERATION: + { + error = "AL_INVALID_OPERATION"; + description = "the specified operation is not allowed in the current state"; + break; + } + + case AL_OUT_OF_MEMORY: + { + error = "AL_OUT_OF_MEMORY"; + description = "there is not enough memory left to execute the command"; + break; + } + } + + // Log the error + err() << "An internal OpenAL call failed in " + << file.substr(file.find_last_of("\\/") + 1) << " (" << line << ") : " + << error << ", " << description + << std::endl; + } +} + + +//////////////////////////////////////////////////////////// +/// 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 7c7d659..b31a031 100644 --- a/src/SFML/Audio/ALCheck.hpp +++ b/src/SFML/Audio/ALCheck.hpp @@ -1,78 +1,78 @@ -////////////////////////////////////////////////////////////
-//
-// SFML - Simple and Fast Multimedia Library
-// Copyright (C) 2007-2013 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_ALCHECK_HPP
-#define SFML_ALCHECK_HPP
-
-////////////////////////////////////////////////////////////
-// Headers
-////////////////////////////////////////////////////////////
-#include <SFML/Config.hpp>
-#include <iostream>
-#include <string>
-#include <al.h>
-#include <alc.h>
-
-
-namespace sf
-{
-namespace priv
-{
-////////////////////////////////////////////////////////////
-/// Let's define a macro to quickly check every OpenAL API calls
-////////////////////////////////////////////////////////////
-#ifdef SFML_DEBUG
-
- // If in debug mode, perform a test on every call
- #define alCheck(Func) ((Func), priv::alCheckError(__FILE__, __LINE__))
-
-#else
-
- // Else, we don't add any overhead
- #define alCheck(Func) (Func)
-
-#endif
-
-
-////////////////////////////////////////////////////////////
-/// Check the last OpenAL error
-///
-/// \param file Source file where the call is located
-/// \param line Line number of the source file where the call is located
-///
-////////////////////////////////////////////////////////////
-void alCheckError(const std::string& file, unsigned int line);
-
-////////////////////////////////////////////////////////////
-/// Make sure that OpenAL is initialized
-///
-////////////////////////////////////////////////////////////
-void ensureALInit();
-
-} // namespace priv
-
-} // namespace sf
-
-
-#endif // SFML_ALCHECK_HPP
+//////////////////////////////////////////////////////////// +// +// 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_ALCHECK_HPP +#define SFML_ALCHECK_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include <SFML/Config.hpp> +#include <iostream> +#include <string> +#include <al.h> +#include <alc.h> + + +namespace sf +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +/// Let's define a macro to quickly check every OpenAL API calls +//////////////////////////////////////////////////////////// +#ifdef SFML_DEBUG + + // If in debug mode, perform a test on every call + #define alCheck(x) x; sf::priv::alCheckError(__FILE__, __LINE__); + +#else + + // Else, we don't add any overhead + #define alCheck(Func) (Func) + +#endif + + +//////////////////////////////////////////////////////////// +/// Check the last OpenAL error +/// +/// \param file Source file where the call is located +/// \param line Line number of the source file where the call is located +/// +//////////////////////////////////////////////////////////// +void alCheckError(const std::string& file, unsigned int line); + +//////////////////////////////////////////////////////////// +/// Make sure that OpenAL is initialized +/// +//////////////////////////////////////////////////////////// +void ensureALInit(); + +} // namespace priv + +} // namespace sf + + +#endif // SFML_ALCHECK_HPP diff --git a/src/SFML/Audio/AudioDevice.cpp b/src/SFML/Audio/AudioDevice.cpp index d218b91..2c9b833 100644 --- a/src/SFML/Audio/AudioDevice.cpp +++ b/src/SFML/Audio/AudioDevice.cpp @@ -1,125 +1,125 @@ -////////////////////////////////////////////////////////////
-//
-// SFML - Simple and Fast Multimedia Library
-// Copyright (C) 2007-2013 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 <SFML/Audio/AudioDevice.hpp>
-#include <SFML/Audio/ALCheck.hpp>
-#include <SFML/Audio/Listener.hpp>
-#include <SFML/System/Err.hpp>
-
-
-namespace
-{
- ALCdevice* audioDevice = NULL;
- ALCcontext* audioContext = NULL;
-}
-
-namespace sf
-{
-namespace priv
-{
-////////////////////////////////////////////////////////////
-AudioDevice::AudioDevice()
-{
- // Create the device
- audioDevice = alcOpenDevice(NULL);
-
- if (audioDevice)
- {
- // Create the context
- audioContext = alcCreateContext(audioDevice, NULL);
-
- if (audioContext)
- {
- // Set the context as the current one (we'll only need one)
- alcMakeContextCurrent(audioContext);
- }
- else
- {
- err() << "Failed to create the audio context" << std::endl;
- }
- }
- else
- {
- err() << "Failed to open the audio device" << std::endl;
- }
-}
-
-
-////////////////////////////////////////////////////////////
-AudioDevice::~AudioDevice()
-{
- // Destroy the context
- alcMakeContextCurrent(NULL);
- if (audioContext)
- alcDestroyContext(audioContext);
-
- // Destroy the device
- if (audioDevice)
- alcCloseDevice(audioDevice);
-}
-
-
-////////////////////////////////////////////////////////////
-bool AudioDevice::isExtensionSupported(const std::string& extension)
-{
- ensureALInit();
-
- if ((extension.length() > 2) && (extension.substr(0, 3) == "ALC"))
- return alcIsExtensionPresent(audioDevice, extension.c_str()) != AL_FALSE;
- else
- return alIsExtensionPresent(extension.c_str()) != AL_FALSE;
-}
-
-
-////////////////////////////////////////////////////////////
-int AudioDevice::getFormatFromChannelCount(unsigned int channelCount)
-{
- ensureALInit();
-
- // Find the good format according to the number of channels
- int format = 0;
- switch (channelCount)
- {
- case 1 : format = AL_FORMAT_MONO16; break;
- case 2 : format = AL_FORMAT_STEREO16; break;
- case 4 : format = alGetEnumValue("AL_FORMAT_QUAD16"); break;
- case 6 : format = alGetEnumValue("AL_FORMAT_51CHN16"); break;
- case 7 : format = alGetEnumValue("AL_FORMAT_61CHN16"); break;
- case 8 : format = alGetEnumValue("AL_FORMAT_71CHN16"); break;
- default : format = 0; break;
- }
-
- // Fixes a bug on OS X
- if (format == -1)
- format = 0;
-
- return format;
-}
-
-} // namespace priv
-
-} // namespace sf
+//////////////////////////////////////////////////////////// +// +// 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 <SFML/Audio/AudioDevice.hpp> +#include <SFML/Audio/ALCheck.hpp> +#include <SFML/Audio/Listener.hpp> +#include <SFML/System/Err.hpp> + + +namespace +{ + ALCdevice* audioDevice = NULL; + ALCcontext* audioContext = NULL; +} + +namespace sf +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +AudioDevice::AudioDevice() +{ + // Create the device + audioDevice = alcOpenDevice(NULL); + + if (audioDevice) + { + // Create the context + audioContext = alcCreateContext(audioDevice, NULL); + + if (audioContext) + { + // Set the context as the current one (we'll only need one) + alcMakeContextCurrent(audioContext); + } + else + { + err() << "Failed to create the audio context" << std::endl; + } + } + else + { + err() << "Failed to open the audio device" << std::endl; + } +} + + +//////////////////////////////////////////////////////////// +AudioDevice::~AudioDevice() +{ + // Destroy the context + alcMakeContextCurrent(NULL); + if (audioContext) + alcDestroyContext(audioContext); + + // Destroy the device + if (audioDevice) + alcCloseDevice(audioDevice); +} + + +//////////////////////////////////////////////////////////// +bool AudioDevice::isExtensionSupported(const std::string& extension) +{ + ensureALInit(); + + if ((extension.length() > 2) && (extension.substr(0, 3) == "ALC")) + return alcIsExtensionPresent(audioDevice, extension.c_str()) != AL_FALSE; + else + return alIsExtensionPresent(extension.c_str()) != AL_FALSE; +} + + +//////////////////////////////////////////////////////////// +int AudioDevice::getFormatFromChannelCount(unsigned int channelCount) +{ + ensureALInit(); + + // Find the good format according to the number of channels + int format = 0; + switch (channelCount) + { + case 1: format = AL_FORMAT_MONO16; break; + case 2: format = AL_FORMAT_STEREO16; break; + case 4: format = alGetEnumValue("AL_FORMAT_QUAD16"); break; + case 6: format = alGetEnumValue("AL_FORMAT_51CHN16"); break; + case 7: format = alGetEnumValue("AL_FORMAT_61CHN16"); break; + case 8: format = alGetEnumValue("AL_FORMAT_71CHN16"); break; + default: format = 0; break; + } + + // Fixes a bug on OS X + if (format == -1) + format = 0; + + return format; +} + +} // namespace priv + +} // namespace sf diff --git a/src/SFML/Audio/AudioDevice.hpp b/src/SFML/Audio/AudioDevice.hpp index 01c7b4c..85c121b 100644 --- a/src/SFML/Audio/AudioDevice.hpp +++ b/src/SFML/Audio/AudioDevice.hpp @@ -1,91 +1,91 @@ -////////////////////////////////////////////////////////////
-//
-// SFML - Simple and Fast Multimedia Library
-// Copyright (C) 2007-2013 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_AUDIODEVICE_HPP
-#define SFML_AUDIODEVICE_HPP
-
-////////////////////////////////////////////////////////////
-// Headers
-////////////////////////////////////////////////////////////
-#include <set>
-#include <string>
-
-
-namespace sf
-{
-namespace priv
-{
-////////////////////////////////////////////////////////////
-/// \brief High-level wrapper around the audio API, it manages
-/// the creation and destruction of the audio device and
-/// context and stores the device capabilities
-///
-////////////////////////////////////////////////////////////
-class AudioDevice
-{
-public :
-
- ////////////////////////////////////////////////////////////
- /// \brief Default constructor
- ///
- ////////////////////////////////////////////////////////////
- AudioDevice();
-
- ////////////////////////////////////////////////////////////
- /// \brief Destructor
- ///
- ////////////////////////////////////////////////////////////
- ~AudioDevice();
-
- ////////////////////////////////////////////////////////////
- /// \brief Check if an OpenAL extension is supported
- ///
- /// This functions automatically finds whether it
- /// is an AL or ALC extension, and calls the corresponding
- /// function.
- ///
- /// \param extension Name of the extension to test
- ///
- /// \return True if the extension is supported, false if not
- ///
- ////////////////////////////////////////////////////////////
- static bool isExtensionSupported(const std::string& extension);
-
- ////////////////////////////////////////////////////////////
- /// \brief Get the OpenAL format that matches the given number of channels
- ///
- /// \param channelCount Number of channels
- ///
- /// \return Corresponding format
- ///
- ////////////////////////////////////////////////////////////
- static int getFormatFromChannelCount(unsigned int channelCount);
-};
-
-} // namespace priv
-
-} // namespace sf
-
-
-#endif // SFML_AUDIODEVICE_HPP
+//////////////////////////////////////////////////////////// +// +// 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_AUDIODEVICE_HPP +#define SFML_AUDIODEVICE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include <set> +#include <string> + + +namespace sf +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +/// \brief High-level wrapper around the audio API, it manages +/// the creation and destruction of the audio device and +/// context and stores the device capabilities +/// +//////////////////////////////////////////////////////////// +class AudioDevice +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + AudioDevice(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~AudioDevice(); + + //////////////////////////////////////////////////////////// + /// \brief Check if an OpenAL extension is supported + /// + /// This functions automatically finds whether it + /// is an AL or ALC extension, and calls the corresponding + /// function. + /// + /// \param extension Name of the extension to test + /// + /// \return True if the extension is supported, false if not + /// + //////////////////////////////////////////////////////////// + static bool isExtensionSupported(const std::string& extension); + + //////////////////////////////////////////////////////////// + /// \brief Get the OpenAL format that matches the given number of channels + /// + /// \param channelCount Number of channels + /// + /// \return Corresponding format + /// + //////////////////////////////////////////////////////////// + static int getFormatFromChannelCount(unsigned int channelCount); +}; + +} // namespace priv + +} // namespace sf + + +#endif // SFML_AUDIODEVICE_HPP diff --git a/src/SFML/Audio/CMakeLists.txt b/src/SFML/Audio/CMakeLists.txt index 818b9b6..ee7b7cb 100644 --- a/src/SFML/Audio/CMakeLists.txt +++ b/src/SFML/Audio/CMakeLists.txt @@ -1,53 +1,65 @@ -
-set(INCROOT ${PROJECT_SOURCE_DIR}/include/SFML/Audio)
-set(SRCROOT ${PROJECT_SOURCE_DIR}/src/SFML/Audio)
-
-# all source files
-set(SRC
- ${SRCROOT}/ALCheck.cpp
- ${SRCROOT}/ALCheck.hpp
- ${SRCROOT}/AudioDevice.cpp
- ${SRCROOT}/AudioDevice.hpp
- ${INCROOT}/Export.hpp
- ${SRCROOT}/Listener.cpp
- ${INCROOT}/Listener.hpp
- ${SRCROOT}/Music.cpp
- ${INCROOT}/Music.hpp
- ${SRCROOT}/Sound.cpp
- ${INCROOT}/Sound.hpp
- ${SRCROOT}/SoundBuffer.cpp
- ${INCROOT}/SoundBuffer.hpp
- ${SRCROOT}/SoundBufferRecorder.cpp
- ${INCROOT}/SoundBufferRecorder.hpp
- ${SRCROOT}/SoundFile.cpp
- ${SRCROOT}/SoundFile.hpp
- ${SRCROOT}/SoundRecorder.cpp
- ${INCROOT}/SoundRecorder.hpp
- ${SRCROOT}/SoundSource.cpp
- ${INCROOT}/SoundSource.hpp
- ${SRCROOT}/SoundStream.cpp
- ${INCROOT}/SoundStream.hpp
-)
-source_group("" FILES ${SRC})
-
-# let CMake know about our additional audio libraries paths (on Windows and OSX)
-if(WINDOWS)
- set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/AL")
- set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/libsndfile/windows")
-elseif (MACOSX)
- set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/libsndfile/osx")
- set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${PROJECT_SOURCE_DIR}/extlibs/libs-osx/Frameworks")
-endif()
-
-# find external libraries
-find_package(OpenAL REQUIRED)
-find_package(Sndfile REQUIRED)
-
-# add include paths of external libraries
-include_directories(${OPENAL_INCLUDE_DIR} ${SNDFILE_INCLUDE_DIR})
-
-# define the sfml-audio target
-sfml_add_library(sfml-audio
- SOURCES ${SRC}
- DEPENDS sfml-system
- EXTERNAL_LIBS ${OPENAL_LIBRARY} ${SNDFILE_LIBRARY})
+ +set(INCROOT ${PROJECT_SOURCE_DIR}/include/SFML/Audio) +set(SRCROOT ${PROJECT_SOURCE_DIR}/src/SFML/Audio) + +# all source files +set(SRC + ${SRCROOT}/ALCheck.cpp + ${SRCROOT}/ALCheck.hpp + ${SRCROOT}/AudioDevice.cpp + ${SRCROOT}/AudioDevice.hpp + ${INCROOT}/Export.hpp + ${SRCROOT}/Listener.cpp + ${INCROOT}/Listener.hpp + ${SRCROOT}/Music.cpp + ${INCROOT}/Music.hpp + ${SRCROOT}/Sound.cpp + ${INCROOT}/Sound.hpp + ${SRCROOT}/SoundBuffer.cpp + ${INCROOT}/SoundBuffer.hpp + ${SRCROOT}/SoundBufferRecorder.cpp + ${INCROOT}/SoundBufferRecorder.hpp + ${SRCROOT}/SoundFile.cpp + ${SRCROOT}/SoundFile.hpp + ${SRCROOT}/SoundRecorder.cpp + ${INCROOT}/SoundRecorder.hpp + ${SRCROOT}/SoundSource.cpp + ${INCROOT}/SoundSource.hpp + ${SRCROOT}/SoundStream.cpp + ${INCROOT}/SoundStream.hpp +) +source_group("" FILES ${SRC}) + +# let CMake know about our additional audio libraries paths (on Windows and OSX) +if(SFML_OS_WINDOWS) + set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/AL") + set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/libsndfile/windows") +elseif(SFML_OS_MACOSX) + set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/libsndfile/osx") + set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${PROJECT_SOURCE_DIR}/extlibs/libs-osx/Frameworks") +elseif(SFML_OS_ANDROID) + set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/AL") + set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/libsndfile/android") +endif() + +# find external libraries +if(NOT SFML_OS_ANDROID) + find_package(OpenAL REQUIRED) + find_package(Sndfile REQUIRED) +else() + find_host_package(OpenAL REQUIRED) + find_host_package(Sndfile REQUIRED) +endif() +include_directories(${OPENAL_INCLUDE_DIR} ${SNDFILE_INCLUDE_DIR}) + +# build the list of external libraries to link +if(SFML_OS_ANDROID) + list(APPEND AUDIO_EXT_LIBS -landroid -lOpenSLES) +endif() +list(APPEND AUDIO_EXT_LIBS ${OPENAL_LIBRARY} ${SNDFILE_LIBRARY}) + +# define the sfml-audio target +sfml_add_library(sfml-audio + SOURCES ${SRC} + DEPENDS sfml-system + EXTERNAL_LIBS ${AUDIO_EXT_LIBS}) diff --git a/src/SFML/Audio/Listener.cpp b/src/SFML/Audio/Listener.cpp index a4995ce..ec0a32f 100644 --- a/src/SFML/Audio/Listener.cpp +++ b/src/SFML/Audio/Listener.cpp @@ -1,111 +1,145 @@ -////////////////////////////////////////////////////////////
-//
-// SFML - Simple and Fast Multimedia Library
-// Copyright (C) 2007-2013 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 <SFML/Audio/Listener.hpp>
-#include <SFML/Audio/ALCheck.hpp>
-
-
-namespace sf
-{
-////////////////////////////////////////////////////////////
-void Listener::setGlobalVolume(float volume)
-{
- priv::ensureALInit();
-
- alCheck(alListenerf(AL_GAIN, volume * 0.01f));
-}
-
-
-////////////////////////////////////////////////////////////
-float Listener::getGlobalVolume()
-{
- priv::ensureALInit();
-
- float volume = 0.f;
- alCheck(alGetListenerf(AL_GAIN, &volume));
-
- return volume * 100;
-}
-
-
-////////////////////////////////////////////////////////////
-void Listener::setPosition(float x, float y, float z)
-{
- priv::ensureALInit();
-
- alCheck(alListener3f(AL_POSITION, x, y, z));
-}
-
-
-////////////////////////////////////////////////////////////
-void Listener::setPosition(const Vector3f& position)
-{
- setPosition(position.x, position.y, position.z);
-}
-
-
-////////////////////////////////////////////////////////////
-Vector3f Listener::getPosition()
-{
- priv::ensureALInit();
-
- Vector3f position;
- alCheck(alGetListener3f(AL_POSITION, &position.x, &position.y, &position.z));
-
- return position;
-}
-
-
-////////////////////////////////////////////////////////////
-void Listener::setDirection(float x, float y, float z)
-{
- priv::ensureALInit();
-
- float orientation[] = {x, y, z, 0.f, 1.f, 0.f};
- alCheck(alListenerfv(AL_ORIENTATION, orientation));
-}
-
-
-////////////////////////////////////////////////////////////
-void Listener::setDirection(const Vector3f& direction)
-{
- setDirection(direction.x, direction.y, direction.z);
-}
-
-
-////////////////////////////////////////////////////////////
-Vector3f Listener::getDirection()
-{
- priv::ensureALInit();
-
- float orientation[6];
- alCheck(alGetListenerfv(AL_ORIENTATION, orientation));
-
- return Vector3f(orientation[0], orientation[1], orientation[2]);
-}
-
-} // namespace sf
+//////////////////////////////////////////////////////////// +// +// 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 <SFML/Audio/Listener.hpp> +#include <SFML/Audio/ALCheck.hpp> + + +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); +} + + +namespace sf +{ +//////////////////////////////////////////////////////////// +void Listener::setGlobalVolume(float volume) +{ + if (volume != listenerVolume) + { + priv::ensureALInit(); + + alCheck(alListenerf(AL_GAIN, volume * 0.01f)); + listenerVolume = volume; + } +} + + +//////////////////////////////////////////////////////////// +float Listener::getGlobalVolume() +{ + return listenerVolume; +} + + +//////////////////////////////////////////////////////////// +void Listener::setPosition(float x, float y, float z) +{ + setPosition(Vector3f(x, y, z)); +} + + +//////////////////////////////////////////////////////////// +void Listener::setPosition(const Vector3f& position) +{ + if (position != listenerPosition) + { + priv::ensureALInit(); + + alCheck(alListener3f(AL_POSITION, position.x, position.y, position.z)); + listenerPosition = position; + } +} + + +//////////////////////////////////////////////////////////// +Vector3f Listener::getPosition() +{ + return listenerPosition; +} + + +//////////////////////////////////////////////////////////// +void Listener::setDirection(float x, float y, float z) +{ + setDirection(Vector3f(x, y, 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; + } +} + + +//////////////////////////////////////////////////////////// +Vector3f Listener::getDirection() +{ + return listenerDirection; +} + + +//////////////////////////////////////////////////////////// +void Listener::setUpVector(float x, float y, float z) +{ + setUpVector(Vector3f(x, y, 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; + } +} + + +//////////////////////////////////////////////////////////// +Vector3f Listener::getUpVector() +{ + return listenerUpVector; +} + +} // namespace sf diff --git a/src/SFML/Audio/Music.cpp b/src/SFML/Audio/Music.cpp index ef784e4..6f3b6db 100644 --- a/src/SFML/Audio/Music.cpp +++ b/src/SFML/Audio/Music.cpp @@ -1,151 +1,151 @@ -////////////////////////////////////////////////////////////
-//
-// SFML - Simple and Fast Multimedia Library
-// Copyright (C) 2007-2013 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 <SFML/Audio/Music.hpp>
-#include <SFML/Audio/ALCheck.hpp>
-#include <SFML/Audio/SoundFile.hpp>
-#include <SFML/System/Lock.hpp>
-#include <SFML/System/Err.hpp>
-#include <fstream>
-
-
-namespace sf
-{
-////////////////////////////////////////////////////////////
-Music::Music() :
-m_file (new priv::SoundFile),
-m_duration()
-{
-
-}
-
-
-////////////////////////////////////////////////////////////
-Music::~Music()
-{
- // We must stop before destroying the file :)
- stop();
-
- delete m_file;
-}
-
-
-////////////////////////////////////////////////////////////
-bool Music::openFromFile(const std::string& filename)
-{
- // First stop the music if it was already running
- stop();
-
- // Open the underlying sound file
- if (!m_file->openRead(filename))
- return false;
-
- // Perform common initializations
- initialize();
-
- return true;
-}
-
-
-////////////////////////////////////////////////////////////
-bool Music::openFromMemory(const void* data, std::size_t sizeInBytes)
-{
- // First stop the music if it was already running
- stop();
-
- // Open the underlying sound file
- if (!m_file->openRead(data, sizeInBytes))
- return false;
-
- // Perform common initializations
- initialize();
-
- return true;
-}
-
-
-////////////////////////////////////////////////////////////
-bool Music::openFromStream(InputStream& stream)
-{
- // First stop the music if it was already running
- stop();
-
- // Open the underlying sound file
- if (!m_file->openRead(stream))
- return false;
-
- // Perform common initializations
- initialize();
-
- return true;
-}
-
-
-////////////////////////////////////////////////////////////
-Time Music::getDuration() const
-{
- return m_duration;
-}
-
-
-////////////////////////////////////////////////////////////
-bool Music::onGetData(SoundStream::Chunk& data)
-{
- Lock lock(m_mutex);
-
- // Fill the chunk parameters
- data.samples = &m_samples[0];
- data.sampleCount = m_file->read(&m_samples[0], m_samples.size());
-
- // Check if we have reached the end of the audio file
- return data.sampleCount == m_samples.size();
-}
-
-
-////////////////////////////////////////////////////////////
-void Music::onSeek(Time timeOffset)
-{
- Lock lock(m_mutex);
-
- m_file->seek(timeOffset);
-}
-
-
-////////////////////////////////////////////////////////////
-void Music::initialize()
-{
- // Compute the music duration
- m_duration = seconds(static_cast<float>(m_file->getSampleCount()) / m_file->getSampleRate() / m_file->getChannelCount());
-
- // Resize the internal buffer so that it can contain 1 second of audio samples
- m_samples.resize(m_file->getSampleRate() * m_file->getChannelCount());
-
- // Initialize the stream
- SoundStream::initialize(m_file->getChannelCount(), m_file->getSampleRate());
-}
-
-} // namespace sf
+//////////////////////////////////////////////////////////// +// +// 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 <SFML/Audio/Music.hpp> +#include <SFML/Audio/ALCheck.hpp> +#include <SFML/Audio/SoundFile.hpp> +#include <SFML/System/Lock.hpp> +#include <SFML/System/Err.hpp> +#include <fstream> + + +namespace sf +{ +//////////////////////////////////////////////////////////// +Music::Music() : +m_file (new priv::SoundFile), +m_duration() +{ + +} + + +//////////////////////////////////////////////////////////// +Music::~Music() +{ + // We must stop before destroying the file + stop(); + + delete m_file; +} + + +//////////////////////////////////////////////////////////// +bool Music::openFromFile(const std::string& filename) +{ + // First stop the music if it was already running + stop(); + + // Open the underlying sound file + if (!m_file->openRead(filename)) + return false; + + // Perform common initializations + initialize(); + + return true; +} + + +//////////////////////////////////////////////////////////// +bool Music::openFromMemory(const void* data, std::size_t sizeInBytes) +{ + // First stop the music if it was already running + stop(); + + // Open the underlying sound file + if (!m_file->openRead(data, sizeInBytes)) + return false; + + // Perform common initializations + initialize(); + + return true; +} + + +//////////////////////////////////////////////////////////// +bool Music::openFromStream(InputStream& stream) +{ + // First stop the music if it was already running + stop(); + + // Open the underlying sound file + if (!m_file->openRead(stream)) + return false; + + // Perform common initializations + initialize(); + + return true; +} + + +//////////////////////////////////////////////////////////// +Time Music::getDuration() const +{ + return m_duration; +} + + +//////////////////////////////////////////////////////////// +bool Music::onGetData(SoundStream::Chunk& data) +{ + Lock lock(m_mutex); + + // Fill the chunk parameters + data.samples = &m_samples[0]; + data.sampleCount = m_file->read(&m_samples[0], m_samples.size()); + + // Check if we have reached the end of the audio file + return data.sampleCount == m_samples.size(); +} + + +//////////////////////////////////////////////////////////// +void Music::onSeek(Time timeOffset) +{ + Lock lock(m_mutex); + + m_file->seek(timeOffset); +} + + +//////////////////////////////////////////////////////////// +void Music::initialize() +{ + // Compute the music duration + m_duration = seconds(static_cast<float>(m_file->getSampleCount()) / m_file->getSampleRate() / m_file->getChannelCount()); + + // Resize the internal buffer so that it can contain 1 second of audio samples + m_samples.resize(m_file->getSampleRate() * m_file->getChannelCount()); + + // Initialize the stream + SoundStream::initialize(m_file->getChannelCount(), m_file->getSampleRate()); +} + +} // namespace sf diff --git a/src/SFML/Audio/Sound.cpp b/src/SFML/Audio/Sound.cpp index 8619cab..d138893 100644 --- a/src/SFML/Audio/Sound.cpp +++ b/src/SFML/Audio/Sound.cpp @@ -1,196 +1,200 @@ -////////////////////////////////////////////////////////////
-//
-// SFML - Simple and Fast Multimedia Library
-// Copyright (C) 2007-2013 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 <SFML/Audio/Sound.hpp>
-#include <SFML/Audio/SoundBuffer.hpp>
-#include <SFML/Audio/ALCheck.hpp>
-
-
-namespace sf
-{
-////////////////////////////////////////////////////////////
-Sound::Sound() :
-m_buffer(NULL)
-{
-}
-
-
-////////////////////////////////////////////////////////////
-Sound::Sound(const SoundBuffer& buffer) :
-m_buffer(NULL)
-{
- setBuffer(buffer);
-}
-
-
-////////////////////////////////////////////////////////////
-Sound::Sound(const Sound& copy) :
-SoundSource(copy),
-m_buffer (NULL)
-{
- if (copy.m_buffer)
- setBuffer(*copy.m_buffer);
- setLoop(copy.getLoop());
-}
-
-
-////////////////////////////////////////////////////////////
-Sound::~Sound()
-{
- stop();
- if (m_buffer)
- m_buffer->detachSound(this);
-}
-
-
-////////////////////////////////////////////////////////////
-void Sound::play()
-{
- alCheck(alSourcePlay(m_source));
-}
-
-
-////////////////////////////////////////////////////////////
-void Sound::pause()
-{
- alCheck(alSourcePause(m_source));
-}
-
-
-////////////////////////////////////////////////////////////
-void Sound::stop()
-{
- alCheck(alSourceStop(m_source));
-}
-
-
-////////////////////////////////////////////////////////////
-void Sound::setBuffer(const SoundBuffer& buffer)
-{
- // First detach from the previous buffer
- if (m_buffer)
- {
- stop();
- m_buffer->detachSound(this);
- }
-
- // Assign and use the new buffer
- m_buffer = &buffer;
- m_buffer->attachSound(this);
- alCheck(alSourcei(m_source, AL_BUFFER, m_buffer->m_buffer));
-}
-
-
-////////////////////////////////////////////////////////////
-void Sound::setLoop(bool Loop)
-{
- alCheck(alSourcei(m_source, AL_LOOPING, Loop));
-}
-
-
-////////////////////////////////////////////////////////////
-void Sound::setPlayingOffset(Time timeOffset)
-{
- alCheck(alSourcef(m_source, AL_SEC_OFFSET, timeOffset.asSeconds()));
-}
-
-
-////////////////////////////////////////////////////////////
-const SoundBuffer* Sound::getBuffer() const
-{
- return m_buffer;
-}
-
-
-////////////////////////////////////////////////////////////
-bool Sound::getLoop() const
-{
- ALint loop;
- alCheck(alGetSourcei(m_source, AL_LOOPING, &loop));
-
- return loop != 0;
-}
-
-
-////////////////////////////////////////////////////////////
-Time Sound::getPlayingOffset() const
-{
- ALfloat secs = 0.f;
- alCheck(alGetSourcef(m_source, AL_SEC_OFFSET, &secs));
-
- return seconds(secs);
-}
-
-
-////////////////////////////////////////////////////////////
-Sound::Status Sound::getStatus() const
-{
- return SoundSource::getStatus();
-}
-
-
-////////////////////////////////////////////////////////////
-Sound& Sound::operator =(const Sound& right)
-{
- // Here we don't use the copy-and-swap idiom, because it would mess up
- // the list of sound instances contained in the buffers
-
- // Detach the sound instance from the previous buffer (if any)
- if (m_buffer)
- {
- stop();
- m_buffer->detachSound(this);
- m_buffer = NULL;
- }
-
- // Copy the sound attributes
- if (right.m_buffer)
- setBuffer(*right.m_buffer);
- setLoop(right.getLoop());
- setPitch(right.getPitch());
- setVolume(right.getVolume());
- setPosition(right.getPosition());
- setRelativeToListener(right.isRelativeToListener());
- setMinDistance(right.getMinDistance());
- setAttenuation(right.getAttenuation());
-
- return *this;
-}
-
-
-////////////////////////////////////////////////////////////
-void Sound::resetBuffer()
-{
- // First stop the sound in case it is playing
- stop();
-
- // Detach the buffer
- alCheck(alSourcei(m_source, AL_BUFFER, 0));
- m_buffer = NULL;
-}
-
-} // namespace sf
+//////////////////////////////////////////////////////////// +// +// 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 <SFML/Audio/Sound.hpp> +#include <SFML/Audio/SoundBuffer.hpp> +#include <SFML/Audio/ALCheck.hpp> + + +namespace sf +{ +//////////////////////////////////////////////////////////// +Sound::Sound() : +m_buffer(NULL) +{ +} + + +//////////////////////////////////////////////////////////// +Sound::Sound(const SoundBuffer& buffer) : +m_buffer(NULL) +{ + setBuffer(buffer); +} + + +//////////////////////////////////////////////////////////// +Sound::Sound(const Sound& copy) : +SoundSource(copy), +m_buffer (NULL) +{ + if (copy.m_buffer) + setBuffer(*copy.m_buffer); + setLoop(copy.getLoop()); +} + + +//////////////////////////////////////////////////////////// +Sound::~Sound() +{ + stop(); + if (m_buffer) + m_buffer->detachSound(this); +} + + +//////////////////////////////////////////////////////////// +void Sound::play() +{ + alCheck(alSourcePlay(m_source)); +} + + +//////////////////////////////////////////////////////////// +void Sound::pause() +{ + alCheck(alSourcePause(m_source)); +} + + +//////////////////////////////////////////////////////////// +void Sound::stop() +{ + alCheck(alSourceStop(m_source)); +} + + +//////////////////////////////////////////////////////////// +void Sound::setBuffer(const SoundBuffer& buffer) +{ + // First detach from the previous buffer + if (m_buffer) + { + stop(); + m_buffer->detachSound(this); + } + + // Assign and use the new buffer + m_buffer = &buffer; + m_buffer->attachSound(this); + alCheck(alSourcei(m_source, AL_BUFFER, m_buffer->m_buffer)); +} + + +//////////////////////////////////////////////////////////// +void Sound::setLoop(bool loop) +{ + alCheck(alSourcei(m_source, AL_LOOPING, loop)); +} + + +//////////////////////////////////////////////////////////// +void Sound::setPlayingOffset(Time timeOffset) +{ + alCheck(alSourcef(m_source, AL_SEC_OFFSET, timeOffset.asSeconds())); +} + + +//////////////////////////////////////////////////////////// +const SoundBuffer* Sound::getBuffer() const +{ + return m_buffer; +} + + +//////////////////////////////////////////////////////////// +bool Sound::getLoop() const +{ + ALint loop; + alCheck(alGetSourcei(m_source, AL_LOOPING, &loop)); + + return loop != 0; +} + + +//////////////////////////////////////////////////////////// +Time Sound::getPlayingOffset() const +{ + ALfloat secs = 0.f; + alCheck(alGetSourcef(m_source, AL_SEC_OFFSET, &secs)); + + return seconds(secs); +} + + +//////////////////////////////////////////////////////////// +Sound::Status Sound::getStatus() const +{ + return SoundSource::getStatus(); +} + + +//////////////////////////////////////////////////////////// +Sound& Sound::operator =(const Sound& right) +{ + // Here we don't use the copy-and-swap idiom, because it would mess up + // the list of sound instances contained in the buffers + + // Detach the sound instance from the previous buffer (if any) + if (m_buffer) + { + stop(); + m_buffer->detachSound(this); + m_buffer = NULL; + } + + // Copy the sound attributes + if (right.m_buffer) + setBuffer(*right.m_buffer); + setLoop(right.getLoop()); + setPitch(right.getPitch()); + setVolume(right.getVolume()); + setPosition(right.getPosition()); + setRelativeToListener(right.isRelativeToListener()); + setMinDistance(right.getMinDistance()); + setAttenuation(right.getAttenuation()); + + return *this; +} + + +//////////////////////////////////////////////////////////// +void Sound::resetBuffer() +{ + // First stop the sound in case it is playing + stop(); + + // Detach the buffer + if (m_buffer) + { + alCheck(alSourcei(m_source, AL_BUFFER, 0)); + m_buffer->detachSound(this); + m_buffer = NULL; + } +} + +} // namespace sf diff --git a/src/SFML/Audio/SoundBuffer.cpp b/src/SFML/Audio/SoundBuffer.cpp index 406a9fe..0d8818c 100644 --- a/src/SFML/Audio/SoundBuffer.cpp +++ b/src/SFML/Audio/SoundBuffer.cpp @@ -1,275 +1,286 @@ -////////////////////////////////////////////////////////////
-//
-// SFML - Simple and Fast Multimedia Library
-// Copyright (C) 2007-2013 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 <SFML/Audio/SoundBuffer.hpp>
-#include <SFML/Audio/SoundFile.hpp>
-#include <SFML/Audio/Sound.hpp>
-#include <SFML/Audio/AudioDevice.hpp>
-#include <SFML/Audio/ALCheck.hpp>
-#include <SFML/System/Err.hpp>
-#include <memory>
-
-
-namespace sf
-{
-////////////////////////////////////////////////////////////
-SoundBuffer::SoundBuffer() :
-m_buffer (0),
-m_duration()
-{
- priv::ensureALInit();
-
- // Create the buffer
- alCheck(alGenBuffers(1, &m_buffer));
-}
-
-
-////////////////////////////////////////////////////////////
-SoundBuffer::SoundBuffer(const SoundBuffer& copy) :
-m_buffer (0),
-m_samples (copy.m_samples),
-m_duration(copy.m_duration),
-m_sounds () // don't copy the attached sounds
-{
- // Create the buffer
- alCheck(alGenBuffers(1, &m_buffer));
-
- // Update the internal buffer with the new samples
- update(copy.getChannelCount(), copy.getSampleRate());
-}
-
-
-////////////////////////////////////////////////////////////
-SoundBuffer::~SoundBuffer()
-{
- // First detach the buffer from the sounds that use it (to avoid OpenAL errors)
- for (SoundList::const_iterator it = m_sounds.begin(); it != m_sounds.end(); ++it)
- (*it)->resetBuffer();
-
- // Destroy the buffer
- if (m_buffer)
- alCheck(alDeleteBuffers(1, &m_buffer));
-}
-
-
-////////////////////////////////////////////////////////////
-bool SoundBuffer::loadFromFile(const std::string& filename)
-{
- priv::SoundFile file;
- if (file.openRead(filename))
- return initialize(file);
- else
- return false;
-}
-
-
-////////////////////////////////////////////////////////////
-bool SoundBuffer::loadFromMemory(const void* data, std::size_t sizeInBytes)
-{
- priv::SoundFile file;
- if (file.openRead(data, sizeInBytes))
- return initialize(file);
- else
- return false;
-}
-
-
-////////////////////////////////////////////////////////////
-bool SoundBuffer::loadFromStream(InputStream& stream)
-{
- priv::SoundFile file;
- if (file.openRead(stream))
- return initialize(file);
- else
- return false;
-}
-
-
-////////////////////////////////////////////////////////////
-bool SoundBuffer::loadFromSamples(const Int16* samples, std::size_t sampleCount, unsigned int channelCount, unsigned int sampleRate)
-{
- if (samples && sampleCount && channelCount && sampleRate)
- {
- // Copy the new audio samples
- m_samples.assign(samples, samples + sampleCount);
-
- // Update the internal buffer with the new samples
- return update(channelCount, sampleRate);
- }
- else
- {
- // Error...
- err() << "Failed to load sound buffer from samples ("
- << "array: " << samples << ", "
- << "count: " << sampleCount << ", "
- << "channels: " << channelCount << ", "
- << "samplerate: " << sampleRate << ")"
- << std::endl;
-
- return false;
- }
-}
-
-
-////////////////////////////////////////////////////////////
-bool SoundBuffer::saveToFile(const std::string& filename) const
-{
- // Create the sound file in write mode
- priv::SoundFile file;
- if (file.openWrite(filename, getChannelCount(), getSampleRate()))
- {
- // Write the samples to the opened file
- file.write(&m_samples[0], m_samples.size());
-
- return true;
- }
- else
- {
- return false;
- }
-}
-
-
-////////////////////////////////////////////////////////////
-const Int16* SoundBuffer::getSamples() const
-{
- return m_samples.empty() ? NULL : &m_samples[0];
-}
-
-
-////////////////////////////////////////////////////////////
-std::size_t SoundBuffer::getSampleCount() const
-{
- return m_samples.size();
-}
-
-
-////////////////////////////////////////////////////////////
-unsigned int SoundBuffer::getSampleRate() const
-{
- ALint sampleRate;
- alCheck(alGetBufferi(m_buffer, AL_FREQUENCY, &sampleRate));
-
- return sampleRate;
-}
-
-
-////////////////////////////////////////////////////////////
-unsigned int SoundBuffer::getChannelCount() const
-{
- ALint channelCount;
- alCheck(alGetBufferi(m_buffer, AL_CHANNELS, &channelCount));
-
- return channelCount;
-}
-
-
-////////////////////////////////////////////////////////////
-Time SoundBuffer::getDuration() const
-{
- return m_duration;
-}
-
-
-////////////////////////////////////////////////////////////
-SoundBuffer& SoundBuffer::operator =(const SoundBuffer& right)
-{
- SoundBuffer temp(right);
-
- std::swap(m_samples, temp.m_samples);
- std::swap(m_buffer, temp.m_buffer);
- std::swap(m_duration, temp.m_duration);
- std::swap(m_sounds, temp.m_sounds); // swap sounds too, so that they are detached when temp is destroyed
-
- return *this;
-}
-
-
-////////////////////////////////////////////////////////////
-bool SoundBuffer::initialize(priv::SoundFile& file)
-{
- // Retrieve the sound parameters
- std::size_t sampleCount = file.getSampleCount();
- unsigned int channelCount = file.getChannelCount();
- unsigned int sampleRate = file.getSampleRate();
-
- // Read the samples from the provided file
- m_samples.resize(sampleCount);
- if (file.read(&m_samples[0], sampleCount) == sampleCount)
- {
- // Update the internal buffer with the new samples
- return update(channelCount, sampleRate);
- }
- else
- {
- return false;
- }
-}
-
-
-////////////////////////////////////////////////////////////
-bool SoundBuffer::update(unsigned int channelCount, unsigned int sampleRate)
-{
- // Check parameters
- if (!channelCount || !sampleRate || m_samples.empty())
- return false;
-
- // Find the good format according to the number of channels
- ALenum format = priv::AudioDevice::getFormatFromChannelCount(channelCount);
-
- // Check if the format is valid
- if (format == 0)
- {
- err() << "Failed to load sound buffer (unsupported number of channels: " << channelCount << ")" << std::endl;
- return false;
- }
-
- // Fill the buffer
- ALsizei size = static_cast<ALsizei>(m_samples.size()) * sizeof(Int16);
- alCheck(alBufferData(m_buffer, format, &m_samples[0], size, sampleRate));
-
- // Compute the duration
- m_duration = milliseconds(1000 * m_samples.size() / sampleRate / channelCount);
-
- return true;
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundBuffer::attachSound(Sound* sound) const
-{
- m_sounds.insert(sound);
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundBuffer::detachSound(Sound* sound) const
-{
- m_sounds.erase(sound);
-}
-
-} // namespace sf
+//////////////////////////////////////////////////////////// +// +// 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 <SFML/Audio/SoundBuffer.hpp> +#include <SFML/Audio/SoundFile.hpp> +#include <SFML/Audio/Sound.hpp> +#include <SFML/Audio/AudioDevice.hpp> +#include <SFML/Audio/ALCheck.hpp> +#include <SFML/System/Err.hpp> +#include <memory> + + +namespace sf +{ +//////////////////////////////////////////////////////////// +SoundBuffer::SoundBuffer() : +m_buffer (0), +m_duration() +{ + priv::ensureALInit(); + + // Create the buffer + alCheck(alGenBuffers(1, &m_buffer)); +} + + +//////////////////////////////////////////////////////////// +SoundBuffer::SoundBuffer(const SoundBuffer& copy) : +m_buffer (0), +m_samples (copy.m_samples), +m_duration(copy.m_duration), +m_sounds () // don't copy the attached sounds +{ + // Create the buffer + alCheck(alGenBuffers(1, &m_buffer)); + + // Update the internal buffer with the new samples + update(copy.getChannelCount(), copy.getSampleRate()); +} + + +//////////////////////////////////////////////////////////// +SoundBuffer::~SoundBuffer() +{ + // First detach the buffer from the sounds that use it (to avoid OpenAL errors) + for (SoundList::const_iterator it = m_sounds.begin(); it != m_sounds.end(); ++it) + (*it)->resetBuffer(); + + // Destroy the buffer + if (m_buffer) + alCheck(alDeleteBuffers(1, &m_buffer)); +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::loadFromFile(const std::string& filename) +{ + priv::SoundFile file; + if (file.openRead(filename)) + return initialize(file); + else + return false; +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::loadFromMemory(const void* data, std::size_t sizeInBytes) +{ + priv::SoundFile file; + if (file.openRead(data, sizeInBytes)) + return initialize(file); + else + return false; +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::loadFromStream(InputStream& stream) +{ + priv::SoundFile file; + if (file.openRead(stream)) + return initialize(file); + else + return false; +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::loadFromSamples(const Int16* samples, std::size_t sampleCount, unsigned int channelCount, unsigned int sampleRate) +{ + if (samples && sampleCount && channelCount && sampleRate) + { + // Copy the new audio samples + m_samples.assign(samples, samples + sampleCount); + + // Update the internal buffer with the new samples + return update(channelCount, sampleRate); + } + else + { + // Error... + err() << "Failed to load sound buffer from samples (" + << "array: " << samples << ", " + << "count: " << sampleCount << ", " + << "channels: " << channelCount << ", " + << "samplerate: " << sampleRate << ")" + << std::endl; + + return false; + } +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::saveToFile(const std::string& filename) const +{ + // Create the sound file in write mode + priv::SoundFile file; + if (file.openWrite(filename, getChannelCount(), getSampleRate())) + { + // Write the samples to the opened file + file.write(&m_samples[0], m_samples.size()); + + return true; + } + else + { + return false; + } +} + + +//////////////////////////////////////////////////////////// +const Int16* SoundBuffer::getSamples() const +{ + return m_samples.empty() ? NULL : &m_samples[0]; +} + + +//////////////////////////////////////////////////////////// +std::size_t SoundBuffer::getSampleCount() const +{ + return m_samples.size(); +} + + +//////////////////////////////////////////////////////////// +unsigned int SoundBuffer::getSampleRate() const +{ + ALint sampleRate; + alCheck(alGetBufferi(m_buffer, AL_FREQUENCY, &sampleRate)); + + return sampleRate; +} + + +//////////////////////////////////////////////////////////// +unsigned int SoundBuffer::getChannelCount() const +{ + ALint channelCount; + alCheck(alGetBufferi(m_buffer, AL_CHANNELS, &channelCount)); + + return channelCount; +} + + +//////////////////////////////////////////////////////////// +Time SoundBuffer::getDuration() const +{ + return m_duration; +} + + +//////////////////////////////////////////////////////////// +SoundBuffer& SoundBuffer::operator =(const SoundBuffer& right) +{ + SoundBuffer temp(right); + + std::swap(m_samples, temp.m_samples); + std::swap(m_buffer, temp.m_buffer); + std::swap(m_duration, temp.m_duration); + std::swap(m_sounds, temp.m_sounds); // swap sounds too, so that they are detached when temp is destroyed + + return *this; +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::initialize(priv::SoundFile& file) +{ + // Retrieve the sound parameters + std::size_t sampleCount = file.getSampleCount(); + unsigned int channelCount = file.getChannelCount(); + unsigned int sampleRate = file.getSampleRate(); + + // Read the samples from the provided file + m_samples.resize(sampleCount); + if (file.read(&m_samples[0], sampleCount) == sampleCount) + { + // Update the internal buffer with the new samples + return update(channelCount, sampleRate); + } + else + { + return false; + } +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::update(unsigned int channelCount, unsigned int sampleRate) +{ + // Check parameters + if (!channelCount || !sampleRate || m_samples.empty()) + return false; + + // Find the good format according to the number of channels + ALenum format = priv::AudioDevice::getFormatFromChannelCount(channelCount); + + // Check if the format is valid + if (format == 0) + { + err() << "Failed to load sound buffer (unsupported number of channels: " << channelCount << ")" << std::endl; + return false; + } + + // First make a copy of the list of sounds so we can reattach later + SoundList sounds(m_sounds); + + // Detach the buffer from the sounds that use it (to avoid OpenAL errors) + for (SoundList::const_iterator it = sounds.begin(); it != sounds.end(); ++it) + (*it)->resetBuffer(); + + // Fill the buffer + ALsizei size = static_cast<ALsizei>(m_samples.size()) * sizeof(Int16); + alCheck(alBufferData(m_buffer, format, &m_samples[0], size, sampleRate)); + + // Compute the duration + m_duration = seconds(static_cast<float>(m_samples.size()) / sampleRate / channelCount); + + // Now reattach the buffer to the sounds that use it + for (SoundList::const_iterator it = sounds.begin(); it != sounds.end(); ++it) + (*it)->setBuffer(*this); + + return true; +} + + +//////////////////////////////////////////////////////////// +void SoundBuffer::attachSound(Sound* sound) const +{ + m_sounds.insert(sound); +} + + +//////////////////////////////////////////////////////////// +void SoundBuffer::detachSound(Sound* sound) const +{ + m_sounds.erase(sound); +} + +} // namespace sf diff --git a/src/SFML/Audio/SoundBufferRecorder.cpp b/src/SFML/Audio/SoundBufferRecorder.cpp index a8b2993..11724b1 100644 --- a/src/SFML/Audio/SoundBufferRecorder.cpp +++ b/src/SFML/Audio/SoundBufferRecorder.cpp @@ -1,68 +1,68 @@ -////////////////////////////////////////////////////////////
-//
-// SFML - Simple and Fast Multimedia Library
-// Copyright (C) 2007-2013 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 <SFML/Audio/SoundBufferRecorder.hpp>
-#include <algorithm>
-#include <iterator>
-
-
-namespace sf
-{
-////////////////////////////////////////////////////////////
-bool SoundBufferRecorder::onStart()
-{
- m_samples.clear();
- m_buffer = SoundBuffer();
-
- return true;
-}
-
-
-////////////////////////////////////////////////////////////
-bool SoundBufferRecorder::onProcessSamples(const Int16* samples, std::size_t sampleCount)
-{
- std::copy(samples, samples + sampleCount, std::back_inserter(m_samples));
-
- return true;
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundBufferRecorder::onStop()
-{
- if (!m_samples.empty())
- m_buffer.loadFromSamples(&m_samples[0], m_samples.size(), 1, getSampleRate());
-}
-
-
-////////////////////////////////////////////////////////////
-const SoundBuffer& SoundBufferRecorder::getBuffer() const
-{
- return m_buffer;
-}
-
-} // namespace sf
+//////////////////////////////////////////////////////////// +// +// 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 <SFML/Audio/SoundBufferRecorder.hpp> +#include <algorithm> +#include <iterator> + + +namespace sf +{ +//////////////////////////////////////////////////////////// +bool SoundBufferRecorder::onStart() +{ + m_samples.clear(); + m_buffer = SoundBuffer(); + + return true; +} + + +//////////////////////////////////////////////////////////// +bool SoundBufferRecorder::onProcessSamples(const Int16* samples, std::size_t sampleCount) +{ + std::copy(samples, samples + sampleCount, std::back_inserter(m_samples)); + + return true; +} + + +//////////////////////////////////////////////////////////// +void SoundBufferRecorder::onStop() +{ + if (!m_samples.empty()) + m_buffer.loadFromSamples(&m_samples[0], m_samples.size(), 1, getSampleRate()); +} + + +//////////////////////////////////////////////////////////// +const SoundBuffer& SoundBufferRecorder::getBuffer() const +{ + return m_buffer; +} + +} // namespace sf diff --git a/src/SFML/Audio/SoundFile.cpp b/src/SFML/Audio/SoundFile.cpp index 91db819..7ca5f82 100644 --- a/src/SFML/Audio/SoundFile.cpp +++ b/src/SFML/Audio/SoundFile.cpp @@ -1,425 +1,451 @@ -////////////////////////////////////////////////////////////
-//
-// SFML - Simple and Fast Multimedia Library
-// Copyright (C) 2007-2013 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 <SFML/Audio/SoundFile.hpp>
-#include <SFML/System/InputStream.hpp>
-#include <SFML/System/Err.hpp>
-#include <cstring>
-#include <cctype>
-
-
-namespace
-{
- // Convert a string to lower case
- std::string toLower(std::string str)
- {
- for (std::string::iterator i = str.begin(); i != str.end(); ++i)
- *i = static_cast<char>(std::tolower(*i));
- return str;
- }
-}
-
-
-namespace sf
-{
-namespace priv
-{
-////////////////////////////////////////////////////////////
-SoundFile::SoundFile() :
-m_file (NULL),
-m_sampleCount (0),
-m_channelCount(0),
-m_sampleRate (0)
-{
-
-}
-
-
-////////////////////////////////////////////////////////////
-SoundFile::~SoundFile()
-{
- if (m_file)
- sf_close(m_file);
-}
-
-
-////////////////////////////////////////////////////////////
-std::size_t SoundFile::getSampleCount() const
-{
- return m_sampleCount;
-}
-
-
-////////////////////////////////////////////////////////////
-unsigned int SoundFile::getChannelCount() const
-{
- return m_channelCount;
-}
-
-
-////////////////////////////////////////////////////////////
-unsigned int SoundFile::getSampleRate() const
-{
- return m_sampleRate;
-}
-
-
-////////////////////////////////////////////////////////////
-bool SoundFile::openRead(const std::string& filename)
-{
- // If the file is already opened, first close it
- if (m_file)
- sf_close(m_file);
-
- // Open the sound file
- SF_INFO fileInfo;
- fileInfo.format = 0;
- m_file = sf_open(filename.c_str(), SFM_READ, &fileInfo);
- if (!m_file)
- {
- err() << "Failed to open sound file \"" << filename << "\" (" << sf_strerror(m_file) << ")" << std::endl;
- return false;
- }
-
- // Initialize the internal state from the loaded information
- initialize(fileInfo);
-
- return true;
-}
-
-
-////////////////////////////////////////////////////////////
-bool SoundFile::openRead(const void* data, std::size_t sizeInBytes)
-{
- // If the file is already opened, first close it
- if (m_file)
- sf_close(m_file);
-
- // Prepare the memory I/O structure
- SF_VIRTUAL_IO io;
- io.get_filelen = &Memory::getLength;
- io.read = &Memory::read;
- io.seek = &Memory::seek;
- io.tell = &Memory::tell;
-
- // Initialize the memory data
- m_memory.begin = static_cast<const char*>(data);
- m_memory.current = m_memory.begin;
- m_memory.size = sizeInBytes;
-
- // Open the sound file
- SF_INFO fileInfo;
- fileInfo.format = 0;
- m_file = sf_open_virtual(&io, SFM_READ, &fileInfo, &m_memory);
- if (!m_file)
- {
- err() << "Failed to open sound file from memory (" << sf_strerror(m_file) << ")" << std::endl;
- return false;
- }
-
- // Initialize the internal state from the loaded information
- initialize(fileInfo);
-
- return true;
-}
-
-
-////////////////////////////////////////////////////////////
-bool SoundFile::openRead(InputStream& stream)
-{
- // If the file is already opened, first close it
- if (m_file)
- sf_close(m_file);
-
- // Prepare the memory I/O structure
- SF_VIRTUAL_IO io;
- io.get_filelen = &Stream::getLength;
- io.read = &Stream::read;
- io.seek = &Stream::seek;
- io.tell = &Stream::tell;
-
- // Initialize the stream data
- m_stream.source = &stream;
- m_stream.size = stream.getSize();
-
- // Make sure that the stream's reading position is at the beginning
- stream.seek(0);
-
- // Open the sound file
- SF_INFO fileInfo;
- fileInfo.format = 0;
- m_file = sf_open_virtual(&io, SFM_READ, &fileInfo, &m_stream);
- if (!m_file)
- {
- err() << "Failed to open sound file from stream (" << sf_strerror(m_file) << ")" << std::endl;
- return false;
- }
-
- // Initialize the internal state from the loaded information
- initialize(fileInfo);
-
- return true;
-}
-
-
-////////////////////////////////////////////////////////////
-bool SoundFile::openWrite(const std::string& filename, unsigned int channelCount, unsigned int sampleRate)
-{
- // If the file is already opened, first close it
- if (m_file)
- sf_close(m_file);
-
- // Find the right format according to the file extension
- int format = getFormatFromFilename(filename);
- if (format == -1)
- {
- // Error : unrecognized extension
- err() << "Failed to create sound file \"" << filename << "\" (unknown format)" << std::endl;
- return false;
- }
-
- // Fill the sound infos with parameters
- SF_INFO fileInfos;
- fileInfos.channels = channelCount;
- fileInfos.samplerate = sampleRate;
- fileInfos.format = format | (format == SF_FORMAT_OGG ? SF_FORMAT_VORBIS : SF_FORMAT_PCM_16);
-
- // Open the sound file for writing
- m_file = sf_open(filename.c_str(), SFM_WRITE, &fileInfos);
- if (!m_file)
- {
- err() << "Failed to create sound file \"" << filename << "\" (" << sf_strerror(m_file) << ")" << std::endl;
- return false;
- }
-
- // Set the sound parameters
- m_channelCount = channelCount;
- m_sampleRate = sampleRate;
- m_sampleCount = 0;
-
- return true;
-}
-
-
-////////////////////////////////////////////////////////////
-std::size_t SoundFile::read(Int16* data, std::size_t sampleCount)
-{
- if (m_file && data && sampleCount)
- return static_cast<std::size_t>(sf_read_short(m_file, data, sampleCount));
- else
- return 0;
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundFile::write(const Int16* data, std::size_t sampleCount)
-{
- if (m_file && data && sampleCount)
- {
- // Write small chunks instead of everything at once,
- // to avoid a stack overflow in libsndfile (happens only with OGG format)
- while (sampleCount > 0)
- {
- std::size_t count = sampleCount > 10000 ? 10000 : sampleCount;
- sf_write_short(m_file, data, count);
- data += count;
- sampleCount -= count;
- }
- }
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundFile::seek(Time timeOffset)
-{
- if (m_file)
- {
- sf_count_t frameOffset = static_cast<sf_count_t>(timeOffset.asSeconds() * m_sampleRate);
- sf_seek(m_file, frameOffset, SEEK_SET);
- }
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundFile::initialize(SF_INFO fileInfo)
-{
- // Save the sound properties
- m_channelCount = fileInfo.channels;
- m_sampleRate = fileInfo.samplerate;
- m_sampleCount = static_cast<std::size_t>(fileInfo.frames) * fileInfo.channels;
-
- // Enable scaling for Vorbis files (float samples)
- // @todo enable when it's faster (it currently has to iterate over the *whole* music)
- //if (fileInfo.format & SF_FORMAT_VORBIS)
- // sf_command(m_file, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE);
-}
-
-
-////////////////////////////////////////////////////////////
-int SoundFile::getFormatFromFilename(const std::string& filename)
-{
- // Extract the extension
- std::string ext = "wav";
- std::string::size_type pos = filename.find_last_of(".");
- if (pos != std::string::npos)
- ext = filename.substr(pos + 1);
-
- // Match every supported extension with its format constant
- if (toLower(ext) == "wav" ) return SF_FORMAT_WAV;
- if (toLower(ext) == "aif" ) return SF_FORMAT_AIFF;
- if (toLower(ext) == "aiff" ) return SF_FORMAT_AIFF;
- if (toLower(ext) == "au" ) return SF_FORMAT_AU;
- if (toLower(ext) == "raw" ) return SF_FORMAT_RAW;
- if (toLower(ext) == "paf" ) return SF_FORMAT_PAF;
- if (toLower(ext) == "svx" ) return SF_FORMAT_SVX;
- if (toLower(ext) == "nist" ) return SF_FORMAT_NIST;
- if (toLower(ext) == "voc" ) return SF_FORMAT_VOC;
- if (toLower(ext) == "sf" ) return SF_FORMAT_IRCAM;
- if (toLower(ext) == "w64" ) return SF_FORMAT_W64;
- if (toLower(ext) == "mat4" ) return SF_FORMAT_MAT4;
- if (toLower(ext) == "mat5" ) return SF_FORMAT_MAT5;
- if (toLower(ext) == "pvf" ) return SF_FORMAT_PVF;
- if (toLower(ext) == "xi" ) return SF_FORMAT_XI;
- if (toLower(ext) == "htk" ) return SF_FORMAT_HTK;
- if (toLower(ext) == "sds" ) return SF_FORMAT_SDS;
- if (toLower(ext) == "avr" ) return SF_FORMAT_AVR;
- if (toLower(ext) == "sd2" ) return SF_FORMAT_SD2;
- if (toLower(ext) == "flac" ) return SF_FORMAT_FLAC;
- if (toLower(ext) == "caf" ) return SF_FORMAT_CAF;
- if (toLower(ext) == "wve" ) return SF_FORMAT_WVE;
- if (toLower(ext) == "ogg" ) return SF_FORMAT_OGG;
- if (toLower(ext) == "mpc2k") return SF_FORMAT_MPC2K;
- if (toLower(ext) == "rf64" ) return SF_FORMAT_RF64;
-
- return -1;
-}
-
-
-////////////////////////////////////////////////////////////
-sf_count_t SoundFile::Memory::getLength(void* user)
-{
- Memory* memory = static_cast<Memory*>(user);
- return memory->size;
-}
-
-
-////////////////////////////////////////////////////////////
-sf_count_t SoundFile::Memory::read(void* ptr, sf_count_t count, void* user)
-{
- Memory* memory = static_cast<Memory*>(user);
-
- sf_count_t position = tell(user);
- if (position + count >= memory->size)
- count = memory->size - position;
-
- std::memcpy(ptr, memory->current, static_cast<std::size_t>(count));
- memory->current += count;
- return count;
-}
-
-
-////////////////////////////////////////////////////////////
-sf_count_t SoundFile::Memory::seek(sf_count_t offset, int whence, void* user)
-{
- Memory* memory = static_cast<Memory*>(user);
- sf_count_t position = 0;
- switch (whence)
- {
- case SEEK_SET : position = offset; break;
- case SEEK_CUR : position = memory->current - memory->begin + offset; break;
- case SEEK_END : position = memory->size - offset; break;
- default : position = 0; break;
- }
-
- if (position >= memory->size)
- position = memory->size - 1;
- else if (position < 0)
- position = 0;
-
- memory->current = memory->begin + position;
- return position;
-}
-
-
-////////////////////////////////////////////////////////////
-sf_count_t SoundFile::Memory::tell(void* user)
-{
- Memory* memory = static_cast<Memory*>(user);
- return memory->current - memory->begin;
-}
-
-
-////////////////////////////////////////////////////////////
-sf_count_t SoundFile::Stream::getLength(void* userData)
-{
- Stream* stream = static_cast<Stream*>(userData);
- return stream->size;
-}
-
-
-////////////////////////////////////////////////////////////
-sf_count_t SoundFile::Stream::read(void* ptr, sf_count_t count, void* userData)
-{
- Stream* stream = static_cast<Stream*>(userData);
- Int64 position = stream->source->tell();
- if (position != -1)
- {
- if (count > stream->size - position)
- count = stream->size - position;
- return stream->source->read(reinterpret_cast<char*>(ptr), count);
- }
- else
- {
- return -1;
- }
-}
-
-
-////////////////////////////////////////////////////////////
-sf_count_t SoundFile::Stream::seek(sf_count_t offset, int whence, void* userData)
-{
- Stream* stream = static_cast<Stream*>(userData);
- switch (whence)
- {
- case SEEK_SET : return stream->source->seek(offset);
- case SEEK_CUR : return stream->source->seek(stream->source->tell() + offset);
- case SEEK_END : return stream->source->seek(stream->size - offset);
- default : return stream->source->seek(0);
- }
-}
-
-
-////////////////////////////////////////////////////////////
-sf_count_t SoundFile::Stream::tell(void* userData)
-{
- Stream* stream = static_cast<Stream*>(userData);
- return stream->source->tell();
-}
-
-} // namespace priv
-
-} // namespace sf
+//////////////////////////////////////////////////////////// +// +// 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 <SFML/Audio/SoundFile.hpp> +#ifdef SFML_SYSTEM_ANDROID + #include <SFML/System/Android/ResourceStream.hpp> +#endif +#include <SFML/System/InputStream.hpp> +#include <SFML/System/Err.hpp> +#include <cstring> +#include <cctype> + + +namespace +{ + // Convert a string to lower case + std::string toLower(std::string str) + { + for (std::string::iterator i = str.begin(); i != str.end(); ++i) + *i = static_cast<char>(std::tolower(*i)); + return str; + } +} + + +namespace sf +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +SoundFile::SoundFile() : +m_file (NULL), +m_sampleCount (0), +m_channelCount(0), +m_sampleRate (0) +{ + #ifdef SFML_SYSTEM_ANDROID + + m_resourceStream = NULL; + + #endif +} + + +//////////////////////////////////////////////////////////// +SoundFile::~SoundFile() +{ + if (m_file) + sf_close(m_file); + + #ifdef SFML_SYSTEM_ANDROID + + if (m_resourceStream) + delete (priv::ResourceStream*)m_resourceStream; + + #endif +} + + +//////////////////////////////////////////////////////////// +std::size_t SoundFile::getSampleCount() const +{ + return m_sampleCount; +} + + +//////////////////////////////////////////////////////////// +unsigned int SoundFile::getChannelCount() const +{ + return m_channelCount; +} + + +//////////////////////////////////////////////////////////// +unsigned int SoundFile::getSampleRate() const +{ + return m_sampleRate; +} + + +//////////////////////////////////////////////////////////// +bool SoundFile::openRead(const std::string& filename) +{ + #ifndef SFML_SYSTEM_ANDROID + + // If the file is already opened, first close it + if (m_file) + sf_close(m_file); + + // Open the sound file + SF_INFO fileInfo; + fileInfo.format = 0; + m_file = sf_open(filename.c_str(), SFM_READ, &fileInfo); + if (!m_file) + { + err() << "Failed to open sound file \"" << filename << "\" (" << sf_strerror(m_file) << ")" << std::endl; + return false; + } + + // Initialize the internal state from the loaded information + initialize(fileInfo); + + return true; + + #else + + if (m_resourceStream) + delete (priv::ResourceStream*)m_resourceStream; + + m_resourceStream = new priv::ResourceStream(filename); + return openRead(*(priv::ResourceStream*)m_resourceStream); + + #endif +} + + +//////////////////////////////////////////////////////////// +bool SoundFile::openRead(const void* data, std::size_t sizeInBytes) +{ + // If the file is already opened, first close it + if (m_file) + sf_close(m_file); + + // Prepare the memory I/O structure + SF_VIRTUAL_IO io; + io.get_filelen = &Memory::getLength; + io.read = &Memory::read; + io.seek = &Memory::seek; + io.tell = &Memory::tell; + + // Initialize the memory data + m_memory.begin = static_cast<const char*>(data); + m_memory.current = m_memory.begin; + m_memory.size = sizeInBytes; + + // Open the sound file + SF_INFO fileInfo; + fileInfo.format = 0; + m_file = sf_open_virtual(&io, SFM_READ, &fileInfo, &m_memory); + if (!m_file) + { + err() << "Failed to open sound file from memory (" << sf_strerror(m_file) << ")" << std::endl; + return false; + } + + // Initialize the internal state from the loaded information + initialize(fileInfo); + + return true; +} + + +//////////////////////////////////////////////////////////// +bool SoundFile::openRead(InputStream& stream) +{ + // If the file is already opened, first close it + if (m_file) + sf_close(m_file); + + // Prepare the memory I/O structure + SF_VIRTUAL_IO io; + io.get_filelen = &Stream::getLength; + io.read = &Stream::read; + io.seek = &Stream::seek; + io.tell = &Stream::tell; + + // Initialize the stream data + m_stream.source = &stream; + m_stream.size = stream.getSize(); + + // Make sure that the stream's reading position is at the beginning + stream.seek(0); + + // Open the sound file + SF_INFO fileInfo; + fileInfo.format = 0; + m_file = sf_open_virtual(&io, SFM_READ, &fileInfo, &m_stream); + if (!m_file) + { + err() << "Failed to open sound file from stream (" << sf_strerror(m_file) << ")" << std::endl; + return false; + } + + // Initialize the internal state from the loaded information + initialize(fileInfo); + + return true; +} + + +//////////////////////////////////////////////////////////// +bool SoundFile::openWrite(const std::string& filename, unsigned int channelCount, unsigned int sampleRate) +{ + // If the file is already opened, first close it + if (m_file) + sf_close(m_file); + + // Find the right format according to the file extension + int format = getFormatFromFilename(filename); + if (format == -1) + { + // Error: unrecognized extension + err() << "Failed to create sound file \"" << filename << "\" (unknown format)" << std::endl; + return false; + } + + // Fill the sound infos with parameters + SF_INFO fileInfos; + fileInfos.channels = channelCount; + fileInfos.samplerate = sampleRate; + fileInfos.format = format | (format == SF_FORMAT_OGG ? SF_FORMAT_VORBIS : SF_FORMAT_PCM_16); + + // Open the sound file for writing + m_file = sf_open(filename.c_str(), SFM_WRITE, &fileInfos); + if (!m_file) + { + err() << "Failed to create sound file \"" << filename << "\" (" << sf_strerror(m_file) << ")" << std::endl; + return false; + } + + // Set the sound parameters + m_channelCount = channelCount; + m_sampleRate = sampleRate; + m_sampleCount = 0; + + return true; +} + + +//////////////////////////////////////////////////////////// +std::size_t SoundFile::read(Int16* data, std::size_t sampleCount) +{ + if (m_file && data && sampleCount) + return static_cast<std::size_t>(sf_read_short(m_file, data, sampleCount)); + else + return 0; +} + + +//////////////////////////////////////////////////////////// +void SoundFile::write(const Int16* data, std::size_t sampleCount) +{ + if (m_file && data && sampleCount) + { + // Write small chunks instead of everything at once, + // to avoid a stack overflow in libsndfile (happens only with OGG format) + while (sampleCount > 0) + { + std::size_t count = sampleCount > 10000 ? 10000 : sampleCount; + sf_write_short(m_file, data, count); + data += count; + sampleCount -= count; + } + } +} + + +//////////////////////////////////////////////////////////// +void SoundFile::seek(Time timeOffset) +{ + if (m_file) + { + sf_count_t frameOffset = static_cast<sf_count_t>(timeOffset.asSeconds() * m_sampleRate); + sf_seek(m_file, frameOffset, SEEK_SET); + } +} + + +//////////////////////////////////////////////////////////// +void SoundFile::initialize(SF_INFO fileInfo) +{ + // Save the sound properties + m_channelCount = fileInfo.channels; + m_sampleRate = fileInfo.samplerate; + m_sampleCount = static_cast<std::size_t>(fileInfo.frames) * fileInfo.channels; + + // Enable scaling for Vorbis files (float samples) + // @todo enable when it's faster (it currently has to iterate over the *whole* music) + //if (fileInfo.format & SF_FORMAT_VORBIS) + // sf_command(m_file, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE); +} + + +//////////////////////////////////////////////////////////// +int SoundFile::getFormatFromFilename(const std::string& filename) +{ + // Extract the extension + std::string ext = "wav"; + std::string::size_type pos = filename.find_last_of("."); + if (pos != std::string::npos) + ext = toLower(filename.substr(pos + 1)); + + // Match every supported extension with its format constant + if (ext == "wav" ) return SF_FORMAT_WAV; + if (ext == "aif" ) return SF_FORMAT_AIFF; + if (ext == "aiff" ) return SF_FORMAT_AIFF; + if (ext == "au" ) return SF_FORMAT_AU; + if (ext == "raw" ) return SF_FORMAT_RAW; + if (ext == "paf" ) return SF_FORMAT_PAF; + if (ext == "svx" ) return SF_FORMAT_SVX; + if (ext == "nist" ) return SF_FORMAT_NIST; + if (ext == "voc" ) return SF_FORMAT_VOC; + if (ext == "sf" ) return SF_FORMAT_IRCAM; + if (ext == "w64" ) return SF_FORMAT_W64; + if (ext == "mat4" ) return SF_FORMAT_MAT4; + if (ext == "mat5" ) return SF_FORMAT_MAT5; + if (ext == "pvf" ) return SF_FORMAT_PVF; + if (ext == "xi" ) return SF_FORMAT_XI; + if (ext == "htk" ) return SF_FORMAT_HTK; + if (ext == "sds" ) return SF_FORMAT_SDS; + if (ext == "avr" ) return SF_FORMAT_AVR; + if (ext == "sd2" ) return SF_FORMAT_SD2; + if (ext == "flac" ) return SF_FORMAT_FLAC; + if (ext == "caf" ) return SF_FORMAT_CAF; + if (ext == "wve" ) return SF_FORMAT_WVE; + if (ext == "ogg" ) return SF_FORMAT_OGG; + if (ext == "mpc2k") return SF_FORMAT_MPC2K; + if (ext == "rf64" ) return SF_FORMAT_RF64; + + return -1; +} + + +//////////////////////////////////////////////////////////// +sf_count_t SoundFile::Memory::getLength(void* user) +{ + Memory* memory = static_cast<Memory*>(user); + return memory->size; +} + + +//////////////////////////////////////////////////////////// +sf_count_t SoundFile::Memory::read(void* ptr, sf_count_t count, void* user) +{ + Memory* memory = static_cast<Memory*>(user); + + sf_count_t position = tell(user); + if (position + count >= memory->size) + count = memory->size - position; + + std::memcpy(ptr, memory->current, static_cast<std::size_t>(count)); + memory->current += count; + return count; +} + + +//////////////////////////////////////////////////////////// +sf_count_t SoundFile::Memory::seek(sf_count_t offset, int whence, void* user) +{ + Memory* memory = static_cast<Memory*>(user); + sf_count_t position = 0; + switch (whence) + { + case SEEK_SET: position = offset; break; + case SEEK_CUR: position = memory->current - memory->begin + offset; break; + case SEEK_END: position = memory->size - offset; break; + default: position = 0; break; + } + + if (position >= memory->size) + position = memory->size - 1; + else if (position < 0) + position = 0; + + memory->current = memory->begin + position; + return position; +} + + +//////////////////////////////////////////////////////////// +sf_count_t SoundFile::Memory::tell(void* user) +{ + Memory* memory = static_cast<Memory*>(user); + return memory->current - memory->begin; +} + + +//////////////////////////////////////////////////////////// +sf_count_t SoundFile::Stream::getLength(void* userData) +{ + Stream* stream = static_cast<Stream*>(userData); + return stream->size; +} + + +//////////////////////////////////////////////////////////// +sf_count_t SoundFile::Stream::read(void* ptr, sf_count_t count, void* userData) +{ + Stream* stream = static_cast<Stream*>(userData); + Int64 position = stream->source->tell(); + if (position != -1) + { + if (count > stream->size - position) + count = stream->size - position; + return stream->source->read(reinterpret_cast<char*>(ptr), count); + } + else + { + return -1; + } +} + + +//////////////////////////////////////////////////////////// +sf_count_t SoundFile::Stream::seek(sf_count_t offset, int whence, void* userData) +{ + Stream* stream = static_cast<Stream*>(userData); + switch (whence) + { + case SEEK_SET: return stream->source->seek(offset); + case SEEK_CUR: return stream->source->seek(stream->source->tell() + offset); + case SEEK_END: return stream->source->seek(stream->size - offset); + default: return stream->source->seek(0); + } +} + + +//////////////////////////////////////////////////////////// +sf_count_t SoundFile::Stream::tell(void* userData) +{ + Stream* stream = static_cast<Stream*>(userData); + return stream->source->tell(); +} + +} // namespace priv + +} // namespace sf diff --git a/src/SFML/Audio/SoundFile.hpp b/src/SFML/Audio/SoundFile.hpp index 105a951..a04a0ff 100644 --- a/src/SFML/Audio/SoundFile.hpp +++ b/src/SFML/Audio/SoundFile.hpp @@ -1,228 +1,231 @@ -////////////////////////////////////////////////////////////
-//
-// SFML - Simple and Fast Multimedia Library
-// Copyright (C) 2007-2013 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_SOUNDFILE_HPP
-#define SFML_SOUNDFILE_HPP
-
-////////////////////////////////////////////////////////////
-// Headers
-////////////////////////////////////////////////////////////
-#include <SFML/System/NonCopyable.hpp>
-#include <SFML/System/Time.hpp>
-#include <sndfile.h>
-#include <string>
-
-
-namespace sf
-{
-class InputStream;
-
-namespace priv
-{
-////////////////////////////////////////////////////////////
-/// \brief Provide read and write access to sound files
-///
-////////////////////////////////////////////////////////////
-class SoundFile : NonCopyable
-{
-public :
-
- ////////////////////////////////////////////////////////////
- /// \brief Default constructor
- ///
- ////////////////////////////////////////////////////////////
- SoundFile();
-
- ////////////////////////////////////////////////////////////
- /// \brief Destructor
- ///
- ////////////////////////////////////////////////////////////
- ~SoundFile();
-
- ////////////////////////////////////////////////////////////
- /// \brief Get the total number of audio samples in the file
- ///
- /// \return Number of samples
- ///
- ////////////////////////////////////////////////////////////
- std::size_t getSampleCount() const;
-
- ////////////////////////////////////////////////////////////
- /// \brief Get the number of channels used by the sound
- ///
- /// \return Number of channels (1 = mono, 2 = stereo)
- ///
- ////////////////////////////////////////////////////////////
- unsigned int getChannelCount() const;
-
- ////////////////////////////////////////////////////////////
- /// \brief Get the sample rate of the sound
- ///
- /// \return Sample rate, in samples per second
- ///
- ////////////////////////////////////////////////////////////
- unsigned int getSampleRate() const;
-
- ////////////////////////////////////////////////////////////
- /// \brief Open a sound file for reading
- ///
- /// \param filename Path of the sound file to load
- ///
- /// \return True if the file was successfully opened
- ///
- ////////////////////////////////////////////////////////////
- bool openRead(const std::string& filename);
-
- ////////////////////////////////////////////////////////////
- /// \brief Open a sound file in memory for reading
- ///
- /// \param data Pointer to the file data in memory
- /// \param sizeInBytes Size of the data to load, in bytes
- ///
- /// \return True if the file was successfully opened
- ///
- ////////////////////////////////////////////////////////////
- bool openRead(const void* data, std::size_t sizeInBytes);
-
- ////////////////////////////////////////////////////////////
- /// \brief Open a sound file from a custom stream for reading
- ///
- /// \param stream Source stream to read from
- ///
- /// \return True if the file was successfully opened
- ///
- ////////////////////////////////////////////////////////////
- bool openRead(InputStream& stream);
-
- ////////////////////////////////////////////////////////////
- /// \brief a the sound file for writing
- ///
- /// \param filename Path of the sound file to write
- /// \param channelCount Number of channels in the sound
- /// \param sampleRate Sample rate of the sound
- ///
- /// \return True if the file was successfully opened
- ///
- ////////////////////////////////////////////////////////////
- bool openWrite(const std::string& filename, unsigned int channelCount, unsigned int sampleRate);
-
- ////////////////////////////////////////////////////////////
- /// \brief Read audio samples from the loaded sound
- ///
- /// \param data Pointer to the sample array to fill
- /// \param sampleCount Number of samples to read
- ///
- /// \return Number of samples actually read (may be less than \a sampleCount)
- ///
- ////////////////////////////////////////////////////////////
- std::size_t read(Int16* data, std::size_t sampleCount);
-
- ////////////////////////////////////////////////////////////
- /// \brief Write audio samples to the file
- ///
- /// \param data Pointer to the sample array to write
- /// \param sampleCount Number of samples to write
- ///
- ////////////////////////////////////////////////////////////
- void write(const Int16* data, std::size_t sampleCount);
-
- ////////////////////////////////////////////////////////////
- /// \brief Change the current read position in the file
- ///
- /// \param timeOffset New playing position, from the beginning of the file
- ///
- ////////////////////////////////////////////////////////////
- void seek(Time timeOffset);
-
-private :
-
- ////////////////////////////////////////////////////////////
- /// \brief Initialize the internal state of the sound file
- ///
- /// This function is called by all the openRead functions.
- ///
- /// \param fileInfo Information about the loaded sound file
- ///
- ////////////////////////////////////////////////////////////
- void initialize(SF_INFO fileInfo);
-
- ////////////////////////////////////////////////////////////
- /// \brief Get the internal format of an audio file according to
- /// its filename extension
- ///
- /// \param filename Filename to check
- ///
- /// \return Internal format matching the filename (-1 if no match)
- ///
- ////////////////////////////////////////////////////////////
- static int getFormatFromFilename(const std::string& filename);
-
- ////////////////////////////////////////////////////////////
- /// \brief Data and callbacks for opening from memory
- ///
- ////////////////////////////////////////////////////////////
- struct Memory
- {
- const char* begin;
- const char* current;
- sf_count_t size;
-
- static sf_count_t getLength(void* user);
- static sf_count_t read(void* ptr, sf_count_t count, void* user);
- static sf_count_t seek(sf_count_t offset, int whence, void* user);
- static sf_count_t tell(void* user);
- };
-
- ////////////////////////////////////////////////////////////
- /// \brief Data and callbacks for opening from stream
- ///
- ////////////////////////////////////////////////////////////
- struct Stream
- {
- InputStream* source;
- Int64 size;
-
- static sf_count_t getLength(void* user);
- static sf_count_t read(void* ptr, sf_count_t count, void* user);
- static sf_count_t seek(sf_count_t offset, int whence, void* user);
- static sf_count_t tell(void* user);
- };
-
- ////////////////////////////////////////////////////////////
- // Member data
- ////////////////////////////////////////////////////////////
- SNDFILE* m_file; ///< File descriptor
- Memory m_memory; ///< Memory reading info
- Stream m_stream; ///< Stream reading info
- std::size_t m_sampleCount; ///< Total number of samples in the file
- unsigned int m_channelCount; ///< Number of channels used by the sound
- unsigned int m_sampleRate; ///< Number of samples per second
-};
-
-} // namespace priv
-
-} // namespace sf
-
-
-#endif // SFML_SOUNDFILE_HPP
+//////////////////////////////////////////////////////////// +// +// 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_SOUNDFILE_HPP +#define SFML_SOUNDFILE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include <SFML/System/NonCopyable.hpp> +#include <SFML/System/Time.hpp> +#include <sndfile.h> +#include <string> + + +namespace sf +{ +class InputStream; + +namespace priv +{ +//////////////////////////////////////////////////////////// +/// \brief Provide read and write access to sound files +/// +//////////////////////////////////////////////////////////// +class SoundFile : NonCopyable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + SoundFile(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~SoundFile(); + + //////////////////////////////////////////////////////////// + /// \brief Get the total number of audio samples in the file + /// + /// \return Number of samples + /// + //////////////////////////////////////////////////////////// + std::size_t getSampleCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the number of channels used by the sound + /// + /// \return Number of channels (1 = mono, 2 = stereo) + /// + //////////////////////////////////////////////////////////// + unsigned int getChannelCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the sample rate of the sound + /// + /// \return Sample rate, in samples per second + /// + //////////////////////////////////////////////////////////// + unsigned int getSampleRate() const; + + //////////////////////////////////////////////////////////// + /// \brief Open a sound file for reading + /// + /// \param filename Path of the sound file to load + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + bool openRead(const std::string& filename); + + //////////////////////////////////////////////////////////// + /// \brief Open a sound file in memory for reading + /// + /// \param data Pointer to the file data in memory + /// \param sizeInBytes Size of the data to load, in bytes + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + bool openRead(const void* data, std::size_t sizeInBytes); + + //////////////////////////////////////////////////////////// + /// \brief Open a sound file from a custom stream for reading + /// + /// \param stream Source stream to read from + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + bool openRead(InputStream& stream); + + //////////////////////////////////////////////////////////// + /// \brief a the sound file for writing + /// + /// \param filename Path of the sound file to write + /// \param channelCount Number of channels in the sound + /// \param sampleRate Sample rate of the sound + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + bool openWrite(const std::string& filename, unsigned int channelCount, unsigned int sampleRate); + + //////////////////////////////////////////////////////////// + /// \brief Read audio samples from the loaded sound + /// + /// \param data Pointer to the sample array to fill + /// \param sampleCount Number of samples to read + /// + /// \return Number of samples actually read (may be less than \a sampleCount) + /// + //////////////////////////////////////////////////////////// + std::size_t read(Int16* data, std::size_t sampleCount); + + //////////////////////////////////////////////////////////// + /// \brief Write audio samples to the file + /// + /// \param data Pointer to the sample array to write + /// \param sampleCount Number of samples to write + /// + //////////////////////////////////////////////////////////// + void write(const Int16* data, std::size_t sampleCount); + + //////////////////////////////////////////////////////////// + /// \brief Change the current read position in the file + /// + /// \param timeOffset New playing position, from the beginning of the file + /// + //////////////////////////////////////////////////////////// + void seek(Time timeOffset); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Initialize the internal state of the sound file + /// + /// This function is called by all the openRead functions. + /// + /// \param fileInfo Information about the loaded sound file + /// + //////////////////////////////////////////////////////////// + void initialize(SF_INFO fileInfo); + + //////////////////////////////////////////////////////////// + /// \brief Get the internal format of an audio file according to + /// its filename extension + /// + /// \param filename Filename to check + /// + /// \return Internal format matching the filename (-1 if no match) + /// + //////////////////////////////////////////////////////////// + static int getFormatFromFilename(const std::string& filename); + + //////////////////////////////////////////////////////////// + /// \brief Data and callbacks for opening from memory + /// + //////////////////////////////////////////////////////////// + struct Memory + { + const char* begin; + const char* current; + sf_count_t size; + + static sf_count_t getLength(void* user); + static sf_count_t read(void* ptr, sf_count_t count, void* user); + static sf_count_t seek(sf_count_t offset, int whence, void* user); + static sf_count_t tell(void* user); + }; + + //////////////////////////////////////////////////////////// + /// \brief Data and callbacks for opening from stream + /// + //////////////////////////////////////////////////////////// + struct Stream + { + InputStream* source; + Int64 size; + + static sf_count_t getLength(void* user); + static sf_count_t read(void* ptr, sf_count_t count, void* user); + static sf_count_t seek(sf_count_t offset, int whence, void* user); + static sf_count_t tell(void* user); + }; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + SNDFILE* m_file; ///< File descriptor + Memory m_memory; ///< Memory reading info + Stream m_stream; ///< Stream reading info + std::size_t m_sampleCount; ///< Total number of samples in the file + unsigned int m_channelCount; ///< Number of channels used by the sound + unsigned int m_sampleRate; ///< Number of samples per second + #ifdef SFML_SYSTEM_ANDROID + void* m_resourceStream; ///< Asset file streamer (if loaded from file) + #endif +}; + +} // namespace priv + +} // namespace sf + + +#endif // SFML_SOUNDFILE_HPP diff --git a/src/SFML/Audio/SoundRecorder.cpp b/src/SFML/Audio/SoundRecorder.cpp index bf7b03f..51e7ef9 100644 --- a/src/SFML/Audio/SoundRecorder.cpp +++ b/src/SFML/Audio/SoundRecorder.cpp @@ -1,203 +1,290 @@ -////////////////////////////////////////////////////////////
-//
-// SFML - Simple and Fast Multimedia Library
-// Copyright (C) 2007-2013 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 <SFML/Audio/SoundRecorder.hpp>
-#include <SFML/Audio/AudioDevice.hpp>
-#include <SFML/Audio/ALCheck.hpp>
-#include <SFML/System/Sleep.hpp>
-#include <SFML/System/Err.hpp>
-
-#ifdef _MSC_VER
- #pragma warning(disable : 4355) // 'this' used in base member initializer list
-#endif
-
-
-namespace
-{
- ALCdevice* captureDevice = NULL;
-}
-
-namespace sf
-{
-////////////////////////////////////////////////////////////
-SoundRecorder::SoundRecorder() :
-m_thread (&SoundRecorder::record, this),
-m_sampleRate (0),
-m_isCapturing(false)
-{
- priv::ensureALInit();
-}
-
-
-////////////////////////////////////////////////////////////
-SoundRecorder::~SoundRecorder()
-{
- // Nothing to do
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundRecorder::start(unsigned int sampleRate)
-{
- // Check if the device can do audio capture
- if (!isAvailable())
- {
- err() << "Failed to start capture : your system cannot capture audio data (call SoundRecorder::IsAvailable to check it)" << std::endl;
- return;
- }
-
- // Check that another capture is not already running
- if (captureDevice)
- {
- err() << "Trying to start audio capture, but another capture is already running" << std::endl;
- return;
- }
-
- // Open the capture device for capturing 16 bits mono samples
- captureDevice = alcCaptureOpenDevice(NULL, sampleRate, AL_FORMAT_MONO16, sampleRate);
- if (!captureDevice)
- {
- err() << "Failed to open the audio capture device" << std::endl;
- return;
- }
-
- // Clear the array of samples
- m_samples.clear();
-
- // Store the sample rate
- m_sampleRate = sampleRate;
-
- // Notify derived class
- if (onStart())
- {
- // Start the capture
- alcCaptureStart(captureDevice);
-
- // Start the capture in a new thread, to avoid blocking the main thread
- m_isCapturing = true;
- m_thread.launch();
- }
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundRecorder::stop()
-{
- // Stop the capturing thread
- m_isCapturing = false;
- m_thread.wait();
-}
-
-
-////////////////////////////////////////////////////////////
-unsigned int SoundRecorder::getSampleRate() const
-{
- return m_sampleRate;
-}
-
-
-////////////////////////////////////////////////////////////
-bool SoundRecorder::isAvailable()
-{
- return (priv::AudioDevice::isExtensionSupported("ALC_EXT_CAPTURE") != AL_FALSE) ||
- (priv::AudioDevice::isExtensionSupported("ALC_EXT_capture") != AL_FALSE); // "bug" in Mac OS X 10.5 and 10.6
-}
-
-
-////////////////////////////////////////////////////////////
-bool SoundRecorder::onStart()
-{
- // Nothing to do
- return true;
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundRecorder::onStop()
-{
- // Nothing to do
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundRecorder::record()
-{
- while (m_isCapturing)
- {
- // Process available samples
- processCapturedSamples();
-
- // Don't bother the CPU while waiting for more captured data
- sleep(milliseconds(100));
- }
-
- // Capture is finished : clean up everything
- cleanup();
-
- // Notify derived class
- onStop();
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundRecorder::processCapturedSamples()
-{
- // Get the number of samples available
- ALCint samplesAvailable;
- alcGetIntegerv(captureDevice, ALC_CAPTURE_SAMPLES, 1, &samplesAvailable);
-
- if (samplesAvailable > 0)
- {
- // Get the recorded samples
- m_samples.resize(samplesAvailable);
- alcCaptureSamples(captureDevice, &m_samples[0], samplesAvailable);
-
- // Forward them to the derived class
- if (!onProcessSamples(&m_samples[0], m_samples.size()))
- {
- // The user wants to stop the capture
- m_isCapturing = false;
- }
- }
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundRecorder::cleanup()
-{
- // Stop the capture
- alcCaptureStop(captureDevice);
-
- // Get the samples left in the buffer
- processCapturedSamples();
-
- // Close the device
- alcCaptureCloseDevice(captureDevice);
- captureDevice = NULL;
-}
-
-} // namespace sf
+//////////////////////////////////////////////////////////// +// +// 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 <SFML/Audio/SoundRecorder.hpp> +#include <SFML/Audio/AudioDevice.hpp> +#include <SFML/Audio/ALCheck.hpp> +#include <SFML/System/Sleep.hpp> +#include <SFML/System/Err.hpp> +#include <cstring> + +#ifdef _MSC_VER + #pragma warning(disable: 4355) // 'this' used in base member initializer list +#endif + + +namespace +{ + ALCdevice* captureDevice = NULL; +} + +namespace sf +{ +//////////////////////////////////////////////////////////// +SoundRecorder::SoundRecorder() : +m_thread (&SoundRecorder::record, this), +m_sampleRate (0), +m_processingInterval(milliseconds(100)), +m_isCapturing (false) +{ + priv::ensureALInit(); + + // Set the device name to the default device + m_deviceName = getDefaultDevice(); +} + + +//////////////////////////////////////////////////////////// +SoundRecorder::~SoundRecorder() +{ + // Nothing to do +} + + +//////////////////////////////////////////////////////////// +bool SoundRecorder::start(unsigned int sampleRate) +{ + // Check if the device can do audio capture + if (!isAvailable()) + { + err() << "Failed to start capture: your system cannot capture audio data (call SoundRecorder::isAvailable to check it)" << std::endl; + return false; + } + + // Check that another capture is not already running + if (captureDevice) + { + err() << "Trying to start audio capture, but another capture is already running" << std::endl; + return false; + } + + // Open the capture device for capturing 16 bits mono samples + captureDevice = alcCaptureOpenDevice(m_deviceName.c_str(), sampleRate, AL_FORMAT_MONO16, sampleRate); + if (!captureDevice) + { + err() << "Failed to open the audio capture device with the name: " << m_deviceName << std::endl; + return false; + } + + // Clear the array of samples + m_samples.clear(); + + // Store the sample rate + m_sampleRate = sampleRate; + + // Notify derived class + if (onStart()) + { + // Start the capture + alcCaptureStart(captureDevice); + + // Start the capture in a new thread, to avoid blocking the main thread + m_isCapturing = true; + m_thread.launch(); + + return true; + } + + return false; +} + + +//////////////////////////////////////////////////////////// +void SoundRecorder::stop() +{ + // Stop the capturing thread + m_isCapturing = false; + m_thread.wait(); + + // Notify derived class + onStop(); +} + + +//////////////////////////////////////////////////////////// +unsigned int SoundRecorder::getSampleRate() const +{ + return m_sampleRate; +} + + +//////////////////////////////////////////////////////////// +std::vector<std::string> SoundRecorder::getAvailableDevices() +{ + std::vector<std::string> deviceNameList; + + const ALchar *deviceList = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); + if (deviceList) + { + while (*deviceList) + { + deviceNameList.push_back(deviceList); + deviceList += std::strlen(deviceList) + 1; + } + } + + return deviceNameList; +} + + +//////////////////////////////////////////////////////////// +std::string SoundRecorder::getDefaultDevice() +{ + return alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); +} + + +//////////////////////////////////////////////////////////// +bool SoundRecorder::setDevice(const std::string& name) +{ + // Store the device name + if (name.empty()) + m_deviceName = getDefaultDevice(); + else + m_deviceName = name; + + if (m_isCapturing) + { + // Stop the capturing thread + m_isCapturing = false; + m_thread.wait(); + + // Open the requested capture device for capturing 16 bits mono samples + captureDevice = alcCaptureOpenDevice(name.c_str(), m_sampleRate, AL_FORMAT_MONO16, m_sampleRate); + if (!captureDevice) + { + // Notify derived class + onStop(); + + err() << "Failed to open the audio capture device with the name: " << m_deviceName << std::endl; + return false; + } + + // Start the capture + alcCaptureStart(captureDevice); + + // Start the capture in a new thread, to avoid blocking the main thread + m_isCapturing = true; + m_thread.launch(); + } + + return true; +} + + +//////////////////////////////////////////////////////////// +const std::string& SoundRecorder::getDevice() const +{ + return m_deviceName; +} + + +//////////////////////////////////////////////////////////// +bool SoundRecorder::isAvailable() +{ + return (priv::AudioDevice::isExtensionSupported("ALC_EXT_CAPTURE") != AL_FALSE) || + (priv::AudioDevice::isExtensionSupported("ALC_EXT_capture") != AL_FALSE); // "bug" in Mac OS X 10.5 and 10.6 +} + + +//////////////////////////////////////////////////////////// +void SoundRecorder::setProcessingInterval(sf::Time interval) +{ + m_processingInterval = interval; +} + + +//////////////////////////////////////////////////////////// +bool SoundRecorder::onStart() +{ + // Nothing to do + return true; +} + + +//////////////////////////////////////////////////////////// +void SoundRecorder::onStop() +{ + // Nothing to do +} + + +//////////////////////////////////////////////////////////// +void SoundRecorder::record() +{ + while (m_isCapturing) + { + // Process available samples + processCapturedSamples(); + + // Don't bother the CPU while waiting for more captured data + sleep(m_processingInterval); + } + + // Capture is finished: clean up everything + cleanup(); +} + + +//////////////////////////////////////////////////////////// +void SoundRecorder::processCapturedSamples() +{ + // Get the number of samples available + ALCint samplesAvailable; + alcGetIntegerv(captureDevice, ALC_CAPTURE_SAMPLES, 1, &samplesAvailable); + + if (samplesAvailable > 0) + { + // Get the recorded samples + m_samples.resize(samplesAvailable); + alcCaptureSamples(captureDevice, &m_samples[0], samplesAvailable); + + // Forward them to the derived class + if (!onProcessSamples(&m_samples[0], m_samples.size())) + { + // The user wants to stop the capture + m_isCapturing = false; + } + } +} + + +//////////////////////////////////////////////////////////// +void SoundRecorder::cleanup() +{ + // Stop the capture + alcCaptureStop(captureDevice); + + // Get the samples left in the buffer + processCapturedSamples(); + + // Close the device + alcCaptureCloseDevice(captureDevice); + captureDevice = NULL; +} + +} // namespace sf diff --git a/src/SFML/Audio/SoundSource.cpp b/src/SFML/Audio/SoundSource.cpp index c5a6524..3129b2e 100644 --- a/src/SFML/Audio/SoundSource.cpp +++ b/src/SFML/Audio/SoundSource.cpp @@ -1,194 +1,194 @@ -////////////////////////////////////////////////////////////
-//
-// SFML - Simple and Fast Multimedia Library
-// Copyright (C) 2007-2013 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 <SFML/Audio/SoundSource.hpp>
-#include <SFML/Audio/ALCheck.hpp>
-
-
-namespace sf
-{
-////////////////////////////////////////////////////////////
-SoundSource::SoundSource()
-{
- priv::ensureALInit();
-
- alCheck(alGenSources(1, &m_source));
- alCheck(alSourcei(m_source, AL_BUFFER, 0));
-}
-
-
-////////////////////////////////////////////////////////////
-SoundSource::SoundSource(const SoundSource& copy)
-{
- priv::ensureALInit();
-
- alCheck(alGenSources(1, &m_source));
- alCheck(alSourcei(m_source, AL_BUFFER, 0));
-
- setPitch(copy.getPitch());
- setVolume(copy.getVolume());
- setPosition(copy.getPosition());
- setRelativeToListener(copy.isRelativeToListener());
- setMinDistance(copy.getMinDistance());
- setAttenuation(copy.getAttenuation());
-}
-
-
-////////////////////////////////////////////////////////////
-SoundSource::~SoundSource()
-{
- alCheck(alSourcei(m_source, AL_BUFFER, 0));
- alCheck(alDeleteSources(1, &m_source));
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundSource::setPitch(float pitch)
-{
- alCheck(alSourcef(m_source, AL_PITCH, pitch));
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundSource::setVolume(float volume)
-{
- alCheck(alSourcef(m_source, AL_GAIN, volume * 0.01f));
-}
-
-////////////////////////////////////////////////////////////
-void SoundSource::setPosition(float x, float y, float z)
-{
- alCheck(alSource3f(m_source, AL_POSITION, x, y, z));
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundSource::setPosition(const Vector3f& position)
-{
- setPosition(position.x, position.y, position.z);
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundSource::setRelativeToListener(bool relative)
-{
- alCheck(alSourcei(m_source, AL_SOURCE_RELATIVE, relative));
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundSource::setMinDistance(float distance)
-{
- alCheck(alSourcef(m_source, AL_REFERENCE_DISTANCE, distance));
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundSource::setAttenuation(float attenuation)
-{
- alCheck(alSourcef(m_source, AL_ROLLOFF_FACTOR, attenuation));
-}
-
-
-////////////////////////////////////////////////////////////
-float SoundSource::getPitch() const
-{
- ALfloat pitch;
- alCheck(alGetSourcef(m_source, AL_PITCH, &pitch));
-
- return pitch;
-}
-
-
-////////////////////////////////////////////////////////////
-float SoundSource::getVolume() const
-{
- ALfloat gain;
- alCheck(alGetSourcef(m_source, AL_GAIN, &gain));
-
- return gain * 100.f;
-}
-
-
-////////////////////////////////////////////////////////////
-Vector3f SoundSource::getPosition() const
-{
- Vector3f position;
- alCheck(alGetSource3f(m_source, AL_POSITION, &position.x, &position.y, &position.z));
-
- return position;
-}
-
-
-////////////////////////////////////////////////////////////
-bool SoundSource::isRelativeToListener() const
-{
- ALint relative;
- alCheck(alGetSourcei(m_source, AL_SOURCE_RELATIVE, &relative));
-
- return relative != 0;
-}
-
-
-////////////////////////////////////////////////////////////
-float SoundSource::getMinDistance() const
-{
- ALfloat distance;
- alCheck(alGetSourcef(m_source, AL_REFERENCE_DISTANCE, &distance));
-
- return distance;
-}
-
-
-////////////////////////////////////////////////////////////
-float SoundSource::getAttenuation() const
-{
- ALfloat attenuation;
- alCheck(alGetSourcef(m_source, AL_ROLLOFF_FACTOR, &attenuation));
-
- return attenuation;
-}
-
-
-////////////////////////////////////////////////////////////
-SoundSource::Status SoundSource::getStatus() const
-{
- ALint status;
- alCheck(alGetSourcei(m_source, AL_SOURCE_STATE, &status));
-
- switch (status)
- {
- case AL_INITIAL :
- case AL_STOPPED : return Stopped;
- case AL_PAUSED : return Paused;
- case AL_PLAYING : return Playing;
- }
-
- return Stopped;
-}
-
-} // namespace sf
+//////////////////////////////////////////////////////////// +// +// 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 <SFML/Audio/SoundSource.hpp> +#include <SFML/Audio/ALCheck.hpp> + + +namespace sf +{ +//////////////////////////////////////////////////////////// +SoundSource::SoundSource() +{ + priv::ensureALInit(); + + alCheck(alGenSources(1, &m_source)); + alCheck(alSourcei(m_source, AL_BUFFER, 0)); +} + + +//////////////////////////////////////////////////////////// +SoundSource::SoundSource(const SoundSource& copy) +{ + priv::ensureALInit(); + + alCheck(alGenSources(1, &m_source)); + alCheck(alSourcei(m_source, AL_BUFFER, 0)); + + setPitch(copy.getPitch()); + setVolume(copy.getVolume()); + setPosition(copy.getPosition()); + setRelativeToListener(copy.isRelativeToListener()); + setMinDistance(copy.getMinDistance()); + setAttenuation(copy.getAttenuation()); +} + + +//////////////////////////////////////////////////////////// +SoundSource::~SoundSource() +{ + alCheck(alSourcei(m_source, AL_BUFFER, 0)); + alCheck(alDeleteSources(1, &m_source)); +} + + +//////////////////////////////////////////////////////////// +void SoundSource::setPitch(float pitch) +{ + alCheck(alSourcef(m_source, AL_PITCH, pitch)); +} + + +//////////////////////////////////////////////////////////// +void SoundSource::setVolume(float volume) +{ + alCheck(alSourcef(m_source, AL_GAIN, volume * 0.01f)); +} + +//////////////////////////////////////////////////////////// +void SoundSource::setPosition(float x, float y, float z) +{ + alCheck(alSource3f(m_source, AL_POSITION, x, y, z)); +} + + +//////////////////////////////////////////////////////////// +void SoundSource::setPosition(const Vector3f& position) +{ + setPosition(position.x, position.y, position.z); +} + + +//////////////////////////////////////////////////////////// +void SoundSource::setRelativeToListener(bool relative) +{ + alCheck(alSourcei(m_source, AL_SOURCE_RELATIVE, relative)); +} + + +//////////////////////////////////////////////////////////// +void SoundSource::setMinDistance(float distance) +{ + alCheck(alSourcef(m_source, AL_REFERENCE_DISTANCE, distance)); +} + + +//////////////////////////////////////////////////////////// +void SoundSource::setAttenuation(float attenuation) +{ + alCheck(alSourcef(m_source, AL_ROLLOFF_FACTOR, attenuation)); +} + + +//////////////////////////////////////////////////////////// +float SoundSource::getPitch() const +{ + ALfloat pitch; + alCheck(alGetSourcef(m_source, AL_PITCH, &pitch)); + + return pitch; +} + + +//////////////////////////////////////////////////////////// +float SoundSource::getVolume() const +{ + ALfloat gain; + alCheck(alGetSourcef(m_source, AL_GAIN, &gain)); + + return gain * 100.f; +} + + +//////////////////////////////////////////////////////////// +Vector3f SoundSource::getPosition() const +{ + Vector3f position; + alCheck(alGetSource3f(m_source, AL_POSITION, &position.x, &position.y, &position.z)); + + return position; +} + + +//////////////////////////////////////////////////////////// +bool SoundSource::isRelativeToListener() const +{ + ALint relative; + alCheck(alGetSourcei(m_source, AL_SOURCE_RELATIVE, &relative)); + + return relative != 0; +} + + +//////////////////////////////////////////////////////////// +float SoundSource::getMinDistance() const +{ + ALfloat distance; + alCheck(alGetSourcef(m_source, AL_REFERENCE_DISTANCE, &distance)); + + return distance; +} + + +//////////////////////////////////////////////////////////// +float SoundSource::getAttenuation() const +{ + ALfloat attenuation; + alCheck(alGetSourcef(m_source, AL_ROLLOFF_FACTOR, &attenuation)); + + return attenuation; +} + + +//////////////////////////////////////////////////////////// +SoundSource::Status SoundSource::getStatus() const +{ + ALint status; + alCheck(alGetSourcei(m_source, AL_SOURCE_STATE, &status)); + + switch (status) + { + case AL_INITIAL: + case AL_STOPPED: return Stopped; + case AL_PAUSED: return Paused; + case AL_PLAYING: return Playing; + } + + return Stopped; +} + +} // namespace sf diff --git a/src/SFML/Audio/SoundStream.cpp b/src/SFML/Audio/SoundStream.cpp index 31df188..8321889 100644 --- a/src/SFML/Audio/SoundStream.cpp +++ b/src/SFML/Audio/SoundStream.cpp @@ -1,365 +1,469 @@ -////////////////////////////////////////////////////////////
-//
-// SFML - Simple and Fast Multimedia Library
-// Copyright (C) 2007-2013 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 <SFML/Audio/SoundStream.hpp>
-#include <SFML/Audio/AudioDevice.hpp>
-#include <SFML/Audio/ALCheck.hpp>
-#include <SFML/System/Sleep.hpp>
-#include <SFML/System/Err.hpp>
-
-#ifdef _MSC_VER
- #pragma warning(disable : 4355) // 'this' used in base member initializer list
-#endif
-
-
-namespace sf
-{
-////////////////////////////////////////////////////////////
-SoundStream::SoundStream() :
-m_thread (&SoundStream::streamData, this),
-m_isStreaming (false),
-m_channelCount (0),
-m_sampleRate (0),
-m_format (0),
-m_loop (false),
-m_samplesProcessed(0)
-{
-
-}
-
-
-////////////////////////////////////////////////////////////
-SoundStream::~SoundStream()
-{
- // Stop the sound if it was playing
- stop();
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundStream::initialize(unsigned int channelCount, unsigned int sampleRate)
-{
- m_channelCount = channelCount;
- m_sampleRate = sampleRate;
-
- // Deduce the format from the number of channels
- m_format = priv::AudioDevice::getFormatFromChannelCount(channelCount);
-
- // Check if the format is valid
- if (m_format == 0)
- {
- m_channelCount = 0;
- m_sampleRate = 0;
- err() << "Unsupported number of channels (" << m_channelCount << ")" << std::endl;
- }
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundStream::play()
-{
- // Check if the sound parameters have been set
- if (m_format == 0)
- {
- err() << "Failed to play audio stream: sound parameters have not been initialized (call Initialize first)" << std::endl;
- return;
- }
-
- // If the sound is already playing (probably paused), just resume it
- if (m_isStreaming)
- {
- alCheck(alSourcePlay(m_source));
- return;
- }
-
- // Move to the beginning
- onSeek(Time::Zero);
-
- // Start updating the stream in a separate thread to avoid blocking the application
- m_samplesProcessed = 0;
- m_isStreaming = true;
- m_thread.launch();
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundStream::pause()
-{
- alCheck(alSourcePause(m_source));
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundStream::stop()
-{
- // Wait for the thread to terminate
- m_isStreaming = false;
- m_thread.wait();
-}
-
-
-////////////////////////////////////////////////////////////
-unsigned int SoundStream::getChannelCount() const
-{
- return m_channelCount;
-}
-
-
-////////////////////////////////////////////////////////////
-unsigned int SoundStream::getSampleRate() const
-{
- return m_sampleRate;
-}
-
-
-////////////////////////////////////////////////////////////
-SoundStream::Status SoundStream::getStatus() const
-{
- Status status = SoundSource::getStatus();
-
- // To compensate for the lag between play() and alSourceplay()
- if ((status == Stopped) && m_isStreaming)
- status = Playing;
-
- return status;
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundStream::setPlayingOffset(Time timeOffset)
-{
- // Stop the stream
- stop();
-
- // Let the derived class update the current position
- onSeek(timeOffset);
-
- // Restart streaming
- m_samplesProcessed = static_cast<Uint64>(timeOffset.asSeconds() * m_sampleRate * m_channelCount);
- m_isStreaming = true;
- m_thread.launch();
-}
-
-
-////////////////////////////////////////////////////////////
-Time SoundStream::getPlayingOffset() const
-{
- if (m_sampleRate && m_channelCount)
- {
- ALfloat secs = 0.f;
- alCheck(alGetSourcef(m_source, AL_SEC_OFFSET, &secs));
-
- return seconds(secs + static_cast<float>(m_samplesProcessed) / m_sampleRate / m_channelCount);
- }
- else
- {
- return Time::Zero;
- }
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundStream::setLoop(bool loop)
-{
- m_loop = loop;
-}
-
-
-////////////////////////////////////////////////////////////
-bool SoundStream::getLoop() const
-{
- return m_loop;
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundStream::streamData()
-{
- // Create the buffers
- alCheck(alGenBuffers(BufferCount, m_buffers));
- for (int i = 0; i < BufferCount; ++i)
- m_endBuffers[i] = false;
-
- // Fill the queue
- bool requestStop = fillQueue();
-
- // Play the sound
- alCheck(alSourcePlay(m_source));
-
- while (m_isStreaming)
- {
- // The stream has been interrupted!
- if (SoundSource::getStatus() == Stopped)
- {
- if (!requestStop)
- {
- // Just continue
- alCheck(alSourcePlay(m_source));
- }
- else
- {
- // End streaming
- m_isStreaming = false;
- }
- }
-
- // Get the number of buffers that have been processed (ie. ready for reuse)
- ALint nbProcessed = 0;
- alCheck(alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &nbProcessed));
-
- while (nbProcessed--)
- {
- // Pop the first unused buffer from the queue
- ALuint buffer;
- alCheck(alSourceUnqueueBuffers(m_source, 1, &buffer));
-
- // Find its number
- unsigned int bufferNum = 0;
- for (int i = 0; i < BufferCount; ++i)
- if (m_buffers[i] == buffer)
- {
- bufferNum = i;
- break;
- }
-
- // Retrieve its size and add it to the samples count
- if (m_endBuffers[bufferNum])
- {
- // This was the last buffer: reset the sample count
- m_samplesProcessed = 0;
- m_endBuffers[bufferNum] = false;
- }
- else
- {
- ALint size, bits;
- alCheck(alGetBufferi(buffer, AL_SIZE, &size));
- alCheck(alGetBufferi(buffer, AL_BITS, &bits));
- m_samplesProcessed += size / (bits / 8);
- }
-
- // Fill it and push it back into the playing queue
- if (!requestStop)
- {
- if (fillAndPushBuffer(bufferNum))
- requestStop = true;
- }
- }
-
- // Leave some time for the other threads if the stream is still playing
- if (SoundSource::getStatus() != Stopped)
- sleep(milliseconds(10));
- }
-
- // Stop the playback
- alCheck(alSourceStop(m_source));
-
- // Unqueue any buffer left in the queue
- clearQueue();
-
- // Delete the buffers
- alCheck(alSourcei(m_source, AL_BUFFER, 0));
- alCheck(alDeleteBuffers(BufferCount, m_buffers));
-}
-
-
-////////////////////////////////////////////////////////////
-bool SoundStream::fillAndPushBuffer(unsigned int bufferNum)
-{
- bool requestStop = false;
-
- // Acquire audio data
- Chunk data = {NULL, 0};
- if (!onGetData(data))
- {
- // Mark the buffer as the last one (so that we know when to reset the playing position)
- m_endBuffers[bufferNum] = true;
-
- // Check if the stream must loop or stop
- if (m_loop)
- {
- // Return to the beginning of the stream source
- onSeek(Time::Zero);
-
- // If we previously had no data, try to fill the buffer once again
- if (!data.samples || (data.sampleCount == 0))
- {
- return fillAndPushBuffer(bufferNum);
- }
- }
- else
- {
- // Not looping: request stop
- requestStop = true;
- }
- }
-
- // Fill the buffer if some data was returned
- if (data.samples && data.sampleCount)
- {
- unsigned int buffer = m_buffers[bufferNum];
-
- // Fill the buffer
- ALsizei size = static_cast<ALsizei>(data.sampleCount) * sizeof(Int16);
- alCheck(alBufferData(buffer, m_format, data.samples, size, m_sampleRate));
-
- // Push it into the sound queue
- alCheck(alSourceQueueBuffers(m_source, 1, &buffer));
- }
-
- return requestStop;
-}
-
-
-////////////////////////////////////////////////////////////
-bool SoundStream::fillQueue()
-{
- // Fill and enqueue all the available buffers
- bool requestStop = false;
- for (int i = 0; (i < BufferCount) && !requestStop; ++i)
- {
- if (fillAndPushBuffer(i))
- requestStop = true;
- }
-
- return requestStop;
-}
-
-
-////////////////////////////////////////////////////////////
-void SoundStream::clearQueue()
-{
- // Get the number of buffers still in the queue
- ALint nbQueued;
- alCheck(alGetSourcei(m_source, AL_BUFFERS_QUEUED, &nbQueued));
-
- // Unqueue them all
- ALuint buffer;
- for (ALint i = 0; i < nbQueued; ++i)
- alCheck(alSourceUnqueueBuffers(m_source, 1, &buffer));
-}
-
-} // namespace sf
+//////////////////////////////////////////////////////////// +// +// 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 <SFML/Audio/SoundStream.hpp> +#include <SFML/Audio/AudioDevice.hpp> +#include <SFML/Audio/ALCheck.hpp> +#include <SFML/System/Sleep.hpp> +#include <SFML/System/Err.hpp> +#include <SFML/System/Lock.hpp> + +#ifdef _MSC_VER + #pragma warning(disable: 4355) // 'this' used in base member initializer list +#endif + + +namespace sf +{ +//////////////////////////////////////////////////////////// +SoundStream::SoundStream() : +m_thread (&SoundStream::streamData, this), +m_threadMutex (), +m_threadStartState(Stopped), +m_isStreaming (false), +m_channelCount (0), +m_sampleRate (0), +m_format (0), +m_loop (false), +m_samplesProcessed(0) +{ + +} + + +//////////////////////////////////////////////////////////// +SoundStream::~SoundStream() +{ + // Stop the sound if it was playing + + // Request the thread to terminate + { + Lock lock(m_threadMutex); + m_isStreaming = false; + } + + // Wait for the thread to terminate + m_thread.wait(); +} + + +//////////////////////////////////////////////////////////// +void SoundStream::initialize(unsigned int channelCount, unsigned int sampleRate) +{ + m_channelCount = channelCount; + m_sampleRate = sampleRate; + + // Deduce the format from the number of channels + m_format = priv::AudioDevice::getFormatFromChannelCount(channelCount); + + // Check if the format is valid + if (m_format == 0) + { + m_channelCount = 0; + m_sampleRate = 0; + err() << "Unsupported number of channels (" << m_channelCount << ")" << std::endl; + } +} + + +//////////////////////////////////////////////////////////// +void SoundStream::play() +{ + // Check if the sound parameters have been set + if (m_format == 0) + { + err() << "Failed to play audio stream: sound parameters have not been initialized (call initialize() first)" << std::endl; + return; + } + + bool isStreaming = false; + Status threadStartState = Stopped; + + { + Lock lock(m_threadMutex); + + isStreaming = m_isStreaming; + threadStartState = m_threadStartState; + } + + + if (isStreaming && (threadStartState == Paused)) + { + // If the sound is paused, resume it + Lock lock(m_threadMutex); + m_threadStartState = Playing; + alCheck(alSourcePlay(m_source)); + return; + } + else if (isStreaming && (threadStartState == Playing)) + { + // If the sound is playing, stop it and continue as if it was stopped + stop(); + } + + // Move to the beginning + onSeek(Time::Zero); + + // Start updating the stream in a separate thread to avoid blocking the application + m_samplesProcessed = 0; + m_isStreaming = true; + m_threadStartState = Playing; + m_thread.launch(); +} + + +//////////////////////////////////////////////////////////// +void SoundStream::pause() +{ + // Handle pause() being called before the thread has started + { + Lock lock(m_threadMutex); + + if (!m_isStreaming) + return; + + m_threadStartState = Paused; + } + + alCheck(alSourcePause(m_source)); +} + + +//////////////////////////////////////////////////////////// +void SoundStream::stop() +{ + // Request the thread to terminate + { + Lock lock(m_threadMutex); + m_isStreaming = false; + } + + // Wait for the thread to terminate + m_thread.wait(); + + // Move to the beginning + onSeek(Time::Zero); + + // Reset the playing position + m_samplesProcessed = 0; +} + + +//////////////////////////////////////////////////////////// +unsigned int SoundStream::getChannelCount() const +{ + return m_channelCount; +} + + +//////////////////////////////////////////////////////////// +unsigned int SoundStream::getSampleRate() const +{ + return m_sampleRate; +} + + +//////////////////////////////////////////////////////////// +SoundStream::Status SoundStream::getStatus() const +{ + Status status = SoundSource::getStatus(); + + // To compensate for the lag between play() and alSourceplay() + if (status == Stopped) + { + Lock lock(m_threadMutex); + + if (m_isStreaming) + status = m_threadStartState; + } + + return status; +} + + +//////////////////////////////////////////////////////////// +void SoundStream::setPlayingOffset(Time timeOffset) +{ + // Get old playing status + Status oldStatus = getStatus(); + + // Stop the stream + stop(); + + // Let the derived class update the current position + onSeek(timeOffset); + + // Restart streaming + m_samplesProcessed = static_cast<Uint64>(timeOffset.asSeconds() * m_sampleRate * m_channelCount); + + if (oldStatus == Stopped) + return; + + m_isStreaming = true; + m_threadStartState = oldStatus; + m_thread.launch(); +} + + +//////////////////////////////////////////////////////////// +Time SoundStream::getPlayingOffset() const +{ + if (m_sampleRate && m_channelCount) + { + ALfloat secs = 0.f; + alCheck(alGetSourcef(m_source, AL_SEC_OFFSET, &secs)); + + return seconds(secs + static_cast<float>(m_samplesProcessed) / m_sampleRate / m_channelCount); + } + else + { + return Time::Zero; + } +} + + +//////////////////////////////////////////////////////////// +void SoundStream::setLoop(bool loop) +{ + m_loop = loop; +} + + +//////////////////////////////////////////////////////////// +bool SoundStream::getLoop() const +{ + return m_loop; +} + + +//////////////////////////////////////////////////////////// +void SoundStream::streamData() +{ + bool requestStop = false; + + { + Lock lock(m_threadMutex); + + // Check if the thread was launched Stopped + if (m_threadStartState == Stopped) + { + m_isStreaming = false; + return; + } + + // Create the buffers + alCheck(alGenBuffers(BufferCount, m_buffers)); + for (int i = 0; i < BufferCount; ++i) + m_endBuffers[i] = false; + + // Fill the queue + requestStop = fillQueue(); + + // Play the sound + alCheck(alSourcePlay(m_source)); + + // Check if the thread was launched Paused + if (m_threadStartState == Paused) + alCheck(alSourcePause(m_source)); + } + + for (;;) + { + { + Lock lock(m_threadMutex); + if (!m_isStreaming) + break; + } + + // The stream has been interrupted! + if (SoundSource::getStatus() == Stopped) + { + if (!requestStop) + { + // Just continue + alCheck(alSourcePlay(m_source)); + } + else + { + // End streaming + Lock lock(m_threadMutex); + m_isStreaming = false; + } + } + + // Get the number of buffers that have been processed (i.e. ready for reuse) + ALint nbProcessed = 0; + alCheck(alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &nbProcessed)); + + while (nbProcessed--) + { + // Pop the first unused buffer from the queue + ALuint buffer; + alCheck(alSourceUnqueueBuffers(m_source, 1, &buffer)); + + // Find its number + unsigned int bufferNum = 0; + for (int i = 0; i < BufferCount; ++i) + if (m_buffers[i] == buffer) + { + bufferNum = i; + break; + } + + // Retrieve its size and add it to the samples count + if (m_endBuffers[bufferNum]) + { + // This was the last buffer: reset the sample count + m_samplesProcessed = 0; + m_endBuffers[bufferNum] = false; + } + else + { + ALint size, bits; + alCheck(alGetBufferi(buffer, AL_SIZE, &size)); + alCheck(alGetBufferi(buffer, AL_BITS, &bits)); + + // Bits can be 0 if the format or parameters are corrupt, avoid division by zero + if (bits == 0) + { + err() << "Bits in sound stream are 0: make sure that the audio format is not corrupt " + << "and initialize() has been called correctly" << std::endl; + + // Abort streaming (exit main loop) + Lock lock(m_threadMutex); + m_isStreaming = false; + requestStop = true; + break; + } + else + { + m_samplesProcessed += size / (bits / 8); + } + } + + // Fill it and push it back into the playing queue + if (!requestStop) + { + if (fillAndPushBuffer(bufferNum)) + requestStop = true; + } + } + + // Leave some time for the other threads if the stream is still playing + if (SoundSource::getStatus() != Stopped) + sleep(milliseconds(10)); + } + + // Stop the playback + alCheck(alSourceStop(m_source)); + + // Dequeue any buffer left in the queue + clearQueue(); + + // Delete the buffers + alCheck(alSourcei(m_source, AL_BUFFER, 0)); + alCheck(alDeleteBuffers(BufferCount, m_buffers)); +} + + +//////////////////////////////////////////////////////////// +bool SoundStream::fillAndPushBuffer(unsigned int bufferNum) +{ + bool requestStop = false; + + // Acquire audio data + Chunk data = {NULL, 0}; + if (!onGetData(data)) + { + // Mark the buffer as the last one (so that we know when to reset the playing position) + m_endBuffers[bufferNum] = true; + + // Check if the stream must loop or stop + if (m_loop) + { + // Return to the beginning of the stream source + onSeek(Time::Zero); + + // If we previously had no data, try to fill the buffer once again + if (!data.samples || (data.sampleCount == 0)) + { + return fillAndPushBuffer(bufferNum); + } + } + else + { + // Not looping: request stop + requestStop = true; + } + } + + // Fill the buffer if some data was returned + if (data.samples && data.sampleCount) + { + unsigned int buffer = m_buffers[bufferNum]; + + // Fill the buffer + ALsizei size = static_cast<ALsizei>(data.sampleCount) * sizeof(Int16); + alCheck(alBufferData(buffer, m_format, data.samples, size, m_sampleRate)); + + // Push it into the sound queue + alCheck(alSourceQueueBuffers(m_source, 1, &buffer)); + } + + return requestStop; +} + + +//////////////////////////////////////////////////////////// +bool SoundStream::fillQueue() +{ + // Fill and enqueue all the available buffers + bool requestStop = false; + for (int i = 0; (i < BufferCount) && !requestStop; ++i) + { + if (fillAndPushBuffer(i)) + requestStop = true; + } + + return requestStop; +} + + +//////////////////////////////////////////////////////////// +void SoundStream::clearQueue() +{ + // Get the number of buffers still in the queue + ALint nbQueued; + alCheck(alGetSourcei(m_source, AL_BUFFERS_QUEUED, &nbQueued)); + + // Dequeue them all + ALuint buffer; + for (ALint i = 0; i < nbQueued; ++i) + alCheck(alSourceUnqueueBuffers(m_source, 1, &buffer)); +} + +} // namespace sf |