FIFOSampleBuffer.cpp 8.6 KB

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