Documentation for module: Audio
Former-commit-id: acb9e00a7af8bf1c36f42b45fe7e7df99e03c0f9
This commit is contained in:
parent
ea920d2e64
commit
8336c05522
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
6993cbcca9ac596667135cb0f30bea4841178d3b
|
||||
|
|
@ -0,0 +1 @@
|
|||
94b2c47c9143adbac0fb7e81df5cc87f969f7150
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue