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