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