Skip to content

Commit

Permalink
feat(audio): add audioPlugin
Browse files Browse the repository at this point in the history
  • Loading branch information
diogomsmiranda committed Nov 25, 2024
1 parent ce15432 commit e8ab1c6
Show file tree
Hide file tree
Showing 22 changed files with 595 additions and 44 deletions.
13 changes: 10 additions & 3 deletions core/include/cubos/core/al/audio_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ namespace cubos::core::al
/// @param listenerCount Number of audio listeners to be supported by the device.
/// @param specifier Identifier of the audio device.
/// @return Handle of the new device
virtual AudioDevice createDevice(unsigned int listenerCount, const std::string& specifier = "") = 0;
virtual AudioDevice createDevice(unsigned int listenerCount) = 0;

/// @brief Creates a new audio buffer.
/// @param data Data to be written to the buffer, either .wav, .mp3 or .flac.
Expand Down Expand Up @@ -148,6 +148,12 @@ namespace cubos::core::al
/// @brief Plays the source.
virtual void play() = 0;

/// @brief Stops the source, restarting buffer to position 0.
virtual void stop() = 0;

/// @brief Pauses the source, allowing to be played from the moment it was paused.
virtual void pause() = 0;

protected:
Source() = default;
};
Expand Down Expand Up @@ -188,8 +194,9 @@ namespace cubos::core::al
/// @return Handle of the new source.
virtual std::shared_ptr<impl::Source> createSource() = 0;

/// @brief Creates a new audio listener.
/// @return Handle of the new listener.
/// @brief Gets the listener with the specific index.
/// @param index Index of the listener.
/// @return Handle of the listener.
virtual std::shared_ptr<impl::Listener> listener(size_t index) = 0;

protected:
Expand Down
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 @@ -17,10 +17,11 @@ namespace cubos::core::al
MiniaudioContext();
~MiniaudioContext() override;

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

private:
#ifdef CUBOS_CORE_MINIAUDIO
Expand Down
81 changes: 41 additions & 40 deletions core/src/al/miniaudio_context.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#define MINIAUDIO_IMPLEMENTATION
#include <cstring>

#include <cubos/core/al/miniaudio_context.hpp>
#include <cubos/core/reflection/external/string.hpp>
#include <cubos/core/tel/logging.hpp>
Expand All @@ -11,8 +13,11 @@ class MiniaudioBuffer : public impl::Buffer
public:
ma_decoder decoder;

MiniaudioBuffer(const void* data, size_t dataSize)
MiniaudioBuffer(const void* srcData, size_t dataSize)
{
data = operator new(dataSize);
std::memcpy(data, srcData, dataSize);

if (ma_decoder_init_memory(data, dataSize, nullptr, &decoder) != MA_SUCCESS)
{
CUBOS_ERROR("Failed to initialize Decoder from data");
Expand All @@ -26,6 +31,7 @@ class MiniaudioBuffer : public impl::Buffer
~MiniaudioBuffer() override
{
ma_decoder_uninit(&decoder);
operator delete(data);
}

float length() override
Expand All @@ -50,6 +56,7 @@ class MiniaudioBuffer : public impl::Buffer

private:
bool mValid = false;
void* data;
};

class MiniaudioListener : public impl::Listener
Expand Down Expand Up @@ -180,54 +187,44 @@ class MiniaudioSource : public impl::Source
}
}

private:
ma_sound mSound;
ma_engine& mEngine;
};

class MiniaudioDevice : public impl::AudioDevice
{
public:
MiniaudioDevice(ma_context& context, const std::string& deviceName, ma_uint32 listenerCount)
: mContext(context)
void stop() override
{
ma_device_info* pPlaybackDeviceInfos;
ma_uint32 playbackDeviceCount;
ma_result result =
ma_context_get_devices(&mContext, &pPlaybackDeviceInfos, &playbackDeviceCount, nullptr, nullptr);

if (result != MA_SUCCESS)
if (ma_sound_stop(&mSound) != MA_SUCCESS)
{
CUBOS_FAIL("Failed to enumerate audio devices");
CUBOS_ERROR("Failed to stop sound");
return;
}
ma_sound_seek_to_pcm_frame(&mSound, 0);
}

ma_device_id* deviceId = nullptr;
for (ma_uint32 i = 0; i < playbackDeviceCount; i++)
{
if (deviceName == pPlaybackDeviceInfos[i].name)
{
deviceId = &pPlaybackDeviceInfos[i].id;
break;
}
}

if (deviceId == nullptr)
void pause() override
{
if (ma_sound_stop(&mSound) != MA_SUCCESS)
{
CUBOS_FAIL("Audio device '{}' not found", deviceName);
CUBOS_ERROR("Failed to pause sound");
return;
}
}

ma_engine_config engineConfig = ma_engine_config_init();
private:
ma_sound mSound;
ma_engine& mEngine;
};

