From 2c5987963033ba4164c76993e458828d6ec6b82a Mon Sep 17 00:00:00 2001 From: lisyarus Date: Fri, 7 Oct 2022 23:40:03 +0300 Subject: [PATCH] Support loading WAV audio --- libs/audio/include/psemek/audio/engine.hpp | 2 +- libs/audio/source/engine.cpp | 61 +++++++++++++++++++--- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/libs/audio/include/psemek/audio/engine.hpp b/libs/audio/include/psemek/audio/engine.hpp index ec4b3cf6..e955a0db 100644 --- a/libs/audio/include/psemek/audio/engine.hpp +++ b/libs/audio/include/psemek/audio/engine.hpp @@ -21,8 +21,8 @@ namespace psemek::audio engine(); ~engine(); - track_ptr load_raw(float const * data, std::size_t sample_count, bool copy = true); track_ptr load_raw(util::span data, bool copy = true); + track_ptr load_wav(util::span data); channel_ptr output(); diff --git a/libs/audio/source/engine.cpp b/libs/audio/source/engine.cpp index 3fc4e61d..92432275 100644 --- a/libs/audio/source/engine.cpp +++ b/libs/audio/source/engine.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include @@ -77,6 +79,41 @@ namespace psemek::audio std::shared_ptr data_; }; + std::vector convert_audio(SDL_AudioSpec const & spec, std::uint8_t * samples, std::size_t length) + { + if (spec.channels > 2) + throw std::runtime_error(util::to_string("Can't convert audio with ", static_cast(spec.channels), " channels")); + + if (spec.freq != 44100) + throw std::runtime_error(util::to_string("Can't convert audio with frequency ", spec.freq)); + + if (spec.format != AUDIO_S16SYS) + throw std::runtime_error(util::to_string("Can't convert audio with format ", spec.format)); + + auto p = reinterpret_cast(samples); + + std::vector result; + + if (spec.channels == 1) + { + result.resize(length); + for (std::size_t i = 0; i < length / 2; ++i) + { + float v = (p[i] * 2.f + 1.f) / 65536.f; + result[2 * i + 0] = v; + result[2 * i + 1] = v; + } + } + else + { + result.resize(length / 2); + for (std::size_t i = 0; i < length / 2; ++i) + result[i] = (p[i] * 2.f + 1.f) / 65536.f; + } + + return result; + } + } struct engine::impl @@ -154,26 +191,38 @@ namespace psemek::audio engine::~engine() = default; - track_ptr engine::load_raw(float const * data, std::size_t sample_count, bool copy) + track_ptr engine::load_raw(util::span data, bool copy) { - if ((sample_count % 2) != 0) + if ((data.size() % 2) != 0) throw std::runtime_error("bad sample count"); auto tdata = std::make_shared(); if (copy) { - tdata->storage.assign(data, data + sample_count); + tdata->storage.assign(data.begin(), data.end()); tdata->samples = tdata->storage; } else - tdata->samples = {data, data + sample_count}; + tdata->samples = data; return std::make_shared(std::move(tdata)); } - track_ptr engine::load_raw(util::span data, bool copy) + track_ptr engine::load_wav(util::span data) { - return load_raw(data.data(), data.size(), copy); + SDL_AudioSpec spec; + std::uint8_t * samples; + std::uint32_t length; + if (!SDL_LoadWAV_RW(SDL_RWFromConstMem(data.data(), data.size()), 1, &spec, &samples, &length)) + sdl2::fail("SDL_LoadWAV_RW failed:"); + + util::at_scope_exit release_samples([samples]{ SDL_FreeWAV(samples); }); + + auto tdata = std::make_shared(); + tdata->storage = convert_audio(spec, samples, length); + tdata->samples = tdata->storage; + + return std::make_shared(std::move(tdata)); } channel_ptr engine::output()