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