// 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> coefficients) : coefficients(std::move(coefficients)) {} std::vector AdpcmDecoder::Decode(span adpcmData) { constexpr size_t BytesPerFrame{0x8}; constexpr size_t SamplesPerFrame{0xE}; size_t remainingSamples{(adpcmData.size() / BytesPerFrame) * SamplesPerFrame}; std::vector 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(sample)}; output.push_back(saturated); history[1] = history[0]; history[0] = saturated; } remainingSamples -= frameSamples; } return output; } }