Documentation for module: Audio

Former-commit-id: 4546f9db5579c219d708f87b7062104d24ec6da2
This commit is contained in:
Gawaboumga
2016-05-30 13:36:52 +02:00
parent 3e4051d82c
commit 406bebe717
23 changed files with 1110 additions and 56 deletions

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,19 +49,36 @@ 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;
alGetListenerf(AL_GAIN, &gain);
return gain*100.f;
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à initiali
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);
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 initiali
// 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);
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;
}