317 lines
7.4 KiB
C++
317 lines
7.4 KiB
C++
// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
|
// This file is part of the "Nazara Engine - Audio module"
|
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
|
|
|
#include <Nazara/Audio/OpenALDevice.hpp>
|
|
#include <Nazara/Audio/OpenALBuffer.hpp>
|
|
#include <Nazara/Audio/OpenALLibrary.hpp>
|
|
#include <Nazara/Audio/OpenALSource.hpp>
|
|
#include <cstring>
|
|
#include <stdexcept>
|
|
#include <Nazara/Audio/Debug.hpp>
|
|
|
|
namespace Nz
|
|
{
|
|
namespace
|
|
{
|
|
thread_local ALCcontext* s_currentContext;
|
|
}
|
|
|
|
OpenALDevice::OpenALDevice(OpenALLibrary& library, ALCdevice* device) :
|
|
m_library(library),
|
|
m_device(device)
|
|
{
|
|
m_context = m_library.alcCreateContext(device, nullptr);
|
|
if (!m_context)
|
|
throw std::runtime_error("failed to create OpenAL context");
|
|
|
|
MakeContextCurrent();
|
|
|
|
m_renderer = reinterpret_cast<const char*>(m_library.alGetString(AL_RENDERER));
|
|
m_vendor = reinterpret_cast<const char*>(m_library.alGetString(AL_VENDOR));
|
|
|
|
// We complete the formats table
|
|
m_audioFormatValues.fill(0);
|
|
|
|
m_audioFormatValues[UnderlyingCast(AudioFormat::I16_Mono)] = AL_FORMAT_MONO16;
|
|
m_audioFormatValues[UnderlyingCast(AudioFormat::I16_Stereo)] = AL_FORMAT_STEREO16;
|
|
|
|
// "The presence of an enum value does not guarantee the applicability of an extension to the current context."
|
|
if (library.alIsExtensionPresent("AL_EXT_MCFORMATS"))
|
|
{
|
|
m_audioFormatValues[UnderlyingCast(AudioFormat::I16_Quad)] = m_library.alGetEnumValue("AL_FORMAT_QUAD16");
|
|
m_audioFormatValues[UnderlyingCast(AudioFormat::I16_5_1)] = m_library.alGetEnumValue("AL_FORMAT_51CHN16");
|
|
m_audioFormatValues[UnderlyingCast(AudioFormat::I16_6_1)] = m_library.alGetEnumValue("AL_FORMAT_61CHN16");
|
|
m_audioFormatValues[UnderlyingCast(AudioFormat::I16_7_1)] = m_library.alGetEnumValue("AL_FORMAT_71CHN16");
|
|
}
|
|
else if (library.alIsExtensionPresent("AL_LOKI_quadriphonic"))
|
|
m_audioFormatValues[UnderlyingCast(AudioFormat::I16_Quad)] = m_library.alGetEnumValue("AL_FORMAT_QUAD16_LOKI");
|
|
|
|
m_extensionStatus.fill(false);
|
|
if (library.alIsExtensionPresent("AL_SOFT_source_latency"))
|
|
m_extensionStatus[UnderlyingCast(OpenALExtension::SourceLatency)] = true;
|
|
|
|
SetListenerDirection(Vector3f::Forward());
|
|
}
|
|
|
|
OpenALDevice::~OpenALDevice()
|
|
{
|
|
MakeContextCurrent();
|
|
|
|
m_library.alcDestroyContext(m_context);
|
|
m_library.alcCloseDevice(m_device);
|
|
|
|
if (s_currentContext == m_context)
|
|
s_currentContext = nullptr;
|
|
}
|
|
|
|
std::shared_ptr<AudioBuffer> OpenALDevice::CreateBuffer()
|
|
{
|
|
MakeContextCurrent();
|
|
|
|
ALuint bufferId = 0;
|
|
m_library.alGenBuffers(1, &bufferId);
|
|
|
|
if (bufferId == 0)
|
|
return {};
|
|
|
|
return std::make_shared<OpenALBuffer>(shared_from_this(), m_library, bufferId);
|
|
}
|
|
|
|
std::shared_ptr<AudioSource> OpenALDevice::CreateSource()
|
|
{
|
|
MakeContextCurrent();
|
|
|
|
ALuint sourceId = 0;
|
|
m_library.alGenSources(1, &sourceId);
|
|
|
|
if (sourceId == 0)
|
|
return {};
|
|
|
|
return std::make_shared<OpenALSource>(shared_from_this(), m_library, sourceId);
|
|
}
|
|
|
|
/*!
|
|
* \brief Gets the factor of the Doppler effect
|
|
* \return Global factor of the Doppler effect
|
|
*/
|
|
float OpenALDevice::GetDopplerFactor() const
|
|
{
|
|
MakeContextCurrent();
|
|
|
|
return m_library.alGetFloat(AL_DOPPLER_FACTOR);
|
|
}
|
|
|
|
/*!
|
|
* \brief Gets the global volume
|
|
* \return Float between [0, inf) with 1.f being the default
|
|
*/
|
|
float OpenALDevice::GetGlobalVolume() const
|
|
{
|
|
MakeContextCurrent();
|
|
|
|
ALfloat gain = 0.f;
|
|
m_library.alGetListenerf(AL_GAIN, &gain);
|
|
|
|
return gain;
|
|
}
|
|
|
|
/*!
|
|
* \brief Gets the direction of the listener
|
|
* \return Direction of the listener, in front of the listener
|
|
*
|
|
* \param up Current up direction
|
|
*
|
|
* \see GetListenerRotation
|
|
*/
|
|
Vector3f OpenALDevice::GetListenerDirection(Vector3f* up) const
|
|
{
|
|
MakeContextCurrent();
|
|
|
|
ALfloat orientation[6];
|
|
m_library.alGetListenerfv(AL_ORIENTATION, orientation);
|
|
|
|
if (up)
|
|
up->Set(orientation[3], orientation[4], orientation[5]);
|
|
|
|
return Vector3f(orientation[0], orientation[1], orientation[2]);
|
|
}
|
|
|
|
/*!
|
|
* \brief Gets the position of the listener
|
|
* \return Position of the listener
|
|
*
|
|
* \see GetListenerVelocity
|
|
*/
|
|
Vector3f OpenALDevice::GetListenerPosition() const
|
|
{
|
|
MakeContextCurrent();
|
|
|
|
Vector3f position;
|
|
m_library.alGetListenerfv(AL_POSITION, &position.x);
|
|
|
|
return position;
|
|
}
|
|
|
|
/*!
|
|
* \brief Gets the rotation of the listener
|
|
* \return Rotation of the listener
|
|
*
|
|
* \param up Current up direction
|
|
*
|
|
* \see GetListenerDirection
|
|
*/
|
|
Quaternionf OpenALDevice::GetListenerRotation() const
|
|
{
|
|
MakeContextCurrent();
|
|
|
|
ALfloat orientation[6];
|
|
m_library.alGetListenerfv(AL_ORIENTATION, orientation);
|
|
|
|
Vector3f forward(orientation[0], orientation[1], orientation[2]);
|
|
Vector3f up(orientation[3], orientation[4], orientation[5]);
|
|
|
|
return Quaternionf::LookAt(forward, up);
|
|
}
|
|
|
|
/*!
|
|
* \brief Gets the velocity of the listener
|
|
* \return Velocity of the listener
|
|
*
|
|
* \see GetListenerPosition
|
|
*/
|
|
Vector3f OpenALDevice::GetListenerVelocity() const
|
|
{
|
|
MakeContextCurrent();
|
|
|
|
Vector3f velocity;
|
|
m_library.alGetListenerfv(AL_VELOCITY, &velocity.x);
|
|
|
|
return velocity;
|
|
}
|
|
|
|
void OpenALDevice::MakeContextCurrent() const
|
|
{
|
|
if (s_currentContext != m_context)
|
|
{
|
|
m_library.alcMakeContextCurrent(m_context);
|
|
s_currentContext = m_context;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* \brief Gets the speed of sound
|
|
* \return Speed of sound
|
|
*/
|
|
float OpenALDevice::GetSpeedOfSound() const
|
|
{
|
|
MakeContextCurrent();
|
|
|
|
return m_library.alGetFloat(AL_SPEED_OF_SOUND);
|
|
}
|
|
|
|
const void* OpenALDevice::GetSubSystemIdentifier() const
|
|
{
|
|
return &m_library;
|
|
}
|
|
|
|
/*!
|
|
* \brief Checks whether the format is supported by the engine
|
|
* \return true if it is the case
|
|
*
|
|
* \param format Format to check
|
|
*/
|
|
bool OpenALDevice::IsFormatSupported(AudioFormat format) const
|
|
{
|
|
if (format == AudioFormat::Unknown)
|
|
return false;
|
|
|
|
return m_audioFormatValues[UnderlyingCast(format)] != 0;
|
|
}
|
|
|
|
/*!
|
|
* \brief Sets the factor of the doppler effect
|
|
*
|
|
* \param dopplerFactor Global factor of the doppler effect
|
|
*/
|
|
void OpenALDevice::SetDopplerFactor(float dopplerFactor)
|
|
{
|
|
MakeContextCurrent();
|
|
|
|
m_library.alDopplerFactor(dopplerFactor);
|
|
}
|
|
|
|
/*!
|
|
* \brief Sets the global volume
|
|
*
|
|
* \param volume Float between [0, inf) with 1.f being the default
|
|
*/
|
|
void OpenALDevice::SetGlobalVolume(float volume)
|
|
{
|
|
MakeContextCurrent();
|
|
|
|
m_library.alListenerf(AL_GAIN, volume);
|
|
}
|
|
|
|
/*!
|
|
* \brief Sets the direction of the listener
|
|
*
|
|
* \param direction Direction of the listener, in front of the listener
|
|
* \param up Up vector
|
|
*
|
|
* \see SetListenerDirection, SetListenerRotation
|
|
*/
|
|
void OpenALDevice::SetListenerDirection(const Vector3f& direction, const Vector3f& up)
|
|
{
|
|
MakeContextCurrent();
|
|
|
|
ALfloat orientation[6] =
|
|
{
|
|
direction.x, direction.y, direction.z,
|
|
up.x, up.y, up.z
|
|
};
|
|
|
|
m_library.alListenerfv(AL_ORIENTATION, orientation);
|
|
}
|
|
|
|
/*!
|
|
* \brief Sets the position of the listener
|
|
*
|
|
* \param position Position of the listener
|
|
*
|
|
* \see SetListenerVelocity
|
|
*/
|
|
void OpenALDevice::SetListenerPosition(const Vector3f& position)
|
|
{
|
|
MakeContextCurrent();
|
|
|
|
m_library.alListenerfv(AL_POSITION, &position.x);
|
|
}
|
|
|
|
/*!
|
|
* \brief Sets the velocity of the listener
|
|
*
|
|
* \param velocity Velocity of the listener
|
|
*
|
|
* \see SetListenerPosition
|
|
*/
|
|
void OpenALDevice::SetListenerVelocity(const Vector3f& velocity)
|
|
{
|
|
MakeContextCurrent();
|
|
|
|
m_library.alListenerfv(AL_VELOCITY, &velocity.x);
|
|
}
|
|
|
|
/*!
|
|
* \brief Sets the speed of sound
|
|
*
|
|
* \param speed Speed of sound
|
|
*/
|
|
void OpenALDevice::SetSpeedOfSound(float speed)
|
|
{
|
|
MakeContextCurrent();
|
|
|
|
m_library.alSpeedOfSound(speed);
|
|
}
|
|
}
|