CSL  6.0
CSL_Core.cpp
Go to the documentation of this file.
1 //
2 // CSL_Core.cpp -- the implementation of Buffer, UnitGenerator, IO, mix-ins, etc.
3 //
4 // See the copyright notice and acknowledgment of authors in the file COPYRIGHT
5 //
6 
7 #include "CSL_Core.h" // it's all declared here
8 //#include "RingBuffer.h" // UnitGenerator uses RingBuffers
9 #include <string.h> // for bzero / memset
10 #include <stdlib.h> // for malloc
11 #include <math.h>
12 
13 // Sound files
14 
15 #ifdef USE_JSND
16  #include "SoundFileJ.h"
17 #endif
18 
19 #ifdef USE_LSND
20  #include "SoundFileL.h"
21  #include <samplerate.h> // libsamplerate header file
22 #endif
23 
24 #ifdef USE_CASND
25  #include "SoundFileCA.h"
26 #endif
27 
28 using namespace csl;
29 
30 #ifdef WIN32 // Windows doesn't have rintf
31 #define rint(x) ((int)(x + 0.5f))
32 #endif
33 
34 //
35 // Basic buffer methods
36 //
37 
38 #pragma mark Buffer
39 
40 // Constructor with size args does not allocate
41 
42 Buffer::Buffer(unsigned numChannels, unsigned numFrames) :
43  mNumChannels(0),
44  mNumFrames(0),
45  mNumAlloc(0),
46  mMonoBufferByteSize(0),
47  mSequence(0),
48  mAreBuffersAllocated(false),
49  mDidIAllocateBuffers(false),
50  mIsPopulated(false),
51  mAreBuffersZero(true),
52  mType(kSamples),
53  mBuffers(0) {
54  setSize(numChannels, numFrames);
55 }
56 
57 // Free buffers on destruction
58 
61  freeBuffers();
62 }
63 
64 // sample pointer accessor (used to be called monoBuffer()
65 
66 SampleBuffer Buffer::buffer(unsigned bufNum) {
67  if (mNumChannels > bufNum)
68  return mBuffers[bufNum];
69  else
70  return 0;
71 }
72 
73 // SetSize creates the vector of sample pointers, does not allocate the sample storage
74 
75 void Buffer::setSize(unsigned numChannels, unsigned numFrames) {
76  if (mAreBuffersAllocated && mDidIAllocateBuffers && (mNumChannels != numChannels)
77  && (mNumAlloc < numFrames)) {
78  freeBuffers();
79  mDidIAllocateBuffers = false;
80  mAreBuffersAllocated = false;
81  }
82  if (mNumChannels != numChannels) {
83  mNumChannels = numChannels; // Transfer parameters to member variables
84  if (mBuffers)
85  delete mBuffers; // free buffer pointers
86  mBuffers = new SampleBuffer[numChannels]; // reserve space for buffers
87  for (unsigned i = 0; i < mNumChannels; i++)
88  mBuffers[i] = 0;
89  }
90  if (mNumFrames != numFrames) {
91  mNumFrames = numFrames;
93  }
94  mIsPopulated = false;
95 }
96 
97 // set size and don't allocate vector space either
98 
99 void Buffer::setSizeOnly(unsigned numChannels, unsigned numFrames) {
100  mNumChannels = numChannels;
101  mNumFrames = numFrames;
102  mMonoBufferByteSize = numFrames * sizeof(sample);
103 }
104 
105 // allocate if not already there
106 
108  if ( ! mAreBuffersAllocated)
109  allocateBuffers();
110 }
111 
112 // answer the buffer's duration in seconds
113 
115  return ((float) mNumFrames / CGestalt::frameRateF());
116 }
117 
118 // allocate the sample arrays
119 
120 //#define FVERBOSE_MALLOC // define for verbose debugging of buffer alloc/free
121 
123 #ifdef FVERBOSE_MALLOC
124  logMsg(" Buffer::allocateBuffers(%x %d %d)", this, mNumChannels, mNumFrames);
125 #endif
126  if (mBuffers == NULL)
127  mBuffers = new SampleBuffer[mNumChannels]; // reserve space for buffers
128  for (unsigned i = 0; i < mNumChannels; i++) {
130  memset(mBuffers[i], 0, mNumFrames * sizeof(sample));
131  }
132 // if (mNumFrames < 16)
133 // logMsg("Small buffer: %d", mNumFrames);
134  mAreBuffersAllocated = true;
135  mDidIAllocateBuffers = true;
137 }
138 
139 // free them carefully
140 
142  if ( ! mAreBuffersAllocated)
143  return; // they aren't allocated -- I shouldn't free them
144  if ( ! mDidIAllocateBuffers)
145  return; // I didn't allocate them -- I shouldn't free them
146  if (& mBuffers == NULL)
147  return;
148 #ifdef FVERBOSE_MALLOC
149  logMsg(" Buffer::freeBuffers (%x %d %d)", this, mNumChannels, mNumFrames);
150 #endif
151  try {
152  for (unsigned i = 0; i < mNumChannels; i++) {
153  if (mBuffers[i]) {
154  delete mBuffers[i]; // do the delete
155  mBuffers[i] = NULL; // set to zero right away
156  }
157  }
158  } catch (std::exception ex) {
159  logMsg(kLogError, "\nError in Buffer::freeBuffers: %s\n", ex.what());
160  throw MemoryError("Error in Buffer::freeBuffers");
161  }
162  mAreBuffersAllocated = false;
163  mDidIAllocateBuffers = false;
164  delete mBuffers;
165  mBuffers = 0;
166  mNumAlloc = 0;
167  mNumFrames = 0;
169 }
170 
171 // empty the sample buffers
172 
174  if ( ! mAreBuffersAllocated)
175  return;
176  for (unsigned i = 0; i < mNumChannels; i++)
177  memset(mBuffers[i], 0, mMonoBufferByteSize);
178  mAreBuffersZero = true;
179 }
180 
181 /// answer a samp ptr tested for extent (offset + maxFrame)
182 
183 sample * Buffer::samplePtrFor(unsigned channel, unsigned offset){
184  return(mBuffers[channel] + offset);
185 }
186 
187 /// answer a samp ptr tested for extent (offset + maxFrame)
188 
189 sample * Buffer::samplePtrFor(unsigned channel, unsigned offset, unsigned maxFrame){
190  if (mNumAlloc >= (offset + maxFrame))
191  return(mBuffers[channel] + offset);
192  return NULL;
193 }
194 
195 ///< answer whether the receiver can store numFrames more frames
196 
197 bool Buffer::canStore(unsigned numFrames) {
198  return ((mNumFrames + numFrames) < mNumAlloc);
199 }
200 
201 // fill with a constant
202 
204  float * bbuffer = NULL;
205  float lVal = value;
206  unsigned outBufNum, i;
207  unsigned numChans = mNumChannels;
208  unsigned numFrames = mNumFrames;
209  for (outBufNum = 0; outBufNum < numChans; outBufNum++) {
210  bbuffer = mBuffers[outBufNum];
211  for (i = 0; i < numFrames; i++)
212  *bbuffer++ = lVal;
213  }
214  mAreBuffersZero = false;
215 }
216 
217 // scale the samples by the given value
218 
219 void Buffer::scaleBy(sample value) {
220  float * bbuffer = NULL;
221  float lVal = value;
222  unsigned outBufNum, i;
223  unsigned numChans = mNumChannels;
224  unsigned numFrames = mNumFrames;
225  for (outBufNum = 0; outBufNum < numChans; outBufNum++) {
226  bbuffer = mBuffers[outBufNum];
227  for (i = 0; i < numFrames; i++)
228  *bbuffer++ *= lVal;
229  }
230  mAreBuffersZero = false;
231 }
232 
233 // copy the "header" info
234 
236  if ((source.mNumChannels > mNumChannels) || (source.mNumFrames > mNumAlloc)) {
237  logMsg("Buffer::copyHeaderFrom(ch %d %d, fr %d %d)",
238  mNumChannels, source.mNumChannels, mNumAlloc, source.mNumFrames);
239  throw RunTimeError("Can't reallocate buffers at run-time");
240  }
241  mNumChannels = source.mNumChannels; // copy members
242  mNumFrames = source.mNumFrames;
243  mMonoBufferByteSize = mNumFrames * sizeof(sample);
244  mSequence = source.mSequence;
245  mType = source.mType;
246 }
247 
248 // Copy everything but samples from the argument to the receiver
249 
250 void Buffer::copyFrom(Buffer & source) throw (RunTimeError) {
251  this->freeBuffers(); // free everything
252  delete mBuffers;
253  mNumChannels = source.mNumChannels; // copy members
254  mNumFrames = source.mNumFrames;
255  mNumAlloc = source.mNumAlloc;
256  mMonoBufferByteSize = mNumFrames * sizeof(sample);
257  mSequence = source.mSequence;
258  mBuffers = new SampleBuffer[mNumChannels]; // reserve space for buffers
259  // copy sample pointers
260  for (unsigned outBufNum = 0; outBufNum < mNumChannels; outBufNum++) {
261  mBuffers[outBufNum] = source.buffer(outBufNum);
262  }
263  mAreBuffersZero = false; // set flags
264  mAreBuffersAllocated = true;
265  mDidIAllocateBuffers = false;
266 }
267 
268 // Copy samples from the argument to the receiver; be paranoid about size limits
269 
271  if ((source.mNumChannels > mNumChannels) || (source.mNumFrames > mNumAlloc)) {
272  logMsg(kLogError, "Buffer::copySamplesFrom(ch %d %d, fr %d %d)",
273  mNumChannels, source.mNumChannels, mNumAlloc, source.mNumFrames);
274  throw RunTimeError("Can't reallocate buffers at run-time");
275  }
276  mNumChannels = source.mNumChannels;
277  mNumFrames = source.mNumFrames;
278  mMonoBufferByteSize = mNumFrames * sizeof(sample);
279  for (unsigned outBufNum = 0; outBufNum < mNumChannels; outBufNum++) { // copy loop
280  unsigned sBufNum = csl_min(outBufNum, (source.mNumChannels - 1));
281  memcpy(mBuffers[outBufNum], source.buffer(sBufNum), mMonoBufferByteSize);
282  }
283  mAreBuffersZero = false;
284 }
285 
287  if ((source.mNumChannels > mNumChannels) || (source.mNumFrames > mNumAlloc)) {
288  logMsg(kLogError, "Buffer::copyOnlySamplesFrom(ch %d %d, fr %d %d)",
289  mNumChannels, source.mNumChannels, mNumFrames, source.mNumFrames);
290  throw RunTimeError("Can't reallocate buffers at run-time");
291  }
292  for (unsigned outBufNum = 0; outBufNum < mNumChannels; outBufNum++) {
293  unsigned sBufNum = csl_min(outBufNum, (source.mNumChannels - 1));
294  memcpy(mBuffers[outBufNum], source.buffer(sBufNum), mMonoBufferByteSize);
295  }
296 }
297 
298 ///< same with write offset
299 
300 void Buffer::copySamplesFromTo(Buffer & source, unsigned offset) throw (RunTimeError) {
301  if ((source.mNumChannels > mNumChannels) || ((offset + source.mNumFrames) > mNumAlloc)) {
302  logMsg(kLogError, "Buffer::copyOnlySamplesFrom(ch %d %d, fr %d %d)",
303  mNumChannels, source.mNumChannels, mNumFrames, source.mNumFrames);
304  throw RunTimeError("Can't reallocate buffers at run-time");
305  }
306  for (unsigned outBufNum = 0; outBufNum < mNumChannels; outBufNum++) {
307  unsigned sBufNum = csl_min(outBufNum, (source.mNumChannels - 1));
308  memcpy(mBuffers[outBufNum] + offset, source.buffer(sBufNum),
309  (source.mNumFrames * sizeof(sample)));
310  }
311 }
312 
313 // read a buffer from a snd file; answer success
314 
315 bool Buffer::readFromFile(char * finam) {
316  if (strlen(finam) == 0) { // if no file name
317  logMsg(kLogError, "Sound file name is empty.");
318 // throw LengthError("Sound file name is empty.");
319  return false;
320  }
321  // open snd file
322  SoundFile * inFile = SoundFile::openSndfile(finam);
323 
324  if ( ! inFile->isValid()) { // check result status
325 // logMsg(kLogError, "Error opening sound file \"%s\" (invalid)", finam);
326  delete inFile;
327  return false;
328  }
329  // copy data over to new buffer
330  this->copyFrom(inFile->mWavetable);
331  this->mDidIAllocateBuffers = true;
332  inFile->mWavetable.mDidIAllocateBuffers = false;
333  delete inFile; // delete infile
334 
335  if (mNumFrames == 0) {
336  logMsg(kLogError, "Error opening sound file \"%s\" (empty)", finam);
337  return false;
338  }
339  // everything's OK; proceed
340 // logMsg("Opened file: \"%s\" = %5.3f sec = %d samps = %d win",
341 // finam, ((float)mSndBuffer.mNumFrames / CGestalt::frameRateF()),
342 // mSndBuffer.mNumFrames, (mSndBuffer.mNumFrames / mFeatExtr->mHopSize));
343  return true;
344 }
345 
346 // normalize the buffer(s) to the given max val; answer the prior max val
347 
348 float Buffer::normalize(float maxVal) {
349  float * bbuffer = NULL;
350  unsigned outBufNum, i;
351  unsigned numChans = mNumChannels;
352  unsigned numFrames = mNumFrames;
353  float maxSamp = 0.0f;
354  for (outBufNum = 0; outBufNum < numChans; outBufNum++) {
355  bbuffer = mBuffers[outBufNum];
356  for (i = 0; i < numFrames; i++) {
357  float samp = fabs(*bbuffer++);
358  if (samp > maxSamp)
359  maxSamp = samp;
360  }
361  }
362  if (maxSamp == 0.0f)
363  return maxSamp;
364  float scaleV = maxVal / maxSamp;
365  for (outBufNum = 0; outBufNum < numChans; outBufNum++) {
366  bbuffer = mBuffers[outBufNum];
367  for (i = 0; i < numFrames; i++) {
368  *bbuffer *= scaleV;
369  bbuffer++;
370  }
371  }
372  return maxSamp;
373 }
374 
375 // normalize the given region only
376 
377 float Buffer::normalize(float maxVal, float from, float to) {
378  float * bbuffer = NULL;
379  unsigned outBufNum, i;
380  unsigned numChans = mNumChannels;
381  unsigned numFrames = mNumFrames;
382  float maxSamp = 0.0f;
383  unsigned samp0 = (unsigned)(from * CGestalt::frameRateF());
384  unsigned sampN = (unsigned)(to * CGestalt::frameRateF());
385 
386  for (outBufNum = 0; outBufNum < numChans; outBufNum++) {
387  bbuffer = mBuffers[outBufNum] + samp0;
388  for (i = samp0; i < sampN; i++) {
389  float samp = fabs(*bbuffer++);
390  if (samp > maxSamp)
391  maxSamp = samp;
392  }
393  }
394  if (maxSamp == 0.0f)
395  return maxSamp;
396  if (maxSamp == maxVal)
397  return maxSamp;
398  float scaleV = maxVal / maxSamp;
399  for (outBufNum = 0; outBufNum < numChans; outBufNum++) {
400  bbuffer = mBuffers[outBufNum] + samp0;
401  for (i = samp0; i < sampN; i++) {
402  *bbuffer *= scaleV;
403  bbuffer++;
404  }
405  }
406  return maxSamp;
407 }
408 
409 #ifdef USE_SRC // sample-rate conversion methods
410 
411 // convert the sample rate using libSampleRate
412 
413 Status Buffer::convertRate(int fromRate, int toRate) {
414  double src_ratio = (double) toRate / (double) fromRate;
415  int error;
416  // scaled buffer length
417  unsigned newLen = (unsigned) (rint(((double) mNumFrames) * src_ratio));
418  SRC_STATE * src_state; // SRC structs
419  SRC_DATA src_data;
420  // create/allocate new scaled buffer
421  Buffer * newBuf = new Buffer(mNumChannels, newLen);
422  newBuf->allocateBuffers();
423 
424 // logMsg("Buffer::convertRate from %d to %d = %d frames", fromRate, toRate, newLen);
425  // create temp name and rename file
426  src_ratio = (double) toRate / (double) fromRate;
427  if (src_is_valid_ratio (src_ratio) == 0) {
428  logMsg (kLogError, "Error: Sample rate change out of valid range.");
429  return kErr;
430  }
431  /* Initialize the sample rate converter. */
432  if ((src_state = src_new (SRC_SINC_FASTEST /* SRC_SINC_BEST_QUALITY */, 1, &error)) == NULL) {
433  logMsg ("Error : src_new() failed : %s.", src_strerror (error));
434  exit (1);
435  };
436  src_data.src_ratio = src_ratio; // set up SRC
437  src_data.input_frames = mNumFrames;
438  src_data.output_frames = newLen;
439  src_data.end_of_input = 1;
440  // loop over the channels
441  for (unsigned i = 0; i < mNumChannels; i++) {
442  src_data.data_in = mBuffers[i];
443  src_data.data_out = newBuf->buffer(i);
444  // call src_process
445  error = src_process(src_state, &src_data);
446  if (error) {
447  logMsg("SRC Error : %s", src_strerror(error));
448  return kErr;
449  }
450  }
451  src_state = src_delete (src_state);
452  this->copyFrom(*newBuf); // copy sample pointers to me
453  mDidIAllocateBuffers = true; // toggle ownership flags
454  newBuf->mDidIAllocateBuffers = false;
455  delete newBuf;
456  return kOk;
457 }
458 
459 #endif
460 
461 ///////////////////////////////////
462 
463 ///< get the root-mean-square of the samples
464 
465 sample Buffer::rms(unsigned chan, unsigned from, unsigned to) {
466  unsigned theCh = chan % mNumChannels;
467  unsigned numFrames = mNumFrames;
468  sample val, sum = 0.0;
469  sample* buffer = mBuffers[theCh];
470  unsigned cnt = 0;
471  for (unsigned i = from; i < to; i++) {
472  val = *buffer++;
473  if (isnan(val)) continue;
474  if (isinf(val)) continue;
475  sum += (val * val); // sum squared samples
476  cnt++;
477  }
478  return sum / cnt;
479 }
480 
481 ///< get the average of the samples
482 
483 sample Buffer::avg(unsigned chan, unsigned from, unsigned to) {
484  unsigned thech = chan % mNumChannels;
485  unsigned numFrames = mNumFrames;
486  sample sum = 0.0;
487  sample* buffer = mBuffers[thech];
488  for (unsigned i = 0; i < numFrames; i++)
489  sum += *buffer++;
490  return sum / numFrames;
491 }
492 
493 ///< get the max of the samples
494 
495 sample Buffer::max(unsigned chan, unsigned from, unsigned to) {
496  unsigned thech = chan % mNumChannels;
497  unsigned numFrames = mNumFrames;
498  sample val, tmax = 0.0;
499  sample* buffer = mBuffers[thech];
500  for (unsigned i = 0; i < numFrames; i++) {
501  val = *buffer++;
502  if (fabs(val) > tmax) tmax - fabs(val);
503  }
504  return tmax;
505 }
506 
507 ///< get the min of the samples
508 
509 sample Buffer::min(unsigned chan, unsigned from, unsigned to) {
510  unsigned thech = chan % mNumChannels;
511  unsigned numFrames = mNumFrames;
512  sample val, tmax = 0.0;
513  sample* buffer = mBuffers[thech];
514  for (unsigned i = 0; i < numFrames; i++) {
515  val = *buffer++;
516  if (fabs(val) > tmax) tmax - fabs(val);
517  }
518  return tmax;
519 }
520 
521 #ifdef CSL_DSP_BUFFER /// Buffer Sample Processing (optional)
522 
523 #include <libtsp.h> // for the autocorrelation
524 
525 ///< count the zero-crossings in the samples
526 
527 unsigned int Buffer::zeroX(unsigned chan) {
528  unsigned thech = chan % mNumChannels;
529  unsigned numFrames = mNumFrames, count = 0, sign = 0;
530  sample val;
531  sample* buffer = mBuffers[thech];
532  for (unsigned i = 0; i < numFrames; i++) {
533  val = *buffer++;
534  if (((val > 0) && sign) || ((val < 0) && ! sign)) {
535  count += 1;
536  sign = 1 - sign;
537  }
538  }
539  return count;
540 }
541 
542 ///< answer the index of the peak value
543 
544 unsigned int Buffer::indexOfPeak(unsigned chan) {
545  unsigned thech = chan % mNumChannels;
546  unsigned numFrames = mNumFrames, index;
547  sample val, tmax = -1000000.0;
548  sample* buffer = mBuffers[thech];
549  for (unsigned i = 0; i < numFrames; i++) {
550  val = *buffer++;
551  if (val > tmax) {
552  tmax = val;
553  index = i;
554  }
555  }
556  return index;
557 }
558 
559 ///< answer the index of the peak value
560 
561 unsigned int Buffer::indexOfPeak(unsigned chan, unsigned lo, unsigned hi) {
562  unsigned index = 0, thech = chan % mNumChannels;
563  sample val, tmax = -100000.0;
564  sample* buffer = mBuffers[thech] + lo;
565  for (unsigned i = lo; i < hi; i++) {
566  val = *buffer++;
567  if (val > tmax) {
568  tmax = val;
569  index = i;
570  }
571  }
572  return index;
573 }
574 
575 ///< answer the index of the peak value
576 
577 unsigned int Buffer::indexOfMin(unsigned chan) {
578  unsigned thech = chan % mNumChannels;
579  unsigned numFrames = mNumFrames, index;
580  sample val, tmin = 1000000.0;
581  sample* buffer = mBuffers[thech];
582  for (unsigned i = 0; i < numFrames; i++) {
583  val = *buffer++;
584  if (val < tmin) {
585  tmin = val;
586  index = i;
587  }
588  }
589  return index;
590 }
591 
592 ///< answer the index of the peak value
593 
594 unsigned int Buffer::indexOfMin(unsigned chan, unsigned lo, unsigned hi) {
595  unsigned index = 0, thech = chan % mNumChannels;
596  sample val, tmin = 1000000.0;
597  sample* buffer = mBuffers[thech] + lo;
598  for (unsigned i = lo; i < hi; i++) {
599  val = *buffer++;
600  if (val < tmin) {
601  tmin = val;
602  index = i;
603  }
604  }
605  return index;
606 }
607 
608 ///< write the autocorrelation into the given array
609 
610 void Buffer::autocorrelation(unsigned chan, SampleBuffer result) {
611  unsigned thech = chan % mNumChannels;
612  unsigned numFrames = mNumFrames;
613  sample* buffer = mBuffers[thech];
614  // SPautoc (const float in[], int in_size, float out[], int out_size)
615  // - out[i] is autocorrelation with lag i
616  SPautoc (buffer, numFrames, result, numFrames); // perform autocorrelation
617 }
618 
619 #endif // CSL_DSP_BUFFER
620 
621 
622 // Sample buffer with channel map and count
623 // the map is so that one can have (e.g.,) a buffer that stands for 3 channels within an 8-channel space
624 
626 
627 BufferCMap::BufferCMap(unsigned numChannels, unsigned numFrames) :
628  Buffer(numChannels, numFrames),
629  mRealNumChannels(numChannels) { }
630 
631 BufferCMap::BufferCMap(unsigned numChannels, unsigned realNumChannels, unsigned numFrames) :
632  Buffer(numChannels, numFrames),
633  mRealNumChannels(realNumChannels) { }
634 
636 
637 
638 //-------------------------------------------------------------------------------------------------//
639 //
640 // UnitGenerator implementation
641 //
642 
643 #pragma mark UnitGenerator
644 
645 // mono by default
646 
647 UnitGenerator::UnitGenerator(unsigned rate, unsigned chans) : Model(),
648  mFrameRate(rate),
649  mNumChannels(chans),
650  mCopyPolicy(kCopy),
651  mNumOutputs(0),
652  mOutputCache(0),
653  mSequence(0)
654  /* mName(0) */
655  { }
656 
657 ///< Destructor
658 
660 // logMsg(" ~UnitGenerator %x", this);
661 }
662 
663 void UnitGenerator::zeroBuffer(Buffer & outputBuffer, unsigned outBufNum) {
664  float * buffer = outputBuffer.buffer(outBufNum);
665  memset(buffer, 0, outputBuffer.mMonoBufferByteSize);
666 }
667 
668 // output management and auto-fan-out
669 
671 // logMsg("UnitGenerator::addOutput %x to %x", ugen, this);
672  mOutputs.push_back(ugen); // if adding the 2nd output, set up fan-out cache
673  if ((mNumOutputs == 1) && (mOutputCache == 0)) {
674  mOutputCache = new Buffer(mNumChannels, CGestalt::blockSize());
676  }
677  mNumOutputs++;
678 }
679 
681  UGenVector::iterator pos;
682  for (pos = mOutputs.begin(); pos != mOutputs.end(); ++pos) {
683  if (*pos == ugen) {
684  mOutputs.erase(pos);
685  break;
686  }
687  }
688  mNumOutputs--;
689 }
690 
691 // pretty-print the receiver
692 
694  logMsg("a UnitGenerator with %d outputs", mOutputs.size());
695 }
696 
697 // check for fan-out; if fanning out, copy previous buffer & return true
698 
699 bool UnitGenerator::checkFanOut(Buffer & outputBuffer) throw (CException) {
700  if (mNumOutputs > 1) { // if we're doing auto-fan-out
701  if (outputBuffer.mSequence <= mSequence) { // if we've already computed this seq #
702  // and block copy samples from the cache into the output
703  outputBuffer.copyOnlySamplesFrom(*mOutputCache);
704 // logMsg("UnitGenerator::checkFanOut");
705  return true; // finished!
706  }
707  }
708  return false;
709 }
710 
711 // if fanning out, store last output and set seq number
712 
713 void UnitGenerator::handleFanOut(Buffer & outputBuffer) throw (CException) {
714  if (mNumOutputs > 1) // if we're doing auto-fan-out and this is the first time
715  mOutputCache->copySamplesFrom(outputBuffer); // store it in the buffer
716  mSequence = csl_max(mSequence, outputBuffer.mSequence); // remember my seq #
717 // this->changed((void *) & outputBuffer); // signal dependents (if any) of my change
718 }
719 
720 //
721 // Generic next buffer function: call the private (mono) version for each I/O channel;
722 // copy or expand depending on the mCopyPolicy;
723 // copy to the private cache in case of fan-out.
724 //
725 
726 void UnitGenerator::nextBuffer(Buffer & outputBuffer) throw (CException) {
727  unsigned numOutputChannels = outputBuffer.mNumChannels;
728  unsigned bufferByteSize = outputBuffer.mMonoBufferByteSize;
729  SampleBuffer buffer0 = outputBuffer.buffer(0);
730 #ifdef CSL_DEBUG
731  logMsg("UnitGenerator::nextBuffer");
732 #endif
733  if (checkFanOut(outputBuffer)) return;
734  // Copy the output buffer samples
735  switch (mCopyPolicy) {
736  default:
737  case kCopy: // compute 1 channel and copy it
738  this->nextBuffer(outputBuffer, 0); // this is where most of the work gets done in CSL
739  for (unsigned i = 1; i < numOutputChannels; i += mNumChannels)
740  memcpy (outputBuffer.buffer(i), buffer0, bufferByteSize);
741  break;
742  case kExpand: // loop through the requested output channels
743  for (unsigned i = 0; i < numOutputChannels; i += mNumChannels)
744  nextBuffer(outputBuffer, i); // call private nextBuffer per-channel
745  break;
746  case kIgnore: // Only do as many channels as I have
747  this->nextBuffer(outputBuffer, 0);
748  break;
749  }
750  handleFanOut(outputBuffer); // process possible fan-out
751 }
752 
753 // Generic private next buffer implementation; by default, just zero out the buffer
754 
755 void UnitGenerator::nextBuffer(Buffer & outputBuffer, unsigned outBufNum) throw (CException) {
756  for (unsigned i = 0; i < mNumChannels; i++)
757  zeroBuffer(outputBuffer, i); // my subclasses do more interesting things here
758 }
759 
760 //-------------------------------------------------------------------------------------------------//
761 //
762 // Port implementation
763 
764 #pragma mark Port
765 
767  mUGen(NULL),
768  mBuffer(new Buffer(1, CGestalt::blockSize())),
769  mValue(0),
770  mValuePtr(& mValue),
771  mPtrIncrement(0) { }
772 
774  mUGen(ug),
775  mBuffer(new Buffer(ug->numChannels(), CGestalt::blockSize())),
776  mValue(0),
777  mPtrIncrement(1) {
779  mValuePtr = mBuffer->buffer(0) - 1; // set to -1 since nextValue does pre-increment
780 }
781 
782 Port::Port(float value) :
783  mUGen(NULL),
784  mBuffer(NULL),
785  mValue(value),
786  mValuePtr(& mValue),
787  mPtrIncrement(0) { }
788 
790 
791 
792 }
793 
794 // check the port's buffer and allocate it if needed
795 
797  Buffer * buf = mBuffer;
798  UnitGenerator * ug = mUGen;
799 
800  if (buf == 0)
801  throw LogicError("Checking an unassigned buffer");
802  if ((buf->mNumChannels != ug->numChannels()) || (buf->mNumFrames == 1)) {
803  buf->freeBuffers();
804  buf->setSize(ug->numChannels(), CGestalt::blockSize());
805  buf->allocateBuffers();
806  }
807 }
808 
809 // Call this to reset the pointer without re-pulling the input (see SumOfSines)
810 
812  if (mPtrIncrement) // if I'm dynamic
813  mValuePtr = (mBuffer->buffer(0)) - 1; // set to -1 since nextValue does pre-increment
814 }
815 
816 // Answer whether the receiver is active
817 
819  if (mUGen == NULL)
820  return (true);
821  else
822  return mUGen->isActive();
823 }
824 
825 // pretty-print the receiver
826 
827 void Port::dump() {
828  logMsg("a Port with UGen = %x, value = %g, incr = %d", mUGen, mValue, mPtrIncrement);
829  if (mUGen != 0) {
830  fprintf(stderr, "\t");
831  mUGen->dump();
832  }
833 }
834 
835 //-------------------------------------------------------------------------------------------------//
836 //
837 // Controllable implementation -- Grab the dynamic values for the scale and offset controls
838 
839 ///< Destructor
840 
842  for (PortMap::iterator pos = mInputs.begin(); pos != mInputs.end(); pos++)
843  delete (pos->second);
844  mInputs.clear();
845 }
846 
847 void Controllable::pullInput(Port * thePort, unsigned numFrames) throw (CException) {
848 #ifdef CSL_DEBUG
849  logMsg("Controllable::pullInput");
850 #endif
851  if (thePort == NULL) {
852  logMsg("Controllable::pullInput port == null!");
853  return;
854  }
855  UnitGenerator * theUG = thePort->mUGen; // get its UGen
856  if (theUG == NULL) { // if it's a static variable
857 // logMsg("Controllable::pullInput UG == null!");
858  return; // ignore it
859  }
860  Buffer * theBuffer = thePort->mBuffer; // else get the buffer
861  if (theBuffer == NULL) { // if it's a static variable
862  logMsg("Controllable::pullInput Buffer == null!");
863  return; // ignore it
864  }
865  thePort->checkBuffer();
866  theBuffer->mNumFrames = numFrames;
867  theBuffer->mType = kSamples;
868  theBuffer->zeroBuffers();
869 
870  theUG->nextBuffer(* theBuffer); //////// and ask the UGen for nextBuffer()
871 
872  theBuffer->mIsPopulated = true;
873  thePort->mValuePtr = (thePort->mBuffer->buffer(0)) - 1;
874  thePort->mValueIndex = 0;
875 }
876 
877 // Controllable implementation -- this version writes into the buffer you pass it
878 
879 void Controllable::pullInput(Port * thePort, Buffer & theBuffer) throw (CException) {
880  if (thePort == NULL)
881  return;
882  UnitGenerator * theUG = thePort->mUGen; // get its UGen
883  if (theUG == NULL) // if it's a static variable
884  return; // ignore it
885  theUG->nextBuffer(theBuffer); ///////// and ask the UGen for nextBuffer()
886 
887  theBuffer.mIsPopulated = true;
888  thePort->mValuePtr = (theBuffer.buffer(0)) - 1;
889  thePort->mValueIndex = 0;
890 }
891 
892 // Plug in a unit generator to the named input slot
893 
895 #ifdef CSL_DEBUG
896  logMsg("Controllable::set input \"%d\" UGen", key);
897 #endif
898  Port * thePort = mInputs[key]; // get the named port
899  if (thePort != 0) // if port found
900  delete thePort;
901  thePort = new Port(&uGen);
902  mInputs[key] = thePort; // add it to the list of inputs
903  uGen.addOutput((UnitGenerator *) this); // be sure to add me as an output of the other guy
904 }
905 
906 void Controllable::addInput(CSL_MAP_KEY key, float value) {
907 #ifdef CSL_DEBUG
908  logMsg("Controllable::set input \"%d\" to %g", key, value);
909 #endif
910  Port * thePort = mInputs[key]; // get the named port
911  if (thePort == 0) { // if no port found
912  thePort = new Port(value);
913  mInputs[key] = thePort; // add it to the list of inputs
914  } else
915  thePort->mValue = value;
916 }
917 
918 // get a port
919 
921  return(mInputs[name]);
922 }
923 
924 // Pretty-print the receiver
925 
927  logMsg("a Controllable with the map:");
928  for (PortMap::iterator pos = mInputs.begin(); pos != mInputs.end(); ++pos) {
929  switch (pos->first) {
930  case CSL_FREQUENCY:
931  logMsg(" key: Frequency = UG: ");
932  break;
933  case CSL_SCALE:
934  logMsg(" key: Scale = UG: ");
935  break;
936  case CSL_OFFSET:
937  logMsg(" key: Offset = UG: ");
938  break;
939  case CSL_INPUT:
940 // case CSL_INPUT_L:
941 // case CSL_INPUT_R:
942  logMsg(" key: Input = UG: ");
943  break;
944  default:
945  logMsg(" key: Other = UG: ");
946 
947  }
948  pos->second->dump(); // go up the graph tree dumping inputs and controls
949  }
950 }
951 
952 /////////////////////////////////////////////////
953 //
954 // Phased implementation -- Constructors
955 
956 Phased::Phased() : Controllable(), mPhase(0.0f) {
957  mInputs[CSL_FREQUENCY] = new Port;
958 #ifdef CSL_DEBUG
959  logMsg("Phased::add freq input");
960 #endif
961 }
962 
963 Phased::Phased(UnitGenerator & frequency, float phase) : mPhase(phase) {
964  this->addInput(CSL_FREQUENCY, frequency);
965 #ifdef CSL_DEBUG
966  logMsg("Phased::add freq input");
967 #endif
968 }
969 
970 Phased::Phased(float frequency, float phase) : mPhase(phase) {
971  this->addInput(CSL_FREQUENCY, frequency);
972 #ifdef CSL_DEBUG
973  logMsg("Phased::add freq input");
974 #endif
975 }
976 
977 Phased::~Phased() { /* ?? */ }
978 
979 // Accessors
980 
982  this->addInput(CSL_FREQUENCY, frequency);
983 }
984 
985 void Phased::setFrequency(float frequency) {
986  this->addInput(CSL_FREQUENCY, frequency);
987 }
988 
989 // Scalable -- Constructors
990 
992  mInputs[CSL_SCALE] = new Port;
993  mInputs[CSL_OFFSET] = new Port;
994 #ifdef CSL_DEBUG
995  logMsg("Scalable::add null inputs");
996 #endif
997 }
998 
999 Scalable::Scalable(float scale) {
1000  this->addInput(CSL_SCALE, scale);
1001  mInputs[CSL_OFFSET] = new Port;
1002 #ifdef CSL_DEBUG
1003  logMsg("Scalable::add scale input");
1004 #endif
1005 }
1006 
1007 Scalable::Scalable(float scale, float offset) {
1008  this->addInput(CSL_SCALE, scale);
1009  this->addInput(CSL_OFFSET, offset);
1010 #ifdef CSL_DEBUG
1011  logMsg("Scalable::add scale/offset input values");
1012 #endif
1013 }
1014 
1015 Scalable::Scalable(UnitGenerator & scale, float offset) {
1016  this->addInput(CSL_SCALE, scale);
1017  this->addInput(CSL_OFFSET, offset);
1018 #ifdef CSL_DEBUG
1019  logMsg("Scalable::add scale/offset input values");
1020 #endif
1021 }
1022 
1024  this->addInput(CSL_SCALE, scale);
1025  this->addInput(CSL_OFFSET, offset);
1026 #ifdef CSL_DEBUG
1027  logMsg("Scalable::add scale/offset input values");
1028 #endif
1029 }
1030 
1032 // if (mInputs) {
1033 //
1034 // }
1035 }
1036 
1037 // Scalable -- Accessors
1038 
1040  this->addInput(CSL_SCALE, scale);
1041 #ifdef CSL_DEBUG
1042  logMsg("Scalable::set scale input UG");
1043 #endif
1044 }
1045 
1046 void Scalable::setScale(float scale) {
1047  this->addInput(CSL_SCALE, scale);
1048 #ifdef CSL_DEBUG
1049  logMsg("Scalable::set scale input value");
1050 #endif
1051 }
1052 
1054  this->addInput(CSL_OFFSET, offset);
1055 #ifdef CSL_DEBUG
1056  logMsg("Scalable::set offset input UG");
1057 #endif
1058 }
1059 
1060 void Scalable::setOffset(float offset) {
1061  this->addInput(CSL_OFFSET, offset);
1062 #ifdef CSL_DEBUG
1063  logMsg("Scalable::set offset input value");
1064 #endif
1065 }
1066 
1067 // trigger passed on here
1068 
1070  if (mInputs[CSL_SCALE])
1071  mInputs[CSL_SCALE]->trigger();
1072  if (mInputs[CSL_OFFSET])
1073  mInputs[CSL_OFFSET]->trigger();
1074 }
1075 
1076 // answer whether scale = 1 & offset = 0
1077 
1078 //void isScaled() {
1079 //
1080 //}
1081 
1082 /////////////////////////////////////////////////
1083 //
1084 // Effect implementation
1085 
1086 #pragma mark Effect
1087 
1089  isInline = false;
1090 // mInputs[CSL_INPUT] = new Port;
1091 #ifdef CSL_DEBUG
1092  logMsg("Effect::add null input");
1093 #endif
1094 }
1095 
1097  isInline = false;
1098  mNumChannels = input.numChannels();
1099  this->addInput(CSL_INPUT, input);
1100 #ifdef CSL_DEBUG
1101  logMsg("Effect::add input UG");
1102 #endif
1103 }
1104 
1106  Port * iPort = mInputs[CSL_INPUT];
1107  if (iPort)
1108  return (iPort->isActive());
1109  return true; // subclasses might not use mInputs[CSL_INPUT]
1110 }
1111 
1113  isInline = false;
1114  this->addInput(CSL_INPUT, input);
1115 #ifdef CSL_DEBUG
1116  logMsg("Effect::add input");
1117 #endif
1118 }
1119 
1120 // Get my input's next buffer
1121 
1122 void Effect::pullInput(Buffer & outputBuffer) throw (CException) {
1123 #ifdef CSL_DEBUG
1124  logMsg("Effect::pullInput");
1125 #endif
1126  if (isInline) // if inline, just use the input pointer
1127  mInputPtr = outputBuffer.buffer(0);
1128  else {
1129  Port * iPort = mInputs[CSL_INPUT];
1130  // else pull a buffer from my input
1131  Controllable::pullInput(iPort, outputBuffer);
1132 
1133  mInputPtr = outputBuffer.buffer(0);
1134  }
1135 }
1136 
1137 void Effect::pullInput(unsigned numFrames) throw (CException) {
1138 #ifdef CSL_DEBUG
1139  logMsg("Effect::pullInput");
1140 #endif
1141  Port * iPort = mInputs[CSL_INPUT];
1142  Controllable::pullInput(iPort, numFrames);
1143  mInputPtr = iPort->mBuffer->buffer(0);
1144 }
1145 
1146 ///< trigger passed on here
1147 
1149  if (mInputs[CSL_INPUT])
1150  mInputs[CSL_INPUT]->trigger();
1151 }
1152 
1153 // FanOut methods
1154 
1155 FanOut::FanOut(UnitGenerator & in, unsigned taps)
1156  : Effect(in), mNumFanOuts(taps), mCurrent(taps) {
1157 #ifdef CSL_DEBUG
1158  logMsg("FanOut::FanOut %d", mNumFanOuts);
1159 #endif
1160 }
1161 
1162 void FanOut::nextBuffer(Buffer & outputBuffer, unsigned outBufNum) throw (CException) {
1163  throw LogicError("Asking for mono nextBuffer of a FanOut");
1164 }
1165 
1166 // nextBuffer just pulls the input every "mOutputs" calls
1167 
1168 void FanOut::nextBuffer(Buffer & outputBuffer) throw (CException) {
1169  if (outputBuffer.mNumChannels != mNumChannels)
1170  throw LogicError("Asking for wrong output ch # of a FanOut");
1171  if (mCurrent >= mNumFanOuts) {
1172  pullInput(outputBuffer.mNumFrames);
1173  mCurrent = 0;
1174 // logMsg(" reset");
1175  } // Copy the output buffer samples
1176  Buffer * buf = mInputs[CSL_INPUT]->mBuffer;
1177  outputBuffer.copyOnlySamplesFrom(*buf);
1178 // logMsg("FanOut %d", mCurrent);
1179  mCurrent++;
1180 }
1181 
1182 // Splitter class -- a de-multiplexer for multi-channel signals
1183 
1185  : FanOut(in, in.numChannels()) { }
1186 
1187 void Splitter::nextBuffer(Buffer & outputBuffer, unsigned outBufNum) throw (CException) {
1188  throw LogicError("Asking for mono nextBuffer of a Splitter");
1189 }
1190 
1191 // Like for FanOut, next-buffer calls the input every mOutput calls,
1192 // but it only copies one channel at a time to the output
1193 
1194 void Splitter::nextBuffer(Buffer & outputBuffer) throw (CException) {
1195  if (outputBuffer.mNumChannels != 1)
1196  throw LogicError("Asking for a stereo output of a channel splitter");
1197  // pull input
1198  if (mCurrent >= mNumFanOuts) {
1199  pullInput(outputBuffer.mNumFrames);
1200  mCurrent = 0;
1201  }
1202  Buffer * buf = mInputs[CSL_INPUT]->mBuffer;
1203  if (buf == 0)
1204  throw LogicError("Missing buffer in channel splitter");
1205  unsigned bufferByteSize = outputBuffer.mMonoBufferByteSize;
1206  SampleBuffer dest = outputBuffer.buffer(0);
1207  SampleBuffer src = buf->buffer(mCurrent);
1208  memcpy(dest, src, bufferByteSize);
1209  mCurrent++;
1210 }
1211 
1212 // Joiner class -- a multiplexer for multi-channel signals
1213 
1215  Controllable::addInput(0, in1);
1216  Controllable::addInput(1, in2);
1217  mNumChannels = 2;
1218 }
1219 
1220 void Joiner::addInput(UnitGenerator & in) { ///< add the argument to vector of inputs
1221  Controllable::addInput(mNumChannels, in);
1222  mNumChannels++;
1223 }
1224 
1226  for (unsigned i = 0; i < mNumChannels; i++) {
1227  if (mInputs[i]->mUGen->isActive())
1228  return true;
1229  }
1230  return false;
1231 }
1232 
1233 
1234 void Joiner::nextBuffer(Buffer & outputBuffer, unsigned outBufNum) throw (CException) {
1235  throw LogicError("Asking for mono nextBuffer of a Joiner");
1236 }
1237 
1238 // nextBuffer calls each of the input channels as a mono channel
1239 
1240 void Joiner::nextBuffer(Buffer & outputBuffer) throw (CException) {
1241  if (outputBuffer.mNumChannels != mNumChannels) {
1242  throw LogicError("Wrong number of channels in a joiner");
1243  }
1244  // set up the fake mono buffer
1245  Buffer tempBuffer(1, outputBuffer.mNumFrames);
1246 
1247  // loop through the mono inputs
1248  for (unsigned i = 0; i < mNumChannels; i++) {
1249  // put the mono in samples into 1 channel of the output
1250  tempBuffer.setBuffer(0, outputBuffer.buffer(i));
1251  // get a buffer of mono samples from one of the inputs
1252  mInputs[i]->mUGen->nextBuffer(tempBuffer);
1253  }
1254 }
1255 
1256 ///< trigger passed on here
1257 
1259  for (unsigned i = 0; i < mNumChannels; i++)
1260  mInputs[i]->trigger();
1261 }
1262 
1263 // Writeable implementation
1264 
1265 void Writeable::writeBuffer(Buffer & inputBuffer, unsigned bufNum) throw (CException) {
1266  // no-op here
1267 }
1268 
1269 void Writeable::writeBuffer(Buffer & inputBuffer) throw (CException) {
1270  unsigned numBufs = inputBuffer.mNumChannels;
1271  for (unsigned i = 0; i < numBufs; i++)
1272  writeBuffer(inputBuffer, i);
1273 }
1274 
1275 // Seekable
1276 
1277 void Seekable::reset() throw (CException) { // reset-to-zero
1278  int pos = seekTo(0, kPositionStart);
1279  if (pos == 0)
1280  throw IOError("Error seeking");
1281 }
1282 
1283 // Interleave = copy from CSL-style Buffer object to an interleaved sample vector
1284 
1286  unsigned numFrames, unsigned numChannels) throw (CException) {
1287 
1288  unsigned numOutputChannels = output.mNumChannels;
1289  unsigned numChannelsToInterleave = csl_min(numOutputChannels, numChannels);
1290  unsigned numChannelsBeyond = numChannels - numChannelsToInterleave;
1291 
1292  for (unsigned frame = 0; frame < numFrames; frame++) {
1293  for (unsigned channel = 0; channel < numChannelsToInterleave; channel++)
1294  *samples++ = output.buffer(channel)[frame];
1295  for (unsigned j = 0; j < numChannelsBeyond; j++)
1296  *samples++ = 0;
1297  }
1298 }
1299 
1300 // Interleave, short * version
1301 
1302 void Interleaver::interleave(Buffer & output, short * samples, unsigned numFrames,
1303  unsigned numChannels) throw (CException) {
1304 
1305  unsigned numOutputChannels = output.mNumChannels;
1306  unsigned numChannelsToInterleave = csl_min(numOutputChannels, numChannels);
1307  unsigned numChannelsBeyond = numChannels - numChannelsToInterleave;
1308 
1309  for (unsigned frame = 0; frame < numFrames; frame++) {
1310  for (unsigned channel = 0; channel < numChannelsToInterleave; channel++)
1311  *samples++ = (short) ((output.buffer(channel)[frame]) * 32767.0);
1312  for (unsigned j = 0; j < numChannelsBeyond; j++)
1313  *samples++ = 0;
1314  }
1315 }
1316 
1317 /// Remap = re-assign channels from the source buffer to the target while interleaving
1318 
1319 void Interleaver::interleaveAndRemap(Buffer & output, SampleBuffer samples, unsigned numFrames,
1320  unsigned numChannels, unsigned *channelMap) throw (CException) {
1321 
1322  unsigned numOutputChannels = output.mNumChannels;
1323  unsigned numChannelsToInterleave = csl_min(numOutputChannels, numChannels);
1324  unsigned numChannelsBeyond = numChannels - numChannelsToInterleave;
1325  unsigned *map = channelMap;
1326 
1327  for (unsigned frame = 0; frame < numFrames; frame++) {
1328  for (unsigned channel = 0; channel < numChannelsToInterleave; channel++)
1329  *samples++ = output.buffer(map[channel])[frame];
1330  for (unsigned j = 0; j < numChannelsBeyond; j++)
1331  *samples++ = 0;
1332  }
1333 }
1334 
1335 // De-interleave = copy from interleaved SampleBuffer to CSL Buffer object
1336 
1337 void Interleaver::deinterleave(Buffer & output, SampleBuffer samples, unsigned numFrames,
1338  unsigned numChannels) throw (CException) {
1339 
1340  unsigned numOutputChannels = output.mNumChannels;
1341  unsigned numChannelsToDeinterleave = csl_min(numOutputChannels, numChannels);
1342  SampleBuffer currentOutputBuffer;
1343  SampleBuffer inputBuffer;
1344  unsigned i;
1345 
1346  for (i = 0; i < numChannelsToDeinterleave; i++) {
1347  currentOutputBuffer = output.buffer(i);
1348  inputBuffer = samples + i;
1349  for (unsigned j = 0; j < numFrames; j++, inputBuffer += numChannels) {
1350  *currentOutputBuffer++ = *inputBuffer;
1351  }
1352  }
1353  if (numOutputChannels > numChannelsToDeinterleave) {
1354  for (i = numChannelsToDeinterleave; i < numOutputChannels; i++)
1355  memset(output.buffer(i), 0, output.mMonoBufferByteSize);
1356  }
1357 }
1358 
1359 // De-interleave, short * version
1360 
1361 void Interleaver::deinterleave(Buffer & output, short * samples, unsigned numFrames,
1362  unsigned numChannels) throw (CException) {
1363 
1364  unsigned numOutputChannels = output.mNumChannels;
1365  unsigned numChannelsToDeinterleave = csl_min(numOutputChannels, numChannels);
1366  SampleBuffer currentOutputBuffer;
1367  short * inputBuffer;
1368  unsigned i;
1369 
1370  for (i = 0; i < numChannelsToDeinterleave; i++) {
1371  currentOutputBuffer = output.buffer(i);
1372  inputBuffer = samples + i;
1373  for (unsigned j = 0; j < numFrames; j++, inputBuffer += numChannels) {
1374  *currentOutputBuffer++ = ((float )*inputBuffer) / 32767.0f;
1375  }
1376  }
1377  if (numOutputChannels > numChannelsToDeinterleave) {
1378  for (i = numChannelsToDeinterleave; i < numOutputChannels; i++)
1379  memset(output.buffer(i), 0, output.mMonoBufferByteSize);
1380  }
1381 }
1382 
1383 //////////////////////////// IO class methods /////////////////////////////////
1384 
1385 // Global array of all known IO devices
1386 
1387 vector < IODevice *> gIODevices;
1388 
1389 // General IO Constructors in all modes
1390 
1391 #pragma mark IO
1392 
1393 IO::IO(unsigned s_rate, unsigned b_size, int in_device, int out_device,
1394  unsigned in_chans, unsigned out_chans)
1395  : mGraph(NULL), mInputBuffer(0, 0), mOutputBuffer(0, 0), mCaptureBuffer(0, 0),
1396  mNumFramesPlayed(0), mSequence(0), mLoggingPeriod(CGestalt::loggingPeriod()),
1397  mNumInChannels(in_chans), mNumOutChannels(out_chans),
1398  mNumRealInChannels(in_chans), mNumRealOutChannels(out_chans),
1399  mStatus(kIONew), mInterleaved(false) {
1400  logMsg("Create IO: %d s @ %d Hz; %d i %d o", b_size, s_rate, in_chans, out_chans);
1401 }
1402 
1403 // set/clear the root generator
1404 
1406  root.addOutput((UnitGenerator *) this);
1407  mGraph = & root;
1408 }
1409 
1411  if (mGraph != NULL)
1412  mGraph->removeOutput((UnitGenerator *) this);
1413  mGraph = NULL;
1414 }
1415 
1416 // increment and answer my seq #
1417 
1419  mSequence++;
1420  return mSequence;
1421 }
1422 
1423 // IO method to call a CSL client's DSP graph
1424 
1425 void IO::pullInput(Buffer & outBuffer, SampleBuffer out) throw(CException) {
1426 
1427 #ifdef DO_TIMING
1428  static struct timeval * mte = & mThen;
1429  static struct timeval * mno = & mNow;
1430  GET_TIME(mte);
1431  maxSampEver = 0.0f;
1432 #endif
1433 // unsigned numFrames = outBuffer.mNumFrames;
1434 // unsigned numChans = outBuffer.mNumChannels;
1435 
1436  if (mGraph) {
1437  try {
1438  outBuffer.mSequence = this->getAndIncrementSequence();
1439 
1440  mGraph->nextBuffer(outBuffer); ////// call the graph's nextBuffer method //////
1441  if (mCaptureBuffer.mNumFrames > 0) {
1442  mCaptureBuffer.copySamplesFromTo(outBuffer, mOffset);
1443  mOffset += outBuffer.mNumFrames;
1444  }
1445  } catch (CException ex) {
1446  // handler: log error and play silence
1447  logMsg(kLogError, "An error occured in the CSL nextBuffer method: %s\n",
1448  ex.mMessage.c_str());
1449 // memset(out, 0, (numFrames * numChans * sizeof(sample)));
1450  }
1451  }
1452 #ifdef DO_TIMING
1453  GET_TIME(mno);
1454  printTimeStatistics(mno, mte, & mThisSec, & mTimeSum, & mTimeVals);
1455 #endif
1456 }
1457 
1458 #ifdef CSL_WINDOWS
1459 
1460 #ifdef DO_TIMING // DO_TIMING
1461 
1462 int (timeval *val, void * e) {
1463  LARGE_INTEGER ticksPerSecond;
1464  LARGE_INTEGER tick; // A point in time
1465  // get the high resolution counter's accuracy
1466  QueryPerformanceFrequency(&ticksPerSecond);
1467  float ticksPerUSecond = ticksPerSecond.QuadPart / 1000000;
1468  // what time is it?
1469  QueryPerformanceCounter(&tick);
1470  val->tv_sec = tick.QuadPart/ticksPerSecond.QuadPart;
1471  val->tv_usec = tick.QuadPart/ticksPerUSecond;
1472 // cerr << "Fraction: " << val->tv_sec << "/" << val->tv_usec << " " << ticksPerUSecond << endl;
1473  return 0;
1474 }
1475 #endif
1476 
1477 #endif
1478 
1479 // IO Timing method
1480 
1481 #ifdef DO_TIMING
1482 //#include "Mixer.h"
1483 //#include "Instrument.h"
1484 //extern std::vector<Instrument *> gInstLibrary;
1485 
1486 void IO::printTimeStatistics(struct timeval * now, struct timeval * then, long * thisSec,
1487  long * timeSum, long * timeVals) {
1488 
1489  if (now->tv_sec - * thisSec > (long) mLoggingPeriod) { // print stats once every so often
1490  *thisSec = now->tv_sec;
1491  if (*timeSum != 0.0) { // print and reset counters
1492  float cycleTime = (float) CGestalt::blockSize() * 1000000.0f / CGestalt::frameRateF();
1493  // remember % usage
1494  mUsage = (float) *timeSum / *timeVals * 100.0f / cycleTime;
1495  *timeVals = 0;
1496  *timeSum = 0;
1497  logMsg("\tCPU usage: %.2f percent (%5.3f).", mUsage, maxSampEver);
1498 // logMsg("\tIO: %d active clients", ((Mixer *) mGraph)->activeSources());
1499 // unsigned num_instruments = library.size();
1500 // for (unsigned i = 0; i < num_instruments; i++) {
1501 // Instrument * instr = library[i];
1502 // if (instr->graph()->isActive())
1503 // logMsg("\t\tInstrument %s.%d", instr->name().c_str(), i);
1504 // }
1505  }
1506  } else { // count blocks with active sounds and sum exec. times
1507  *timeVals += 1;
1508  *timeSum += SUB_TIMES(now, then);
1509  }
1510  // cerr << "here now/this: " << now->tvSec << " " << then->tvSec << endl;
1511 }
1512 
1513 #endif
1514 
1515 // Answer the most recent input buffer
1516 
1519 }
1520 
1521 // really get the desired format of input
1522 
1523 Buffer & IO::getInput(unsigned numFrames, unsigned numChannels) throw(CException) {
1524  if (mNumInChannels == 0)
1525  throw IOError("Can't get unopened input");
1526  if (mInterleaved) {
1527  Interleaver interleaver;
1528  interleaver.deinterleave(mInputBuffer, mInputPointer, numFrames, numChannels);
1529  mInputBuffer.mIsPopulated = true;
1530  }
1531  return(mInputBuffer);
1532 }
1533 
1534 // begin output capture
1535 
1536 void IO::capture_on(float dur) {
1539  mOffset = 0;
1540 }
1541 
1542 // begin output capture
1543 
1545  mCaptureBuffer.setSize(1, 0);
1546 }
1547 
1548 // answer the capture buffer
1549 
1551  return & mCaptureBuffer;
1552 }
1553 
1554 // IO Device
1555 
1556 IODevice::IODevice(char * name, unsigned index, unsigned maxIn, unsigned maxOut, bool isIn, bool isOut)
1557  : mIndex(index), mMaxInputChannels(maxIn), mMaxOutputChannels(maxOut),
1558  mIsDefaultIn(isIn), mIsDefaultOut(isOut) {
1559  strcpy(mName, name);
1560 }
1561 
1562 IODevice::IODevice(string name, unsigned index, unsigned maxIn, unsigned maxOut, bool isIn, bool isOut)
1563  : mIndex(index), mMaxInputChannels(maxIn), mMaxOutputChannels(maxOut),
1564  mIsDefaultIn(isIn), mIsDefaultOut(isOut) {
1565  strcpy(mName, name.c_str());
1566 }
1567 
1568 // pretty-print an IO Device
1569 
1571  logMsg(" IO: %d = %s - %d i %d o %g Hz%s%s",
1572  mIndex,
1573  mName,
1575  mFrameRate,
1576  (mIsDefaultIn ? " - def in" : ""),
1577  (mIsDefaultOut ? " - def out" : ""));
1578 }
sample * SampleBuffer
1-channel buffer data type, vector of (sample)
Definition: CSL_Types.h:194
bool mAreBuffersZero
have the buffers been zeroed out?
Definition: CSL_Core.h:123
void logMsg(const char *format,...)
These are the public logging messages.
Definition: CGestalt.cpp:292
#define CSL_FREQUENCY
Definition: CSL_Types.h:278
void pullInput(Buffer &outputBuffer)
Definition: CSL_Core.cpp:1122
virtual Buffer & getInput()
Get the current input from the sound card.
Definition: CSL_Core.cpp:1517
The Model/Observable/Subject class; instances of its subclasses should send themselves, this->changed(some_data); on "relevant" state changes; the code they inherit (from Model) manages updating the list of observer/dependent objects in that they each receive update(some_data); and can access the model-passed data (the model might pass "this").
Definition: CGestalt.h:258
unsigned mNumFrames
num frames used in each buffer
Definition: CSL_Core.h:113
virtual SampleBuffer samplePtrFor(unsigned channel, unsigned offset)
answer a samp ptr with offset
Definition: CSL_Core.cpp:183
virtual void setBuffer(unsigned bufNum, SampleBuffer sPtr)
Definition: CSL_Core.h:158
#define csl_min(a, b)
static unsigned mFrameRate
default sample rate (tested up to 96000)
Definition: CGestalt.cpp:32
csl::Status convertRate(int fromRate, int toRate)
convert the sample rate using libSampleRate
bool mAreBuffersAllocated
are the buffers allocated?
Definition: CSL_Core.h:120
call monoNextBuffer multiple times
Definition: CSL_Core.h:212
bool mIsDefaultIn
am i the default in?
Definition: CSL_Core.h:827
AdditiveInstrument.h – Sum-of-sines synthesis instrument class.
Definition: Accessor.h:17
void handleFanOut(Buffer &outputBuffer)
Definition: CSL_Core.cpp:713
Effect – mix-in for classes that have unit generators as inputs (like filters).
Definition: CSL_Core.h:466
void pullInput(Buffer &outBuffer, SampleBuffer out=0)
get a buffer from the CSL graph
Definition: CSL_Core.cpp:1425
Interleaver handles copying interleaved sample buffers (like sound files and inter-process sockets) t...
Definition: CSL_Core.h:672
float maxSampEver
Definition: CSL_Core.h:805
Splitter(UnitGenerator &in)
Constructor.
Definition: CSL_Core.cpp:1184
void copyHeaderFrom(Buffer &source)
copy the "header" fields of a buffer
Definition: CSL_Core.cpp:235
unsigned mIndex
index (API-specific)
Definition: CSL_Core.h:822
virtual unsigned seekTo(int position, SeekPosition whence)=0
general-purpose seek on a stream
Port()
Constructors: default is a float = 0.
Definition: CSL_Core.cpp:766
bool canStore(unsigned numFrames)
answer whether the recevei can store numFrames more frames
Definition: CSL_Core.cpp:197
char mName[CSL_NAME_LEN]
public members
Definition: CSL_Core.h:821
bool mIsDefaultOut
am i the default out?
Definition: CSL_Core.h:828
virtual ~Buffer()
Destructor de-allocated.
Definition: CSL_Core.cpp:59
void resetPtr()
reset the buffer pointer without re-pulling the input
Definition: CSL_Core.cpp:811
unsigned mSequence
sequence counter
Definition: CSL_Core.h:785
Illegal operation at run time.
virtual SampleBuffer buffer(unsigned bufNum)
convenience accessors for sample buffers
Definition: CSL_Core.cpp:66
virtual bool isActive()
am I active?
Definition: CSL_Core.cpp:1105
"OK" return status
void dump()
pretty-print the receiver
Definition: CSL_Core.cpp:827
unsigned mLoggingPeriod
logging period in seconds
Definition: CSL_Core.h:786
Phased()
Constructors; this one is rearely used.
Definition: CSL_Core.cpp:956
float mValue
my value (in case I'm fixed [mUGen == NULL])
Definition: CSL_Core.h:322
unsigned mPtrIncrement
the inter-sample ptr increment (0 for const, 1 for dynamic)
Definition: CSL_Core.h:324
void addOutput(UnitGenerator *ugen)
add to or return the UGen vector of outputs
Definition: CSL_Core.cpp:670
void copyOnlySamplesFrom(Buffer &src)
import data from the given buffer
Definition: CSL_Core.cpp:286
Buffer * mOutputCache
my past output ring buffer (only used in case of fan-out)
Definition: CSL_Core.h:296
Effect()
Constructors.
Definition: CSL_Core.cpp:1088
#define csl_max(a, b)
void copyFrom(Buffer &src)
Definition: CSL_Core.cpp:250
static float frameRateF()
default frame rate as a float
Definition: CGestalt.cpp:52
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
FanOut(UnitGenerator &in, unsigned taps)
Constructors.
Definition: CSL_Core.cpp:1155
void freeBuffers()
fcn to free them
Definition: CSL_Core.cpp:141
virtual bool isActive()
answer whether I'm active
Definition: CSL_Core.cpp:818
void deinterleave(Buffer &output, SampleBuffer samples, unsigned numFrames, unsigned numChannels)
De-interleave = copy from interleaved SampleBuffer to CSL Buffer object.
Definition: CSL_Core.cpp:1337
virtual void reset()
reset-to-zero
Definition: CSL_Core.cpp:1277
#define GET_TIME(val)
Definition: CSL_Core.h:700
void zeroBuffers()
fill all data with 0
Definition: CSL_Core.cpp:173
The CSL system defaults class.
Definition: CGestalt.h:39
Impossible operation.
virtual void dump()
pretty-print the receiver
Definition: CSL_Core.cpp:693
~Scalable()
Destructor.
Definition: CSL_Core.cpp:1031
void setSize(unsigned numChannels, unsigned numFrames)
Definition: CSL_Core.cpp:75
unsigned mNumFanOuts
the number of outputs
Definition: CSL_Core.h:625
SampleBufferVector mBuffers
the storage vector – pointers to (SampleBuffer) buffers
Definition: CSL_Core.h:182
unsigned CSL_MAP_KEY
Forward declaration.
Definition: CSL_Types.h:233
Controllable – superclass of the mix-ins that add control or signal inputs. This holds onto a map of...
Definition: CSL_Core.h:371
void setOffset(UnitGenerator &offset)
set the receiver's offset member to a UGen or a float
Definition: CSL_Core.cpp:1053
unsigned mMonoBufferByteSize
size of each buffer in bytes
Definition: CSL_Core.h:115
UGenVector mOutputs
the vector of my output UGens
Definition: CSL_Core.h:294
UnitGenerator * mGraph
the root of my client DSP graph, often a mixer or panner
Definition: CSL_Core.h:777
unsigned mNumOutputs
the number of outputs
Definition: CSL_Core.h:295
Malloc failure subclass.
static unsigned blockSize()
the default block size
Definition: CGestalt.cpp:57
void interleaveAndRemap(Buffer &output, SampleBuffer samples, unsigned numFrames, unsigned numChannels, unsigned *channelMap)
Interleave = copy from CSL-style Buffer object to an interleaved sample vector Remap = re-assign chan...
Definition: CSL_Core.cpp:1319
void dump()
pretty-print the receiver' device
Definition: CSL_Core.cpp:1570
virtual unsigned numChannels()
Definition: CSL_Core.h:252
unsigned mNumChannels
num channels in buffer (num mono buffers)
Definition: CSL_Core.h:112
void zeroBuffer(Buffer &outputBuffer, unsigned outBufNum)
utility method to zero out an outputBuffer
Definition: CSL_Core.cpp:663
float sample
(could be changed to int, or double)
Definition: CSL_Types.h:191
unsigned mNumChannels
my "expected" number of output channels
Definition: CSL_Core.h:292
float mFrameRate
current SR
Definition: CSL_Core.h:825
virtual void nextBuffer(Buffer &outputBuffer)
nextBuffer processes joiner channels
Definition: CSL_Core.cpp:1240
Scalable()
Constructors.
Definition: CSL_Core.cpp:991
BufferContentType mType
Data type flag set the internal size variables (no buffer allocation takes place) ...
Definition: CSL_Core.h:124
float rms(unsigned chan, unsigned from, unsigned to)
Buffer Sample Processing (optional). One could also easily add Buffer operators, such as (Buffer + Bu...
Definition: CSL_Core.cpp:465
void setSizeOnly(unsigned numChannels, unsigned numFrames)
this version doesn't even allocate the pointers
Definition: CSL_Core.cpp:99
#define CSL_INPUT
Definition: CSL_Types.h:275
#define SUB_TIMES(t1, t2)
Definition: CSL_Core.h:701
Buffer mCaptureBuffer
the output buffer I use for capturing output (for testing)
Definition: CSL_Core.h:780
bool isActive()
am I active?
Definition: CSL_Core.cpp:1225
float max(unsigned chan, unsigned from, unsigned to)
get the max of the absolute val of the samples
Definition: CSL_Core.cpp:495
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:1168
unsigned mNumAlloc
num frames in each buffer
Definition: CSL_Core.h:114
float min(unsigned chan, unsigned from, unsigned to)
get the min of the samples
Definition: CSL_Core.cpp:509
~Phased()
Destructor.
Definition: CSL_Core.cpp:977
virtual bool isActive()
query whether I'm currently active (Envelopes can go inactive)
Definition: CSL_Core.h:273
void copySamplesFrom(Buffer &src)
import data from the given buffer
Definition: CSL_Core.cpp:270
virtual void trigger()
trigger passed on here
Definition: CSL_Core.cpp:1258
virtual void trigger()
trigger passed on here get the input port
Definition: CSL_Core.cpp:1148
void copySamplesFromTo(Buffer &src, unsigned offset)
same with write offset
Definition: CSL_Core.cpp:300
unsigned mMaxInputChannels
HW ins
Definition: CSL_Core.h:823
void scaleBy(sample value)
scale the samples by the given value
Definition: CSL_Core.cpp:219
void checkBuffer()
check the port's buffer and allocate it if needed
Definition: CSL_Core.cpp:796
vector< IODevice * > gIODevices
Definition: CSL_Core.cpp:1387
void fillWith(sample value)
fill data with the given value
Definition: CSL_Core.cpp:203
void setInput(UnitGenerator &inp)
set the receiver's input generator
Definition: CSL_Core.cpp:1112
virtual void trigger()
trigger passed on here
Definition: CSL_Core.cpp:1069
Joiner()
< loop through my vector of inputs
Definition: CSL_Core.h:650
static unsigned mNumInChannels
The actual start-up values are defined in CSL_Types.h.
Definition: CGestalt.cpp:29
unsigned mOffset
used for capture offset
Definition: CSL_Core.h:793
unsigned mNumOutChannels
outputs
Definition: CSL_Core.h:788
virtual void nextBuffer(Buffer &outputBuffer)
I'm mono nextBuffer processes splitter channels.
Definition: CSL_Core.cpp:1194
Status
CSL status flags (for return values)
IO Error.
virtual void capture_off()
end output capture
Definition: CSL_Core.cpp:1544
void checkBuffers()
allocate if not already there
Definition: CSL_Core.cpp:107
void addInput(UnitGenerator &in)
add the argument to vector of inputs
Definition: CSL_Core.cpp:1220
compute 1 channel and copy
Definition: CSL_Core.h:211
UnitGenerator * mUGen
my unit generator (pointer or NULL)
Definition: CSL_Core.h:320
virtual ~UnitGenerator()
Destructor.
Definition: CSL_Core.cpp:659
Buffer * mBuffer
the buffer used to hold my output
Definition: CSL_Core.h:321
void printTimeStatistics(struct timeval *tthen, struct timeval *tnow, long *tsecond, long *ttimeSum, long *ttimeVals)
Definition: CSL_Core.cpp:1486
float duration()
answer the buffer's duration in seconds
Definition: CSL_Core.cpp:114
unsigned mMaxOutputChannels
HW outs
Definition: CSL_Core.h:824
void setFrequency(UnitGenerator &frequency)
Setter accessors.
Definition: CSL_Core.cpp:981
#define CSL_OFFSET
Definition: CSL_Types.h:274
bool mDidIAllocateBuffers
who allocated my data buffers?
Definition: CSL_Core.h:121
void setRoot(UnitGenerator &root)
set/clear my graph root generator
Definition: CSL_Core.cpp:1405
IO(unsigned s_rate=44100, unsigned b_size=CSL_mBlockSize, int in_device=-1, int out_device=-1, unsigned in_chans=2, unsigned out_chans=2)
superclass = Model
Definition: CSL_Core.cpp:1393
Buffer – the multi-channel sample buffer class (passed around between generators and IO guys)...
Definition: CSL_Core.h:106
float avg(unsigned chan, unsigned from, unsigned to)
get the average of the samples
Definition: CSL_Core.cpp:483
float * mValuePtr
my value's address (const or buffer pointer)
Definition: CSL_Core.h:323
virtual ~Port()
Destructor.
Definition: CSL_Core.cpp:789
void clearRoot()
Definition: CSL_Core.cpp:1410
ignore extra buffer channels
Definition: CSL_Core.h:213
Buffer mInputBuffer
the most recent input buffer (if it's turned on)
Definition: CSL_Core.h:778
float normalize(float maxVal)
normalize the buffer(s) to the given max; answer the prior max
Definition: CSL_Core.cpp:348
Port * getPort(CSL_MAP_KEY name)
Definition: CSL_Core.cpp:920
void allocateBuffers()
fcn to malloc storage buffers
Definition: CSL_Core.cpp:122
bool checkFanOut(Buffer &outputBuffer)
check for fan-out and copy previous buffer; return true if fanning out
Definition: CSL_Core.cpp:699
float mUsage
cpu usage % print the CPU usage message
Definition: CSL_Core.h:798
Port – used to represent constant, control-rate or signal inputs and outputs in named maps; holds a ...
Definition: CSL_Core.h:312
bool readFromFile(char *fname)
read a buffer from a snd file; answer success
Definition: CSL_Core.cpp:315
void addInput(CSL_MAP_KEY name, UnitGenerator &ugen)
Plug in a unit generator to the named input slot.
Definition: CSL_Core.cpp:894
void removeOutput(UnitGenerator *ugen)
Definition: CSL_Core.cpp:680
PortMap mInputs
the map of my inputs or controls (used by the mix-in classes)
Definition: CSL_Core.h:378
forward declaration
Definition: CSL_Core.h:241
Buffer(unsigned numChannels=1, unsigned numFrames=CSL_mBlockSize)
Constructor: default is mono and default-size.
Definition: CSL_Core.cpp:42
bool isInline
whether to use input or buffer as source
Definition: CSL_Core.h:475
~BufferCMap()
Destructor.
Definition: CSL_Core.cpp:635
#define CSL_SCALE
Definition: CSL_Types.h:273
unsigned getAndIncrementSequence()
increment and answer my seq #
Definition: CSL_Core.cpp:1418
void error(int num, const char *m, const char *path)
Definition: OSC_support.cpp:70
void setScale(UnitGenerator &scale)
set the receiver's scale member to a UGen or a float
Definition: CSL_Core.cpp:1039
static unsigned mLoggingPeriod
log CPU every 15 sec
Definition: CGestalt.cpp:41
UnitGenerator(unsigned rate=CGestalt::frameRate(), unsigned chans=1)
Constructors (UGens are mono by default) defaults to mono and maxBlockSize if not specified...
Definition: CSL_Core.cpp:647
virtual void capture_on(float dur)
test the IO's graph
Definition: CSL_Core.cpp:1536
A fan-out generator for DSP graphs with loops.
Definition: CSL_Core.h:615
BufferCMap()
Constructors: default is useless.
Definition: CSL_Core.cpp:625
"error" return status
Regular audio samples.
Definition: CSL_Core.h:72
virtual void writeBuffer(Buffer &inputBuffer)
write to the receiver
Definition: CSL_Core.cpp:1269
void pullInput(Port *thePort, unsigned numFrames)
method to read the control values (in case they're dynamic). this sends nextBuffer() to the input...
Definition: CSL_Core.cpp:847
void interleave(Buffer &output, SampleBuffer samples, unsigned numFrames, unsigned numChannels)
Interleave = copy from CSL-style Buffer object to an interleaved sample vector.
Definition: CSL_Core.cpp:1285
static unsigned mNumOutChannels
stereo outputs
Definition: CGestalt.cpp:30
virtual void dump()
pretty-print the receiver's input/controls map
Definition: CSL_Core.cpp:926
virtual Buffer * get_capture()
answer the capture buffer
Definition: CSL_Core.cpp:1550
#define SAFE_MALLOC(ptr, type, len)
Useful Macros.
Definition: CGestalt.h:103
bool mIsPopulated
does the buffer have data?
Definition: CSL_Core.h:122
Base class of CSL exceptions (written upper-case). Has a string message.
virtual ~Controllable()
Constructor takes no arguments.
Definition: CSL_Core.cpp:841