AdpcmDecoder.cs 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. namespace Ryujinx.Audio.Adpcm
  2. {
  3. public static class AdpcmDecoder
  4. {
  5. private const int SamplesPerFrame = 14;
  6. private const int BytesPerFrame = 8;
  7. public static int[] Decode(byte[] Buffer, AdpcmDecoderContext Context)
  8. {
  9. int Samples = GetSamplesCountFromSize(Buffer.Length);
  10. int[] Pcm = new int[Samples * 2];
  11. short History0 = Context.History0;
  12. short History1 = Context.History1;
  13. int InputOffset = 0;
  14. int OutputOffset = 0;
  15. while (InputOffset < Buffer.Length)
  16. {
  17. byte Header = Buffer[InputOffset++];
  18. int Scale = 0x800 << (Header & 0xf);
  19. int CoeffIndex = (Header >> 4) & 7;
  20. short Coeff0 = Context.Coefficients[CoeffIndex * 2 + 0];
  21. short Coeff1 = Context.Coefficients[CoeffIndex * 2 + 1];
  22. int FrameSamples = SamplesPerFrame;
  23. if (FrameSamples > Samples)
  24. {
  25. FrameSamples = Samples;
  26. }
  27. int Value = 0;
  28. for (int SampleIndex = 0; SampleIndex < FrameSamples; SampleIndex++)
  29. {
  30. int Sample;
  31. if ((SampleIndex & 1) == 0)
  32. {
  33. Value = Buffer[InputOffset++];
  34. Sample = (Value << 24) >> 28;
  35. }
  36. else
  37. {
  38. Sample = (Value << 28) >> 28;
  39. }
  40. int Prediction = Coeff0 * History0 + Coeff1 * History1;
  41. Sample = (Sample * Scale + Prediction + 0x400) >> 11;
  42. short SaturatedSample = DspUtils.Saturate(Sample);
  43. History1 = History0;
  44. History0 = SaturatedSample;
  45. Pcm[OutputOffset++] = SaturatedSample;
  46. Pcm[OutputOffset++] = SaturatedSample;
  47. }
  48. Samples -= FrameSamples;
  49. }
  50. Context.History0 = History0;
  51. Context.History1 = History1;
  52. return Pcm;
  53. }
  54. public static long GetSizeFromSamplesCount(int SamplesCount)
  55. {
  56. int Frames = SamplesCount / SamplesPerFrame;
  57. return Frames * BytesPerFrame;
  58. }
  59. public static int GetSamplesCountFromSize(long Size)
  60. {
  61. int Frames = (int)(Size / BytesPerFrame);
  62. return Frames * SamplesPerFrame;
  63. }
  64. }
  65. }