CSL  6.0
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 #pragma mark RingBuffer
160 
161 // ~~~~~~~~~ RingBuffer implementation ~~~~~~~~~~~~~~
162 
163 // Constructors
164 
166  Effect(), Writeable(), mCurrentWriteFrame(0),
167  mBuffer(), mTempCurrentWriteFrame(0) {
168  mTap.setBuffer(this);
169 }
170 
171 RingBuffer::RingBuffer(unsigned int nmChannels, unsigned int nmFrames)
172  : Effect(), Writeable(), mCurrentWriteFrame(0),
173  mBuffer(nmChannels, nmFrames),
174  mTempCurrentWriteFrame(0) {
176  mTap.setBuffer(this);
177 }
178 
179 RingBuffer::RingBuffer(UnitGenerator & input, unsigned int nmChannels, unsigned int nmFrames)
180  : Effect(input), Writeable(), mCurrentWriteFrame(0),
181  mBuffer(nmChannels, nmFrames),
182  mTempCurrentWriteFrame(0) {
184  mTap.setBuffer(this);
185 }
186 
187 // Buffer nextBuffer reads from the default tap
188 
189 void RingBuffer::nextBuffer(Buffer &outputBuffer) throw(CException) {
190  if (mInputs[CSL_INPUT]) {
191  Effect::pullInput(outputBuffer);
192  writeBuffer(outputBuffer);
193  }
194  return mTap.nextBuffer(outputBuffer);
195 }
196 
198  return mTap.destructiveNextBuffer(outputBuffer);
199 }
200 
201 void RingBuffer::writeBuffer(Buffer &inputBuffer) throw(CException) {
202  Writeable::writeBuffer(inputBuffer);
203  mCurrentWriteFrame = mTempCurrentWriteFrame;
204  return;
205 }
206 
207 void RingBuffer::sumIntoBuffer(Buffer &inputBuffer) throw(CException) {
208  unsigned numBufs = inputBuffer.mNumChannels;
209  for (unsigned i = 0; i < numBufs; i++)
210  sumIntoBuffer(inputBuffer, i);
211  mCurrentWriteFrame = mTempCurrentWriteFrame;
212  return;
213 }
214 
215 unsigned RingBuffer::seekTo(int position) throw(CException) {
216  unsigned writeFrame = mCurrentWriteFrame;
217  unsigned numFrames = mBuffer.mNumFrames;
218 
219  writeFrame += position;
220  while (writeFrame > numFrames)
221  writeFrame -= numFrames;
222  mCurrentWriteFrame = writeFrame;
223  return mCurrentWriteFrame;
224 }
225 
226 // Buffer write method
227 
228 void RingBuffer::writeBuffer(Buffer &inputBuffer, unsigned bufNum) throw(CException) {
229  if (bufNum >= mNumChannels) return;
230  unsigned numFrames = inputBuffer.mNumFrames; // get everything into registers
231  unsigned currentFrame = mCurrentWriteFrame;
232  unsigned ringBufferStartFrame = mTap.mLoopStartFrame;
233  unsigned ringBufferEndFrame = mBuffer.mNumFrames - mTap.mLoopEndFrame;
234 
235  if (currentFrame > ringBufferEndFrame)
236  currentFrame = ringBufferStartFrame;
237  else if (currentFrame < ringBufferStartFrame)
238  currentFrame = ringBufferStartFrame;
239 
240  unsigned framesWritten = 0;
241  unsigned currentBufNum = bufNum % mBuffer.mNumChannels;
242  SampleBuffer currentBufferPtr = mBuffer.buffer(currentBufNum) + currentFrame;
243  SampleBuffer inputBufferPtr = inputBuffer.buffer(bufNum);
244 // printf("\tRB: %7.5f\n", *inputBufferPtr);
245  for (; numFrames > 0; numFrames -= framesWritten) {
246  bool copyToEnd = (currentFrame + numFrames) > ringBufferEndFrame;
247  framesWritten = copyToEnd ? (ringBufferEndFrame - currentFrame) : numFrames;
248  memcpy (currentBufferPtr, inputBufferPtr, framesWritten * sizeof(sample*));
249  if (copyToEnd)
250  currentFrame = ringBufferStartFrame;
251  else
252  currentFrame += framesWritten;
253  // increment buffer pointers
254  currentBufferPtr = mBuffer.buffer(currentBufNum) + currentFrame;
255  inputBufferPtr += framesWritten;
256  }
257  // remember the state
258  mTempCurrentWriteFrame = currentFrame;
259  return;
260 }
261 
262 void RingBuffer::sumIntoBuffer(Buffer &inputBuffer, unsigned bufNum) throw(CException) {
263  // get everything into registers
264  unsigned numFrames = inputBuffer.mNumFrames;
265  unsigned currentFrame = mCurrentWriteFrame;
266  unsigned ringBufferStartFrame = mTap.mLoopStartFrame;
267  unsigned ringBufferEndFrame = mBuffer.mNumFrames - mTap.mLoopEndFrame;
268 
269  if (currentFrame > ringBufferEndFrame)
270  currentFrame = ringBufferStartFrame;
271  else if (currentFrame < ringBufferStartFrame)
272  currentFrame = ringBufferStartFrame;
273 
274  unsigned framesWritten = 0;
275  unsigned currentBufNum = bufNum % mBuffer.mNumChannels;
276  bool canCopyToEnd;
277 
278  SampleBuffer currentBufferPtr = mBuffer.buffer(currentBufNum) + currentFrame;
279  SampleBuffer inputBufferPtr = inputBuffer.buffer(bufNum);
280 
281  for (; numFrames > 0; numFrames -= framesWritten) {
282  canCopyToEnd = (currentFrame + numFrames) > ringBufferEndFrame;
283  framesWritten = canCopyToEnd ? (ringBufferEndFrame - currentFrame) : numFrames;
284 
285  for (unsigned i = 0; i < framesWritten; i++)
286  *currentBufferPtr++ += *inputBufferPtr++;
287 
288  if (canCopyToEnd) {
289  currentFrame = ringBufferStartFrame;
290  currentBufferPtr = mBuffer.buffer(currentBufNum) + currentFrame;
291  } else
292  currentFrame += framesWritten;
293  }
294 
295  // remember the state
296  mTempCurrentWriteFrame = currentFrame;
297 
298  return;
299 }
300 
301 #pragma mark BufferStream
302 
303 // ~~~~~~~~~ BufferStream implementation starts here ~~~~~~~~~~~~~~
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 }
sample * SampleBuffer
1-channel buffer data type, vector of (sample)
Definition: CSL_Types.h:194
void logMsg(const char *format,...)
These are the public logging messages.
Definition: CGestalt.cpp:292
SeekPosition
Enumeration for seek flags.
Definition: CSL_Core.h:560
void pullInput(Buffer &outputBuffer)
Definition: CSL_Core.cpp:1122
RingBuffer is the storage + a default reader.
Definition: RingBuffer.h:56
unsigned mNumFrames
num frames used in each buffer
Definition: CSL_Core.h:113
void setOffset(int offset)
Definition: RingBuffer.cpp:27
AdditiveInstrument.h – Sum-of-sines synthesis instrument class.
Definition: Accessor.h:17
Effect – mix-in for classes that have unit generators as inputs (like filters).
Definition: CSL_Core.h:466
void sumIntoBuffer(Buffer &inputBuffer)
Do an adding write of data into the ring buffer.
Definition: RingBuffer.cpp:207
RingBuffer()
Constructors.
Definition: RingBuffer.cpp:165
void setBuffer(RingBuffer *parent)
Definition: RingBuffer.h:38
RingBufferTap mTap
internal tap so a RingBuffer can also be a a UnitGenerator
Definition: RingBuffer.h:67
virtual void nextBuffer(Buffer &outputBuffer)
get a buffer of Frames – this is the core CSL "pull" function; the given buffer can be written into...
Definition: CSL_Core.cpp:726
unsigned duration()
Definition: RingBuffer.cpp:23
void nextBuffer(Buffer &outputBuffer)
nextBuffer method
Definition: RingBuffer.cpp:42
void writeBuffer(Buffer &inputBuffer)
Write a buffer of data into the ring buffer.
Definition: RingBuffer.cpp:326
unsigned mCurrentFrame
where I currently am in the buffer
Definition: CSL_Core.h:580
float sample
(could be changed to int, or double)
Definition: CSL_Types.h:191
Buffer mBuffer
Definition: RingBuffer.h:66
#define CSL_INPUT
Definition: CSL_Types.h:275
RingBuffer * mParentBuffer
Definition: RingBuffer.h:47
void writeBuffer(Buffer &inputBuffer)
Write a buffer of data into the ring buffer.
Definition: RingBuffer.cpp:201
Writeable – a mix-in for buffers and streams that one can write to.
Definition: CSL_Core.h:546
unsigned seekTo(int position, SeekPosition whence)
general-purpose seek on a stream
Definition: RingBuffer.cpp:138
unsigned seekTo(int position)
Definition: RingBuffer.cpp:215
void nextBuffer(Buffer &outputBuffer)
Calls the setLoopEnd of it's tap.
Definition: RingBuffer.cpp:189
void nextBuffer(Buffer &outputBuffer)
Read a buffer from the buffer stream.
Definition: RingBuffer.cpp:320
unsigned seekTo(int position, SeekPosition whence)
general-purpose seek on a stream
Definition: RingBuffer.cpp:305
Buffer – the multi-channel sample buffer class (passed around between generators and IO guys)...
Definition: CSL_Core.h:106
void destructiveNextBuffer(Buffer &outputBuffer)
zeroing as it goes.
Definition: RingBuffer.cpp:89
RingBufferTap(RingBuffer *parent=0, int offset=0)
Create a tap on a ring buffer, optionally offset relative to the current write position.
Definition: RingBuffer.cpp:16
void destructiveNextBuffer(Buffer &outputBuffer)
Read a buffer zeroing as you go.
Definition: RingBuffer.cpp:197
void allocateBuffers()
fcn to malloc storage buffers
Definition: CSL_Core.cpp:122
forward declaration
Definition: CSL_Core.h:241
virtual void writeBuffer(Buffer &inputBuffer)
write to the receiver
Definition: CSL_Core.cpp:1269
Seekable – a mix-in for positionable streams.
Definition: CSL_Core.h:577
unsigned mCurrentWriteFrame
state – users can manipulate my internal tap and buffer
Definition: RingBuffer.h:65
Base class of CSL exceptions (written upper-case). Has a string message.