#include "push_aulib_decoder.h" #include #include #include #include #include #include "appfat.h" namespace devilution { void PushAulibDecoder::PushSamples(const std::int16_t *data, unsigned size) noexcept { 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)); } void PushAulibDecoder::PushSamples(const std::uint8_t *data, unsigned size) noexcept { 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)); } void PushAulibDecoder::DiscardPendingSamples() noexcept { const std::lock_guard lock(queue_mutex_); queue_ = std::queue(); } bool PushAulibDecoder::open([[maybe_unused]] SDL_RWops *rwops) { assert(rwops == nullptr); return true; } bool PushAulibDecoder::rewind() { return false; } std::chrono::microseconds PushAulibDecoder::duration() const { return {}; } bool PushAulibDecoder::seekToTime([[maybe_unused]] std::chrono::microseconds pos) { return false; } 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; for (unsigned i = 0; i < count; ++i) { buf[i] = static_cast(samples[i]) / Scale; } }; unsigned remaining = len; { const std::lock_guard lock(queue_mutex_); AudioQueueItem *item; while ((item = Next()) != nullptr) { if (static_cast(remaining) <= item->len) { writeFloats(item->pos, remaining); item->pos += remaining; item->len -= remaining; return len; } writeFloats(item->pos, item->len); buf += item->len; remaining -= static_cast(item->len); queue_.pop(); } } std::memset(buf, 0, remaining * sizeof(buf[0])); return len; } PushAulibDecoder::AudioQueueItem *PushAulibDecoder::Next() { while (!queue_.empty() && queue_.front().len == 0) queue_.pop(); if (queue_.empty()) return nullptr; return &queue_.front(); } } // namespace devilution