Documentation for module: Audio

Former-commit-id: acb9e00a7af8bf1c36f42b45fe7e7df99e03c0f9
This commit is contained in:
Gawaboumga 2016-05-30 13:36:52 +02:00
parent ea920d2e64
commit 8336c05522
23 changed files with 1110 additions and 56 deletions

View File

@ -7,11 +7,21 @@
namespace Nz
{
/*!
* \ingroup audio
* \brief Mixes channels in mono
*
* \param input Input buffer with multiples channels
* \param output Output butter for mono
* \param channelCount Number of channels
* \param frameCount Number of frames
*
* \remark The input buffer may be the same as the output one
*/
template<typename T>
void MixToMono(T* input, T* output, unsigned int channelCount, unsigned int frameCount)
{
///DOC: Le buffer d'entrée peut être le même que le buffer de sortie
// Pour éviter l'overflow, on utilise comme accumulateur un type assez grand, (u)int 64 bits pour les entiers, double pour les flottants
// To avoid overflow, we use, as an accumulator, a type which is large enough: (u)int 64 bits for integers, double for floatings
typedef typename std::conditional<std::is_unsigned<T>::value, UInt64, Int64>::type BiggestInt;
typedef typename std::conditional<std::is_integral<T>::value, BiggestInt, double>::type Biggest;

View File

@ -27,18 +27,23 @@
#ifndef NAZARA_CONFIG_AUDIO_HPP
#define NAZARA_CONFIG_AUDIO_HPP
/// Modifier la configuration d'un module nécessite une recompilation quasi-intégrale de celui-ci et de ceux en héritant
/*!
* \defgroup audio (NazaraAudio) Audio module
* Audio/System module including classes to handle music, sound, etc...
*/
// Utilise un manager de mémoire pour gérer les allocations dynamiques (détecte les leaks au prix d'allocations/libérations dynamiques plus lentes)
/// Each modification of a parameter needs a recompilation of the module
// Use the MemoryManager to manage dynamic allocations (can detect memory leak but allocations/frees are slower)
#define NAZARA_AUDIO_MANAGE_MEMORY 0
// Active les tests de sécurité supplémentaires (Teste notamment les arguments des fonctions, conseillé pour le développement)
// Activate the security tests based on the code (Advised for development)
#define NAZARA_AUDIO_SAFE 1
// Le nombre de buffers utilisés lors du streaming d'objets audio (Au moins deux)
// The number of buffers used for audio streaming (At least two)
#define NAZARA_AUDIO_STREAMED_BUFFER_COUNT 2
/// Vérification des valeurs et types de certaines constantes
/// Checking the values and types of certain constants
#include <Nazara/Audio/ConfigCheck.hpp>
#if !defined(NAZARA_STATIC)

View File

@ -7,12 +7,12 @@
#ifndef NAZARA_CONFIG_CHECK_AUDIO_HPP
#define NAZARA_CONFIG_CHECK_AUDIO_HPP
/// Ce fichier sert à vérifier la valeur des constantes du fichier Config.hpp
/// This file is used to check the constant values defined in Config.hpp
#include <type_traits>
#define NazaraCheckTypeAndVal(name, type, op, val, err) static_assert(std::is_ ##type <decltype(name)>::value && name op val, #type err)
// On force la valeur de MANAGE_MEMORY en mode debug
// We force the value of MANAGE_MEMORY in debug
#if defined(NAZARA_DEBUG) && !NAZARA_AUDIO_MANAGE_MEMORY
#undef NAZARA_AUDIO_MANAGE_MEMORY
#define NAZARA_AUDIO_MANAGE_MEMORY 0

View File

@ -2,7 +2,7 @@
// This file is part of the "Nazara Engine - Audio module"
// For conditions of distribution and use, see copyright notice in Config.hpp
// On suppose que Debug.hpp a déjà été inclus, tout comme Config.hpp
// We assume that Debug.hpp has already been included, same thing for Config.hpp
#if NAZARA_AUDIO_MANAGE_MEMORY
#undef delete
#undef new

View File

@ -13,7 +13,7 @@ namespace Nz
{
AudioFormat_Unknown = -1,
// La valeur entière est le nombre de canaux possédés par ce format
// The integer value is the number of channels used by the format
AudioFormat_Mono = 1,
AudioFormat_Stereo = 2,
AudioFormat_Quad = 4,

View File

@ -15,18 +15,18 @@
#include <Nazara/Core/String.hpp>
#include <vector>
// Inclusion des headers OpenAL
// Inclusion of OpenAL headers
// Étant donné que les headers OpenAL ne nous permettent pas de n'avoir que les signatures sans les pointeurs de fonctions
// Et que je ne souhaite pas les modifier, je suis contraint de les placer dans un espace de nom différent pour ensuite
// remettre dans l'espace global les choses intéressantes (les typedef notamment)
// OpenAL headers does not allow us to only get the signatures without the pointers to the functions
// And I do no want to modify them, I'm obliged to put them in a different namespace
// to put only interesting things back in the global namespace (specially typedef)
namespace OpenALDetail
{
#include <AL/al.h>
#include <AL/alc.h>
}
// Si quelqu'un a une meilleure idée ...
// If someone has a better idea ...
using OpenALDetail::ALboolean;
using OpenALDetail::ALbyte;
using OpenALDetail::ALchar;

View File

@ -7,6 +7,13 @@
namespace Nz
{
/*!
* \brief Creates a new sound buffer from the arguments
* \return A reference to the newly created sound buffer
*
* \param args Arguments for the sound buffer
*/
template<typename... Args>
SoundBufferRef SoundBuffer::New(Args&&... args)
{

View File

@ -12,7 +12,7 @@
#include <Nazara/Audio/Enums.hpp>
#include <Nazara/Math/Vector3.hpp>
///TODO: Faire hériter SoundEmitter de Node
///TODO: Inherit SoundEmitter from Node
namespace Nz
{

View File

@ -16,6 +16,21 @@
namespace Nz
{
/*!
* \ingroup audio
* \class Nz::Audio
* \brief Audio class that represents the module initializer of Audio
*/
/*!
* \brief Gets the format of the audio
* \return AudioFormat Enumeration type for the format
*
* \param channelCount Number of channels
*
* \remark Produces a NazaraError if the number of channels is erroneous (3 or 5) and AudioFormat_Unknown is returned
*/
AudioFormat Audio::GetAudioFormat(unsigned int channelCount)
{
switch (channelCount)
@ -34,11 +49,21 @@ namespace Nz
}
}
/*!
* \brief Gets the factor of the doppler effect
* \return Global factor of the doppler effect
*/
float Audio::GetDopplerFactor()
{
return alGetFloat(AL_DOPPLER_FACTOR);
}
/*!
* \brief Gets the global volume
* \return Float between [0, inf) with 100.f being the default
*/
float Audio::GetGlobalVolume()
{
ALfloat gain = 0.f;
@ -47,6 +72,13 @@ namespace Nz
return gain * 100.f;
}
/*!
* \brief Gets the direction of the listener
* \return Direction of the listener, in front of the listener
*
* \see GetListenerRotation
*/
Vector3f Audio::GetListenerDirection()
{
ALfloat orientation[6];
@ -55,6 +87,13 @@ namespace Nz
return Vector3f(orientation[0], orientation[1], orientation[2]);
}
/*!
* \brief Gets the position of the listener
* \return Position of the listener
*
* \see GetListenerVelocity
*/
Vector3f Audio::GetListenerPosition()
{
Vector3f position;
@ -63,6 +102,11 @@ namespace Nz
return position;
}
/*!
* \brief Gets the rotation of the listener
* \return Rotation of the listener
*/
Quaternionf Audio::GetListenerRotation()
{
ALfloat orientation[6];
@ -73,6 +117,13 @@ namespace Nz
return Quaternionf::RotationBetween(Vector3f::Forward(), forward);
}
/*!
* \brief Gets the velocity of the listener
* \return Velocity of the listener
*
* \see GetListenerPosition
*/
Vector3f Audio::GetListenerVelocity()
{
Vector3f velocity;
@ -81,20 +132,33 @@ namespace Nz
return velocity;
}
/*!
* \brief Gets the speed of sound
* \return Speed of sound
*/
float Audio::GetSpeedOfSound()
{
return alGetFloat(AL_SPEED_OF_SOUND);
}
/*!
* \brief Initializes the Audio module
* \return true if initialization is successful
*
* \remark Produces a NazaraError if initialization of modules Core, OpenAL or SoundBuffer failed
* \remark Produces a NazaraNotice
*/
bool Audio::Initialize()
{
if (s_moduleReferenceCounter > 0)
if (IsInitialized())
{
s_moduleReferenceCounter++;
return true; // Déjà initialisé
return true; // Already initialized
}
// Initialisation des dépendances
// Initialisation of dependencies
if (!Core::Initialize())
{
NazaraError("Failed to initialize core module");
@ -103,10 +167,10 @@ namespace Nz
s_moduleReferenceCounter++;
// Initialisation du module
// Initialisation of the module
CallOnExit onExit(Audio::Uninitialize);
// Initialisation d'OpenAL
// Initialisation of OpenAL
if (!OpenAL::Initialize())
{
NazaraError("Failed to initialize OpenAL");
@ -119,7 +183,7 @@ namespace Nz
return false;
}
// Définition de l'orientation par défaut
// Definition of the orientation by default
SetListenerDirection(Vector3f::Forward());
// Loaders
@ -131,6 +195,13 @@ namespace Nz
return true;
}
/*!
* \brief Checks whether the format is supported by the engine
* \return true if it is the case
*
* \param format Format to check
*/
bool Audio::IsFormatSupported(AudioFormat format)
{
if (format == AudioFormat_Unknown)
@ -139,21 +210,46 @@ namespace Nz
return OpenAL::AudioFormat[format] != 0;
}
/*!
* \brief Checks whether the module is initialized
* \return true if module is initialized
*/
bool Audio::IsInitialized()
{
return s_moduleReferenceCounter != 0;
}
/*!
* \brief Sets the factor of the doppler effect
*
* \param dopplerFactor Global factor of the doppler effect
*/
void Audio::SetDopplerFactor(float dopplerFactor)
{
alDopplerFactor(dopplerFactor);
}
/*!
* \brief Sets the global volume
*
* \param volume Float between [0, inf) with 100.f being the default
*/
void Audio::SetGlobalVolume(float volume)
{
alListenerf(AL_GAIN, volume * 0.01f);
}
/*!
* \brief Sets the direction of the listener
*
* \param direction Direction of the listener, in front of the listener
*
* \see SetListenerDirection, SetListenerRotation
*/
void Audio::SetListenerDirection(const Vector3f& direction)
{
Vector3f up = Vector3f::Up();
@ -167,6 +263,14 @@ namespace Nz
alListenerfv(AL_ORIENTATION, orientation);
}
/*!
* \brief Sets the direction of the listener
*
* \param (dirX, dirY, dirZ) Direction of the listener, in front of the listener
*
* \see SetListenerDirection, SetListenerRotation
*/
void Audio::SetListenerDirection(float dirX, float dirY, float dirZ)
{
Vector3f up = Vector3f::Up();
@ -180,16 +284,38 @@ namespace Nz
alListenerfv(AL_ORIENTATION, orientation);
}
/*!
* \brief Sets the position of the listener
*
* \param position Position of the listener
*
* \see SetListenerVelocity
*/
void Audio::SetListenerPosition(const Vector3f& position)
{
alListenerfv(AL_POSITION, position);
}
/*!
* \brief Sets the position of the listener
*
* \param (x, y, z) Position of the listener
*
* \see SetListenerVelocity
*/
void Audio::SetListenerPosition(float x, float y, float z)
{
alListener3f(AL_POSITION, x, y, z);
}
/*!
* \brief Sets the rotation of the listener
*
* \param rotation Rotation of the listener
*/
void Audio::SetListenerRotation(const Quaternionf& rotation)
{
Vector3f forward = rotation * Vector3f::Forward();
@ -204,33 +330,61 @@ namespace Nz
alListenerfv(AL_ORIENTATION, orientation);
}
/*!
* \brief Sets the velocity of the listener
*
* \param velocity Velocity of the listener
*
* \see SetListenerPosition
*/
void Audio::SetListenerVelocity(const Vector3f& velocity)
{
alListenerfv(AL_VELOCITY, velocity);
}
/*!
* \brief Sets the velocity of the listener
*
* \param (velX, velY, velZ) Velocity of the listener
*
* \see SetListenerPosition
*/
void Audio::SetListenerVelocity(float velX, float velY, float velZ)
{
alListener3f(AL_VELOCITY, velX, velY, velZ);
}
/*!
* \brief Sets the speed of sound
*
* \param speed Speed of sound
*/
void Audio::SetSpeedOfSound(float speed)
{
alSpeedOfSound(speed);
}
/*!
* \brief Uninitializes the Audio module
*
* \remark Produces a NazaraNotice
*/
void Audio::Uninitialize()
{
if (s_moduleReferenceCounter != 1)
{
// Le module est soit encore utilisé, soit pas initialisé
// The module is still in use, or can not be uninitialized
if (s_moduleReferenceCounter > 1)
s_moduleReferenceCounter--;
return;
}
// Libération du module
// Free of module
s_moduleReferenceCounter = 0;
// Loaders
@ -241,7 +395,7 @@ namespace Nz
NazaraNotice("Uninitialized: Audio module");
// Libération des dépendances
// Free of dependencies
Core::Uninitialize();
}

View File

@ -14,6 +14,19 @@
namespace Nz
{
/*!
* \ingroup audio
* \class Nz::Music
* \brief Audio class that represents a music
*
* \remark Module Audio needs to be initialized to use this class
*/
/*!
* \brief Checks whether the parameters for the loading of the music are correct
* \return true If parameters are valid
*/
bool MusicParams::IsValid() const
{
return true;
@ -32,11 +45,26 @@ namespace Nz
unsigned int sampleRate;
};
/*!
* \brief Destructs the object and calls Destroy
*
* \see Destroy
*/
Music::~Music()
{
Destroy();
}
/*!
* \brief Creates a music with a sound stream
* \return true if creation was succesful
*
* \param soundStream Sound stream which is the source for the music
*
* \remark Produces a NazaraError if soundStream is invalid with NAZARA_AUDIO_SAFE defined
*/
bool Music::Create(SoundStream* soundStream)
{
NazaraAssert(soundStream, "Invalid stream");
@ -48,7 +76,7 @@ namespace Nz
m_impl = new MusicImpl;
m_impl->sampleRate = soundStream->GetSampleRate();
m_impl->audioFormat = OpenAL::AudioFormat[format];
m_impl->chunkSamples.resize(format * m_impl->sampleRate); // Une seconde de samples
m_impl->chunkSamples.resize(format * m_impl->sampleRate); // One second of samples
m_impl->stream.reset(soundStream);
SetPlayingOffset(0);
@ -56,6 +84,10 @@ namespace Nz
return true;
}
/*!
* \brief Destroys the current music and frees resources
*/
void Music::Destroy()
{
if (m_impl)
@ -67,6 +99,14 @@ namespace Nz
}
}
/*!
* \brief Enables the looping of the music
*
* \param loop Should music loop
*
* \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined
*/
void Music::EnableLooping(bool loop)
{
#if NAZARA_AUDIO_SAFE
@ -80,6 +120,13 @@ namespace Nz
m_impl->loop = loop;
}
/*!
* \brief Gets the duration of the music
* \return Duration of the music in milliseconds
*
* \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined
*/
UInt32 Music::GetDuration() const
{
#if NAZARA_AUDIO_SAFE
@ -93,6 +140,13 @@ namespace Nz
return m_impl->stream->GetDuration();
}
/*!
* \brief Gets the format of the music
* \return Enumeration of type AudioFormat (mono, stereo, ...)
*
* \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined
*/
AudioFormat Music::GetFormat() const
{
#if NAZARA_AUDIO_SAFE
@ -106,6 +160,13 @@ namespace Nz
return m_impl->stream->GetFormat();
}
/*!
* \brief Gets the current offset in the music
* \return Offset in milliseconds (works with entire seconds)
*
* \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined
*/
UInt32 Music::GetPlayingOffset() const
{
#if NAZARA_AUDIO_SAFE
@ -125,6 +186,13 @@ namespace Nz
return static_cast<UInt32>((1000ULL * (samples + (m_impl->processedSamples / m_impl->stream->GetFormat()))) / m_impl->sampleRate);
}
/*!
* \brief Gets the number of samples in the music
* \return Count of samples (number of seconds * sample rate * channel count)
*
* \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined
*/
UInt32 Music::GetSampleCount() const
{
#if NAZARA_AUDIO_SAFE
@ -138,6 +206,13 @@ namespace Nz
return m_impl->stream->GetSampleCount();
}
/*!
* \brief Gets the rates of sample in the music
* \return Rate of sample in Hertz (Hz)
*
* \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined
*/
UInt32 Music::GetSampleRate() const
{
#if NAZARA_AUDIO_SAFE
@ -151,6 +226,14 @@ namespace Nz
return m_impl->sampleRate;
}
/*!
* \brief Gets the status of the music
* \return Enumeration of type SoundStatus (Playing, Stopped, ...)
*
* \remark If the music is not playing, Stopped is returned
* \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined
*/
SoundStatus Music::GetStatus() const
{
#if NAZARA_AUDIO_SAFE
@ -163,13 +246,20 @@ namespace Nz
SoundStatus status = GetInternalStatus();
// Pour compenser les éventuels retards (ou le laps de temps entre Play() et la mise en route du thread)
// To compensate any delays (or the timelaps between Play() and the thread startup)
if (m_impl->streaming && status == SoundStatus_Stopped)
status = SoundStatus_Playing;
return status;
}
/*!
* \brief Checks whether the music is looping
* \return true if it is the case
*
* \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined
*/
bool Music::IsLooping() const
{
#if NAZARA_AUDIO_SAFE
@ -183,26 +273,61 @@ namespace Nz
return m_impl->loop;
}
/*!
* \brief Loads the music from file
* \return true if loading is successful
*
* \param filePath Path to the file
* \param params Parameters for the music
*/
bool Music::OpenFromFile(const String& filePath, const MusicParams& params)
{
return MusicLoader::LoadFromFile(this, filePath, params);
}
/*!
* \brief Loads the music from memory
* \return true if loading is successful
*
* \param data Raw memory
* \param size Size of the memory
* \param params Parameters for the music
*/
bool Music::OpenFromMemory(const void* data, std::size_t size, const MusicParams& params)
{
return MusicLoader::LoadFromMemory(this, data, size, params);
}
/*!
* \brief Loads the music from stream
* \return true if loading is successful
*
* \param stream Stream to the music
* \param params Parameters for the music
*/
bool Music::OpenFromStream(Stream& stream, const MusicParams& params)
{
return MusicLoader::LoadFromStream(this, stream, params);
}
/*!
* \brief Pauses the music
*/
void Music::Pause()
{
alSourcePause(m_source);
}
/*!
* \brief Plays the music
*
* \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined
*/
void Music::Play()
{
#if NAZARA_AUDIO_SAFE
@ -238,6 +363,14 @@ namespace Nz
}
}
/*!
* \brief Sets the playing offset for the music
*
* \param offset Offset in the music in milliseconds
*
* \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined
*/
void Music::SetPlayingOffset(UInt32 offset)
{
#if NAZARA_AUDIO_SAFE
@ -260,6 +393,12 @@ namespace Nz
Play();
}
/*!
* \brief Stops the music
*
* \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined
*/
void Music::Stop()
{
#if NAZARA_AUDIO_SAFE
@ -277,6 +416,13 @@ namespace Nz
}
}
/*!
* \brief Fills the buffer and queues it up
* \return true if operation was successful
*
* \param buffer Index of the buffer
*/
bool Music::FillAndQueueBuffer(unsigned int buffer)
{
unsigned int sampleCount = m_impl->chunkSamples.size();
@ -304,27 +450,31 @@ namespace Nz
alSourceQueueBuffers(m_source, 1, &buffer);
}
return sampleRead != sampleCount; // Fin du stream (N'arrive pas en cas de loop)
return sampleRead != sampleCount; // End of stream (Does not happen when looping)
}
/*!
* \brief Thread function for the music
*/
void Music::MusicThread()
{
// Allocation des buffers de streaming
// Allocation of streaming buffers
ALuint buffers[NAZARA_AUDIO_STREAMED_BUFFER_COUNT];
alGenBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers);
for (unsigned int i = 0; i < NAZARA_AUDIO_STREAMED_BUFFER_COUNT; ++i)
{
if (FillAndQueueBuffer(buffers[i]))
break; // Nous avons atteint la fin du stream, inutile de rajouter des buffers
break; // We have reached the end of the stream, there is no use to add new buffers
}
alSourcePlay(m_source);
// Boucle de lecture (remplissage de nouveaux buffers au fur et à mesure)
// Reading loop (Filling new buffers as playing)
while (m_impl->streaming)
{
// La lecture s'est arrêtée, nous avons atteint la fin du stream
// The reading has stopped, we have reached the end of the stream
SoundStatus status = GetInternalStatus();
if (status == SoundStatus_Stopped)
{
@ -334,7 +484,7 @@ namespace Nz
Nz::LockGuard lock(m_impl->bufferLock);
// On traite les buffers lus
// We treat read buffers
ALint processedCount = 0;
alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &processedCount);
while (processedCount--)
@ -355,14 +505,14 @@ namespace Nz
lock.Unlock();
// On retourne dormir un peu
// We go back to sleep
Thread::Sleep(50);
}
// Arrêt de la lecture du son (dans le cas où ça ne serait pas déjà fait)
// Stop playing of the sound (in the case where it has not been already done)
alSourceStop(m_source);
// On supprime les buffers du stream
// We delete buffers from the stream
ALint queuedBufferCount;
alGetSourcei(m_source, AL_BUFFERS_QUEUED, &queuedBufferCount);

View File

@ -23,6 +23,14 @@ namespace Nz
ALCcontext* s_context = nullptr;
unsigned int s_version;
/*!
* \brief Parses the devices
* \return Number of devices
*
* \param deviceString String for the device (input / output)
* \param devices List of names of the devices
*/
std::size_t ParseDevices(const char* deviceString, std::vector<String>& devices)
{
if (!deviceString)
@ -41,35 +49,77 @@ namespace Nz
}
}
/*!
* \ingroup audio
* \class Nz::OpenAL
* \brief Audio class that represents the link with OpenAL
*
* \remark This class is meant to be used by Module Audio
*/
/*!
* \brief Gets the entry for the function name
* \return Pointer to the function
*
* \param entryPoint Name of the entry
*
* \remark This does not produces a NazaraError if entry does not exist
*/
OpenALFunc OpenAL::GetEntry(const String& entryPoint)
{
return LoadEntry(entryPoint.GetConstBuffer(), false);
}
/*!
* \brief Gets the name of the renderer
* \return Name of the renderer
*/
String OpenAL::GetRendererName()
{
return s_rendererName;
}
/*!
* \brief Gets the name of the vendor
* \return Name of the vendor
*/
String OpenAL::GetVendorName()
{
return s_vendorName;
}
/*!
* \brief Gets the version of OpenAL
* \return Version of OpenAL
*/
unsigned int OpenAL::GetVersion()
{
return s_version;
}
/*!
* \brief Initializes the module OpenAL
* \return true if initialization is successful
*
* \param openDevice True to get information from the device
*
* \remark Produces a NazaraError if one of the entry failed
* \remark Produces a NazaraError if opening device failed with openDevice parameter set to true
*/
bool OpenAL::Initialize(bool openDevice)
{
if (s_library.IsLoaded())
if (IsInitialized())
return true;
#if defined(NAZARA_PLATFORM_WINDOWS)
///FIXME: Est-ce qu'OpenAL Soft est une meilleure implémentation que Creative ?
/// Si on pouvait se résigner à utiliser OpenAL Soft tout le temps, cela nous permettrait d'utiliser les extensions sonores
/// et de donner plus de possibilités techniques au niveau de l'audio.
///FIXME: Is OpenAL Soft a better implementation than Creative ?
/// If we could use OpenAL Soft everytime, this would allow us to use sonorous extensions
/// and give us more technical possibilities with audio
const char* libs[] = {
"soft_oal.dll",
"wrap_oal.dll",
@ -217,11 +267,23 @@ namespace Nz
return true;
}
/*!
* \brief Checks whether the module is initialized
* \return true if it is the case
*/
bool OpenAL::IsInitialized()
{
return s_library.IsLoaded();
}
/*!
* \brief Queries the input devices
* \return Number of devices
*
* \param devices List of names of the input devices
*/
std::size_t OpenAL::QueryInputDevices(std::vector<String>& devices)
{
const char* deviceString = reinterpret_cast<const char*>(alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER));
@ -231,6 +293,13 @@ namespace Nz
return ParseDevices(deviceString, devices);
}
/*!
* \brief Queries the output devices
* \return Number of devices
*
* \param devices List of names of the output devices
*/
std::size_t OpenAL::QueryOutputDevices(std::vector<String>& devices)
{
const char* deviceString = reinterpret_cast<const char*>(alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER));
@ -240,6 +309,13 @@ namespace Nz
return ParseDevices(deviceString, devices);
}
/*!
* \brief Sets the active device
* \return true if device is successfully opened
*
* \param deviceName Name of the device
*/
bool OpenAL::SetDevice(const String& deviceName)
{
s_deviceName = deviceName;
@ -253,6 +329,10 @@ namespace Nz
return true;
}
/*!
* \brief Uninitializes the module
*/
void OpenAL::Uninitialize()
{
CloseDevice();
@ -262,8 +342,14 @@ namespace Nz
s_library.Unload();
}
///ATTENTION: La valeur entière est le nombre de canaux possédés par ce format
ALenum OpenAL::AudioFormat[AudioFormat_Max+1] = {0}; // Valeur ajoutées au chargement d'OpenAL
///WARNING: The integer value is the number of canals owned by the format
ALenum OpenAL::AudioFormat[AudioFormat_Max+1] = {0}; // Added values with loading of OpenAL
/*!
* \brief Closes the device
*
* \remark Produces a NazaraWarning if you try to close an active device
*/
void OpenAL::CloseDevice()
{
@ -277,24 +363,31 @@ namespace Nz
}
if (!alcCloseDevice(s_device))
// Nous n'avons pas pu fermer le device, ce qui signifie qu'il est en cours d'utilisation
// We could not close the close, this means that it's still in use
NazaraWarning("Failed to close device");
s_device = nullptr;
}
}
/*!
* \brief Opens the device
* \return true if open is successful
*
* \remark Produces a NazaraError if it could not create the context
*/
bool OpenAL::OpenDevice()
{
// Initialisation du module
s_device = alcOpenDevice(s_deviceName.IsEmpty() ? nullptr : s_deviceName.GetConstBuffer()); // On choisit le device par défaut
// Initialisation of the module
s_device = alcOpenDevice(s_deviceName.IsEmpty() ? nullptr : s_deviceName.GetConstBuffer()); // We choose the default device
if (!s_device)
{
NazaraError("Failed to open default device");
return false;
}
// Un seul contexte nous suffira
// One context is enough
s_context = alcCreateContext(s_device, nullptr);
if (!s_context)
{
@ -341,7 +434,7 @@ namespace Nz
s_version = 0;
}
// On complète le tableau de formats
// We complete the formats table
AudioFormat[AudioFormat_Mono] = AL_FORMAT_MONO16;
AudioFormat[AudioFormat_Stereo] = AL_FORMAT_STEREO16;
@ -359,6 +452,16 @@ namespace Nz
return true;
}
/*!
* \brief Loads the entry for the function name
* \return Pointer to the function
*
* \param name Name of the entry
* \param throwException Should throw exception if failed ?
*
* \remark Produces a std::runtime_error if entry does not exist and throwException is set to true
*/
OpenALFunc OpenAL::LoadEntry(const char* name, bool throwException)
{
OpenALFunc entry = reinterpret_cast<OpenALFunc>(s_library.GetSymbol(name));

View File

@ -14,32 +14,76 @@
namespace Nz
{
/*!
* \ingroup audio
* \class Nz::Sound
* \brief Audio class that represents a sound
*
* \remark Module Audio needs to be initialized to use this class
*/
/*!
* \brief Constructs a Sound object
*
* \param soundBuffer Buffer to read sound from
*/
Sound::Sound(const SoundBuffer* soundBuffer)
{
SetBuffer(soundBuffer);
}
/*!
* \brief Constructs a Sound object which is a copy of another
*
* \param sound Sound to copy
*/
Sound::Sound(const Sound& sound) :
SoundEmitter(sound)
{
SetBuffer(sound.m_buffer);
}
/*!
* \brief Destructs the object and calls Stop
*
* \see Stop
*/
Sound::~Sound()
{
Stop();
}
/*!
* \brief Enables the looping of the music
*
* \param loop Should sound loop
*/
void Sound::EnableLooping(bool loop)
{
alSourcei(m_source, AL_LOOPING, loop);
}
/*!
* \brief Gets the internal buffer
* \return Internal buffer
*/
const SoundBuffer* Sound::GetBuffer() const
{
return m_buffer;
}
/*!
* \brief Gets the duration of the sound
* \return Duration of the music in milliseconds
*
* \remark Produces a NazaraError if there is no buffer
*/
UInt32 Sound::GetDuration() const
{
NazaraAssert(m_buffer, "Invalid sound buffer");
@ -47,6 +91,11 @@ namespace Nz
return m_buffer->GetDuration();
}
/*!
* \brief Gets the current offset in the sound
* \return Offset in milliseconds (works with entire seconds)
*/
UInt32 Sound::GetPlayingOffset() const
{
ALint samples = 0;
@ -55,11 +104,21 @@ namespace Nz
return static_cast<UInt32>(1000ULL * samples / m_buffer->GetSampleRate());
}
/*!
* \brief Gets the status of the music
* \return Enumeration of type SoundStatus (Playing, Stopped, ...)
*/
SoundStatus Sound::GetStatus() const
{
return GetInternalStatus();
}
/*!
* \brief Checks whether the sound is looping
* \return true if it is the case
*/
bool Sound::IsLooping() const
{
ALint loop;
@ -68,16 +127,36 @@ namespace Nz
return loop != AL_FALSE;
}
/*!
* \brief Checks whether the sound is playable
* \return true if it is the case
*/
bool Sound::IsPlayable() const
{
return m_buffer != nullptr;
}
/*!
* \brief Checks whether the sound is playing
* \return true if it is the case
*/
bool Sound::IsPlaying() const
{
return GetStatus() == SoundStatus_Playing;
}
/*!
* \brief Loads the sound from file
* \return true if loading is successful
*
* \param filePath Path to the file
* \param params Parameters for the sound
*
* \remark Produces a NazaraError if loading failed
*/
bool Sound::LoadFromFile(const String& filePath, const SoundBufferParams& params)
{
SoundBufferRef buffer = SoundBuffer::New();
@ -91,6 +170,17 @@ namespace Nz
return true;
}
/*!
* \brief Loads the sound from memory
* \return true if loading is successful
*
* \param data Raw memory
* \param size Size of the memory
* \param params Parameters for the sound
*
* \remark Produces a NazaraError if loading failed
*/
bool Sound::LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params)
{
SoundBufferRef buffer = SoundBuffer::New();
@ -104,6 +194,16 @@ namespace Nz
return true;
}
/*!
* \brief Loads the sound from stream
* \return true if loading is successful
*
* \param stream Stream to the sound
* \param params Parameters for the sound
*
* \remark Produces a NazaraError if loading failed
*/
bool Sound::LoadFromStream(Stream& stream, const SoundBufferParams& params)
{
SoundBufferRef buffer = SoundBuffer::New();
@ -117,15 +217,25 @@ namespace Nz
return true;
}
/*!
* \brief Pauses the sound
*/
void Sound::Pause()
{
alSourcePause(m_source);
}
/*!
* \brief Plays the music
*
* \remark Produces a NazaraError if the sound is not playable with NAZARA_AUDIO_SAFE defined
*/
void Sound::Play()
{
#if NAZARA_AUDIO_SAFE
if (!m_buffer)
if (!IsPlayable())
{
NazaraError("Invalid sound buffer");
return;
@ -135,6 +245,14 @@ namespace Nz
alSourcePlay(m_source);
}
/*!
* \brief Sets the internal buffer
*
* \param buffer Internal buffer
*
* \remark Produces a NazaraError if buffer is invalid with NAZARA_AUDIO_SAFE defined
*/
void Sound::SetBuffer(const SoundBuffer* buffer)
{
#if NAZARA_AUDIO_SAFE
@ -158,11 +276,21 @@ namespace Nz
alSourcei(m_source, AL_BUFFER, AL_NONE);
}
/*!
* \brief Sets the playing offset for the sound
*
* \param offset Offset in the sound in milliseconds
*/
void Sound::SetPlayingOffset(UInt32 offset)
{
alSourcei(m_source, AL_SAMPLE_OFFSET, static_cast<ALint>(offset/1000.f * m_buffer->GetSampleRate()));
}
/*!
* \brief Stops the sound
*/
void Sound::Stop()
{
alSourceStop(m_source);

View File

@ -12,10 +12,23 @@
#include <stdexcept>
#include <Nazara/Audio/Debug.hpp>
///FIXME: Adapter la création
///FIXME: Adapt the creation
namespace Nz
{
/*!
* \ingroup audio
* \class Nz::SoundBuffer
* \brief Audio class that represents a buffer for sound
*
* \remark Module Audio needs to be initialized to use this class
*/
/*!
* \brief Checks whether the parameters for the buffer' sound are correct
* \return true If parameters are valid
*/
bool SoundBufferParams::IsValid() const
{
return true;
@ -31,6 +44,20 @@ namespace Nz
UInt32 sampleRate;
};
/*!
* \brief Constructs a SoundBuffer object
*
* \param format Format for the audio
* \param sampleCount Number of samples
* \param sampleRate Rate of samples
* \param samples Samples raw data
*
* \remark Produces a NazaraError if creation went wrong with NAZARA_AUDIO_SAFE defined
* \remark Produces a std::runtime_error if creation went wrong with NAZARA_AUDIO_SAFE defined
*
* \see Create
*/
SoundBuffer::SoundBuffer(AudioFormat format, unsigned int sampleCount, unsigned int sampleRate, const Int16* samples)
{
Create(format, sampleCount, sampleRate, samples);
@ -44,6 +71,12 @@ namespace Nz
#endif
}
/*!
* \brief Destructs the object and calls Destroy
*
* \see Destroy
*/
SoundBuffer::~SoundBuffer()
{
OnSoundBufferRelease(this);
@ -51,6 +84,19 @@ namespace Nz
Destroy();
}
/*!
* \brief Creates the SoundBuffer object
* \return true if creation is successful
*
* \param format Format for the audio
* \param sampleCount Number of samples
* \param sampleRate Rate of samples
* \param samples Samples raw data
*
* \remark Produces a NazaraError if creation went wrong with NAZARA_AUDIO_SAFE defined,
* this could happen if parameters are invalid or creation of OpenAL buffers failed
*/
bool SoundBuffer::Create(AudioFormat format, unsigned int sampleCount, unsigned int sampleRate, const Int16* samples)
{
Destroy();
@ -81,7 +127,7 @@ namespace Nz
}
#endif
// On vide le stack d'erreurs
// We empty the error stack
while (alGetError() != AL_NO_ERROR);
ALuint buffer;
@ -115,6 +161,10 @@ namespace Nz
return true;
}
/*!
* \brief Destroys the current sound buffer and frees resources
*/
void SoundBuffer::Destroy()
{
if (m_impl)
@ -126,6 +176,13 @@ namespace Nz
}
}
/*!
* \brief Gets the duration of the sound buffer
* \return Duration of the sound buffer in milliseconds
*
* \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined
*/
UInt32 SoundBuffer::GetDuration() const
{
#if NAZARA_AUDIO_SAFE
@ -139,6 +196,13 @@ namespace Nz
return m_impl->duration;
}
/*!
* \brief Gets the format of the sound buffer
* \return Enumeration of type AudioFormat (mono, stereo, ...)
*
* \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined
*/
AudioFormat SoundBuffer::GetFormat() const
{
#if NAZARA_AUDIO_SAFE
@ -152,6 +216,13 @@ namespace Nz
return m_impl->format;
}
/*!
* \brief Gets the internal raw samples
* \return Pointer to raw data
*
* \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined
*/
const Int16* SoundBuffer::GetSamples() const
{
#if NAZARA_AUDIO_SAFE
@ -165,6 +236,13 @@ namespace Nz
return m_impl->samples.get();
}
/*!
* \brief Gets the number of samples in the sound buffer
* \return Count of samples (number of seconds * sample rate * channel count)
*
* \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined
*/
unsigned int SoundBuffer::GetSampleCount() const
{
#if NAZARA_AUDIO_SAFE
@ -178,6 +256,13 @@ namespace Nz
return m_impl->sampleCount;
}
/*!
* \brief Gets the rates of sample in the sound buffer
* \return Rate of sample in Hertz (Hz)
*
* \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined
*/
unsigned int SoundBuffer::GetSampleRate() const
{
#if NAZARA_AUDIO_SAFE
@ -191,31 +276,75 @@ namespace Nz
return m_impl->sampleRate;
}
/*!
* \brief Checks whether the sound buffer is valid
* \return true if it is the case
*/
bool SoundBuffer::IsValid() const
{
return m_impl != nullptr;
}
/*!
* \brief Loads the sound buffer from file
* \return true if loading is successful
*
* \param filePath Path to the file
* \param params Parameters for the sound buffer
*/
bool SoundBuffer::LoadFromFile(const String& filePath, const SoundBufferParams& params)
{
return SoundBufferLoader::LoadFromFile(this, filePath, params);
}
/*!
* \brief Loads the sound buffer from memory
* \return true if loading is successful
*
* \param data Raw memory
* \param size Size of the memory
* \param params Parameters for the sound buffer
*/
bool SoundBuffer::LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params)
{
return SoundBufferLoader::LoadFromMemory(this, data, size, params);
}
/*!
* \brief Loads the sound buffer from stream
* \return true if loading is successful
*
* \param stream Stream to the sound buffer
* \param params Parameters for the sound buffer
*/
bool SoundBuffer::LoadFromStream(Stream& stream, const SoundBufferParams& params)
{
return SoundBufferLoader::LoadFromStream(this, stream, params);
}
/*!
* \brief Checks whether the format is supported by the engine
* \return true if it is the case
*
* \param format Format to check
*/
bool SoundBuffer::IsFormatSupported(AudioFormat format)
{
return Audio::IsFormatSupported(format);
}
/*!
* \brief Gets the internal OpenAL buffer
* \return The index of the OpenAL buffer
*
* \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined
*/
unsigned int SoundBuffer::GetOpenALBuffer() const
{
#ifdef NAZARA_DEBUG
@ -229,6 +358,13 @@ namespace Nz
return m_impl->buffer;
}
/*!
* \brief Initializes the libraries and managers
* \return true if initialization is successful
*
* \remark Produces a NazaraError if sub-initialization failed
*/
bool SoundBuffer::Initialize()
{
if (!SoundBufferLibrary::Initialize())
@ -246,6 +382,10 @@ namespace Nz
return true;
}
/*!
* \brief Uninitializes the libraries and managers
*/
void SoundBuffer::Uninitialize()
{
SoundBufferManager::Uninitialize();

View File

@ -11,11 +11,32 @@
namespace Nz
{
/*!
* \ingroup audio
* \class Nz::SoundEmitter
* \brief Audio class that represents a sound source, that emits sound
*
* \remark Module Audio needs to be initialized to use this class
* \remark This class is abstract
*/
/*!
* \brief Constructs a SoundEmitter object
*/
SoundEmitter::SoundEmitter()
{
alGenSources(1, &m_source);
}
/*!
* \brief Constructs a SoundEmitter object which is a copy of another
*
* \param emitter SoundEmitter to copy
*
* \remark Position and velocity are not copied
*/
SoundEmitter::SoundEmitter(const SoundEmitter& emitter)
{
alGenSources(1, &m_source);
@ -23,20 +44,35 @@ namespace Nz
SetAttenuation(emitter.GetAttenuation());
SetMinDistance(emitter.GetMinDistance());
SetPitch(emitter.GetPitch());
// Pas de copie de position ou de vitesse
// No copy for position or velocity
SetVolume(emitter.GetVolume());
}
/*!
* \brief Destructs the object
*/
SoundEmitter::~SoundEmitter()
{
alDeleteSources(1, &m_source);
}
/*!
* \brief Enables spatialization
*
* \param spatialization True if spatialization is enabled
*/
void SoundEmitter::EnableSpatialization(bool spatialization)
{
alSourcei(m_source, AL_SOURCE_RELATIVE, !spatialization);
}
/*!
* \brief Gets the attenuation
* \return Amount that your sound will drop off as by the inverse square law
*/
float SoundEmitter::GetAttenuation() const
{
ALfloat attenuation;
@ -45,6 +81,11 @@ namespace Nz
return attenuation;
}
/*!
* \brief Gets the minimum distance to hear
* \return Distance to begin to hear
*/
float SoundEmitter::GetMinDistance() const
{
ALfloat distance;
@ -53,6 +94,11 @@ namespace Nz
return distance;
}
/*!
* \brief Gets the pitch
* \return Pitch of the sound
*/
float SoundEmitter::GetPitch() const
{
ALfloat pitch;
@ -61,6 +107,11 @@ namespace Nz
return pitch;
}
/*!
* \brief Gets the position of the emitter
* \return Position of the sound
*/
Vector3f SoundEmitter::GetPosition() const
{
Vector3f position;
@ -69,6 +120,11 @@ namespace Nz
return position;
}
/*!
* \brief Gets the velocity of the emitter
* \return Velocity of the sound
*/
Vector3f SoundEmitter::GetVelocity() const
{
Vector3f velocity;
@ -77,6 +133,11 @@ namespace Nz
return velocity;
}
/*!
* \brief Gets the volume of the emitter
* \param volume Float between [0, inf) with 100.f being the default
*/
float SoundEmitter::GetVolume() const
{
ALfloat gain;
@ -85,6 +146,11 @@ namespace Nz
return gain * 100.f;
}
/*!
* \brief Checks whether the sound emitter has spatialization enabled
* \return true if it the case
*/
bool SoundEmitter::IsSpatialized() const
{
ALint relative;
@ -93,46 +159,99 @@ namespace Nz
return relative == AL_FALSE;
}
/*!
* \brief Sets the attenuation
*
* \param attenuation Amount that your sound will drop off as by the inverse square law
*/
void SoundEmitter::SetAttenuation(float attenuation)
{
alSourcef(m_source, AL_ROLLOFF_FACTOR, attenuation);
}
/*!
* \brief Sets the minimum distance to hear
*
* \param minDistance to begin to hear
*/
void SoundEmitter::SetMinDistance(float minDistance)
{
alSourcef(m_source, AL_REFERENCE_DISTANCE, minDistance);
}
/*!
* \brief Sets the pitch
*
* \param pitch of the sound
*/
void SoundEmitter::SetPitch(float pitch)
{
alSourcef(m_source, AL_PITCH, pitch);
}
/*!
* \brief Sets the position of the emitter
*
* \param position Position of the sound
*/
void SoundEmitter::SetPosition(const Vector3f& position)
{
alSourcefv(m_source, AL_POSITION, position);
}
/*!
* \brief Sets the position of the emitter
*
* \param position Position of the sound with (x, y, z)
*/
void SoundEmitter::SetPosition(float x, float y, float z)
{
alSource3f(m_source, AL_POSITION, x, y, z);
}
/*!
* \brief Sets the velocity of the emitter
*
* \param velocity Velocity of the sound
*/
void SoundEmitter::SetVelocity(const Vector3f& velocity)
{
alSourcefv(m_source, AL_VELOCITY, velocity);
}
/*!
* \brief Sets the velocity of the emitter
*
* \param velocity Velocity with (velX, velY, velZ)
*/
void SoundEmitter::SetVelocity(float velX, float velY, float velZ)
{
alSource3f(m_source, AL_VELOCITY, velX, velY, velZ);
}
/*!
* \brief Sets the volume of the emitter
*
* \param volume Float between [0, inf) with 100.f being the default
*/
void SoundEmitter::SetVolume(float volume)
{
alSourcef(m_source, AL_GAIN, volume * 0.01f);
}
/*!
* \brief Gets the status of the sound emitter
* \return Enumeration of type SoundStatus (Playing, Stopped, ...)
*/
SoundStatus SoundEmitter::GetInternalStatus() const
{
ALint state;

View File

@ -6,5 +6,13 @@
namespace Nz
{
/*!
* \ingroup audio
* \class Nz::SoundStream
* \brief Audio class that represents a sound stream
*
* \remark This class is abstract
*/
SoundStream::~SoundStream() = default;
}

View File

@ -0,0 +1,19 @@
#include <Nazara/Audio/Algorithm.hpp>
#include <Catch/catch.hpp>
#include <array>
TEST_CASE("MixToMono", "[AUDIO][ALGORITHM]")
{
SECTION("Mix two channels together")
{
std::array<int, 4> input{ 1, 3, 5, 3 };
std::array<int, 2> output{ 0, 0 };
// Two channels and two frames !
Nz::MixToMono(input.data(), output.data(), 2, 2);
std::array<int, 2> theoric{ 2, 4 }; // It's the mean of the two channels
REQUIRE(output == theoric);
}
}

View File

@ -0,0 +1,49 @@
#include <Nazara/Audio/Music.hpp>
#include <Catch/catch.hpp>
#include <Nazara/Audio/Audio.hpp>
#include <Nazara/Core/Thread.hpp>
SCENARIO("Music", "[AUDIO][MUSIC]")
{
GIVEN("A music")
{
Nz::Music music;
WHEN("We load our music")
{
REQUIRE(music.OpenFromFile("resources/Engine/Audio/The_Brabanconne.ogg"));
THEN("We can ask the informations of the file")
{
REQUIRE(music.GetDuration() <= 64000); // 1 min 03 = 63s = 63000ms
REQUIRE(music.GetDuration() >= 63000);
REQUIRE(music.GetFormat() == Nz::AudioFormat_Stereo);
REQUIRE(music.GetPlayingOffset() == 0);
REQUIRE(music.GetSampleCount() <= 5644800); // 64s * 44100 Hz * 2 (stereo)
REQUIRE(music.GetSampleCount() >= 5556600); // 63s * 44100 Hz * 2 (stereo)
REQUIRE(music.GetSampleRate() == 44100 /* Hz */);
REQUIRE(music.GetStatus() == Nz::SoundStatus_Stopped);
REQUIRE(music.IsLooping() == false);
}
THEN("We can play it and get the time offset")
{
Nz::Audio::SetGlobalVolume(0.f);
music.Play();
Nz::Thread::Sleep(1000);
REQUIRE(music.GetPlayingOffset() >= 950);
Nz::Thread::Sleep(200);
REQUIRE(music.GetPlayingOffset() <= 1300);
music.Pause();
REQUIRE(music.GetStatus() == Nz::SoundStatus_Paused);
music.SetPlayingOffset(3500);
REQUIRE(music.GetPlayingOffset() >= 3500);
Nz::Audio::SetGlobalVolume(100.f);
}
}
}
}

View File

@ -0,0 +1,44 @@
#include <Nazara/Audio/Sound.hpp>
#include <Catch/catch.hpp>
#include <Nazara/Audio/Audio.hpp>
#include <Nazara/Core/Thread.hpp>
SCENARIO("Sound", "[AUDIO][SOUND]")
{
GIVEN("A sound")
{
Nz::Sound sound;
WHEN("We load our sound")
{
REQUIRE(sound.LoadFromFile("resources/Engine/Audio/Cat.flac"));
THEN("We can ask the informations of the file")
{
REQUIRE(sound.GetDuration() <= 8500); // 8s = 8000ms
REQUIRE(sound.GetDuration() >= 8000);
REQUIRE(sound.GetStatus() == Nz::SoundStatus_Stopped);
REQUIRE(sound.IsLooping() == false);
}
THEN("We can play it and get the time offset")
{
Nz::Audio::SetGlobalVolume(0.f);
sound.Play();
Nz::Thread::Sleep(1000);
REQUIRE(sound.GetPlayingOffset() >= 950);
Nz::Thread::Sleep(200);
REQUIRE(sound.GetPlayingOffset() <= 1300);
sound.Pause();
REQUIRE(sound.GetStatus() == Nz::SoundStatus_Paused);
sound.SetPlayingOffset(3500);
REQUIRE(sound.GetPlayingOffset() >= 3500);
Nz::Audio::SetGlobalVolume(100.f);
}
}
}
}

View File

@ -0,0 +1,21 @@
#include <Nazara/Audio/SoundBuffer.hpp>
#include <Catch/catch.hpp>
SCENARIO("SoundBuffer", "[AUDIO][SOUNDBUFFER]")
{
GIVEN("A sound buffer")
{
Nz::SoundBuffer soundBuffer;
WHEN("We load our sound")
{
REQUIRE(soundBuffer.LoadFromFile("resources/Engine/Audio/Cat.flac"));
THEN("We can ask the informations of the file")
{
REQUIRE(soundBuffer.GetDuration() <= 8500); // 8s = 8000ms
REQUIRE(soundBuffer.GetDuration() >= 8000);
}
}
}
}

View File

@ -0,0 +1,41 @@
#include <Nazara/Audio/Sound.hpp>
#include <Catch/catch.hpp>
#include <Nazara/Core/Thread.hpp>
SCENARIO("SoundEmitter", "[AUDIO][SOUNDEMITTER]")
{
GIVEN("A sound emitter")
{
Nz::Sound sound;
WHEN("We load our sound")
{
REQUIRE(sound.LoadFromFile("resources/Engine/Audio/Cat.flac"));
THEN("We can ask information about position and velocity")
{
sound.EnableSpatialization(true);
sound.SetPosition(Nz::Vector3f::Zero());
sound.SetVelocity(Nz::Vector3f::UnitX());
REQUIRE(sound.IsSpatialized());
REQUIRE(sound.GetPosition() == Nz::Vector3f::Zero());
REQUIRE(sound.GetVelocity() == Nz::Vector3f::UnitX());
}
THEN("We can ask information about attenuation, pitch, ...")
{
sound.SetAttenuation(0.4f);
sound.SetMinDistance(40.f);
sound.SetPitch(0.8f);
sound.SetVolume(50.f);
REQUIRE(Approx(sound.GetAttenuation()) == 0.4f);
REQUIRE(Approx(sound.GetMinDistance()) == 40.f);
REQUIRE(Approx(sound.GetPitch()) == 0.8f);
REQUIRE(Approx(sound.GetVolume()) == 50.f);
}
}
}
}

View File

@ -0,0 +1 @@
6993cbcca9ac596667135cb0f30bea4841178d3b

View File

@ -0,0 +1 @@
94b2c47c9143adbac0fb7e81df5cc87f969f7150

View File

@ -0,0 +1,54 @@
The_Brabanconne.ogg
https://en.wikipedia.org/wiki/File:The_Brabanconne.ogg
Original file:
The_Brabanconne.ogg (Ogg Vorbis sound file, length 1 min 3 s, 378 kbps)
Summary:
Description: The Belgian national anthem (instrumental version) performed by the United States Navy Band. Direct link is at http://www.navyband.navy.mil/anthems/ANTHEMS/Belgium.mp3.
Date: 19 October 2004
Source: http://www.navyband.navy.mil/anthems/national_anthems.htm
Author: United States Navy Band (rendition), uploaded to Wikimedia by Keith Lehwald
Licencing:
This file is a work of a sailor or employee of the U.S. Navy, taken or made as part of that person's official duties. As a work of the U.S. federal government, the image is in the public domain.
This file has been identified as being free of known restrictions under copyright law, including all related and neighboring rights.
-------------------------------------------------------------------------------------------------
Cat.flac:
http://www.freesound.org/people/EARR/sounds/148013/
Original file:
148013__earr__angry-cat.flac (Flac sound file, length 8 s, 96000 Hz, 24 bit depth)
Author:
EARR
Description:
Slightly angry cat. She is a beautiful Siamese cat called Agostina. She is angry for the recording because i pressed his tail.
Information about the recording and equipment:
-Location: Living room.
-Type of acoustic environment: Small, diffuse, moderately reflective.
-Distance from sound source to microphones: Approx a few centimeters.
-Miking technique: Jecklin disk.
-Microphones: 2 Brüel & Kjaer type 4190 capsules with type 2669L head amplifier.
-Microphone preamps: Modified Brüel & Kjaer type 5935L.
-ADC: Echo Audiofire 4. (line inputs 3 & 4).
-Recorder: Echo Audiofire 4 and Dell D630C running Samplitude 10.
Eq: Compensation only for the response of the microphones (In this case for flat response at 60º. See Brüel & Kjaer type 4190 datasheet).
No reverb, no compression, no fx.
Licencing:
Creative commons