Audio: Rewrite audio module
This commit is contained in:
parent
eb4629947e
commit
6165b3a101
|
|
@ -31,10 +31,17 @@
|
|||
|
||||
#include <Nazara/Audio/Algorithm.hpp>
|
||||
#include <Nazara/Audio/Audio.hpp>
|
||||
#include <Nazara/Audio/AudioBuffer.hpp>
|
||||
#include <Nazara/Audio/AudioDevice.hpp>
|
||||
#include <Nazara/Audio/AudioSource.hpp>
|
||||
#include <Nazara/Audio/Config.hpp>
|
||||
#include <Nazara/Audio/Enums.hpp>
|
||||
#include <Nazara/Audio/Music.hpp>
|
||||
#include <Nazara/Audio/OpenAL.hpp>
|
||||
#include <Nazara/Audio/OpenALBuffer.hpp>
|
||||
#include <Nazara/Audio/OpenALDevice.hpp>
|
||||
#include <Nazara/Audio/OpenALLibrary.hpp>
|
||||
#include <Nazara/Audio/OpenALSource.hpp>
|
||||
#include <Nazara/Audio/Sound.hpp>
|
||||
#include <Nazara/Audio/SoundBuffer.hpp>
|
||||
#include <Nazara/Audio/SoundEmitter.hpp>
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@
|
|||
#include <Nazara/Audio/SoundBuffer.hpp>
|
||||
#include <Nazara/Audio/SoundStream.hpp>
|
||||
#include <Nazara/Core/Core.hpp>
|
||||
#include <Nazara/Math/Quaternion.hpp>
|
||||
#include <Nazara/Math/Vector3.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
|
|
@ -32,35 +30,23 @@ namespace Nz
|
|||
Audio(Audio&&) = delete;
|
||||
~Audio();
|
||||
|
||||
float GetDopplerFactor() const;
|
||||
float GetGlobalVolume() const;
|
||||
Vector3f GetListenerDirection() const;
|
||||
Vector3f GetListenerPosition() const;
|
||||
Quaternionf GetListenerRotation() const;
|
||||
Vector3f GetListenerVelocity() const;
|
||||
const std::shared_ptr<AudioDevice>& GetDefaultDevice() const;
|
||||
|
||||
SoundBufferLoader& GetSoundBufferLoader();
|
||||
const SoundBufferLoader& GetSoundBufferLoader() const;
|
||||
SoundStreamLoader& GetSoundStreamLoader();
|
||||
const SoundStreamLoader& GetSoundStreamLoader() const;
|
||||
float GetSpeedOfSound() const;
|
||||
|
||||
bool IsFormatSupported(AudioFormat format) const;
|
||||
std::shared_ptr<AudioDevice> OpenOutputDevice(const std::string& deviceName);
|
||||
|
||||
void SetDopplerFactor(float dopplerFactor);
|
||||
void SetGlobalVolume(float volume);
|
||||
void SetListenerDirection(const Vector3f& direction);
|
||||
void SetListenerDirection(float dirX, float dirY, float dirZ);
|
||||
void SetListenerPosition(const Vector3f& position);
|
||||
void SetListenerPosition(float x, float y, float z);
|
||||
void SetListenerRotation(const Quaternionf& rotation);
|
||||
void SetListenerVelocity(const Vector3f& velocity);
|
||||
void SetListenerVelocity(float velX, float velY, float velZ);
|
||||
void SetSpeedOfSound(float speed);
|
||||
std::vector<std::string> QueryInputDevices() const;
|
||||
std::vector<std::string> QueryOutputDevices() const;
|
||||
|
||||
Audio& operator=(const Audio&) = delete;
|
||||
Audio& operator=(Audio&&) = delete;
|
||||
|
||||
private:
|
||||
std::shared_ptr<AudioDevice> m_defaultDevice;
|
||||
SoundBufferLoader m_soundBufferLoader;
|
||||
SoundStreamLoader m_soundStreamLoader;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright (C) 2022 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
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_AUDIO_AUDIOBUFFER_HPP
|
||||
#define NAZARA_AUDIO_AUDIOBUFFER_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Audio/Config.hpp>
|
||||
#include <Nazara/Audio/Enums.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class AudioDevice;
|
||||
|
||||
class NAZARA_AUDIO_API AudioBuffer
|
||||
{
|
||||
public:
|
||||
inline AudioBuffer(std::shared_ptr<AudioDevice> device);
|
||||
AudioBuffer(const AudioBuffer&) = default;
|
||||
AudioBuffer(AudioBuffer&&) = default;
|
||||
virtual ~AudioBuffer();
|
||||
|
||||
inline const std::shared_ptr<AudioDevice>& GetAudioDevice() const;
|
||||
virtual UInt32 GetSampleCount() const = 0;
|
||||
virtual UInt32 GetSize() const = 0;
|
||||
virtual UInt32 GetSampleRate() const = 0;
|
||||
|
||||
virtual bool Reset(AudioFormat format, UInt64 sampleCount, UInt32 sampleRate, const void* samples) = 0;
|
||||
|
||||
AudioBuffer& operator=(const AudioBuffer&) = default;
|
||||
AudioBuffer& operator=(AudioBuffer&&) = default;
|
||||
|
||||
private:
|
||||
std::shared_ptr<AudioDevice> m_device;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/AudioBuffer.inl>
|
||||
|
||||
#endif // NAZARA_AUDIO_AUDIOBUFFER_HPP
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (C) 2022 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/AudioBuffer.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline AudioBuffer::AudioBuffer(std::shared_ptr<AudioDevice> device) :
|
||||
m_device(std::move(device))
|
||||
{
|
||||
}
|
||||
|
||||
inline const std::shared_ptr<AudioDevice>& AudioBuffer::GetAudioDevice() const
|
||||
{
|
||||
return m_device;
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/DebugOff.hpp>
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright (C) 2022 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
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_AUDIO_AUDIODEVICE_HPP
|
||||
#define NAZARA_AUDIO_AUDIODEVICE_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Audio/Config.hpp>
|
||||
#include <Nazara/Audio/Enums.hpp>
|
||||
#include <Nazara/Core/Signal.hpp>
|
||||
#include <Nazara/Math/Quaternion.hpp>
|
||||
#include <Nazara/Math/Vector3.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class AudioBuffer;
|
||||
class AudioSource;
|
||||
|
||||
class NAZARA_AUDIO_API AudioDevice : public std::enable_shared_from_this<AudioDevice>
|
||||
{
|
||||
public:
|
||||
AudioDevice() = default;
|
||||
AudioDevice(const AudioDevice&) = delete;
|
||||
AudioDevice(AudioDevice&&) = default;
|
||||
virtual ~AudioDevice();
|
||||
|
||||
virtual std::shared_ptr<AudioBuffer> CreateBuffer() = 0;
|
||||
virtual std::shared_ptr<AudioSource> CreateSource() = 0;
|
||||
|
||||
virtual float GetDopplerFactor() const = 0;
|
||||
virtual float GetGlobalVolume() const = 0;
|
||||
virtual Vector3f GetListenerDirection(Vector3f* up = nullptr) const = 0;
|
||||
virtual Vector3f GetListenerPosition() const = 0;
|
||||
virtual Quaternionf GetListenerRotation(Vector3f* up = nullptr) const = 0;
|
||||
virtual Vector3f GetListenerVelocity() const = 0;
|
||||
virtual float GetSpeedOfSound() const = 0;
|
||||
|
||||
virtual bool IsFormatSupported(AudioFormat format) const = 0;
|
||||
|
||||
virtual void SetDopplerFactor(float dopplerFactor) = 0;
|
||||
virtual void SetGlobalVolume(float volume) = 0;
|
||||
virtual void SetListenerDirection(const Vector3f& direction, const Vector3f& up = Vector3f::Up()) = 0;
|
||||
virtual void SetListenerPosition(const Vector3f& position) = 0;
|
||||
inline void SetListenerRotation(const Quaternionf& rotation);
|
||||
virtual void SetListenerVelocity(const Vector3f& velocity) = 0;
|
||||
virtual void SetSpeedOfSound(float speed) = 0;
|
||||
|
||||
AudioDevice& operator=(const AudioDevice&) = delete;
|
||||
AudioDevice& operator=(AudioDevice&&) = default;
|
||||
|
||||
NazaraSignal(OnAudioDeviceRelease, AudioDevice* /*audioDevice*/);
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/AudioDevice.inl>
|
||||
|
||||
#endif // NAZARA_AUDIO_AUDIODEVICE_HPP
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (C) 2022 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/AudioDevice.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline void AudioDevice::SetListenerRotation(const Quaternionf& rotation)
|
||||
{
|
||||
SetListenerDirection(rotation * Vector3f::Forward(), rotation * Vector3f::Up());
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/DebugOff.hpp>
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
// Copyright (C) 2022 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
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_AUDIO_AUDIOSOURCE_HPP
|
||||
#define NAZARA_AUDIO_AUDIOSOURCE_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Audio/Config.hpp>
|
||||
#include <Nazara/Audio/Enums.hpp>
|
||||
#include <Nazara/Math/Vector3.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class AudioBuffer;
|
||||
class AudioDevice;
|
||||
|
||||
class NAZARA_AUDIO_API AudioSource
|
||||
{
|
||||
public:
|
||||
inline AudioSource(std::shared_ptr<AudioDevice> device);
|
||||
AudioSource(const AudioSource&) = delete;
|
||||
AudioSource(AudioSource&&) = delete;
|
||||
virtual ~AudioSource();
|
||||
|
||||
virtual void EnableLooping(bool loop) = 0;
|
||||
virtual void EnableSpatialization(bool spatialization) = 0;
|
||||
|
||||
inline const std::shared_ptr<AudioDevice>& GetAudioDevice() const;
|
||||
virtual float GetAttenuation() const = 0;
|
||||
virtual float GetMinDistance() const = 0;
|
||||
virtual float GetPitch() const = 0;
|
||||
virtual Vector3f GetPosition() const = 0;
|
||||
virtual UInt32 GetSampleOffset() const = 0;
|
||||
virtual Vector3f GetVelocity() const = 0;
|
||||
virtual SoundStatus GetStatus() const = 0;
|
||||
virtual float GetVolume() const = 0;
|
||||
|
||||
virtual bool IsLooping() const = 0;
|
||||
virtual bool IsSpatializationEnabled() const = 0;
|
||||
|
||||
virtual void QueueBuffer(std::shared_ptr<AudioBuffer> audioBuffer) = 0;
|
||||
|
||||
virtual void Pause() = 0;
|
||||
virtual void Play() = 0;
|
||||
|
||||
virtual void SetAttenuation(float attenuation) = 0;
|
||||
virtual void SetBuffer(std::shared_ptr<AudioBuffer> audioBuffer) = 0;
|
||||
virtual void SetMinDistance(float minDistance) = 0;
|
||||
virtual void SetPitch(float pitch) = 0;
|
||||
virtual void SetPosition(const Vector3f& position) = 0;
|
||||
virtual void SetSampleOffset(UInt32 offset) = 0;
|
||||
virtual void SetVelocity(const Vector3f& velocity) = 0;
|
||||
virtual void SetVolume(float volume) = 0;
|
||||
|
||||
virtual void Stop() = 0;
|
||||
|
||||
virtual std::shared_ptr<AudioBuffer> TryUnqueueProcessedBuffer() = 0;
|
||||
|
||||
virtual void UnqueueAllBuffers() = 0;
|
||||
|
||||
AudioSource& operator=(const AudioSource&) = delete;
|
||||
AudioSource& operator=(AudioSource&&) = delete;
|
||||
|
||||
private:
|
||||
std::shared_ptr<AudioDevice> m_device;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/AudioSource.inl>
|
||||
|
||||
#endif // NAZARA_AUDIO_AUDIOSOURCE_HPP
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (C) 2022 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/AudioSource.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline AudioSource::AudioSource(std::shared_ptr<AudioDevice> device) :
|
||||
m_device(std::move(device))
|
||||
{
|
||||
}
|
||||
|
||||
inline const std::shared_ptr<AudioDevice>& AudioSource::GetAudioDevice() const
|
||||
{
|
||||
return m_device;
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/DebugOff.hpp>
|
||||
|
|
@ -40,9 +40,6 @@
|
|||
// Activate the security tests based on the code (Advised for development)
|
||||
#define NAZARA_AUDIO_SAFE 1
|
||||
|
||||
// The number of buffers used for audio streaming (At least two)
|
||||
#define NAZARA_AUDIO_STREAMED_BUFFER_COUNT 2
|
||||
|
||||
/// Checking the values and types of certain constants
|
||||
#include <Nazara/Audio/ConfigCheck.hpp>
|
||||
|
||||
|
|
|
|||
|
|
@ -18,8 +18,6 @@
|
|||
#define NAZARA_AUDIO_MANAGE_MEMORY 0
|
||||
#endif
|
||||
|
||||
NazaraCheckTypeAndVal(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, integral, >, 0, " shall be a strictly positive integer");
|
||||
|
||||
#undef NazaraCheckTypeAndVal
|
||||
|
||||
#endif // NAZARA_AUDIO_CONFIGCHECK_HPP
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
#ifndef NAZARA_AUDIO_ENUMS_HPP
|
||||
#define NAZARA_AUDIO_ENUMS_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
enum class AudioFormat
|
||||
|
|
|
|||
|
|
@ -11,20 +11,24 @@
|
|||
#include <Nazara/Audio/Enums.hpp>
|
||||
#include <Nazara/Audio/SoundEmitter.hpp>
|
||||
#include <Nazara/Audio/SoundStream.hpp>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
struct MusicImpl;
|
||||
class AudioBuffer;
|
||||
|
||||
class NAZARA_AUDIO_API Music : public Resource, public SoundEmitter
|
||||
{
|
||||
public:
|
||||
Music();
|
||||
Music(AudioDevice& device);
|
||||
Music(const Music&) = delete;
|
||||
Music(Music&&) noexcept;
|
||||
Music(Music&&) noexcept = default;
|
||||
~Music();
|
||||
|
||||
bool Create(std::shared_ptr<SoundStream> soundStream);
|
||||
|
|
@ -53,12 +57,22 @@ namespace Nz
|
|||
void Stop() override;
|
||||
|
||||
Music& operator=(const Music&) = delete;
|
||||
Music& operator=(Music&&) noexcept;
|
||||
Music& operator=(Music&&) noexcept = default;
|
||||
|
||||
private:
|
||||
std::unique_ptr<MusicImpl> m_impl;
|
||||
AudioFormat m_audioFormat;
|
||||
std::atomic_bool m_streaming;
|
||||
std::atomic<UInt64> m_processedSamples;
|
||||
mutable std::mutex m_bufferLock;
|
||||
std::size_t m_bufferCount;
|
||||
std::shared_ptr<SoundStream> m_stream;
|
||||
std::thread m_thread;
|
||||
std::vector<Int16> m_chunkSamples;
|
||||
UInt32 m_sampleRate;
|
||||
UInt64 m_streamOffset;
|
||||
bool m_looping;
|
||||
|
||||
bool FillAndQueueBuffer(unsigned int buffer);
|
||||
bool FillAndQueueBuffer(std::shared_ptr<AudioBuffer> buffer);
|
||||
void MusicThread(std::condition_variable& cv, std::mutex& m, std::exception_ptr& err);
|
||||
void StopThread();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,13 +7,9 @@
|
|||
#ifndef NAZARA_AUDIO_OPENAL_HPP
|
||||
#define NAZARA_AUDIO_OPENAL_HPP
|
||||
|
||||
#if defined(NAZARA_AUDIO_OPENAL) || defined(NAZARA_AUDIO_BUILD)
|
||||
// no include reordering
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Audio/Config.hpp>
|
||||
#include <Nazara/Audio/Enums.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#if defined(NAZARA_AUDIO_OPENAL) || defined(NAZARA_AUDIO_BUILD)
|
||||
|
||||
// Inclusion of OpenAL headers
|
||||
|
||||
|
|
@ -57,135 +53,102 @@ using OpenALDetail::ALCuint;
|
|||
using OpenALDetail::ALCushort;
|
||||
using OpenALDetail::ALCvoid;
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
using OpenALFunc = void(*)();
|
||||
#define NAZARA_AUDIO_FOREACH_AL_FUNC(cb) \
|
||||
cb(alBuffer3f, OpenALDetail::LPALBUFFER3F) \
|
||||
cb(alBuffer3i, OpenALDetail::LPALBUFFER3I) \
|
||||
cb(alBufferData, OpenALDetail::LPALBUFFERDATA) \
|
||||
cb(alBufferf, OpenALDetail::LPALBUFFERF) \
|
||||
cb(alBufferfv, OpenALDetail::LPALBUFFERFV) \
|
||||
cb(alBufferi, OpenALDetail::LPALBUFFERI) \
|
||||
cb(alBufferiv, OpenALDetail::LPALBUFFERIV) \
|
||||
cb(alDeleteBuffers, OpenALDetail::LPALDELETEBUFFERS) \
|
||||
cb(alDeleteSources, OpenALDetail::LPALDELETESOURCES) \
|
||||
cb(alDisable, OpenALDetail::LPALDISABLE) \
|
||||
cb(alDistanceModel, OpenALDetail::LPALDISTANCEMODEL) \
|
||||
cb(alDopplerFactor, OpenALDetail::LPALDOPPLERFACTOR) \
|
||||
cb(alDopplerVelocity, OpenALDetail::LPALDOPPLERVELOCITY) \
|
||||
cb(alEnable, OpenALDetail::LPALENABLE) \
|
||||
cb(alGenBuffers, OpenALDetail::LPALGENBUFFERS) \
|
||||
cb(alGenSources, OpenALDetail::LPALGENSOURCES) \
|
||||
cb(alGetBoolean, OpenALDetail::LPALGETBOOLEAN) \
|
||||
cb(alGetBooleanv, OpenALDetail::LPALGETBOOLEANV) \
|
||||
cb(alGetBuffer3f, OpenALDetail::LPALGETBUFFER3F) \
|
||||
cb(alGetBuffer3i, OpenALDetail::LPALGETBUFFER3I) \
|
||||
cb(alGetBufferf, OpenALDetail::LPALGETBUFFERF) \
|
||||
cb(alGetBufferfv, OpenALDetail::LPALGETBUFFERFV) \
|
||||
cb(alGetBufferi, OpenALDetail::LPALGETBUFFERI) \
|
||||
cb(alGetBufferiv, OpenALDetail::LPALGETBUFFERIV) \
|
||||
cb(alGetDouble, OpenALDetail::LPALGETDOUBLE) \
|
||||
cb(alGetDoublev, OpenALDetail::LPALGETDOUBLEV) \
|
||||
cb(alGetEnumValue, OpenALDetail::LPALGETENUMVALUE) \
|
||||
cb(alGetError, OpenALDetail::LPALGETERROR) \
|
||||
cb(alGetFloat, OpenALDetail::LPALGETFLOAT) \
|
||||
cb(alGetFloatv, OpenALDetail::LPALGETFLOATV) \
|
||||
cb(alGetInteger, OpenALDetail::LPALGETINTEGER) \
|
||||
cb(alGetIntegerv, OpenALDetail::LPALGETINTEGERV) \
|
||||
cb(alGetListener3f, OpenALDetail::LPALGETLISTENER3F) \
|
||||
cb(alGetListener3i, OpenALDetail::LPALGETLISTENER3I) \
|
||||
cb(alGetListenerf, OpenALDetail::LPALGETLISTENERF) \
|
||||
cb(alGetListenerfv, OpenALDetail::LPALGETLISTENERFV) \
|
||||
cb(alGetListeneri, OpenALDetail::LPALGETLISTENERI) \
|
||||
cb(alGetListeneriv, OpenALDetail::LPALGETLISTENERIV) \
|
||||
cb(alGetProcAddress, OpenALDetail::LPALGETPROCADDRESS) \
|
||||
cb(alGetSource3f, OpenALDetail::LPALGETSOURCE3F) \
|
||||
cb(alGetSource3i, OpenALDetail::LPALGETSOURCE3I) \
|
||||
cb(alGetSourcef, OpenALDetail::LPALGETSOURCEF) \
|
||||
cb(alGetSourcefv, OpenALDetail::LPALGETSOURCEFV) \
|
||||
cb(alGetSourcei, OpenALDetail::LPALGETSOURCEI) \
|
||||
cb(alGetSourceiv, OpenALDetail::LPALGETSOURCEIV) \
|
||||
cb(alGetString, OpenALDetail::LPALGETSTRING) \
|
||||
cb(alIsBuffer, OpenALDetail::LPALISBUFFER) \
|
||||
cb(alIsEnabled, OpenALDetail::LPALISENABLED) \
|
||||
cb(alIsExtensionPresent, OpenALDetail::LPALISEXTENSIONPRESENT) \
|
||||
cb(alIsSource, OpenALDetail::LPALISSOURCE) \
|
||||
cb(alListener3f, OpenALDetail::LPALLISTENER3F) \
|
||||
cb(alListener3i, OpenALDetail::LPALLISTENER3I) \
|
||||
cb(alListenerf, OpenALDetail::LPALLISTENERF) \
|
||||
cb(alListenerfv, OpenALDetail::LPALLISTENERFV) \
|
||||
cb(alListeneri, OpenALDetail::LPALLISTENERI) \
|
||||
cb(alListeneriv, OpenALDetail::LPALLISTENERIV) \
|
||||
cb(alSource3f, OpenALDetail::LPALSOURCE3F) \
|
||||
cb(alSource3i, OpenALDetail::LPALSOURCE3I) \
|
||||
cb(alSourcef, OpenALDetail::LPALSOURCEF) \
|
||||
cb(alSourcefv, OpenALDetail::LPALSOURCEFV) \
|
||||
cb(alSourcei, OpenALDetail::LPALSOURCEI) \
|
||||
cb(alSourceiv, OpenALDetail::LPALSOURCEIV) \
|
||||
cb(alSourcePause, OpenALDetail::LPALSOURCEPAUSE) \
|
||||
cb(alSourcePausev, OpenALDetail::LPALSOURCEPAUSEV) \
|
||||
cb(alSourcePlay, OpenALDetail::LPALSOURCEPLAY) \
|
||||
cb(alSourcePlayv, OpenALDetail::LPALSOURCEPLAYV) \
|
||||
cb(alSourceQueueBuffers, OpenALDetail::LPALSOURCEQUEUEBUFFERS) \
|
||||
cb(alSourceRewind, OpenALDetail::LPALSOURCEREWIND) \
|
||||
cb(alSourceRewindv, OpenALDetail::LPALSOURCEREWINDV) \
|
||||
cb(alSourceStop, OpenALDetail::LPALSOURCESTOP) \
|
||||
cb(alSourceStopv, OpenALDetail::LPALSOURCESTOPV) \
|
||||
cb(alSourceUnqueueBuffers, OpenALDetail::LPALSOURCEUNQUEUEBUFFERS) \
|
||||
cb(alSpeedOfSound, OpenALDetail::LPALSPEEDOFSOUND)
|
||||
|
||||
class NAZARA_AUDIO_API OpenAL
|
||||
{
|
||||
public:
|
||||
static OpenALFunc GetEntry(const std::string& entryPoint);
|
||||
static std::string GetRendererName();
|
||||
static std::string GetVendorName();
|
||||
static unsigned int GetVersion();
|
||||
|
||||
static bool Initialize(bool openDevice = true);
|
||||
|
||||
static bool IsInitialized();
|
||||
|
||||
static std::size_t QueryInputDevices(std::vector<std::string>& devices);
|
||||
static std::size_t QueryOutputDevices(std::vector<std::string>& devices);
|
||||
|
||||
static bool SetDevice(const std::string& deviceName);
|
||||
|
||||
static void Uninitialize();
|
||||
|
||||
static ALenum AudioFormat[AudioFormatCount];
|
||||
|
||||
private:
|
||||
static void CloseDevice();
|
||||
static bool OpenDevice();
|
||||
static OpenALFunc LoadEntry(const char* name, bool throwException = false);
|
||||
};
|
||||
|
||||
// al
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALBUFFER3F alBuffer3f;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALBUFFER3I alBuffer3i;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALBUFFERDATA alBufferData;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALBUFFERF alBufferf;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALBUFFERFV alBufferfv;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALBUFFERI alBufferi;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALBUFFERIV alBufferiv;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALDELETEBUFFERS alDeleteBuffers;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALDELETESOURCES alDeleteSources;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALDISABLE alDisable;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALDISTANCEMODEL alDistanceModel;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALDOPPLERFACTOR alDopplerFactor;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALDOPPLERVELOCITY alDopplerVelocity;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALENABLE alEnable;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGENBUFFERS alGenBuffers;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGENSOURCES alGenSources;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETBOOLEAN alGetBoolean;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETBOOLEANV alGetBooleanv;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETBUFFER3F alGetBuffer3f;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETBUFFER3I alGetBuffer3i;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETBUFFERF alGetBufferf;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETBUFFERFV alGetBufferfv;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETBUFFERI alGetBufferi;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETBUFFERIV alGetBufferiv;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETDOUBLE alGetDouble;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETDOUBLEV alGetDoublev;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETENUMVALUE alGetEnumValue;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETERROR alGetError;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETFLOAT alGetFloat;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETFLOATV alGetFloatv;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETINTEGER alGetInteger;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETINTEGERV alGetIntegerv;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETLISTENER3F alGetListener3f;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETLISTENER3I alGetListener3i;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETLISTENERF alGetListenerf;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETLISTENERFV alGetListenerfv;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETLISTENERI alGetListeneri;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETLISTENERIV alGetListeneriv;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETPROCADDRESS alGetProcAddress;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETSOURCE3F alGetSource3f;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETSOURCE3I alGetSource3i;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETSOURCEF alGetSourcef;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETSOURCEFV alGetSourcefv;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETSOURCEI alGetSourcei;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETSOURCEIV alGetSourceiv;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALGETSTRING alGetString;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALISBUFFER alIsBuffer;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALISENABLED alIsEnabled;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALISEXTENSIONPRESENT alIsExtensionPresent;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALISSOURCE alIsSource;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALLISTENER3F alListener3f;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALLISTENER3I alListener3i;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALLISTENERF alListenerf;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALLISTENERFV alListenerfv;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALLISTENERI alListeneri;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALLISTENERIV alListeneriv;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALSOURCE3F alSource3f;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALSOURCE3I alSource3i;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALSOURCEF alSourcef;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALSOURCEFV alSourcefv;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALSOURCEI alSourcei;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALSOURCEIV alSourceiv;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALSOURCEPAUSE alSourcePause;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALSOURCEPAUSEV alSourcePausev;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALSOURCEPLAY alSourcePlay;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALSOURCEPLAYV alSourcePlayv;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALSOURCEQUEUEBUFFERS alSourceQueueBuffers;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALSOURCEREWIND alSourceRewind;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALSOURCEREWINDV alSourceRewindv;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALSOURCESTOP alSourceStop;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALSOURCESTOPV alSourceStopv;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALSOURCEUNQUEUEBUFFERS alSourceUnqueueBuffers;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALSPEEDOFSOUND alSpeedOfSound;
|
||||
|
||||
// alc
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCCAPTURECLOSEDEVICE alcCaptureCloseDevice;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCCAPTUREOPENDEVICE alcCaptureOpenDevice;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCCAPTURESAMPLES alcCaptureSamples;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCCAPTURESTART alcCaptureStart;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCCAPTURESTOP alcCaptureStop;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCCLOSEDEVICE alcCloseDevice;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCCREATECONTEXT alcCreateContext;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCDESTROYCONTEXT alcDestroyContext;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCGETCONTEXTSDEVICE alcGetContextsDevice;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCGETCURRENTCONTEXT alcGetCurrentContext;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCGETENUMVALUE alcGetEnumValue;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCGETERROR alcGetError;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCGETINTEGERV alcGetIntegerv;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCGETPROCADDRESS alcGetProcAddress;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCGETSTRING alcGetString;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCISEXTENSIONPRESENT alcIsExtensionPresent;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCMAKECONTEXTCURRENT alcMakeContextCurrent;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCOPENDEVICE alcOpenDevice;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCPROCESSCONTEXT alcProcessContext;
|
||||
NAZARA_AUDIO_API extern OpenALDetail::LPALCSUSPENDCONTEXT alcSuspendContext;
|
||||
|
||||
}
|
||||
#define NAZARA_AUDIO_FOREACH_ALC_FUNC(cb) \
|
||||
cb(alcCaptureCloseDevice, OpenALDetail::LPALCCAPTURECLOSEDEVICE) \
|
||||
cb(alcCaptureOpenDevice, OpenALDetail::LPALCCAPTUREOPENDEVICE) \
|
||||
cb(alcCaptureSamples, OpenALDetail::LPALCCAPTURESAMPLES) \
|
||||
cb(alcCaptureStart, OpenALDetail::LPALCCAPTURESTART) \
|
||||
cb(alcCaptureStop, OpenALDetail::LPALCCAPTURESTOP) \
|
||||
cb(alcCloseDevice, OpenALDetail::LPALCCLOSEDEVICE) \
|
||||
cb(alcCreateContext, OpenALDetail::LPALCCREATECONTEXT) \
|
||||
cb(alcDestroyContext, OpenALDetail::LPALCDESTROYCONTEXT) \
|
||||
cb(alcGetContextsDevice, OpenALDetail::LPALCGETCONTEXTSDEVICE) \
|
||||
cb(alcGetCurrentContext, OpenALDetail::LPALCGETCURRENTCONTEXT) \
|
||||
cb(alcGetEnumValue, OpenALDetail::LPALCGETENUMVALUE) \
|
||||
cb(alcGetError, OpenALDetail::LPALCGETERROR) \
|
||||
cb(alcGetIntegerv, OpenALDetail::LPALCGETINTEGERV) \
|
||||
cb(alcGetProcAddress, OpenALDetail::LPALCGETPROCADDRESS) \
|
||||
cb(alcGetString, OpenALDetail::LPALCGETSTRING) \
|
||||
cb(alcIsExtensionPresent, OpenALDetail::LPALCISEXTENSIONPRESENT) \
|
||||
cb(alcMakeContextCurrent, OpenALDetail::LPALCMAKECONTEXTCURRENT) \
|
||||
cb(alcOpenDevice, OpenALDetail::LPALCOPENDEVICE) \
|
||||
cb(alcProcessContext, OpenALDetail::LPALCPROCESSCONTEXT) \
|
||||
cb(alcSuspendContext, OpenALDetail::LPALCSUSPENDCONTEXT) \
|
||||
|
||||
#endif // NAZARA_AUDIO_OPENAL
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (C) 2022 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
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_AUDIO_OPENALBUFFER_HPP
|
||||
#define NAZARA_AUDIO_OPENALBUFFER_HPP
|
||||
|
||||
#if defined(NAZARA_AUDIO_OPENAL) || defined(NAZARA_AUDIO_BUILD)
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Audio/AudioBuffer.hpp>
|
||||
#include <Nazara/Audio/Config.hpp>
|
||||
#include <Nazara/Audio/OpenAL.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class OpenALDevice;
|
||||
class OpenALLibrary;
|
||||
|
||||
class NAZARA_AUDIO_API OpenALBuffer final : public AudioBuffer
|
||||
{
|
||||
public:
|
||||
inline OpenALBuffer(std::shared_ptr<AudioDevice> device, OpenALLibrary& library, ALuint bufferId);
|
||||
OpenALBuffer(const OpenALBuffer&) = delete;
|
||||
OpenALBuffer(OpenALBuffer&&) = delete;
|
||||
~OpenALBuffer();
|
||||
|
||||
inline ALuint GetBufferId() const;
|
||||
UInt32 GetSampleCount() const override;
|
||||
UInt32 GetSize() const override;
|
||||
UInt32 GetSampleRate() const override;
|
||||
|
||||
bool Reset(AudioFormat format, UInt64 sampleCount, UInt32 sampleRate, const void* samples) override;
|
||||
|
||||
OpenALBuffer& operator=(const OpenALBuffer&) = delete;
|
||||
OpenALBuffer& operator=(OpenALBuffer&&) = delete;
|
||||
|
||||
private:
|
||||
OpenALDevice& GetDevice();
|
||||
const OpenALDevice& GetDevice() const;
|
||||
|
||||
ALuint m_bufferId;
|
||||
OpenALLibrary& m_library;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/OpenALBuffer.inl>
|
||||
|
||||
#endif // NAZARA_AUDIO_OPENAL
|
||||
|
||||
#endif // NAZARA_AUDIO_OPENALBUFFER_HPP
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright (C) 2022 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/OpenALBuffer.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline OpenALBuffer::OpenALBuffer(std::shared_ptr<AudioDevice> device, OpenALLibrary& library, ALuint bufferId) :
|
||||
AudioBuffer(std::move(device)),
|
||||
m_bufferId(bufferId),
|
||||
m_library(library)
|
||||
{
|
||||
}
|
||||
|
||||
inline ALuint OpenALBuffer::GetBufferId() const
|
||||
{
|
||||
return m_bufferId;
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/DebugOff.hpp>
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
// Copyright (C) 2022 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
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_AUDIO_OPENALDEVICE_HPP
|
||||
#define NAZARA_AUDIO_OPENALDEVICE_HPP
|
||||
|
||||
#if defined(NAZARA_AUDIO_OPENAL) || defined(NAZARA_AUDIO_BUILD)
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Audio/AudioDevice.hpp>
|
||||
#include <Nazara/Audio/Config.hpp>
|
||||
#include <Nazara/Audio/Enums.hpp>
|
||||
#include <Nazara/Audio/OpenAL.hpp>
|
||||
#include <Nazara/Core/MovablePtr.hpp>
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class OpenALLibrary;
|
||||
|
||||
class NAZARA_AUDIO_API OpenALDevice : public AudioDevice
|
||||
{
|
||||
friend OpenALLibrary;
|
||||
|
||||
public:
|
||||
OpenALDevice(OpenALLibrary& library, ALCdevice* device);
|
||||
OpenALDevice(const OpenALDevice&) = delete;
|
||||
OpenALDevice(OpenALDevice&&) = default;
|
||||
~OpenALDevice();
|
||||
|
||||
std::shared_ptr<AudioBuffer> CreateBuffer() override;
|
||||
std::shared_ptr<AudioSource> CreateSource() override;
|
||||
|
||||
float GetDopplerFactor() const override;
|
||||
float GetGlobalVolume() const override;
|
||||
Vector3f GetListenerDirection(Vector3f* up = nullptr) const override;
|
||||
Vector3f GetListenerPosition() const override;
|
||||
Quaternionf GetListenerRotation(Vector3f* up = nullptr) const override;
|
||||
Vector3f GetListenerVelocity() const override;
|
||||
float GetSpeedOfSound() const override;
|
||||
|
||||
bool IsFormatSupported(AudioFormat format) const override;
|
||||
|
||||
void MakeContextCurrent() const;
|
||||
|
||||
void SetDopplerFactor(float dopplerFactor) override;
|
||||
void SetGlobalVolume(float volume) override;
|
||||
void SetListenerDirection(const Vector3f& direction, const Vector3f& up = Vector3f::Up()) override;
|
||||
void SetListenerPosition(const Vector3f& position) override;
|
||||
void SetListenerVelocity(const Vector3f& velocity) override;
|
||||
void SetSpeedOfSound(float speed) override;
|
||||
|
||||
inline ALenum TranslateAudioFormat(AudioFormat format) const;
|
||||
|
||||
OpenALDevice& operator=(const OpenALDevice&) = delete;
|
||||
OpenALDevice& operator=(OpenALDevice&&) = default;
|
||||
|
||||
private:
|
||||
std::array<ALenum, AudioFormatCount> m_audioFormatValues;
|
||||
std::string m_renderer;
|
||||
std::string m_vendor;
|
||||
OpenALLibrary& m_library;
|
||||
MovablePtr<ALCcontext> m_context;
|
||||
MovablePtr<ALCdevice> m_device;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/OpenALDevice.inl>
|
||||
|
||||
#endif // NAZARA_AUDIO_OPENAL
|
||||
|
||||
#endif // NAZARA_AUDIO_OPENALDEVICE_HPP
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright (C) 2022 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/Core/Algorithm.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline ALenum OpenALDevice::TranslateAudioFormat(AudioFormat format) const
|
||||
{
|
||||
return m_audioFormatValues[UnderlyingCast(format)];
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/DebugOff.hpp>
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright (C) 2022 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
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_AUDIO_OPENALLIBRARY_HPP
|
||||
#define NAZARA_AUDIO_OPENALLIBRARY_HPP
|
||||
|
||||
#if defined(NAZARA_AUDIO_OPENAL) || defined(NAZARA_AUDIO_BUILD)
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Audio/Config.hpp>
|
||||
#include <Nazara/Audio/Enums.hpp>
|
||||
#include <Nazara/Audio/OpenAL.hpp>
|
||||
#include <Nazara/Audio/OpenALDevice.hpp>
|
||||
#include <Nazara/Core/DynLib.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class NAZARA_AUDIO_API OpenALLibrary
|
||||
{
|
||||
public:
|
||||
OpenALLibrary() = default;
|
||||
OpenALLibrary(const OpenALLibrary&) = delete;
|
||||
OpenALLibrary(OpenALLibrary&&) = delete;
|
||||
inline ~OpenALLibrary();
|
||||
|
||||
bool Load();
|
||||
|
||||
std::vector<std::string> QueryInputDevices();
|
||||
std::vector<std::string> QueryOutputDevices();
|
||||
|
||||
std::shared_ptr<OpenALDevice> OpenDevice(const char* name = nullptr);
|
||||
|
||||
void Unload();
|
||||
|
||||
OpenALLibrary& operator=(const OpenALLibrary&) = delete;
|
||||
OpenALLibrary& operator=(OpenALLibrary&&) = delete;
|
||||
|
||||
#define NAZARA_AUDIO_FUNC(name, sig) sig name;
|
||||
NAZARA_AUDIO_FOREACH_AL_FUNC(NAZARA_AUDIO_FUNC)
|
||||
NAZARA_AUDIO_FOREACH_ALC_FUNC(NAZARA_AUDIO_FUNC)
|
||||
#undef NAZARA_AUDIO_FUNC
|
||||
|
||||
private:
|
||||
std::vector<std::string> ParseDevices(const char* deviceString);
|
||||
|
||||
DynLib m_library;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/OpenALLibrary.inl>
|
||||
|
||||
#endif // NAZARA_AUDIO_OPENAL
|
||||
|
||||
#endif // NAZARA_AUDIO_OPENALLIBRARY_HPP
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (C) 2022 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/OpenALLibrary.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline OpenALLibrary::~OpenALLibrary()
|
||||
{
|
||||
Unload();
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/DebugOff.hpp>
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright (C) 2022 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
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_AUDIO_OPENALSOURCE_HPP
|
||||
#define NAZARA_AUDIO_OPENALSOURCE_HPP
|
||||
|
||||
#if defined(NAZARA_AUDIO_OPENAL) || defined(NAZARA_AUDIO_BUILD)
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Audio/AudioSource.hpp>
|
||||
#include <Nazara/Audio/Config.hpp>
|
||||
#include <Nazara/Audio/OpenAL.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class OpenALBuffer;
|
||||
class OpenALDevice;
|
||||
class OpenALLibrary;
|
||||
|
||||
class NAZARA_AUDIO_API OpenALSource final : public AudioSource
|
||||
{
|
||||
public:
|
||||
inline OpenALSource(std::shared_ptr<AudioDevice> device, OpenALLibrary& library, ALuint sourceId);
|
||||
OpenALSource(const OpenALSource&) = delete;
|
||||
OpenALSource(OpenALSource&&) = delete;
|
||||
~OpenALSource();
|
||||
|
||||
void EnableLooping(bool loop) override;
|
||||
void EnableSpatialization(bool spatialization) override;
|
||||
|
||||
float GetAttenuation() const override;
|
||||
float GetMinDistance() const override;
|
||||
float GetPitch() const override;
|
||||
Vector3f GetPosition() const override;
|
||||
UInt32 GetSampleOffset() const override;
|
||||
Vector3f GetVelocity() const override;
|
||||
SoundStatus GetStatus() const override;
|
||||
float GetVolume() const override;
|
||||
|
||||
bool IsLooping() const override;
|
||||
bool IsSpatializationEnabled() const override;
|
||||
|
||||
void QueueBuffer(std::shared_ptr<AudioBuffer> audioBuffer) override;
|
||||
|
||||
void Pause() override;
|
||||
void Play() override;
|
||||
|
||||
void SetAttenuation(float attenuation) override;
|
||||
void SetBuffer(std::shared_ptr<AudioBuffer> audioBuffer) override;
|
||||
void SetMinDistance(float minDistance) override;
|
||||
void SetPitch(float pitch) override;
|
||||
void SetPosition(const Vector3f& position) override;
|
||||
void SetSampleOffset(UInt32 offset) override;
|
||||
void SetVelocity(const Vector3f& velocity) override;
|
||||
void SetVolume(float volume) override;
|
||||
|
||||
void Stop() override;
|
||||
|
||||
std::shared_ptr<AudioBuffer> TryUnqueueProcessedBuffer() override;
|
||||
|
||||
void UnqueueAllBuffers() override;
|
||||
|
||||
OpenALSource& operator=(const OpenALSource&) = delete;
|
||||
OpenALSource& operator=(OpenALSource&&) = delete;
|
||||
|
||||
private:
|
||||
OpenALDevice& GetDevice();
|
||||
const OpenALDevice& GetDevice() const;
|
||||
|
||||
std::shared_ptr<OpenALBuffer> m_currentBuffer;
|
||||
std::vector<std::shared_ptr<OpenALBuffer>> m_queuedBuffers;
|
||||
ALuint m_sourceId;
|
||||
OpenALLibrary& m_library;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/OpenALSource.inl>
|
||||
|
||||
#endif // NAZARA_AUDIO_OPENAL
|
||||
|
||||
#endif // NAZARA_AUDIO_OPENALSOURCE_HPP
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (C) 2022 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/OpenALSource.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline OpenALSource::OpenALSource(std::shared_ptr<AudioDevice> device, OpenALLibrary& library, ALuint sourceId) :
|
||||
AudioSource(std::move(device)),
|
||||
m_sourceId(sourceId),
|
||||
m_library(library)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/DebugOff.hpp>
|
||||
|
|
@ -17,15 +17,16 @@ namespace Nz
|
|||
class NAZARA_AUDIO_API Sound : public SoundEmitter
|
||||
{
|
||||
public:
|
||||
Sound() = default;
|
||||
Sound(std::shared_ptr<const SoundBuffer> soundBuffer);
|
||||
using SoundEmitter::SoundEmitter;
|
||||
Sound();
|
||||
Sound(AudioDevice& audioDevice, std::shared_ptr<SoundBuffer> soundBuffer);
|
||||
Sound(const Sound&) = default;
|
||||
Sound(Sound&&) noexcept = default;
|
||||
Sound(Sound&&) = default;
|
||||
~Sound();
|
||||
|
||||
void EnableLooping(bool loop) override;
|
||||
|
||||
const std::shared_ptr<const SoundBuffer>& GetBuffer() const;
|
||||
const std::shared_ptr<SoundBuffer>& GetBuffer() const;
|
||||
UInt32 GetDuration() const override;
|
||||
UInt32 GetPlayingOffset() const override;
|
||||
SoundStatus GetStatus() const override;
|
||||
|
|
@ -40,16 +41,16 @@ namespace Nz
|
|||
void Pause() override;
|
||||
void Play() override;
|
||||
|
||||
void SetBuffer(std::shared_ptr<const SoundBuffer> soundBuffer);
|
||||
void SetBuffer(std::shared_ptr<SoundBuffer> soundBuffer);
|
||||
void SetPlayingOffset(UInt32 offset);
|
||||
|
||||
void Stop() override;
|
||||
|
||||
Sound& operator=(const Sound&) = delete; ///TODO?
|
||||
Sound& operator=(Sound&&) noexcept = default;
|
||||
Sound& operator=(const Sound&) = default;
|
||||
Sound& operator=(Sound&&) = default;
|
||||
|
||||
private:
|
||||
std::shared_ptr<const SoundBuffer> m_buffer;
|
||||
std::shared_ptr<SoundBuffer> m_buffer;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#define NAZARA_AUDIO_SOUNDBUFFER_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Audio/AudioDevice.hpp>
|
||||
#include <Nazara/Audio/Config.hpp>
|
||||
#include <Nazara/Audio/Enums.hpp>
|
||||
#include <Nazara/Core/ObjectLibrary.hpp>
|
||||
|
|
@ -15,7 +16,8 @@
|
|||
#include <Nazara/Core/ResourceLoader.hpp>
|
||||
#include <Nazara/Core/ResourceManager.hpp>
|
||||
#include <Nazara/Core/ResourceParameters.hpp>
|
||||
#include <Nazara/Core/Signal.hpp>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
|
|
@ -26,6 +28,8 @@ namespace Nz
|
|||
bool IsValid() const;
|
||||
};
|
||||
|
||||
class AudioBuffer;
|
||||
class AudioDevice;
|
||||
class Sound;
|
||||
class SoundBuffer;
|
||||
|
||||
|
|
@ -40,36 +44,41 @@ namespace Nz
|
|||
friend Sound;
|
||||
|
||||
public:
|
||||
SoundBuffer();
|
||||
SoundBuffer() = default;
|
||||
SoundBuffer(AudioFormat format, UInt64 sampleCount, UInt32 sampleRate, const Int16* samples);
|
||||
SoundBuffer(const SoundBuffer&) = delete;
|
||||
SoundBuffer(SoundBuffer&&) = delete;
|
||||
~SoundBuffer();
|
||||
~SoundBuffer() = default;
|
||||
|
||||
bool Create(AudioFormat format, UInt64 sampleCount, UInt32 sampleRate, const Int16* samples);
|
||||
void Destroy();
|
||||
const std::shared_ptr<AudioBuffer>& GetBuffer(AudioDevice* device);
|
||||
|
||||
UInt32 GetDuration() const;
|
||||
AudioFormat GetFormat() const;
|
||||
const Int16* GetSamples() const;
|
||||
UInt64 GetSampleCount() const;
|
||||
UInt32 GetSampleRate() const;
|
||||
|
||||
bool IsValid() const;
|
||||
inline UInt32 GetDuration() const;
|
||||
inline AudioFormat GetFormat() const;
|
||||
inline const Int16* GetSamples() const;
|
||||
inline UInt64 GetSampleCount() const;
|
||||
inline UInt32 GetSampleRate() const;
|
||||
|
||||
SoundBuffer& operator=(const SoundBuffer&) = delete;
|
||||
SoundBuffer& operator=(SoundBuffer&&) = delete;
|
||||
|
||||
static bool IsFormatSupported(AudioFormat format);
|
||||
|
||||
static std::shared_ptr<SoundBuffer> LoadFromFile(const std::filesystem::path& filePath, const SoundBufferParams& params = SoundBufferParams());
|
||||
static std::shared_ptr<SoundBuffer> LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params = SoundBufferParams());
|
||||
static std::shared_ptr<SoundBuffer> LoadFromStream(Stream& stream, const SoundBufferParams& params = SoundBufferParams());
|
||||
|
||||
private:
|
||||
unsigned int GetOpenALBuffer() const;
|
||||
struct AudioDeviceEntry
|
||||
{
|
||||
std::shared_ptr<AudioBuffer> audioBuffer;
|
||||
|
||||
std::unique_ptr<SoundBufferImpl> m_impl;
|
||||
NazaraSlot(AudioDevice, OnAudioDeviceRelease, audioDeviceReleaseSlot);
|
||||
};
|
||||
|
||||
std::unordered_map<AudioDevice*, AudioDeviceEntry> m_audioBufferByDevice;
|
||||
std::unique_ptr<Int16[]> m_samples;
|
||||
AudioFormat m_format;
|
||||
UInt32 m_duration;
|
||||
UInt32 m_sampleRate;
|
||||
UInt64 m_sampleCount;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,64 @@
|
|||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Audio/SoundBuffer.hpp>
|
||||
#include <memory>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \brief Gets the duration of the sound buffer
|
||||
* \return Duration of the sound buffer in milliseconds
|
||||
*
|
||||
* \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined
|
||||
*/
|
||||
inline UInt32 SoundBuffer::GetDuration() const
|
||||
{
|
||||
return m_duration;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the format of the sound buffer
|
||||
* \return Enumeration of type AudioFormat (mono, stereo, ...)
|
||||
*
|
||||
* \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined
|
||||
*/
|
||||
inline AudioFormat SoundBuffer::GetFormat() const
|
||||
{
|
||||
return m_format;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the internal raw samples
|
||||
* \return Pointer to raw data
|
||||
*
|
||||
* \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined
|
||||
*/
|
||||
inline const Int16* SoundBuffer::GetSamples() const
|
||||
{
|
||||
return m_samples.get();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the number of samples in the sound buffer
|
||||
* \return Count of samples (number of seconds * sample rate * channel count)
|
||||
*
|
||||
* \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined
|
||||
*/
|
||||
inline UInt64 SoundBuffer::GetSampleCount() const
|
||||
{
|
||||
return m_sampleCount;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the rates of sample in the sound buffer
|
||||
* \return Rate of sample in Hertz (Hz)
|
||||
*
|
||||
* \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined
|
||||
*/
|
||||
inline UInt32 SoundBuffer::GetSampleRate() const
|
||||
{
|
||||
return m_sampleRate;
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Audio/DebugOff.hpp>
|
||||
|
|
|
|||
|
|
@ -17,10 +17,15 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
class AudioDevice;
|
||||
class AudioSource;
|
||||
|
||||
class NAZARA_AUDIO_API SoundEmitter
|
||||
{
|
||||
public:
|
||||
SoundEmitter(SoundEmitter&& emitter) noexcept;
|
||||
SoundEmitter(AudioDevice& audioDevice);
|
||||
SoundEmitter(const SoundEmitter&) = delete;
|
||||
SoundEmitter(SoundEmitter&&) noexcept = default;
|
||||
virtual ~SoundEmitter();
|
||||
|
||||
virtual void EnableLooping(bool loop) = 0;
|
||||
|
|
@ -38,7 +43,7 @@ namespace Nz
|
|||
|
||||
virtual bool IsLooping() const = 0;
|
||||
inline bool IsPlaying() const;
|
||||
bool IsSpatialized() const;
|
||||
bool IsSpatializationEnabled() const;
|
||||
|
||||
virtual void Pause() = 0;
|
||||
virtual void Play() = 0;
|
||||
|
|
@ -47,25 +52,16 @@ namespace Nz
|
|||
void SetMinDistance(float minDistance);
|
||||
void SetPitch(float pitch);
|
||||
void SetPosition(const Vector3f& position);
|
||||
void SetPosition(float x, float y, float z);
|
||||
void SetVelocity(const Vector3f& velocity);
|
||||
void SetVelocity(float velX, float velY, float velZ);
|
||||
void SetVolume(float volume);
|
||||
|
||||
virtual void Stop() = 0;
|
||||
|
||||
SoundEmitter& operator=(const SoundEmitter&) = delete;
|
||||
SoundEmitter& operator=(SoundEmitter&&) noexcept;
|
||||
SoundEmitter& operator=(SoundEmitter&&) noexcept = default;
|
||||
|
||||
protected:
|
||||
SoundEmitter();
|
||||
SoundEmitter(const SoundEmitter& emitter);
|
||||
|
||||
SoundStatus GetInternalStatus() const;
|
||||
|
||||
static constexpr unsigned int InvalidSource = std::numeric_limits<unsigned int>::max();
|
||||
|
||||
unsigned int m_source;
|
||||
std::shared_ptr<AudioSource> m_source;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
* \ingroup math
|
||||
* \ingroup math
|
||||
* \class Nz::Box
|
||||
* \brief Math class that represents a three dimensional box
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Shader module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
// no header guards
|
||||
|
||||
#if !defined(NAZARA_SHADERLANG_ERROR) && (!defined(NAZARA_SHADERLANG_LEXER_ERROR) || !defined(NAZARA_SHADERLANG_PARSER_ERROR) || !defined(NAZARA_SHADERLANG_COMPILER_ERROR))
|
||||
#error You must define NAZARA_SHADERLANG_ERROR or NAZARA_SHADERLANG_LEXER_ERROR/NAZARA_SHADERLANG_PARSER_ERROR/NAZARA_SHADERLANG_COMPILER_ERROR before including this file
|
||||
#endif
|
||||
|
||||
#ifndef NAZARA_SHADERLANG_LEXER_ERROR
|
||||
#define NAZARA_SHADERLANG_LEXER_ERROR(...) NAZARA_SHADERLANG_ERROR(L, ...)
|
||||
#endif
|
||||
|
||||
#ifndef NAZARA_SHADERLANG_PARSER_ERROR
|
||||
#define NAZARA_SHADERLANG_PARSER_ERROR(...) NAZARA_SHADERLANG_ERROR(P, ...)
|
||||
#endif
|
||||
|
||||
#ifndef NAZARA_SHADERLANG_COMPILER_ERROR
|
||||
#define NAZARA_SHADERLANG_COMPILER_ERROR(...) NAZARA_SHADERLANG_COMPILER_ERROR(C, ...)
|
||||
#endif
|
||||
|
||||
// Lexer errors
|
||||
NAZARA_SHADERLANG_LEXER_ERROR(1, BadNumber, "bad number")
|
||||
NAZARA_SHADERLANG_LEXER_ERROR(2, NumberOutOfRange, "number is out of range")
|
||||
NAZARA_SHADERLANG_LEXER_ERROR(3, UnfinishedString, "unfinished string")
|
||||
NAZARA_SHADERLANG_LEXER_ERROR(4, UnrecognizedChar, "unrecognized character")
|
||||
NAZARA_SHADERLANG_LEXER_ERROR(5, UnrecognizedToken, "unrecognized token")
|
||||
|
||||
// Parser errors
|
||||
NAZARA_SHADERLANG_PARSER_ERROR(1, AttributeError, "attribute error")
|
||||
NAZARA_SHADERLANG_PARSER_ERROR(2, ExpectedToken, "expected token")
|
||||
NAZARA_SHADERLANG_PARSER_ERROR(3, DuplicateIdentifier, "duplicate identifier")
|
||||
NAZARA_SHADERLANG_PARSER_ERROR(4, DuplicateModule, "duplicate module")
|
||||
NAZARA_SHADERLANG_PARSER_ERROR(5, ReservedKeyword, "reserved keyword")
|
||||
NAZARA_SHADERLANG_PARSER_ERROR(6, UnknownAttribute, "unknown attribute")
|
||||
NAZARA_SHADERLANG_PARSER_ERROR(7, UnknownType, "unknown type")
|
||||
NAZARA_SHADERLANG_PARSER_ERROR(8, UnexpectedToken, "unexpected token")
|
||||
|
||||
// Compiler errors
|
||||
|
||||
#undef NAZARA_SHADERLANG_ERROR
|
||||
#undef NAZARA_SHADERLANG_COMPILER_ERROR
|
||||
#undef NAZARA_SHADERLANG_LEXER_ERROR
|
||||
#undef NAZARA_SHADERLANG_PARSER_ERROR
|
||||
|
|
@ -3,10 +3,11 @@
|
|||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Audio/Audio.hpp>
|
||||
#include <Nazara/Audio/AudioBuffer.hpp>
|
||||
#include <Nazara/Audio/AudioSource.hpp>
|
||||
#include <Nazara/Audio/Config.hpp>
|
||||
#include <Nazara/Audio/Enums.hpp>
|
||||
#include <Nazara/Audio/OpenAL.hpp>
|
||||
#include <Nazara/Audio/SoundBuffer.hpp>
|
||||
#include <Nazara/Audio/OpenALLibrary.hpp>
|
||||
#include <Nazara/Audio/Formats/drwavLoader.hpp>
|
||||
#include <Nazara/Audio/Formats/libflacLoader.hpp>
|
||||
#include <Nazara/Audio/Formats/libvorbisLoader.hpp>
|
||||
|
|
@ -20,6 +21,11 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
OpenALLibrary s_openalLibrary;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup audio
|
||||
* \class Nz::Audio
|
||||
|
|
@ -29,12 +35,9 @@ namespace Nz
|
|||
Audio::Audio(Config /*config*/) :
|
||||
ModuleBase("Audio", this)
|
||||
{
|
||||
// Initialisation of OpenAL
|
||||
if (!OpenAL::Initialize())
|
||||
throw std::runtime_error("failed to initialize OpenAL");
|
||||
|
||||
// Definition of the orientation by default
|
||||
SetListenerDirection(Vector3f::Forward());
|
||||
// Load OpenAL
|
||||
if (!s_openalLibrary.Load())
|
||||
throw std::runtime_error("failed to load OpenAL");
|
||||
|
||||
// Loaders
|
||||
m_soundBufferLoader.RegisterLoader(Loaders::GetSoundBufferLoader_drwav());
|
||||
|
|
@ -45,88 +48,19 @@ namespace Nz
|
|||
m_soundStreamLoader.RegisterLoader(Loaders::GetSoundStreamLoader_libvorbis());
|
||||
m_soundBufferLoader.RegisterLoader(Loaders::GetSoundBufferLoader_minimp3());
|
||||
m_soundStreamLoader.RegisterLoader(Loaders::GetSoundStreamLoader_minimp3());
|
||||
|
||||
m_defaultDevice = s_openalLibrary.OpenDevice();
|
||||
}
|
||||
|
||||
Audio::~Audio()
|
||||
{
|
||||
OpenAL::Uninitialize();
|
||||
m_defaultDevice.reset();
|
||||
s_openalLibrary.Unload();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the factor of the doppler effect
|
||||
* \return Global factor of the doppler effect
|
||||
*/
|
||||
float Audio::GetDopplerFactor() const
|
||||
const std::shared_ptr<AudioDevice>& Audio::GetDefaultDevice() const
|
||||
{
|
||||
return alGetFloat(AL_DOPPLER_FACTOR);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the global volume
|
||||
* \return Float between [0, inf) with 100.f being the default
|
||||
*/
|
||||
float Audio::GetGlobalVolume() const
|
||||
{
|
||||
ALfloat gain = 0.f;
|
||||
alGetListenerf(AL_GAIN, &gain);
|
||||
|
||||
return gain * 100.f;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the direction of the listener
|
||||
* \return Direction of the listener, in front of the listener
|
||||
*
|
||||
* \see GetListenerRotation
|
||||
*/
|
||||
Vector3f Audio::GetListenerDirection() const
|
||||
{
|
||||
ALfloat orientation[6];
|
||||
alGetListenerfv(AL_ORIENTATION, orientation);
|
||||
|
||||
return Vector3f(orientation[0], orientation[1], orientation[2]);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the position of the listener
|
||||
* \return Position of the listener
|
||||
*
|
||||
* \see GetListenerVelocity
|
||||
*/
|
||||
Vector3f Audio::GetListenerPosition() const
|
||||
{
|
||||
Vector3f position;
|
||||
alGetListenerfv(AL_POSITION, &position.x);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the rotation of the listener
|
||||
* \return Rotation of the listener
|
||||
*/
|
||||
Quaternionf Audio::GetListenerRotation() const
|
||||
{
|
||||
ALfloat orientation[6];
|
||||
alGetListenerfv(AL_ORIENTATION, orientation);
|
||||
|
||||
Vector3f forward(orientation[0], orientation[1], orientation[2]);
|
||||
|
||||
return Quaternionf::RotationBetween(Vector3f::Forward(), forward);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the velocity of the listener
|
||||
* \return Velocity of the listener
|
||||
*
|
||||
* \see GetListenerPosition
|
||||
*/
|
||||
Vector3f Audio::GetListenerVelocity() const
|
||||
{
|
||||
Vector3f velocity;
|
||||
alGetListenerfv(AL_VELOCITY, &velocity.x);
|
||||
|
||||
return velocity;
|
||||
return m_defaultDevice;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -165,174 +99,19 @@ namespace Nz
|
|||
return m_soundStreamLoader;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the speed of sound
|
||||
* \return Speed of sound
|
||||
*/
|
||||
float Audio::GetSpeedOfSound() const
|
||||
std::shared_ptr<AudioDevice> Audio::OpenOutputDevice(const std::string& deviceName)
|
||||
{
|
||||
return alGetFloat(AL_SPEED_OF_SOUND);
|
||||
return s_openalLibrary.OpenDevice(deviceName.c_str());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the format is supported by the engine
|
||||
* \return true if it is the case
|
||||
*
|
||||
* \param format Format to check
|
||||
*/
|
||||
bool Audio::IsFormatSupported(AudioFormat format) const
|
||||
std::vector<std::string> Audio::QueryInputDevices() const
|
||||
{
|
||||
if (format == AudioFormat::Unknown)
|
||||
return false;
|
||||
|
||||
return OpenAL::AudioFormat[UnderlyingCast(format)] != 0;
|
||||
return s_openalLibrary.QueryInputDevices();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the factor of the doppler effect
|
||||
*
|
||||
* \param dopplerFactor Global factor of the doppler effect
|
||||
*/
|
||||
|
||||
void Audio::SetDopplerFactor(float dopplerFactor)
|
||||
std::vector<std::string> Audio::QueryOutputDevices() const
|
||||
{
|
||||
alDopplerFactor(dopplerFactor);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the global volume
|
||||
*
|
||||
* \param volume Float between [0, inf) with 100.f being the default
|
||||
*/
|
||||
|
||||
void Audio::SetGlobalVolume(float volume)
|
||||
{
|
||||
alListenerf(AL_GAIN, volume * 0.01f);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the direction of the listener
|
||||
*
|
||||
* \param direction Direction of the listener, in front of the listener
|
||||
*
|
||||
* \see SetListenerDirection, SetListenerRotation
|
||||
*/
|
||||
|
||||
void Audio::SetListenerDirection(const Vector3f& direction)
|
||||
{
|
||||
Vector3f up = Vector3f::Up();
|
||||
|
||||
ALfloat orientation[6] =
|
||||
{
|
||||
direction.x, direction.y, direction.z,
|
||||
up.x, up.y, up.z
|
||||
};
|
||||
|
||||
alListenerfv(AL_ORIENTATION, orientation);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the direction of the listener
|
||||
*
|
||||
* \param (dirX, dirY, dirZ) Direction of the listener, in front of the listener
|
||||
*
|
||||
* \see SetListenerDirection, SetListenerRotation
|
||||
*/
|
||||
|
||||
void Audio::SetListenerDirection(float dirX, float dirY, float dirZ)
|
||||
{
|
||||
Vector3f up = Vector3f::Up();
|
||||
|
||||
ALfloat orientation[6] =
|
||||
{
|
||||
dirX, dirY, dirZ,
|
||||
up.x, up.y, up.z
|
||||
};
|
||||
|
||||
alListenerfv(AL_ORIENTATION, orientation);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the position of the listener
|
||||
*
|
||||
* \param position Position of the listener
|
||||
*
|
||||
* \see SetListenerVelocity
|
||||
*/
|
||||
|
||||
void Audio::SetListenerPosition(const Vector3f& position)
|
||||
{
|
||||
alListenerfv(AL_POSITION, &position.x);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the position of the listener
|
||||
*
|
||||
* \param (x, y, z) Position of the listener
|
||||
*
|
||||
* \see SetListenerVelocity
|
||||
*/
|
||||
|
||||
void Audio::SetListenerPosition(float x, float y, float z)
|
||||
{
|
||||
alListener3f(AL_POSITION, x, y, z);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the rotation of the listener
|
||||
*
|
||||
* \param rotation Rotation of the listener
|
||||
*/
|
||||
|
||||
void Audio::SetListenerRotation(const Quaternionf& rotation)
|
||||
{
|
||||
Vector3f forward = rotation * Vector3f::Forward();
|
||||
Vector3f up = Vector3f::Up();
|
||||
|
||||
ALfloat orientation[6] =
|
||||
{
|
||||
forward.x, forward.y, forward.z,
|
||||
up.x, up.y, up.z
|
||||
};
|
||||
|
||||
alListenerfv(AL_ORIENTATION, orientation);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the velocity of the listener
|
||||
*
|
||||
* \param velocity Velocity of the listener
|
||||
*
|
||||
* \see SetListenerPosition
|
||||
*/
|
||||
|
||||
void Audio::SetListenerVelocity(const Vector3f& velocity)
|
||||
{
|
||||
alListenerfv(AL_VELOCITY, &velocity.x);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the velocity of the listener
|
||||
*
|
||||
* \param (velX, velY, velZ) Velocity of the listener
|
||||
*
|
||||
* \see SetListenerPosition
|
||||
*/
|
||||
|
||||
void Audio::SetListenerVelocity(float velX, float velY, float velZ)
|
||||
{
|
||||
alListener3f(AL_VELOCITY, velX, velY, velZ);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the speed of sound
|
||||
*
|
||||
* \param speed Speed of sound
|
||||
*/
|
||||
|
||||
void Audio::SetSpeedOfSound(float speed)
|
||||
{
|
||||
alSpeedOfSound(speed);
|
||||
return s_openalLibrary.QueryOutputDevices();
|
||||
}
|
||||
|
||||
Audio* Audio::s_instance = nullptr;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (C) 2022 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/AudioBuffer.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
AudioBuffer::~AudioBuffer() = default;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (C) 2022 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/AudioDevice.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
AudioDevice::~AudioDevice() = default;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (C) 2022 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/AudioSource.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
AudioSource::~AudioSource() = default;
|
||||
}
|
||||
|
|
@ -4,15 +4,14 @@
|
|||
|
||||
#include <Nazara/Audio/Music.hpp>
|
||||
#include <Nazara/Audio/Algorithm.hpp>
|
||||
#include <Nazara/Audio/OpenAL.hpp>
|
||||
#include <Nazara/Audio/Audio.hpp>
|
||||
#include <Nazara/Audio/AudioBuffer.hpp>
|
||||
#include <Nazara/Audio/AudioDevice.hpp>
|
||||
#include <Nazara/Audio/AudioSource.hpp>
|
||||
#include <Nazara/Audio/SoundStream.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
|
|
@ -25,22 +24,18 @@ namespace Nz
|
|||
* \remark Module Audio needs to be initialized to use this class
|
||||
*/
|
||||
|
||||
struct MusicImpl
|
||||
Music::Music() :
|
||||
Music(*Audio::Instance()->GetDefaultDevice())
|
||||
{
|
||||
ALenum audioFormat;
|
||||
std::atomic_bool streaming = false;
|
||||
std::atomic<UInt64> processedSamples;
|
||||
std::vector<Int16> chunkSamples;
|
||||
std::mutex bufferLock;
|
||||
std::shared_ptr<SoundStream> stream;
|
||||
std::thread thread;
|
||||
UInt64 streamOffset;
|
||||
bool loop = false;
|
||||
unsigned int sampleRate;
|
||||
};
|
||||
|
||||
Music::Music() = default;
|
||||
Music::Music(Music&&) noexcept = default;
|
||||
}
|
||||
|
||||
Music::Music(AudioDevice& device) :
|
||||
SoundEmitter(device),
|
||||
m_streaming(false),
|
||||
m_bufferCount(2),
|
||||
m_looping(false)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destructs the object and calls Destroy
|
||||
|
|
@ -54,11 +49,10 @@ namespace Nz
|
|||
|
||||
/*!
|
||||
* \brief Creates a music with a sound stream
|
||||
* \return true if creation was succesful
|
||||
* \return true if creation was successful
|
||||
*
|
||||
* \param soundStream Sound stream which is the source for the music
|
||||
*/
|
||||
|
||||
bool Music::Create(std::shared_ptr<SoundStream> soundStream)
|
||||
{
|
||||
NazaraAssert(soundStream, "Invalid stream");
|
||||
|
|
@ -67,11 +61,10 @@ namespace Nz
|
|||
|
||||
AudioFormat format = soundStream->GetFormat();
|
||||
|
||||
m_impl = std::make_unique<MusicImpl>();
|
||||
m_impl->sampleRate = soundStream->GetSampleRate();
|
||||
m_impl->audioFormat = OpenAL::AudioFormat[UnderlyingCast(format)];
|
||||
m_impl->chunkSamples.resize(GetChannelCount(format) * m_impl->sampleRate); // One second of samples
|
||||
m_impl->stream = std::move(soundStream);
|
||||
m_sampleRate = soundStream->GetSampleRate();
|
||||
m_audioFormat = soundStream->GetFormat();
|
||||
m_chunkSamples.resize(GetChannelCount(format) * m_sampleRate); // One second of samples
|
||||
m_stream = std::move(soundStream);
|
||||
|
||||
SetPlayingOffset(0);
|
||||
|
||||
|
|
@ -85,12 +78,7 @@ namespace Nz
|
|||
*/
|
||||
void Music::Destroy()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
StopThread();
|
||||
|
||||
m_impl.reset();
|
||||
}
|
||||
StopThread();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -102,9 +90,7 @@ namespace Nz
|
|||
*/
|
||||
void Music::EnableLooping(bool loop)
|
||||
{
|
||||
NazaraAssert(m_impl, "Music not created");
|
||||
|
||||
m_impl->loop = loop;
|
||||
m_looping = loop;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -115,9 +101,9 @@ namespace Nz
|
|||
*/
|
||||
UInt32 Music::GetDuration() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Music not created");
|
||||
NazaraAssert(m_stream, "Music not created");
|
||||
|
||||
return m_impl->stream->GetDuration();
|
||||
return m_stream->GetDuration();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -128,9 +114,9 @@ namespace Nz
|
|||
*/
|
||||
AudioFormat Music::GetFormat() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Music not created");
|
||||
NazaraAssert(m_stream, "Music not created");
|
||||
|
||||
return m_impl->stream->GetFormat();
|
||||
return m_stream->GetFormat();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -141,15 +127,14 @@ namespace Nz
|
|||
*/
|
||||
UInt32 Music::GetPlayingOffset() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Music not created");
|
||||
NazaraAssert(m_stream, "Music not created");
|
||||
|
||||
// Prevent music thread from enqueing new buffers while we're getting the count
|
||||
std::lock_guard<std::mutex> lock(m_impl->bufferLock);
|
||||
// Prevent music thread from enqueuing new buffers while we're getting the count
|
||||
std::lock_guard<std::mutex> lock(m_bufferLock);
|
||||
|
||||
ALint samples = 0;
|
||||
alGetSourcei(m_source, AL_SAMPLE_OFFSET, &samples);
|
||||
UInt32 sampleOffset = m_source->GetSampleOffset();
|
||||
|
||||
return static_cast<UInt32>((1000ULL * (samples + (m_impl->processedSamples / GetChannelCount(m_impl->stream->GetFormat())))) / m_impl->sampleRate);
|
||||
return static_cast<UInt32>((1000ULL * (sampleOffset + (m_processedSamples / GetChannelCount(m_stream->GetFormat())))) / m_sampleRate);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -160,9 +145,9 @@ namespace Nz
|
|||
*/
|
||||
UInt64 Music::GetSampleCount() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Music not created");
|
||||
NazaraAssert(m_stream, "Music not created");
|
||||
|
||||
return m_impl->stream->GetSampleCount();
|
||||
return m_stream->GetSampleCount();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -173,9 +158,9 @@ namespace Nz
|
|||
*/
|
||||
UInt32 Music::GetSampleRate() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Music not created");
|
||||
NazaraAssert(m_stream, "Music not created");
|
||||
|
||||
return m_impl->sampleRate;
|
||||
return m_sampleRate;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -186,12 +171,12 @@ namespace Nz
|
|||
*/
|
||||
SoundStatus Music::GetStatus() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Music not created");
|
||||
NazaraAssert(m_stream, "Music not created");
|
||||
|
||||
SoundStatus status = GetInternalStatus();
|
||||
SoundStatus status = m_source->GetStatus();
|
||||
|
||||
// To compensate any delays (or the timelaps between Play() and the thread startup)
|
||||
if (m_impl->streaming && status == SoundStatus::Stopped)
|
||||
if (m_streaming && status == SoundStatus::Stopped)
|
||||
status = SoundStatus::Playing;
|
||||
|
||||
return status;
|
||||
|
|
@ -205,9 +190,7 @@ namespace Nz
|
|||
*/
|
||||
bool Music::IsLooping() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Music not created");
|
||||
|
||||
return m_impl->loop;
|
||||
return m_looping;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -267,9 +250,7 @@ namespace Nz
|
|||
*/
|
||||
void Music::Pause()
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
alSourcePause(m_source);
|
||||
m_source->Pause();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -284,10 +265,10 @@ namespace Nz
|
|||
*/
|
||||
void Music::Play()
|
||||
{
|
||||
NazaraAssert(m_impl, "Music not created");
|
||||
NazaraAssert(m_stream, "Music not created");
|
||||
|
||||
// Maybe we are already playing
|
||||
if (m_impl->streaming)
|
||||
if (m_streaming)
|
||||
{
|
||||
switch (GetStatus())
|
||||
{
|
||||
|
|
@ -296,7 +277,7 @@ namespace Nz
|
|||
break;
|
||||
|
||||
case SoundStatus::Paused:
|
||||
alSourcePlay(m_source);
|
||||
m_source->Play();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -309,12 +290,12 @@ namespace Nz
|
|||
std::condition_variable cv;
|
||||
|
||||
// Starting streaming thread
|
||||
m_impl->streaming = true;
|
||||
m_streaming = true;
|
||||
|
||||
std::exception_ptr exceptionPtr;
|
||||
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
m_impl->thread = std::thread(&Music::MusicThread, this, std::ref(cv), std::ref(mutex), std::ref(exceptionPtr));
|
||||
m_thread = std::thread(&Music::MusicThread, this, std::ref(cv), std::ref(mutex), std::ref(exceptionPtr));
|
||||
|
||||
// Wait until thread signal it has properly started (or an error occurred)
|
||||
cv.wait(lock);
|
||||
|
|
@ -335,17 +316,17 @@ namespace Nz
|
|||
*/
|
||||
void Music::SetPlayingOffset(UInt32 offset)
|
||||
{
|
||||
NazaraAssert(m_impl, "Music not created");
|
||||
NazaraAssert(m_stream, "Music not created");
|
||||
|
||||
bool isPlaying = m_impl->streaming;
|
||||
bool isPlaying = m_streaming;
|
||||
|
||||
if (isPlaying)
|
||||
Stop();
|
||||
|
||||
UInt64 sampleOffset = UInt64(offset) * m_impl->sampleRate * GetChannelCount(m_impl->stream->GetFormat()) / 1000ULL;
|
||||
UInt64 sampleOffset = UInt64(offset) * m_sampleRate * GetChannelCount(m_stream->GetFormat()) / 1000ULL;
|
||||
|
||||
m_impl->processedSamples = sampleOffset;
|
||||
m_impl->streamOffset = sampleOffset;
|
||||
m_processedSamples = sampleOffset;
|
||||
m_streamOffset = sampleOffset;
|
||||
|
||||
if (isPlaying)
|
||||
Play();
|
||||
|
|
@ -358,31 +339,27 @@ namespace Nz
|
|||
*/
|
||||
void Music::Stop()
|
||||
{
|
||||
NazaraAssert(m_impl, "Music not created");
|
||||
|
||||
StopThread();
|
||||
SetPlayingOffset(0);
|
||||
}
|
||||
|
||||
Music& Music::operator=(Music&&) noexcept = default;
|
||||
|
||||
bool Music::FillAndQueueBuffer(unsigned int buffer)
|
||||
bool Music::FillAndQueueBuffer(std::shared_ptr<AudioBuffer> buffer)
|
||||
{
|
||||
std::size_t sampleCount = m_impl->chunkSamples.size();
|
||||
std::size_t sampleCount = m_chunkSamples.size();
|
||||
std::size_t sampleRead = 0;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_impl->stream->GetMutex());
|
||||
std::lock_guard<std::mutex> lock(m_stream->GetMutex());
|
||||
|
||||
m_impl->stream->Seek(m_impl->streamOffset);
|
||||
m_stream->Seek(m_streamOffset);
|
||||
|
||||
// Fill the buffer by reading from the stream
|
||||
for (;;)
|
||||
{
|
||||
sampleRead += m_impl->stream->Read(&m_impl->chunkSamples[sampleRead], sampleCount - sampleRead);
|
||||
if (sampleRead < sampleCount && m_impl->loop)
|
||||
sampleRead += m_stream->Read(&m_chunkSamples[sampleRead], sampleCount - sampleRead);
|
||||
if (sampleRead < sampleCount && m_looping)
|
||||
{
|
||||
// In case we read less than expected, assume we reached the end of the stream and seek back to the beginning
|
||||
m_impl->stream->Seek(0);
|
||||
m_stream->Seek(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -390,14 +367,14 @@ namespace Nz
|
|||
break;
|
||||
}
|
||||
|
||||
m_impl->streamOffset = m_impl->stream->Tell();
|
||||
m_streamOffset = m_stream->Tell();
|
||||
}
|
||||
|
||||
// Update the buffer (send it to OpenAL) and queue it if we got any data
|
||||
// Update the buffer on the AudioDevice and queue it if we got any data
|
||||
if (sampleRead > 0)
|
||||
{
|
||||
alBufferData(buffer, m_impl->audioFormat, &m_impl->chunkSamples[0], static_cast<ALsizei>(sampleRead*sizeof(Int16)), static_cast<ALsizei>(m_impl->sampleRate));
|
||||
alSourceQueueBuffers(m_source, 1, &buffer);
|
||||
buffer->Reset(m_audioFormat, sampleRead, m_sampleRate, &m_chunkSamples[0]);
|
||||
m_source->QueueBuffer(buffer);
|
||||
}
|
||||
|
||||
return sampleRead != sampleCount; // End of stream (Does not happen when looping)
|
||||
|
|
@ -406,20 +383,18 @@ namespace Nz
|
|||
void Music::MusicThread(std::condition_variable& cv, std::mutex& m, std::exception_ptr& err)
|
||||
{
|
||||
// Allocation of streaming buffers
|
||||
std::array<ALuint, NAZARA_AUDIO_STREAMED_BUFFER_COUNT> buffers;
|
||||
alGenBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers.data());
|
||||
|
||||
CallOnExit freebuffers([&]
|
||||
CallOnExit unqueueBuffers([&]
|
||||
{
|
||||
alDeleteBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers.data());
|
||||
m_source->UnqueueAllBuffers();
|
||||
});
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
for (ALuint buffer : buffers)
|
||||
for (std::size_t i = 0; i < m_bufferCount; ++i)
|
||||
{
|
||||
if (FillAndQueueBuffer(buffer))
|
||||
std::shared_ptr<AudioBuffer> buffer = m_source->GetAudioDevice()->CreateBuffer();
|
||||
|
||||
if (FillAndQueueBuffer(std::move(buffer)))
|
||||
break; // We have reached the end of the stream, there is no use to add new buffers
|
||||
}
|
||||
}
|
||||
|
|
@ -432,23 +407,12 @@ namespace Nz
|
|||
return;
|
||||
}
|
||||
|
||||
CallOnExit unqueueBuffers([&]
|
||||
{
|
||||
// We delete buffers from the stream
|
||||
ALint queuedBufferCount;
|
||||
alGetSourcei(m_source, AL_BUFFERS_QUEUED, &queuedBufferCount);
|
||||
m_source->Play();
|
||||
|
||||
ALuint buffer;
|
||||
for (ALint i = 0; i < queuedBufferCount; ++i)
|
||||
alSourceUnqueueBuffers(m_source, 1, &buffer);
|
||||
});
|
||||
|
||||
alSourcePlay(m_source);
|
||||
|
||||
CallOnExit stopSource([&]
|
||||
{
|
||||
// Stop playing of the sound (in the case where it has not been already done)
|
||||
alSourceStop(m_source);
|
||||
m_source->Stop();
|
||||
});
|
||||
|
||||
// Signal we're good
|
||||
|
|
@ -458,35 +422,25 @@ namespace Nz
|
|||
} // m & cv no longer exists from here
|
||||
|
||||
// Reading loop (Filling new buffers as playing)
|
||||
while (m_impl->streaming)
|
||||
while (m_streaming)
|
||||
{
|
||||
// The reading has stopped, we have reached the end of the stream
|
||||
SoundStatus status = GetInternalStatus();
|
||||
SoundStatus status = m_source->GetStatus();
|
||||
if (status == SoundStatus::Stopped)
|
||||
{
|
||||
m_impl->streaming = false;
|
||||
// The reading has stopped, we have reached the end of the stream
|
||||
m_streaming = false;
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_impl->bufferLock);
|
||||
std::lock_guard<std::mutex> lock(m_bufferLock);
|
||||
|
||||
// We treat read buffers
|
||||
ALint processedCount = 0;
|
||||
alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &processedCount);
|
||||
while (processedCount--)
|
||||
while (std::shared_ptr<AudioBuffer> buffer = m_source->TryUnqueueProcessedBuffer())
|
||||
{
|
||||
ALuint buffer;
|
||||
alSourceUnqueueBuffers(m_source, 1, &buffer);
|
||||
m_processedSamples += buffer->GetSampleCount();
|
||||
|
||||
ALint bits, size;
|
||||
alGetBufferi(buffer, AL_BITS, &bits);
|
||||
alGetBufferi(buffer, AL_SIZE, &size);
|
||||
|
||||
if (bits != 0)
|
||||
m_impl->processedSamples += (8 * size) / bits;
|
||||
|
||||
if (FillAndQueueBuffer(buffer))
|
||||
if (FillAndQueueBuffer(std::move(buffer)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -498,10 +452,10 @@ namespace Nz
|
|||
|
||||
void Music::StopThread()
|
||||
{
|
||||
if (m_impl->streaming)
|
||||
m_impl->streaming = false;
|
||||
if (m_streaming)
|
||||
m_streaming = false;
|
||||
|
||||
if (m_impl->thread.joinable())
|
||||
m_impl->thread.join();
|
||||
if (m_thread.joinable())
|
||||
m_thread.join();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,577 +0,0 @@
|
|||
// Copyright (C) 2022 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/OpenAL.hpp>
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Core/DynLib.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Core/StringExt.hpp>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
DynLib s_openalLbrary;
|
||||
std::string s_openalDeviceName;
|
||||
std::string s_openalRndererName;
|
||||
std::string s_openalVendorName;
|
||||
ALCdevice* s_openalDevice = nullptr;
|
||||
ALCcontext* s_openalContext = nullptr;
|
||||
unsigned int s_openalVersion;
|
||||
|
||||
std::size_t ParseOpenALDevices(const char* deviceString, std::vector<std::string>& devices)
|
||||
{
|
||||
if (!deviceString)
|
||||
return 0;
|
||||
|
||||
std::size_t startSize = devices.size();
|
||||
|
||||
std::size_t length;
|
||||
while ((length = std::strlen(deviceString)) > 0)
|
||||
{
|
||||
devices.emplace_back(deviceString, length);
|
||||
deviceString += length + 1;
|
||||
}
|
||||
|
||||
return devices.size() - startSize;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup audio
|
||||
* \class Nz::OpenAL
|
||||
* \brief Audio class that represents the link with OpenAL
|
||||
*
|
||||
* \remark This class is meant to be used by Module Audio
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Gets the entry for the function name
|
||||
* \return Pointer to the function
|
||||
*
|
||||
* \param entryPoint Name of the entry
|
||||
*
|
||||
* \remark This does not produces a NazaraError if entry does not exist
|
||||
*/
|
||||
|
||||
OpenALFunc OpenAL::GetEntry(const std::string& entryPoint)
|
||||
{
|
||||
return LoadEntry(entryPoint.data(), false);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the name of the renderer
|
||||
* \return Name of the renderer
|
||||
*/
|
||||
|
||||
std::string OpenAL::GetRendererName()
|
||||
{
|
||||
return s_openalRndererName;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the name of the vendor
|
||||
* \return Name of the vendor
|
||||
*/
|
||||
|
||||
std::string OpenAL::GetVendorName()
|
||||
{
|
||||
return s_openalVendorName;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the version of OpenAL
|
||||
* \return Version of OpenAL
|
||||
*/
|
||||
|
||||
unsigned int OpenAL::GetVersion()
|
||||
{
|
||||
return s_openalVersion;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Initializes the module OpenAL
|
||||
* \return true if initialization is successful
|
||||
*
|
||||
* \param openDevice True to get information from the device
|
||||
*
|
||||
* \remark Produces a NazaraError if one of the entry failed
|
||||
* \remark Produces a NazaraError if opening device failed with openDevice parameter set to true
|
||||
*/
|
||||
|
||||
bool OpenAL::Initialize(bool openDevice)
|
||||
{
|
||||
if (IsInitialized())
|
||||
return true;
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
///FIXME: Is OpenAL Soft a better implementation than Creative ?
|
||||
/// If we could use OpenAL Soft everytime, this would allow us to use sonorous extensions
|
||||
/// and give us more technical possibilities with audio
|
||||
const char* libs[] = {
|
||||
"soft_oal.dll",
|
||||
"wrap_oal.dll",
|
||||
"openal32.dll"
|
||||
};
|
||||
#elif defined(NAZARA_PLATFORM_LINUX)
|
||||
const char* libs[] = {
|
||||
"libopenal.so.1",
|
||||
"libopenal.so.0",
|
||||
"libopenal.so"
|
||||
};
|
||||
#elif defined(NAZARA_PLATFORM_MACOSX)
|
||||
const char* libs[] = {
|
||||
"libopenal.dylib",
|
||||
"libopenal.1.dylib",
|
||||
};
|
||||
#else
|
||||
NazaraError("Unknown OS");
|
||||
return false;
|
||||
#endif
|
||||
|
||||
bool succeeded = false;
|
||||
for (const char* path : libs)
|
||||
{
|
||||
ErrorFlags errFlags(ErrorMode::Silent);
|
||||
std::filesystem::path libPath(path);
|
||||
if (!s_openalLbrary.Load(libPath))
|
||||
continue;
|
||||
|
||||
errFlags.SetFlags(0);
|
||||
|
||||
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.generic_u8string() + " loading failed: " + std::string(e.what()));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!succeeded)
|
||||
{
|
||||
NazaraError("Failed to load OpenAL");
|
||||
Uninitialize();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (openDevice)
|
||||
OpenDevice();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the module is initialized
|
||||
* \return true if it is the case
|
||||
*/
|
||||
|
||||
bool OpenAL::IsInitialized()
|
||||
{
|
||||
return s_openalLbrary.IsLoaded();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Queries the input devices
|
||||
* \return Number of devices
|
||||
*
|
||||
* \param devices List of names of the input devices
|
||||
*/
|
||||
|
||||
std::size_t OpenAL::QueryInputDevices(std::vector<std::string>& devices)
|
||||
{
|
||||
const char* deviceString = reinterpret_cast<const char*>(alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER));
|
||||
if (!deviceString)
|
||||
return 0;
|
||||
|
||||
return ParseOpenALDevices(deviceString, devices);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Queries the output devices
|
||||
* \return Number of devices
|
||||
*
|
||||
* \param devices List of names of the output devices
|
||||
*/
|
||||
|
||||
std::size_t OpenAL::QueryOutputDevices(std::vector<std::string>& devices)
|
||||
{
|
||||
const char* deviceString = reinterpret_cast<const char*>(alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER));
|
||||
if (!deviceString)
|
||||
return 0;
|
||||
|
||||
return ParseOpenALDevices(deviceString, devices);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the active device
|
||||
* \return true if device is successfully opened
|
||||
*
|
||||
* \param deviceName Name of the device
|
||||
*/
|
||||
|
||||
bool OpenAL::SetDevice(const std::string& deviceName)
|
||||
{
|
||||
s_openalDeviceName = deviceName;
|
||||
if (IsInitialized())
|
||||
{
|
||||
CloseDevice();
|
||||
|
||||
return OpenDevice();
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the module
|
||||
*/
|
||||
|
||||
void OpenAL::Uninitialize()
|
||||
{
|
||||
CloseDevice();
|
||||
|
||||
s_openalRndererName.clear();
|
||||
s_openalVendorName.clear();
|
||||
s_openalLbrary.Unload();
|
||||
}
|
||||
|
||||
ALenum OpenAL::AudioFormat[AudioFormatCount] = {0}; // Added values with loading of OpenAL
|
||||
|
||||
/*!
|
||||
* \brief Closes the device
|
||||
*
|
||||
* \remark Produces a NazaraWarning if you try to close an active device
|
||||
*/
|
||||
|
||||
void OpenAL::CloseDevice()
|
||||
{
|
||||
if (s_openalDevice)
|
||||
{
|
||||
if (s_openalContext)
|
||||
{
|
||||
alcMakeContextCurrent(nullptr);
|
||||
alcDestroyContext(s_openalContext);
|
||||
s_openalContext = nullptr;
|
||||
}
|
||||
|
||||
if (!alcCloseDevice(s_openalDevice))
|
||||
// We could not close the close, this means that it's still in use
|
||||
NazaraWarning("Failed to close device");
|
||||
|
||||
s_openalDevice = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Opens the device
|
||||
* \return true if open is successful
|
||||
*
|
||||
* \remark Produces a NazaraError if it could not create the context
|
||||
*/
|
||||
|
||||
bool OpenAL::OpenDevice()
|
||||
{
|
||||
// Initialisation of the module
|
||||
s_openalDevice = alcOpenDevice(s_openalDeviceName.empty() ? nullptr : s_openalDeviceName.data()); // We choose the default device
|
||||
if (!s_openalDevice)
|
||||
{
|
||||
NazaraError("Failed to open default device");
|
||||
return false;
|
||||
}
|
||||
|
||||
// One context is enough
|
||||
s_openalContext = alcCreateContext(s_openalDevice, nullptr);
|
||||
if (!s_openalContext)
|
||||
{
|
||||
NazaraError("Failed to create context");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!alcMakeContextCurrent(s_openalContext))
|
||||
{
|
||||
NazaraError("Failed to activate context");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_openalRndererName = reinterpret_cast<const char*>(alGetString(AL_RENDERER));
|
||||
s_openalVendorName = 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_openalVersion = major*100 + minor*10;
|
||||
|
||||
NazaraDebug("OpenAL version: " + NumberToString(major) + '.' + NumberToString(minor));
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraDebug("Unable to retrieve OpenAL major version");
|
||||
s_openalVersion = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraDebug("Unable to retrieve OpenAL version");
|
||||
s_openalVersion = 0;
|
||||
}
|
||||
|
||||
// We complete the formats table
|
||||
AudioFormat[UnderlyingCast(AudioFormat::I16_Mono)] = AL_FORMAT_MONO16;
|
||||
AudioFormat[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 (alIsExtensionPresent("AL_EXT_MCFORMATS"))
|
||||
{
|
||||
AudioFormat[UnderlyingCast(AudioFormat::I16_Quad)] = alGetEnumValue("AL_FORMAT_QUAD16");
|
||||
AudioFormat[UnderlyingCast(AudioFormat::I16_5_1)] = alGetEnumValue("AL_FORMAT_51CHN16");
|
||||
AudioFormat[UnderlyingCast(AudioFormat::I16_6_1)] = alGetEnumValue("AL_FORMAT_61CHN16");
|
||||
AudioFormat[UnderlyingCast(AudioFormat::I16_7_1)] = alGetEnumValue("AL_FORMAT_71CHN16");
|
||||
}
|
||||
else if (alIsExtensionPresent("AL_LOKI_quadriphonic"))
|
||||
AudioFormat[UnderlyingCast(AudioFormat::I16_Quad)] = alGetEnumValue("AL_FORMAT_QUAD16_LOKI");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Loads the entry for the function name
|
||||
* \return Pointer to the function
|
||||
*
|
||||
* \param name Name of the entry
|
||||
* \param throwException Should throw exception if failed ?
|
||||
*
|
||||
* \remark Produces a std::runtime_error if entry does not exist and throwException is set to true
|
||||
*/
|
||||
|
||||
OpenALFunc OpenAL::LoadEntry(const char* name, bool throwException)
|
||||
{
|
||||
OpenALFunc entry = reinterpret_cast<OpenALFunc>(s_openalLbrary.GetSymbol(name));
|
||||
if (!entry && throwException)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "failed to load \"" << name << '"';
|
||||
|
||||
throw std::runtime_error(oss.str());
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
// al
|
||||
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
|
||||
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;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
// Copyright (C) 2022 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/OpenALBuffer.hpp>
|
||||
#include <Nazara/Audio/OpenALDevice.hpp>
|
||||
#include <Nazara/Audio/OpenALLibrary.hpp>
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
OpenALBuffer::~OpenALBuffer()
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
m_library.alDeleteBuffers(1, &m_bufferId);
|
||||
}
|
||||
|
||||
UInt32 OpenALBuffer::GetSampleCount() const
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
ALint bits, size;
|
||||
m_library.alGetBufferi(m_bufferId, AL_BITS, &bits);
|
||||
m_library.alGetBufferi(m_bufferId, AL_SIZE, &size);
|
||||
|
||||
UInt32 sampleCount = 0;
|
||||
if (bits != 0)
|
||||
sampleCount += (8 * SafeCast<UInt32>(size)) / SafeCast<UInt32>(bits);
|
||||
|
||||
return sampleCount;
|
||||
}
|
||||
|
||||
UInt32 OpenALBuffer::GetSize() const
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
ALint size;
|
||||
m_library.alGetBufferi(m_bufferId, AL_SIZE, &size);
|
||||
|
||||
return SafeCast<UInt32>(size);
|
||||
}
|
||||
|
||||
UInt32 OpenALBuffer::GetSampleRate() const
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
ALint sampleRate;
|
||||
m_library.alGetBufferi(m_bufferId, AL_FREQUENCY, &sampleRate);
|
||||
|
||||
return SafeCast<UInt32>(sampleRate);
|
||||
}
|
||||
|
||||
bool OpenALBuffer::Reset(AudioFormat format, UInt64 sampleCount, UInt32 sampleRate, const void* samples)
|
||||
{
|
||||
OpenALDevice& device = GetDevice();
|
||||
|
||||
ALenum alFormat = device.TranslateAudioFormat(format);
|
||||
if (!alFormat)
|
||||
{
|
||||
NazaraError("unsupported format");
|
||||
return false;
|
||||
}
|
||||
|
||||
device.MakeContextCurrent();
|
||||
|
||||
// We empty the error stack
|
||||
while (m_library.alGetError() != AL_NO_ERROR);
|
||||
|
||||
// TODO: Use SafeCast
|
||||
m_library.alBufferData(m_bufferId, alFormat, samples, static_cast<ALsizei>(sampleCount * sizeof(Int16)), static_cast<ALsizei>(sampleRate));
|
||||
|
||||
if (ALenum lastError = m_library.alGetError(); lastError != AL_NO_ERROR)
|
||||
{
|
||||
NazaraError("failed to reset OpenAL buffer: " + std::to_string(lastError));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
OpenALDevice& OpenALBuffer::GetDevice()
|
||||
{
|
||||
return SafeCast<OpenALDevice&>(*GetAudioDevice());
|
||||
}
|
||||
|
||||
const OpenALDevice& OpenALBuffer::GetDevice() const
|
||||
{
|
||||
return SafeCast<OpenALDevice&>(*GetAudioDevice());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,309 @@
|
|||
// Copyright (C) 2022 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");
|
||||
|
||||
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 100.f being the default
|
||||
*/
|
||||
float OpenALDevice::GetGlobalVolume() const
|
||||
{
|
||||
MakeContextCurrent();
|
||||
|
||||
ALfloat gain = 0.f;
|
||||
m_library.alGetListenerf(AL_GAIN, &gain);
|
||||
|
||||
return gain * 100.f;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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(Vector3f* up) const
|
||||
{
|
||||
MakeContextCurrent();
|
||||
|
||||
ALfloat orientation[6];
|
||||
m_library.alGetListenerfv(AL_ORIENTATION, orientation);
|
||||
|
||||
Vector3f forward(orientation[0], orientation[1], orientation[2]);
|
||||
|
||||
if (up)
|
||||
up->Set(orientation[3], orientation[4], orientation[5]);
|
||||
|
||||
return Quaternionf::RotationBetween(Vector3f::Forward(), forward);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
// Copyright (C) 2022 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/OpenALLibrary.hpp>
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Core/StringExt.hpp>
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
bool OpenALLibrary::Load()
|
||||
{
|
||||
Unload();
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
std::array libs{
|
||||
"soft_oal.dll",
|
||||
"wrap_oal.dll",
|
||||
"openal32.dll"
|
||||
};
|
||||
#elif defined(NAZARA_PLATFORM_LINUX)
|
||||
std::array libs {
|
||||
"libopenal.so.1",
|
||||
"libopenal.so.0",
|
||||
"libopenal.so"
|
||||
};
|
||||
#elif defined(NAZARA_PLATFORM_MACOSX)
|
||||
std::array libs {
|
||||
"libopenal.dylib",
|
||||
"libopenal.1.dylib",
|
||||
};
|
||||
#else
|
||||
NazaraError("unhandled OS");
|
||||
return false;
|
||||
#endif
|
||||
|
||||
for (const char* libname : libs)
|
||||
{
|
||||
if (!m_library.Load(libname))
|
||||
continue;
|
||||
|
||||
auto LoadSymbol = [this](const char* name)
|
||||
{
|
||||
DynLibFunc funcPtr = m_library.GetSymbol(name);
|
||||
if (!funcPtr)
|
||||
throw std::runtime_error(std::string("failed to load ") + name);
|
||||
|
||||
return funcPtr;
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
#define NAZARA_AUDIO_FUNC(name, sig) name = reinterpret_cast<sig>(LoadSymbol(#name));
|
||||
NAZARA_AUDIO_FOREACH_AL_FUNC(NAZARA_AUDIO_FUNC)
|
||||
NAZARA_AUDIO_FOREACH_ALC_FUNC(NAZARA_AUDIO_FUNC)
|
||||
#undef NAZARA_AUDIO_FUNC
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
NazaraWarning(std::string("failed to load ") + libname + ": " + e.what());
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NazaraError("failed to load OpenAL library");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> OpenALLibrary::QueryInputDevices()
|
||||
{
|
||||
return ParseDevices(alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER));
|
||||
}
|
||||
|
||||
std::vector<std::string> OpenALLibrary::QueryOutputDevices()
|
||||
{
|
||||
return ParseDevices(alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER));
|
||||
}
|
||||
|
||||
std::shared_ptr<OpenALDevice> OpenALLibrary::OpenDevice(const char* name)
|
||||
{
|
||||
ALCdevice* device = alcOpenDevice(name);
|
||||
if (!device)
|
||||
throw std::runtime_error("failed to open device");
|
||||
|
||||
return std::make_shared<OpenALDevice>(*this, device);
|
||||
}
|
||||
|
||||
void OpenALLibrary::Unload()
|
||||
{
|
||||
if (!m_library.IsLoaded())
|
||||
return;
|
||||
|
||||
#define NAZARA_AUDIO_FUNC(name, sig) name = nullptr;
|
||||
NAZARA_AUDIO_FOREACH_AL_FUNC(NAZARA_AUDIO_FUNC)
|
||||
NAZARA_AUDIO_FOREACH_ALC_FUNC(NAZARA_AUDIO_FUNC)
|
||||
#undef NAZARA_AUDIO_FUNC
|
||||
|
||||
m_library.Unload();
|
||||
}
|
||||
|
||||
std::vector<std::string> OpenALLibrary::ParseDevices(const char* deviceString)
|
||||
{
|
||||
if (!deviceString)
|
||||
return {};
|
||||
|
||||
std::vector<std::string> devices;
|
||||
std::size_t length;
|
||||
while ((length = std::strlen(deviceString)) > 0)
|
||||
{
|
||||
devices.emplace_back(deviceString, length);
|
||||
deviceString += length + 1;
|
||||
}
|
||||
|
||||
return devices;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,298 @@
|
|||
// Copyright (C) 2022 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/OpenALSource.hpp>
|
||||
#include <Nazara/Audio/OpenALBuffer.hpp>
|
||||
#include <Nazara/Audio/OpenALLibrary.hpp>
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/StackArray.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
OpenALSource::~OpenALSource()
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
m_library.alDeleteSources(1, &m_sourceId);
|
||||
}
|
||||
|
||||
void OpenALSource::EnableLooping(bool loop)
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
m_library.alSourcei(m_sourceId, AL_LOOPING, loop);
|
||||
}
|
||||
|
||||
void OpenALSource::EnableSpatialization(bool spatialization)
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
m_library.alSourcei(m_sourceId, AL_SOURCE_RELATIVE, !spatialization);
|
||||
}
|
||||
|
||||
float OpenALSource::GetAttenuation() const
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
ALfloat attenuation;
|
||||
m_library.alGetSourcefv(m_sourceId, AL_ROLLOFF_FACTOR, &attenuation);
|
||||
|
||||
return attenuation;
|
||||
}
|
||||
|
||||
float OpenALSource::GetMinDistance() const
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
ALfloat minDistance;
|
||||
m_library.alGetSourcefv(m_sourceId, AL_REFERENCE_DISTANCE, &minDistance);
|
||||
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
float OpenALSource::GetPitch() const
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
ALfloat pitch;
|
||||
m_library.alGetSourcefv(m_sourceId, AL_PITCH, &pitch);
|
||||
|
||||
return pitch;
|
||||
}
|
||||
|
||||
Vector3f OpenALSource::GetPosition() const
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
Vector3f position;
|
||||
m_library.alGetSourcefv(m_sourceId, AL_POSITION, &position.x);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
UInt32 OpenALSource::GetSampleOffset() const
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
ALint samples = 0;
|
||||
m_library.alGetSourcei(m_sourceId, AL_SAMPLE_OFFSET, &samples);
|
||||
|
||||
return SafeCast<UInt32>(samples);
|
||||
}
|
||||
|
||||
Vector3f OpenALSource::GetVelocity() const
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
Vector3f velocity;
|
||||
m_library.alGetSourcefv(m_sourceId, AL_VELOCITY, &velocity.x);
|
||||
|
||||
return velocity;
|
||||
}
|
||||
|
||||
SoundStatus OpenALSource::GetStatus() const
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
ALint state;
|
||||
m_library.alGetSourcei(m_sourceId, 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;
|
||||
}
|
||||
|
||||
float OpenALSource::GetVolume() const
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
ALfloat volume;
|
||||
m_library.alGetSourcefv(m_sourceId, AL_GAIN, &volume);
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
bool OpenALSource::IsLooping() const
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
ALint relative;
|
||||
m_library.alGetSourcei(m_sourceId, AL_LOOPING, &relative);
|
||||
|
||||
return relative == AL_FALSE;
|
||||
}
|
||||
|
||||
bool OpenALSource::IsSpatializationEnabled() const
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
ALint relative;
|
||||
m_library.alGetSourcei(m_sourceId, AL_SOURCE_RELATIVE, &relative);
|
||||
|
||||
return relative == AL_FALSE;
|
||||
}
|
||||
|
||||
void OpenALSource::QueueBuffer(std::shared_ptr<AudioBuffer> audioBuffer)
|
||||
{
|
||||
NazaraAssert(audioBuffer, "invalid buffer");
|
||||
NazaraAssert(audioBuffer->GetAudioDevice() == GetAudioDevice(), "incompatible buffer");
|
||||
|
||||
std::shared_ptr<OpenALBuffer> newBuffer = std::static_pointer_cast<OpenALBuffer>(std::move(audioBuffer));
|
||||
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
ALuint bufferId = newBuffer->GetBufferId();
|
||||
m_library.alSourceQueueBuffers(m_sourceId, 1, &bufferId);
|
||||
|
||||
m_queuedBuffers.emplace_back(std::move(newBuffer));
|
||||
}
|
||||
|
||||
void OpenALSource::Pause()
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
m_library.alSourcePause(m_sourceId);
|
||||
}
|
||||
|
||||
void OpenALSource::Play()
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
m_library.alSourcePlay(m_sourceId);
|
||||
}
|
||||
|
||||
void OpenALSource::SetAttenuation(float attenuation)
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
m_library.alSourcef(m_sourceId, AL_ROLLOFF_FACTOR, attenuation);
|
||||
}
|
||||
|
||||
void OpenALSource::SetBuffer(std::shared_ptr<AudioBuffer> audioBuffer)
|
||||
{
|
||||
NazaraAssert(audioBuffer->GetAudioDevice() == GetAudioDevice(), "incompatible buffer");
|
||||
|
||||
std::shared_ptr<OpenALBuffer> newBuffer = std::static_pointer_cast<OpenALBuffer>(std::move(audioBuffer));
|
||||
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
if (newBuffer)
|
||||
m_library.alSourcei(m_sourceId, AL_BUFFER, newBuffer->GetBufferId());
|
||||
else
|
||||
m_library.alSourcei(m_sourceId, AL_BUFFER, AL_NONE);
|
||||
|
||||
m_currentBuffer = std::move(newBuffer);
|
||||
}
|
||||
|
||||
void OpenALSource::SetMinDistance(float minDistance)
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
m_library.alSourcef(m_sourceId, AL_REFERENCE_DISTANCE, minDistance);
|
||||
}
|
||||
|
||||
void OpenALSource::SetPitch(float pitch)
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
m_library.alSourcef(m_sourceId, AL_PITCH, pitch);
|
||||
}
|
||||
|
||||
void OpenALSource::SetPosition(const Vector3f& position)
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
m_library.alSource3f(m_sourceId, AL_POSITION, position.x, position.y, position.z);
|
||||
}
|
||||
|
||||
void OpenALSource::SetSampleOffset(UInt32 offset)
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
m_library.alSourcei(m_sourceId, AL_SAMPLE_OFFSET, offset);
|
||||
}
|
||||
|
||||
void OpenALSource::SetVelocity(const Vector3f& velocity)
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
m_library.alSource3f(m_sourceId, AL_VELOCITY, velocity.x, velocity.y, velocity.z);
|
||||
}
|
||||
|
||||
void OpenALSource::SetVolume(float volume)
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
m_library.alSourcef(m_sourceId, AL_GAIN, volume);
|
||||
}
|
||||
|
||||
void OpenALSource::Stop()
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
m_library.alSourceStop(m_sourceId);
|
||||
}
|
||||
|
||||
std::shared_ptr<AudioBuffer> OpenALSource::TryUnqueueProcessedBuffer()
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
ALint processedCount = 0;
|
||||
m_library.alGetSourcei(m_sourceId, AL_BUFFERS_PROCESSED, &processedCount);
|
||||
|
||||
if (processedCount == 0)
|
||||
return {};
|
||||
|
||||
ALuint bufferId;
|
||||
m_library.alSourceUnqueueBuffers(m_sourceId, 1, &bufferId);
|
||||
|
||||
auto it = std::find_if(m_queuedBuffers.begin(), m_queuedBuffers.end(), [=](const std::shared_ptr<OpenALBuffer>& alBuffer)
|
||||
{
|
||||
return alBuffer->GetBufferId() == bufferId;
|
||||
});
|
||||
assert(it != m_queuedBuffers.end());
|
||||
|
||||
std::shared_ptr<AudioBuffer> buffer = *it;
|
||||
m_queuedBuffers.erase(it);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void OpenALSource::UnqueueAllBuffers()
|
||||
{
|
||||
GetDevice().MakeContextCurrent();
|
||||
|
||||
ALint queuedBufferCount = 0;
|
||||
m_library.alGetSourcei(m_sourceId, AL_BUFFERS_QUEUED, &queuedBufferCount);
|
||||
|
||||
StackArray<ALuint> buffers = NazaraStackArrayNoInit(ALuint, queuedBufferCount);
|
||||
m_library.alSourceUnqueueBuffers(m_sourceId, queuedBufferCount, buffers.data());
|
||||
|
||||
m_queuedBuffers.clear();
|
||||
}
|
||||
|
||||
OpenALDevice& OpenALSource::GetDevice()
|
||||
{
|
||||
return SafeCast<OpenALDevice&>(*GetAudioDevice());
|
||||
}
|
||||
|
||||
const OpenALDevice& OpenALSource::GetDevice() const
|
||||
{
|
||||
return SafeCast<OpenALDevice&>(*GetAudioDevice());
|
||||
}
|
||||
}
|
||||
|
|
@ -3,8 +3,10 @@
|
|||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Audio/Sound.hpp>
|
||||
#include <Nazara/Audio/Audio.hpp>
|
||||
#include <Nazara/Audio/AudioSource.hpp>
|
||||
#include <Nazara/Audio/Config.hpp>
|
||||
#include <Nazara/Audio/OpenAL.hpp>
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
|
|
@ -18,12 +20,18 @@ namespace Nz
|
|||
* \remark Module Audio needs to be initialized to use this class
|
||||
*/
|
||||
|
||||
Sound::Sound() :
|
||||
Sound(*Audio::Instance()->GetDefaultDevice())
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a Sound object
|
||||
*
|
||||
* \param soundBuffer Buffer to read sound from
|
||||
*/
|
||||
Sound::Sound(std::shared_ptr<const SoundBuffer> soundBuffer)
|
||||
Sound::Sound(AudioDevice& audioDevice, std::shared_ptr<SoundBuffer> soundBuffer) :
|
||||
Sound(audioDevice)
|
||||
{
|
||||
SetBuffer(std::move(soundBuffer));
|
||||
}
|
||||
|
|
@ -45,16 +53,14 @@ namespace Nz
|
|||
*/
|
||||
void Sound::EnableLooping(bool loop)
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
alSourcei(m_source, AL_LOOPING, loop);
|
||||
m_source->EnableLooping(loop);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the internal buffer
|
||||
* \return Internal buffer
|
||||
*/
|
||||
const std::shared_ptr<const SoundBuffer>& Sound::GetBuffer() const
|
||||
const std::shared_ptr<SoundBuffer>& Sound::GetBuffer() const
|
||||
{
|
||||
return m_buffer;
|
||||
}
|
||||
|
|
@ -78,12 +84,8 @@ namespace Nz
|
|||
*/
|
||||
UInt32 Sound::GetPlayingOffset() const
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
ALint samples = 0;
|
||||
alGetSourcei(m_source, AL_SAMPLE_OFFSET, &samples);
|
||||
|
||||
return static_cast<UInt32>(1000ULL * samples / m_buffer->GetSampleRate());
|
||||
UInt32 sampleCount = m_source->GetSampleOffset();
|
||||
return SafeCast<UInt32>(1000ULL * sampleCount / m_buffer->GetSampleRate());
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -92,7 +94,7 @@ namespace Nz
|
|||
*/
|
||||
SoundStatus Sound::GetStatus() const
|
||||
{
|
||||
return GetInternalStatus();
|
||||
return m_source->GetStatus();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -101,19 +103,13 @@ namespace Nz
|
|||
*/
|
||||
bool Sound::IsLooping() const
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
ALint loop;
|
||||
alGetSourcei(m_source, AL_LOOPING, &loop);
|
||||
|
||||
return loop != AL_FALSE;
|
||||
return m_source->IsLooping();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the sound is playable
|
||||
* \return true if it is the case
|
||||
*/
|
||||
|
||||
bool Sound::IsPlayable() const
|
||||
{
|
||||
return m_buffer != nullptr;
|
||||
|
|
@ -137,7 +133,7 @@ namespace Nz
|
|||
return false;
|
||||
}
|
||||
|
||||
SetBuffer(buffer);
|
||||
SetBuffer(std::move(buffer));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -160,7 +156,7 @@ namespace Nz
|
|||
return false;
|
||||
}
|
||||
|
||||
SetBuffer(buffer);
|
||||
SetBuffer(std::move(buffer));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -182,7 +178,7 @@ namespace Nz
|
|||
return false;
|
||||
}
|
||||
|
||||
SetBuffer(buffer);
|
||||
SetBuffer(std::move(buffer));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -191,9 +187,7 @@ namespace Nz
|
|||
*/
|
||||
void Sound::Pause()
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
alSourcePause(m_source);
|
||||
m_source->Pause();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -203,10 +197,9 @@ namespace Nz
|
|||
*/
|
||||
void Sound::Play()
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
NazaraAssert(IsPlayable(), "Music is not playable");
|
||||
NazaraAssert(IsPlayable(), "Sound is not playable");
|
||||
|
||||
alSourcePlay(m_source);
|
||||
m_source->Play();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -216,10 +209,9 @@ namespace Nz
|
|||
*
|
||||
* \remark Produces a NazaraError if buffer is invalid with NAZARA_AUDIO_SAFE defined
|
||||
*/
|
||||
void Sound::SetBuffer(std::shared_ptr<const SoundBuffer> buffer)
|
||||
void Sound::SetBuffer(std::shared_ptr<SoundBuffer> buffer)
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
NazaraAssert(!buffer || buffer->IsValid(), "Invalid sound buffer");
|
||||
NazaraAssert(buffer, "Invalid sound buffer");
|
||||
|
||||
if (m_buffer == buffer)
|
||||
return;
|
||||
|
|
@ -227,11 +219,7 @@ namespace Nz
|
|||
Stop();
|
||||
|
||||
m_buffer = std::move(buffer);
|
||||
|
||||
if (m_buffer)
|
||||
alSourcei(m_source, AL_BUFFER, m_buffer->GetOpenALBuffer());
|
||||
else
|
||||
alSourcei(m_source, AL_BUFFER, AL_NONE);
|
||||
m_source->SetBuffer(m_buffer->GetBuffer(m_source->GetAudioDevice().get()));
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -241,9 +229,7 @@ namespace Nz
|
|||
*/
|
||||
void Sound::SetPlayingOffset(UInt32 offset)
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
alSourcei(m_source, AL_SAMPLE_OFFSET, static_cast<ALint>(offset/1000.f * m_buffer->GetSampleRate()));
|
||||
m_source->SetSampleOffset(SafeCast<UInt32>(UInt64(offset) * m_buffer->GetSampleRate() / 1000));
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -253,7 +239,6 @@ namespace Nz
|
|||
*/
|
||||
void Sound::Stop()
|
||||
{
|
||||
if (m_source != InvalidSource)
|
||||
alSourceStop(m_source);
|
||||
m_source->Stop();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,17 +5,14 @@
|
|||
#include <Nazara/Audio/SoundBuffer.hpp>
|
||||
#include <Nazara/Audio/Algorithm.hpp>
|
||||
#include <Nazara/Audio/Audio.hpp>
|
||||
#include <Nazara/Audio/AudioBuffer.hpp>
|
||||
#include <Nazara/Audio/Config.hpp>
|
||||
#include <Nazara/Audio/OpenAL.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
///FIXME: Adapt the creation
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
/*!
|
||||
|
|
@ -36,18 +33,6 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
struct SoundBufferImpl
|
||||
{
|
||||
ALuint buffer;
|
||||
AudioFormat format;
|
||||
UInt32 duration;
|
||||
std::unique_ptr<Int16[]> samples;
|
||||
UInt64 sampleCount;
|
||||
UInt32 sampleRate;
|
||||
};
|
||||
|
||||
SoundBuffer::SoundBuffer() = default;
|
||||
|
||||
/*!
|
||||
* \brief Constructs a SoundBuffer object
|
||||
*
|
||||
|
|
@ -58,197 +43,41 @@ namespace Nz
|
|||
*
|
||||
* \remark Produces a NazaraError if creation went wrong with NAZARA_AUDIO_SAFE defined
|
||||
* \remark Produces a std::runtime_error if creation went wrong with NAZARA_AUDIO_SAFE defined
|
||||
*
|
||||
* \see Create
|
||||
*/
|
||||
SoundBuffer::SoundBuffer(AudioFormat format, UInt64 sampleCount, UInt32 sampleRate, const Int16* samples)
|
||||
{
|
||||
Create(format, sampleCount, sampleRate, samples);
|
||||
NazaraAssert(sampleCount > 0, "sample count must be different from zero");
|
||||
NazaraAssert(sampleRate > 0, "sample rate must be different from zero");
|
||||
NazaraAssert(samples, "invalid samples");
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Failed to create sound buffer");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#endif
|
||||
m_duration = SafeCast<UInt32>((1000ULL*sampleCount / (GetChannelCount(format) * sampleRate)));
|
||||
m_format = format;
|
||||
m_sampleCount = sampleCount;
|
||||
m_sampleRate = sampleRate;
|
||||
m_samples = std::make_unique<Int16[]>(sampleCount);
|
||||
std::memcpy(&m_samples[0], samples, sampleCount * sizeof(Int16));
|
||||
}
|
||||
|
||||
SoundBuffer::~SoundBuffer() = default;
|
||||
|
||||
/*!
|
||||
* \brief Creates the SoundBuffer object
|
||||
* \return true if creation is successful
|
||||
*
|
||||
* \param format Format for the audio
|
||||
* \param sampleCount Number of samples
|
||||
* \param sampleRate Rate of samples
|
||||
* \param samples Samples raw data
|
||||
*
|
||||
* \remark Produces a NazaraError if creation went wrong with NAZARA_AUDIO_SAFE defined,
|
||||
* this could happen if parameters are invalid or creation of OpenAL buffers failed
|
||||
*/
|
||||
bool SoundBuffer::Create(AudioFormat format, UInt64 sampleCount, UInt32 sampleRate, const Int16* samples)
|
||||
const std::shared_ptr<AudioBuffer>& SoundBuffer::GetBuffer(AudioDevice* device)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!IsFormatSupported(format))
|
||||
auto it = m_audioBufferByDevice.find(device);
|
||||
if (it == m_audioBufferByDevice.end())
|
||||
{
|
||||
NazaraError("Audio format is not supported");
|
||||
return false;
|
||||
auto audioBuffer = device->CreateBuffer();
|
||||
if (!audioBuffer->Reset(m_format, m_sampleCount, m_sampleRate, m_samples.get()))
|
||||
throw std::runtime_error("failed to initialize audio buffer");
|
||||
|
||||
it = m_audioBufferByDevice.emplace(device, AudioDeviceEntry{}).first;
|
||||
|
||||
AudioDeviceEntry& entry = it->second;
|
||||
entry.audioBuffer = std::move(audioBuffer);
|
||||
entry.audioDeviceReleaseSlot.Connect(device->OnAudioDeviceRelease, [this](AudioDevice* device)
|
||||
{
|
||||
m_audioBufferByDevice.erase(device);
|
||||
});
|
||||
}
|
||||
|
||||
if (sampleCount == 0)
|
||||
{
|
||||
NazaraError("Sample rate must be different from zero");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sampleRate == 0)
|
||||
{
|
||||
NazaraError("Sample rate must be different from zero");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!samples)
|
||||
{
|
||||
NazaraError("Invalid sample source");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// We empty the error stack
|
||||
while (alGetError() != AL_NO_ERROR);
|
||||
|
||||
ALuint buffer;
|
||||
alGenBuffers(1, &buffer);
|
||||
if (alGetError() != AL_NO_ERROR)
|
||||
{
|
||||
NazaraError("Failed to create OpenAL buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
CallOnExit clearBufferOnExit([buffer] () { alDeleteBuffers(1, &buffer); });
|
||||
|
||||
alBufferData(buffer, OpenAL::AudioFormat[UnderlyingCast(format)], samples, static_cast<ALsizei>(sampleCount*sizeof(Int16)), static_cast<ALsizei>(sampleRate));
|
||||
|
||||
if (alGetError() != AL_NO_ERROR)
|
||||
{
|
||||
NazaraError("Failed to set OpenAL buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_impl = std::make_unique<SoundBufferImpl>();
|
||||
m_impl->buffer = buffer;
|
||||
m_impl->duration = static_cast<UInt32>((1000ULL*sampleCount / (GetChannelCount(format) * sampleRate)));
|
||||
m_impl->format = format;
|
||||
m_impl->sampleCount = sampleCount;
|
||||
m_impl->sampleRate = sampleRate;
|
||||
m_impl->samples = std::make_unique<Int16[]>(sampleCount);
|
||||
std::memcpy(&m_impl->samples[0], samples, sampleCount*sizeof(Int16));
|
||||
|
||||
clearBufferOnExit.Reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the current sound buffer and frees resources
|
||||
*/
|
||||
void SoundBuffer::Destroy()
|
||||
{
|
||||
m_impl.reset();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the duration of the sound buffer
|
||||
* \return Duration of the sound buffer in milliseconds
|
||||
*
|
||||
* \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined
|
||||
*/
|
||||
UInt32 SoundBuffer::GetDuration() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Sound buffer not created");
|
||||
|
||||
return m_impl->duration;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the format of the sound buffer
|
||||
* \return Enumeration of type AudioFormat (mono, stereo, ...)
|
||||
*
|
||||
* \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined
|
||||
*/
|
||||
|
||||
AudioFormat SoundBuffer::GetFormat() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Sound buffer not created");
|
||||
|
||||
return m_impl->format;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the internal raw samples
|
||||
* \return Pointer to raw data
|
||||
*
|
||||
* \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined
|
||||
*/
|
||||
const Int16* SoundBuffer::GetSamples() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Sound buffer not created");
|
||||
|
||||
return m_impl->samples.get();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the number of samples in the sound buffer
|
||||
* \return Count of samples (number of seconds * sample rate * channel count)
|
||||
*
|
||||
* \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined
|
||||
*/
|
||||
UInt64 SoundBuffer::GetSampleCount() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Sound buffer not created");
|
||||
|
||||
return m_impl->sampleCount;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the rates of sample in the sound buffer
|
||||
* \return Rate of sample in Hertz (Hz)
|
||||
*
|
||||
* \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined
|
||||
*/
|
||||
UInt32 SoundBuffer::GetSampleRate() const
|
||||
{
|
||||
NazaraAssert(m_impl, "Sound buffer not created");
|
||||
|
||||
return m_impl->sampleRate;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the sound buffer is valid
|
||||
* \return true if it is the case
|
||||
*/
|
||||
|
||||
bool SoundBuffer::IsValid() const
|
||||
{
|
||||
return m_impl != nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the format is supported by the engine
|
||||
* \return true if it is the case
|
||||
*
|
||||
* \param format Format to check
|
||||
*/
|
||||
bool SoundBuffer::IsFormatSupported(AudioFormat format)
|
||||
{
|
||||
Audio* audio = Audio::Instance();
|
||||
NazaraAssert(audio, "Audio module has not been initialized");
|
||||
|
||||
return audio->IsFormatSupported(format);
|
||||
return it->second.audioBuffer;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -296,23 +125,4 @@ namespace Nz
|
|||
|
||||
return audio->GetSoundBufferLoader().LoadFromStream(stream, params);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the internal OpenAL buffer
|
||||
* \return The index of the OpenAL buffer
|
||||
*
|
||||
* \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined
|
||||
*/
|
||||
unsigned int SoundBuffer::GetOpenALBuffer() const
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraInternalError("Sound buffer not created");
|
||||
return AL_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->buffer;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,9 @@
|
|||
// This file is part of the "Nazara Engine - Audio module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
// http://connect.creativelabs.com/openal/Documentation/OpenAL_Programmers_Guide.pdf
|
||||
|
||||
#include <Nazara/Audio/SoundEmitter.hpp>
|
||||
#include <Nazara/Audio/OpenAL.hpp>
|
||||
#include <Nazara/Audio/AudioDevice.hpp>
|
||||
#include <Nazara/Audio/AudioSource.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
|
|
@ -23,173 +22,87 @@ namespace Nz
|
|||
/*!
|
||||
* \brief Constructs a SoundEmitter object
|
||||
*/
|
||||
SoundEmitter::SoundEmitter()
|
||||
SoundEmitter::SoundEmitter(AudioDevice& audioDevice) :
|
||||
m_source(audioDevice.CreateSource())
|
||||
{
|
||||
alGenSources(1, &m_source);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a SoundEmitter object which is a copy of another
|
||||
*
|
||||
* \param emitter SoundEmitter to copy
|
||||
*
|
||||
* \remark Position and velocity are not copied
|
||||
*/
|
||||
|
||||
SoundEmitter::SoundEmitter(const SoundEmitter& emitter)
|
||||
{
|
||||
if (emitter.m_source != InvalidSource)
|
||||
{
|
||||
alGenSources(1, &m_source);
|
||||
|
||||
SetAttenuation(emitter.GetAttenuation());
|
||||
SetMinDistance(emitter.GetMinDistance());
|
||||
SetPitch(emitter.GetPitch());
|
||||
// No copy for position or velocity
|
||||
SetVolume(emitter.GetVolume());
|
||||
}
|
||||
else
|
||||
m_source = InvalidSource;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a SoundEmitter object by moving another
|
||||
*
|
||||
* \param emitter SoundEmitter to move
|
||||
*
|
||||
* \remark The moved sound emitter cannot be used after being moved
|
||||
*/
|
||||
SoundEmitter::SoundEmitter(SoundEmitter&& emitter) noexcept :
|
||||
m_source(emitter.m_source)
|
||||
{
|
||||
emitter.m_source = InvalidSource;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destructs the object
|
||||
*/
|
||||
SoundEmitter::~SoundEmitter()
|
||||
{
|
||||
if (m_source != InvalidSource)
|
||||
alDeleteSources(1, &m_source);
|
||||
}
|
||||
SoundEmitter::~SoundEmitter() = default;
|
||||
|
||||
/*!
|
||||
* \brief Enables spatialization
|
||||
*
|
||||
* \param spatialization True if spatialization is enabled
|
||||
*/
|
||||
|
||||
void SoundEmitter::EnableSpatialization(bool spatialization)
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
alSourcei(m_source, AL_SOURCE_RELATIVE, !spatialization);
|
||||
m_source->EnableSpatialization(spatialization);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the attenuation
|
||||
* \return Amount that your sound will drop off as by the inverse square law
|
||||
*/
|
||||
|
||||
float SoundEmitter::GetAttenuation() const
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
ALfloat attenuation;
|
||||
alGetSourcef(m_source, AL_ROLLOFF_FACTOR, &attenuation);
|
||||
|
||||
return attenuation;
|
||||
return m_source->GetAttenuation();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the minimum distance to hear
|
||||
* \return Distance to begin to hear
|
||||
*/
|
||||
|
||||
float SoundEmitter::GetMinDistance() const
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
ALfloat distance;
|
||||
alGetSourcef(m_source, AL_REFERENCE_DISTANCE, &distance);
|
||||
|
||||
return distance;
|
||||
return m_source->GetMinDistance();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the pitch
|
||||
* \return Pitch of the sound
|
||||
*/
|
||||
|
||||
float SoundEmitter::GetPitch() const
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
ALfloat pitch;
|
||||
alGetSourcef(m_source, AL_PITCH, &pitch);
|
||||
|
||||
return pitch;
|
||||
return m_source->GetPitch();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the position of the emitter
|
||||
* \return Position of the sound
|
||||
*/
|
||||
|
||||
Vector3f SoundEmitter::GetPosition() const
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
Vector3f position;
|
||||
alGetSourcefv(m_source, AL_POSITION, &position.x);
|
||||
|
||||
return position;
|
||||
return m_source->GetPosition();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the velocity of the emitter
|
||||
* \return Velocity of the sound
|
||||
*/
|
||||
|
||||
Vector3f SoundEmitter::GetVelocity() const
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
Vector3f velocity;
|
||||
alGetSourcefv(m_source, AL_VELOCITY, &velocity.x);
|
||||
|
||||
return velocity;
|
||||
return m_source->GetVelocity();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the volume of the emitter
|
||||
* \param volume Float between [0, inf) with 100.f being the default
|
||||
*/
|
||||
|
||||
float SoundEmitter::GetVolume() const
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
ALfloat gain;
|
||||
alGetSourcef(m_source, AL_GAIN, &gain);
|
||||
|
||||
return gain * 100.f;
|
||||
return m_source->GetVolume();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the sound emitter has spatialization enabled
|
||||
* \return true if it the case
|
||||
*/
|
||||
|
||||
bool SoundEmitter::IsSpatialized() const
|
||||
bool SoundEmitter::IsSpatializationEnabled() const
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
ALint relative;
|
||||
alGetSourcei(m_source, AL_SOURCE_RELATIVE, &relative);
|
||||
|
||||
return relative == AL_FALSE;
|
||||
return m_source->IsSpatializationEnabled();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -197,12 +110,9 @@ namespace Nz
|
|||
*
|
||||
* \param attenuation Amount that your sound will drop off as by the inverse square law
|
||||
*/
|
||||
|
||||
void SoundEmitter::SetAttenuation(float attenuation)
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
alSourcef(m_source, AL_ROLLOFF_FACTOR, attenuation);
|
||||
m_source->SetAttenuation(attenuation);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -210,12 +120,9 @@ namespace Nz
|
|||
*
|
||||
* \param minDistance to begin to hear
|
||||
*/
|
||||
|
||||
void SoundEmitter::SetMinDistance(float minDistance)
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
alSourcef(m_source, AL_REFERENCE_DISTANCE, minDistance);
|
||||
m_source->SetMinDistance(minDistance);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -223,12 +130,9 @@ namespace Nz
|
|||
*
|
||||
* \param pitch of the sound
|
||||
*/
|
||||
|
||||
void SoundEmitter::SetPitch(float pitch)
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
alSourcef(m_source, AL_PITCH, pitch);
|
||||
m_source->SetPitch(pitch);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -236,25 +140,9 @@ namespace Nz
|
|||
*
|
||||
* \param position Position of the sound
|
||||
*/
|
||||
|
||||
void SoundEmitter::SetPosition(const Vector3f& position)
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
alSourcefv(m_source, AL_POSITION, &position.x);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the position of the emitter
|
||||
*
|
||||
* \param position Position of the sound with (x, y, z)
|
||||
*/
|
||||
|
||||
void SoundEmitter::SetPosition(float x, float y, float z)
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
alSource3f(m_source, AL_POSITION, x, y, z);
|
||||
m_source->SetPosition(position);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -262,25 +150,9 @@ namespace Nz
|
|||
*
|
||||
* \param velocity Velocity of the sound
|
||||
*/
|
||||
|
||||
void SoundEmitter::SetVelocity(const Vector3f& velocity)
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
alSourcefv(m_source, AL_VELOCITY, &velocity.x);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the velocity of the emitter
|
||||
*
|
||||
* \param velocity Velocity with (velX, velY, velZ)
|
||||
*/
|
||||
|
||||
void SoundEmitter::SetVelocity(float velX, float velY, float velZ)
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
alSource3f(m_source, AL_VELOCITY, velX, velY, velZ);
|
||||
m_source->SetVelocity(velocity);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -288,56 +160,8 @@ namespace Nz
|
|||
*
|
||||
* \param volume Float between [0, inf) with 100.f being the default
|
||||
*/
|
||||
|
||||
void SoundEmitter::SetVolume(float volume)
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
alSourcef(m_source, AL_GAIN, volume * 0.01f);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Assign a sound emitter by moving it
|
||||
*
|
||||
* \param emitter SoundEmitter to move
|
||||
*
|
||||
* \return *this
|
||||
*/
|
||||
SoundEmitter& SoundEmitter::operator=(SoundEmitter&& emitter) noexcept
|
||||
{
|
||||
std::swap(m_source, emitter.m_source);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the status of the sound emitter
|
||||
* \return Enumeration of type SoundStatus (Playing, Stopped, ...)
|
||||
*/
|
||||
|
||||
SoundStatus SoundEmitter::GetInternalStatus() const
|
||||
{
|
||||
NazaraAssert(m_source != InvalidSource, "Invalid sound emitter");
|
||||
|
||||
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;
|
||||
m_source->SetVolume(volume);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ SCENARIO("Music", "[AUDIO][MUSIC]")
|
|||
|
||||
THEN("We can play it and get the time offset")
|
||||
{
|
||||
Nz::Audio::Instance()->SetGlobalVolume(0.f);
|
||||
Nz::Audio::Instance()->GetDefaultDevice()->SetGlobalVolume(0.f);
|
||||
|
||||
music.Play();
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
|
@ -44,7 +44,7 @@ SCENARIO("Music", "[AUDIO][MUSIC]")
|
|||
music.SetPlayingOffset(3500);
|
||||
REQUIRE(music.GetPlayingOffset() >= 3500);
|
||||
|
||||
Nz::Audio::Instance()->SetGlobalVolume(100.f);
|
||||
Nz::Audio::Instance()->GetDefaultDevice()->SetGlobalVolume(100.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ SCENARIO("SoundEmitter", "[AUDIO][SOUNDEMITTER]")
|
|||
sound.SetPosition(Nz::Vector3f::Zero());
|
||||
sound.SetVelocity(Nz::Vector3f::UnitX());
|
||||
|
||||
REQUIRE(sound.IsSpatialized());
|
||||
REQUIRE(sound.IsSpatializationEnabled());
|
||||
REQUIRE(sound.GetPosition() == Nz::Vector3f::Zero());
|
||||
REQUIRE(sound.GetVelocity() == Nz::Vector3f::UnitX());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ SCENARIO("Sound", "[AUDIO][SOUND]")
|
|||
|
||||
THEN("We can play it and get the time offset")
|
||||
{
|
||||
Nz::Audio::Instance()->SetGlobalVolume(0.f);
|
||||
Nz::Audio::Instance()->GetDefaultDevice()->SetGlobalVolume(0.f);
|
||||
|
||||
sound.Play();
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
|
@ -39,7 +39,7 @@ SCENARIO("Sound", "[AUDIO][SOUND]")
|
|||
sound.SetPlayingOffset(3500);
|
||||
REQUIRE(sound.GetPlayingOffset() >= 3500);
|
||||
|
||||
Nz::Audio::Instance()->SetGlobalVolume(100.f);
|
||||
Nz::Audio::Instance()->GetDefaultDevice()->SetGlobalVolume(100.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue