VoiceContext.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. using ChocolArm64.Memory;
  2. using Ryujinx.Audio.Adpcm;
  3. using System;
  4. namespace Ryujinx.HLE.OsHle.Services.Aud.AudioRenderer
  5. {
  6. class VoiceContext
  7. {
  8. private bool Acquired;
  9. private bool BufferReload;
  10. private int ResamplerFracPart;
  11. private int BufferIndex;
  12. private int Offset;
  13. public int SampleRate;
  14. public int ChannelsCount;
  15. public float Volume;
  16. public PlayState PlayState;
  17. public SampleFormat SampleFormat;
  18. public AdpcmDecoderContext AdpcmCtx;
  19. public WaveBuffer[] WaveBuffers;
  20. public VoiceOut OutStatus;
  21. private int[] Samples;
  22. public bool Playing => Acquired && PlayState == PlayState.Playing;
  23. public VoiceContext()
  24. {
  25. WaveBuffers = new WaveBuffer[4];
  26. }
  27. public void SetAcquireState(bool NewState)
  28. {
  29. if (Acquired && !NewState)
  30. {
  31. //Release.
  32. Reset();
  33. }
  34. Acquired = NewState;
  35. }
  36. private void Reset()
  37. {
  38. BufferReload = true;
  39. BufferIndex = 0;
  40. Offset = 0;
  41. OutStatus.PlayedSamplesCount = 0;
  42. OutStatus.PlayedWaveBuffersCount = 0;
  43. OutStatus.VoiceDropsCount = 0;
  44. }
  45. public int[] GetBufferData(AMemory Memory, int MaxSamples, out int SamplesCount)
  46. {
  47. if (!Playing)
  48. {
  49. SamplesCount = 0;
  50. return null;
  51. }
  52. if (BufferReload)
  53. {
  54. BufferReload = false;
  55. UpdateBuffer(Memory);
  56. }
  57. WaveBuffer Wb = WaveBuffers[BufferIndex];
  58. int MaxSize = Samples.Length - Offset;
  59. int Size = MaxSamples * AudioConsts.HostChannelsCount;
  60. if (Size > MaxSize)
  61. {
  62. Size = MaxSize;
  63. }
  64. int[] Output = new int[Size];
  65. Array.Copy(Samples, Offset, Output, 0, Size);
  66. SamplesCount = Size / AudioConsts.HostChannelsCount;
  67. OutStatus.PlayedSamplesCount += SamplesCount;
  68. Offset += Size;
  69. if (Offset == Samples.Length)
  70. {
  71. Offset = 0;
  72. if (Wb.Looping == 0)
  73. {
  74. SetBufferIndex((BufferIndex + 1) & 3);
  75. }
  76. OutStatus.PlayedWaveBuffersCount++;
  77. if (Wb.LastBuffer != 0)
  78. {
  79. PlayState = PlayState.Paused;
  80. }
  81. }
  82. return Output;
  83. }
  84. private void UpdateBuffer(AMemory Memory)
  85. {
  86. //TODO: Implement conversion for formats other
  87. //than interleaved stereo (2 channels).
  88. //As of now, it assumes that HostChannelsCount == 2.
  89. WaveBuffer Wb = WaveBuffers[BufferIndex];
  90. if (SampleFormat == SampleFormat.PcmInt16)
  91. {
  92. int SamplesCount = (int)(Wb.Size / (sizeof(short) * ChannelsCount));
  93. Samples = new int[SamplesCount * AudioConsts.HostChannelsCount];
  94. if (ChannelsCount == 1)
  95. {
  96. for (int Index = 0; Index < SamplesCount; Index++)
  97. {
  98. short Sample = Memory.ReadInt16(Wb.Position + Index * 2);
  99. Samples[Index * 2 + 0] = Sample;
  100. Samples[Index * 2 + 1] = Sample;
  101. }
  102. }
  103. else
  104. {
  105. for (int Index = 0; Index < SamplesCount * 2; Index++)
  106. {
  107. Samples[Index] = Memory.ReadInt16(Wb.Position + Index * 2);
  108. }
  109. }
  110. }
  111. else if (SampleFormat == SampleFormat.Adpcm)
  112. {
  113. byte[] Buffer = Memory.ReadBytes(Wb.Position, Wb.Size);
  114. Samples = AdpcmDecoder.Decode(Buffer, AdpcmCtx);
  115. }
  116. else
  117. {
  118. throw new InvalidOperationException();
  119. }
  120. if (SampleRate != AudioConsts.HostSampleRate)
  121. {
  122. //TODO: We should keep the frames being discarded (see the 4 below)
  123. //on a buffer and include it on the next samples buffer, to allow
  124. //the resampler to do seamless interpolation between wave buffers.
  125. int SamplesCount = Samples.Length / AudioConsts.HostChannelsCount;
  126. SamplesCount = Math.Max(SamplesCount - 4, 0);
  127. Samples = Resampler.Resample2Ch(
  128. Samples,
  129. SampleRate,
  130. AudioConsts.HostSampleRate,
  131. SamplesCount,
  132. ref ResamplerFracPart);
  133. }
  134. }
  135. public void SetBufferIndex(int Index)
  136. {
  137. BufferIndex = Index & 3;
  138. BufferReload = true;
  139. }
  140. }
  141. }