You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

109 lines
2.4 KiB

#include "push_aulib_decoder.h"
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <limits>
#include <mutex>
#include <type_traits>
#include <variant>
#include <aulib.h>
#include "appfat.h"
namespace devilution {
namespace {
float SampleToFloat(int16_t sample)
{
constexpr float Factor = 1.0F / (std::numeric_limits<int16_t>::max() + 1);
return sample * Factor;
}
float SampleToFloat(uint8_t sample)
{
constexpr float Factor = 2.0F / std::numeric_limits<uint8_t>::max();
return (sample * Factor) - 1;
}
template <typename T>
void ToFloats(const T *samples, float *out, unsigned count)
{
std::transform(samples, samples + count, out, [](T sample) {
return SampleToFloat(sample);
});
}
} // namespace
void PushAulibDecoder::DiscardPendingSamples() noexcept
{
const auto lock = std::lock_guard(queue_mutex_);
queue_ = std::queue<AudioQueueItem>();
}
bool PushAulibDecoder::open([[maybe_unused]] SDL_IOStream *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;
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 auto lock = std::lock_guard(queue_mutex_);
AudioQueueItem *item;
while ((item = Next()) != nullptr) {
if (static_cast<unsigned>(remaining) <= item->len) {
WriteFloats(*item, buf, remaining);
item->pos += remaining;
item->len -= remaining;
if (item->len == 0)
queue_.pop();
return len;
}
WriteFloats(*item, buf, 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