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