From ecdf7380a8f3aa7f4c551f87cc6afd6ef463d1fd Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Tue, 15 Aug 2023 16:16:40 +0900 Subject: [PATCH] PushAulibDecoder: Support 8-bit samples directly Previously, we converted 8-bit audio to 16-bit, and then to float. Eliminates the 8->16 conversion step. Also optimizes the 16-bit conversion a bit. --- Source/utils/push_aulib_decoder.cpp | 56 ++++++++++++++--------------- Source/utils/push_aulib_decoder.h | 29 ++++++++++++--- 2 files changed, 53 insertions(+), 32 deletions(-) diff --git a/Source/utils/push_aulib_decoder.cpp b/Source/utils/push_aulib_decoder.cpp index 575394061..ea4bea2ed 100644 --- a/Source/utils/push_aulib_decoder.cpp +++ b/Source/utils/push_aulib_decoder.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include @@ -12,34 +14,33 @@ namespace devilution { -void PushAulibDecoder::PushSamples(const std::int16_t *data, unsigned size) noexcept +namespace { + +float SampleToFloat(int16_t sample) +{ + constexpr float Factor = 1.0 / (std::numeric_limits::max() + 1); + return sample * Factor; +} + +float SampleToFloat(uint8_t sample) { - AudioQueueItem item; - item.data.reset(new std::int16_t[size]); - std::memcpy(item.data.get(), data, size * sizeof(data[0])); - item.len = size; - item.pos = item.data.get(); - const std::lock_guard lock(queue_mutex_); - queue_.push(std::move(item)); + constexpr float Factor = 2.0 / std::numeric_limits::max(); + return (sample * Factor) - 1; } -void PushAulibDecoder::PushSamples(const std::uint8_t *data, unsigned size) noexcept +template +void ToFloats(const T *samples, float *out, unsigned count) { - AudioQueueItem item; - item.data.reset(new std::int16_t[size]); - constexpr std::int16_t Center = 128; - constexpr std::int16_t Scale = 256; - for (unsigned i = 0; i < size; ++i) - item.data[i] = static_cast((data[i] - Center) * Scale); - item.len = size; - item.pos = item.data.get(); - const std::lock_guard lock(queue_mutex_); - queue_.push(std::move(item)); + std::transform(samples, samples + count, out, [](T sample) { + return SampleToFloat(sample); + }); } +} // namespace + void PushAulibDecoder::DiscardPendingSamples() noexcept { - const std::lock_guard lock(queue_mutex_); + const auto lock = std::lock_guard(queue_mutex_); queue_ = std::queue(); } @@ -68,26 +69,25 @@ int PushAulibDecoder::doDecoding(float buf[], int len, bool &callAgain) { callAgain = false; - const auto writeFloats = [&buf](const std::int16_t *samples, unsigned count) { - constexpr float Scale = std::numeric_limits::max() + 1.F; - for (unsigned i = 0; i < count; ++i) { - buf[i] = static_cast(samples[i]) / Scale; - } + constexpr auto WriteFloats = [](PushAulibDecoder::AudioQueueItem &item, float *out, unsigned count) { + std::visit([&](const auto &samples) { ToFloats(&samples[item.pos], out, count); }, item.data); }; unsigned remaining = len; { - const std::lock_guard lock(queue_mutex_); + const auto lock = std::lock_guard(queue_mutex_); AudioQueueItem *item; while ((item = Next()) != nullptr) { if (static_cast(remaining) <= item->len) { - writeFloats(item->pos, remaining); + WriteFloats(*item, buf, remaining); item->pos += remaining; item->len -= remaining; + if (item->len == 0) + queue_.pop(); return len; } - writeFloats(item->pos, item->len); + WriteFloats(*item, buf, item->len); buf += item->len; remaining -= static_cast(item->len); queue_.pop(); diff --git a/Source/utils/push_aulib_decoder.h b/Source/utils/push_aulib_decoder.h index 8943dd812..b227d0090 100644 --- a/Source/utils/push_aulib_decoder.h +++ b/Source/utils/push_aulib_decoder.h @@ -2,8 +2,11 @@ #include #include +#include #include +#include #include +#include #include #include @@ -23,8 +26,14 @@ public: { } - void PushSamples(const std::uint8_t *data, unsigned size) noexcept; - void PushSamples(const std::int16_t *data, unsigned size) noexcept; + template + void PushSamples(const T *data, unsigned size) noexcept + { + AudioQueueItem item { data, size }; + const auto lock = std::lock_guard(queue_mutex_); + queue_.push(std::move(item)); + } + void DiscardPendingSamples() noexcept; bool open(SDL_RWops *rwops) override; @@ -48,9 +57,21 @@ protected: private: struct AudioQueueItem { - std::unique_ptr data; + std::variant< + std::unique_ptr, + std::unique_ptr> + data; unsigned len; - const std::int16_t *pos; + unsigned pos; + + template + AudioQueueItem(const T *data, unsigned size) + : data { std::unique_ptr { new T[size] } } + , len { size } + , pos { 0 } + { + std::memcpy(std::get>(this->data).get(), data, size * sizeof(T)); + } }; const int numChannels_;