|
|
|
|
#include "push_aulib_decoder.h"
|
|
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
#include <cstring>
|
|
|
|
|
#include <limits>
|
|
|
|
|
#include <mutex>
|
|
|
|
|
|
|
|
|
|
#include <aulib.h>
|
|
|
|
|
|
|
|
|
|
#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<SdlMutex> 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<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));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PushAulibDecoder::DiscardPendingSamples() noexcept
|
|
|
|
|
{
|
|
|
|
|
const std::lock_guard<SdlMutex> lock(queue_mutex_);
|
|
|
|
|
queue_ = std::queue<AudioQueueItem>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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<std::int16_t>::max() + 1.F;
|
|
|
|
|
for (unsigned i = 0; i < count; ++i) {
|
|
|
|
|
buf[i] = static_cast<float>(samples[i]) / Scale;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
unsigned remaining = len;
|
|
|
|
|
{
|
|
|
|
|
const std::lock_guard<SdlMutex> lock(queue_mutex_);
|
|
|
|
|
AudioQueueItem *item;
|
|
|
|
|
while ((item = Next()) != nullptr) {
|
|
|
|
|
if (static_cast<unsigned>(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<int>(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
|