CSL 5.2

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

RingBuffer.cpp
Go to the documentation of this file.
1 //
2 // RingBuffer.cpp -- the ring buffer class implementation
3 // See the copyright notice and acknowledgment of authors in the file COPYRIGHT
4 //
5
6 #include "RingBuffer.h"
7
8 #include <string.h> // for memcpy
9
10 using namespace csl;
11
12 // ~~~~~~~~~~~~~ RingBufferTap implementation ~~~~~~~~~~~~~~~~ //
13
14 // Tap constructors
15
16 RingBufferTap::RingBufferTap(RingBuffer *parent, int offset) : UnitGenerator(), Seekable(),
17 mLoopStartFrame(0), mLoopEndFrame(0), mParentBuffer(parent) {
18 setOffset(offset);
19 }
20
21 // Tap utilities.
22
23 unsigned RingBufferTap::duration() {
24 return mParentBuffer->mBuffer.mNumFrames;
25 }
26
27 void RingBufferTap::setOffset(int offset) {
28 int offsetFrame = offset;
29 if (mParentBuffer) {
30 unsigned bufferSize = mParentBuffer->mBuffer.mNumFrames;
31 offsetFrame = mParentBuffer->mCurrentWriteFrame + offset;
32 while (offsetFrame < 0)
33 offsetFrame += bufferSize;
34 while ((unsigned) offsetFrame > bufferSize)
35 offsetFrame -= bufferSize;
36 }
37 mCurrentFrame = (unsigned) offsetFrame;
38 }
39
40 // Override next_buffer as well to store the local state
41
42 void RingBufferTap::nextBuffer(Buffer &outputBuffer) throw(CException){
43
44 UnitGenerator::nextBuffer(outputBuffer); // Call the super version
45
46 mCurrentFrame = mTempCurrentFrame; // remember the state
47 return;
48 }
49
50 // Tap private nextBuffer: copy frames from the buffer, wrapping around at end
51
52 void RingBufferTap::nextBuffer(Buffer &outputBuffer, unsigned outBufNum) throw(CException) {
53 // get everything into registers
54 unsigned numFrames = outputBuffer.mNumFrames;
55 unsigned currentFrame = mCurrentFrame;
56 unsigned ringBufferStartFrame = mLoopStartFrame;
57 unsigned ringBufferEndFrame = mParentBuffer->mBuffer.mNumFrames - mLoopEndFrame; // get the end frame from the begining of the buffer.
58 unsigned currentBufNum = outBufNum % (mParentBuffer->mBuffer.mNumChannels); // if out of buffers then recycle from buffer 0.
59 unsigned framesWritten = 0;
60 bool canCopyToEnd;
61
62 // Check bounds, and if outside of loop points, then reset to start frame of tap loop.
63 if (currentFrame > ringBufferEndFrame)
64 currentFrame = ringBufferStartFrame;
65 else if (currentFrame < ringBufferStartFrame)
66 currentFrame = ringBufferStartFrame;
67
68 // Get a pointer to the buffers (read and write).
69 SampleBuffer currentBufferPtr = mParentBuffer->mBuffer.buffer(currentBufNum) + currentFrame;
70 SampleBuffer outputBufferPtr = outputBuffer.buffer(outBufNum);
71
72 for (; numFrames > 0; numFrames -= framesWritten) {
73 canCopyToEnd = (currentFrame + numFrames) > ringBufferEndFrame;
74 framesWritten = canCopyToEnd ? (ringBufferEndFrame - currentFrame) : numFrames;
75 memcpy(outputBufferPtr, currentBufferPtr, framesWritten * sizeof(sample*));
76 if (canCopyToEnd)
77 currentFrame = ringBufferStartFrame;
78 else
79 currentFrame += framesWritten;
80 // increment buffer pointers
81 currentBufferPtr = mParentBuffer->mBuffer.buffer(currentBufNum) + currentFrame;
82 outputBufferPtr += framesWritten;
83 }
84 mTempCurrentFrame = currentFrame; // remember the state
85
86 return;
87 }
88
89 void RingBufferTap::destructiveNextBuffer(Buffer &outputBuffer) throw(CException) {
90 unsigned numOutputBuffers = outputBuffer.mNumChannels;
91 unsigned i;
92
93 for (i = 0; i < numOutputBuffers; i++)
94 destructiveNextBuffer(outputBuffer, i);
95
96 mCurrentFrame = mTempCurrentFrame; // remember the state
97 return;
98 }
99
100 // this is the same as next buffer, but I zero out things as I go along
101
102 void RingBufferTap::destructiveNextBuffer(Buffer &outputBuffer, unsigned outBufNum) throw(CException) {
103 // get everything into registers
104 unsigned numFrames = outputBuffer.mNumFrames;
105 unsigned currentFrame = mCurrentFrame;
106 unsigned ringBufferStartFrame = mLoopStartFrame;
107 unsigned ringBufferEndFrame = mParentBuffer->mBuffer.mNumFrames - mLoopEndFrame;
108
109 if (currentFrame > ringBufferEndFrame)
110 currentFrame = ringBufferStartFrame;
111 else if (currentFrame < ringBufferStartFrame)
112 currentFrame = ringBufferStartFrame;
113 unsigned currentBufNum = outBufNum % (mParentBuffer->mBuffer.mNumChannels);
114 SampleBuffer currentBufferPtr = mParentBuffer->mBuffer.buffer(currentBufNum) + currentFrame;
115 SampleBuffer outputBufferPtr = outputBuffer.buffer(outBufNum);
116
117 unsigned framesWritten = 0;
118 for (; numFrames > 0; numFrames -= framesWritten) {
119 bool copyToEnd = (currentFrame + numFrames) > ringBufferEndFrame;
120 framesWritten = copyToEnd ? (ringBufferEndFrame - currentFrame) : numFrames;
121 memcpy (outputBufferPtr, currentBufferPtr, framesWritten * sizeof(sample*));
122 memset (currentBufferPtr, 0, framesWritten * sizeof(sample*));
123 if (copyToEnd)
124 currentFrame = ringBufferStartFrame;
125 else
126 currentFrame += framesWritten;
127 // increment buffer pointers
128 currentBufferPtr = mParentBuffer->mBuffer.buffer(currentBufNum) + currentFrame;
129 outputBufferPtr += framesWritten;
130 }
131 // remember the state
132 mTempCurrentFrame = currentFrame;
133 return;
134 }
135
136 // Taps are also Seekable
137
138 unsigned RingBufferTap::seekTo(int position, SeekPosition whence) throw(CException){
139 switch(whence) {
140 case kPositionStart:
141 setOffset((int) position);
142 break;
143 case kPositionCurrent: {
144 int offsetFrame = mCurrentFrame + position;
145 int bufferSize = mParentBuffer->mBuffer.mNumFrames;
146 while (offsetFrame < 0)
147 offsetFrame += bufferSize;
148 while (offsetFrame > bufferSize)
149 offsetFrame -= bufferSize;
150 }
151 break;
152 case kPositionEnd:
153 setOffset(-1 * position);
154 break;
155 }
156 return mCurrentFrame;
157 }
158
159 // ~~~~~~~~~ RingBuffer implementation ~~~~~~~~~~~~~~
160
161 // Constructors
162
163 RingBuffer::RingBuffer() :
164 Effect(), Writeable(), mCurrentWriteFrame(0),
165 mBuffer(), mTempCurrentWriteFrame(0) {
166 mTap.setBuffer(this);
167 }
168
169 RingBuffer::RingBuffer(unsigned int nmChannels, unsigned int nmFrames)
170 : Effect(), Writeable(), mCurrentWriteFrame(0),
171 mBuffer(nmChannels, nmFrames),
172 mTempCurrentWriteFrame(0) {
173 mBuffer.allocateBuffers();
174 mTap.setBuffer(this);
175 }
176
177 RingBuffer::RingBuffer(UnitGenerator & input, unsigned int nmChannels, unsigned int nmFrames)
178 : Effect(input), Writeable(), mCurrentWriteFrame(0),
179 mBuffer(nmChannels, nmFrames),
180 mTempCurrentWriteFrame(0) {
181 mBuffer.allocateBuffers();
182 mTap.setBuffer(this);
183 }
184
185 // Buffer nextBuffer reads from the default tap
186
187 void RingBuffer::nextBuffer(Buffer &outputBuffer) throw(CException) {
188 if (mInputs[CSL_INPUT]) {
189 Effect::pullInput(outputBuffer);
190 writeBuffer(outputBuffer);
191 }
192 return mTap.nextBuffer(outputBuffer);
193 }
194
195 void RingBuffer::destructiveNextBuffer(Buffer &outputBuffer) throw(CException) {
196 return mTap.destructiveNextBuffer(outputBuffer);
197 }
198
199 void RingBuffer::writeBuffer(Buffer &inputBuffer) throw(CException) {
200 Writeable::writeBuffer(inputBuffer);
201 mCurrentWriteFrame = mTempCurrentWriteFrame;
202 return;
203 }
204
205 void RingBuffer::sumIntoBuffer(Buffer &inputBuffer) throw(CException) {
206 unsigned numBufs = inputBuffer.mNumChannels;
207 for (unsigned i = 0; i < numBufs; i++)
208 sumIntoBuffer(inputBuffer, i);
209 mCurrentWriteFrame = mTempCurrentWriteFrame;
210 return;
211 }
212
213 unsigned RingBuffer::seekTo(int position) throw(CException) {
214 unsigned writeFrame = mCurrentWriteFrame;
215 unsigned numFrames = mBuffer.mNumFrames;
216
217 writeFrame += position;
218 while (writeFrame > numFrames)
219 writeFrame -= numFrames;
220 mCurrentWriteFrame = writeFrame;
221 return mCurrentWriteFrame;
222 }
223
224 // Buffer write method
225 void RingBuffer::writeBuffer(Buffer &inputBuffer, unsigned bufNum) throw(CException) {
226 if (bufNum >= mNumChannels) return;
227 unsigned numFrames = inputBuffer.mNumFrames; // get everything into registers
228 unsigned currentFrame = mCurrentWriteFrame;
229 unsigned ringBufferStartFrame = mTap.mLoopStartFrame;
230 unsigned ringBufferEndFrame = mBuffer.mNumFrames - mTap.mLoopEndFrame;
231
232 if (currentFrame > ringBufferEndFrame)
233 currentFrame = ringBufferStartFrame;
234 else if (currentFrame < ringBufferStartFrame)
235 currentFrame = ringBufferStartFrame;
236
237 unsigned framesWritten = 0;
238 unsigned currentBufNum = bufNum % mBuffer.mNumChannels;
239 SampleBuffer currentBufferPtr = mBuffer.buffer(currentBufNum) + currentFrame;
240 SampleBuffer inputBufferPtr = inputBuffer.buffer(bufNum);
241 // printf("\tRB: %7.5f\n", *inputBufferPtr);
242 for (; numFrames > 0; numFrames -= framesWritten) {
243 bool copyToEnd = (currentFrame + numFrames) > ringBufferEndFrame;
244 framesWritten = copyToEnd ? (ringBufferEndFrame - currentFrame) : numFrames;
245 memcpy (currentBufferPtr, inputBufferPtr, framesWritten * sizeof(sample*));
246 if (copyToEnd)
247 currentFrame = ringBufferStartFrame;
248 else
249 currentFrame += framesWritten;
250 // increment buffer pointers
251 currentBufferPtr = mBuffer.buffer(currentBufNum) + currentFrame;
252 inputBufferPtr += framesWritten;
253 }
254 // remember the state
255 mTempCurrentWriteFrame = currentFrame;
256 return;
257 }
258
259 void RingBuffer::sumIntoBuffer(Buffer &inputBuffer, unsigned bufNum) throw(CException) {
260 // get everything into registers
261 unsigned numFrames = inputBuffer.mNumFrames;
262 unsigned currentFrame = mCurrentWriteFrame;
263 unsigned ringBufferStartFrame = mTap.mLoopStartFrame;
264 unsigned ringBufferEndFrame = mBuffer.mNumFrames - mTap.mLoopEndFrame;
265
266 if (currentFrame > ringBufferEndFrame)
267 currentFrame = ringBufferStartFrame;
268 else if (currentFrame < ringBufferStartFrame)
269 currentFrame = ringBufferStartFrame;
270
271 unsigned framesWritten = 0;
272 unsigned currentBufNum = bufNum % mBuffer.mNumChannels;
273 bool canCopyToEnd;
274
275 SampleBuffer currentBufferPtr = mBuffer.buffer(currentBufNum) + currentFrame;
276 SampleBuffer inputBufferPtr = inputBuffer.buffer(bufNum);
277
278 for (; numFrames > 0; numFrames -= framesWritten) {
279 canCopyToEnd = (currentFrame + numFrames) > ringBufferEndFrame;
280 framesWritten = canCopyToEnd ? (ringBufferEndFrame - currentFrame) : numFrames;
281
282 for (unsigned i = 0; i < framesWritten; i++)
283 *currentBufferPtr++ += *inputBufferPtr++;
284
285 if (canCopyToEnd) {
286 currentFrame = ringBufferStartFrame;
287 currentBufferPtr = mBuffer.buffer(currentBufNum) + currentFrame;
288 } else
289 currentFrame += framesWritten;
290 }
291
292 // remember the state
293 mTempCurrentWriteFrame = currentFrame;
294
295 return;
296 }
297
298
299 // ~~~~~~~~~ BufferStream implementation starts here!!! ~~~~~~~~~~~~~~
300
301 unsigned BufferStream::duration() const {
302 return mBuffer->mNumFrames;
303 }
304
305 unsigned BufferStream::seekTo(int position, SeekPosition whence) throw(CException) {
306 switch(whence) {
307 case kPositionStart:
308 mCurrentFrame = position;
309 break;
310 case kPositionCurrent:
311 mCurrentFrame += position;
312 break;
313 case kPositionEnd:
314 mCurrentFrame = mBuffer->mNumFrames - position;
315 break;
316 }
317 return mCurrentFrame;
318 }
319
320 void BufferStream::nextBuffer(Buffer & outputBuffer) throw(CException) {
321 UnitGenerator::nextBuffer(outputBuffer);
322 mCurrentFrame = mTempCurrentFrame; // remember state
323 return;
324 }
325
326 void BufferStream::writeBuffer(Buffer &inputBuffer) throw(CException) {
327 Writeable::writeBuffer(inputBuffer);
328 mCurrentWriteFrame = mTempCurrentWriteFrame; // remember state
329 return;
330 }
331
332 void BufferStream::nextBuffer(Buffer &outputBuffer, unsigned outBufNum) throw(CException) {
333 // get everything into registers
334 unsigned numFrames = outputBuffer.mNumFrames;
335 unsigned currentFrame = mCurrentFrame;
336 unsigned bufferEndFrame = mBuffer->mNumFrames;
337 unsigned currentBufNum = outBufNum % (mBuffer->mNumChannels);
338 SampleBuffer outputBufferPtr = outputBuffer.buffer(outBufNum);
339
340 // if we are past the end
341 if (currentFrame > bufferEndFrame) {
342 memset(outputBufferPtr, 0, numFrames);
343 return;
344 }
345
346 SampleBuffer currentBufPtr = mBuffer->buffer(currentBufNum) + currentFrame;
347 unsigned framesWritten = 0;
348 bool copyToEnd = (currentFrame + numFrames) > bufferEndFrame;
349 framesWritten = copyToEnd ? (bufferEndFrame - currentFrame) : numFrames;
350 memcpy (outputBufferPtr, currentBufPtr, framesWritten * sizeof(sample*));
351 currentFrame += framesWritten;
352 if (framesWritten < numFrames) {
353 outputBufferPtr += framesWritten;
354 memset(outputBufferPtr, 0, numFrames - framesWritten);
355 } // remember the state
356 mTempCurrentFrame = currentFrame;
357 return;
358 }
359
360 void BufferStream::writeBuffer(Buffer &inputBuffer, unsigned bufNum) throw(CException) {
361 // get everything into registers
362 unsigned numFrames = inputBuffer.mNumFrames;
363 unsigned currentFrame = mCurrentWriteFrame;
364 unsigned bufferEndFrame = mBuffer->mNumFrames;
365
366 if (currentFrame > bufferEndFrame) {
367 logMsg(kLogError, "Attempt to write into a buffer, past the end");
368 return;
369 }
370
371 unsigned currentBufNum = bufNum % mBuffer->mNumChannels;
372 SampleBuffer currentBufPtr = mBuffer->buffer(currentBufNum) + currentFrame;
373 SampleBuffer inputBufferPtr = inputBuffer.buffer(bufNum);
374 unsigned framesWritten = 0;
375 bool copyToEnd = (currentFrame + numFrames) > bufferEndFrame;
376 framesWritten = copyToEnd ? (bufferEndFrame - currentFrame) : numFrames;
377 memcpy (currentBufPtr, inputBufferPtr, framesWritten * sizeof(sample*));
378 currentFrame += framesWritten;
379 // remember the state
380 mTempCurrentWriteFrame = currentFrame;
381 return;
382 }