class MiniaudioDevice : public impl::AudioDevice
{
public:
MiniaudioDevice(ma_uint32 listenerCount)
{
if (listenerCount > MA_ENGINE_MAX_LISTENERS)
{
CUBOS_FAIL("Maximum number of listeners is 4");
return;
}

ma_engine_config engineConfig = ma_engine_config_init();

engineConfig.listenerCount = listenerCount;
engineConfig.pPlaybackDeviceID = deviceId; // Use the found device ID

if (ma_engine_init(&engineConfig, &mEngine) != MA_SUCCESS)
{
Expand All @@ -246,6 +243,7 @@ class MiniaudioDevice : public impl::AudioDevice

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

Expand All @@ -270,7 +268,6 @@ class MiniaudioDevice : public impl::AudioDevice
}

private:
ma_context mContext;
ma_device mDevice;
ma_engine mEngine;
std::vector<std::shared_ptr<MiniaudioListener>> mListeners;
Expand Down Expand Up @@ -308,8 +305,6 @@ std::string MiniaudioContext::getDefaultDevice()
return "";
}

ma_context_uninit(&mContext);

for (ma_uint32 i = 0; i < playbackDeviceCount; i++)
{
if (pPlaybackDeviceInfos[i].isDefault != 0u)
Expand All @@ -325,6 +320,15 @@ std::string MiniaudioContext::getDefaultDevice()
#endif
}

int MiniaudioContext::getMaxListenerCount()
{
#ifdef CUBOS_CORE_MINIAUDIO
return MA_ENGINE_MAX_LISTENERS;
#else
return 0;
#endif
}

void MiniaudioContext::enumerateDevices(std::vector<std::string>& devices)
{
#ifdef CUBOS_CORE_MINIAUDIO
Expand All @@ -339,8 +343,6 @@ void MiniaudioContext::enumerateDevices(std::vector<std::string>& devices)
return;
}

ma_context_uninit(&mContext);

devices.reserve(playbackDeviceCount);

for (ma_uint32 i = 0; i < playbackDeviceCount; i++)
Expand Down Expand Up @@ -375,10 +377,10 @@ Buffer MiniaudioContext::createBuffer(const void* data, size_t dataSize)
#endif
}

