62 lines
2.1 KiB
C#
62 lines
2.1 KiB
C#
using System;
|
|
|
|
namespace Ryujinx.Audio.ADPCM
|
|
{
|
|
class Decoder
|
|
{
|
|
private const int SamplesPerFrame = 14;
|
|
|
|
private AudioHelper Helper;
|
|
|
|
public Decoder()
|
|
{
|
|
Helper = new AudioHelper();
|
|
}
|
|
|
|
public short[] Decode(byte[] ADPCM, Info ADPCMInfo, int Samples)
|
|
{
|
|
short[] PCM = new short[Samples];
|
|
|
|
short Hist1 = ADPCMInfo.History1;
|
|
short Hist2 = ADPCMInfo.History2;
|
|
short[] Coefficients = ADPCMInfo.Coefficients;
|
|
|
|
int FrameCount = Helper.DivideByRoundUp(Samples, SamplesPerFrame);
|
|
int SamplesRemaining = Samples;
|
|
|
|
int OutIndex = 0;
|
|
int InIndex = 0;
|
|
|
|
for (int Index = 0; Index < FrameCount; Index++)
|
|
{
|
|
byte PredictorScale = ADPCM[InIndex++];
|
|
int Scale = (1 << Helper.GetLowNibble(PredictorScale)) * 2048;
|
|
int Predictor = Helper.GetHighNibble(PredictorScale);
|
|
|
|
short Coef1 = ADPCMInfo.Coefficients[Predictor * 2];
|
|
short Coef2 = ADPCMInfo.Coefficients[Predictor * 2 + 1];
|
|
|
|
int SamplesToRead = Math.Min(SamplesPerFrame, SamplesRemaining);
|
|
|
|
for (int SampleIndex = 0; SampleIndex < SamplesToRead; SampleIndex++)
|
|
{
|
|
int ADPCMSample = SampleIndex % 2 == 0 ? Helper.GetHighNibble(ADPCM[InIndex]) : Helper.GetLowNibble(ADPCM[InIndex++]);
|
|
int Distance = Scale * ADPCMSample;
|
|
int PredictedSample = Coef1 * Hist1 + Coef2 * Hist2;
|
|
int CorrectedSample = PredictedSample + Distance;
|
|
int ScaledSample = (CorrectedSample + 1024) >> 11;
|
|
short ClampedSample = Helper.Clamp16(ScaledSample);
|
|
|
|
Hist2 = Hist1;
|
|
Hist1 = ClampedSample;
|
|
|
|
PCM[OutIndex++] = ClampedSample;
|
|
}
|
|
|
|
SamplesRemaining -= SamplesToRead;
|
|
}
|
|
|
|
return PCM;
|
|
}
|
|
}
|
|
}
|