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
FIFOSampleBuffer(int numChannels)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
~FIFOSampleBuffer()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
setChannels(int numChannels)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.
rewind()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.
putSamples(const SAMPLETYPE * samples,uint nSamples)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!
putSamples(uint nSamples)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.
ptrEnd(uint slackCapacity)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
ptrBegin()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.
ensureCapacity(uint capacityRequirement)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
getCapacity() const193 uint FIFOSampleBuffer::getCapacity() const
194 {
195     return sizeInBytes / (channels * sizeof(SAMPLETYPE));
196 }
197 
198 
199 // Returns the number of samples currently in the buffer
numSamples() const200 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.
receiveSamples(SAMPLETYPE * output,uint maxSamples)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.
receiveSamples(uint maxSamples)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
isEmpty() const244 int FIFOSampleBuffer::isEmpty() const
245 {
246     return (samplesInBuffer == 0) ? 1 : 0;
247 }
248 
249 
250 // Clears the sample buffer
clear()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
adjustAmountOfSamples(uint numSamples)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
addSilent(uint nSamples)271 void FIFOSampleBuffer::addSilent(uint nSamples)
272 {
273     memset(ptrEnd(nSamples), 0, sizeof(SAMPLETYPE) * nSamples * channels);
274     samplesInBuffer += nSamples;
275 }
276