skyline/app/src/main/cpp/skyline/audio/adpcm_decoder.cpp

53 lines
1.7 KiB
C++

// SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#include "common.h"
#include "adpcm_decoder.h"
namespace skyline::audio {
AdpcmDecoder::AdpcmDecoder(std::vector<std::array<i16, 2>> coefficients) : coefficients(std::move(coefficients)) {}
std::vector<i16> AdpcmDecoder::Decode(span<u8> adpcmData) {
constexpr size_t BytesPerFrame{0x8};
constexpr size_t SamplesPerFrame{0xE};
size_t remainingSamples{(adpcmData.size() / BytesPerFrame) * SamplesPerFrame};
std::vector<i16> output;
output.reserve(remainingSamples);
size_t inputOffset{};
while (inputOffset < adpcmData.size()) {
FrameHeader header{adpcmData[inputOffset++]};
size_t frameSamples{std::min(SamplesPerFrame, remainingSamples)};
i32 ctx{};
for (size_t index{}; index < frameSamples; index++) {
i32 sample{};
if (index & 1) {
sample = (ctx << 28) >> 28;
} else {
ctx = adpcmData[inputOffset++];
sample = (ctx << 24) >> 28;
}
i32 prediction{history[0] * coefficients[header.coefficientIndex][0] + history[1] * coefficients[header.coefficientIndex][1]};
sample = (sample * (0x800 << header.scale) + prediction + 0x400) >> 11;
auto saturated{audio::Saturate<i16, i32>(sample)};
output.push_back(saturated);
history[1] = history[0];
history[0] = saturated;
}
remainingSamples -= frameSamples;
}
return output;
}
}