CSL  5.2
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 #ifndef WIN32
13 #include <samplerate.h> // libsamplerate header file
14 #endif
15 using namespace csl;
16 
17 #ifdef WIN32
18 
19 #define rint(x) ((int)(x + 0.5f))
20 
21 #endif
22 
23 //
24 // Basic buffer methods
25 //
26 
27 // Constructor with size args does not allocate
28 
29 Buffer::Buffer(unsigned numChannels, unsigned numFrames) :
30  mNumChannels(0),
31  mNumFrames(0),
32  mNumAlloc(0),
33  mMonoBufferByteSize(0),
34  mSequence(0),
35  mAreBuffersAllocated(false),
36  mDidIAllocateBuffers(false),
37  mIsPopulated(false),
38  mAreBuffersZero(true),
39  mType(kSamples),
40  mBuffers(0) {
41  setSize(numChannels, numFrames);
42 }
43 
44 // Free on destruction
45 
48  freeBuffers();
49 }
50 
51 // SetSize creates the vector of sample pointers, does not allocate the sample storage
52 
53 
54 void Buffer::setSize(unsigned numChannels, unsigned numFrames) {
55  if (mAreBuffersAllocated && mDidIAllocateBuffers && (mNumChannels != numChannels)
56  && (mNumAlloc < numFrames)) {
57  freeBuffers();
58  mDidIAllocateBuffers = false;
59  mAreBuffersAllocated = false;
60  }
61  if (mNumChannels != numChannels) {
62  mNumChannels = numChannels; // Transfer parameters to member variables
63  if (mBuffers)
64  delete mBuffers; // free buffer pointers
65  mBuffers = new SampleBuffer[numChannels]; // reserve space for buffers
66  for (unsigned i = 0; i < mNumChannels; i++)
67  mBuffers[i] = 0;
68  }
69  if (mNumFrames != numFrames) {
70  mNumFrames = numFrames;
72  }
73  mIsPopulated = false;
74 }
75 
76 // set size and don't allocate vector space either
77 
78 void Buffer::setSizeOnly(unsigned numChannels, unsigned numFrames) {
79  mNumChannels = numChannels;
80  mNumFrames = numFrames;
81  mMonoBufferByteSize = numFrames * sizeof(sample);
82 }
83 
84 // allocate if not already there
85 
87  if ( ! mAreBuffersAllocated)
89 }
90 
91 // allocate the sample arrays
92 
93 //#define FVERBOSE_MALLOC // define for verbose debugging of buffer alloc/free
94 
96 #ifdef FVERBOSE_MALLOC
97  logMsg(" Buffer::allocateBuffers(%x %d %d)", this, mNumChannels, mNumFrames);
98 #endif
99  for (unsigned i = 0; i < mNumChannels; i++) {
101  memset(mBuffers[i], 0, mNumFrames * sizeof(sample));
102  }
103 // if (mNumFrames < 16)
104 // logMsg("Small buffer: %d", mNumFrames);
105  mAreBuffersAllocated = true;
106  mDidIAllocateBuffers = true;
108 }
109 
110 // free them carefully
111 
113  if ( ! mAreBuffersAllocated)
114  return; // they aren't allocated -- I shouldn't free them
115  if ( ! mDidIAllocateBuffers)
116  return; // I didn't allocate them -- I shouldn't free them
117  if (& mBuffers == NULL)
118  return;
119 #ifdef FVERBOSE_MALLOC
120  logMsg(" Buffer::freeBuffers (%x %d %d)", this, mNumChannels, mNumFrames);
121 #endif
122  try {
123  for (unsigned i = 0; i < mNumChannels; i++) {
124  if (mBuffers[i]) {
125  delete mBuffers[i]; // do the delete
126  mBuffers[i] = NULL; // set to zero right away
127  }
128  }
129  } catch (std::exception ex) {
130  logMsg(kLogError, "\nError in Buffer::freeBuffers: %s\n", ex.what());
131  throw MemoryError("Error in Buffer::freeBuffers");
132  }
133  mAreBuffersAllocated = false;
134  mDidIAllocateBuffers = false;
135  delete mBuffers;
136  mBuffers = 0;
137  mNumAlloc = 0;
138 }
139 
140 // empty the sample buffers
141 
143  if ( ! mAreBuffersAllocated)
144  return;
145  for (unsigned i = 0; i < mNumChannels; i++)
146  memset(mBuffers[i], 0, mMonoBufferByteSize);
147  mAreBuffersZero = true;
148 }
149 
150 /// answer a samp ptr tested for extent (offset + maxFrame)
151 
152 sample * Buffer::samplePtrFor(unsigned channel, unsigned offset){
153  return(mBuffers[channel] + offset);
154 }
155 
156 /// answer a samp ptr tested for extent (offset + maxFrame)
157 
158 sample * Buffer::samplePtrFor(unsigned channel, unsigned offset, unsigned maxFrame){
159  if (mNumAlloc >= (offset + maxFrame))
160  return(mBuffers[channel] + offset);
161  return NULL;
162 }
163 
164 ///< answer whether the receiver can store numFrames more frames
165 
166 bool Buffer::canStore(unsigned numFrames) {
167  return ((mNumFrames + numFrames) < mNumAlloc);
168 }
169 
170 // fill with a constant
171 
173  float * bbuffer = NULL;
174  unsigned outBufNum, i;
175  unsigned numChans = mNumChannels;
176  unsigned numFrames = mNumFrames;
177  for (outBufNum = 0; outBufNum < numChans; outBufNum++) {
178  bbuffer = mBuffers[outBufNum];
179  for (i = 0; i < numFrames; i++)
180  *bbuffer++ = value;
181  }
182  mAreBuffersZero = false;
183 }
184 
185 // copy the "header" info
186 
188  if ((source.mNumChannels > mNumChannels) || (source.mNumFrames > mNumAlloc)) {
189  logMsg("Buffer::copyHeaderFrom(ch %d %d, fr %d %d)",
190  mNumChannels, source.mNumChannels, mNumAlloc, source.mNumFrames);
191  throw RunTimeError("Can't reallocate buffers at run-time");
192  }
193  mNumChannels = source.mNumChannels; // copy members
194  mNumFrames = source.mNumFrames;
195  mMonoBufferByteSize = mNumFrames * sizeof(sample);
196  mSequence = source.mSequence;
197  mType = source.mType;
198 }
199 
200 // Copy everything but samples from the argument to the receiver
201 
202 void Buffer::copyFrom(Buffer & source) throw (RunTimeError) {
203  this->freeBuffers(); // free everything
204  delete mBuffers;
205  mNumChannels = source.mNumChannels; // copy members
206  mNumFrames = source.mNumFrames;
207  mNumAlloc = source.mNumAlloc;
208  mMonoBufferByteSize = mNumFrames * sizeof(sample);
209  mSequence = source.mSequence;
210  mBuffers = new SampleBuffer[mNumChannels]; // reserve space for buffers
211  // copy sample pointers
212  for (unsigned outBufNum = 0; outBufNum < mNumChannels; outBufNum++) {
213  mBuffers[outBufNum] = source.monoBuffer(outBufNum);
214  }
215  mAreBuffersZero = false; // set flags
216  mAreBuffersAllocated = true;
217  mDidIAllocateBuffers = false;
218 }
219 
220 // Copy samples from the argument to the receiver; be paranoid about size limits
221 
223  if ((source.mNumChannels > mNumChannels) || (source.mNumFrames > mNumAlloc)) {
224  logMsg(kLogError, "Buffer::copySamplesFrom(ch %d %d, fr %d %d)",
225  mNumChannels, source.mNumChannels, mNumAlloc, source.mNumFrames);
226  throw RunTimeError("Can't reallocate buffers at run-time");
227  }
228  mNumChannels = source.mNumChannels;
229  mNumFrames = source.mNumFrames;
230  mMonoBufferByteSize = mNumFrames * sizeof(sample);
231  for (unsigned outBufNum = 0; outBufNum < mNumChannels; outBufNum++) { // copy loop
232  unsigned sBufNum = csl_min(outBufNum, (source.mNumChannels - 1));
233  memcpy(mBuffers[outBufNum], source.monoBuffer(sBufNum), mMonoBufferByteSize);
234  }
235  mAreBuffersZero = false;
236 }
237 
239  if ((source.mNumChannels > mNumChannels) || (source.mNumFrames > mNumAlloc)) {
240  logMsg(kLogError, "Buffer::copyOnlySamplesFrom(ch %d %d, fr %d %d)",
241  mNumChannels, source.mNumChannels, mNumFrames, source.mNumFrames);
242  throw RunTimeError("Can't reallocate buffers at run-time");
243  }
244  for (unsigned outBufNum = 0; outBufNum < mNumChannels; outBufNum++) {
245  unsigned sBufNum = csl_min(outBufNum, (source.mNumChannels - 1));
246  memcpy(mBuffers[outBufNum], source.monoBuffer(sBufNum), mMonoBufferByteSize);
247  }
248 }
249 
250 ///< same with write offset
251 
252 void Buffer::copySamplesFromTo(Buffer & source, unsigned offset) throw (RunTimeError) {
253  if ((source.mNumChannels > mNumChannels) || ((offset + source.mNumFrames) > mNumAlloc)) {
254  logMsg(kLogError, "Buffer::copyOnlySamplesFrom(ch %d %d, fr %d %d)",
255  mNumChannels, source.mNumChannels, mNumFrames, source.mNumFrames);
256  throw RunTimeError("Can't reallocate buffers at run-time");
257  }
258  for (unsigned outBufNum = 0; outBufNum < mNumChannels; outBufNum++) {
259  unsigned sBufNum = csl_min(outBufNum, (source.mNumChannels - 1));
260  memcpy(mBuffers[outBufNum] + offset, source.monoBuffer(sBufNum),
261  (source.mNumFrames * sizeof(sample)));
262  }
263 }
264 
265 #ifdef USE_SRC
266 
267 // convert the sample rate using libSampleRate
268 
269 Status Buffer::convertRate(int fromRate, int toRate) {
270  double src_ratio = (double) toRate / (double) fromRate;
271  int error;
272  // scaled buffer length
273  unsigned newLen = (unsigned) (rint(((double) mNumFrames) * src_ratio));
274  SRC_STATE * src_state; // SRC structs
275  SRC_DATA src_data;
276  // create/allocate new scaled buffer
277  Buffer * newBuf = new Buffer(mNumChannels, newLen);
278  newBuf->allocateBuffers();
279 
280 // logMsg("Buffer::convertRate from %d to %d = %d frames", fromRate, toRate, newLen);
281  // create temp name and rename file
282  src_ratio = (double) toRate / (double) fromRate;
283  if (src_is_valid_ratio (src_ratio) == 0) {
284  logMsg (kLogError, "Error: Sample rate change out of valid range.");
285  return kErr;
286  }
287  /* Initialize the sample rate converter. */
288  if ((src_state = src_new (SRC_SINC_FASTEST /* SRC_SINC_BEST_QUALITY */, 1, &error)) == NULL) {
289  logMsg ("Error : src_new() failed : %s.", src_strerror (error));
290  exit (1);
291  };
292  src_data.src_ratio = src_ratio; // set up SRC
293  src_data.input_frames = mNumFrames;
294  src_data.output_frames = newLen;
295  src_data.end_of_input = 1;
296  // loop over the channels
297  for (unsigned i = 0; i < mNumChannels; i++) {
298  src_data.data_in = mBuffers[i];
299  src_data.data_out = newBuf->buffer(i);
300  // call src_process
301  error = src_process(src_state, &src_data);
302  if (error) {
303  logMsg("SRC Error : %s", src_strerror(error));
304  return kErr;
305  }
306  }
307  src_state = src_delete (src_state);
308  this->copyFrom(*newBuf); // copy sample pointers to me
309  mDidIAllocateBuffers = true; // toggle ownership flags
310  newBuf->mDidIAllocateBuffers = false;
311  delete newBuf;
312  return kOk;
313 }
314 
315 #endif
316 
317 ///////////////////////////////////
318 
319 #ifdef CSL_DSP_BUFFER /// Buffer Sample Processing (optional)
320 
321 #include <libtsp.h> // for the autocorrelation
322 
323 ///< get the root-mean-square of the samples
324 
325 sample Buffer::rms(unsigned chan) {
326  unsigned thech = chan % mNumChannels;
327  unsigned numFrames = mNumFrames;
328  sample val, sum = 0.0;
329  sample* buffer = mBuffers[thech];
330  for (unsigned i = 0; i < numFrames; i++) {
331  val = *buffer++;
332  sum += (val * val);
333  }
334  return sum / numFrames;
335 }
336 
337 ///< get the average of the samples
338 
339 sample Buffer::avg(unsigned chan) {
340  unsigned thech = chan % mNumChannels;
341  unsigned numFrames = mNumFrames;
342  sample sum = 0.0;
343  sample* buffer = mBuffers[thech];
344  for (unsigned i = 0; i < numFrames; i++)
345  sum += *buffer++;
346  return sum / numFrames;
347 }
348 
349 ///< get the max of the samples
350 
351 sample Buffer::max(unsigned chan) {
352  unsigned thech = chan % mNumChannels;
353  unsigned numFrames = mNumFrames;
354  sample val, tmax = 0.0;
355  sample* buffer = mBuffers[thech];
356  for (unsigned i = 0; i < numFrames; i++) {
357  val = *buffer++;
358  if (fabs(val) > tmax) tmax - fabs(val);
359  }
360  return tmax;
361 }
362 
363 ///< get the min of the samples
364 
365 sample Buffer::min(unsigned chan) {
366  unsigned thech = chan % mNumChannels;
367  unsigned numFrames = mNumFrames;
368  sample val, tmax = 0.0;
369  sample* buffer = mBuffers[thech];
370  for (unsigned i = 0; i < numFrames; i++) {
371  val = *buffer++;
372  if (fabs(val) > tmax) tmax - fabs(val);
373  }
374  return tmax;
375 }
376 
377 ///< count the zero-crossings in the samples
378 
379 unsigned int Buffer::zeroX(unsigned chan) {
380  unsigned thech = chan % mNumChannels;
381  unsigned numFrames = mNumFrames, count = 0, sign = 0;
382  sample val;
383  sample* buffer = mBuffers[thech];
384  for (unsigned i = 0; i < numFrames; i++) {
385  val = *buffer++;
386  if (((val > 0) && sign) || ((val < 0) && ! sign)) {
387  count += 1;
388  sign = 1 - sign;
389  }
390  }
391  return count;
392 }
393 
394 ///< answer the index of the peak value
395 
396 unsigned int Buffer::indexOfPeak(unsigned chan) {
397  unsigned thech = chan % mNumChannels;
398  unsigned numFrames = mNumFrames, index;
399  sample val, tmax = -1000000.0;
400  sample* buffer = mBuffers[thech];
401  for (unsigned i = 0; i < numFrames; i++) {
402  val = *buffer++;
403  if (val > tmax) {
404  tmax = val;
405  index = i;
406  }
407  }
408  return index;
409 }
410 
411 ///< answer the index of the peak value
412 
413 unsigned int Buffer::indexOfPeak(unsigned chan, unsigned lo, unsigned hi) {
414  unsigned index = 0, thech = chan % mNumChannels;
415  sample val, tmax = -100000.0;
416  sample* buffer = mBuffers[thech] + lo;
417  for (unsigned i = lo; i < hi; i++) {
418  val = *buffer++;
419  if (val > tmax) {
420  tmax = val;
421  index = i;
422  }
423  }
424  return index;
425 }
426 
427 ///< answer the index of the peak value
428 
429 unsigned int Buffer::indexOfMin(unsigned chan) {
430  unsigned thech = chan % mNumChannels;
431  unsigned numFrames = mNumFrames, index;
432  sample val, tmin = 1000000.0;
433  sample* buffer = mBuffers[thech];
434  for (unsigned i = 0; i < numFrames; i++) {
435  val = *buffer++;
436  if (val < tmin) {
437  tmin = val;
438  index = i;
439  }
440  }
441  return index;
442 }
443 
444 ///< answer the index of the peak value
445 
446 unsigned int Buffer::indexOfMin(unsigned chan, unsigned lo, unsigned hi) {
447  unsigned index = 0, thech = chan % mNumChannels;
448  sample val, tmin = 1000000.0;
449  sample* buffer = mBuffers[thech] + lo;
450  for (unsigned i = lo; i < hi; i++) {
451  val = *buffer++;
452  if (val < tmin) {
453  tmin = val;
454  index = i;
455  }
456  }
457  return index;
458 }
459 
460 ///< write the autocorrelation into the given array
461 
462 void Buffer::autocorrelation(unsigned chan, SampleBuffer result) {
463  unsigned thech = chan % mNumChannels;
464  unsigned numFrames = mNumFrames;
465  sample* buffer = mBuffers[thech];
466  // SPautoc (const float in[], int in_size, float out[], int out_size)
467  // - out[i] is autocorrelation with lag i
468  SPautoc (buffer, numFrames, result, numFrames); // perform autocorrelation
469 }
470 
471 #endif // CSL_DSP_BUFFER
472 
473 
474 // Sample buffer with channel map and count
475 // the map is so that one can have (e.g.,) a buffer that stands for 3 channels within an 8-channel space
476 
478 
479 BufferCMap::BufferCMap(unsigned numChannels, unsigned numFrames) :
480  Buffer(numChannels, numFrames),
481  mRealNumChannels(numChannels) { }
482 
483 BufferCMap::BufferCMap(unsigned numChannels, unsigned realNumChannels, unsigned numFrames) :
484  Buffer(numChannels, numFrames),
485  mRealNumChannels(realNumChannels) { }
486 
488 
489 
490 //-------------------------------------------------------------------------------------------------//
491 //
492 // UnitGenerator implementation
493 //
494 
495 // mono by default
496 
497 UnitGenerator::UnitGenerator(unsigned rate, unsigned chans) : Model(),
498  mFrameRate(rate),
499  mNumChannels(chans),
500  mCopyPolicy(kCopy),
501  mNumOutputs(0),
502  mOutputCache(0),
503  mSequence(0)
504  /* mName(0) */
505  { }
506 
507 ///< Destructor
508 
510 // logMsg(" ~UnitGenerator %x", this);
511 }
512 
513 void UnitGenerator::zeroBuffer(Buffer & outputBuffer, unsigned outBufNum) {
514  float * buffer = outputBuffer.monoBuffer(outBufNum);
515  memset(buffer, 0, outputBuffer.mMonoBufferByteSize);
516 }
517 
518 // output management and auto-fan-out
519 
521 // logMsg("UnitGenerator::addOutput %x to %x", ugen, this);
522  mOutputs.push_back(ugen); // if adding the 2nd output, set up fan-out cache
523  if ((mNumOutputs == 1) && (mOutputCache == 0)) {
524  mOutputCache = new Buffer(mNumChannels, CGestalt::maxBufferFrames());
526  }
527  mNumOutputs++;
528 }
529 
531  UGenVector::iterator pos;
532  for (pos = mOutputs.begin(); pos != mOutputs.end(); ++pos) {
533  if (*pos == ugen) {
534  mOutputs.erase(pos);
535  break;
536  }
537  }
538  mNumOutputs--;
539 }
540 
541 // pretty-print the receiver
542 
544  logMsg("a UnitGenerator with %d outputs", mOutputs.size());
545 }
546 
547 // check for fan-out; if fanning out, copy previous buffer & return true
548 
549 bool UnitGenerator::checkFanOut(Buffer & outputBuffer) throw (CException) {
550  if (mNumOutputs > 1) { // if we're doing auto-fan-out
551  if (outputBuffer.mSequence <= mSequence) { // if we've already computed this seq #
552  // and block copy samples from the cache into the output
553  outputBuffer.copyOnlySamplesFrom(*mOutputCache);
554 // logMsg("UnitGenerator::checkFanOut");
555  return true; // finished!
556  }
557  }
558  return false;
559 }
560 
561 // if fanning out, store last output and set seq number
562 
563 void UnitGenerator::handleFanOut(Buffer & outputBuffer) throw (CException) {
564  if (mNumOutputs > 1) // if we're doing auto-fan-out and this is the first time
565  mOutputCache->copySamplesFrom(outputBuffer); // store it in the buffer
566  mSequence = csl_max(mSequence, outputBuffer.mSequence); // remember my seq #
567 // this->changed((void *) & outputBuffer); // signal dependents (if any) of my change
568 }
569 
570 //
571 // Generic next buffer function: call the private (mono) version for each I/O channel;
572 // copy or expand depending on the mCopyPolicy;
573 // copy to the private cache in case of fan-out.
574 //
575 
576 void UnitGenerator::nextBuffer(Buffer & outputBuffer) throw (CException) {
577  unsigned numOutputChannels = outputBuffer.mNumChannels;
578  unsigned bufferByteSize = outputBuffer.mMonoBufferByteSize;
579  SampleBuffer buffer0 = outputBuffer.monoBuffer(0);
580 #ifdef CSL_DEBUG
581  logMsg("UnitGenerator::nextBuffer");
582 #endif
583  if (checkFanOut(outputBuffer)) return;
584  // Copy the output buffer samples
585  switch (mCopyPolicy) {
586  default:
587  case kCopy: // compute 1 channel and copy it
588  this->nextBuffer(outputBuffer, 0); // this is where most of the work gets done in CSL
589  for (unsigned i = 1; i < numOutputChannels; i += mNumChannels)
590  memcpy (outputBuffer.monoBuffer(i), buffer0, bufferByteSize);
591  break;
592  case kExpand: // loop through the requested output channels
593  for (unsigned i = 0; i < numOutputChannels; i += mNumChannels)
594  nextBuffer(outputBuffer, i); // call private nextBuffer per-channel
595  break;
596  case kIgnore: // Only do as many channels as I have
597  this->nextBuffer(outputBuffer, 0);
598  break;
599  }
600  handleFanOut(outputBuffer); // process possible fan-out
601 }
602 
603 // Generic private next buffer implementation; by default, just zero out the buffer
604 
605 void UnitGenerator::nextBuffer(Buffer & outputBuffer, unsigned outBufNum) throw (CException) {
606  for (unsigned i = 0; i < mNumChannels; i++)
607  zeroBuffer(outputBuffer, i); // my subclasses do more interesting things here
608 }
609 
610 //-------------------------------------------------------------------------------------------------//
611 //
612 // Port implementation
613 
615  mUGen(NULL),
616  mBuffer(new Buffer(1, CGestalt::blockSize())),
617  mValue(0),
618  mValuePtr(& mValue),
619  mPtrIncrement(0) { }
620 
622  mUGen(ug),
623  mBuffer(new Buffer(ug->numChannels(), CGestalt::blockSize())),
624  mValue(0),
625  mPtrIncrement(1) {
627  mValuePtr = mBuffer->monoBuffer(0) - 1; // set to -1 since nextValue does pre-increment
628 }
629 
630 Port::Port(float value) :
631  mUGen(NULL),
632  mBuffer(NULL),
633  mValue(value),
634  mValuePtr(& mValue),
635  mPtrIncrement(0) { }
636 
638 
639 
640 }
641 
642 // check the port's buffer and allocate it if needed
643 
645  Buffer * buf = mBuffer;
646  UnitGenerator * ug = mUGen;
647 
648  if (buf == 0)
649  throw LogicError("Checking an unassigned buffer");
650  if ((buf->mNumChannels != ug->numChannels()) || (buf->mNumFrames == 1)) {
651  buf->freeBuffers();
652  buf->setSize(ug->numChannels(), CGestalt::blockSize());
653  buf->allocateBuffers();
654  }
655 }
656 
657 // Call this to reset the pointer without re-pulling the input (see SumOfSines)
658 
660  if (mPtrIncrement) // if I'm dynamic
661  mValuePtr = (mBuffer->monoBuffer(0)) - 1; // set to -1 since nextValue does pre-increment
662 }
663 
664 // Answer whether the receiver is active
665 
667  if (mUGen == NULL)
668  return (true);
669  else
670  return mUGen->isActive();
671 }
672 
673 // pretty-print the receiver
674 
675 void Port::dump() {
676  logMsg("a Port with UGen = %x, value = %g, incr = %d", mUGen, mValue, mPtrIncrement);
677  if (mUGen != 0) {
678  fprintf(stderr, "\t");
679  mUGen->dump();
680  }
681 }
682 
683 //-------------------------------------------------------------------------------------------------//
684 //
685 // Controllable implementation -- Grab the dynamic values for the scale and offset controls
686 
687 ///< Destructor
688 
690  for (PortMap::iterator pos = mInputs.begin(); pos != mInputs.end(); pos++)
691  delete (pos->second);
692  mInputs.clear();
693 }
694 
695 void Controllable::pullInput(Port * thePort, unsigned numFrames) throw (CException) {
696 #ifdef CSL_DEBUG
697  logMsg("Controllable::pullInput");
698 #endif
699  if (thePort == NULL) {
700  logMsg("Controllable::pullInput port == null!");
701  return;
702  }
703  UnitGenerator * theUG = thePort->mUGen; // get its UGen
704  if (theUG == NULL) { // if it's a static variable
705 // logMsg("Controllable::pullInput UG == null!");
706  return; // ignore it
707  }
708  Buffer * theBuffer = thePort->mBuffer; // else get the buffer
709  if (theBuffer == NULL) { // if it's a static variable
710  logMsg("Controllable::pullInput Buffer == null!");
711  return; // ignore it
712  }
713  thePort->checkBuffer();
714  theBuffer->mNumFrames = numFrames;
715  theBuffer->mType = kSamples;
716  theBuffer->zeroBuffers();
717 
718  theUG->nextBuffer(* theBuffer); //////// and ask the UGen for nextBuffer()
719 
720  theBuffer->mIsPopulated = true;
721  thePort->mValuePtr = (thePort->mBuffer->monoBuffer(0)) - 1;
722  thePort->mValueIndex = 0;
723 }
724 
725 // Controllable implementation -- this version writes into the buffer you pass it
726 
727 void Controllable::pullInput(Port * thePort, Buffer & theBuffer) throw (CException) {
728  if (thePort == NULL)
729  return;
730  UnitGenerator * theUG = thePort->mUGen; // get its UGen
731  if (theUG == NULL) // if it's a static variable
732  return; // ignore it
733  theUG->nextBuffer(theBuffer); ///////// and ask the UGen for nextBuffer()
734 
735  theBuffer.mIsPopulated = true;
736  thePort->mValuePtr = (theBuffer.monoBuffer(0)) - 1;
737  thePort->mValueIndex = 0;
738 }
739 
740 // Plug in a unit generator to the named input slot
741 
743 #ifdef CSL_DEBUG
744  logMsg("Controllable::set input \"%d\" UGen", key);
745 #endif
746  Port * thePort = mInputs[key]; // get the named port
747  if (thePort != 0) // if port found
748  delete thePort;
749  thePort = new Port(&uGen);
750  mInputs[key] = thePort; // add it to the list of inputs
751  uGen.addOutput((UnitGenerator *) this); // be sure to add me as an output of the other guy
752 }
753 
754 void Controllable::addInput(CSL_MAP_KEY key, float value) {
755 #ifdef CSL_DEBUG
756  logMsg("Controllable::set input \"%d\" to %g", key, value);
757 #endif
758  Port * thePort = mInputs[key]; // get the named port
759  if (thePort == 0) { // if no port found
760  thePort = new Port(value);
761  mInputs[key] = thePort; // add it to the list of inputs
762  } else
763  thePort->mValue = value;
764 }
765 
766 // get a port
767 
769  return(mInputs[name]);
770 }
771 
772 // Pretty-print the receiver
773 
775  logMsg("a Controllable with the map:");
776  for (PortMap::iterator pos = mInputs.begin(); pos != mInputs.end(); ++pos) {
777  switch (pos->first) {
778  case CSL_FREQUENCY:
779  logMsg(" key: Frequency = UG: ");
780  break;
781  case CSL_SCALE:
782  logMsg(" key: Scale = UG: ");
783  break;
784  case CSL_OFFSET:
785  logMsg(" key: Offset = UG: ");
786  break;
787  case CSL_INPUT:
788 // case CSL_INPUT_L:
789 // case CSL_INPUT_R:
790  logMsg(" key: Input = UG: ");
791  break;
792  default:
793  logMsg(" key: Other = UG: ");
794 
795  }
796  pos->second->dump(); // go up the graph tree dumping inputs and controls
797  }
798 }
799 
800 /////////////////////////////////////////////////
801 //
802 // Phased implementation -- Constructors
803 
804 Phased::Phased() : Controllable(), mPhase(0.0f) {
805  mInputs[CSL_FREQUENCY] = new Port;
806 #ifdef CSL_DEBUG
807  logMsg("Phased::add freq input");
808 #endif
809 }
810 
811 Phased::Phased(UnitGenerator & frequency, float phase) : mPhase(phase) {
812  this->addInput(CSL_FREQUENCY, frequency);
813 #ifdef CSL_DEBUG
814  logMsg("Phased::add freq input");
815 #endif
816 }
817 
818 Phased::Phased(float frequency, float phase) : mPhase(phase) {
819  this->addInput(CSL_FREQUENCY, frequency);
820 #ifdef CSL_DEBUG
821  logMsg("Phased::add freq input");
822 #endif
823 }
824 
825 Phased::~Phased() { /* ?? */ }
826 
827 // Accessors
828 
830  this->addInput(CSL_FREQUENCY, frequency);
831 }
832 
833 void Phased::setFrequency(float frequency) {
834  this->addInput(CSL_FREQUENCY, frequency);
835 }
836 
837 // Scalable -- Constructors
838 
840  mInputs[CSL_SCALE] = new Port;
841  mInputs[CSL_OFFSET] = new Port;
842 #ifdef CSL_DEBUG
843  logMsg("Scalable::add null inputs");
844 #endif
845 }
846 
847 Scalable::Scalable(float scale) {
848  this->addInput(CSL_SCALE, scale);
849  mInputs[CSL_OFFSET] = new Port;
850 #ifdef CSL_DEBUG
851  logMsg("Scalable::add scale input");
852 #endif
853 }
854 
855 Scalable::Scalable(float scale, float offset) {
856  this->addInput(CSL_SCALE, scale);
857  this->addInput(CSL_OFFSET, offset);
858 #ifdef CSL_DEBUG
859  logMsg("Scalable::add scale/offset input values");
860 #endif
861 }
862 
863 Scalable::Scalable(UnitGenerator & scale, float offset) {
864  this->addInput(CSL_SCALE, scale);
865  this->addInput(CSL_OFFSET, offset);
866 #ifdef CSL_DEBUG
867  logMsg("Scalable::add scale/offset input values");
868 #endif
869 }
870 
872  this->addInput(CSL_SCALE, scale);
873  this->addInput(CSL_OFFSET, offset);
874 #ifdef CSL_DEBUG
875  logMsg("Scalable::add scale/offset input values");
876 #endif
877 }
878 
880 // if (mInputs) {
881 //
882 // }
883 }
884 
885 // Scalable -- Accessors
886 
888  this->addInput(CSL_SCALE, scale);
889 #ifdef CSL_DEBUG
890  logMsg("Scalable::set scale input UG");
891 #endif
892 }
893 
894 void Scalable::setScale(float scale) {
895  this->addInput(CSL_SCALE, scale);
896 #ifdef CSL_DEBUG
897  logMsg("Scalable::set scale input value");
898 #endif
899 }
900 
902  this->addInput(CSL_OFFSET, offset);
903 #ifdef CSL_DEBUG
904  logMsg("Scalable::set offset input UG");
905 #endif
906 }
907 
908 void Scalable::setOffset(float offset) {
909  this->addInput(CSL_OFFSET, offset);
910 #ifdef CSL_DEBUG
911  logMsg("Scalable::set offset input value");
912 #endif
913 }
914 
915 // trigger passed on here
916 
918  if (mInputs[CSL_SCALE])
919  mInputs[CSL_SCALE]->trigger();
920  if (mInputs[CSL_OFFSET])
921  mInputs[CSL_OFFSET]->trigger();
922 }
923 
924 // answer whether scale = 1 & offset = 0
925 
926 //void isScaled() {
927 //
928 //}
929 
930 /////////////////////////////////////////////////
931 //
932 // Effect implementation
933 
935  isInline = false;
936 // mInputs[CSL_INPUT] = new Port;
937 #ifdef CSL_DEBUG
938  logMsg("Effect::add null input");
939 #endif
940 }
941 
943  isInline = false;
944  mNumChannels = input.numChannels();
945  this->addInput(CSL_INPUT, input);
946 #ifdef CSL_DEBUG
947  logMsg("Effect::add input UG");
948 #endif
949 }
950 
952  Port * iPort = mInputs[CSL_INPUT];
953  if (iPort)
954  return (iPort->isActive());
955  return true; // subclasses might not use mInputs[CSL_INPUT]
956 }
957 
959  isInline = false;
960  this->addInput(CSL_INPUT, input);
961 #ifdef CSL_DEBUG
962  logMsg("Effect::add input");
963 #endif
964 }
965 
966 // Get my input's next buffer
967 
968 void Effect::pullInput(Buffer & outputBuffer) throw (CException) {
969 #ifdef CSL_DEBUG
970  logMsg("Effect::pullInput");
971 #endif
972  if (isInline) // if inline, just use the input pointer
973  mInputPtr = outputBuffer.buffer(0);
974  else {
975  Port * iPort = mInputs[CSL_INPUT];
976  // else pull a buffer from my input
977  Controllable::pullInput(iPort, outputBuffer);
978 
979  mInputPtr = outputBuffer.buffer(0);
980  }
981 }
982 
983 void Effect::pullInput(unsigned numFrames) throw (CException) {
984 #ifdef CSL_DEBUG
985  logMsg("Effect::pullInput");
986 #endif
987  Port * iPort = mInputs[CSL_INPUT];
988  Controllable::pullInput(iPort, numFrames);
989  mInputPtr = iPort->mBuffer->buffer(0);
990 }
991 
992 ///< trigger passed on here
993 
995  if (mInputs[CSL_INPUT])
996  mInputs[CSL_INPUT]->trigger();
997 }
998 
999 // FanOut methods
1000 
1001 FanOut::FanOut(UnitGenerator & in, unsigned taps)
1002  : Effect(in), mNumFanOuts(taps), mCurrent(taps) {
1003 #ifdef CSL_DEBUG
1004  logMsg("FanOut::FanOut %d", mNumFanOuts);
1005 #endif
1006 }
1007 
1008 void FanOut::nextBuffer(Buffer & outputBuffer, unsigned outBufNum) throw (CException) {
1009  throw LogicError("Asking for mono nextBuffer of a FanOut");
1010 }
1011 
1012 // nextBuffer just pulls the input every "mOutputs" calls
1013 
1014 void FanOut::nextBuffer(Buffer & outputBuffer) throw (CException) {
1015  if (outputBuffer.mNumChannels != mNumChannels)
1016  throw LogicError("Asking for wrong output ch # of a FanOut");
1017  if (mCurrent >= mNumFanOuts) {
1018  pullInput(outputBuffer.mNumFrames);
1019  mCurrent = 0;
1020 // logMsg(" reset");
1021  } // Copy the output buffer samples
1022  Buffer * buf = mInputs[CSL_INPUT]->mBuffer;
1023  outputBuffer.copyOnlySamplesFrom(*buf);
1024 // logMsg("FanOut %d", mCurrent);
1025  mCurrent++;
1026 }
1027 
1028 // Splitter class -- a de-multiplexer for multi-channel signals
1029 
1031  : FanOut(in, in.numChannels()) { }
1032 
1033 void Splitter::nextBuffer(Buffer & outputBuffer, unsigned outBufNum) throw (CException) {
1034  throw LogicError("Asking for mono nextBuffer of a Splitter");
1035 }
1036 
1037 // Like for FanOut, next-buffer calls the input every mOutput calls,
1038 // but it only copies one channel at a time to the output
1039 
1040 void Splitter::nextBuffer(Buffer & outputBuffer) throw (CException) {
1041  if (outputBuffer.mNumChannels != 1)
1042  throw LogicError("Asking for a stereo output of a channel splitter");
1043  // pull input
1044  if (mCurrent >= mNumFanOuts) {
1045  pullInput(outputBuffer.mNumFrames);
1046  mCurrent = 0;
1047  }
1048  Buffer * buf = mInputs[CSL_INPUT]->mBuffer;
1049  if (buf == 0)
1050  throw LogicError("Missing buffer in channel splitter");
1051  unsigned bufferByteSize = outputBuffer.mMonoBufferByteSize;
1052  SampleBuffer dest = outputBuffer.monoBuffer(0);
1053  SampleBuffer src = buf->monoBuffer(mCurrent);
1054  memcpy(dest, src, bufferByteSize);
1055  mCurrent++;
1056 }
1057 
1058 // Joiner class -- a multiplexer for multi-channel signals
1059 
1061  Controllable::addInput(0, in1);
1062  Controllable::addInput(1, in2);
1063  mNumChannels = 2;
1064 }
1065 
1066 void Joiner::addInput(UnitGenerator & in) { ///< add the argument to vector of inputs
1067  Controllable::addInput(mNumChannels, in);
1068  mNumChannels++;
1069 }
1070 
1072  for (unsigned i = 0; i < mNumChannels; i++) {
1073  if (mInputs[i]->mUGen->isActive())
1074  return true;
1075  }
1076  return false;
1077 }
1078 
1079 
1080 void Joiner::nextBuffer(Buffer & outputBuffer, unsigned outBufNum) throw (CException) {
1081  throw LogicError("Asking for mono nextBuffer of a Joiner");
1082 }
1083 
1084 // nextBuffer calls each of the input channels as a mono channel
1085 
1086 void Joiner::nextBuffer(Buffer & outputBuffer) throw (CException) {
1087  if (outputBuffer.mNumChannels != mNumChannels) {
1088  throw LogicError("Wrong number of channels in a joiner");
1089  }
1090  // set up the fake mono buffer
1091  Buffer tempBuffer(1, outputBuffer.mNumFrames);
1092 
1093  // loop through the mono inputs
1094  for (unsigned i = 0; i < mNumChannels; i++) {
1095  // put the mono in samples into 1 channel of the output
1096  tempBuffer.setBuffer(0, outputBuffer.monoBuffer(i));
1097  // get a buffer of mono samples from one of the inputs
1098  mInputs[i]->mUGen->nextBuffer(tempBuffer);
1099  }
1100 }
1101 
1102 ///< trigger passed on here
1103 
1105  for (unsigned i = 0; i < mNumChannels; i++)
1106  mInputs[i]->trigger();
1107 }
1108 
1109 // Writeable implementation
1110 
1111 void Writeable::writeBuffer(Buffer & inputBuffer, unsigned bufNum) throw (CException) {
1112  // no-op here
1113 }
1114 
1115 void Writeable::writeBuffer(Buffer & inputBuffer) throw (CException) {
1116  unsigned numBufs = inputBuffer.mNumChannels;
1117  for (unsigned i = 0; i < numBufs; i++)
1118  writeBuffer(inputBuffer, i);
1119 }
1120 
1121 // Seekable
1122 
1123 void Seekable::reset() throw (CException) { // reset-to-zero
1124  int pos = seekTo(0, kPositionStart);
1125  if (pos == 0)
1126  throw IOError("Error seeking");
1127 }
1128 
1129 // Interleave = copy from CSL-style Buffer object to an interleaved sample vector
1130 
1132  unsigned numFrames, unsigned numChannels) throw (CException) {
1133 
1134  unsigned numOutputChannels = output.mNumChannels;
1135  unsigned numChannelsToInterleave = csl_min(numOutputChannels, numChannels);
1136  unsigned numChannelsBeyond = numChannels - numChannelsToInterleave;
1137 
1138  for (unsigned frame = 0; frame < numFrames; frame++) {
1139  for (unsigned channel = 0; channel < numChannelsToInterleave; channel++)
1140  *samples++ = output.monoBuffer(channel)[frame];
1141  for (unsigned j = 0; j < numChannelsBeyond; j++)
1142  *samples++ = 0;
1143  }
1144 }
1145 
1146 // Interleave, short * version
1147 
1148 void Interleaver::interleave(Buffer & output, short * samples, unsigned numFrames,
1149  unsigned numChannels) throw (CException) {
1150 
1151  unsigned numOutputChannels = output.mNumChannels;
1152  unsigned numChannelsToInterleave = csl_min(numOutputChannels, numChannels);
1153  unsigned numChannelsBeyond = numChannels - numChannelsToInterleave;
1154 
1155  for (unsigned frame = 0; frame < numFrames; frame++) {
1156  for (unsigned channel = 0; channel < numChannelsToInterleave; channel++)
1157  *samples++ = (short) ((output.monoBuffer(channel)[frame]) * 32767.0);
1158  for (unsigned j = 0; j < numChannelsBeyond; j++)
1159  *samples++ = 0;
1160  }
1161 }
1162 
1163 /// Remap = re-assign channels from the source buffer to the target while interleaving
1164 
1165 void Interleaver::interleaveAndRemap(Buffer & output, SampleBuffer samples, unsigned numFrames,
1166  unsigned numChannels, unsigned *channelMap) throw (CException) {
1167 
1168  unsigned numOutputChannels = output.mNumChannels;
1169  unsigned numChannelsToInterleave = csl_min(numOutputChannels, numChannels);
1170  unsigned numChannelsBeyond = numChannels - numChannelsToInterleave;
1171  unsigned *map = channelMap;
1172 
1173  for (unsigned frame = 0; frame < numFrames; frame++) {
1174  for (unsigned channel = 0; channel < numChannelsToInterleave; channel++)
1175  *samples++ = output.monoBuffer(map[channel])[frame];
1176  for (unsigned j = 0; j < numChannelsBeyond; j++)
1177  *samples++ = 0;
1178  }
1179 }
1180 
1181 // De-interleave = copy from interleaved SampleBuffer to CSL Buffer object
1182 
1183 void Interleaver::deinterleave(Buffer & output, SampleBuffer samples, unsigned numFrames,
1184  unsigned numChannels) throw (CException) {
1185 
1186  unsigned numOutputChannels = output.mNumChannels;
1187  unsigned numChannelsToDeinterleave = csl_min(numOutputChannels, numChannels);
1188  SampleBuffer currentOutputBuffer;
1189  SampleBuffer inputBuffer;
1190  unsigned i;
1191 
1192  for (i = 0; i < numChannelsToDeinterleave; i++) {
1193  currentOutputBuffer = output.monoBuffer(i);
1194  inputBuffer = samples + i;
1195  for (unsigned j = 0; j < numFrames; j++, inputBuffer += numChannels) {
1196  *currentOutputBuffer++ = *inputBuffer;
1197  }
1198  }
1199  if (numOutputChannels > numChannelsToDeinterleave) {
1200  for (i = numChannelsToDeinterleave; i < numOutputChannels; i++)
1201  memset(output.monoBuffer(i), 0, output.mMonoBufferByteSize);
1202  }
1203 }
1204 
1205 // De-interleave, short * version
1206 
1207 void Interleaver::deinterleave(Buffer & output, short * samples, unsigned numFrames,
1208  unsigned numChannels) throw (CException) {
1209 
1210  unsigned numOutputChannels = output.mNumChannels;
1211  unsigned numChannelsToDeinterleave = csl_min(numOutputChannels, numChannels);
1212  SampleBuffer currentOutputBuffer;
1213  short * inputBuffer;
1214  unsigned i;
1215 
1216  for (i = 0; i < numChannelsToDeinterleave; i++) {
1217  currentOutputBuffer = output.monoBuffer(i);
1218  inputBuffer = samples + i;
1219  for (unsigned j = 0; j < numFrames; j++, inputBuffer += numChannels) {
1220  *currentOutputBuffer++ = ((float )*inputBuffer) / 32767.0f;
1221  }
1222  }
1223  if (numOutputChannels > numChannelsToDeinterleave) {
1224  for (i = numChannelsToDeinterleave; i < numOutputChannels; i++)
1225  memset(output.monoBuffer(i), 0, output.mMonoBufferByteSize);
1226  }
1227 }
1228 
1229 //////////////////////////// IO class methods /////////////////////////////////
1230 
1231 // Global array of all known IO devices
1232 
1233 vector < IODevice *> gIODevices;
1234 
1235 // General IO Constructors in all modes
1236 
1237 IO::IO(unsigned s_rate, unsigned b_size, int in_device, int out_device,
1238  unsigned in_chans, unsigned out_chans)
1239  : mGraph(NULL), mNumFramesPlayed(0), mSequence(0),
1240  mLoggingPeriod(CGestalt::loggingPeriod()),
1241  mNumInChannels(in_chans), mNumOutChannels(out_chans),
1242  mNumRealInChannels(in_chans), mNumRealOutChannels(out_chans),
1243  mStatus(kIONew), mInterleaved(false) {
1244  logMsg("Create IO: %d s @ %d Hz; %d i %d o", b_size, s_rate, in_chans, out_chans);
1245 }
1246 
1247 // set/clear the root generator
1248 
1250  root.addOutput((UnitGenerator *) this);
1251  mGraph = & root;
1252 }
1253 
1255  if (mGraph != NULL)
1256  mGraph->removeOutput((UnitGenerator *) this);
1257  mGraph = NULL;
1258 }
1259 
1260 // increment and answer my seq #
1261 
1263  mSequence++;
1264  return mSequence;
1265 }
1266 
1267 // IO method to call a CSL client's DSP graph
1268 
1269 void IO::pullInput(Buffer & outBuffer, SampleBuffer out) throw(CException) {
1270 
1271 #ifdef DO_TIMING
1272  static struct timeval * mte = & mThen;
1273  static struct timeval * mno = & mNow;
1274  GET_TIME(mte);
1275  float maxSampEver = 0.0f;
1276 #endif
1277 // unsigned numFrames = outBuffer.mNumFrames;
1278 // unsigned numChans = outBuffer.mNumChannels;
1279 
1280  if (mGraph) {
1281  try {
1282  outBuffer.mSequence = this->getAndIncrementSequence();
1283 
1284  mGraph->nextBuffer(outBuffer); ////// call the graph's nextBuffer method //////
1285 
1286  } catch (CException ex) {
1287  // handler: log error and play silence
1288  logMsg(kLogError, "An error occured in the CSL nextBuffer method: %s\n",
1289  ex.mMessage.c_str());
1290 // memset(out, 0, (numFrames * numChans * sizeof(sample)));
1291  }
1292  }
1293 #ifdef DO_TIMING
1294  GET_TIME(mno);
1295  printTimeStatistics(mno, mte, & mThisSec, & mTimeSum, & mTimeVals);
1296 #endif
1297 }
1298 
1299 #ifdef CSL_WINDOWS
1300 
1301 #ifdef DO_TIMING // DO_TIMING
1302 
1303 int (timeval *val, void * e) {
1304  LARGE_INTEGER ticksPerSecond;
1305  LARGE_INTEGER tick; // A point in time
1306  // get the high resolution counter's accuracy
1307  QueryPerformanceFrequency(&ticksPerSecond);
1308  float ticksPerUSecond = ticksPerSecond.QuadPart / 1000000;
1309  // what time is it?
1310  QueryPerformanceCounter(&tick);
1311  val->tv_sec = tick.QuadPart/ticksPerSecond.QuadPart;
1312  val->tv_usec = tick.QuadPart/ticksPerUSecond;
1313 // cerr << "Fraction: " << val->tv_sec << "/" << val->tv_usec << " " << ticksPerUSecond << endl;
1314  return 0;
1315 }
1316 #endif
1317 
1318 #endif
1319 
1320 // IO Timing method
1321 
1322 #ifdef DO_TIMING
1323 //#include "Mixer.h"
1324 //#include "Instrument.h"
1325 //extern std::vector<Instrument *> gInstLibrary;
1326 
1327 void IO::printTimeStatistics(struct timeval * now, struct timeval * then, long * thisSec,
1328  long * timeSum, long * timeVals) {
1329 
1330  if (now->tv_sec - * thisSec > (long) mLoggingPeriod) { // print stats once every so often
1331  *thisSec = now->tv_sec;
1332  if (*timeSum != 0.0) { // print and reset counters
1333  float cycleTime = (float) CGestalt::blockSize() * 1000000.0f / (float) CGestalt::frameRate();
1334  // remember % usage
1335  mUsage = (float) *timeSum / *timeVals * 100.0f / cycleTime;
1336  *timeVals = 0;
1337  *timeSum = 0;
1338  logMsg("\tCPU usage: %.2f percent (%5.3f).", mUsage, maxSampEver);
1339 // logMsg("\tIO: %d active clients", ((Mixer *) mGraph)->activeSources());
1340 // unsigned num_instruments = library.size();
1341 // for (unsigned i = 0; i < num_instruments; i++) {
1342 // Instrument * instr = library[i];
1343 // if (instr->graph()->isActive())
1344 // logMsg("\t\tInstrument %s.%d", instr->name().c_str(), i);
1345 // }
1346  }
1347  } else { // count blocks with active sounds and sum exec. times
1348  *timeVals += 1;
1349  *timeSum += SUB_TIMES(now, then);
1350  }
1351  // cerr << "here now/this: " << now->tvSec << " " << then->tvSec << endl;
1352 }
1353 
1354 #endif
1355 
1356 // Answer the most recent input buffer
1357 
1360 }
1361 
1362 // really get the desired format of input
1363 
1364 Buffer & IO::getInput(unsigned numFrames, unsigned numChannels) throw(CException) {
1365  if (mNumInChannels == 0)
1366  throw IOError("Can't get unopened input");
1367  if (mInterleaved) {
1368  Interleaver interleaver;
1369  interleaver.deinterleave(mInputBuffer, mInputPointer, numFrames, numChannels);
1370  mInputBuffer.mIsPopulated = true;
1371  }
1372  return(mInputBuffer);
1373 }
1374 
1375 // IO Device
1376 
1377 IODevice::IODevice(char * name, unsigned index, unsigned maxIn, unsigned maxOut, bool isIn, bool isOut)
1378  : mIndex(index), mMaxInputChannels(maxIn), mMaxOutputChannels(maxOut),
1379  mIsDefaultIn(isIn), mIsDefaultOut(isOut) {
1380  strcpy(mName, name);
1381 }
1382 
1383 IODevice::IODevice(string name, unsigned index, unsigned maxIn, unsigned maxOut, bool isIn, bool isOut)
1384  : mIndex(index), mMaxInputChannels(maxIn), mMaxOutputChannels(maxOut),
1385  mIsDefaultIn(isIn), mIsDefaultOut(isOut) {
1386  strcpy(mName, name.c_str());
1387 }
1388 
1389 // pretty-print an IO Device
1390 
1392  logMsg(" IO: %d = %s - %d i %d o %g Hz%s%s",
1393  mIndex,
1394  mName,
1396  mFrameRate,
1397  (mIsDefaultIn ? " - def in" : ""),
1398  (mIsDefaultOut ? " - def out" : ""));
1399 }