FIFOSampleBuffer.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. ////////////////////////////////////////////////////////////////////////////////
  2. ///
  3. /// A buffer class for temporarily storaging sound samples, operates as a
  4. /// first-in-first-out pipe.
  5. ///
  6. /// Samples are added to the end of the sample buffer with the 'putSamples'
  7. /// function, and are received from the beginning of the buffer by calling
  8. /// the 'receiveSamples' function. The class automatically removes the
  9. /// outputted samples from the buffer, as well as grows the buffer size
  10. /// whenever necessary.
  11. ///
  12. /// Author : Copyright (c) Olli Parviainen
  13. /// Author e-mail : oparviai 'at' iki.fi
  14. /// SoundTouch WWW: http://www.surina.net/soundtouch
  15. ///
  16. ////////////////////////////////////////////////////////////////////////////////
  17. //
  18. // License :
  19. //
  20. // SoundTouch audio processing library
  21. // Copyright (c) Olli Parviainen
  22. //
  23. // This library is free software; you can redistribute it and/or
  24. // modify it under the terms of the GNU Lesser General Public
  25. // License as published by the Free Software Foundation; either
  26. // version 2.1 of the License, or (at your option) any later version.
  27. //
  28. // This library is distributed in the hope that it will be useful,
  29. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  30. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  31. // Lesser General Public License for more details.
  32. //
  33. // You should have received a copy of the GNU Lesser General Public
  34. // License along with this library; if not, write to the Free Software
  35. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  36. //
  37. ////////////////////////////////////////////////////////////////////////////////
  38. #include <stdlib.h>
  39. #include <memory.h>
  40. #include <string.h>
  41. #include <assert.h>
  42. #include "FIFOSampleBuffer.h"
  43. using namespace soundtouch;
  44. // Constructor
  45. FIFOSampleBuffer::FIFOSampleBuffer(int numChannels)
  46. {
  47. assert(numChannels > 0);
  48. sizeInBytes = 0; // reasonable initial value
  49. buffer = nullptr;
  50. bufferUnaligned = nullptr;
  51. samplesInBuffer = 0;
  52. bufferPos = 0;
  53. channels = (uint)numChannels;
  54. ensureCapacity(32); // allocate initial capacity
  55. }
  56. // destructor
  57. FIFOSampleBuffer::~FIFOSampleBuffer()
  58. {
  59. delete[] bufferUnaligned;
  60. bufferUnaligned = nullptr;
  61. buffer = nullptr;
  62. }
  63. // Sets number of channels, 1 = mono, 2 = stereo
  64. void FIFOSampleBuffer::setChannels(int numChannels)
  65. {
  66. uint usedBytes;
  67. if (!verifyNumberOfChannels(numChannels)) return;
  68. usedBytes = channels * samplesInBuffer;
  69. channels = (uint)numChannels;
  70. samplesInBuffer = usedBytes / channels;
  71. }
  72. // if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and
  73. // zeroes this pointer by copying samples from the 'bufferPos' pointer
  74. // location on to the beginning of the buffer.
  75. void FIFOSampleBuffer::rewind()
  76. {
  77. if (buffer && bufferPos)
  78. {
  79. memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer);
  80. bufferPos = 0;
  81. }
  82. }
  83. // Adds 'numSamples' pcs of samples from the 'samples' memory position to
  84. // the sample buffer.
  85. void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples)
  86. {
  87. memcpy(ptrEnd(nSamples), samples, sizeof(SAMPLETYPE) * nSamples * channels);
  88. samplesInBuffer += nSamples;
  89. }
  90. // Increases the number of samples in the buffer without copying any actual
  91. // samples.
  92. //
  93. // This function is used to update the number of samples in the sample buffer
  94. // when accessing the buffer directly with 'ptrEnd' function. Please be
  95. // careful though!
  96. void FIFOSampleBuffer::putSamples(uint nSamples)
  97. {
  98. uint req;
  99. req = samplesInBuffer + nSamples;
  100. ensureCapacity(req);
  101. samplesInBuffer += nSamples;
  102. }
  103. // Returns a pointer to the end of the used part of the sample buffer (i.e.
  104. // where the new samples are to be inserted). This function may be used for
  105. // inserting new samples into the sample buffer directly. Please be careful!
  106. //
  107. // Parameter 'slackCapacity' tells the function how much free capacity (in
  108. // terms of samples) there _at least_ should be, in order to the caller to
  109. // successfully insert all the required samples to the buffer. When necessary,
  110. // the function grows the buffer size to comply with this requirement.
  111. //
  112. // When using this function as means for inserting new samples, also remember
  113. // to increase the sample count afterwards, by calling the
  114. // 'putSamples(numSamples)' function.
  115. SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity)
  116. {
  117. ensureCapacity(samplesInBuffer + slackCapacity);
  118. return buffer + samplesInBuffer * channels;
  119. }
  120. // Returns a pointer to the beginning of the currently non-outputted samples.
  121. // This function is provided for accessing the output samples directly.
  122. // Please be careful!
  123. //
  124. // When using this function to output samples, also remember to 'remove' the
  125. // outputted samples from the buffer by calling the
  126. // 'receiveSamples(numSamples)' function
  127. SAMPLETYPE *FIFOSampleBuffer::ptrBegin()
  128. {
  129. assert(buffer);
  130. return buffer + bufferPos * channels;
  131. }
  132. // Ensures that the buffer has enough capacity, i.e. space for _at least_
  133. // 'capacityRequirement' number of samples. The buffer is grown in steps of
  134. // 4 kilobytes to eliminate the need for frequently growing up the buffer,
  135. // as well as to round the buffer size up to the virtual memory page size.
  136. void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement)
  137. {
  138. SAMPLETYPE *tempUnaligned, *temp;
  139. if (capacityRequirement > getCapacity())
  140. {
  141. // enlarge the buffer in 4kbyte steps (round up to next 4k boundary)
  142. sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096;
  143. assert(sizeInBytes % 2 == 0);
  144. tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)];
  145. if (tempUnaligned == nullptr)
  146. {
  147. ST_THROW_RT_ERROR("Couldn't allocate memory!\n");
  148. }
  149. // Align the buffer to begin at 16byte cache line boundary for optimal performance
  150. temp = (SAMPLETYPE *)SOUNDTOUCH_ALIGN_POINTER_16(tempUnaligned);
  151. if (samplesInBuffer)
  152. {
  153. memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE));
  154. }
  155. delete[] bufferUnaligned;
  156. buffer = temp;
  157. bufferUnaligned = tempUnaligned;
  158. bufferPos = 0;
  159. }
  160. else
  161. {
  162. // simply rewind the buffer (if necessary)
  163. rewind();
  164. }
  165. }
  166. // Returns the current buffer capacity in terms of samples
  167. uint FIFOSampleBuffer::getCapacity() const
  168. {
  169. return sizeInBytes / (channels * sizeof(SAMPLETYPE));
  170. }
  171. // Returns the number of samples currently in the buffer
  172. uint FIFOSampleBuffer::numSamples() const
  173. {
  174. return samplesInBuffer;
  175. }
  176. // Output samples from beginning of the sample buffer. Copies demanded number
  177. // of samples to output and removes them from the sample buffer. If there
  178. // are less than 'numsample' samples in the buffer, returns all available.
  179. //
  180. // Returns number of samples copied.
  181. uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples)
  182. {
  183. uint num;
  184. num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples;
  185. memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num);
  186. return receiveSamples(num);
  187. }
  188. // Removes samples from the beginning of the sample buffer without copying them
  189. // anywhere. Used to reduce the number of samples in the buffer, when accessing
  190. // the sample buffer with the 'ptrBegin' function.
  191. uint FIFOSampleBuffer::receiveSamples(uint maxSamples)
  192. {
  193. if (maxSamples >= samplesInBuffer)
  194. {
  195. uint temp;
  196. temp = samplesInBuffer;
  197. samplesInBuffer = 0;
  198. return temp;
  199. }
  200. samplesInBuffer -= maxSamples;
  201. bufferPos += maxSamples;
  202. return maxSamples;
  203. }
  204. // Returns nonzero if the sample buffer is empty
  205. int FIFOSampleBuffer::isEmpty() const
  206. {
  207. return (samplesInBuffer == 0) ? 1 : 0;
  208. }
  209. // Clears the sample buffer
  210. void FIFOSampleBuffer::clear()
  211. {
  212. samplesInBuffer = 0;
  213. bufferPos = 0;
  214. }
  215. /// allow trimming (downwards) amount of samples in pipeline.
  216. /// Returns adjusted amount of samples
  217. uint FIFOSampleBuffer::adjustAmountOfSamples(uint numSamples)
  218. {
  219. if (numSamples < samplesInBuffer)
  220. {
  221. samplesInBuffer = numSamples;
  222. }
  223. return samplesInBuffer;
  224. }
  225. /// Add silence to end of buffer
  226. void FIFOSampleBuffer::addSilent(uint nSamples)
  227. {
  228. memset(ptrEnd(nSamples), 0, sizeof(SAMPLETYPE) * nSamples * channels);
  229. samplesInBuffer += nSamples;
  230. }