Browse Source

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.
pull/6474/head
Gleb Mazovetskiy 3 years ago
parent
commit
ecdf7380a8
  1. 56
      Source/utils/push_aulib_decoder.cpp
  2. 29
      Source/utils/push_aulib_decoder.h

56
Source/utils/push_aulib_decoder.cpp

@ -5,6 +5,8 @@
#include <cstring>
#include <limits>
#include <mutex>
#include <type_traits>
#include <variant>
#include <aulib.h>
@ -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<int16_t>::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<SdlMutex> lock(queue_mutex_);
queue_.push(std::move(item));
constexpr float Factor = 2.0 / std::numeric_limits<uint8_t>::max();
return (sample * Factor) - 1;
}
void PushAulibDecoder::PushSamples(const std::uint8_t *data, unsigned size) noexcept
template <typename T>
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<std::int16_t>((data[i] - Center) * Scale);
item.len = size;
item.pos = item.data.get();
const std::lock_guard<SdlMutex> 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<SdlMutex> lock(queue_mutex_);
const auto lock = std::lock_guard(queue_mutex_);
queue_ = std::queue<AudioQueueItem>();
}
@ -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<std::int16_t>::max() + 1.F;
for (unsigned i = 0; i < count; ++i) {
buf[i] = static_cast<float>(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<SdlMutex> lock(queue_mutex_);
const auto lock = std::lock_guard(queue_mutex_);
AudioQueueItem *item;
while ((item = Next()) != nullptr) {
if (static_cast<unsigned>(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<int>(item->len);
queue_.pop();

29
Source/utils/push_aulib_decoder.h

@ -2,8 +2,11 @@
#include <chrono>
#include <cstdint>
#include <cstring>
#include <memory>
#include <mutex>
#include <queue>
#include <variant>
#include <Aulib/Decoder.h>
#include <SDL_mutex.h>
@ -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 <typename T>
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<std::int16_t[]> data;
std::variant<
std::unique_ptr<int16_t[]>,
std::unique_ptr<uint8_t[]>>
data;
unsigned len;
const std::int16_t *pos;
unsigned pos;
template <typename T>
AudioQueueItem(const T *data, unsigned size)
: data { std::unique_ptr<T[]> { new T[size] } }
, len { size }
, pos { 0 }
{
std::memcpy(std::get<std::unique_ptr<T[]>>(this->data).get(), data, size * sizeof(T));
}
};
const int numChannels_;

Loading…
Cancel
Save