diff --git a/include/Nazara/Audio.hpp b/include/Nazara/Audio.hpp index 4463fec3e..2ecf5bc81 100644 --- a/include/Nazara/Audio.hpp +++ b/include/Nazara/Audio.hpp @@ -31,10 +31,17 @@ #include #include +#include +#include +#include #include #include #include #include +#include +#include +#include +#include #include #include #include diff --git a/include/Nazara/Audio/Audio.hpp b/include/Nazara/Audio/Audio.hpp index e3ddf2eae..d3e31983c 100644 --- a/include/Nazara/Audio/Audio.hpp +++ b/include/Nazara/Audio/Audio.hpp @@ -13,8 +13,6 @@ #include #include #include -#include -#include 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& 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 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 QueryInputDevices() const; + std::vector QueryOutputDevices() const; Audio& operator=(const Audio&) = delete; Audio& operator=(Audio&&) = delete; private: + std::shared_ptr m_defaultDevice; SoundBufferLoader m_soundBufferLoader; SoundStreamLoader m_soundStreamLoader; diff --git a/include/Nazara/Audio/AudioBuffer.hpp b/include/Nazara/Audio/AudioBuffer.hpp new file mode 100644 index 000000000..ea3de270d --- /dev/null +++ b/include/Nazara/Audio/AudioBuffer.hpp @@ -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 +#include +#include +#include + +namespace Nz +{ + class AudioDevice; + + class NAZARA_AUDIO_API AudioBuffer + { + public: + inline AudioBuffer(std::shared_ptr device); + AudioBuffer(const AudioBuffer&) = default; + AudioBuffer(AudioBuffer&&) = default; + virtual ~AudioBuffer(); + + inline const std::shared_ptr& 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 m_device; + }; +} + +#include + +#endif // NAZARA_AUDIO_AUDIOBUFFER_HPP diff --git a/include/Nazara/Audio/AudioBuffer.inl b/include/Nazara/Audio/AudioBuffer.inl new file mode 100644 index 000000000..b09b01e37 --- /dev/null +++ b/include/Nazara/Audio/AudioBuffer.inl @@ -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 +#include + +namespace Nz +{ + inline AudioBuffer::AudioBuffer(std::shared_ptr device) : + m_device(std::move(device)) + { + } + + inline const std::shared_ptr& AudioBuffer::GetAudioDevice() const + { + return m_device; + } +} + +#include diff --git a/include/Nazara/Audio/AudioDevice.hpp b/include/Nazara/Audio/AudioDevice.hpp new file mode 100644 index 000000000..54522d23f --- /dev/null +++ b/include/Nazara/Audio/AudioDevice.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 +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class AudioBuffer; + class AudioSource; + + class NAZARA_AUDIO_API AudioDevice : public std::enable_shared_from_this + { + public: + AudioDevice() = default; + AudioDevice(const AudioDevice&) = delete; + AudioDevice(AudioDevice&&) = default; + virtual ~AudioDevice(); + + virtual std::shared_ptr CreateBuffer() = 0; + virtual std::shared_ptr 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 + +#endif // NAZARA_AUDIO_AUDIODEVICE_HPP diff --git a/include/Nazara/Audio/AudioDevice.inl b/include/Nazara/Audio/AudioDevice.inl new file mode 100644 index 000000000..01209d48b --- /dev/null +++ b/include/Nazara/Audio/AudioDevice.inl @@ -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 +#include + +namespace Nz +{ + inline void AudioDevice::SetListenerRotation(const Quaternionf& rotation) + { + SetListenerDirection(rotation * Vector3f::Forward(), rotation * Vector3f::Up()); + } +} + +#include diff --git a/include/Nazara/Audio/AudioSource.hpp b/include/Nazara/Audio/AudioSource.hpp new file mode 100644 index 000000000..94932d293 --- /dev/null +++ b/include/Nazara/Audio/AudioSource.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 +#include +#include +#include + +namespace Nz +{ + class AudioBuffer; + class AudioDevice; + + class NAZARA_AUDIO_API AudioSource + { + public: + inline AudioSource(std::shared_ptr 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& 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) = 0; + + virtual void Pause() = 0; + virtual void Play() = 0; + + virtual void SetAttenuation(float attenuation) = 0; + virtual void SetBuffer(std::shared_ptr 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 TryUnqueueProcessedBuffer() = 0; + + virtual void UnqueueAllBuffers() = 0; + + AudioSource& operator=(const AudioSource&) = delete; + AudioSource& operator=(AudioSource&&) = delete; + + private: + std::shared_ptr m_device; + }; +} + +#include + +#endif // NAZARA_AUDIO_AUDIOSOURCE_HPP diff --git a/include/Nazara/Audio/AudioSource.inl b/include/Nazara/Audio/AudioSource.inl new file mode 100644 index 000000000..f3c9cc0b0 --- /dev/null +++ b/include/Nazara/Audio/AudioSource.inl @@ -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 +#include + +namespace Nz +{ + inline AudioSource::AudioSource(std::shared_ptr device) : + m_device(std::move(device)) + { + } + + inline const std::shared_ptr& AudioSource::GetAudioDevice() const + { + return m_device; + } +} + +#include diff --git a/include/Nazara/Audio/Config.hpp b/include/Nazara/Audio/Config.hpp index 4cf09df2d..1927c6ba3 100644 --- a/include/Nazara/Audio/Config.hpp +++ b/include/Nazara/Audio/Config.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 diff --git a/include/Nazara/Audio/ConfigCheck.hpp b/include/Nazara/Audio/ConfigCheck.hpp index 7b5f4971a..2539622ad 100644 --- a/include/Nazara/Audio/ConfigCheck.hpp +++ b/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 diff --git a/include/Nazara/Audio/Enums.hpp b/include/Nazara/Audio/Enums.hpp index 67bb4b540..70d2977cf 100644 --- a/include/Nazara/Audio/Enums.hpp +++ b/include/Nazara/Audio/Enums.hpp @@ -7,6 +7,8 @@ #ifndef NAZARA_AUDIO_ENUMS_HPP #define NAZARA_AUDIO_ENUMS_HPP +#include + namespace Nz { enum class AudioFormat diff --git a/include/Nazara/Audio/Music.hpp b/include/Nazara/Audio/Music.hpp index 985fb0121..ff792c1e0 100644 --- a/include/Nazara/Audio/Music.hpp +++ b/include/Nazara/Audio/Music.hpp @@ -11,20 +11,24 @@ #include #include #include +#include #include -#include +#include #include +#include +#include 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); @@ -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 m_impl; + AudioFormat m_audioFormat; + std::atomic_bool m_streaming; + std::atomic m_processedSamples; + mutable std::mutex m_bufferLock; + std::size_t m_bufferCount; + std::shared_ptr m_stream; + std::thread m_thread; + std::vector m_chunkSamples; + UInt32 m_sampleRate; + UInt64 m_streamOffset; + bool m_looping; - bool FillAndQueueBuffer(unsigned int buffer); + bool FillAndQueueBuffer(std::shared_ptr buffer); void MusicThread(std::condition_variable& cv, std::mutex& m, std::exception_ptr& err); void StopThread(); }; diff --git a/include/Nazara/Audio/OpenAL.hpp b/include/Nazara/Audio/OpenAL.hpp index aa0cc572e..a141cb99d 100644 --- a/include/Nazara/Audio/OpenAL.hpp +++ b/include/Nazara/Audio/OpenAL.hpp @@ -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 -#include -#include -#include -#include +#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& devices); - static std::size_t QueryOutputDevices(std::vector& 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 diff --git a/include/Nazara/Audio/OpenALBuffer.hpp b/include/Nazara/Audio/OpenALBuffer.hpp new file mode 100644 index 000000000..a114eb7b3 --- /dev/null +++ b/include/Nazara/Audio/OpenALBuffer.hpp @@ -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 +#include +#include +#include + +namespace Nz +{ + class OpenALDevice; + class OpenALLibrary; + + class NAZARA_AUDIO_API OpenALBuffer final : public AudioBuffer + { + public: + inline OpenALBuffer(std::shared_ptr 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 + +#endif // NAZARA_AUDIO_OPENAL + +#endif // NAZARA_AUDIO_OPENALBUFFER_HPP diff --git a/include/Nazara/Audio/OpenALBuffer.inl b/include/Nazara/Audio/OpenALBuffer.inl new file mode 100644 index 000000000..513d46f11 --- /dev/null +++ b/include/Nazara/Audio/OpenALBuffer.inl @@ -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 +#include + +namespace Nz +{ + inline OpenALBuffer::OpenALBuffer(std::shared_ptr device, OpenALLibrary& library, ALuint bufferId) : + AudioBuffer(std::move(device)), + m_bufferId(bufferId), + m_library(library) + { + } + + inline ALuint OpenALBuffer::GetBufferId() const + { + return m_bufferId; + } +} + +#include diff --git a/include/Nazara/Audio/OpenALDevice.hpp b/include/Nazara/Audio/OpenALDevice.hpp new file mode 100644 index 000000000..ba2331f1e --- /dev/null +++ b/include/Nazara/Audio/OpenALDevice.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 +#include +#include +#include +#include +#include +#include +#include + +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 CreateBuffer() override; + std::shared_ptr 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 m_audioFormatValues; + std::string m_renderer; + std::string m_vendor; + OpenALLibrary& m_library; + MovablePtr m_context; + MovablePtr m_device; + }; +} + +#include + +#endif // NAZARA_AUDIO_OPENAL + +#endif // NAZARA_AUDIO_OPENALDEVICE_HPP diff --git a/include/Nazara/Audio/OpenALDevice.inl b/include/Nazara/Audio/OpenALDevice.inl new file mode 100644 index 000000000..047fdcfc9 --- /dev/null +++ b/include/Nazara/Audio/OpenALDevice.inl @@ -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 +#include +#include + +namespace Nz +{ + inline ALenum OpenALDevice::TranslateAudioFormat(AudioFormat format) const + { + return m_audioFormatValues[UnderlyingCast(format)]; + } +} + +#include diff --git a/include/Nazara/Audio/OpenALLibrary.hpp b/include/Nazara/Audio/OpenALLibrary.hpp new file mode 100644 index 000000000..ab460a760 --- /dev/null +++ b/include/Nazara/Audio/OpenALLibrary.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 +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_AUDIO_API OpenALLibrary + { + public: + OpenALLibrary() = default; + OpenALLibrary(const OpenALLibrary&) = delete; + OpenALLibrary(OpenALLibrary&&) = delete; + inline ~OpenALLibrary(); + + bool Load(); + + std::vector QueryInputDevices(); + std::vector QueryOutputDevices(); + + std::shared_ptr 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 ParseDevices(const char* deviceString); + + DynLib m_library; + }; +} + +#include + +#endif // NAZARA_AUDIO_OPENAL + +#endif // NAZARA_AUDIO_OPENALLIBRARY_HPP diff --git a/include/Nazara/Audio/OpenALLibrary.inl b/include/Nazara/Audio/OpenALLibrary.inl new file mode 100644 index 000000000..681f45256 --- /dev/null +++ b/include/Nazara/Audio/OpenALLibrary.inl @@ -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 +#include + +namespace Nz +{ + inline OpenALLibrary::~OpenALLibrary() + { + Unload(); + } +} + +#include diff --git a/include/Nazara/Audio/OpenALSource.hpp b/include/Nazara/Audio/OpenALSource.hpp new file mode 100644 index 000000000..91e8edb31 --- /dev/null +++ b/include/Nazara/Audio/OpenALSource.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 +#include +#include +#include + +namespace Nz +{ + class OpenALBuffer; + class OpenALDevice; + class OpenALLibrary; + + class NAZARA_AUDIO_API OpenALSource final : public AudioSource + { + public: + inline OpenALSource(std::shared_ptr 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) override; + + void Pause() override; + void Play() override; + + void SetAttenuation(float attenuation) override; + void SetBuffer(std::shared_ptr 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 TryUnqueueProcessedBuffer() override; + + void UnqueueAllBuffers() override; + + OpenALSource& operator=(const OpenALSource&) = delete; + OpenALSource& operator=(OpenALSource&&) = delete; + + private: + OpenALDevice& GetDevice(); + const OpenALDevice& GetDevice() const; + + std::shared_ptr m_currentBuffer; + std::vector> m_queuedBuffers; + ALuint m_sourceId; + OpenALLibrary& m_library; + }; +} + +#include + +#endif // NAZARA_AUDIO_OPENAL + +#endif // NAZARA_AUDIO_OPENALSOURCE_HPP diff --git a/include/Nazara/Audio/OpenALSource.inl b/include/Nazara/Audio/OpenALSource.inl new file mode 100644 index 000000000..88f8f30b4 --- /dev/null +++ b/include/Nazara/Audio/OpenALSource.inl @@ -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 +#include + +namespace Nz +{ + inline OpenALSource::OpenALSource(std::shared_ptr device, OpenALLibrary& library, ALuint sourceId) : + AudioSource(std::move(device)), + m_sourceId(sourceId), + m_library(library) + { + } +} + +#include diff --git a/include/Nazara/Audio/Sound.hpp b/include/Nazara/Audio/Sound.hpp index 4bfae72ac..560b5cb14 100644 --- a/include/Nazara/Audio/Sound.hpp +++ b/include/Nazara/Audio/Sound.hpp @@ -17,15 +17,16 @@ namespace Nz class NAZARA_AUDIO_API Sound : public SoundEmitter { public: - Sound() = default; - Sound(std::shared_ptr soundBuffer); + using SoundEmitter::SoundEmitter; + Sound(); + Sound(AudioDevice& audioDevice, std::shared_ptr soundBuffer); Sound(const Sound&) = default; - Sound(Sound&&) noexcept = default; + Sound(Sound&&) = default; ~Sound(); void EnableLooping(bool loop) override; - const std::shared_ptr& GetBuffer() const; + const std::shared_ptr& 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 soundBuffer); + void SetBuffer(std::shared_ptr 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 m_buffer; + std::shared_ptr m_buffer; }; } diff --git a/include/Nazara/Audio/SoundBuffer.hpp b/include/Nazara/Audio/SoundBuffer.hpp index e87a372da..d3b2c571a 100644 --- a/include/Nazara/Audio/SoundBuffer.hpp +++ b/include/Nazara/Audio/SoundBuffer.hpp @@ -8,6 +8,7 @@ #define NAZARA_AUDIO_SOUNDBUFFER_HPP #include +#include #include #include #include @@ -15,7 +16,8 @@ #include #include #include -#include +#include +#include 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& 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 LoadFromFile(const std::filesystem::path& filePath, const SoundBufferParams& params = SoundBufferParams()); static std::shared_ptr LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params = SoundBufferParams()); static std::shared_ptr LoadFromStream(Stream& stream, const SoundBufferParams& params = SoundBufferParams()); private: - unsigned int GetOpenALBuffer() const; + struct AudioDeviceEntry + { + std::shared_ptr audioBuffer; - std::unique_ptr m_impl; + NazaraSlot(AudioDevice, OnAudioDeviceRelease, audioDeviceReleaseSlot); + }; + + std::unordered_map m_audioBufferByDevice; + std::unique_ptr m_samples; + AudioFormat m_format; + UInt32 m_duration; + UInt32 m_sampleRate; + UInt64 m_sampleCount; }; } diff --git a/include/Nazara/Audio/SoundBuffer.inl b/include/Nazara/Audio/SoundBuffer.inl index 5bf7d6998..afa95e570 100644 --- a/include/Nazara/Audio/SoundBuffer.inl +++ b/include/Nazara/Audio/SoundBuffer.inl @@ -3,11 +3,64 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include #include 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 diff --git a/include/Nazara/Audio/SoundEmitter.hpp b/include/Nazara/Audio/SoundEmitter.hpp index 98d652a17..eca2fd366 100644 --- a/include/Nazara/Audio/SoundEmitter.hpp +++ b/include/Nazara/Audio/SoundEmitter.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::max(); - - unsigned int m_source; + std::shared_ptr m_source; }; } diff --git a/include/Nazara/Math/Box.inl b/include/Nazara/Math/Box.inl index b308b56a1..7d3c0b9d1 100644 --- a/include/Nazara/Math/Box.inl +++ b/include/Nazara/Math/Box.inl @@ -13,7 +13,7 @@ namespace Nz { /*! - * \ingroup math + * \ingroup math * \class Nz::Box * \brief Math class that represents a three dimensional box */ diff --git a/include/Nazara/Shader/ShaderLangErrorList.hpp b/include/Nazara/Shader/ShaderLangErrorList.hpp new file mode 100644 index 000000000..e6e3c4e9b --- /dev/null +++ b/include/Nazara/Shader/ShaderLangErrorList.hpp @@ -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 diff --git a/src/Nazara/Audio/Audio.cpp b/src/Nazara/Audio/Audio.cpp index e61d7e426..cb74009ad 100644 --- a/src/Nazara/Audio/Audio.cpp +++ b/src/Nazara/Audio/Audio.cpp @@ -3,10 +3,11 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include #include #include -#include -#include +#include #include #include #include @@ -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& 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 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 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 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; diff --git a/src/Nazara/Audio/AudioBuffer.cpp b/src/Nazara/Audio/AudioBuffer.cpp new file mode 100644 index 000000000..8c5272aaf --- /dev/null +++ b/src/Nazara/Audio/AudioBuffer.cpp @@ -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 +#include + +namespace Nz +{ + AudioBuffer::~AudioBuffer() = default; +} diff --git a/src/Nazara/Audio/AudioDevice.cpp b/src/Nazara/Audio/AudioDevice.cpp new file mode 100644 index 000000000..06262737b --- /dev/null +++ b/src/Nazara/Audio/AudioDevice.cpp @@ -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 +#include + +namespace Nz +{ + AudioDevice::~AudioDevice() = default; +} diff --git a/src/Nazara/Audio/AudioSource.cpp b/src/Nazara/Audio/AudioSource.cpp new file mode 100644 index 000000000..3953378c5 --- /dev/null +++ b/src/Nazara/Audio/AudioSource.cpp @@ -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 +#include + +namespace Nz +{ + AudioSource::~AudioSource() = default; +} diff --git a/src/Nazara/Audio/Music.cpp b/src/Nazara/Audio/Music.cpp index e1d35da71..17cda430b 100644 --- a/src/Nazara/Audio/Music.cpp +++ b/src/Nazara/Audio/Music.cpp @@ -4,15 +4,14 @@ #include #include -#include +#include +#include +#include +#include #include #include #include -#include #include -#include -#include -#include #include 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 processedSamples; - std::vector chunkSamples; - std::mutex bufferLock; - std::shared_ptr 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) { NazaraAssert(soundStream, "Invalid stream"); @@ -67,11 +61,10 @@ namespace Nz AudioFormat format = soundStream->GetFormat(); - m_impl = std::make_unique(); - 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 lock(m_impl->bufferLock); + // Prevent music thread from enqueuing new buffers while we're getting the count + std::lock_guard lock(m_bufferLock); - ALint samples = 0; - alGetSourcei(m_source, AL_SAMPLE_OFFSET, &samples); + UInt32 sampleOffset = m_source->GetSampleOffset(); - return static_cast((1000ULL * (samples + (m_impl->processedSamples / GetChannelCount(m_impl->stream->GetFormat())))) / m_impl->sampleRate); + return static_cast((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 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 buffer) { - std::size_t sampleCount = m_impl->chunkSamples.size(); + std::size_t sampleCount = m_chunkSamples.size(); std::size_t sampleRead = 0; { - std::lock_guard lock(m_impl->stream->GetMutex()); + std::lock_guard 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(sampleRead*sizeof(Int16)), static_cast(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 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 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 lock(m_impl->bufferLock); + std::lock_guard lock(m_bufferLock); // We treat read buffers - ALint processedCount = 0; - alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &processedCount); - while (processedCount--) + while (std::shared_ptr 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(); } } diff --git a/src/Nazara/Audio/OpenAL.cpp b/src/Nazara/Audio/OpenAL.cpp deleted file mode 100644 index fac466b04..000000000 --- a/src/Nazara/Audio/OpenAL.cpp +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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& 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(LoadEntry("alBuffer3f")); - alBuffer3i = reinterpret_cast(LoadEntry("alBuffer3i")); - alBufferData = reinterpret_cast(LoadEntry("alBufferData")); - alBufferf = reinterpret_cast(LoadEntry("alBufferf")); - alBufferfv = reinterpret_cast(LoadEntry("alBufferfv")); - alBufferi = reinterpret_cast(LoadEntry("alBufferi")); - alBufferiv = reinterpret_cast(LoadEntry("alBufferiv")); - alDeleteBuffers = reinterpret_cast(LoadEntry("alDeleteBuffers")); - alDeleteSources = reinterpret_cast(LoadEntry("alDeleteSources")); - alDisable = reinterpret_cast(LoadEntry("alDisable")); - alDistanceModel = reinterpret_cast(LoadEntry("alDistanceModel")); - alDopplerFactor = reinterpret_cast(LoadEntry("alDopplerFactor")); - alDopplerVelocity = reinterpret_cast(LoadEntry("alDopplerVelocity")); - alEnable = reinterpret_cast(LoadEntry("alEnable")); - alGenBuffers = reinterpret_cast(LoadEntry("alGenBuffers")); - alGenSources = reinterpret_cast(LoadEntry("alGenSources")); - alGetBoolean = reinterpret_cast(LoadEntry("alGetBoolean")); - alGetBooleanv = reinterpret_cast(LoadEntry("alGetBooleanv")); - alGetBuffer3f = reinterpret_cast(LoadEntry("alGetBuffer3f")); - alGetBuffer3i = reinterpret_cast(LoadEntry("alGetBuffer3i")); - alGetBufferf = reinterpret_cast(LoadEntry("alGetBufferf")); - alGetBufferfv = reinterpret_cast(LoadEntry("alGetBufferfv")); - alGetBufferi = reinterpret_cast(LoadEntry("alGetBufferi")); - alGetBufferiv = reinterpret_cast(LoadEntry("alGetBufferiv")); - alGetDouble = reinterpret_cast(LoadEntry("alGetDouble")); - alGetDoublev = reinterpret_cast(LoadEntry("alGetDoublev")); - alGetEnumValue = reinterpret_cast(LoadEntry("alGetEnumValue")); - alGetError = reinterpret_cast(LoadEntry("alGetError")); - alGetFloat = reinterpret_cast(LoadEntry("alGetFloat")); - alGetFloatv = reinterpret_cast(LoadEntry("alGetFloatv")); - alGetInteger = reinterpret_cast(LoadEntry("alGetInteger")); - alGetIntegerv = reinterpret_cast(LoadEntry("alGetIntegerv")); - alGetListener3f = reinterpret_cast(LoadEntry("alGetListener3f")); - alGetListener3i = reinterpret_cast(LoadEntry("alGetListener3i")); - alGetListenerf = reinterpret_cast(LoadEntry("alGetListenerf")); - alGetListenerfv = reinterpret_cast(LoadEntry("alGetListenerfv")); - alGetListeneri = reinterpret_cast(LoadEntry("alGetListeneri")); - alGetListeneriv = reinterpret_cast(LoadEntry("alGetListeneriv")); - alGetProcAddress = reinterpret_cast(LoadEntry("alGetProcAddress")); - alGetSource3f = reinterpret_cast(LoadEntry("alGetSource3f")); - alGetSource3i = reinterpret_cast(LoadEntry("alGetSource3i")); - alGetSourcef = reinterpret_cast(LoadEntry("alGetSourcef")); - alGetSourcefv = reinterpret_cast(LoadEntry("alGetSourcefv")); - alGetSourcei = reinterpret_cast(LoadEntry("alGetSourcei")); - alGetSourceiv = reinterpret_cast(LoadEntry("alGetSourceiv")); - alGetString = reinterpret_cast(LoadEntry("alGetString")); - alIsBuffer = reinterpret_cast(LoadEntry("alIsBuffer")); - alIsEnabled = reinterpret_cast(LoadEntry("alIsEnabled")); - alIsExtensionPresent = reinterpret_cast(LoadEntry("alIsExtensionPresent")); - alIsSource = reinterpret_cast(LoadEntry("alIsSource")); - alListener3f = reinterpret_cast(LoadEntry("alListener3f")); - alListener3i = reinterpret_cast(LoadEntry("alListener3i")); - alListenerf = reinterpret_cast(LoadEntry("alListenerf")); - alListenerfv = reinterpret_cast(LoadEntry("alListenerfv")); - alListeneri = reinterpret_cast(LoadEntry("alListeneri")); - alListeneriv = reinterpret_cast(LoadEntry("alListeneriv")); - alSource3f = reinterpret_cast(LoadEntry("alSource3f")); - alSource3i = reinterpret_cast(LoadEntry("alSource3i")); - alSourcef = reinterpret_cast(LoadEntry("alSourcef")); - alSourcefv = reinterpret_cast(LoadEntry("alSourcefv")); - alSourcei = reinterpret_cast(LoadEntry("alSourcei")); - alSourceiv = reinterpret_cast(LoadEntry("alSourceiv")); - alSourcePause = reinterpret_cast(LoadEntry("alSourcePause")); - alSourcePausev = reinterpret_cast(LoadEntry("alSourcePausev")); - alSourcePlay = reinterpret_cast(LoadEntry("alSourcePlay")); - alSourcePlayv = reinterpret_cast(LoadEntry("alSourcePlayv")); - alSourceQueueBuffers = reinterpret_cast(LoadEntry("alSourceQueueBuffers")); - alSourceRewind = reinterpret_cast(LoadEntry("alSourceRewind")); - alSourceRewindv = reinterpret_cast(LoadEntry("alSourceRewindv")); - alSourceStop = reinterpret_cast(LoadEntry("alSourceStop")); - alSourceStopv = reinterpret_cast(LoadEntry("alSourceStopv")); - alSourceUnqueueBuffers = reinterpret_cast(LoadEntry("alSourceUnqueueBuffers")); - alSpeedOfSound = reinterpret_cast(LoadEntry("alSpeedOfSound")); - - // alc - alcCaptureCloseDevice = reinterpret_cast(LoadEntry("alcCaptureCloseDevice")); - alcCaptureOpenDevice = reinterpret_cast(LoadEntry("alcCaptureOpenDevice")); - alcCaptureSamples = reinterpret_cast(LoadEntry("alcCaptureSamples")); - alcCaptureStart = reinterpret_cast(LoadEntry("alcCaptureStart")); - alcCaptureStop = reinterpret_cast(LoadEntry("alcCaptureStop")); - alcCloseDevice = reinterpret_cast(LoadEntry("alcCloseDevice")); - alcCreateContext = reinterpret_cast(LoadEntry("alcCreateContext")); - alcDestroyContext = reinterpret_cast(LoadEntry("alcDestroyContext")); - alcGetContextsDevice = reinterpret_cast(LoadEntry("alcGetContextsDevice")); - alcGetCurrentContext = reinterpret_cast(LoadEntry("alcGetCurrentContext")); - alcGetEnumValue = reinterpret_cast(LoadEntry("alcGetEnumValue")); - alcGetError = reinterpret_cast(LoadEntry("alcGetError")); - alcGetIntegerv = reinterpret_cast(LoadEntry("alcGetIntegerv")); - alcGetProcAddress = reinterpret_cast(LoadEntry("alcGetProcAddress")); - alcGetString = reinterpret_cast(LoadEntry("alcGetString")); - alcIsExtensionPresent = reinterpret_cast(LoadEntry("alcIsExtensionPresent")); - alcMakeContextCurrent = reinterpret_cast(LoadEntry("alcMakeContextCurrent")); - alcOpenDevice = reinterpret_cast(LoadEntry("alcOpenDevice")); - alcProcessContext = reinterpret_cast(LoadEntry("alcProcessContext")); - alcSuspendContext = reinterpret_cast(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& devices) - { - const char* deviceString = reinterpret_cast(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& devices) - { - const char* deviceString = reinterpret_cast(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(alGetString(AL_RENDERER)); - s_openalVendorName = reinterpret_cast(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(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; - -} diff --git a/src/Nazara/Audio/OpenALBuffer.cpp b/src/Nazara/Audio/OpenALBuffer.cpp new file mode 100644 index 000000000..c7c2cefcd --- /dev/null +++ b/src/Nazara/Audio/OpenALBuffer.cpp @@ -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 +#include +#include +#include +#include + +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(size)) / SafeCast(bits); + + return sampleCount; + } + + UInt32 OpenALBuffer::GetSize() const + { + GetDevice().MakeContextCurrent(); + + ALint size; + m_library.alGetBufferi(m_bufferId, AL_SIZE, &size); + + return SafeCast(size); + } + + UInt32 OpenALBuffer::GetSampleRate() const + { + GetDevice().MakeContextCurrent(); + + ALint sampleRate; + m_library.alGetBufferi(m_bufferId, AL_FREQUENCY, &sampleRate); + + return SafeCast(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(sampleCount * sizeof(Int16)), static_cast(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(*GetAudioDevice()); + } + + const OpenALDevice& OpenALBuffer::GetDevice() const + { + return SafeCast(*GetAudioDevice()); + } +} diff --git a/src/Nazara/Audio/OpenALDevice.cpp b/src/Nazara/Audio/OpenALDevice.cpp new file mode 100644 index 000000000..64ab3bac4 --- /dev/null +++ b/src/Nazara/Audio/OpenALDevice.cpp @@ -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 +#include +#include +#include +#include +#include +#include + +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(m_library.alGetString(AL_RENDERER)); + m_vendor = reinterpret_cast(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 OpenALDevice::CreateBuffer() + { + MakeContextCurrent(); + + ALuint bufferId = 0; + m_library.alGenBuffers(1, &bufferId); + + if (bufferId == 0) + return {}; + + return std::make_shared(shared_from_this(), m_library, bufferId); + } + + std::shared_ptr OpenALDevice::CreateSource() + { + MakeContextCurrent(); + + ALuint sourceId = 0; + m_library.alGenSources(1, &sourceId); + + if (sourceId == 0) + return {}; + + return std::make_shared(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); + } +} diff --git a/src/Nazara/Audio/OpenALLibrary.cpp b/src/Nazara/Audio/OpenALLibrary.cpp new file mode 100644 index 000000000..eccdd16b1 --- /dev/null +++ b/src/Nazara/Audio/OpenALLibrary.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(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 OpenALLibrary::QueryInputDevices() + { + return ParseDevices(alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER)); + } + + std::vector OpenALLibrary::QueryOutputDevices() + { + return ParseDevices(alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER)); + } + + std::shared_ptr OpenALLibrary::OpenDevice(const char* name) + { + ALCdevice* device = alcOpenDevice(name); + if (!device) + throw std::runtime_error("failed to open device"); + + return std::make_shared(*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 OpenALLibrary::ParseDevices(const char* deviceString) + { + if (!deviceString) + return {}; + + std::vector devices; + std::size_t length; + while ((length = std::strlen(deviceString)) > 0) + { + devices.emplace_back(deviceString, length); + deviceString += length + 1; + } + + return devices; + } +} diff --git a/src/Nazara/Audio/OpenALSource.cpp b/src/Nazara/Audio/OpenALSource.cpp new file mode 100644 index 000000000..003e8007f --- /dev/null +++ b/src/Nazara/Audio/OpenALSource.cpp @@ -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 +#include +#include +#include +#include +#include +#include + +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(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) + { + NazaraAssert(audioBuffer, "invalid buffer"); + NazaraAssert(audioBuffer->GetAudioDevice() == GetAudioDevice(), "incompatible buffer"); + + std::shared_ptr newBuffer = std::static_pointer_cast(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) + { + NazaraAssert(audioBuffer->GetAudioDevice() == GetAudioDevice(), "incompatible buffer"); + + std::shared_ptr newBuffer = std::static_pointer_cast(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 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& alBuffer) + { + return alBuffer->GetBufferId() == bufferId; + }); + assert(it != m_queuedBuffers.end()); + + std::shared_ptr 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 buffers = NazaraStackArrayNoInit(ALuint, queuedBufferCount); + m_library.alSourceUnqueueBuffers(m_sourceId, queuedBufferCount, buffers.data()); + + m_queuedBuffers.clear(); + } + + OpenALDevice& OpenALSource::GetDevice() + { + return SafeCast(*GetAudioDevice()); + } + + const OpenALDevice& OpenALSource::GetDevice() const + { + return SafeCast(*GetAudioDevice()); + } +} diff --git a/src/Nazara/Audio/Sound.cpp b/src/Nazara/Audio/Sound.cpp index ed5be7ca1..2d566bb7c 100644 --- a/src/Nazara/Audio/Sound.cpp +++ b/src/Nazara/Audio/Sound.cpp @@ -3,8 +3,10 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include #include -#include +#include #include #include @@ -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 soundBuffer) + Sound::Sound(AudioDevice& audioDevice, std::shared_ptr 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& Sound::GetBuffer() const + const std::shared_ptr& 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(1000ULL * samples / m_buffer->GetSampleRate()); + UInt32 sampleCount = m_source->GetSampleOffset(); + return SafeCast(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 buffer) + void Sound::SetBuffer(std::shared_ptr 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(offset/1000.f * m_buffer->GetSampleRate())); + m_source->SetSampleOffset(SafeCast(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(); } } diff --git a/src/Nazara/Audio/SoundBuffer.cpp b/src/Nazara/Audio/SoundBuffer.cpp index a5d89b9e0..4272d0578 100644 --- a/src/Nazara/Audio/SoundBuffer.cpp +++ b/src/Nazara/Audio/SoundBuffer.cpp @@ -5,17 +5,14 @@ #include #include #include +#include #include -#include -#include #include #include #include #include #include -///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 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((1000ULL*sampleCount / (GetChannelCount(format) * sampleRate))); + m_format = format; + m_sampleCount = sampleCount; + m_sampleRate = sampleRate; + m_samples = std::make_unique(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& 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(sampleCount*sizeof(Int16)), static_cast(sampleRate)); - - if (alGetError() != AL_NO_ERROR) - { - NazaraError("Failed to set OpenAL buffer"); - return false; - } - - m_impl = std::make_unique(); - m_impl->buffer = buffer; - m_impl->duration = static_cast((1000ULL*sampleCount / (GetChannelCount(format) * sampleRate))); - m_impl->format = format; - m_impl->sampleCount = sampleCount; - m_impl->sampleRate = sampleRate; - m_impl->samples = std::make_unique(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; - } } diff --git a/src/Nazara/Audio/SoundEmitter.cpp b/src/Nazara/Audio/SoundEmitter.cpp index a0c1e5815..6bc0666bb 100644 --- a/src/Nazara/Audio/SoundEmitter.cpp +++ b/src/Nazara/Audio/SoundEmitter.cpp @@ -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 -#include +#include +#include #include #include @@ -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); } } diff --git a/tests/Engine/Audio/MusicTest.cpp b/tests/Engine/Audio/MusicTest.cpp index 0ccd02452..70e266eff 100644 --- a/tests/Engine/Audio/MusicTest.cpp +++ b/tests/Engine/Audio/MusicTest.cpp @@ -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); } } } diff --git a/tests/Engine/Audio/SoundEmitterTest.cpp b/tests/Engine/Audio/SoundEmitterTest.cpp index 84dbc53d5..9cad3f3a6 100644 --- a/tests/Engine/Audio/SoundEmitterTest.cpp +++ b/tests/Engine/Audio/SoundEmitterTest.cpp @@ -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()); } diff --git a/tests/Engine/Audio/SoundTest.cpp b/tests/Engine/Audio/SoundTest.cpp index 998f9f249..08ffc624d 100644 --- a/tests/Engine/Audio/SoundTest.cpp +++ b/tests/Engine/Audio/SoundTest.cpp @@ -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); } } }