diff --git a/CMakeLists.txt b/CMakeLists.txt index bfa4be7..4d98e2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ project(ChargeAudio VERSION 1.0) set(CMAKE_CXX_STANDARD 17) set(CMAKE_EXPORT_COMPILE_COMMANDS 1) set(CMAKE_MODULE_PATH "modules/" ${CMAKE_MODULE_PATH}) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-subobject-linkage") if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fsanitize=address") endif() diff --git a/src/ChargeAudio.hpp b/src/ChargeAudio.hpp index 3eead2c..e73a496 100644 --- a/src/ChargeAudio.hpp +++ b/src/ChargeAudio.hpp @@ -1,26 +1,23 @@ #ifndef CHARGE_AUDIO_BASE_H #define CHARGE_AUDIO_BASE_H +#include "miniaudio/miniaudio.h" + #include -#include #include -#include -#include +#include + #include #include namespace ChargeAudio { -namespace _ma { -#include "miniaudio/miniaudio.h" -} using namespace Corrade; -using namespace _ma; typedef Containers::Pointer SoundContainer; typedef Containers::Pointer ListenerContainer; class Sound { public: enum class SoundState { Idle, Playing, Paused, Finished }; - + enum class SoundType { FromFile, RawPCM }; // No copying Sound(const Sound &) = delete; Sound &operator=(const Sound &) = delete; @@ -35,6 +32,8 @@ public: void Reset(); const SoundState GetState(); + const SoundType GetSoundType(); + const float GetPlaybackTime(); bool SetPlaybackTime(float time); const float GetDuration(); @@ -45,13 +44,15 @@ public: private: Sound(class Engine *engine, std::function setupFunction, - std::string additionalErrorMessage = ""); + SoundType type, std::string additionalErrorMessage = ""); static void onSoundFinish(void *customData, ma_sound *); class Engine *baseEngine; ma_sound maSound; ma_sound_config maConfig; + ma_pcm_rb maRingBuffer; SoundState state = SoundState::Idle; + SoundType type; friend class Engine; }; @@ -78,7 +79,7 @@ private: class Engine { public: - Engine(); + Engine(uint32_t sampleRate = 44100, uint32_t channels = 2); // No copying Engine(const Engine &) = delete; @@ -91,15 +92,21 @@ public: ~Engine(); // Creating tools + SoundContainer CreateSound(int bufferLengthInSeconds); SoundContainer CreateSound(std::string filepath, bool streamFile = false); ListenerContainer CreateListener(); void SetVolume(float value); const float GetVolume(); + uint32_t GetSampleRate(); + uint32_t GetChannelCount(); + private: ma_engine maEngine; + ma_engine_config maConfig; ma_result maResponse; + ma_decoder maStero; ma_uint64 listenerCounter = 0; friend class Listener; friend class Sound; diff --git a/src/Engine.cpp b/src/Engine.cpp index baaf4b2..0981963 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -1,19 +1,19 @@ #include "ChargeAudio.hpp" -#include -#include -#include -#include -#include +#include "miniaudio/miniaudio.h" -#include +#include +#include #include -#include using namespace ChargeAudio; using namespace Corrade; -Engine::Engine() { - if ((maResponse = ma_engine_init(NULL, &maEngine)) != MA_SUCCESS) { +Engine::Engine(uint32_t sampleRate, uint32_t channels) { + maConfig = ma_engine_config_init(); + maConfig.sampleRate = sampleRate; + maConfig.channels = channels; + + if ((maResponse = ma_engine_init(&maConfig, &maEngine)) != MA_SUCCESS) { Utility::Error{} << "Could not init miniaudio (" << maResponse << ")"; throw new std::runtime_error( "Failed to init miniaudio engine. Check STDERR for more info."); @@ -22,6 +22,27 @@ Engine::Engine() { Engine::~Engine() { ma_engine_uninit(&maEngine); } +uint32_t Engine::GetSampleRate() { return maEngine.sampleRate; } +uint32_t Engine::GetChannelCount() { return ma_engine_get_channels(&maEngine); } + +SoundContainer Engine::CreateSound(int bufferLengthInSeconds) { + return SoundContainer(new Sound( + this, + [length = bufferLengthInSeconds, channels = GetChannelCount(), + sampleRate = GetSampleRate()](Sound *sound) { + ma_result result = ma_pcm_rb_init( + ma_format_s32, channels, sampleRate * channels * length, nullptr, + nullptr, &sound->maRingBuffer); + if (result != MA_SUCCESS) { + Utility::Error{} << "Failed to create a new ring buffer!" << " (" + << result << ")"; + throw new std::runtime_error("Failed to create a new ring buffer! " + "Check STDERR for more info."); + } + }, + Sound::SoundType::RawPCM, "Failed to create the sound from the data: ")); +} + SoundContainer Engine::CreateSound(const std::string filepath, bool streamFile) { return SoundContainer(new Sound( @@ -30,6 +51,7 @@ SoundContainer Engine::CreateSound(const std::string filepath, sound->maConfig.pFilePath = filepath.c_str(); sound->maConfig.flags = (streamFile ? MA_SOUND_FLAG_STREAM : 0); }, + Sound::SoundType::FromFile, "Failed to create the sound from the file: " + filepath)); } diff --git a/src/Listener.cpp b/src/Listener.cpp index 8f886ef..d531548 100644 --- a/src/Listener.cpp +++ b/src/Listener.cpp @@ -1,6 +1,4 @@ #include "ChargeAudio.hpp" -#include -#include using namespace ChargeAudio; diff --git a/src/Sound.cpp b/src/Sound.cpp index b8d2023..c93eba8 100644 --- a/src/Sound.cpp +++ b/src/Sound.cpp @@ -1,14 +1,11 @@ #include "ChargeAudio.hpp" -#include -#include -#include #include #include using namespace ChargeAudio; Sound::Sound(Engine *engine, std::function setupFunction, - std::string additionalErrorMessage) + SoundType soundType, std::string additionalErrorMessage) : baseEngine(engine) { maConfig = ma_sound_config_init_2(&baseEngine->maEngine); maConfig.endCallback = Sound::onSoundFinish; @@ -23,10 +20,16 @@ Sound::Sound(Engine *engine, std::function setupFunction, "Failed to create a new sound. Check STDERR for more info.\n" + additionalErrorMessage); } + type = soundType; +} + +Sound::~Sound() { + ma_pcm_rb_uninit(&maRingBuffer); + ma_sound_uninit(&maSound); } -Sound::~Sound() { ma_sound_uninit(&maSound); } const Sound::SoundState Sound::GetState() { return state; } +const Sound::SoundType Sound::GetSoundType() { return type; } const float Sound::GetDuration() { float time;