From 52949f66f45575385736cd9a27c72a8cc2636547 Mon Sep 17 00:00:00 2001 From: Diogo Miranda Date: Wed, 2 Oct 2024 15:13:46 +0100 Subject: [PATCH] feat(audio): Add AudioListener and MiniaudioListener --- core/include/cubos/core/al/audio_context.hpp | 62 ++++++++----- .../cubos/core/al/miniaudio_context.hpp | 3 +- core/src/al/miniaudio_context.cpp | 89 ++++++++++++++----- engine/src/audio/audio.cpp | 5 +- 4 files changed, 109 insertions(+), 50 deletions(-) diff --git a/core/include/cubos/core/al/audio_context.hpp b/core/include/cubos/core/al/audio_context.hpp index 7556d8f03..20894bfc5 100644 --- a/core/include/cubos/core/al/audio_context.hpp +++ b/core/include/cubos/core/al/audio_context.hpp @@ -18,6 +18,7 @@ namespace cubos::core::al { class Buffer; class Source; + class Listener; } // namespace impl /// @brief Handle to an audio buffer. @@ -32,6 +33,12 @@ namespace cubos::core::al /// @ingroup core-al using Source = std::shared_ptr; + /// @brief Handle to an audio listener. + /// @see impl::Listener - audio listener interface. + /// @see AudioDevice::createListener() + /// @ingroup core-al + using Listener = std::shared_ptr; + /// @brief Audio device interface used to wrap low-level audio rendering APIs. class CUBOS_CORE_API AudioDevice { @@ -41,32 +48,13 @@ namespace cubos::core::al /// @brief Forbid copy construction. AudioDevice(const AudioDevice&) = delete; - /// @brief Creates a new audio buffer - /// @param data Data to be written to the buffer, cubos currently supports .wav, .mp3 and .flac files - /// @param datSize Size of the data to be written. - /// @return Handle of the new buffer. - virtual Buffer createBuffer(const void* data, size_t dataSize) = 0; - /// @brief Creates a new audio source. /// @return Handle of the new source. virtual Source createSource() = 0; - /// @brief Sets the position of the listener. - /// @param position Position. - /// @param listenerIndex Index of the listener. - virtual void setListenerPosition(const glm::vec3& position, unsigned int listenerIndex = 0) = 0; - - /// @brief Sets the orientation of the listener. - /// @param forward Forward direction of the listener. - /// @param up Up direction of the listener. - /// @param listenerIndex Index of the listener. - virtual void setListenerOrientation(const glm::vec3& forward, const glm::vec3& up, - unsigned int listenerIndex = 0) = 0; - - /// @brief Sets the velocity of the listener. Used to implement the doppler effect. - /// @param velocity Velocity of the listener. - /// @param listenerIndex Index of the listener. - virtual void setListenerVelocity(const glm::vec3& velocity, unsigned int listenerIndex = 0) = 0; + /// @brief Creates a new audio listener. + /// @return Handle of the new listener. + virtual Listener listener(size_t index) = 0; protected: AudioDevice() = default; @@ -90,7 +78,13 @@ namespace cubos::core::al /// @brief Creates a new audio device /// @param specifier The specifier of the audio device, used to identify it /// @return Handle of the new device - virtual std::shared_ptr createDevice(const std::string& specifier) = 0; + virtual std::shared_ptr createDevice(const std::string& specifier, unsigned int listenerCount) = 0; + + /// @brief Creates a new audio buffer. + /// @param data Data to be written to the buffer, cubos currently supports .wav, .mp3 and .flac files. + /// @param datSize Size of the data to be written. + /// @return Handle of the new buffer. + virtual Buffer createBuffer(const void* data, size_t dataSize) = 0; }; /// @brief Namespace to store the abstract types implemented by the audio device implementations. @@ -167,5 +161,27 @@ namespace cubos::core::al protected: Source() = default; }; + + class CUBOS_CORE_API Listener + { + public: + virtual ~Listener() = default; + + /// @brief Sets the velocity of the listener. Used to implement the doppler effect. + /// @param velocity Velocity of the listener. + virtual void setVelocity(const glm::vec3& velocity) = 0; + + /// @brief Sets the position of the listener. + /// @param position Position. + virtual void setPosition(const glm::vec3& position) = 0; + + /// @brief Sets the orientation of the listener. + /// @param forward Forward direction of the listener. + /// @param up Up direction of the listener. + virtual void setOrientation(const glm::vec3& forward, const glm::vec3& up) = 0; + + protected: + Listener() = default; + }; } // namespace impl } // namespace cubos::core::al diff --git a/core/include/cubos/core/al/miniaudio_context.hpp b/core/include/cubos/core/al/miniaudio_context.hpp index 1263f60c5..630f74ff9 100644 --- a/core/include/cubos/core/al/miniaudio_context.hpp +++ b/core/include/cubos/core/al/miniaudio_context.hpp @@ -15,7 +15,8 @@ namespace cubos::core::al MiniaudioContext(); ~MiniaudioContext() override; - std::shared_ptr createDevice(const std::string& specifier) override; + std::shared_ptr createDevice(const std::string& specifier, unsigned int listenerCount) override; + Buffer createBuffer(const void* data, size_t dataSize) override; static void enumerateDevices(std::vector& devices); static std::string getDefaultDevice(); diff --git a/core/src/al/miniaudio_context.cpp b/core/src/al/miniaudio_context.cpp index 382c1820c..1b1abe316 100644 --- a/core/src/al/miniaudio_context.cpp +++ b/core/src/al/miniaudio_context.cpp @@ -3,6 +3,8 @@ #include #include +// TODO: settings.getInteger("audio ") + using namespace cubos::core::al; class MiniaudioBuffer : public impl::Buffer @@ -49,7 +51,6 @@ class MiniaudioSource : public impl::Source ~MiniaudioSource() override { ma_sound_uninit(&mSound); - ma_engine_uninit(&mEngine); } void setBuffer(Buffer buffer) override @@ -135,11 +136,46 @@ class MiniaudioSource : public impl::Source ma_engine mEngine; }; +class MiniaudioListener : public impl::Listener +{ +public: + MiniaudioListener(ma_engine& engine, unsigned int index) + : mEngine(engine) + , mIndex(index) + { + } + + ~MiniaudioListener() override + { + } + + void setPosition(const glm::vec3& position) override + { + ma_engine_listener_set_position(&mEngine, mIndex, position.x, position.y, position.z); + } + + void setOrientation(const glm::vec3& forward, const glm::vec3& up) override + { + ma_engine_listener_set_direction(&mEngine, mIndex, forward.x, forward.y, forward.z); + ma_engine_listener_set_world_up(&mEngine, mIndex, up.x, up.y, up.z); + } + + void setVelocity(const glm::vec3& velocity) override + { + ma_engine_listener_set_velocity(&mEngine, mIndex, velocity.x, velocity.y, velocity.z); + } + +private: + ma_engine& mEngine; + unsigned int mIndex; +}; + class MiniaudioDevice : public cubos::core::al::AudioDevice { public: - MiniaudioDevice(ma_context& context, const std::string& deviceName) + MiniaudioDevice(ma_context& context, const std::string& deviceName, ma_uint32 listenerCount) : mContext(context) + , mListeners() { ma_device_info* pPlaybackDeviceInfos; ma_uint32 playbackDeviceCount; @@ -169,6 +205,14 @@ class MiniaudioDevice : public cubos::core::al::AudioDevice } ma_engine_config engineConfig = ma_engine_config_init(); + + if (listenerCount > MA_ENGINE_MAX_LISTENERS) + { + CUBOS_FAIL("Maximum number of listeners is 4"); + return; + } + + engineConfig.listenerCount = listenerCount; engineConfig.pPlaybackDeviceID = deviceId; // Use the found device ID if (ma_engine_init(&engineConfig, &mEngine) != MA_SUCCESS) @@ -176,6 +220,12 @@ class MiniaudioDevice : public cubos::core::al::AudioDevice CUBOS_FAIL("Failed to initialize audio engine"); return; } + + mListeners.reserve(listenerCount); + for (ma_uint32 i = 0; i < listenerCount; ++i) + { + mListeners.emplace_back(std::make_shared(mEngine, i)); + } } ~MiniaudioDevice() override @@ -183,36 +233,26 @@ class MiniaudioDevice : public cubos::core::al::AudioDevice ma_device_uninit(&mDevice); } - Buffer createBuffer(const void* data, size_t dataSize) override - { - return std::make_shared(data, dataSize); - } - Source createSource() override { return std::make_shared(mEngine); } - void setListenerPosition(const glm::vec3& position, ma_uint32 listenerIndex) override + Listener listener(size_t index) override { - ma_engine_listener_set_position(&mEngine, listenerIndex, position.x, position.y, position.z); - } - - void setListenerOrientation(const glm::vec3& forward, const glm::vec3& up, ma_uint32 listenerIndex) override - { - ma_engine_listener_set_direction(&mEngine, listenerIndex, forward.x, forward.y, forward.z); - ma_engine_listener_set_world_up(&mEngine, listenerIndex, up.x, up.y, up.z); - } - - void setListenerVelocity(const glm::vec3& velocity, ma_uint32 listenerIndex) override - { - ma_engine_listener_set_velocity(&mEngine, listenerIndex, velocity.x, velocity.y, velocity.z); + if (index >= mListeners.size()) + { + CUBOS_ERROR("Listener index out of range"); + return nullptr; + } + return mListeners[index]; } private: ma_context mContext; ma_device mDevice; ma_engine mEngine; + std::vector> mListeners; }; MiniaudioContext::MiniaudioContext() @@ -299,7 +339,12 @@ void MiniaudioContext::enumerateDevices(std::vector& devices) } } -std::shared_ptr MiniaudioContext::createDevice(const std::string& specifier) +Buffer MiniaudioContext::createBuffer(const void* data, size_t dataSize) +{ + return std::make_shared(data, dataSize); +} + +std::shared_ptr MiniaudioContext::createDevice(const std::string& specifier, ma_uint32 listenerCount) { - return std::make_shared(mContext, specifier); + return std::make_shared(mContext, specifier, listenerCount); } diff --git a/engine/src/audio/audio.cpp b/engine/src/audio/audio.cpp index aa7cfc225..8629f7262 100644 --- a/engine/src/audio/audio.cpp +++ b/engine/src/audio/audio.cpp @@ -11,9 +11,6 @@ CUBOS_REFLECT_IMPL(cubos::engine::Audio) cubos::engine::Audio::Audio(std::shared_ptr context, core::memory::Stream& stream) { - // create audio device from context - auto device = context->createDevice("AudioDevice"); // TODO: does this make sense? - stream.seek(0, cubos::core::memory::SeekOrigin::End); size_t streamSize = stream.tell(); void* contents = operator new(sizeof(char) * streamSize); @@ -26,7 +23,7 @@ cubos::engine::Audio::Audio(std::shared_ptr c return; }; - mData = device->createBuffer(contents, (size_t)streamSize); + mData = context->createBuffer(contents, (size_t)streamSize); if (mData == nullptr) { CUBOS_ERROR("Couldn't create audio buffer");