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