Switch from Nz prefix to namespace Nz
What a huge commit Former-commit-id: 38ac5eebf70adc1180f571f6006192d28fb99897
This commit is contained in:
@@ -14,233 +14,236 @@
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
nzAudioFormat NzAudio::GetAudioFormat(unsigned int channelCount)
|
||||
namespace Nz
|
||||
{
|
||||
switch (channelCount)
|
||||
AudioFormat Audio::GetAudioFormat(unsigned int channelCount)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
return static_cast<nzAudioFormat>(channelCount);
|
||||
switch (channelCount)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
return static_cast<AudioFormat>(channelCount);
|
||||
|
||||
default:
|
||||
NazaraError("Invalid channel count: " + NzString::Number(channelCount));
|
||||
return nzAudioFormat_Unknown;
|
||||
default:
|
||||
NazaraError("Invalid channel count: " + String::Number(channelCount));
|
||||
return AudioFormat_Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float NzAudio::GetDopplerFactor()
|
||||
{
|
||||
return alGetFloat(AL_DOPPLER_FACTOR);
|
||||
}
|
||||
|
||||
float NzAudio::GetGlobalVolume()
|
||||
{
|
||||
ALfloat gain = 0.f;
|
||||
alGetListenerf(AL_GAIN, &gain);
|
||||
|
||||
return gain*100.f;
|
||||
}
|
||||
|
||||
NzVector3f NzAudio::GetListenerDirection()
|
||||
{
|
||||
ALfloat orientation[6];
|
||||
alGetListenerfv(AL_ORIENTATION, orientation);
|
||||
|
||||
return NzVector3f(orientation[0], orientation[1], orientation[2]);
|
||||
}
|
||||
|
||||
NzVector3f NzAudio::GetListenerPosition()
|
||||
{
|
||||
NzVector3f position;
|
||||
alGetListenerfv(AL_POSITION, position);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
NzQuaternionf NzAudio::GetListenerRotation()
|
||||
{
|
||||
ALfloat orientation[6];
|
||||
alGetListenerfv(AL_ORIENTATION, orientation);
|
||||
|
||||
NzVector3f forward(orientation[0], orientation[1], orientation[2]);
|
||||
|
||||
return NzQuaternionf::RotationBetween(NzVector3f::Forward(), forward);
|
||||
}
|
||||
|
||||
NzVector3f NzAudio::GetListenerVelocity()
|
||||
{
|
||||
NzVector3f velocity;
|
||||
alGetListenerfv(AL_VELOCITY, velocity);
|
||||
|
||||
return velocity;
|
||||
}
|
||||
|
||||
float NzAudio::GetSpeedOfSound()
|
||||
{
|
||||
return alGetFloat(AL_SPEED_OF_SOUND);
|
||||
}
|
||||
|
||||
bool NzAudio::Initialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter > 0)
|
||||
float Audio::GetDopplerFactor()
|
||||
{
|
||||
return alGetFloat(AL_DOPPLER_FACTOR);
|
||||
}
|
||||
|
||||
float Audio::GetGlobalVolume()
|
||||
{
|
||||
ALfloat gain = 0.f;
|
||||
alGetListenerf(AL_GAIN, &gain);
|
||||
|
||||
return gain*100.f;
|
||||
}
|
||||
|
||||
Vector3f Audio::GetListenerDirection()
|
||||
{
|
||||
ALfloat orientation[6];
|
||||
alGetListenerfv(AL_ORIENTATION, orientation);
|
||||
|
||||
return Vector3f(orientation[0], orientation[1], orientation[2]);
|
||||
}
|
||||
|
||||
Vector3f Audio::GetListenerPosition()
|
||||
{
|
||||
Vector3f position;
|
||||
alGetListenerfv(AL_POSITION, position);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
Quaternionf Audio::GetListenerRotation()
|
||||
{
|
||||
ALfloat orientation[6];
|
||||
alGetListenerfv(AL_ORIENTATION, orientation);
|
||||
|
||||
Vector3f forward(orientation[0], orientation[1], orientation[2]);
|
||||
|
||||
return Quaternionf::RotationBetween(Vector3f::Forward(), forward);
|
||||
}
|
||||
|
||||
Vector3f Audio::GetListenerVelocity()
|
||||
{
|
||||
Vector3f velocity;
|
||||
alGetListenerfv(AL_VELOCITY, velocity);
|
||||
|
||||
return velocity;
|
||||
}
|
||||
|
||||
float Audio::GetSpeedOfSound()
|
||||
{
|
||||
return alGetFloat(AL_SPEED_OF_SOUND);
|
||||
}
|
||||
|
||||
bool Audio::Initialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter > 0)
|
||||
{
|
||||
s_moduleReferenceCounter++;
|
||||
return true; // Déjà initialisé
|
||||
}
|
||||
|
||||
// Initialisation des dépendances
|
||||
if (!Core::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize core module");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_moduleReferenceCounter++;
|
||||
return true; // Déjà initialisé
|
||||
|
||||
// Initialisation du module
|
||||
CallOnExit onExit(Audio::Uninitialize);
|
||||
|
||||
// Initialisation d'OpenAL
|
||||
if (!OpenAL::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize OpenAL");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SoundBuffer::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize sound buffers");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Définition de l'orientation par défaut
|
||||
SetListenerDirection(Vector3f::Forward());
|
||||
|
||||
// Loaders
|
||||
Loaders::Register_sndfile();
|
||||
|
||||
onExit.Reset();
|
||||
|
||||
NazaraNotice("Initialized: Audio module");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Initialisation des dépendances
|
||||
if (!NzCore::Initialize())
|
||||
bool Audio::IsFormatSupported(AudioFormat format)
|
||||
{
|
||||
NazaraError("Failed to initialize core module");
|
||||
return false;
|
||||
if (format == AudioFormat_Unknown)
|
||||
return false;
|
||||
|
||||
return OpenAL::AudioFormat[format] != 0;
|
||||
}
|
||||
|
||||
s_moduleReferenceCounter++;
|
||||
|
||||
// Initialisation du module
|
||||
NzCallOnExit onExit(NzAudio::Uninitialize);
|
||||
|
||||
// Initialisation d'OpenAL
|
||||
if (!NzOpenAL::Initialize())
|
||||
bool Audio::IsInitialized()
|
||||
{
|
||||
NazaraError("Failed to initialize OpenAL");
|
||||
return false;
|
||||
return s_moduleReferenceCounter != 0;
|
||||
}
|
||||
|
||||
if (!NzSoundBuffer::Initialize())
|
||||
void Audio::SetDopplerFactor(float dopplerFactor)
|
||||
{
|
||||
NazaraError("Failed to initialize sound buffers");
|
||||
return false;
|
||||
alDopplerFactor(dopplerFactor);
|
||||
}
|
||||
|
||||
// Définition de l'orientation par défaut
|
||||
SetListenerDirection(NzVector3f::Forward());
|
||||
|
||||
// Loaders
|
||||
NzLoaders_sndfile_Register();
|
||||
|
||||
onExit.Reset();
|
||||
|
||||
NazaraNotice("Initialized: Audio module");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzAudio::IsFormatSupported(nzAudioFormat format)
|
||||
{
|
||||
if (format == nzAudioFormat_Unknown)
|
||||
return false;
|
||||
|
||||
return NzOpenAL::AudioFormat[format] != 0;
|
||||
}
|
||||
|
||||
bool NzAudio::IsInitialized()
|
||||
{
|
||||
return s_moduleReferenceCounter != 0;
|
||||
}
|
||||
|
||||
void NzAudio::SetDopplerFactor(float dopplerFactor)
|
||||
{
|
||||
alDopplerFactor(dopplerFactor);
|
||||
}
|
||||
|
||||
void NzAudio::SetGlobalVolume(float volume)
|
||||
{
|
||||
alListenerf(AL_GAIN, volume*0.01f);
|
||||
}
|
||||
|
||||
void NzAudio::SetListenerDirection(const NzVector3f& direction)
|
||||
{
|
||||
NzVector3f up = NzVector3f::Up();
|
||||
|
||||
ALfloat orientation[6] =
|
||||
void Audio::SetGlobalVolume(float volume)
|
||||
{
|
||||
direction.x, direction.y, direction.z,
|
||||
up.x, up.y, up.z
|
||||
};
|
||||
|
||||
alListenerfv(AL_ORIENTATION, orientation);
|
||||
}
|
||||
|
||||
void NzAudio::SetListenerDirection(float dirX, float dirY, float dirZ)
|
||||
{
|
||||
NzVector3f up = NzVector3f::Up();
|
||||
|
||||
ALfloat orientation[6] =
|
||||
{
|
||||
dirX, dirY, dirZ,
|
||||
up.x, up.y, up.z
|
||||
};
|
||||
|
||||
alListenerfv(AL_ORIENTATION, orientation);
|
||||
}
|
||||
|
||||
void NzAudio::SetListenerPosition(const NzVector3f& position)
|
||||
{
|
||||
alListenerfv(AL_POSITION, position);
|
||||
}
|
||||
|
||||
void NzAudio::SetListenerPosition(float x, float y, float z)
|
||||
{
|
||||
alListener3f(AL_POSITION, x, y, z);
|
||||
}
|
||||
|
||||
void NzAudio::SetListenerRotation(const NzQuaternionf& rotation)
|
||||
{
|
||||
NzVector3f forward = rotation * NzVector3f::Forward();
|
||||
NzVector3f up = NzVector3f::Up();
|
||||
|
||||
ALfloat orientation[6] =
|
||||
{
|
||||
forward.x, forward.y, forward.z,
|
||||
up.x, up.y, up.z
|
||||
};
|
||||
|
||||
alListenerfv(AL_ORIENTATION, orientation);
|
||||
}
|
||||
|
||||
void NzAudio::SetListenerVelocity(const NzVector3f& velocity)
|
||||
{
|
||||
alListenerfv(AL_VELOCITY, velocity);
|
||||
}
|
||||
|
||||
void NzAudio::SetListenerVelocity(float velX, float velY, float velZ)
|
||||
{
|
||||
alListener3f(AL_VELOCITY, velX, velY, velZ);
|
||||
}
|
||||
|
||||
void NzAudio::SetSpeedOfSound(float speed)
|
||||
{
|
||||
alSpeedOfSound(speed);
|
||||
}
|
||||
|
||||
void NzAudio::Uninitialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter != 1)
|
||||
{
|
||||
// Le module est soit encore utilisé, soit pas initialisé
|
||||
if (s_moduleReferenceCounter > 1)
|
||||
s_moduleReferenceCounter--;
|
||||
|
||||
return;
|
||||
alListenerf(AL_GAIN, volume*0.01f);
|
||||
}
|
||||
|
||||
// Libération du module
|
||||
s_moduleReferenceCounter = 0;
|
||||
void Audio::SetListenerDirection(const Vector3f& direction)
|
||||
{
|
||||
Vector3f up = Vector3f::Up();
|
||||
|
||||
// Loaders
|
||||
NzLoaders_sndfile_Unregister();
|
||||
ALfloat orientation[6] =
|
||||
{
|
||||
direction.x, direction.y, direction.z,
|
||||
up.x, up.y, up.z
|
||||
};
|
||||
|
||||
NzSoundBuffer::Uninitialize();
|
||||
NzOpenAL::Uninitialize();
|
||||
alListenerfv(AL_ORIENTATION, orientation);
|
||||
}
|
||||
|
||||
NazaraNotice("Uninitialized: Audio module");
|
||||
void Audio::SetListenerDirection(float dirX, float dirY, float dirZ)
|
||||
{
|
||||
Vector3f up = Vector3f::Up();
|
||||
|
||||
// Libération des dépendances
|
||||
NzCore::Uninitialize();
|
||||
ALfloat orientation[6] =
|
||||
{
|
||||
dirX, dirY, dirZ,
|
||||
up.x, up.y, up.z
|
||||
};
|
||||
|
||||
alListenerfv(AL_ORIENTATION, orientation);
|
||||
}
|
||||
|
||||
void Audio::SetListenerPosition(const Vector3f& position)
|
||||
{
|
||||
alListenerfv(AL_POSITION, position);
|
||||
}
|
||||
|
||||
void Audio::SetListenerPosition(float x, float y, float z)
|
||||
{
|
||||
alListener3f(AL_POSITION, x, y, z);
|
||||
}
|
||||
|
||||
void Audio::SetListenerRotation(const Quaternionf& rotation)
|
||||
{
|
||||
Vector3f forward = rotation * Vector3f::Forward();
|
||||
Vector3f up = Vector3f::Up();
|
||||
|
||||
ALfloat orientation[6] =
|
||||
{
|
||||
forward.x, forward.y, forward.z,
|
||||
up.x, up.y, up.z
|
||||
};
|
||||
|
||||
alListenerfv(AL_ORIENTATION, orientation);
|
||||
}
|
||||
|
||||
void Audio::SetListenerVelocity(const Vector3f& velocity)
|
||||
{
|
||||
alListenerfv(AL_VELOCITY, velocity);
|
||||
}
|
||||
|
||||
void Audio::SetListenerVelocity(float velX, float velY, float velZ)
|
||||
{
|
||||
alListener3f(AL_VELOCITY, velX, velY, velZ);
|
||||
}
|
||||
|
||||
void Audio::SetSpeedOfSound(float speed)
|
||||
{
|
||||
alSpeedOfSound(speed);
|
||||
}
|
||||
|
||||
void Audio::Uninitialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter != 1)
|
||||
{
|
||||
// Le module est soit encore utilisé, soit pas initialisé
|
||||
if (s_moduleReferenceCounter > 1)
|
||||
s_moduleReferenceCounter--;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Libération du module
|
||||
s_moduleReferenceCounter = 0;
|
||||
|
||||
// Loaders
|
||||
Loaders::Unregister_sndfile();
|
||||
|
||||
SoundBuffer::Uninitialize();
|
||||
OpenAL::Uninitialize();
|
||||
|
||||
NazaraNotice("Uninitialized: Audio module");
|
||||
|
||||
// Libération des dépendances
|
||||
Core::Uninitialize();
|
||||
}
|
||||
|
||||
unsigned int Audio::s_moduleReferenceCounter = 0;
|
||||
}
|
||||
|
||||
unsigned int NzAudio::s_moduleReferenceCounter = 0;
|
||||
|
||||
@@ -21,373 +21,379 @@
|
||||
#include <sndfile/sndfile.h>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace
|
||||
namespace Nz
|
||||
{
|
||||
sf_count_t GetSize(void* user_data)
|
||||
namespace Detail
|
||||
{
|
||||
NzInputStream* stream = static_cast<NzInputStream*>(user_data);
|
||||
return stream->GetSize();
|
||||
}
|
||||
|
||||
sf_count_t Read(void* ptr, sf_count_t count, void* user_data)
|
||||
{
|
||||
NzInputStream* stream = static_cast<NzInputStream*>(user_data);
|
||||
return static_cast<sf_count_t>(stream->Read(ptr, static_cast<std::size_t>(count)));
|
||||
}
|
||||
|
||||
sf_count_t Seek(sf_count_t offset, int whence, void* user_data)
|
||||
{
|
||||
NzInputStream* stream = static_cast<NzInputStream*>(user_data);
|
||||
switch (whence)
|
||||
sf_count_t GetSize(void* user_data)
|
||||
{
|
||||
case SEEK_CUR:
|
||||
stream->Read(nullptr, static_cast<std::size_t>(offset));
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
stream->SetCursorPos(stream->GetSize() + offset); // L'offset est négatif ici
|
||||
break;
|
||||
|
||||
case SEEK_SET:
|
||||
stream->SetCursorPos(offset);
|
||||
break;
|
||||
|
||||
default:
|
||||
NazaraInternalError("Seek mode not handled");
|
||||
InputStream* stream = static_cast<InputStream*>(user_data);
|
||||
return stream->GetSize();
|
||||
}
|
||||
|
||||
return stream->GetCursorPos();
|
||||
}
|
||||
sf_count_t Read(void* ptr, sf_count_t count, void* user_data)
|
||||
{
|
||||
InputStream* stream = static_cast<InputStream*>(user_data);
|
||||
return static_cast<sf_count_t>(stream->Read(ptr, static_cast<std::size_t>(count)));
|
||||
}
|
||||
|
||||
sf_count_t Tell(void* user_data)
|
||||
{
|
||||
NzInputStream* stream = static_cast<NzInputStream*>(user_data);
|
||||
return stream->GetCursorPos();
|
||||
}
|
||||
|
||||
static SF_VIRTUAL_IO callbacks = {GetSize, Seek, Read, nullptr, Tell};
|
||||
|
||||
class sndfileStream : public NzSoundStream
|
||||
{
|
||||
public:
|
||||
sndfileStream() :
|
||||
m_handle(nullptr)
|
||||
sf_count_t Seek(sf_count_t offset, int whence, void* user_data)
|
||||
{
|
||||
InputStream* stream = static_cast<InputStream*>(user_data);
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_CUR:
|
||||
stream->Read(nullptr, static_cast<std::size_t>(offset));
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
stream->SetCursorPos(stream->GetSize() + offset); // L'offset est négatif ici
|
||||
break;
|
||||
|
||||
case SEEK_SET:
|
||||
stream->SetCursorPos(offset);
|
||||
break;
|
||||
|
||||
default:
|
||||
NazaraInternalError("Seek mode not handled");
|
||||
}
|
||||
|
||||
~sndfileStream()
|
||||
{
|
||||
if (m_handle)
|
||||
sf_close(m_handle);
|
||||
}
|
||||
return stream->GetCursorPos();
|
||||
}
|
||||
|
||||
nzUInt32 GetDuration() const override
|
||||
{
|
||||
return m_duration;
|
||||
}
|
||||
sf_count_t Tell(void* user_data)
|
||||
{
|
||||
InputStream* stream = static_cast<InputStream*>(user_data);
|
||||
return stream->GetCursorPos();
|
||||
}
|
||||
|
||||
nzAudioFormat GetFormat() const override
|
||||
{
|
||||
// Nous avons besoin du nombre de canaux d'origine pour convertir en mono, nous trichons donc un peu...
|
||||
if (m_mixToMono)
|
||||
return nzAudioFormat_Mono;
|
||||
else
|
||||
return m_format;
|
||||
}
|
||||
static SF_VIRTUAL_IO callbacks = {GetSize, Seek, Read, nullptr, Tell};
|
||||
|
||||
nzUInt32 GetSampleCount() const override
|
||||
{
|
||||
return m_sampleCount;
|
||||
}
|
||||
|
||||
nzUInt32 GetSampleRate() const override
|
||||
{
|
||||
return m_sampleRate;
|
||||
}
|
||||
|
||||
bool Open(const NzString& filePath, bool forceMono)
|
||||
{
|
||||
// Nous devons gérer nous-même le flux car il doit rester ouvert après le passage du loader
|
||||
// (les flux automatiquement ouverts par le ResourceLoader étant fermés après celui-ci)
|
||||
std::unique_ptr<NzFile> file(new NzFile);
|
||||
if (!file->Open(filePath, nzOpenMode_ReadOnly))
|
||||
class sndfileStream : public SoundStream
|
||||
{
|
||||
public:
|
||||
sndfileStream() :
|
||||
m_handle(nullptr)
|
||||
{
|
||||
NazaraError("Failed to open stream from file: " + NzError::GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ownedStream = std::move(file);
|
||||
return Open(*m_ownedStream, forceMono);
|
||||
}
|
||||
|
||||
bool Open(const void* data, std::size_t size, bool forceMono)
|
||||
{
|
||||
m_ownedStream.reset(new NzMemoryStream(data, size));
|
||||
return Open(*m_ownedStream, forceMono);
|
||||
}
|
||||
|
||||
bool Open(NzInputStream& stream, bool forceMono)
|
||||
{
|
||||
SF_INFO infos;
|
||||
infos.format = 0; // Format inconnu
|
||||
|
||||
m_handle = sf_open_virtual(&callbacks, SFM_READ, &infos, &stream);
|
||||
if (!m_handle)
|
||||
~sndfileStream()
|
||||
{
|
||||
NazaraError("Failed to open sound: " + NzString(sf_strerror(m_handle)));
|
||||
return false;
|
||||
if (m_handle)
|
||||
sf_close(m_handle);
|
||||
}
|
||||
|
||||
// Un peu de RRID
|
||||
NzCallOnExit onExit([this]
|
||||
UInt32 GetDuration() const override
|
||||
{
|
||||
sf_close(m_handle);
|
||||
m_handle = nullptr;
|
||||
});
|
||||
|
||||
m_format = NzAudio::GetAudioFormat(infos.channels);
|
||||
if (m_format == nzAudioFormat_Unknown)
|
||||
{
|
||||
NazaraError("Channel count not handled");
|
||||
return false;
|
||||
return m_duration;
|
||||
}
|
||||
|
||||
m_sampleCount = static_cast<nzUInt32>(infos.channels*infos.frames);
|
||||
m_sampleRate = infos.samplerate;
|
||||
|
||||
// Durée de la musique (s) = samples / channels*rate
|
||||
m_duration = static_cast<nzUInt32>(1000ULL*m_sampleCount / (m_format*m_sampleRate));
|
||||
|
||||
// https://github.com/LaurentGomila/SFML/issues/271
|
||||
// http://www.mega-nerd.com/libsndfile/command.html#SFC_SET_SCALE_FLOAT_INT_READ
|
||||
///FIXME: Seulement le Vorbis ?
|
||||
if (infos.format & SF_FORMAT_VORBIS)
|
||||
sf_command(m_handle, SFC_SET_SCALE_FLOAT_INT_READ, nullptr, SF_TRUE);
|
||||
|
||||
// On mixera en mono lors de la lecture
|
||||
if (forceMono && m_format != nzAudioFormat_Mono)
|
||||
AudioFormat GetFormat() const override
|
||||
{
|
||||
m_mixToMono = true;
|
||||
m_sampleCount = static_cast<nzUInt32>(infos.frames);
|
||||
// Nous avons besoin du nombre de canaux d'origine pour convertir en mono, nous trichons donc un peu...
|
||||
if (m_mixToMono)
|
||||
return AudioFormat_Mono;
|
||||
else
|
||||
return m_format;
|
||||
}
|
||||
else
|
||||
m_mixToMono = false;
|
||||
|
||||
onExit.Reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int Read(void* buffer, unsigned int sampleCount)
|
||||
{
|
||||
// Si la musique a été demandée en mono, nous devons la convertir à la volée lors de la lecture
|
||||
if (m_mixToMono)
|
||||
UInt32 GetSampleCount() const override
|
||||
{
|
||||
// On garde un buffer sur le côté pour éviter la réallocation
|
||||
m_mixBuffer.resize(m_format * sampleCount);
|
||||
sf_count_t readSampleCount = sf_read_short(m_handle, m_mixBuffer.data(), m_format * sampleCount);
|
||||
NzMixToMono(m_mixBuffer.data(), static_cast<nzInt16*>(buffer), m_format, sampleCount);
|
||||
|
||||
return static_cast<unsigned int>(readSampleCount / m_format);
|
||||
return m_sampleCount;
|
||||
}
|
||||
else
|
||||
return static_cast<unsigned int>(sf_read_short(m_handle, static_cast<nzInt16*>(buffer), sampleCount));
|
||||
}
|
||||
|
||||
void Seek(nzUInt32 offset) override
|
||||
{
|
||||
sf_seek(m_handle, offset*m_sampleRate / 1000, SEEK_SET);
|
||||
}
|
||||
UInt32 GetSampleRate() const override
|
||||
{
|
||||
return m_sampleRate;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<nzInt16> m_mixBuffer;
|
||||
std::unique_ptr<NzInputStream> m_ownedStream;
|
||||
nzAudioFormat m_format;
|
||||
SNDFILE* m_handle;
|
||||
bool m_mixToMono;
|
||||
nzUInt32 m_duration;
|
||||
unsigned int m_sampleCount;
|
||||
unsigned int m_sampleRate;
|
||||
};
|
||||
bool Open(const String& filePath, bool forceMono)
|
||||
{
|
||||
// Nous devons gérer nous-même le flux car il doit rester ouvert après le passage du loader
|
||||
// (les flux automatiquement ouverts par le ResourceLoader étant fermés après celui-ci)
|
||||
std::unique_ptr<File> file(new File);
|
||||
if (!file->Open(filePath, OpenMode_ReadOnly))
|
||||
{
|
||||
NazaraError("Failed to open stream from file: " + Error::GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsSupported(const NzString& extension)
|
||||
{
|
||||
static std::set<NzString> supportedExtensions = {
|
||||
"aiff", "au", "avr", "caf", "flac", "htk", "ircam", "mat4", "mat5", "mpc2k",
|
||||
"nist","ogg", "pvf", "raw", "rf64", "sd2", "sds", "svx", "voc", "w64", "wav", "wve"
|
||||
m_ownedStream = std::move(file);
|
||||
return Open(*m_ownedStream, forceMono);
|
||||
}
|
||||
|
||||
bool Open(const void* data, std::size_t size, bool forceMono)
|
||||
{
|
||||
m_ownedStream.reset(new MemoryStream(data, size));
|
||||
return Open(*m_ownedStream, forceMono);
|
||||
}
|
||||
|
||||
bool Open(InputStream& stream, bool forceMono)
|
||||
{
|
||||
SF_INFO infos;
|
||||
infos.format = 0; // Format inconnu
|
||||
|
||||
m_handle = sf_open_virtual(&callbacks, SFM_READ, &infos, &stream);
|
||||
if (!m_handle)
|
||||
{
|
||||
NazaraError("Failed to open sound: " + String(sf_strerror(m_handle)));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Un peu de RRID
|
||||
CallOnExit onExit([this]
|
||||
{
|
||||
sf_close(m_handle);
|
||||
m_handle = nullptr;
|
||||
});
|
||||
|
||||
m_format = Audio::GetAudioFormat(infos.channels);
|
||||
if (m_format == AudioFormat_Unknown)
|
||||
{
|
||||
NazaraError("Channel count not handled");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_sampleCount = static_cast<UInt32>(infos.channels*infos.frames);
|
||||
m_sampleRate = infos.samplerate;
|
||||
|
||||
// Durée de la musique (s) = samples / channels*rate
|
||||
m_duration = static_cast<UInt32>(1000ULL*m_sampleCount / (m_format*m_sampleRate));
|
||||
|
||||
// https://github.com/LaurentGomila/SFML/issues/271
|
||||
// http://www.mega-nerd.com/libsndfile/command.html#SFC_SET_SCALE_FLOAT_INT_READ
|
||||
///FIXME: Seulement le Vorbis ?
|
||||
if (infos.format & SF_FORMAT_VORBIS)
|
||||
sf_command(m_handle, SFC_SET_SCALE_FLOAT_INT_READ, nullptr, SF_TRUE);
|
||||
|
||||
// On mixera en mono lors de la lecture
|
||||
if (forceMono && m_format != AudioFormat_Mono)
|
||||
{
|
||||
m_mixToMono = true;
|
||||
m_sampleCount = static_cast<UInt32>(infos.frames);
|
||||
}
|
||||
else
|
||||
m_mixToMono = false;
|
||||
|
||||
onExit.Reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int Read(void* buffer, unsigned int sampleCount)
|
||||
{
|
||||
// Si la musique a été demandée en mono, nous devons la convertir à la volée lors de la lecture
|
||||
if (m_mixToMono)
|
||||
{
|
||||
// On garde un buffer sur le côté pour éviter la réallocation
|
||||
m_mixBuffer.resize(m_format * sampleCount);
|
||||
sf_count_t readSampleCount = sf_read_short(m_handle, m_mixBuffer.data(), m_format * sampleCount);
|
||||
MixToMono(m_mixBuffer.data(), static_cast<Int16*>(buffer), m_format, sampleCount);
|
||||
|
||||
return static_cast<unsigned int>(readSampleCount / m_format);
|
||||
}
|
||||
else
|
||||
return static_cast<unsigned int>(sf_read_short(m_handle, static_cast<Int16*>(buffer), sampleCount));
|
||||
}
|
||||
|
||||
void Seek(UInt32 offset) override
|
||||
{
|
||||
sf_seek(m_handle, offset*m_sampleRate / 1000, SEEK_SET);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Int16> m_mixBuffer;
|
||||
std::unique_ptr<InputStream> m_ownedStream;
|
||||
AudioFormat m_format;
|
||||
SNDFILE* m_handle;
|
||||
bool m_mixToMono;
|
||||
UInt32 m_duration;
|
||||
unsigned int m_sampleCount;
|
||||
unsigned int m_sampleRate;
|
||||
};
|
||||
|
||||
return supportedExtensions.find(extension) != supportedExtensions.end();
|
||||
bool IsSupported(const String& extension)
|
||||
{
|
||||
static std::set<String> supportedExtensions = {
|
||||
"aiff", "au", "avr", "caf", "flac", "htk", "ircam", "mat4", "mat5", "mpc2k",
|
||||
"nist","ogg", "pvf", "raw", "rf64", "sd2", "sds", "svx", "voc", "w64", "wav", "wve"
|
||||
};
|
||||
|
||||
return supportedExtensions.find(extension) != supportedExtensions.end();
|
||||
}
|
||||
|
||||
Ternary CheckMusic(InputStream& stream, const MusicParams& parameters)
|
||||
{
|
||||
NazaraUnused(parameters);
|
||||
|
||||
SF_INFO info;
|
||||
info.format = 0; // Format inconnu
|
||||
|
||||
// Si on peut ouvrir le flux, c'est qu'il est dans un format compatible
|
||||
SNDFILE* file = sf_open_virtual(&callbacks, SFM_READ, &info, &stream);
|
||||
if (file)
|
||||
{
|
||||
sf_close(file);
|
||||
return Ternary_True;
|
||||
}
|
||||
else
|
||||
return Ternary_False;
|
||||
}
|
||||
|
||||
bool LoadMusicFile(Music* music, const String& filePath, const MusicParams& parameters)
|
||||
{
|
||||
std::unique_ptr<sndfileStream> musicStream(new sndfileStream);
|
||||
if (!musicStream->Open(filePath, parameters.forceMono))
|
||||
{
|
||||
NazaraError("Failed to open music stream");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!music->Create(musicStream.get())) // Transfert de propriété
|
||||
{
|
||||
NazaraError("Failed to create music");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Le pointeur a été transféré avec succès, nous pouvons laisser tomber la propriété
|
||||
musicStream.release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadMusicMemory(Music* music, const void* data, std::size_t size, const MusicParams& parameters)
|
||||
{
|
||||
std::unique_ptr<sndfileStream> musicStream(new sndfileStream);
|
||||
if (!musicStream->Open(data, size, parameters.forceMono))
|
||||
{
|
||||
NazaraError("Failed to open music stream");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!music->Create(musicStream.get())) // Transfert de propriété
|
||||
{
|
||||
NazaraError("Failed to create music");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Le pointeur a été transféré avec succès, nous pouvons laisser tomber la propriété
|
||||
musicStream.release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadMusicStream(Music* music, InputStream& stream, const MusicParams& parameters)
|
||||
{
|
||||
std::unique_ptr<sndfileStream> musicStream(new sndfileStream);
|
||||
if (!musicStream->Open(stream, parameters.forceMono))
|
||||
{
|
||||
NazaraError("Failed to open music stream");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!music->Create(musicStream.get())) // Transfert de propriété
|
||||
{
|
||||
NazaraError("Failed to create music");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Le pointeur a été transféré avec succès, nous pouvons laisser tomber la propriété
|
||||
musicStream.release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Ternary CheckSoundBuffer(InputStream& stream, const SoundBufferParams& parameters)
|
||||
{
|
||||
NazaraUnused(parameters);
|
||||
|
||||
SF_INFO info;
|
||||
info.format = 0;
|
||||
|
||||
SNDFILE* file = sf_open_virtual(&callbacks, SFM_READ, &info, &stream);
|
||||
if (file)
|
||||
{
|
||||
sf_close(file);
|
||||
return Ternary_True;
|
||||
}
|
||||
else
|
||||
return Ternary_False;
|
||||
}
|
||||
|
||||
bool LoadSoundBuffer(SoundBuffer* soundBuffer, InputStream& stream, const SoundBufferParams& parameters)
|
||||
{
|
||||
SF_INFO info;
|
||||
info.format = 0;
|
||||
|
||||
SNDFILE* file = sf_open_virtual(&callbacks, SFM_READ, &info, &stream);
|
||||
if (!file)
|
||||
{
|
||||
NazaraError("Failed to load sound file: " + String(sf_strerror(file)));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Lynix utilise RAII...
|
||||
// C'est très efficace !
|
||||
// MemoryLeak est confus...
|
||||
CallOnExit onExit([file]
|
||||
{
|
||||
sf_close(file);
|
||||
});
|
||||
|
||||
AudioFormat format = Audio::GetAudioFormat(info.channels);
|
||||
if (format == AudioFormat_Unknown)
|
||||
{
|
||||
NazaraError("Channel count not handled");
|
||||
return false;
|
||||
}
|
||||
|
||||
// https://github.com/LaurentGomila/SFML/issues/271
|
||||
// http://www.mega-nerd.com/libsndfile/command.html#SFC_SET_SCALE_FLOAT_INT_READ
|
||||
///FIXME: Seulement le Vorbis ?
|
||||
if (info.format & SF_FORMAT_VORBIS)
|
||||
sf_command(file, SFC_SET_SCALE_FLOAT_INT_READ, nullptr, SF_TRUE);
|
||||
|
||||
unsigned int sampleCount = static_cast<unsigned int>(info.frames * info.channels);
|
||||
std::unique_ptr<Int16[]> samples(new Int16[sampleCount]);
|
||||
|
||||
if (sf_read_short(file, samples.get(), sampleCount) != sampleCount)
|
||||
{
|
||||
NazaraError("Failed to read samples");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Une conversion en mono est-elle nécessaire ?
|
||||
if (parameters.forceMono && format != AudioFormat_Mono)
|
||||
{
|
||||
// Nous effectuons la conversion en mono dans le même buffer (il va de toute façon être copié)
|
||||
MixToMono(samples.get(), samples.get(), static_cast<unsigned int>(info.channels), static_cast<unsigned int>(info.frames));
|
||||
|
||||
format = AudioFormat_Mono;
|
||||
sampleCount = static_cast<unsigned int>(info.frames);
|
||||
}
|
||||
|
||||
if (!soundBuffer->Create(format, sampleCount, info.samplerate, samples.get()))
|
||||
{
|
||||
NazaraError("Failed to create sound buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
nzTernary CheckMusic(NzInputStream& stream, const NzMusicParams& parameters)
|
||||
namespace Loaders
|
||||
{
|
||||
NazaraUnused(parameters);
|
||||
|
||||
SF_INFO info;
|
||||
info.format = 0; // Format inconnu
|
||||
|
||||
// Si on peut ouvrir le flux, c'est qu'il est dans un format compatible
|
||||
SNDFILE* file = sf_open_virtual(&callbacks, SFM_READ, &info, &stream);
|
||||
if (file)
|
||||
void Register_sndfile()
|
||||
{
|
||||
sf_close(file);
|
||||
return nzTernary_True;
|
||||
}
|
||||
else
|
||||
return nzTernary_False;
|
||||
}
|
||||
|
||||
bool LoadMusicFile(NzMusic* music, const NzString& filePath, const NzMusicParams& parameters)
|
||||
{
|
||||
std::unique_ptr<sndfileStream> musicStream(new sndfileStream);
|
||||
if (!musicStream->Open(filePath, parameters.forceMono))
|
||||
{
|
||||
NazaraError("Failed to open music stream");
|
||||
return false;
|
||||
MusicLoader::RegisterLoader(Detail::IsSupported, Detail::CheckMusic, Detail::LoadMusicStream, Detail::LoadMusicFile, Detail::LoadMusicMemory);
|
||||
SoundBufferLoader::RegisterLoader(Detail::IsSupported, Detail::CheckSoundBuffer, Detail::LoadSoundBuffer);
|
||||
}
|
||||
|
||||
if (!music->Create(musicStream.get())) // Transfert de propriété
|
||||
void Unregister_sndfile()
|
||||
{
|
||||
NazaraError("Failed to create music");
|
||||
return false;
|
||||
MusicLoader::UnregisterLoader(Detail::IsSupported, Detail::CheckMusic, Detail::LoadMusicStream, Detail::LoadMusicFile, Detail::LoadMusicMemory);
|
||||
SoundBufferLoader::UnregisterLoader(Detail::IsSupported, Detail::CheckSoundBuffer, Detail::LoadSoundBuffer);
|
||||
}
|
||||
|
||||
// Le pointeur a été transféré avec succès, nous pouvons laisser tomber la propriété
|
||||
musicStream.release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadMusicMemory(NzMusic* music, const void* data, std::size_t size, const NzMusicParams& parameters)
|
||||
{
|
||||
std::unique_ptr<sndfileStream> musicStream(new sndfileStream);
|
||||
if (!musicStream->Open(data, size, parameters.forceMono))
|
||||
{
|
||||
NazaraError("Failed to open music stream");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!music->Create(musicStream.get())) // Transfert de propriété
|
||||
{
|
||||
NazaraError("Failed to create music");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Le pointeur a été transféré avec succès, nous pouvons laisser tomber la propriété
|
||||
musicStream.release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadMusicStream(NzMusic* music, NzInputStream& stream, const NzMusicParams& parameters)
|
||||
{
|
||||
std::unique_ptr<sndfileStream> musicStream(new sndfileStream);
|
||||
if (!musicStream->Open(stream, parameters.forceMono))
|
||||
{
|
||||
NazaraError("Failed to open music stream");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!music->Create(musicStream.get())) // Transfert de propriété
|
||||
{
|
||||
NazaraError("Failed to create music");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Le pointeur a été transféré avec succès, nous pouvons laisser tomber la propriété
|
||||
musicStream.release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nzTernary CheckSoundBuffer(NzInputStream& stream, const NzSoundBufferParams& parameters)
|
||||
{
|
||||
NazaraUnused(parameters);
|
||||
|
||||
SF_INFO info;
|
||||
info.format = 0;
|
||||
|
||||
SNDFILE* file = sf_open_virtual(&callbacks, SFM_READ, &info, &stream);
|
||||
if (file)
|
||||
{
|
||||
sf_close(file);
|
||||
return nzTernary_True;
|
||||
}
|
||||
else
|
||||
return nzTernary_False;
|
||||
}
|
||||
|
||||
bool LoadSoundBuffer(NzSoundBuffer* soundBuffer, NzInputStream& stream, const NzSoundBufferParams& parameters)
|
||||
{
|
||||
SF_INFO info;
|
||||
info.format = 0;
|
||||
|
||||
SNDFILE* file = sf_open_virtual(&callbacks, SFM_READ, &info, &stream);
|
||||
if (!file)
|
||||
{
|
||||
NazaraError("Failed to load sound file: " + NzString(sf_strerror(file)));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Lynix utilise RAII...
|
||||
// C'est très efficace !
|
||||
// MemoryLeak est confus...
|
||||
NzCallOnExit onExit([file]
|
||||
{
|
||||
sf_close(file);
|
||||
});
|
||||
|
||||
nzAudioFormat format = NzAudio::GetAudioFormat(info.channels);
|
||||
if (format == nzAudioFormat_Unknown)
|
||||
{
|
||||
NazaraError("Channel count not handled");
|
||||
return false;
|
||||
}
|
||||
|
||||
// https://github.com/LaurentGomila/SFML/issues/271
|
||||
// http://www.mega-nerd.com/libsndfile/command.html#SFC_SET_SCALE_FLOAT_INT_READ
|
||||
///FIXME: Seulement le Vorbis ?
|
||||
if (info.format & SF_FORMAT_VORBIS)
|
||||
sf_command(file, SFC_SET_SCALE_FLOAT_INT_READ, nullptr, SF_TRUE);
|
||||
|
||||
unsigned int sampleCount = static_cast<unsigned int>(info.frames * info.channels);
|
||||
std::unique_ptr<nzInt16[]> samples(new nzInt16[sampleCount]);
|
||||
|
||||
if (sf_read_short(file, samples.get(), sampleCount) != sampleCount)
|
||||
{
|
||||
NazaraError("Failed to read samples");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Une conversion en mono est-elle nécessaire ?
|
||||
if (parameters.forceMono && format != nzAudioFormat_Mono)
|
||||
{
|
||||
// Nous effectuons la conversion en mono dans le même buffer (il va de toute façon être copié)
|
||||
NzMixToMono(samples.get(), samples.get(), static_cast<unsigned int>(info.channels), static_cast<unsigned int>(info.frames));
|
||||
|
||||
format = nzAudioFormat_Mono;
|
||||
sampleCount = static_cast<unsigned int>(info.frames);
|
||||
}
|
||||
|
||||
if (!soundBuffer->Create(format, sampleCount, info.samplerate, samples.get()))
|
||||
{
|
||||
NazaraError("Failed to create sound buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void NzLoaders_sndfile_Register()
|
||||
{
|
||||
NzMusicLoader::RegisterLoader(IsSupported, CheckMusic, LoadMusicStream, LoadMusicFile, LoadMusicMemory);
|
||||
NzSoundBufferLoader::RegisterLoader(IsSupported, CheckSoundBuffer, LoadSoundBuffer);
|
||||
}
|
||||
|
||||
void NzLoaders_sndfile_Unregister()
|
||||
{
|
||||
NzMusicLoader::UnregisterLoader(IsSupported, CheckMusic, LoadMusicStream, LoadMusicFile, LoadMusicMemory);
|
||||
NzSoundBufferLoader::UnregisterLoader(IsSupported, CheckSoundBuffer, LoadSoundBuffer);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,13 @@
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
|
||||
void NzLoaders_sndfile_Register();
|
||||
void NzLoaders_sndfile_Unregister();
|
||||
namespace Nz
|
||||
{
|
||||
namespace Loaders
|
||||
{
|
||||
void Register_sndfile();
|
||||
void Unregister_sndfile();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // NAZARA_LOADERS_SNDFILE_HPP
|
||||
|
||||
@@ -11,328 +11,331 @@
|
||||
#include <vector>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
bool NzMusicParams::IsValid() const
|
||||
namespace Nz
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
struct NzMusicImpl
|
||||
{
|
||||
ALenum audioFormat;
|
||||
std::unique_ptr<NzSoundStream> stream;
|
||||
std::vector<nzInt16> chunkSamples;
|
||||
NzThread thread;
|
||||
bool loop = false;
|
||||
bool streaming = false;
|
||||
unsigned int sampleRate;
|
||||
};
|
||||
|
||||
NzMusic::~NzMusic()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NzMusic::Create(NzSoundStream* soundStream)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!soundStream)
|
||||
bool MusicParams::IsValid() const
|
||||
{
|
||||
NazaraError("Sound stream must be valid");
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
nzAudioFormat format = soundStream->GetFormat();
|
||||
|
||||
m_impl = new NzMusicImpl;
|
||||
m_impl->sampleRate = soundStream->GetSampleRate();
|
||||
m_impl->audioFormat = NzOpenAL::AudioFormat[format];
|
||||
m_impl->chunkSamples.resize(format * m_impl->sampleRate); // Une seconde de samples
|
||||
m_impl->stream.reset(soundStream);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzMusic::Destroy()
|
||||
{
|
||||
if (m_impl)
|
||||
struct MusicImpl
|
||||
{
|
||||
Stop();
|
||||
ALenum audioFormat;
|
||||
std::unique_ptr<SoundStream> stream;
|
||||
std::vector<Int16> chunkSamples;
|
||||
Thread thread;
|
||||
bool loop = false;
|
||||
bool streaming = false;
|
||||
unsigned int sampleRate;
|
||||
};
|
||||
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
Music::~Music()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void NzMusic::EnableLooping(bool loop)
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
bool Music::Create(SoundStream* soundStream)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return;
|
||||
Destroy();
|
||||
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!soundStream)
|
||||
{
|
||||
NazaraError("Sound stream must be valid");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
AudioFormat format = soundStream->GetFormat();
|
||||
|
||||
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->stream.reset(soundStream);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->loop = loop;
|
||||
}
|
||||
|
||||
nzUInt32 NzMusic::GetDuration() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
void Music::Destroy()
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
if (m_impl)
|
||||
{
|
||||
Stop();
|
||||
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Music::EnableLooping(bool loop)
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->loop = loop;
|
||||
}
|
||||
|
||||
UInt32 Music::GetDuration() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->stream->GetDuration();
|
||||
}
|
||||
|
||||
AudioFormat Music::GetFormat() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return AudioFormat_Unknown;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->stream->GetFormat();
|
||||
}
|
||||
|
||||
UInt32 Music::GetPlayingOffset() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
///TODO
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->stream->GetDuration();
|
||||
}
|
||||
|
||||
nzAudioFormat NzMusic::GetFormat() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
UInt32 Music::GetSampleCount() const
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return nzAudioFormat_Unknown;
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->stream->GetSampleCount();
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->stream->GetFormat();
|
||||
}
|
||||
|
||||
nzUInt32 NzMusic::GetPlayingOffset() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
UInt32 Music::GetSampleRate() const
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return 0;
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->stream->GetSampleRate();
|
||||
}
|
||||
#endif
|
||||
|
||||
///TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
nzUInt32 NzMusic::GetSampleCount() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
SoundStatus Music::GetStatus() const
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return 0;
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return SoundStatus_Stopped;
|
||||
}
|
||||
#endif
|
||||
|
||||
SoundStatus status = GetInternalStatus();
|
||||
|
||||
// Pour compenser les éventuels retards (ou le laps de temps entre Play() et la mise en route du thread)
|
||||
if (m_impl->streaming && status == SoundStatus_Stopped)
|
||||
status = SoundStatus_Playing;
|
||||
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->stream->GetSampleCount();
|
||||
}
|
||||
|
||||
nzUInt32 NzMusic::GetSampleRate() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
bool Music::IsLooping() const
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return 0;
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->loop;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->stream->GetSampleRate();
|
||||
}
|
||||
|
||||
nzSoundStatus NzMusic::GetStatus() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
bool Music::OpenFromFile(const String& filePath, const MusicParams& params)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return nzSoundStatus_Stopped;
|
||||
return MusicLoader::LoadFromFile(this, filePath, params);
|
||||
}
|
||||
#endif
|
||||
|
||||
nzSoundStatus status = GetInternalStatus();
|
||||
|
||||
// Pour compenser les éventuels retards (ou le laps de temps entre Play() et la mise en route du thread)
|
||||
if (m_impl->streaming && status == nzSoundStatus_Stopped)
|
||||
status = nzSoundStatus_Playing;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool NzMusic::IsLooping() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
bool Music::OpenFromMemory(const void* data, std::size_t size, const MusicParams& params)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return false;
|
||||
return MusicLoader::LoadFromMemory(this, data, size, params);
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->loop;
|
||||
}
|
||||
|
||||
bool NzMusic::OpenFromFile(const NzString& filePath, const NzMusicParams& params)
|
||||
{
|
||||
return NzMusicLoader::LoadFromFile(this, filePath, params);
|
||||
}
|
||||
|
||||
bool NzMusic::OpenFromMemory(const void* data, std::size_t size, const NzMusicParams& params)
|
||||
{
|
||||
return NzMusicLoader::LoadFromMemory(this, data, size, params);
|
||||
}
|
||||
|
||||
bool NzMusic::OpenFromStream(NzInputStream& stream, const NzMusicParams& params)
|
||||
{
|
||||
return NzMusicLoader::LoadFromStream(this, stream, params);
|
||||
}
|
||||
|
||||
void NzMusic::Pause()
|
||||
{
|
||||
alSourcePause(m_source);
|
||||
}
|
||||
|
||||
void NzMusic::Play()
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
bool Music::OpenFromStream(InputStream& stream, const MusicParams& params)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return;
|
||||
return MusicLoader::LoadFromStream(this, stream, params);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Nous sommes déjà en train de jouer
|
||||
if (m_impl->streaming)
|
||||
void Music::Pause()
|
||||
{
|
||||
// Peut-être sommes-nous en pause
|
||||
if (GetStatus() != nzSoundStatus_Playing)
|
||||
alSourcePlay(m_source);
|
||||
alSourcePause(m_source);
|
||||
}
|
||||
|
||||
void Music::Play()
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Nous sommes déjà en train de jouer
|
||||
if (m_impl->streaming)
|
||||
{
|
||||
// Peut-être sommes-nous en pause
|
||||
if (GetStatus() != SoundStatus_Playing)
|
||||
alSourcePlay(m_source);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Lancement du thread de streaming
|
||||
m_impl->stream->Seek(0);
|
||||
m_impl->streaming = true;
|
||||
m_impl->thread = Thread(&Music::MusicThread, this);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Lancement du thread de streaming
|
||||
m_impl->stream->Seek(0);
|
||||
m_impl->streaming = true;
|
||||
m_impl->thread = NzThread(&NzMusic::MusicThread, this);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void NzMusic::SetPlayingOffset(nzUInt32 offset)
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
void Music::SetPlayingOffset(UInt32 offset)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
///TODO
|
||||
}
|
||||
|
||||
void NzMusic::Stop()
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_impl->streaming)
|
||||
{
|
||||
m_impl->streaming = false;
|
||||
m_impl->thread.Join();
|
||||
}
|
||||
}
|
||||
|
||||
bool NzMusic::FillAndQueueBuffer(unsigned int buffer)
|
||||
{
|
||||
unsigned int sampleCount = m_impl->chunkSamples.size();
|
||||
unsigned int sampleRead = 0;
|
||||
|
||||
// Lecture depuis le stream pour remplir le buffer
|
||||
for (;;)
|
||||
{
|
||||
sampleRead += m_impl->stream->Read(&m_impl->chunkSamples[sampleRead], sampleCount - sampleRead);
|
||||
if (sampleRead < sampleCount && !m_impl->loop)
|
||||
break; // Fin du stream (On ne boucle pas)
|
||||
|
||||
m_impl->stream->Seek(0); // On boucle au début du stream et on remplit à nouveau
|
||||
///TODO
|
||||
}
|
||||
|
||||
// Mise à jour du buffer (envoi à OpenAL) et placement dans la file d'attente
|
||||
if (sampleRead > 0)
|
||||
void Music::Stop()
|
||||
{
|
||||
alBufferData(buffer, m_impl->audioFormat, &m_impl->chunkSamples[0], sampleRead*sizeof(nzInt16), m_impl->sampleRate);
|
||||
alSourceQueueBuffers(m_source, 1, &buffer);
|
||||
}
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
return sampleRead != sampleCount; // Fin du stream (N'arrive pas en cas de loop)
|
||||
}
|
||||
|
||||
void NzMusic::MusicThread()
|
||||
{
|
||||
// Allocation des buffers de streaming
|
||||
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
|
||||
}
|
||||
|
||||
alSourcePlay(m_source);
|
||||
|
||||
// Boucle de lecture (remplissage de nouveaux buffers au fur et à mesure)
|
||||
while (m_impl->streaming)
|
||||
{
|
||||
// La lecture s'est arrêtée, nous avons atteint la fin du stream
|
||||
nzSoundStatus status = GetInternalStatus();
|
||||
if (status == nzSoundStatus_Stopped)
|
||||
if (m_impl->streaming)
|
||||
{
|
||||
m_impl->streaming = false;
|
||||
break;
|
||||
m_impl->thread.Join();
|
||||
}
|
||||
|
||||
// On traite les buffers lus
|
||||
ALint processedCount = 0;
|
||||
alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &processedCount);
|
||||
|
||||
ALuint buffer;
|
||||
while (processedCount--)
|
||||
{
|
||||
alSourceUnqueueBuffers(m_source, 1, &buffer);
|
||||
if (FillAndQueueBuffer(buffer))
|
||||
break;
|
||||
}
|
||||
|
||||
// On retourne dormir un peu
|
||||
NzThread::Sleep(50);
|
||||
}
|
||||
|
||||
// Arrêt de la lecture du son (dans le cas où ça ne serait pas déjà fait)
|
||||
alSourceStop(m_source);
|
||||
bool Music::FillAndQueueBuffer(unsigned int buffer)
|
||||
{
|
||||
unsigned int sampleCount = m_impl->chunkSamples.size();
|
||||
unsigned int sampleRead = 0;
|
||||
|
||||
// On supprime les buffers du stream
|
||||
ALint queuedBufferCount;
|
||||
alGetSourcei(m_source, AL_BUFFERS_QUEUED, &queuedBufferCount);
|
||||
// Lecture depuis le stream pour remplir le buffer
|
||||
for (;;)
|
||||
{
|
||||
sampleRead += m_impl->stream->Read(&m_impl->chunkSamples[sampleRead], sampleCount - sampleRead);
|
||||
if (sampleRead < sampleCount && !m_impl->loop)
|
||||
break; // Fin du stream (On ne boucle pas)
|
||||
|
||||
ALuint buffer;
|
||||
for (ALint i = 0; i < queuedBufferCount; ++i)
|
||||
alSourceUnqueueBuffers(m_source, 1, &buffer);
|
||||
m_impl->stream->Seek(0); // On boucle au début du stream et on remplit à nouveau
|
||||
}
|
||||
|
||||
alDeleteBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers);
|
||||
// Mise à jour du buffer (envoi à OpenAL) et placement dans la file d'attente
|
||||
if (sampleRead > 0)
|
||||
{
|
||||
alBufferData(buffer, m_impl->audioFormat, &m_impl->chunkSamples[0], sampleRead*sizeof(Int16), m_impl->sampleRate);
|
||||
alSourceQueueBuffers(m_source, 1, &buffer);
|
||||
}
|
||||
|
||||
return sampleRead != sampleCount; // Fin du stream (N'arrive pas en cas de loop)
|
||||
}
|
||||
|
||||
void Music::MusicThread()
|
||||
{
|
||||
// Allocation des buffers de streaming
|
||||
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
|
||||
}
|
||||
|
||||
alSourcePlay(m_source);
|
||||
|
||||
// Boucle de lecture (remplissage de nouveaux buffers au fur et à mesure)
|
||||
while (m_impl->streaming)
|
||||
{
|
||||
// La lecture s'est arrêtée, nous avons atteint la fin du stream
|
||||
SoundStatus status = GetInternalStatus();
|
||||
if (status == SoundStatus_Stopped)
|
||||
{
|
||||
m_impl->streaming = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// On traite les buffers lus
|
||||
ALint processedCount = 0;
|
||||
alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &processedCount);
|
||||
|
||||
ALuint buffer;
|
||||
while (processedCount--)
|
||||
{
|
||||
alSourceUnqueueBuffers(m_source, 1, &buffer);
|
||||
if (FillAndQueueBuffer(buffer))
|
||||
break;
|
||||
}
|
||||
|
||||
// On retourne dormir un peu
|
||||
Thread::Sleep(50);
|
||||
}
|
||||
|
||||
// Arrêt de la lecture du son (dans le cas où ça ne serait pas déjà fait)
|
||||
alSourceStop(m_source);
|
||||
|
||||
// On supprime les buffers du stream
|
||||
ALint queuedBufferCount;
|
||||
alGetSourcei(m_source, AL_BUFFERS_QUEUED, &queuedBufferCount);
|
||||
|
||||
ALuint buffer;
|
||||
for (ALint i = 0; i < queuedBufferCount; ++i)
|
||||
alSourceUnqueueBuffers(m_source, 1, &buffer);
|
||||
|
||||
alDeleteBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers);
|
||||
}
|
||||
|
||||
MusicLoader::LoaderList Music::s_loaders;
|
||||
}
|
||||
|
||||
NzMusicLoader::LoaderList NzMusic::s_loaders;
|
||||
|
||||
@@ -11,459 +11,462 @@
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace
|
||||
namespace Nz
|
||||
{
|
||||
NzDynLib s_library;
|
||||
NzString s_deviceName;
|
||||
NzString s_rendererName;
|
||||
NzString s_vendorName;
|
||||
ALCdevice* s_device = nullptr;
|
||||
ALCcontext* s_context = nullptr;
|
||||
unsigned int s_version;
|
||||
|
||||
unsigned int ParseDevices(const char* deviceString, std::vector<NzString>& devices)
|
||||
namespace
|
||||
{
|
||||
DynLib s_library;
|
||||
String s_deviceName;
|
||||
String s_rendererName;
|
||||
String s_vendorName;
|
||||
ALCdevice* s_device = nullptr;
|
||||
ALCcontext* s_context = nullptr;
|
||||
unsigned int s_version;
|
||||
|
||||
unsigned int ParseDevices(const char* deviceString, std::vector<String>& devices)
|
||||
{
|
||||
if (!deviceString)
|
||||
return 0;
|
||||
|
||||
unsigned int startSize = devices.size();
|
||||
|
||||
unsigned int length;
|
||||
while ((length = std::strlen(deviceString)) > 0)
|
||||
{
|
||||
devices.push_back(String(deviceString, length));
|
||||
deviceString += length + 1;
|
||||
}
|
||||
|
||||
return devices.size() - startSize;
|
||||
}
|
||||
}
|
||||
|
||||
OpenALFunc OpenAL::GetEntry(const String& entryPoint)
|
||||
{
|
||||
return LoadEntry(entryPoint.GetConstBuffer(), false);
|
||||
}
|
||||
|
||||
String OpenAL::GetRendererName()
|
||||
{
|
||||
return s_rendererName;
|
||||
}
|
||||
|
||||
String OpenAL::GetVendorName()
|
||||
{
|
||||
return s_vendorName;
|
||||
}
|
||||
|
||||
unsigned int OpenAL::GetVersion()
|
||||
{
|
||||
return s_version;
|
||||
}
|
||||
|
||||
bool OpenAL::Initialize(bool openDevice)
|
||||
{
|
||||
if (s_library.IsLoaded())
|
||||
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.
|
||||
const char* libs[] = {
|
||||
"soft_oal.dll",
|
||||
"wrap_oal.dll",
|
||||
"openal32.dll"
|
||||
};
|
||||
#elif defined(NAZARA_PLATFORM_LINUX)
|
||||
const char* libs[] = {
|
||||
"libopenal.so.1",
|
||||
"libopenal.so.0",
|
||||
"libopenal.so"
|
||||
};
|
||||
//#elif defined(NAZARA_PLATFORM_MACOSX)
|
||||
#else
|
||||
NazaraError("Unknown OS");
|
||||
return false;
|
||||
#endif
|
||||
|
||||
bool succeeded = false;
|
||||
for (const char* path : libs)
|
||||
{
|
||||
String libPath(path);
|
||||
if (!s_library.Load(libPath))
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
// al
|
||||
alBuffer3f = reinterpret_cast<OpenALDetail::LPALBUFFER3F>(LoadEntry("alBuffer3f"));
|
||||
alBuffer3i = reinterpret_cast<OpenALDetail::LPALBUFFER3I>(LoadEntry("alBuffer3i"));
|
||||
alBufferData = reinterpret_cast<OpenALDetail::LPALBUFFERDATA>(LoadEntry("alBufferData"));
|
||||
alBufferf = reinterpret_cast<OpenALDetail::LPALBUFFERF>(LoadEntry("alBufferf"));
|
||||
alBufferfv = reinterpret_cast<OpenALDetail::LPALBUFFERFV>(LoadEntry("alBufferfv"));
|
||||
alBufferi = reinterpret_cast<OpenALDetail::LPALBUFFERI>(LoadEntry("alBufferi"));
|
||||
alBufferiv = reinterpret_cast<OpenALDetail::LPALBUFFERIV>(LoadEntry("alBufferiv"));
|
||||
alDeleteBuffers = reinterpret_cast<OpenALDetail::LPALDELETEBUFFERS>(LoadEntry("alDeleteBuffers"));
|
||||
alDeleteSources = reinterpret_cast<OpenALDetail::LPALDELETESOURCES>(LoadEntry("alDeleteSources"));
|
||||
alDisable = reinterpret_cast<OpenALDetail::LPALDISABLE>(LoadEntry("alDisable"));
|
||||
alDistanceModel = reinterpret_cast<OpenALDetail::LPALDISTANCEMODEL>(LoadEntry("alDistanceModel"));
|
||||
alDopplerFactor = reinterpret_cast<OpenALDetail::LPALDOPPLERFACTOR>(LoadEntry("alDopplerFactor"));
|
||||
alDopplerVelocity = reinterpret_cast<OpenALDetail::LPALDOPPLERVELOCITY>(LoadEntry("alDopplerVelocity"));
|
||||
alEnable = reinterpret_cast<OpenALDetail::LPALENABLE>(LoadEntry("alEnable"));
|
||||
alGenBuffers = reinterpret_cast<OpenALDetail::LPALGENBUFFERS>(LoadEntry("alGenBuffers"));
|
||||
alGenSources = reinterpret_cast<OpenALDetail::LPALGENSOURCES>(LoadEntry("alGenSources"));
|
||||
alGetBoolean = reinterpret_cast<OpenALDetail::LPALGETBOOLEAN>(LoadEntry("alGetBoolean"));
|
||||
alGetBooleanv = reinterpret_cast<OpenALDetail::LPALGETBOOLEANV>(LoadEntry("alGetBooleanv"));
|
||||
alGetBuffer3f = reinterpret_cast<OpenALDetail::LPALGETBUFFER3F>(LoadEntry("alGetBuffer3f"));
|
||||
alGetBuffer3i = reinterpret_cast<OpenALDetail::LPALGETBUFFER3I>(LoadEntry("alGetBuffer3i"));
|
||||
alGetBufferf = reinterpret_cast<OpenALDetail::LPALGETBUFFERF>(LoadEntry("alGetBufferf"));
|
||||
alGetBufferfv = reinterpret_cast<OpenALDetail::LPALGETBUFFERFV>(LoadEntry("alGetBufferfv"));
|
||||
alGetBufferi = reinterpret_cast<OpenALDetail::LPALGETBUFFERI>(LoadEntry("alGetBufferi"));
|
||||
alGetBufferiv = reinterpret_cast<OpenALDetail::LPALGETBUFFERIV>(LoadEntry("alGetBufferiv"));
|
||||
alGetDouble = reinterpret_cast<OpenALDetail::LPALGETDOUBLE>(LoadEntry("alGetDouble"));
|
||||
alGetDoublev = reinterpret_cast<OpenALDetail::LPALGETDOUBLEV>(LoadEntry("alGetDoublev"));
|
||||
alGetEnumValue = reinterpret_cast<OpenALDetail::LPALGETENUMVALUE>(LoadEntry("alGetEnumValue"));
|
||||
alGetError = reinterpret_cast<OpenALDetail::LPALGETERROR>(LoadEntry("alGetError"));
|
||||
alGetFloat = reinterpret_cast<OpenALDetail::LPALGETFLOAT>(LoadEntry("alGetFloat"));
|
||||
alGetFloatv = reinterpret_cast<OpenALDetail::LPALGETFLOATV>(LoadEntry("alGetFloatv"));
|
||||
alGetInteger = reinterpret_cast<OpenALDetail::LPALGETINTEGER>(LoadEntry("alGetInteger"));
|
||||
alGetIntegerv = reinterpret_cast<OpenALDetail::LPALGETINTEGERV>(LoadEntry("alGetIntegerv"));
|
||||
alGetListener3f = reinterpret_cast<OpenALDetail::LPALGETLISTENER3F>(LoadEntry("alGetListener3f"));
|
||||
alGetListener3i = reinterpret_cast<OpenALDetail::LPALGETLISTENER3I>(LoadEntry("alGetListener3i"));
|
||||
alGetListenerf = reinterpret_cast<OpenALDetail::LPALGETLISTENERF>(LoadEntry("alGetListenerf"));
|
||||
alGetListenerfv = reinterpret_cast<OpenALDetail::LPALGETLISTENERFV>(LoadEntry("alGetListenerfv"));
|
||||
alGetListeneri = reinterpret_cast<OpenALDetail::LPALGETLISTENERI>(LoadEntry("alGetListeneri"));
|
||||
alGetListeneriv = reinterpret_cast<OpenALDetail::LPALGETLISTENERIV>(LoadEntry("alGetListeneriv"));
|
||||
alGetProcAddress = reinterpret_cast<OpenALDetail::LPALGETPROCADDRESS>(LoadEntry("alGetProcAddress"));
|
||||
alGetSource3f = reinterpret_cast<OpenALDetail::LPALGETSOURCE3F>(LoadEntry("alGetSource3f"));
|
||||
alGetSource3i = reinterpret_cast<OpenALDetail::LPALGETSOURCE3I>(LoadEntry("alGetSource3i"));
|
||||
alGetSourcef = reinterpret_cast<OpenALDetail::LPALGETSOURCEF>(LoadEntry("alGetSourcef"));
|
||||
alGetSourcefv = reinterpret_cast<OpenALDetail::LPALGETSOURCEFV>(LoadEntry("alGetSourcefv"));
|
||||
alGetSourcei = reinterpret_cast<OpenALDetail::LPALGETSOURCEI>(LoadEntry("alGetSourcei"));
|
||||
alGetSourceiv = reinterpret_cast<OpenALDetail::LPALGETSOURCEIV>(LoadEntry("alGetSourceiv"));
|
||||
alGetString = reinterpret_cast<OpenALDetail::LPALGETSTRING>(LoadEntry("alGetString"));
|
||||
alIsBuffer = reinterpret_cast<OpenALDetail::LPALISBUFFER>(LoadEntry("alIsBuffer"));
|
||||
alIsEnabled = reinterpret_cast<OpenALDetail::LPALISENABLED>(LoadEntry("alIsEnabled"));
|
||||
alIsExtensionPresent = reinterpret_cast<OpenALDetail::LPALISEXTENSIONPRESENT>(LoadEntry("alIsExtensionPresent"));
|
||||
alIsSource = reinterpret_cast<OpenALDetail::LPALISSOURCE>(LoadEntry("alIsSource"));
|
||||
alListener3f = reinterpret_cast<OpenALDetail::LPALLISTENER3F>(LoadEntry("alListener3f"));
|
||||
alListener3i = reinterpret_cast<OpenALDetail::LPALLISTENER3I>(LoadEntry("alListener3i"));
|
||||
alListenerf = reinterpret_cast<OpenALDetail::LPALLISTENERF>(LoadEntry("alListenerf"));
|
||||
alListenerfv = reinterpret_cast<OpenALDetail::LPALLISTENERFV>(LoadEntry("alListenerfv"));
|
||||
alListeneri = reinterpret_cast<OpenALDetail::LPALLISTENERI>(LoadEntry("alListeneri"));
|
||||
alListeneriv = reinterpret_cast<OpenALDetail::LPALLISTENERIV>(LoadEntry("alListeneriv"));
|
||||
alSource3f = reinterpret_cast<OpenALDetail::LPALSOURCE3F>(LoadEntry("alSource3f"));
|
||||
alSource3i = reinterpret_cast<OpenALDetail::LPALSOURCE3I>(LoadEntry("alSource3i"));
|
||||
alSourcef = reinterpret_cast<OpenALDetail::LPALSOURCEF>(LoadEntry("alSourcef"));
|
||||
alSourcefv = reinterpret_cast<OpenALDetail::LPALSOURCEFV>(LoadEntry("alSourcefv"));
|
||||
alSourcei = reinterpret_cast<OpenALDetail::LPALSOURCEI>(LoadEntry("alSourcei"));
|
||||
alSourceiv = reinterpret_cast<OpenALDetail::LPALSOURCEIV>(LoadEntry("alSourceiv"));
|
||||
alSourcePause = reinterpret_cast<OpenALDetail::LPALSOURCEPAUSE>(LoadEntry("alSourcePause"));
|
||||
alSourcePausev = reinterpret_cast<OpenALDetail::LPALSOURCEPAUSEV>(LoadEntry("alSourcePausev"));
|
||||
alSourcePlay = reinterpret_cast<OpenALDetail::LPALSOURCEPLAY>(LoadEntry("alSourcePlay"));
|
||||
alSourcePlayv = reinterpret_cast<OpenALDetail::LPALSOURCEPLAYV>(LoadEntry("alSourcePlayv"));
|
||||
alSourceQueueBuffers = reinterpret_cast<OpenALDetail::LPALSOURCEQUEUEBUFFERS>(LoadEntry("alSourceQueueBuffers"));
|
||||
alSourceRewind = reinterpret_cast<OpenALDetail::LPALSOURCEREWIND>(LoadEntry("alSourceRewind"));
|
||||
alSourceRewindv = reinterpret_cast<OpenALDetail::LPALSOURCEREWINDV>(LoadEntry("alSourceRewindv"));
|
||||
alSourceStop = reinterpret_cast<OpenALDetail::LPALSOURCESTOP>(LoadEntry("alSourceStop"));
|
||||
alSourceStopv = reinterpret_cast<OpenALDetail::LPALSOURCESTOPV>(LoadEntry("alSourceStopv"));
|
||||
alSourceUnqueueBuffers = reinterpret_cast<OpenALDetail::LPALSOURCEUNQUEUEBUFFERS>(LoadEntry("alSourceUnqueueBuffers"));
|
||||
alSpeedOfSound = reinterpret_cast<OpenALDetail::LPALSPEEDOFSOUND>(LoadEntry("alSpeedOfSound"));
|
||||
|
||||
// alc
|
||||
alcCaptureCloseDevice = reinterpret_cast<OpenALDetail::LPALCCAPTURECLOSEDEVICE>(LoadEntry("alcCaptureCloseDevice"));
|
||||
alcCaptureOpenDevice = reinterpret_cast<OpenALDetail::LPALCCAPTUREOPENDEVICE>(LoadEntry("alcCaptureOpenDevice"));
|
||||
alcCaptureSamples = reinterpret_cast<OpenALDetail::LPALCCAPTURESAMPLES>(LoadEntry("alcCaptureSamples"));
|
||||
alcCaptureStart = reinterpret_cast<OpenALDetail::LPALCCAPTURESTART>(LoadEntry("alcCaptureStart"));
|
||||
alcCaptureStop = reinterpret_cast<OpenALDetail::LPALCCAPTURESTOP>(LoadEntry("alcCaptureStop"));
|
||||
alcCloseDevice = reinterpret_cast<OpenALDetail::LPALCCLOSEDEVICE>(LoadEntry("alcCloseDevice"));
|
||||
alcCreateContext = reinterpret_cast<OpenALDetail::LPALCCREATECONTEXT>(LoadEntry("alcCreateContext"));
|
||||
alcDestroyContext = reinterpret_cast<OpenALDetail::LPALCDESTROYCONTEXT>(LoadEntry("alcDestroyContext"));
|
||||
alcGetContextsDevice = reinterpret_cast<OpenALDetail::LPALCGETCONTEXTSDEVICE>(LoadEntry("alcGetContextsDevice"));
|
||||
alcGetCurrentContext = reinterpret_cast<OpenALDetail::LPALCGETCURRENTCONTEXT>(LoadEntry("alcGetCurrentContext"));
|
||||
alcGetEnumValue = reinterpret_cast<OpenALDetail::LPALCGETENUMVALUE>(LoadEntry("alcGetEnumValue"));
|
||||
alcGetError = reinterpret_cast<OpenALDetail::LPALCGETERROR>(LoadEntry("alcGetError"));
|
||||
alcGetIntegerv = reinterpret_cast<OpenALDetail::LPALCGETINTEGERV>(LoadEntry("alcGetIntegerv"));
|
||||
alcGetProcAddress = reinterpret_cast<OpenALDetail::LPALCGETPROCADDRESS>(LoadEntry("alcGetProcAddress"));
|
||||
alcGetString = reinterpret_cast<OpenALDetail::LPALCGETSTRING>(LoadEntry("alcGetString"));
|
||||
alcIsExtensionPresent = reinterpret_cast<OpenALDetail::LPALCISEXTENSIONPRESENT>(LoadEntry("alcIsExtensionPresent"));
|
||||
alcMakeContextCurrent = reinterpret_cast<OpenALDetail::LPALCMAKECONTEXTCURRENT>(LoadEntry("alcMakeContextCurrent"));
|
||||
alcOpenDevice = reinterpret_cast<OpenALDetail::LPALCOPENDEVICE>(LoadEntry("alcOpenDevice"));
|
||||
alcProcessContext = reinterpret_cast<OpenALDetail::LPALCPROCESSCONTEXT>(LoadEntry("alcProcessContext"));
|
||||
alcSuspendContext = reinterpret_cast<OpenALDetail::LPALCSUSPENDCONTEXT>(LoadEntry("alcSuspendContext"));
|
||||
|
||||
succeeded = true;
|
||||
break;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
NazaraWarning(libPath + " loading failed: " + String(e.what()));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!succeeded)
|
||||
{
|
||||
NazaraError("Failed to load OpenAL");
|
||||
Uninitialize();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (openDevice)
|
||||
OpenDevice();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenAL::IsInitialized()
|
||||
{
|
||||
return s_library.IsLoaded();
|
||||
}
|
||||
|
||||
unsigned int OpenAL::QueryInputDevices(std::vector<String>& devices)
|
||||
{
|
||||
const char* deviceString = reinterpret_cast<const char*>(alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER));
|
||||
if (!deviceString)
|
||||
return 0;
|
||||
|
||||
unsigned int startSize = devices.size();
|
||||
|
||||
unsigned int length;
|
||||
while ((length = std::strlen(deviceString)) > 0)
|
||||
{
|
||||
devices.push_back(NzString(deviceString, length));
|
||||
deviceString += length + 1;
|
||||
}
|
||||
|
||||
return devices.size() - startSize;
|
||||
return ParseDevices(deviceString, devices);
|
||||
}
|
||||
}
|
||||
|
||||
NzOpenALFunc NzOpenAL::GetEntry(const NzString& entryPoint)
|
||||
{
|
||||
return LoadEntry(entryPoint.GetConstBuffer(), false);
|
||||
}
|
||||
|
||||
NzString NzOpenAL::GetRendererName()
|
||||
{
|
||||
return s_rendererName;
|
||||
}
|
||||
|
||||
NzString NzOpenAL::GetVendorName()
|
||||
{
|
||||
return s_vendorName;
|
||||
}
|
||||
|
||||
unsigned int NzOpenAL::GetVersion()
|
||||
{
|
||||
return s_version;
|
||||
}
|
||||
|
||||
bool NzOpenAL::Initialize(bool openDevice)
|
||||
{
|
||||
if (s_library.IsLoaded())
|
||||
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.
|
||||
const char* libs[] = {
|
||||
"soft_oal.dll",
|
||||
"wrap_oal.dll",
|
||||
"openal32.dll"
|
||||
};
|
||||
#elif defined(NAZARA_PLATFORM_LINUX)
|
||||
const char* libs[] = {
|
||||
"libopenal.so.1",
|
||||
"libopenal.so.0",
|
||||
"libopenal.so"
|
||||
};
|
||||
//#elif defined(NAZARA_PLATFORM_MACOSX)
|
||||
#else
|
||||
NazaraError("Unknown OS");
|
||||
return false;
|
||||
#endif
|
||||
|
||||
bool succeeded = false;
|
||||
for (const char* path : libs)
|
||||
unsigned int OpenAL::QueryOutputDevices(std::vector<String>& devices)
|
||||
{
|
||||
NzString libPath(path);
|
||||
if (!s_library.Load(libPath))
|
||||
continue;
|
||||
const char* deviceString = reinterpret_cast<const char*>(alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER));
|
||||
if (!deviceString)
|
||||
return 0;
|
||||
|
||||
try
|
||||
{
|
||||
// al
|
||||
alBuffer3f = reinterpret_cast<NzOpenALDetail::LPALBUFFER3F>(LoadEntry("alBuffer3f"));
|
||||
alBuffer3i = reinterpret_cast<NzOpenALDetail::LPALBUFFER3I>(LoadEntry("alBuffer3i"));
|
||||
alBufferData = reinterpret_cast<NzOpenALDetail::LPALBUFFERDATA>(LoadEntry("alBufferData"));
|
||||
alBufferf = reinterpret_cast<NzOpenALDetail::LPALBUFFERF>(LoadEntry("alBufferf"));
|
||||
alBufferfv = reinterpret_cast<NzOpenALDetail::LPALBUFFERFV>(LoadEntry("alBufferfv"));
|
||||
alBufferi = reinterpret_cast<NzOpenALDetail::LPALBUFFERI>(LoadEntry("alBufferi"));
|
||||
alBufferiv = reinterpret_cast<NzOpenALDetail::LPALBUFFERIV>(LoadEntry("alBufferiv"));
|
||||
alDeleteBuffers = reinterpret_cast<NzOpenALDetail::LPALDELETEBUFFERS>(LoadEntry("alDeleteBuffers"));
|
||||
alDeleteSources = reinterpret_cast<NzOpenALDetail::LPALDELETESOURCES>(LoadEntry("alDeleteSources"));
|
||||
alDisable = reinterpret_cast<NzOpenALDetail::LPALDISABLE>(LoadEntry("alDisable"));
|
||||
alDistanceModel = reinterpret_cast<NzOpenALDetail::LPALDISTANCEMODEL>(LoadEntry("alDistanceModel"));
|
||||
alDopplerFactor = reinterpret_cast<NzOpenALDetail::LPALDOPPLERFACTOR>(LoadEntry("alDopplerFactor"));
|
||||
alDopplerVelocity = reinterpret_cast<NzOpenALDetail::LPALDOPPLERVELOCITY>(LoadEntry("alDopplerVelocity"));
|
||||
alEnable = reinterpret_cast<NzOpenALDetail::LPALENABLE>(LoadEntry("alEnable"));
|
||||
alGenBuffers = reinterpret_cast<NzOpenALDetail::LPALGENBUFFERS>(LoadEntry("alGenBuffers"));
|
||||
alGenSources = reinterpret_cast<NzOpenALDetail::LPALGENSOURCES>(LoadEntry("alGenSources"));
|
||||
alGetBoolean = reinterpret_cast<NzOpenALDetail::LPALGETBOOLEAN>(LoadEntry("alGetBoolean"));
|
||||
alGetBooleanv = reinterpret_cast<NzOpenALDetail::LPALGETBOOLEANV>(LoadEntry("alGetBooleanv"));
|
||||
alGetBuffer3f = reinterpret_cast<NzOpenALDetail::LPALGETBUFFER3F>(LoadEntry("alGetBuffer3f"));
|
||||
alGetBuffer3i = reinterpret_cast<NzOpenALDetail::LPALGETBUFFER3I>(LoadEntry("alGetBuffer3i"));
|
||||
alGetBufferf = reinterpret_cast<NzOpenALDetail::LPALGETBUFFERF>(LoadEntry("alGetBufferf"));
|
||||
alGetBufferfv = reinterpret_cast<NzOpenALDetail::LPALGETBUFFERFV>(LoadEntry("alGetBufferfv"));
|
||||
alGetBufferi = reinterpret_cast<NzOpenALDetail::LPALGETBUFFERI>(LoadEntry("alGetBufferi"));
|
||||
alGetBufferiv = reinterpret_cast<NzOpenALDetail::LPALGETBUFFERIV>(LoadEntry("alGetBufferiv"));
|
||||
alGetDouble = reinterpret_cast<NzOpenALDetail::LPALGETDOUBLE>(LoadEntry("alGetDouble"));
|
||||
alGetDoublev = reinterpret_cast<NzOpenALDetail::LPALGETDOUBLEV>(LoadEntry("alGetDoublev"));
|
||||
alGetEnumValue = reinterpret_cast<NzOpenALDetail::LPALGETENUMVALUE>(LoadEntry("alGetEnumValue"));
|
||||
alGetError = reinterpret_cast<NzOpenALDetail::LPALGETERROR>(LoadEntry("alGetError"));
|
||||
alGetFloat = reinterpret_cast<NzOpenALDetail::LPALGETFLOAT>(LoadEntry("alGetFloat"));
|
||||
alGetFloatv = reinterpret_cast<NzOpenALDetail::LPALGETFLOATV>(LoadEntry("alGetFloatv"));
|
||||
alGetInteger = reinterpret_cast<NzOpenALDetail::LPALGETINTEGER>(LoadEntry("alGetInteger"));
|
||||
alGetIntegerv = reinterpret_cast<NzOpenALDetail::LPALGETINTEGERV>(LoadEntry("alGetIntegerv"));
|
||||
alGetListener3f = reinterpret_cast<NzOpenALDetail::LPALGETLISTENER3F>(LoadEntry("alGetListener3f"));
|
||||
alGetListener3i = reinterpret_cast<NzOpenALDetail::LPALGETLISTENER3I>(LoadEntry("alGetListener3i"));
|
||||
alGetListenerf = reinterpret_cast<NzOpenALDetail::LPALGETLISTENERF>(LoadEntry("alGetListenerf"));
|
||||
alGetListenerfv = reinterpret_cast<NzOpenALDetail::LPALGETLISTENERFV>(LoadEntry("alGetListenerfv"));
|
||||
alGetListeneri = reinterpret_cast<NzOpenALDetail::LPALGETLISTENERI>(LoadEntry("alGetListeneri"));
|
||||
alGetListeneriv = reinterpret_cast<NzOpenALDetail::LPALGETLISTENERIV>(LoadEntry("alGetListeneriv"));
|
||||
alGetProcAddress = reinterpret_cast<NzOpenALDetail::LPALGETPROCADDRESS>(LoadEntry("alGetProcAddress"));
|
||||
alGetSource3f = reinterpret_cast<NzOpenALDetail::LPALGETSOURCE3F>(LoadEntry("alGetSource3f"));
|
||||
alGetSource3i = reinterpret_cast<NzOpenALDetail::LPALGETSOURCE3I>(LoadEntry("alGetSource3i"));
|
||||
alGetSourcef = reinterpret_cast<NzOpenALDetail::LPALGETSOURCEF>(LoadEntry("alGetSourcef"));
|
||||
alGetSourcefv = reinterpret_cast<NzOpenALDetail::LPALGETSOURCEFV>(LoadEntry("alGetSourcefv"));
|
||||
alGetSourcei = reinterpret_cast<NzOpenALDetail::LPALGETSOURCEI>(LoadEntry("alGetSourcei"));
|
||||
alGetSourceiv = reinterpret_cast<NzOpenALDetail::LPALGETSOURCEIV>(LoadEntry("alGetSourceiv"));
|
||||
alGetString = reinterpret_cast<NzOpenALDetail::LPALGETSTRING>(LoadEntry("alGetString"));
|
||||
alIsBuffer = reinterpret_cast<NzOpenALDetail::LPALISBUFFER>(LoadEntry("alIsBuffer"));
|
||||
alIsEnabled = reinterpret_cast<NzOpenALDetail::LPALISENABLED>(LoadEntry("alIsEnabled"));
|
||||
alIsExtensionPresent = reinterpret_cast<NzOpenALDetail::LPALISEXTENSIONPRESENT>(LoadEntry("alIsExtensionPresent"));
|
||||
alIsSource = reinterpret_cast<NzOpenALDetail::LPALISSOURCE>(LoadEntry("alIsSource"));
|
||||
alListener3f = reinterpret_cast<NzOpenALDetail::LPALLISTENER3F>(LoadEntry("alListener3f"));
|
||||
alListener3i = reinterpret_cast<NzOpenALDetail::LPALLISTENER3I>(LoadEntry("alListener3i"));
|
||||
alListenerf = reinterpret_cast<NzOpenALDetail::LPALLISTENERF>(LoadEntry("alListenerf"));
|
||||
alListenerfv = reinterpret_cast<NzOpenALDetail::LPALLISTENERFV>(LoadEntry("alListenerfv"));
|
||||
alListeneri = reinterpret_cast<NzOpenALDetail::LPALLISTENERI>(LoadEntry("alListeneri"));
|
||||
alListeneriv = reinterpret_cast<NzOpenALDetail::LPALLISTENERIV>(LoadEntry("alListeneriv"));
|
||||
alSource3f = reinterpret_cast<NzOpenALDetail::LPALSOURCE3F>(LoadEntry("alSource3f"));
|
||||
alSource3i = reinterpret_cast<NzOpenALDetail::LPALSOURCE3I>(LoadEntry("alSource3i"));
|
||||
alSourcef = reinterpret_cast<NzOpenALDetail::LPALSOURCEF>(LoadEntry("alSourcef"));
|
||||
alSourcefv = reinterpret_cast<NzOpenALDetail::LPALSOURCEFV>(LoadEntry("alSourcefv"));
|
||||
alSourcei = reinterpret_cast<NzOpenALDetail::LPALSOURCEI>(LoadEntry("alSourcei"));
|
||||
alSourceiv = reinterpret_cast<NzOpenALDetail::LPALSOURCEIV>(LoadEntry("alSourceiv"));
|
||||
alSourcePause = reinterpret_cast<NzOpenALDetail::LPALSOURCEPAUSE>(LoadEntry("alSourcePause"));
|
||||
alSourcePausev = reinterpret_cast<NzOpenALDetail::LPALSOURCEPAUSEV>(LoadEntry("alSourcePausev"));
|
||||
alSourcePlay = reinterpret_cast<NzOpenALDetail::LPALSOURCEPLAY>(LoadEntry("alSourcePlay"));
|
||||
alSourcePlayv = reinterpret_cast<NzOpenALDetail::LPALSOURCEPLAYV>(LoadEntry("alSourcePlayv"));
|
||||
alSourceQueueBuffers = reinterpret_cast<NzOpenALDetail::LPALSOURCEQUEUEBUFFERS>(LoadEntry("alSourceQueueBuffers"));
|
||||
alSourceRewind = reinterpret_cast<NzOpenALDetail::LPALSOURCEREWIND>(LoadEntry("alSourceRewind"));
|
||||
alSourceRewindv = reinterpret_cast<NzOpenALDetail::LPALSOURCEREWINDV>(LoadEntry("alSourceRewindv"));
|
||||
alSourceStop = reinterpret_cast<NzOpenALDetail::LPALSOURCESTOP>(LoadEntry("alSourceStop"));
|
||||
alSourceStopv = reinterpret_cast<NzOpenALDetail::LPALSOURCESTOPV>(LoadEntry("alSourceStopv"));
|
||||
alSourceUnqueueBuffers = reinterpret_cast<NzOpenALDetail::LPALSOURCEUNQUEUEBUFFERS>(LoadEntry("alSourceUnqueueBuffers"));
|
||||
alSpeedOfSound = reinterpret_cast<NzOpenALDetail::LPALSPEEDOFSOUND>(LoadEntry("alSpeedOfSound"));
|
||||
|
||||
// alc
|
||||
alcCaptureCloseDevice = reinterpret_cast<NzOpenALDetail::LPALCCAPTURECLOSEDEVICE>(LoadEntry("alcCaptureCloseDevice"));
|
||||
alcCaptureOpenDevice = reinterpret_cast<NzOpenALDetail::LPALCCAPTUREOPENDEVICE>(LoadEntry("alcCaptureOpenDevice"));
|
||||
alcCaptureSamples = reinterpret_cast<NzOpenALDetail::LPALCCAPTURESAMPLES>(LoadEntry("alcCaptureSamples"));
|
||||
alcCaptureStart = reinterpret_cast<NzOpenALDetail::LPALCCAPTURESTART>(LoadEntry("alcCaptureStart"));
|
||||
alcCaptureStop = reinterpret_cast<NzOpenALDetail::LPALCCAPTURESTOP>(LoadEntry("alcCaptureStop"));
|
||||
alcCloseDevice = reinterpret_cast<NzOpenALDetail::LPALCCLOSEDEVICE>(LoadEntry("alcCloseDevice"));
|
||||
alcCreateContext = reinterpret_cast<NzOpenALDetail::LPALCCREATECONTEXT>(LoadEntry("alcCreateContext"));
|
||||
alcDestroyContext = reinterpret_cast<NzOpenALDetail::LPALCDESTROYCONTEXT>(LoadEntry("alcDestroyContext"));
|
||||
alcGetContextsDevice = reinterpret_cast<NzOpenALDetail::LPALCGETCONTEXTSDEVICE>(LoadEntry("alcGetContextsDevice"));
|
||||
alcGetCurrentContext = reinterpret_cast<NzOpenALDetail::LPALCGETCURRENTCONTEXT>(LoadEntry("alcGetCurrentContext"));
|
||||
alcGetEnumValue = reinterpret_cast<NzOpenALDetail::LPALCGETENUMVALUE>(LoadEntry("alcGetEnumValue"));
|
||||
alcGetError = reinterpret_cast<NzOpenALDetail::LPALCGETERROR>(LoadEntry("alcGetError"));
|
||||
alcGetIntegerv = reinterpret_cast<NzOpenALDetail::LPALCGETINTEGERV>(LoadEntry("alcGetIntegerv"));
|
||||
alcGetProcAddress = reinterpret_cast<NzOpenALDetail::LPALCGETPROCADDRESS>(LoadEntry("alcGetProcAddress"));
|
||||
alcGetString = reinterpret_cast<NzOpenALDetail::LPALCGETSTRING>(LoadEntry("alcGetString"));
|
||||
alcIsExtensionPresent = reinterpret_cast<NzOpenALDetail::LPALCISEXTENSIONPRESENT>(LoadEntry("alcIsExtensionPresent"));
|
||||
alcMakeContextCurrent = reinterpret_cast<NzOpenALDetail::LPALCMAKECONTEXTCURRENT>(LoadEntry("alcMakeContextCurrent"));
|
||||
alcOpenDevice = reinterpret_cast<NzOpenALDetail::LPALCOPENDEVICE>(LoadEntry("alcOpenDevice"));
|
||||
alcProcessContext = reinterpret_cast<NzOpenALDetail::LPALCPROCESSCONTEXT>(LoadEntry("alcProcessContext"));
|
||||
alcSuspendContext = reinterpret_cast<NzOpenALDetail::LPALCSUSPENDCONTEXT>(LoadEntry("alcSuspendContext"));
|
||||
|
||||
succeeded = true;
|
||||
break;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
NazaraWarning(libPath + " loading failed: " + NzString(e.what()));
|
||||
continue;
|
||||
}
|
||||
return ParseDevices(deviceString, devices);
|
||||
}
|
||||
|
||||
if (!succeeded)
|
||||
bool OpenAL::SetDevice(const String& deviceName)
|
||||
{
|
||||
NazaraError("Failed to load OpenAL");
|
||||
Uninitialize();
|
||||
s_deviceName = deviceName;
|
||||
if (IsInitialized())
|
||||
{
|
||||
CloseDevice();
|
||||
|
||||
return false;
|
||||
return OpenDevice();
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
if (openDevice)
|
||||
OpenDevice();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzOpenAL::IsInitialized()
|
||||
{
|
||||
return s_library.IsLoaded();
|
||||
}
|
||||
|
||||
unsigned int NzOpenAL::QueryInputDevices(std::vector<NzString>& devices)
|
||||
{
|
||||
const char* deviceString = reinterpret_cast<const char*>(alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER));
|
||||
if (!deviceString)
|
||||
return 0;
|
||||
|
||||
return ParseDevices(deviceString, devices);
|
||||
}
|
||||
|
||||
unsigned int NzOpenAL::QueryOutputDevices(std::vector<NzString>& devices)
|
||||
{
|
||||
const char* deviceString = reinterpret_cast<const char*>(alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER));
|
||||
if (!deviceString)
|
||||
return 0;
|
||||
|
||||
return ParseDevices(deviceString, devices);
|
||||
}
|
||||
|
||||
bool NzOpenAL::SetDevice(const NzString& deviceName)
|
||||
{
|
||||
s_deviceName = deviceName;
|
||||
if (IsInitialized())
|
||||
void OpenAL::Uninitialize()
|
||||
{
|
||||
CloseDevice();
|
||||
|
||||
return OpenDevice();
|
||||
s_rendererName.Clear(false);
|
||||
s_vendorName.Clear(false);
|
||||
s_library.Unload();
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzOpenAL::Uninitialize()
|
||||
{
|
||||
CloseDevice();
|
||||
///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
|
||||
|
||||
s_rendererName.Clear(false);
|
||||
s_vendorName.Clear(false);
|
||||
s_library.Unload();
|
||||
}
|
||||
|
||||
///ATTENTION: La valeur entière est le nombre de canaux possédés par ce format
|
||||
ALenum NzOpenAL::AudioFormat[nzAudioFormat_Max+1] = {0}; // Valeur ajoutées au chargement d'OpenAL
|
||||
|
||||
void NzOpenAL::CloseDevice()
|
||||
{
|
||||
if (s_device)
|
||||
void OpenAL::CloseDevice()
|
||||
{
|
||||
if (s_context)
|
||||
if (s_device)
|
||||
{
|
||||
alcMakeContextCurrent(nullptr);
|
||||
alcDestroyContext(s_context);
|
||||
s_context = nullptr;
|
||||
}
|
||||
|
||||
if (!alcCloseDevice(s_device))
|
||||
// Nous n'avons pas pu fermer le device, ce qui signifie qu'il est en cours d'utilisation
|
||||
NazaraWarning("Failed to close device");
|
||||
|
||||
s_device = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool NzOpenAL::OpenDevice()
|
||||
{
|
||||
// Initialisation du module
|
||||
s_device = alcOpenDevice(s_deviceName.IsEmpty() ? nullptr : s_deviceName.GetConstBuffer()); // On choisit le device par défaut
|
||||
if (!s_device)
|
||||
{
|
||||
NazaraError("Failed to open default device");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Un seul contexte nous suffira
|
||||
s_context = alcCreateContext(s_device, nullptr);
|
||||
if (!s_context)
|
||||
{
|
||||
NazaraError("Failed to create context");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!alcMakeContextCurrent(s_context))
|
||||
{
|
||||
NazaraError("Failed to activate context");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_rendererName = reinterpret_cast<const char*>(alGetString(AL_RENDERER));
|
||||
s_vendorName = reinterpret_cast<const char*>(alGetString(AL_VENDOR));
|
||||
|
||||
const ALchar* version = alGetString(AL_VERSION);
|
||||
if (version)
|
||||
{
|
||||
unsigned int major = version[0] - '0';
|
||||
unsigned int minor = version[2] - '0';
|
||||
|
||||
if (major != 0 && major <= 9)
|
||||
{
|
||||
if (minor > 9)
|
||||
if (s_context)
|
||||
{
|
||||
NazaraWarning("Unable to retrieve OpenAL minor version (using 0)");
|
||||
minor = 0;
|
||||
alcMakeContextCurrent(nullptr);
|
||||
alcDestroyContext(s_context);
|
||||
s_context = nullptr;
|
||||
}
|
||||
|
||||
s_version = major*100 + minor*10;
|
||||
if (!alcCloseDevice(s_device))
|
||||
// Nous n'avons pas pu fermer le device, ce qui signifie qu'il est en cours d'utilisation
|
||||
NazaraWarning("Failed to close device");
|
||||
|
||||
NazaraDebug("OpenAL version: " + NzString::Number(major) + '.' + NzString::Number(minor));
|
||||
s_device = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenAL::OpenDevice()
|
||||
{
|
||||
// Initialisation du module
|
||||
s_device = alcOpenDevice(s_deviceName.IsEmpty() ? nullptr : s_deviceName.GetConstBuffer()); // On choisit le device par défaut
|
||||
if (!s_device)
|
||||
{
|
||||
NazaraError("Failed to open default device");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Un seul contexte nous suffira
|
||||
s_context = alcCreateContext(s_device, nullptr);
|
||||
if (!s_context)
|
||||
{
|
||||
NazaraError("Failed to create context");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!alcMakeContextCurrent(s_context))
|
||||
{
|
||||
NazaraError("Failed to activate context");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_rendererName = reinterpret_cast<const char*>(alGetString(AL_RENDERER));
|
||||
s_vendorName = reinterpret_cast<const char*>(alGetString(AL_VENDOR));
|
||||
|
||||
const ALchar* version = alGetString(AL_VERSION);
|
||||
if (version)
|
||||
{
|
||||
unsigned int major = version[0] - '0';
|
||||
unsigned int minor = version[2] - '0';
|
||||
|
||||
if (major != 0 && major <= 9)
|
||||
{
|
||||
if (minor > 9)
|
||||
{
|
||||
NazaraWarning("Unable to retrieve OpenAL minor version (using 0)");
|
||||
minor = 0;
|
||||
}
|
||||
|
||||
s_version = major*100 + minor*10;
|
||||
|
||||
NazaraDebug("OpenAL version: " + String::Number(major) + '.' + String::Number(minor));
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraDebug("Unable to retrieve OpenAL major version");
|
||||
s_version = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraDebug("Unable to retrieve OpenAL major version");
|
||||
NazaraDebug("Unable to retrieve OpenAL version");
|
||||
s_version = 0;
|
||||
}
|
||||
|
||||
// On complète le tableau de formats
|
||||
AudioFormat[AudioFormat_Mono] = AL_FORMAT_MONO16;
|
||||
AudioFormat[AudioFormat_Stereo] = AL_FORMAT_STEREO16;
|
||||
|
||||
// "The presence of an enum value does not guarantee the applicability of an extension to the current context."
|
||||
if (alIsExtensionPresent("AL_EXT_MCFORMATS"))
|
||||
{
|
||||
AudioFormat[AudioFormat_Quad] = alGetEnumValue("AL_FORMAT_QUAD16");
|
||||
AudioFormat[AudioFormat_5_1] = alGetEnumValue("AL_FORMAT_51CHN16");
|
||||
AudioFormat[AudioFormat_6_1] = alGetEnumValue("AL_FORMAT_61CHN16");
|
||||
AudioFormat[AudioFormat_7_1] = alGetEnumValue("AL_FORMAT_71CHN16");
|
||||
}
|
||||
else if (alIsExtensionPresent("AL_LOKI_quadriphonic"))
|
||||
AudioFormat[AudioFormat_Quad] = alGetEnumValue("AL_FORMAT_QUAD16_LOKI");
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
||||
OpenALFunc OpenAL::LoadEntry(const char* name, bool throwException)
|
||||
{
|
||||
NazaraDebug("Unable to retrieve OpenAL version");
|
||||
s_version = 0;
|
||||
OpenALFunc entry = reinterpret_cast<OpenALFunc>(s_library.GetSymbol(name));
|
||||
if (!entry && throwException)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "failed to load \"" << name << '"';
|
||||
|
||||
throw std::runtime_error(oss.str());
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
// On complète le tableau de formats
|
||||
AudioFormat[nzAudioFormat_Mono] = AL_FORMAT_MONO16;
|
||||
AudioFormat[nzAudioFormat_Stereo] = AL_FORMAT_STEREO16;
|
||||
|
||||
// "The presence of an enum value does not guarantee the applicability of an extension to the current context."
|
||||
if (alIsExtensionPresent("AL_EXT_MCFORMATS"))
|
||||
{
|
||||
AudioFormat[nzAudioFormat_Quad] = alGetEnumValue("AL_FORMAT_QUAD16");
|
||||
AudioFormat[nzAudioFormat_5_1] = alGetEnumValue("AL_FORMAT_51CHN16");
|
||||
AudioFormat[nzAudioFormat_6_1] = alGetEnumValue("AL_FORMAT_61CHN16");
|
||||
AudioFormat[nzAudioFormat_7_1] = alGetEnumValue("AL_FORMAT_71CHN16");
|
||||
}
|
||||
else if (alIsExtensionPresent("AL_LOKI_quadriphonic"))
|
||||
AudioFormat[nzAudioFormat_Quad] = alGetEnumValue("AL_FORMAT_QUAD16_LOKI");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NzOpenALFunc NzOpenAL::LoadEntry(const char* name, bool throwException)
|
||||
{
|
||||
NzOpenALFunc entry = reinterpret_cast<NzOpenALFunc>(s_library.GetSymbol(name));
|
||||
if (!entry && throwException)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "failed to load \"" << name << '"';
|
||||
|
||||
throw std::runtime_error(oss.str());
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
// al
|
||||
NzOpenALDetail::LPALBUFFER3F alBuffer3f = nullptr;
|
||||
NzOpenALDetail::LPALBUFFER3I alBuffer3i = nullptr;
|
||||
NzOpenALDetail::LPALBUFFERDATA alBufferData = nullptr;
|
||||
NzOpenALDetail::LPALBUFFERF alBufferf = nullptr;
|
||||
NzOpenALDetail::LPALBUFFERFV alBufferfv = nullptr;
|
||||
NzOpenALDetail::LPALBUFFERI alBufferi = nullptr;
|
||||
NzOpenALDetail::LPALBUFFERIV alBufferiv = nullptr;
|
||||
NzOpenALDetail::LPALDELETEBUFFERS alDeleteBuffers = nullptr;
|
||||
NzOpenALDetail::LPALDELETESOURCES alDeleteSources = nullptr;
|
||||
NzOpenALDetail::LPALDISABLE alDisable = nullptr;
|
||||
NzOpenALDetail::LPALDISTANCEMODEL alDistanceModel = nullptr;
|
||||
NzOpenALDetail::LPALDOPPLERFACTOR alDopplerFactor = nullptr;
|
||||
NzOpenALDetail::LPALDOPPLERVELOCITY alDopplerVelocity = nullptr;
|
||||
NzOpenALDetail::LPALENABLE alEnable = nullptr;
|
||||
NzOpenALDetail::LPALGENBUFFERS alGenBuffers = nullptr;
|
||||
NzOpenALDetail::LPALGENSOURCES alGenSources = nullptr;
|
||||
NzOpenALDetail::LPALGETBOOLEAN alGetBoolean = nullptr;
|
||||
NzOpenALDetail::LPALGETBOOLEANV alGetBooleanv = nullptr;
|
||||
NzOpenALDetail::LPALGETBUFFER3F alGetBuffer3f = nullptr;
|
||||
NzOpenALDetail::LPALGETBUFFER3I alGetBuffer3i = nullptr;
|
||||
NzOpenALDetail::LPALGETBUFFERF alGetBufferf = nullptr;
|
||||
NzOpenALDetail::LPALGETBUFFERFV alGetBufferfv = nullptr;
|
||||
NzOpenALDetail::LPALGETBUFFERI alGetBufferi = nullptr;
|
||||
NzOpenALDetail::LPALGETBUFFERIV alGetBufferiv = nullptr;
|
||||
NzOpenALDetail::LPALGETDOUBLE alGetDouble = nullptr;
|
||||
NzOpenALDetail::LPALGETDOUBLEV alGetDoublev = nullptr;
|
||||
NzOpenALDetail::LPALGETENUMVALUE alGetEnumValue = nullptr;
|
||||
NzOpenALDetail::LPALGETERROR alGetError = nullptr;
|
||||
NzOpenALDetail::LPALGETFLOAT alGetFloat = nullptr;
|
||||
NzOpenALDetail::LPALGETFLOATV alGetFloatv = nullptr;
|
||||
NzOpenALDetail::LPALGETINTEGER alGetInteger = nullptr;
|
||||
NzOpenALDetail::LPALGETINTEGERV alGetIntegerv = nullptr;
|
||||
NzOpenALDetail::LPALGETLISTENER3F alGetListener3f = nullptr;
|
||||
NzOpenALDetail::LPALGETLISTENER3I alGetListener3i = nullptr;
|
||||
NzOpenALDetail::LPALGETLISTENERF alGetListenerf = nullptr;
|
||||
NzOpenALDetail::LPALGETLISTENERFV alGetListenerfv = nullptr;
|
||||
NzOpenALDetail::LPALGETLISTENERI alGetListeneri = nullptr;
|
||||
NzOpenALDetail::LPALGETLISTENERIV alGetListeneriv = nullptr;
|
||||
NzOpenALDetail::LPALGETPROCADDRESS alGetProcAddress = nullptr;
|
||||
NzOpenALDetail::LPALGETSOURCE3F alGetSource3f = nullptr;
|
||||
NzOpenALDetail::LPALGETSOURCE3I alGetSource3i = nullptr;
|
||||
NzOpenALDetail::LPALGETSOURCEF alGetSourcef = nullptr;
|
||||
NzOpenALDetail::LPALGETSOURCEFV alGetSourcefv = nullptr;
|
||||
NzOpenALDetail::LPALGETSOURCEI alGetSourcei = nullptr;
|
||||
NzOpenALDetail::LPALGETSOURCEIV alGetSourceiv = nullptr;
|
||||
NzOpenALDetail::LPALGETSTRING alGetString = nullptr;
|
||||
NzOpenALDetail::LPALISBUFFER alIsBuffer = nullptr;
|
||||
NzOpenALDetail::LPALISENABLED alIsEnabled = nullptr;
|
||||
NzOpenALDetail::LPALISEXTENSIONPRESENT alIsExtensionPresent = nullptr;
|
||||
NzOpenALDetail::LPALISSOURCE alIsSource = nullptr;
|
||||
NzOpenALDetail::LPALLISTENER3F alListener3f = nullptr;
|
||||
NzOpenALDetail::LPALLISTENER3I alListener3i = nullptr;
|
||||
NzOpenALDetail::LPALLISTENERF alListenerf = nullptr;
|
||||
NzOpenALDetail::LPALLISTENERFV alListenerfv = nullptr;
|
||||
NzOpenALDetail::LPALLISTENERI alListeneri = nullptr;
|
||||
NzOpenALDetail::LPALLISTENERIV alListeneriv = nullptr;
|
||||
NzOpenALDetail::LPALSOURCE3F alSource3f = nullptr;
|
||||
NzOpenALDetail::LPALSOURCE3I alSource3i = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEF alSourcef = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEFV alSourcefv = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEI alSourcei = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEIV alSourceiv = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEPAUSE alSourcePause = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEPAUSEV alSourcePausev = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEPLAY alSourcePlay = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEPLAYV alSourcePlayv = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEQUEUEBUFFERS alSourceQueueBuffers = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEREWIND alSourceRewind = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEREWINDV alSourceRewindv = nullptr;
|
||||
NzOpenALDetail::LPALSOURCESTOP alSourceStop = nullptr;
|
||||
NzOpenALDetail::LPALSOURCESTOPV alSourceStopv = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEUNQUEUEBUFFERS alSourceUnqueueBuffers = nullptr;
|
||||
NzOpenALDetail::LPALSPEEDOFSOUND alSpeedOfSound = nullptr;
|
||||
OpenALDetail::LPALBUFFER3F alBuffer3f = nullptr;
|
||||
OpenALDetail::LPALBUFFER3I alBuffer3i = nullptr;
|
||||
OpenALDetail::LPALBUFFERDATA alBufferData = nullptr;
|
||||
OpenALDetail::LPALBUFFERF alBufferf = nullptr;
|
||||
OpenALDetail::LPALBUFFERFV alBufferfv = nullptr;
|
||||
OpenALDetail::LPALBUFFERI alBufferi = nullptr;
|
||||
OpenALDetail::LPALBUFFERIV alBufferiv = nullptr;
|
||||
OpenALDetail::LPALDELETEBUFFERS alDeleteBuffers = nullptr;
|
||||
OpenALDetail::LPALDELETESOURCES alDeleteSources = nullptr;
|
||||
OpenALDetail::LPALDISABLE alDisable = nullptr;
|
||||
OpenALDetail::LPALDISTANCEMODEL alDistanceModel = nullptr;
|
||||
OpenALDetail::LPALDOPPLERFACTOR alDopplerFactor = nullptr;
|
||||
OpenALDetail::LPALDOPPLERVELOCITY alDopplerVelocity = nullptr;
|
||||
OpenALDetail::LPALENABLE alEnable = nullptr;
|
||||
OpenALDetail::LPALGENBUFFERS alGenBuffers = nullptr;
|
||||
OpenALDetail::LPALGENSOURCES alGenSources = nullptr;
|
||||
OpenALDetail::LPALGETBOOLEAN alGetBoolean = nullptr;
|
||||
OpenALDetail::LPALGETBOOLEANV alGetBooleanv = nullptr;
|
||||
OpenALDetail::LPALGETBUFFER3F alGetBuffer3f = nullptr;
|
||||
OpenALDetail::LPALGETBUFFER3I alGetBuffer3i = nullptr;
|
||||
OpenALDetail::LPALGETBUFFERF alGetBufferf = nullptr;
|
||||
OpenALDetail::LPALGETBUFFERFV alGetBufferfv = nullptr;
|
||||
OpenALDetail::LPALGETBUFFERI alGetBufferi = nullptr;
|
||||
OpenALDetail::LPALGETBUFFERIV alGetBufferiv = nullptr;
|
||||
OpenALDetail::LPALGETDOUBLE alGetDouble = nullptr;
|
||||
OpenALDetail::LPALGETDOUBLEV alGetDoublev = nullptr;
|
||||
OpenALDetail::LPALGETENUMVALUE alGetEnumValue = nullptr;
|
||||
OpenALDetail::LPALGETERROR alGetError = nullptr;
|
||||
OpenALDetail::LPALGETFLOAT alGetFloat = nullptr;
|
||||
OpenALDetail::LPALGETFLOATV alGetFloatv = nullptr;
|
||||
OpenALDetail::LPALGETINTEGER alGetInteger = nullptr;
|
||||
OpenALDetail::LPALGETINTEGERV alGetIntegerv = nullptr;
|
||||
OpenALDetail::LPALGETLISTENER3F alGetListener3f = nullptr;
|
||||
OpenALDetail::LPALGETLISTENER3I alGetListener3i = nullptr;
|
||||
OpenALDetail::LPALGETLISTENERF alGetListenerf = nullptr;
|
||||
OpenALDetail::LPALGETLISTENERFV alGetListenerfv = nullptr;
|
||||
OpenALDetail::LPALGETLISTENERI alGetListeneri = nullptr;
|
||||
OpenALDetail::LPALGETLISTENERIV alGetListeneriv = nullptr;
|
||||
OpenALDetail::LPALGETPROCADDRESS alGetProcAddress = nullptr;
|
||||
OpenALDetail::LPALGETSOURCE3F alGetSource3f = nullptr;
|
||||
OpenALDetail::LPALGETSOURCE3I alGetSource3i = nullptr;
|
||||
OpenALDetail::LPALGETSOURCEF alGetSourcef = nullptr;
|
||||
OpenALDetail::LPALGETSOURCEFV alGetSourcefv = nullptr;
|
||||
OpenALDetail::LPALGETSOURCEI alGetSourcei = nullptr;
|
||||
OpenALDetail::LPALGETSOURCEIV alGetSourceiv = nullptr;
|
||||
OpenALDetail::LPALGETSTRING alGetString = nullptr;
|
||||
OpenALDetail::LPALISBUFFER alIsBuffer = nullptr;
|
||||
OpenALDetail::LPALISENABLED alIsEnabled = nullptr;
|
||||
OpenALDetail::LPALISEXTENSIONPRESENT alIsExtensionPresent = nullptr;
|
||||
OpenALDetail::LPALISSOURCE alIsSource = nullptr;
|
||||
OpenALDetail::LPALLISTENER3F alListener3f = nullptr;
|
||||
OpenALDetail::LPALLISTENER3I alListener3i = nullptr;
|
||||
OpenALDetail::LPALLISTENERF alListenerf = nullptr;
|
||||
OpenALDetail::LPALLISTENERFV alListenerfv = nullptr;
|
||||
OpenALDetail::LPALLISTENERI alListeneri = nullptr;
|
||||
OpenALDetail::LPALLISTENERIV alListeneriv = nullptr;
|
||||
OpenALDetail::LPALSOURCE3F alSource3f = nullptr;
|
||||
OpenALDetail::LPALSOURCE3I alSource3i = nullptr;
|
||||
OpenALDetail::LPALSOURCEF alSourcef = nullptr;
|
||||
OpenALDetail::LPALSOURCEFV alSourcefv = nullptr;
|
||||
OpenALDetail::LPALSOURCEI alSourcei = nullptr;
|
||||
OpenALDetail::LPALSOURCEIV alSourceiv = nullptr;
|
||||
OpenALDetail::LPALSOURCEPAUSE alSourcePause = nullptr;
|
||||
OpenALDetail::LPALSOURCEPAUSEV alSourcePausev = nullptr;
|
||||
OpenALDetail::LPALSOURCEPLAY alSourcePlay = nullptr;
|
||||
OpenALDetail::LPALSOURCEPLAYV alSourcePlayv = nullptr;
|
||||
OpenALDetail::LPALSOURCEQUEUEBUFFERS alSourceQueueBuffers = nullptr;
|
||||
OpenALDetail::LPALSOURCEREWIND alSourceRewind = nullptr;
|
||||
OpenALDetail::LPALSOURCEREWINDV alSourceRewindv = nullptr;
|
||||
OpenALDetail::LPALSOURCESTOP alSourceStop = nullptr;
|
||||
OpenALDetail::LPALSOURCESTOPV alSourceStopv = nullptr;
|
||||
OpenALDetail::LPALSOURCEUNQUEUEBUFFERS alSourceUnqueueBuffers = nullptr;
|
||||
OpenALDetail::LPALSPEEDOFSOUND alSpeedOfSound = nullptr;
|
||||
|
||||
// alc
|
||||
NzOpenALDetail::LPALCCAPTURECLOSEDEVICE alcCaptureCloseDevice = nullptr;
|
||||
NzOpenALDetail::LPALCCAPTUREOPENDEVICE alcCaptureOpenDevice = nullptr;
|
||||
NzOpenALDetail::LPALCCAPTURESAMPLES alcCaptureSamples = nullptr;
|
||||
NzOpenALDetail::LPALCCAPTURESTART alcCaptureStart = nullptr;
|
||||
NzOpenALDetail::LPALCCAPTURESTOP alcCaptureStop = nullptr;
|
||||
NzOpenALDetail::LPALCCLOSEDEVICE alcCloseDevice = nullptr;
|
||||
NzOpenALDetail::LPALCCREATECONTEXT alcCreateContext = nullptr;
|
||||
NzOpenALDetail::LPALCDESTROYCONTEXT alcDestroyContext = nullptr;
|
||||
NzOpenALDetail::LPALCGETCONTEXTSDEVICE alcGetContextsDevice = nullptr;
|
||||
NzOpenALDetail::LPALCGETCURRENTCONTEXT alcGetCurrentContext = nullptr;
|
||||
NzOpenALDetail::LPALCGETENUMVALUE alcGetEnumValue = nullptr;
|
||||
NzOpenALDetail::LPALCGETERROR alcGetError = nullptr;
|
||||
NzOpenALDetail::LPALCGETINTEGERV alcGetIntegerv = nullptr;
|
||||
NzOpenALDetail::LPALCGETPROCADDRESS alcGetProcAddress = nullptr;
|
||||
NzOpenALDetail::LPALCGETSTRING alcGetString = nullptr;
|
||||
NzOpenALDetail::LPALCISEXTENSIONPRESENT alcIsExtensionPresent = nullptr;
|
||||
NzOpenALDetail::LPALCMAKECONTEXTCURRENT alcMakeContextCurrent = nullptr;
|
||||
NzOpenALDetail::LPALCOPENDEVICE alcOpenDevice = nullptr;
|
||||
NzOpenALDetail::LPALCPROCESSCONTEXT alcProcessContext = nullptr;
|
||||
NzOpenALDetail::LPALCSUSPENDCONTEXT alcSuspendContext = nullptr;
|
||||
OpenALDetail::LPALCCAPTURECLOSEDEVICE alcCaptureCloseDevice = nullptr;
|
||||
OpenALDetail::LPALCCAPTUREOPENDEVICE alcCaptureOpenDevice = nullptr;
|
||||
OpenALDetail::LPALCCAPTURESAMPLES alcCaptureSamples = nullptr;
|
||||
OpenALDetail::LPALCCAPTURESTART alcCaptureStart = nullptr;
|
||||
OpenALDetail::LPALCCAPTURESTOP alcCaptureStop = nullptr;
|
||||
OpenALDetail::LPALCCLOSEDEVICE alcCloseDevice = nullptr;
|
||||
OpenALDetail::LPALCCREATECONTEXT alcCreateContext = nullptr;
|
||||
OpenALDetail::LPALCDESTROYCONTEXT alcDestroyContext = nullptr;
|
||||
OpenALDetail::LPALCGETCONTEXTSDEVICE alcGetContextsDevice = nullptr;
|
||||
OpenALDetail::LPALCGETCURRENTCONTEXT alcGetCurrentContext = nullptr;
|
||||
OpenALDetail::LPALCGETENUMVALUE alcGetEnumValue = nullptr;
|
||||
OpenALDetail::LPALCGETERROR alcGetError = nullptr;
|
||||
OpenALDetail::LPALCGETINTEGERV alcGetIntegerv = nullptr;
|
||||
OpenALDetail::LPALCGETPROCADDRESS alcGetProcAddress = nullptr;
|
||||
OpenALDetail::LPALCGETSTRING alcGetString = nullptr;
|
||||
OpenALDetail::LPALCISEXTENSIONPRESENT alcIsExtensionPresent = nullptr;
|
||||
OpenALDetail::LPALCMAKECONTEXTCURRENT alcMakeContextCurrent = nullptr;
|
||||
OpenALDetail::LPALCOPENDEVICE alcOpenDevice = nullptr;
|
||||
OpenALDetail::LPALCPROCESSCONTEXT alcProcessContext = nullptr;
|
||||
OpenALDetail::LPALCSUSPENDCONTEXT alcSuspendContext = nullptr;
|
||||
|
||||
@@ -12,162 +12,165 @@
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
NzSound::NzSound(const NzSoundBuffer* soundBuffer)
|
||||
namespace Nz
|
||||
{
|
||||
SetBuffer(soundBuffer);
|
||||
}
|
||||
|
||||
NzSound::NzSound(const NzSound& sound) :
|
||||
NzSoundEmitter(sound)
|
||||
{
|
||||
SetBuffer(sound.m_buffer);
|
||||
}
|
||||
|
||||
NzSound::~NzSound()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
void NzSound::EnableLooping(bool loop)
|
||||
{
|
||||
alSourcei(m_source, AL_LOOPING, loop);
|
||||
}
|
||||
|
||||
const NzSoundBuffer* NzSound::GetBuffer() const
|
||||
{
|
||||
return m_buffer;
|
||||
}
|
||||
|
||||
nzUInt32 NzSound::GetDuration() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_buffer)
|
||||
Sound::Sound(const SoundBuffer* soundBuffer)
|
||||
{
|
||||
NazaraError("Invalid sound buffer");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_buffer->GetDuration();
|
||||
}
|
||||
|
||||
nzUInt32 NzSound::GetPlayingOffset() const
|
||||
{
|
||||
ALfloat seconds = -1.f;
|
||||
alGetSourcef(m_source, AL_SEC_OFFSET, &seconds);
|
||||
|
||||
return static_cast<nzUInt32>(seconds*1000);
|
||||
}
|
||||
|
||||
nzSoundStatus NzSound::GetStatus() const
|
||||
{
|
||||
return GetInternalStatus();
|
||||
}
|
||||
|
||||
bool NzSound::IsLooping() const
|
||||
{
|
||||
ALint loop;
|
||||
alGetSourcei(m_source, AL_LOOPING, &loop);
|
||||
|
||||
return loop != AL_FALSE;
|
||||
}
|
||||
|
||||
bool NzSound::IsPlayable() const
|
||||
{
|
||||
return m_buffer != nullptr;
|
||||
}
|
||||
|
||||
bool NzSound::IsPlaying() const
|
||||
{
|
||||
return GetStatus() == nzSoundStatus_Playing;
|
||||
}
|
||||
|
||||
bool NzSound::LoadFromFile(const NzString& filePath, const NzSoundBufferParams& params)
|
||||
{
|
||||
NzSoundBufferRef buffer = NzSoundBuffer::New();
|
||||
if (!buffer->LoadFromFile(filePath, params))
|
||||
{
|
||||
NazaraError("Failed to load buffer from file (" + filePath + ')');
|
||||
return false;
|
||||
SetBuffer(soundBuffer);
|
||||
}
|
||||
|
||||
SetBuffer(buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzSound::LoadFromMemory(const void* data, std::size_t size, const NzSoundBufferParams& params)
|
||||
{
|
||||
NzSoundBufferRef buffer = NzSoundBuffer::New();
|
||||
if (!buffer->LoadFromMemory(data, size, params))
|
||||
Sound::Sound(const Sound& sound) :
|
||||
SoundEmitter(sound)
|
||||
{
|
||||
NazaraError("Failed to load buffer from memory (" + NzString::Pointer(data) + ')');
|
||||
return false;
|
||||
SetBuffer(sound.m_buffer);
|
||||
}
|
||||
|
||||
SetBuffer(buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzSound::LoadFromStream(NzInputStream& stream, const NzSoundBufferParams& params)
|
||||
{
|
||||
NzSoundBufferRef buffer = NzSoundBuffer::New();
|
||||
if (!buffer->LoadFromStream(stream, params))
|
||||
Sound::~Sound()
|
||||
{
|
||||
NazaraError("Failed to load buffer from stream");
|
||||
return false;
|
||||
Stop();
|
||||
}
|
||||
|
||||
SetBuffer(buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzSound::Pause()
|
||||
{
|
||||
alSourcePause(m_source);
|
||||
}
|
||||
|
||||
void NzSound::Play()
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_buffer)
|
||||
void Sound::EnableLooping(bool loop)
|
||||
{
|
||||
NazaraError("Invalid sound buffer");
|
||||
return;
|
||||
alSourcei(m_source, AL_LOOPING, loop);
|
||||
}
|
||||
#endif
|
||||
|
||||
alSourcePlay(m_source);
|
||||
}
|
||||
|
||||
void NzSound::SetBuffer(const NzSoundBuffer* buffer)
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (buffer && !buffer->IsValid())
|
||||
const SoundBuffer* Sound::GetBuffer() const
|
||||
{
|
||||
NazaraError("Invalid sound buffer");
|
||||
return;
|
||||
return m_buffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_buffer == buffer)
|
||||
return;
|
||||
UInt32 Sound::GetDuration() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_buffer)
|
||||
{
|
||||
NazaraError("Invalid sound buffer");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
Stop();
|
||||
return m_buffer->GetDuration();
|
||||
}
|
||||
|
||||
m_buffer = buffer;
|
||||
UInt32 Sound::GetPlayingOffset() const
|
||||
{
|
||||
ALfloat seconds = -1.f;
|
||||
alGetSourcef(m_source, AL_SEC_OFFSET, &seconds);
|
||||
|
||||
if (m_buffer)
|
||||
alSourcei(m_source, AL_BUFFER, m_buffer->GetOpenALBuffer());
|
||||
else
|
||||
alSourcei(m_source, AL_BUFFER, AL_NONE);
|
||||
}
|
||||
|
||||
void NzSound::SetPlayingOffset(nzUInt32 offset)
|
||||
{
|
||||
alSourcef(m_source, AL_SEC_OFFSET, offset/1000.f);
|
||||
}
|
||||
|
||||
void NzSound::Stop()
|
||||
{
|
||||
alSourceStop(m_source);
|
||||
return static_cast<UInt32>(seconds*1000);
|
||||
}
|
||||
|
||||
SoundStatus Sound::GetStatus() const
|
||||
{
|
||||
return GetInternalStatus();
|
||||
}
|
||||
|
||||
bool Sound::IsLooping() const
|
||||
{
|
||||
ALint loop;
|
||||
alGetSourcei(m_source, AL_LOOPING, &loop);
|
||||
|
||||
return loop != AL_FALSE;
|
||||
}
|
||||
|
||||
bool Sound::IsPlayable() const
|
||||
{
|
||||
return m_buffer != nullptr;
|
||||
}
|
||||
|
||||
bool Sound::IsPlaying() const
|
||||
{
|
||||
return GetStatus() == SoundStatus_Playing;
|
||||
}
|
||||
|
||||
bool Sound::LoadFromFile(const String& filePath, const SoundBufferParams& params)
|
||||
{
|
||||
SoundBufferRef buffer = SoundBuffer::New();
|
||||
if (!buffer->LoadFromFile(filePath, params))
|
||||
{
|
||||
NazaraError("Failed to load buffer from file (" + filePath + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
SetBuffer(buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sound::LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params)
|
||||
{
|
||||
SoundBufferRef buffer = SoundBuffer::New();
|
||||
if (!buffer->LoadFromMemory(data, size, params))
|
||||
{
|
||||
NazaraError("Failed to load buffer from memory (" + String::Pointer(data) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
SetBuffer(buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sound::LoadFromStream(InputStream& stream, const SoundBufferParams& params)
|
||||
{
|
||||
SoundBufferRef buffer = SoundBuffer::New();
|
||||
if (!buffer->LoadFromStream(stream, params))
|
||||
{
|
||||
NazaraError("Failed to load buffer from stream");
|
||||
return false;
|
||||
}
|
||||
|
||||
SetBuffer(buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sound::Pause()
|
||||
{
|
||||
alSourcePause(m_source);
|
||||
}
|
||||
|
||||
void Sound::Play()
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_buffer)
|
||||
{
|
||||
NazaraError("Invalid sound buffer");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
alSourcePlay(m_source);
|
||||
}
|
||||
|
||||
void Sound::SetBuffer(const SoundBuffer* buffer)
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (buffer && !buffer->IsValid())
|
||||
{
|
||||
NazaraError("Invalid sound buffer");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_buffer == buffer)
|
||||
return;
|
||||
|
||||
Stop();
|
||||
|
||||
m_buffer = buffer;
|
||||
|
||||
if (m_buffer)
|
||||
alSourcei(m_source, AL_BUFFER, m_buffer->GetOpenALBuffer());
|
||||
else
|
||||
alSourcei(m_source, AL_BUFFER, AL_NONE);
|
||||
}
|
||||
|
||||
void Sound::SetPlayingOffset(UInt32 offset)
|
||||
{
|
||||
alSourcef(m_source, AL_SEC_OFFSET, offset/1000.f);
|
||||
}
|
||||
|
||||
void Sound::Stop()
|
||||
{
|
||||
alSourceStop(m_source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,243 +14,246 @@
|
||||
|
||||
///FIXME: Adapter la création
|
||||
|
||||
bool NzSoundBufferParams::IsValid() const
|
||||
namespace Nz
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
struct NzSoundBufferImpl
|
||||
{
|
||||
ALuint buffer;
|
||||
nzAudioFormat format;
|
||||
nzUInt32 duration;
|
||||
std::unique_ptr<nzInt16[]> samples;
|
||||
nzUInt32 sampleCount;
|
||||
nzUInt32 sampleRate;
|
||||
};
|
||||
|
||||
NzSoundBuffer::NzSoundBuffer(nzAudioFormat format, unsigned int sampleCount, unsigned int sampleRate, const nzInt16* samples)
|
||||
{
|
||||
Create(format, sampleCount, sampleRate, samples);
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_impl)
|
||||
bool SoundBufferParams::IsValid() const
|
||||
{
|
||||
NazaraError("Failed to create sound buffer");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
NzSoundBuffer::~NzSoundBuffer()
|
||||
{
|
||||
OnSoundBufferRelease(this);
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NzSoundBuffer::Create(nzAudioFormat format, unsigned int sampleCount, unsigned int sampleRate, const nzInt16* samples)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!IsFormatSupported(format))
|
||||
{
|
||||
NazaraError("Audio format is not supported");
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sampleCount == 0)
|
||||
struct SoundBufferImpl
|
||||
{
|
||||
NazaraError("Sample rate must be different from zero");
|
||||
return false;
|
||||
ALuint buffer;
|
||||
AudioFormat format;
|
||||
UInt32 duration;
|
||||
std::unique_ptr<Int16[]> samples;
|
||||
UInt32 sampleCount;
|
||||
UInt32 sampleRate;
|
||||
};
|
||||
|
||||
SoundBuffer::SoundBuffer(AudioFormat format, unsigned int sampleCount, unsigned int sampleRate, const Int16* samples)
|
||||
{
|
||||
Create(format, sampleCount, sampleRate, samples);
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Failed to create sound buffer");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (sampleRate == 0)
|
||||
SoundBuffer::~SoundBuffer()
|
||||
{
|
||||
NazaraError("Sample rate must be different from zero");
|
||||
return false;
|
||||
OnSoundBufferRelease(this);
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
if (!samples)
|
||||
bool SoundBuffer::Create(AudioFormat format, unsigned int sampleCount, unsigned int sampleRate, const Int16* samples)
|
||||
{
|
||||
NazaraError("Invalid sample source");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
Destroy();
|
||||
|
||||
// On vide le stack d'erreurs
|
||||
while (alGetError() != AL_NO_ERROR);
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!IsFormatSupported(format))
|
||||
{
|
||||
NazaraError("Audio format is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
ALuint buffer;
|
||||
alGenBuffers(1, &buffer);
|
||||
if (sampleCount == 0)
|
||||
{
|
||||
NazaraError("Sample rate must be different from zero");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (alGetError() != AL_NO_ERROR)
|
||||
{
|
||||
NazaraError("Failed to create OpenAL buffer");
|
||||
return false;
|
||||
if (sampleRate == 0)
|
||||
{
|
||||
NazaraError("Sample rate must be different from zero");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!samples)
|
||||
{
|
||||
NazaraError("Invalid sample source");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// On vide le stack d'erreurs
|
||||
while (alGetError() != AL_NO_ERROR);
|
||||
|
||||
ALuint buffer;
|
||||
alGenBuffers(1, &buffer);
|
||||
|
||||
if (alGetError() != AL_NO_ERROR)
|
||||
{
|
||||
NazaraError("Failed to create OpenAL buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
alBufferData(buffer, OpenAL::AudioFormat[format], samples, sampleCount*sizeof(Int16), sampleRate);
|
||||
|
||||
if (alGetError() != AL_NO_ERROR)
|
||||
{
|
||||
alDeleteBuffers(1, &buffer);
|
||||
|
||||
NazaraError("Failed to set OpenAL buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_impl = new SoundBufferImpl;
|
||||
m_impl->buffer = buffer;
|
||||
m_impl->duration = (1000*sampleCount / (format * sampleRate));
|
||||
m_impl->format = format;
|
||||
m_impl->sampleCount = sampleCount;
|
||||
m_impl->sampleRate = sampleRate;
|
||||
m_impl->samples.reset(new Int16[sampleCount]);
|
||||
std::memcpy(&m_impl->samples[0], samples, sampleCount*sizeof(Int16));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
alBufferData(buffer, NzOpenAL::AudioFormat[format], samples, sampleCount*sizeof(nzInt16), sampleRate);
|
||||
|
||||
if (alGetError() != AL_NO_ERROR)
|
||||
void SoundBuffer::Destroy()
|
||||
{
|
||||
alDeleteBuffers(1, &buffer);
|
||||
if (m_impl)
|
||||
{
|
||||
OnSoundBufferDestroy(this);
|
||||
|
||||
NazaraError("Failed to set OpenAL buffer");
|
||||
return false;
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
m_impl = new NzSoundBufferImpl;
|
||||
m_impl->buffer = buffer;
|
||||
m_impl->duration = (1000*sampleCount / (format * sampleRate));
|
||||
m_impl->format = format;
|
||||
m_impl->sampleCount = sampleCount;
|
||||
m_impl->sampleRate = sampleRate;
|
||||
m_impl->samples.reset(new nzInt16[sampleCount]);
|
||||
std::memcpy(&m_impl->samples[0], samples, sampleCount*sizeof(nzInt16));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzSoundBuffer::Destroy()
|
||||
{
|
||||
if (m_impl)
|
||||
UInt32 SoundBuffer::GetDuration() const
|
||||
{
|
||||
OnSoundBufferDestroy(this);
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nzUInt32 NzSoundBuffer::GetDuration() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->duration;
|
||||
}
|
||||
|
||||
nzAudioFormat NzSoundBuffer::GetFormat() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return nzAudioFormat_Unknown;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->format;
|
||||
}
|
||||
|
||||
const nzInt16* NzSoundBuffer::GetSamples() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->samples.get();
|
||||
}
|
||||
|
||||
unsigned int NzSoundBuffer::GetSampleCount() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->sampleCount;
|
||||
}
|
||||
|
||||
unsigned int NzSoundBuffer::GetSampleRate() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->sampleRate;
|
||||
}
|
||||
|
||||
bool NzSoundBuffer::IsValid() const
|
||||
{
|
||||
return m_impl != nullptr;
|
||||
}
|
||||
|
||||
bool NzSoundBuffer::LoadFromFile(const NzString& filePath, const NzSoundBufferParams& params)
|
||||
{
|
||||
return NzSoundBufferLoader::LoadFromFile(this, filePath, params);
|
||||
}
|
||||
|
||||
bool NzSoundBuffer::LoadFromMemory(const void* data, std::size_t size, const NzSoundBufferParams& params)
|
||||
{
|
||||
return NzSoundBufferLoader::LoadFromMemory(this, data, size, params);
|
||||
}
|
||||
|
||||
bool NzSoundBuffer::LoadFromStream(NzInputStream& stream, const NzSoundBufferParams& params)
|
||||
{
|
||||
return NzSoundBufferLoader::LoadFromStream(this, stream, params);
|
||||
}
|
||||
|
||||
bool NzSoundBuffer::IsFormatSupported(nzAudioFormat format)
|
||||
{
|
||||
return NzAudio::IsFormatSupported(format);
|
||||
}
|
||||
|
||||
unsigned int NzSoundBuffer::GetOpenALBuffer() const
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraInternalError("Sound buffer not created");
|
||||
return AL_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->buffer;
|
||||
}
|
||||
|
||||
bool NzSoundBuffer::Initialize()
|
||||
{
|
||||
if (!NzSoundBufferLibrary::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialise library");
|
||||
return false;
|
||||
return m_impl->duration;
|
||||
}
|
||||
|
||||
if (!NzSoundBufferManager::Initialize())
|
||||
AudioFormat SoundBuffer::GetFormat() const
|
||||
{
|
||||
NazaraError("Failed to initialise manager");
|
||||
return false;
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return AudioFormat_Unknown;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->format;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
const Int16* SoundBuffer::GetSamples() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
void NzSoundBuffer::Uninitialize()
|
||||
{
|
||||
NzSoundBufferManager::Uninitialize();
|
||||
NzSoundBufferLibrary::Uninitialize();
|
||||
}
|
||||
return m_impl->samples.get();
|
||||
}
|
||||
|
||||
NzSoundBufferLibrary::LibraryMap NzSoundBuffer::s_library;
|
||||
NzSoundBufferLoader::LoaderList NzSoundBuffer::s_loaders;
|
||||
NzSoundBufferManager::ManagerMap NzSoundBuffer::s_managerMap;
|
||||
NzSoundBufferManager::ManagerParams NzSoundBuffer::s_managerParameters;
|
||||
unsigned int SoundBuffer::GetSampleCount() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->sampleCount;
|
||||
}
|
||||
|
||||
unsigned int SoundBuffer::GetSampleRate() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->sampleRate;
|
||||
}
|
||||
|
||||
bool SoundBuffer::IsValid() const
|
||||
{
|
||||
return m_impl != nullptr;
|
||||
}
|
||||
|
||||
bool SoundBuffer::LoadFromFile(const String& filePath, const SoundBufferParams& params)
|
||||
{
|
||||
return SoundBufferLoader::LoadFromFile(this, filePath, params);
|
||||
}
|
||||
|
||||
bool SoundBuffer::LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params)
|
||||
{
|
||||
return SoundBufferLoader::LoadFromMemory(this, data, size, params);
|
||||
}
|
||||
|
||||
bool SoundBuffer::LoadFromStream(InputStream& stream, const SoundBufferParams& params)
|
||||
{
|
||||
return SoundBufferLoader::LoadFromStream(this, stream, params);
|
||||
}
|
||||
|
||||
bool SoundBuffer::IsFormatSupported(AudioFormat format)
|
||||
{
|
||||
return Audio::IsFormatSupported(format);
|
||||
}
|
||||
|
||||
unsigned int SoundBuffer::GetOpenALBuffer() const
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraInternalError("Sound buffer not created");
|
||||
return AL_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->buffer;
|
||||
}
|
||||
|
||||
bool SoundBuffer::Initialize()
|
||||
{
|
||||
if (!SoundBufferLibrary::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialise library");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SoundBufferManager::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialise manager");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SoundBuffer::Uninitialize()
|
||||
{
|
||||
SoundBufferManager::Uninitialize();
|
||||
SoundBufferLibrary::Uninitialize();
|
||||
}
|
||||
|
||||
SoundBufferLibrary::LibraryMap SoundBuffer::s_library;
|
||||
SoundBufferLoader::LoaderList SoundBuffer::s_loaders;
|
||||
SoundBufferManager::ManagerMap SoundBuffer::s_managerMap;
|
||||
SoundBufferManager::ManagerParams SoundBuffer::s_managerParameters;
|
||||
}
|
||||
|
||||
@@ -9,148 +9,151 @@
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
NzSoundEmitter::NzSoundEmitter()
|
||||
namespace Nz
|
||||
{
|
||||
alGenSources(1, &m_source);
|
||||
}
|
||||
|
||||
NzSoundEmitter::NzSoundEmitter(const NzSoundEmitter& emitter)
|
||||
{
|
||||
alGenSources(1, &m_source);
|
||||
|
||||
SetAttenuation(emitter.GetAttenuation());
|
||||
SetMinDistance(emitter.GetMinDistance());
|
||||
SetPitch(emitter.GetPitch());
|
||||
// Pas de copie de position ou de vitesse
|
||||
SetVolume(emitter.GetVolume());
|
||||
}
|
||||
|
||||
NzSoundEmitter::~NzSoundEmitter()
|
||||
{
|
||||
alDeleteSources(1, &m_source);
|
||||
}
|
||||
|
||||
void NzSoundEmitter::EnableSpatialization(bool spatialization)
|
||||
{
|
||||
alSourcei(m_source, AL_SOURCE_RELATIVE, !spatialization);
|
||||
}
|
||||
|
||||
float NzSoundEmitter::GetAttenuation() const
|
||||
{
|
||||
ALfloat attenuation;
|
||||
alGetSourcef(m_source, AL_ROLLOFF_FACTOR, &attenuation);
|
||||
|
||||
return attenuation;
|
||||
}
|
||||
|
||||
float NzSoundEmitter::GetMinDistance() const
|
||||
{
|
||||
ALfloat distance;
|
||||
alGetSourcef(m_source, AL_REFERENCE_DISTANCE, &distance);
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
float NzSoundEmitter::GetPitch() const
|
||||
{
|
||||
ALfloat pitch;
|
||||
alGetSourcef(m_source, AL_PITCH, &pitch);
|
||||
|
||||
return pitch;
|
||||
}
|
||||
|
||||
NzVector3f NzSoundEmitter::GetPosition() const
|
||||
{
|
||||
NzVector3f position;
|
||||
alGetSourcefv(m_source, AL_POSITION, position);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
NzVector3f NzSoundEmitter::GetVelocity() const
|
||||
{
|
||||
NzVector3f velocity;
|
||||
alGetSourcefv(m_source, AL_VELOCITY, velocity);
|
||||
|
||||
return velocity;
|
||||
}
|
||||
|
||||
float NzSoundEmitter::GetVolume() const
|
||||
{
|
||||
ALfloat gain;
|
||||
alGetSourcef(m_source, AL_GAIN, &gain);
|
||||
|
||||
return gain * 100.f;
|
||||
}
|
||||
|
||||
bool NzSoundEmitter::IsSpatialized() const
|
||||
{
|
||||
ALint relative;
|
||||
alGetSourcei(m_source, AL_SOURCE_RELATIVE, &relative);
|
||||
|
||||
return relative == AL_FALSE;
|
||||
}
|
||||
|
||||
void NzSoundEmitter::SetAttenuation(float attenuation)
|
||||
{
|
||||
alSourcef(m_source, AL_ROLLOFF_FACTOR, attenuation);
|
||||
}
|
||||
|
||||
void NzSoundEmitter::SetMinDistance(float minDistance)
|
||||
{
|
||||
alSourcef(m_source, AL_REFERENCE_DISTANCE, minDistance);
|
||||
}
|
||||
|
||||
void NzSoundEmitter::SetPitch(float pitch)
|
||||
{
|
||||
alSourcef(m_source, AL_PITCH, pitch);
|
||||
}
|
||||
|
||||
void NzSoundEmitter::SetPosition(const NzVector3f& position)
|
||||
{
|
||||
alSourcefv(m_source, AL_POSITION, position);
|
||||
}
|
||||
|
||||
void NzSoundEmitter::SetPosition(float x, float y, float z)
|
||||
{
|
||||
alSource3f(m_source, AL_POSITION, x, y, z);
|
||||
}
|
||||
|
||||
void NzSoundEmitter::SetVelocity(const NzVector3f& velocity)
|
||||
{
|
||||
alSourcefv(m_source, AL_VELOCITY, velocity);
|
||||
}
|
||||
|
||||
void NzSoundEmitter::SetVelocity(float velX, float velY, float velZ)
|
||||
{
|
||||
alSource3f(m_source, AL_VELOCITY, velX, velY, velZ);
|
||||
}
|
||||
|
||||
void NzSoundEmitter::SetVolume(float volume)
|
||||
{
|
||||
alSourcef(m_source, AL_GAIN, volume*0.01f);
|
||||
}
|
||||
|
||||
nzSoundStatus NzSoundEmitter::GetInternalStatus() const
|
||||
{
|
||||
ALint state;
|
||||
alGetSourcei(m_source, AL_SOURCE_STATE, &state);
|
||||
|
||||
switch (state)
|
||||
SoundEmitter::SoundEmitter()
|
||||
{
|
||||
case AL_INITIAL:
|
||||
case AL_STOPPED:
|
||||
return nzSoundStatus_Stopped;
|
||||
|
||||
case AL_PAUSED:
|
||||
return nzSoundStatus_Paused;
|
||||
|
||||
case AL_PLAYING:
|
||||
return nzSoundStatus_Playing;
|
||||
|
||||
default:
|
||||
NazaraInternalError("Source state unrecognized");
|
||||
alGenSources(1, &m_source);
|
||||
}
|
||||
|
||||
return nzSoundStatus_Stopped;
|
||||
SoundEmitter::SoundEmitter(const SoundEmitter& emitter)
|
||||
{
|
||||
alGenSources(1, &m_source);
|
||||
|
||||
SetAttenuation(emitter.GetAttenuation());
|
||||
SetMinDistance(emitter.GetMinDistance());
|
||||
SetPitch(emitter.GetPitch());
|
||||
// Pas de copie de position ou de vitesse
|
||||
SetVolume(emitter.GetVolume());
|
||||
}
|
||||
|
||||
SoundEmitter::~SoundEmitter()
|
||||
{
|
||||
alDeleteSources(1, &m_source);
|
||||
}
|
||||
|
||||
void SoundEmitter::EnableSpatialization(bool spatialization)
|
||||
{
|
||||
alSourcei(m_source, AL_SOURCE_RELATIVE, !spatialization);
|
||||
}
|
||||
|
||||
float SoundEmitter::GetAttenuation() const
|
||||
{
|
||||
ALfloat attenuation;
|
||||
alGetSourcef(m_source, AL_ROLLOFF_FACTOR, &attenuation);
|
||||
|
||||
return attenuation;
|
||||
}
|
||||
|
||||
float SoundEmitter::GetMinDistance() const
|
||||
{
|
||||
ALfloat distance;
|
||||
alGetSourcef(m_source, AL_REFERENCE_DISTANCE, &distance);
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
float SoundEmitter::GetPitch() const
|
||||
{
|
||||
ALfloat pitch;
|
||||
alGetSourcef(m_source, AL_PITCH, &pitch);
|
||||
|
||||
return pitch;
|
||||
}
|
||||
|
||||
Vector3f SoundEmitter::GetPosition() const
|
||||
{
|
||||
Vector3f position;
|
||||
alGetSourcefv(m_source, AL_POSITION, position);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
Vector3f SoundEmitter::GetVelocity() const
|
||||
{
|
||||
Vector3f velocity;
|
||||
alGetSourcefv(m_source, AL_VELOCITY, velocity);
|
||||
|
||||
return velocity;
|
||||
}
|
||||
|
||||
float SoundEmitter::GetVolume() const
|
||||
{
|
||||
ALfloat gain;
|
||||
alGetSourcef(m_source, AL_GAIN, &gain);
|
||||
|
||||
return gain * 100.f;
|
||||
}
|
||||
|
||||
bool SoundEmitter::IsSpatialized() const
|
||||
{
|
||||
ALint relative;
|
||||
alGetSourcei(m_source, AL_SOURCE_RELATIVE, &relative);
|
||||
|
||||
return relative == AL_FALSE;
|
||||
}
|
||||
|
||||
void SoundEmitter::SetAttenuation(float attenuation)
|
||||
{
|
||||
alSourcef(m_source, AL_ROLLOFF_FACTOR, attenuation);
|
||||
}
|
||||
|
||||
void SoundEmitter::SetMinDistance(float minDistance)
|
||||
{
|
||||
alSourcef(m_source, AL_REFERENCE_DISTANCE, minDistance);
|
||||
}
|
||||
|
||||
void SoundEmitter::SetPitch(float pitch)
|
||||
{
|
||||
alSourcef(m_source, AL_PITCH, pitch);
|
||||
}
|
||||
|
||||
void SoundEmitter::SetPosition(const Vector3f& position)
|
||||
{
|
||||
alSourcefv(m_source, AL_POSITION, position);
|
||||
}
|
||||
|
||||
void SoundEmitter::SetPosition(float x, float y, float z)
|
||||
{
|
||||
alSource3f(m_source, AL_POSITION, x, y, z);
|
||||
}
|
||||
|
||||
void SoundEmitter::SetVelocity(const Vector3f& velocity)
|
||||
{
|
||||
alSourcefv(m_source, AL_VELOCITY, velocity);
|
||||
}
|
||||
|
||||
void SoundEmitter::SetVelocity(float velX, float velY, float velZ)
|
||||
{
|
||||
alSource3f(m_source, AL_VELOCITY, velX, velY, velZ);
|
||||
}
|
||||
|
||||
void SoundEmitter::SetVolume(float volume)
|
||||
{
|
||||
alSourcef(m_source, AL_GAIN, volume*0.01f);
|
||||
}
|
||||
|
||||
SoundStatus SoundEmitter::GetInternalStatus() const
|
||||
{
|
||||
ALint state;
|
||||
alGetSourcei(m_source, AL_SOURCE_STATE, &state);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case AL_INITIAL:
|
||||
case AL_STOPPED:
|
||||
return SoundStatus_Stopped;
|
||||
|
||||
case AL_PAUSED:
|
||||
return SoundStatus_Paused;
|
||||
|
||||
case AL_PLAYING:
|
||||
return SoundStatus_Playing;
|
||||
|
||||
default:
|
||||
NazaraInternalError("Source state unrecognized");
|
||||
}
|
||||
|
||||
return SoundStatus_Stopped;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,4 +4,7 @@
|
||||
|
||||
#include <Nazara/Audio/SoundStream.hpp>
|
||||
|
||||
NzSoundStream::~NzSoundStream() = default;
|
||||
namespace Nz
|
||||
{
|
||||
SoundStream::~SoundStream() = default;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user