AudioDevice MiniaudioContext::createDevice(unsigned int listenerCount, const std::string& specifier)
AudioDevice MiniaudioContext::createDevice(unsigned int listenerCount)
{
#ifdef CUBOS_CORE_MINIAUDIO
auto device = std::make_shared<MiniaudioDevice>(mContext, specifier, listenerCount);
auto device = std::make_shared<MiniaudioDevice>(listenerCount);
if (!device->isValid())
{
CUBOS_ERROR("Failed to create MiniaudioDevice");
Expand All @@ -388,7 +390,6 @@ AudioDevice MiniaudioContext::createDevice(unsigned int listenerCount, const std
return device;
#else
(void)listenerCount;
(void)specifier;
return nullptr;
#endif
}
9 changes: 9 additions & 0 deletions engine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ set(CUBOS_ENGINE_SOURCE
"src/utils/free_camera/plugin.cpp"
"src/utils/free_camera/controller.cpp"

"src/audio/plugin.cpp"
"src/audio/source.cpp"
"src/audio/source_impl.cpp"
"src/audio/listener.cpp"
"src/audio/listener_impl.cpp"
"src/audio/pause.cpp"
"src/audio/play.cpp"
"src/audio/stop.cpp"

"src/audio/audio.cpp"
"src/audio/bridge.cpp"

Expand Down
24 changes: 24 additions & 0 deletions engine/include/cubos/engine/audio/listener.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/// @file
/// @brief Component @ref cubos::engine::AudioListener.
/// @ingroup audio-plugin

#pragma once

#include <map>

#include <cubos/core/al/audio_context.hpp>
#include <cubos/core/reflection/reflect.hpp>

#include <cubos/engine/api.hpp>

namespace cubos::engine
{
/// @brief Component which adds an AudioListener to the entitiy
/// @ingroup audio-plugin
struct CUBOS_ENGINE_API AudioListener
{
CUBOS_REFLECT;

bool active{false};
};
} // namespace cubos::engine
22 changes: 22 additions & 0 deletions engine/include/cubos/engine/audio/pause.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/// @file
/// @brief Component @ref cubos::engine::AudioPause.
/// @ingroup audio-plugin

#pragma once

#include <glm/glm.hpp>

#include <cubos/core/reflection/reflect.hpp>

#include <cubos/engine/api.hpp>
#include <cubos/engine/prelude.hpp>

namespace cubos::engine
{
/// @brief Component which adds an AudioSource to the entitiy
/// @ingroup audio-plugin
struct CUBOS_ENGINE_API AudioPause
{
CUBOS_REFLECT;
};
} // namespace cubos::engine
22 changes: 22 additions & 0 deletions engine/include/cubos/engine/audio/play.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/// @file
/// @brief Component @ref cubos::engine::AudioPlay.
/// @ingroup audio-plugin

#pragma once

#include <glm/glm.hpp>

#include <cubos/core/reflection/reflect.hpp>

#include <cubos/engine/api.hpp>
#include <cubos/engine/prelude.hpp>

namespace cubos::engine
{
/// @brief Component which adds an AudioSource to the entitiy
/// @ingroup audio-plugin
struct CUBOS_ENGINE_API AudioPlay
{
CUBOS_REFLECT;
};
} // namespace cubos::engine
40 changes: 40 additions & 0 deletions engine/include/cubos/engine/audio/plugin.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/// @dir
/// @brief @ref audio-plugin plugin directory.

/// @file
/// @brief Plugin entry point.
/// @ingroup audio-plugin

#pragma once

#include <cubos/engine/audio/audio.hpp>
#include <cubos/engine/audio/listener.hpp>
#include <cubos/engine/audio/pause.hpp>
#include <cubos/engine/audio/play.hpp>
#include <cubos/engine/audio/source.hpp>
#include <cubos/engine/audio/stop.hpp>
#include <cubos/engine/prelude.hpp>

namespace cubos::engine
{
/// @defgroup audio-plugin Audio
/// @ingroup engine
/// @brief Adds audio to @b Cubos
///
/// ## Settings
/// - `audio.listener.count` - number of listeners per audio device (default: `4`).
///
/// ## Dependencies
/// - @ref settings-plugin

/// @brief Initializes the audio context (after @ref settingsTag).
CUBOS_ENGINE_API extern Tag audioInitTag;

/// @brief Initializes the audio state (after @ref audioInitTag).
CUBOS_ENGINE_API extern Tag audioStateInitTag;

/// @brief Plugin entry function.
/// @param cubos @b Cubos main class.
/// @ingroup assets-plugin
CUBOS_ENGINE_API void audioPlugin(Cubos& cubos);
} // namespace cubos::engine
41 changes: 41 additions & 0 deletions engine/include/cubos/engine/audio/source.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/// @file
/// @brief Component @ref cubos::engine::AudioSource.
/// @ingroup audio-plugin

#pragma once

#include <glm/glm.hpp>

#include <cubos/core/al/audio_context.hpp>
#include <cubos/core/reflection/reflect.hpp>

#include <cubos/engine/api.hpp>
#include <cubos/engine/audio/audio.hpp>
#include <cubos/engine/prelude.hpp>

namespace cubos::engine
{
/// @brief Component which adds an AudioSource to the entitiy
/// @ingroup audio-plugin
struct CUBOS_ENGINE_API AudioSource
{
CUBOS_REFLECT;

bool playing{false};
bool looping{false};
bool stop{false};

float gain{1.0f};
float pitch{1.0f};
float maxDistance{FLT_MAX};
float minDistance{1.0f};

float innerConeAngle{360.0f};
float outerConeAngle{360.0f};
float outerConeGain{1.0f};

glm::vec3 coneDirection;

Asset<Audio> sound{};
};
} // namespace cubos::engine
Loading

0 comments on commit e8ab1c6

Please sign in to comment.