Skip to content

Commit

Permalink
feat(audio): Add AudioListener and MiniaudioListener
Browse files Browse the repository at this point in the history
  • Loading branch information
diogomsmiranda committed Oct 22, 2024
1 parent 20a2545 commit 124311b
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 50 deletions.
62 changes: 39 additions & 23 deletions core/include/cubos/core/al/audio_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace cubos::core::al
{
class Buffer;
class Source;
class Listener;
} // namespace impl

/// @brief Handle to an audio buffer.
Expand All @@ -32,6 +33,12 @@ namespace cubos::core::al
/// @ingroup core-al
using Source = std::shared_ptr<impl::Source>;

/// @brief Handle to an audio listener.
/// @see impl::Listener - audio listener interface.
/// @see AudioDevice::createListener()
/// @ingroup core-al
using Listener = std::shared_ptr<impl::Listener>;

/// @brief Audio device interface used to wrap low-level audio rendering APIs.
class CUBOS_CORE_API AudioDevice
{
Expand All @@ -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;
Expand All @@ -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<AudioDevice> createDevice(const std::string& specifier) = 0;
virtual std::shared_ptr<AudioDevice> 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.
Expand Down Expand Up @@ -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
3 changes: 2 additions & 1 deletion core/include/cubos/core/al/miniaudio_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ namespace cubos::core::al
MiniaudioContext();
~MiniaudioContext() override;

std::shared_ptr<AudioDevice> createDevice(const std::string& specifier) override;
std::shared_ptr<AudioDevice> createDevice(const std::string& specifier, unsigned int listenerCount) override;
Buffer createBuffer(const void* data, size_t dataSize) override;

static void enumerateDevices(std::vector<std::string>& devices);
static std::string getDefaultDevice();
Expand Down
89 changes: 67 additions & 22 deletions core/src/al/miniaudio_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include <cubos/core/log.hpp>
#include <cubos/core/reflection/external/string.hpp>

// TODO: settings.getInteger("audio ")

using namespace cubos::core::al;

class MiniaudioBuffer : public impl::Buffer
Expand Down Expand Up @@ -49,7 +51,6 @@ class MiniaudioSource : public impl::Source
~MiniaudioSource() override
{
ma_sound_uninit(&mSound);
ma_engine_uninit(&mEngine);
}

void setBuffer(Buffer buffer) override
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -169,50 +205,54 @@ 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)
{
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<MiniaudioListener>(mEngine, i));
}
}

~MiniaudioDevice() override
{
ma_device_uninit(&mDevice);
}

Buffer createBuffer(const void* data, size_t dataSize) override
{
return std::make_shared<MiniaudioBuffer>(data, dataSize);
}

Source createSource() override
{
return std::make_shared<MiniaudioSource>(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<std::shared_ptr<MiniaudioListener>> mListeners;
};

MiniaudioContext::MiniaudioContext()
Expand Down Expand Up @@ -299,7 +339,12 @@ void MiniaudioContext::enumerateDevices(std::vector<std::string>& devices)
}
}

std::shared_ptr<AudioDevice> MiniaudioContext::createDevice(const std::string& specifier)
Buffer MiniaudioContext::createBuffer(const void* data, size_t dataSize)
{
return std::make_shared<MiniaudioBuffer>(data, dataSize);
}

std::shared_ptr<AudioDevice> MiniaudioContext::createDevice(const std::string& specifier, ma_uint32 listenerCount)
{
return std::make_shared<MiniaudioDevice>(mContext, specifier);
return std::make_shared<MiniaudioDevice>(mContext, specifier, listenerCount);
}
5 changes: 1 addition & 4 deletions engine/src/audio/audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ CUBOS_REFLECT_IMPL(cubos::engine::Audio)

cubos::engine::Audio::Audio(std::shared_ptr<cubos::core::al::MiniaudioContext> 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);
Expand All @@ -26,7 +23,7 @@ cubos::engine::Audio::Audio(std::shared_ptr<cubos::core::al::MiniaudioContext> 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");
Expand Down

0 comments on commit 124311b

Please sign in to comment.