DynamicRingBuffer.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. using Ryujinx.Common;
  2. using System;
  3. namespace Ryujinx.Audio.Backends.Common
  4. {
  5. /// <summary>
  6. /// A ring buffer that grow if data written to it is too big to fit.
  7. /// </summary>
  8. public class DynamicRingBuffer
  9. {
  10. private const int RingBufferAlignment = 2048;
  11. private object _lock = new object();
  12. private byte[] _buffer;
  13. private int _size;
  14. private int _headOffset;
  15. private int _tailOffset;
  16. public int Length => _size;
  17. public DynamicRingBuffer(int initialCapacity = RingBufferAlignment)
  18. {
  19. _buffer = new byte[initialCapacity];
  20. }
  21. public void Clear()
  22. {
  23. _size = 0;
  24. _headOffset = 0;
  25. _tailOffset = 0;
  26. }
  27. public void Clear(int size)
  28. {
  29. lock (_lock)
  30. {
  31. if (size > _size)
  32. {
  33. size = _size;
  34. }
  35. if (size == 0)
  36. {
  37. return;
  38. }
  39. _headOffset = (_headOffset + size) % _buffer.Length;
  40. _size -= size;
  41. if (_size == 0)
  42. {
  43. _headOffset = 0;
  44. _tailOffset = 0;
  45. }
  46. }
  47. }
  48. private void SetCapacityLocked(int capacity)
  49. {
  50. byte[] buffer = new byte[capacity];
  51. if (_size > 0)
  52. {
  53. if (_headOffset < _tailOffset)
  54. {
  55. Buffer.BlockCopy(_buffer, _headOffset, buffer, 0, _size);
  56. }
  57. else
  58. {
  59. Buffer.BlockCopy(_buffer, _headOffset, buffer, 0, _buffer.Length - _headOffset);
  60. Buffer.BlockCopy(_buffer, 0, buffer, _buffer.Length - _headOffset, _tailOffset);
  61. }
  62. }
  63. _buffer = buffer;
  64. _headOffset = 0;
  65. _tailOffset = _size;
  66. }
  67. public void Write<T>(T[] buffer, int index, int count)
  68. {
  69. if (count == 0)
  70. {
  71. return;
  72. }
  73. lock (_lock)
  74. {
  75. if ((_size + count) > _buffer.Length)
  76. {
  77. SetCapacityLocked(BitUtils.AlignUp(_size + count, RingBufferAlignment));
  78. }
  79. if (_headOffset < _tailOffset)
  80. {
  81. int tailLength = _buffer.Length - _tailOffset;
  82. if (tailLength >= count)
  83. {
  84. Buffer.BlockCopy(buffer, index, _buffer, _tailOffset, count);
  85. }
  86. else
  87. {
  88. Buffer.BlockCopy(buffer, index, _buffer, _tailOffset, tailLength);
  89. Buffer.BlockCopy(buffer, index + tailLength, _buffer, 0, count - tailLength);
  90. }
  91. }
  92. else
  93. {
  94. Buffer.BlockCopy(buffer, index, _buffer, _tailOffset, count);
  95. }
  96. _size += count;
  97. _tailOffset = (_tailOffset + count) % _buffer.Length;
  98. }
  99. }
  100. public int Read<T>(T[] buffer, int index, int count)
  101. {
  102. lock (_lock)
  103. {
  104. if (count > _size)
  105. {
  106. count = _size;
  107. }
  108. if (count == 0)
  109. {
  110. return 0;
  111. }
  112. if (_headOffset < _tailOffset)
  113. {
  114. Buffer.BlockCopy(_buffer, _headOffset, buffer, index, count);
  115. }
  116. else
  117. {
  118. int tailLength = _buffer.Length - _headOffset;
  119. if (tailLength >= count)
  120. {
  121. Buffer.BlockCopy(_buffer, _headOffset, buffer, index, count);
  122. }
  123. else
  124. {
  125. Buffer.BlockCopy(_buffer, _headOffset, buffer, index, tailLength);
  126. Buffer.BlockCopy(_buffer, 0, buffer, index + tailLength, count - tailLength);
  127. }
  128. }
  129. _size -= count;
  130. _headOffset = (_headOffset + count) % _buffer.Length;
  131. if (_size == 0)
  132. {
  133. _headOffset = 0;
  134. _tailOffset = 0;
  135. }
  136. return count;
  137. }
  138. }
  139. }
  140. }