CSL  5.2
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 
17  mLoopStartFrame(0), mLoopEndFrame(0), mParentBuffer(parent) {
18  setOffset(offset);
19 }
20 
21 // Tap utilities.
22 
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 
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 
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) {
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) {
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 
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 }