2020-07-07 16:35:34 +02:00
|
|
|
// 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 {
|
2021-02-06 13:36:58 +01:00
|
|
|
AdpcmDecoder::AdpcmDecoder(std::vector<std::array<i16, 2>> coefficients) : coefficients(std::move(coefficients)) {}
|
2020-07-07 16:35:34 +02:00
|
|
|
|
2020-09-25 02:05:12 +02:00
|
|
|
std::vector<i16> AdpcmDecoder::Decode(span<u8> adpcmData) {
|
2020-08-21 15:28:47 +02:00
|
|
|
constexpr size_t BytesPerFrame{0x8};
|
|
|
|
constexpr size_t SamplesPerFrame{0xE};
|
2020-07-07 16:35:34 +02:00
|
|
|
|
2020-08-21 15:28:47 +02:00
|
|
|
size_t remainingSamples{(adpcmData.size() / BytesPerFrame) * SamplesPerFrame};
|
2020-07-07 16:35:34 +02:00
|
|
|
|
|
|
|
std::vector<i16> output;
|
|
|
|
output.reserve(remainingSamples);
|
|
|
|
|
|
|
|
size_t inputOffset{};
|
|
|
|
|
|
|
|
while (inputOffset < adpcmData.size()) {
|
2020-08-21 15:28:47 +02:00
|
|
|
FrameHeader header{adpcmData[inputOffset++]};
|
2020-07-07 16:35:34 +02:00
|
|
|
|
2020-08-21 15:28:47 +02:00
|
|
|
size_t frameSamples{std::min(SamplesPerFrame, remainingSamples)};
|
2020-07-07 16:35:34 +02:00
|
|
|
|
|
|
|
i32 ctx{};
|
|
|
|
|
2020-09-26 07:17:57 +02:00
|
|
|
for (size_t index{}; index < frameSamples; index++) {
|
2020-07-07 16:35:34 +02:00
|
|
|
i32 sample{};
|
|
|
|
|
|
|
|
if (index & 1) {
|
|
|
|
sample = (ctx << 28) >> 28;
|
|
|
|
} else {
|
|
|
|
ctx = adpcmData[inputOffset++];
|
|
|
|
sample = (ctx << 24) >> 28;
|
|
|
|
}
|
|
|
|
|
2020-09-26 07:17:57 +02:00
|
|
|
i32 prediction{history[0] * coefficients[header.coefficientIndex][0] + history[1] * coefficients[header.coefficientIndex][1]};
|
2020-07-07 16:35:34 +02:00
|
|
|
sample = (sample * (0x800 << header.scale) + prediction + 0x400) >> 11;
|
|
|
|
|
2020-09-26 07:17:57 +02:00
|
|
|
auto saturated{audio::Saturate<i16, i32>(sample)};
|
2020-07-07 16:35:34 +02:00
|
|
|
output.push_back(saturated);
|
|
|
|
history[1] = history[0];
|
|
|
|
history[0] = saturated;
|
|
|
|
}
|
|
|
|
|
|
|
|
remainingSamples -= frameSamples;
|
|
|
|
}
|
|
|
|
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
}
|