FIFOSampleBuffer.cpp (8520B)
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 39 #include <stdlib.h> 40 #include <memory.h> 41 #include <string.h> 42 #include <assert.h> 43 44 #include "FIFOSampleBuffer.h" 45 46 using namespace soundtouch; 47 48 // Constructor 49 FIFOSampleBuffer::FIFOSampleBuffer(int numChannels) 50 { 51 assert(numChannels > 0); 52 sizeInBytes = 0; // reasonable initial value 53 buffer = NULL; 54 bufferUnaligned = NULL; 55 samplesInBuffer = 0; 56 bufferPos = 0; 57 channels = (uint)numChannels; 58 ensureCapacity(32); // allocate initial capacity 59 } 60 61 62 // destructor 63 FIFOSampleBuffer::~FIFOSampleBuffer() 64 { 65 delete[] bufferUnaligned; 66 bufferUnaligned = NULL; 67 buffer = NULL; 68 } 69 70 71 // Sets number of channels, 1 = mono, 2 = stereo 72 void FIFOSampleBuffer::setChannels(int numChannels) 73 { 74 uint usedBytes; 75 76 if (!verifyNumberOfChannels(numChannels)) return; 77 78 usedBytes = channels * samplesInBuffer; 79 channels = (uint)numChannels; 80 samplesInBuffer = usedBytes / channels; 81 } 82 83 84 // if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and 85 // zeroes this pointer by copying samples from the 'bufferPos' pointer 86 // location on to the beginning of the buffer. 87 void FIFOSampleBuffer::rewind() 88 { 89 if (buffer && bufferPos) 90 { 91 memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer); 92 bufferPos = 0; 93 } 94 } 95 96 97 // Adds 'numSamples' pcs of samples from the 'samples' memory position to 98 // the sample buffer. 99 void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples) 100 { 101 memcpy(ptrEnd(nSamples), samples, sizeof(SAMPLETYPE) * nSamples * channels); 102 samplesInBuffer += nSamples; 103 } 104 105 106 // Increases the number of samples in the buffer without copying any actual 107 // samples. 108 // 109 // This function is used to update the number of samples in the sample buffer 110 // when accessing the buffer directly with 'ptrEnd' function. Please be 111 // careful though! 112 void FIFOSampleBuffer::putSamples(uint nSamples) 113 { 114 uint req; 115 116 req = samplesInBuffer + nSamples; 117 ensureCapacity(req); 118 samplesInBuffer += nSamples; 119 } 120 121 122 // Returns a pointer to the end of the used part of the sample buffer (i.e. 123 // where the new samples are to be inserted). This function may be used for 124 // inserting new samples into the sample buffer directly. Please be careful! 125 // 126 // Parameter 'slackCapacity' tells the function how much free capacity (in 127 // terms of samples) there _at least_ should be, in order to the caller to 128 // successfully insert all the required samples to the buffer. When necessary, 129 // the function grows the buffer size to comply with this requirement. 130 // 131 // When using this function as means for inserting new samples, also remember 132 // to increase the sample count afterwards, by calling the 133 // 'putSamples(numSamples)' function. 134 SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity) 135 { 136 ensureCapacity(samplesInBuffer + slackCapacity); 137 return buffer + samplesInBuffer * channels; 138 } 139 140 141 // Returns a pointer to the beginning of the currently non-outputted samples. 142 // This function is provided for accessing the output samples directly. 143 // Please be careful! 144 // 145 // When using this function to output samples, also remember to 'remove' the 146 // outputted samples from the buffer by calling the 147 // 'receiveSamples(numSamples)' function 148 SAMPLETYPE *FIFOSampleBuffer::ptrBegin() 149 { 150 assert(buffer); 151 return buffer + bufferPos * channels; 152 } 153 154 155 // Ensures that the buffer has enough capacity, i.e. space for _at least_ 156 // 'capacityRequirement' number of samples. The buffer is grown in steps of 157 // 4 kilobytes to eliminate the need for frequently growing up the buffer, 158 // as well as to round the buffer size up to the virtual memory page size. 159 void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement) 160 { 161 SAMPLETYPE *tempUnaligned, *temp; 162 163 if (capacityRequirement > getCapacity()) 164 { 165 // enlarge the buffer in 4kbyte steps (round up to next 4k boundary) 166 sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096; 167 assert(sizeInBytes % 2 == 0); 168 tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; 169 if (tempUnaligned == NULL) 170 { 171 ST_THROW_RT_ERROR("Couldn't allocate memory!\n"); 172 } 173 // Align the buffer to begin at 16byte cache line boundary for optimal performance 174 temp = (SAMPLETYPE *)SOUNDTOUCH_ALIGN_POINTER_16(tempUnaligned); 175 if (samplesInBuffer) 176 { 177 memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE)); 178 } 179 delete[] bufferUnaligned; 180 buffer = temp; 181 bufferUnaligned = tempUnaligned; 182 bufferPos = 0; 183 } 184 else 185 { 186 // simply rewind the buffer (if necessary) 187 rewind(); 188 } 189 } 190 191 192 // Returns the current buffer capacity in terms of samples 193 uint FIFOSampleBuffer::getCapacity() const 194 { 195 return sizeInBytes / (channels * sizeof(SAMPLETYPE)); 196 } 197 198 199 // Returns the number of samples currently in the buffer 200 uint FIFOSampleBuffer::numSamples() const 201 { 202 return samplesInBuffer; 203 } 204 205 206 // Output samples from beginning of the sample buffer. Copies demanded number 207 // of samples to output and removes them from the sample buffer. If there 208 // are less than 'numsample' samples in the buffer, returns all available. 209 // 210 // Returns number of samples copied. 211 uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples) 212 { 213 uint num; 214 215 num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples; 216 217 memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num); 218 return receiveSamples(num); 219 } 220 221 222 // Removes samples from the beginning of the sample buffer without copying them 223 // anywhere. Used to reduce the number of samples in the buffer, when accessing 224 // the sample buffer with the 'ptrBegin' function. 225 uint FIFOSampleBuffer::receiveSamples(uint maxSamples) 226 { 227 if (maxSamples >= samplesInBuffer) 228 { 229 uint temp; 230 231 temp = samplesInBuffer; 232 samplesInBuffer = 0; 233 return temp; 234 } 235 236 samplesInBuffer -= maxSamples; 237 bufferPos += maxSamples; 238 239 return maxSamples; 240 } 241 242 243 // Returns nonzero if the sample buffer is empty 244 int FIFOSampleBuffer::isEmpty() const 245 { 246 return (samplesInBuffer == 0) ? 1 : 0; 247 } 248 249 250 // Clears the sample buffer 251 void FIFOSampleBuffer::clear() 252 { 253 samplesInBuffer = 0; 254 bufferPos = 0; 255 } 256 257 258 /// allow trimming (downwards) amount of samples in pipeline. 259 /// Returns adjusted amount of samples 260 uint FIFOSampleBuffer::adjustAmountOfSamples(uint numSamples) 261 { 262 if (numSamples < samplesInBuffer) 263 { 264 samplesInBuffer = numSamples; 265 } 266 return samplesInBuffer; 267 } 268 269 270 /// Add silence to end of buffer 271 void FIFOSampleBuffer::addSilent(uint nSamples) 272 { 273 memset(ptrEnd(nSamples), 0, sizeof(SAMPLETYPE) * nSamples * channels); 274 samplesInBuffer += nSamples; 275 }