CSL 5.2

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

- File List
- File Members

CSL_Core.h
Go to the documentation of this file.
1 ///
2 /// CSL_Core.h -- the specification file for the core classes of CSL version 5
3 ///
4 /// See the copyright notice and acknowledgment of authors in the file COPYRIGHT
5 ///
6 /// What's here:
7 ///
8 /// Core Classes
9 /// Buffer -- the multi-channel sample buffer class (passed around between generators and IO guys)
10 /// BufferCMap -- a sample buffer with channel map and count (used for many-channel processing)
11 /// Port -- used to represent signal and control inputs and outputs in named maps;
12 /// holds a UnitGenerator and its buffer
13 /// UnitGenerator -- an object that can fill a buffer with samples, the central abstraction of CSL DSP
14 ///
15 /// Mix-in classes (added to UnitGenerator)
16 /// Controllable -- superclass of the mix-ins that add control or signal inputs (held in maps)
17 /// Effect -- A (controllable) UnitGenerator subclass that process an input port (e.g., filters, panners).
18 /// All effects inherit from me.
19 /// Scalable -- A (controllable) mix-in that adds scale (multiplicative) and offset (additive)
20 /// inputs (used by most common UGens)
21 /// Phased -- a (controllable) mix-in for generators with frequency inputs and persistent phase accumulators
22 /// All of these mix-in classes add macros for handling their special named control ports, as in
23 /// DECLARE_PHASED_CONTROLS, LOAD_PHASED_CONTROLS, and UPDATE_PHASED_CONTROLS
24 /// Writeable -- a mix-in for generators that one can write into a buffer on
25 /// Seekable -- a mix-in for generators that one can position (seek) as a stream
26 /// Cacheable -- a mix-in for generators that can cache their past output values (of any size)
27 ///
28 /// Channel/Buffer processing
29 /// FanOut -- 1-in n-out fan-out object (now built in to UnitGenerator)
30 /// Splitter -- splits a stream into multiple 1-channel outputs
31 /// Joiner -- joins multiple 1-channel inputs into a single stream
32 /// Interleaver -- general inderleaver/de-interleaver
33 ///
34 /// I/O
35 /// IO -- the input/output stream/driver, its utility functions and virtual constructors
36 /// IODevice -- a holder for a sound interface with name, id, # IO channels, etc.
37 ///
38
39 #ifndef CSL_CORE_H // This is in case you try to include this twice
40 #define CSL_CORE_H
41
42 #include "CSL_Types.h" // CSL type definitions and central macros, Observer classes
43 #include "CSL_Exceptions.h" // CSL exception hierarchy
44 #include "CGestalt.h" // System constants class
45
46 namespace csl { // All this happens in the CSL namespace
47
48 ///
49 /// Sample buffer contents type (optional)
50 /// One could argue that we should use subclasses for this, but they're not behaviorally different at present.
51 ///
52
53 #ifdef CSL_ENUMS
54 typedef enum {
55 kSamples, ///< Regular audio samples
56 kSpectra, ///< FFT complex spectral frames
57 kLPCCoeff, ///< LPC reflection coefficients
58 kIRData, ///< FIR Impulse Response frames
59 kWavelet, ///< Wavelet coefficients
60 kGeometry, ///< Spatial geometry buffers
61 kUnknown ///< Unknown or other data type
62 } BufferContentType;
63 #else
64 #define kSamples 0
65 #define kSpectra 1
66 #define kLPCCoeff 2
67 #define kIRData 3
68 #define kWavelet 4
69 #define kGeometry 5
70 #define kUnknown 6
71 typedef int BufferContentType;
72 #endif
73
74 //-------------------------------------------------------------------------------------------------//
75 ///
76 /// Buffer -- the multi-channel sample buffer class (passed around between generators and IO guys).
77 ///
78 /// Buffers have an opaque pointer () to their data () and know their # channels and frames.
79 /// They have Boolean aspects about their buffer allocation, and can allocate, free, zero, and check their data.
80 ///
81 /// Note that this is a "record" class in that its members are all public and it has no accessor
82 /// functions or complicated methods. It does handle sample buffer allocation and has
83 /// Boolean members to determine what its pointer state is.
84 /// Note also that Buffers are *not* thread-safe; they hand out pointers (sample*)
85 /// that are assumed to be volatile.
86 ///
87
88 class Buffer {
89 public: /// Constructors: default is mono and default-size
90 Buffer(unsigned numChannels = 1, unsigned numFrames = CSL_mBlockSize);
91 virtual ~Buffer(); ///< Destructor
92
93 // public data members
94 unsigned mNumChannels; ///< num channels in buffer (num mono buffers)
95 unsigned mNumFrames; ///< num frames used in each buffer
96 unsigned mNumAlloc; ///< num frames in each buffer
97 unsigned mMonoBufferByteSize; ///< size of each buffer in bytes
98 unsigned mSequence; ///< sequential serial number
99 Timestamp mTimestamp; ///< the buffer's most recent timestamp
100
101 bool mAreBuffersAllocated; ///< are the buffers allocated?
102 bool mDidIAllocateBuffers; ///< who allocated my data buffers?
103 bool mIsPopulated; ///< does the buffer have data?
104 bool mAreBuffersZero; ///< have the buffers been zeroed out?
105 BufferContentType mType; ///< Data type flag
106 /// set the internal size variables (no buffer allocation takes place)
107 void setSize(unsigned numChannels, unsigned numFrames);
108 /// this version doesn't even allocate the pointers
109 void setSizeOnly(unsigned numChannels, unsigned numFrames);
110
111 void checkBuffers() throw (MemoryError); ///< allocate if not already there
112 void allocateBuffers() throw (MemoryError); ///< fcn to malloc storage buffers
113 void freeBuffers(); ///< fcn to free them
114 bool canStore(unsigned numFrames); ///< answer whether the recevei can store numFrames more frames
115
116 void zeroBuffers(); ///< fill all data with 0
117 void fillWith(sample value); ///< fill data with the given value
118 // import data from the given buffer
119 void copyFrom(Buffer & src) throw (RunTimeError);
120 void copyHeaderFrom(Buffer & source) throw (RunTimeError); ///< copy the "header" fields of a buffer
121 void copySamplesFrom(Buffer & src) throw (RunTimeError); ///< import data from the given buffer
122 void copySamplesFromTo(Buffer & src, unsigned offset) throw (RunTimeError); ///< same with write offset
123 void copyOnlySamplesFrom(Buffer & src) throw (RunTimeError);///< import data from the given buffer
124
125 csl::Status convertRate(int fromRate, int toRate); ///< convert the sample rate using libSampleRate
126
127 /// answer a samp ptr with offset
128 virtual SampleBuffer samplePtrFor(unsigned channel, unsigned offset);
129 /// answer a samp ptr tested for extent (offset + maxFrame)
130 virtual SampleBuffer samplePtrFor(unsigned channel, unsigned offset, unsigned maxFrame);
131
132 /// convenience accessors for sample buffers
133 virtual SampleBuffer monoBuffer(unsigned bufNum) { return mBuffers[bufNum]; }
134 virtual SampleBuffer buffer(unsigned bufNum) { return mBuffers[bufNum]; }
135 virtual SampleBuffer * buffers() { return mBuffers; }
136 /// Set the buffer pointer (rare; used in joiners)
137 virtual void setBuffers(SampleBuffer * sPtr) { mBuffers = sPtr; };
138 virtual void setBuffer(unsigned bufNum, SampleBuffer sPtr) { mBuffers[bufNum] = sPtr; };
139 virtual void setBuffer(unsigned bufNum, unsigned offset, sample samp) { *((mBuffers[bufNum]) + offset) = samp; };
140
141 /// Buffer Sample Processing (optional)
142 /// One could also easily add Buffer operators, such as (Buffer + Buffer) or (Buffer * Buffer)
143
144 #ifdef CSL_DSP_BUFFER
145 float rms(unsigned chan); ///< get the root-mean-square of the samples
146 float avg(unsigned chan); ///< get the average of the samples
147 float max(unsigned chan); ///< get the max of the absolute val of the samples
148 float min(unsigned chan); ///< get the min of the samples
149 unsigned int zeroX(unsigned chan); ///< count the zero-crossings in the samples
150 unsigned int indexOfPeak(unsigned chan); ///< answer the index of the peak value
151 unsigned int indexOfPeak(unsigned chan, unsigned low, unsigned hi); ///< answer the index of the peak value
152 unsigned int indexOfMin(unsigned chan); ///< answer the index of the peak value
153 unsigned int indexOfMin(unsigned chan, unsigned low, unsigned hi); ///< answer the index of the peak value
154 void autocorrelation(unsigned chan, SampleBuffer result); ///< autocorrelation into the given array
155 #endif
156
157 protected:
158 SampleBufferVector mBuffers; ///< the storage vector -- pointers to (SampleBuffer) buffers
159
160 };
161
162 ///
163 /// BufferCMap is a Sample buffer with channel map and count.
164 /// The map is so that one can have (e.g.,) a buffer that stands for 3 channels within an 8-channel space
165 ///
166
167 class BufferCMap : public Buffer {
168 public:
169 BufferCMap(); ///< Constructors: default is useless
170 BufferCMap(unsigned numChannels, unsigned numFrames); ///< ask for a given number of "virtual" channels
171 BufferCMap(unsigned numChannels, unsigned realNumChannels, unsigned numFrames);
172 ~BufferCMap(); ///< Destructor
173
174 unsigned mRealNumChannels; ///< the actual number of channels used
175 std::vector<int> mChannelMap; ///< the map between virtual and real channels
176
177 /// Pointer accessor uses channel map
178 SampleBuffer monoBuffer(unsigned bufNum) { return mBuffers[mChannelMap[bufNum]]; }
179 };
180
181 ///
182 /// UnitGenerator buffer copy policy flags (for multi-channel expansion)
183 ///
184
185 #ifdef CSL_ENUMS
186 typedef enum {
187 kCopy, ///< compute 1 channel and copy
188 kExpand, ///< call monoNextBuffer multiple times
189 kIgnore ///< ignore extra buffer channels
190 } BufferCopyPolicy;
191 #else
192 #define kCopy 0
193 #define kExpand 1
194 #define kIgnore 2
195 typedef int BufferCopyPolicy;
196 #endif
197
198 class RingBuffer; ///< forward declaration
199
200 //-------------------------------------------------------------------------------------------------//
201 ///
202 /// UnitGenerator -- the core of CSL; all unit generators inherit from this class.
203 ///
204 /// These have members for their sample rate and number of channels, and know their outputs.
205 /// The main operation is the nextBuffer() method, which is overridden in many of the subclasses.
206 ///
207 /// If more than 1 output is used, these can handle fan-out automatically, either synchronous
208 /// (as in loops in a graph) or async (as in separate call-back threads).
209 /// The mOutputCache RingBuffer may hold some large number of past samples, and can use nextBuffer()
210 /// to do n-way fan-out either synchronously or with differing buffer sizes or callback rates.
211 ///
212 /// UnitGenerator inherits from Model, meaning that it has to send this->changed((void *) dataBuffer)
213 /// from within its nextBuffer method so that dependent objects (like signal views) can get notification
214 /// when it computes samples. This mechanism could also be used for signal flow.
215 ///
216
217 class UnitGenerator : public Model {
218 public:
219 /// Constructors (UGens are mono by default)
220 /// defaults to mono and maxBlockSize if not specified.
221 UnitGenerator(unsigned rate = CGestalt::frameRate(), unsigned chans = 1);
222 virtual ~UnitGenerator(); ///< Destructor
223
224 // accessing methods
225 unsigned frameRate() { return mFrameRate; }; ///< get/set the receiver's frame rate
226 void setFrameRate(unsigned rate) { mFrameRate = rate; }
227
228 virtual unsigned numChannels() { return mNumChannels; }; ///< get/set the receiver's number of outputs
229 void setNumChannels(unsigned ch) { mNumChannels = ch; }
230
231 BufferCopyPolicy copyPolicy() { return mCopyPolicy; }; ///< get/set the receiver's buffer copy policy
232 void setCopyPolicy(BufferCopyPolicy ch) { mCopyPolicy = ch; }
233
234 // string name() { return mName; }; ///< get/set the receiver's name string
235 // void setName(char * ch) { mName = string(ch); }
236 // void setName(string ch) { mName = ch; }
237
238 /// get a buffer of Frames -- this is the core CSL "pull" function;
239 /// the given buffer can be written into, and a changed() message is sent.
240 virtual void nextBuffer(Buffer & outputBuffer) throw (CException);
241
242 /// really compute the next buffer given an offset base channel;
243 /// this is called by nextBuffer, possibly multiple times
244 virtual void nextBuffer(Buffer & outputBuffer, unsigned outBufNum) throw (CException);
245
246 /// query whether I'm fixed (StaticVariable overrides this)
247 virtual bool isFixed() { return false; };
248 /// query whether I'm currently active (Envelopes can go inactive)
249 virtual bool isActive() { return true; };
250 /// add to or return the UGen vector of outputs
251 void addOutput(UnitGenerator * ugen);
252 void removeOutput(UnitGenerator * ugen);
253 UGenVector outputs() { return mOutputs; };
254 virtual unsigned numOutputs() { return mNumOutputs; };
255 /// check for fan-out and copy previous buffer; return true if fanning out
256 bool checkFanOut(Buffer & outputBuffer) throw (CException);
257 void handleFanOut(Buffer & outputBuffer) throw (CException);
258
259 /// set/get the value (not allowed in the abstract, useful for static values)
260 virtual void setValue(sample theValue) { throw LogicError("can't set value of a generator"); };
261 virtual sample value() { throw LogicError("can't get value of a generator"); };
262
263 virtual void dump(); ///< pretty-print the receiver
264 virtual void trigger() { }; ///< trigger ignored here
265
266 protected: // My data members
267 unsigned mFrameRate; ///< the frame rate -- initialized to be the default by the constructor
268 unsigned mNumChannels; ///< my "expected" number of output channels
269 BufferCopyPolicy mCopyPolicy; ///< the policy I use if asked for more or fewer channels
270 UGenVector mOutputs; ///< the vector of my output UGens
271 unsigned mNumOutputs; ///< the number of outputs
272 Buffer * mOutputCache; ///< my past output ring buffer (only used in case of fan-out)
273 unsigned mSequence; ///< the highest-seen buffer seq number
274 // string mName; ///< my name (used for editors)
275 /// utility method to zero out an outputBuffer
276 void zeroBuffer(Buffer & outputBuffer, unsigned outBufNum);
277 };
278
279 //-------------------------------------------------------------------------------------------------//
280 ///
281 /// Port -- used to represent constant, control-rate or signal inputs and outputs in named maps;
282 /// holds a UnitGenerator and its buffer, OR a single floating-point value (in which case the
283 /// UGen pointer is set to NULL and mPtrIncrement = 0).
284 /// The nextValue() message is used to get the dynamic or static value.
285 ///
286
287 class Port {
288 public:
289 Port(); ///< Constructors: default is a float = 0
290 Port(UnitGenerator * ug); ///< Given a UGen, use it as the input
291 Port(float value); ///< given a float, hold it as the static value
292 virtual ~Port(); ///< Destructor
293
294 // public data members
295 UnitGenerator * mUGen; ///< my unit generator (pointer or NULL)
296 Buffer * mBuffer; ///< the buffer used to hold my output
297 float mValue; ///< my value (in case I'm fixed [mUGen == NULL])
298 float *mValuePtr; ///< my value's address (const or buffer pointer)
299 unsigned mPtrIncrement; ///< the inter-sample ptr increment (0 for const, 1 for dynamic)
300 unsigned mValueIndex; ///< my index (into the UGen's buffer)
301
302 void checkBuffer() throw (LogicError); ///< check the port's buffer and allocate it if needed
303 inline float nextValue(); ///< answer the next value (dynamic or constant)
304 inline void nextFrame(SampleBuffer where); ///< write the val to a buffer
305 inline bool isReady(); ///< answer whether I'm ready to be read
306 void resetPtr(); ///< reset the buffer pointer without re-pulling the input
307 virtual bool isActive(); ///< answer whether I'm active
308 void dump(); ///< pretty-print the receiver
309 bool isFixed() { return (mPtrIncrement == 0); }; ///< am I fixed or dynamic
310 virtual void trigger() { if (mUGen) mUGen->trigger(); }; ///< trigger passed on here
311
312 };
313
314 // Answer the next value (dynamic or constant) as a fast inline function
315
316 inline sample Port::nextValue() {
317 mValuePtr += mPtrIncrement; // increment the pointer (mPtrIncrement may be 0)
318 return *mValuePtr; // return the value
319 }
320
321 // Write the next n-dimensional sample frame
322
323 inline void Port::nextFrame(SampleBuffer where) {
324 for (unsigned i = 0; i < mBuffer->mNumChannels; i++)
325 *where++ = mBuffer->buffer(i)[mValueIndex];
326 mValueIndex++; // increment the counter (an unsigned, initially 0)
327 }
328
329 // Answer whether the give port is ready (i.e., has its UGen or scalar value set up and primed)
330
331 inline bool Port::isReady() {
332 return (mValuePtr != 0);
333 }
334
335 //-------------------------------------------------------------------------------------------------//
336 ///
337 /// Controllable -- superclass of the mix-ins that add control or signal inputs.
338 /// This holds onto a map of port objects that represent the inputs,
339 /// and manages the naming and processing flow for dynamic inputs.
340 ///
341 /// A typical complex UGen will have several ports, e.g., for frequency, scale, and
342 /// offset in the case of an oscillator that supports AM and FM.
343 /// The pullInput() message is used to call the nextBuffer() method of a given port.
344 ///
345
346 class Controllable {
347 public:
348 Controllable() : mInputs() { }; ///< Constructor takes no arguments
349 virtual ~Controllable(); ///< Destructor (remove the output links of the ports)
350
351 Port * getPort(CSL_MAP_KEY name);
352 protected:
353 PortMap mInputs; ///< the map of my inputs or controls (used by the mix-in classes)
354
355 /// Plug in a unit generator to the named input slot
356 void addInput(CSL_MAP_KEY name, UnitGenerator & ugen);
357 /// Plug in a float to the named input slot
358 void addInput(CSL_MAP_KEY name, float value);
359 /// method to read the control values (in case they're dynamic).
360 /// this sends nextBuffer() to the input.
361 void pullInput(Port * thePort, unsigned numFrames) throw (CException);
362 void pullInput(Port * thePort, Buffer & theBuffer) throw (CException);
363
364 virtual void dump(); ///< pretty-print the receiver's input/controls map
365 };
366
367 //-------------------------------------------------------------------------------------------------//
368 ///
369 /// Scalable -- mix-in class with scale and offset control inputs (may be constants or generators).
370 /// This uses the mInput map keys CSL_SCALE and CSL_OFFSET.
371 /// Most actual unit generators inherit this as well as UnitGenerator.
372 /// We use Controllable as a virtual superclass so that we can mix it in twice (in classes that are also Phased)
373 ///
374
375 class Scalable : public virtual Controllable {
376 public:
377 Scalable(); ///< Constructors
378 Scalable(float scale); ///< use the given static scale
379 Scalable(float scale, float offset); ///< use the given static scale & offset
380 Scalable(UnitGenerator & scale, float offset); ///< use the given dynamic scale & static offset
381 Scalable(UnitGenerator & scale, UnitGenerator & offset); ///< use the given dynamic scale & offset
382 ~Scalable(); ///< Destructor
383
384 // accessors
385 void setScale(UnitGenerator & scale); ///< set the receiver's scale member to a UGen or a float
386 void setScale(float scale);
387
388 void setOffset(UnitGenerator & offset); ///< set the receiver's offset member to a UGen or a float
389 void setOffset(float offset);
390 virtual void trigger(); ///< trigger passed on here
391 void isScaled(); ///< answer whether scale = 1 & offset = 0
392
393 };
394
395 /// Macros for all the Scalable UnitGenerators (note that these don't end with ";")
396 /// Note that these make some assumptions about variable names declared in the method;
397
398 /// Declare the pointer to scale/offset buffers (if used) and current scale/offset values
399
400 #define DECLARE_SCALABLE_CONTROLS \
401 Port * scalePort = mInputs[CSL_SCALE]; \
402 Port * offsetPort = mInputs[CSL_OFFSET]; \
403 float scaleValue, offsetValue
404
405 /// Load the scale/offset-related values at the start
406
407 #define LOAD_SCALABLE_CONTROLS \
408 Controllable::pullInput(scalePort, numFrames); \
409 scaleValue = scalePort->nextValue(); \
410 Controllable::pullInput(offsetPort, numFrames); \
411 offsetValue = offsetPort->nextValue()
412
413 // Update the scale/offset-related values in the loop
414
415 #define UPDATE_SCALABLE_CONTROLS \
416 scaleValue = scalePort->nextValue(); \
417 offsetValue = offsetPort->nextValue()
418
419 #define CHECK_UPDATE_SCALABLE_CONTROLS \
420 if (scalePort) \
421 scaleValue = scalePort->nextValue(); \
422 if (offsetPort) \
423 offsetValue = offsetPort->nextValue()
424
425 #define IS_UNSCALED \
426 (scalePort->isFixed()) && (offsetPort->isFixed()) && \
427 (scaleValue == 1.0) && (offsetValue == 0.0)
428
429
430 //-------------------------------------------------------------------------------------------------//
431 ///
432 /// Effect -- mix-in for classes that have unit generators as inputs (like filters).
433 /// Note that this always uses a separate buffer for the input.
434 ///
435
436 class Effect : public UnitGenerator, public virtual Controllable {
437 public:
438 Effect(); ///< Constructors
439 Effect(UnitGenerator & input); ///< use the given input
440
441 virtual bool isActive(); ///< am I active?
442
443 void setInput(UnitGenerator & inp); ///< set the receiver's input generator
444 // UnitGenerator *input() { return mInputs[CSL_INPUT]->mUGen; } // no getter for now
445 bool isInline; ///< whether to use input or buffer as source
446 void setInline() { isInline = true; } ///< set the Effect to be inline
447
448 protected:
449 SampleBuffer mInputPtr; ///< A pointer to my input's data.
450 /// method to read the input value
451 void pullInput(Buffer & outputBuffer) throw (CException);
452 void pullInput(unsigned numFrames) throw (CException);
453 virtual void trigger(); ///< trigger passed on here
454 /// get the input port
455 inline Port * inPort() { return mInputs[CSL_INPUT]; };
456 };
457
458 //-------------------------------------------------------------------------------------------------//
459 ///
460 /// Phased -- a mix-in for objects with phase accumulators (local float) and frequency controls (an input port).
461 /// This puts an item named CSL_FREQUENCY in the Controllable parent mInputs map.
462 /// We use Controllable as a virtual superclass so that we can mix it in twice (in classes that are also Scalable)
463 ///
464
465 class Phased : public virtual Controllable {
466 public:
467 Phased(); ///< Constructors; this one is rearely used
468 Phased(float frequency, float phase = 0); ///< use the given dynamic frequency & phase
469 Phased(UnitGenerator & freq, float phase = 0); ///< use the given dynamic or static frequency
470 ~Phased(); ///< Destructor
471
472 /// Setter accessors
473 void setFrequency(UnitGenerator & frequency); ///< set frequency
474 void setFrequency(float frequency); ///< set frequency
475 void setPhase(float phase) { mPhase = phase; }; ///< set phase
476
477 protected:
478 sample mPhase; ///< the actual phase accumulator
479 };
480
481 /// Macros for all the Phased UnitGenerators (note that these don't end with ";")
482 /// These make some assumptions about variable names declared in the method;
483 /// i.e., the number of frames to compute must be named "numFrames."
484 /// Use this: unsigned numFrames = outputBuffer.mNumFrames;
485
486 /// Declare the frequency port (accessing the mInputs map) and current value.
487
488 #define DECLARE_PHASED_CONTROLS \
489 Port * freqPort = mInputs[CSL_FREQUENCY]; \
490 float freqValue
491
492 /// Load the freq-related values at the start of the callback; if the frequency is a dynamic UGen input,
493 /// then pull its value, get the pointer to its buffer, and set the first value,
494 /// otherwise store the constant value
495
496 #define LOAD_PHASED_CONTROLS \
497 Controllable::pullInput(freqPort, numFrames); \
498 freqValue = freqPort->nextValue()
499
500 /// Update the freq-related value in the loop
501
502 #define UPDATE_PHASED_CONTROLS \
503 freqValue = freqPort->nextValue()
504
505 #define CHECK_UPDATE_PHASED_CONTROLS \
506 if (freqPort) \
507 freqValue = freqPort->nextValue()
508
509 //-------------------------------------------------------------------------------------------------//
510 ///
511 /// Writeable -- a mix-in for buffers and streams that one can write to
512 ///
513
514 class Writeable {
515 public: /// write to the receiver
516 virtual void writeBuffer(Buffer& inputBuffer) throw(CException);
517 virtual ~Writeable() { /* ?? */ };
518
519 protected: /// write to the receiver
520 virtual void writeBuffer(Buffer & inputBuffer, unsigned bufNum) throw(CException);
521 };
522
523 ///
524 /// Enumeration for seek flags
525 ///
526
527 #ifdef CSL_ENUMS
528 typedef enum {
529 kPositionStart,
530 kPositionCurrent,
531 kPositionEnd
532 } SeekPosition;
533 #else
534 #define kPositionStart 0
535 #define kPositionCurrent 1
536 #define kPositionEnd 2
537 typedef int SeekPosition;
538 #endif
539
540 //-------------------------------------------------------------------------------------------------//
541 ///
542 /// Seekable -- a mix-in for positionable streams
543 ///
544
545 class Seekable {
546 public:
547 Seekable() : mCurrentFrame(0), mActualFrame(0.0) { } ///< Constructor
548 virtual ~Seekable() { /* ?? */ };
549
550 unsigned mCurrentFrame; ///< where I currently am in the buffer
551 double mActualFrame; ///< where I actually am in the buffer
552
553 /// general-purpose seek on a stream
554 virtual unsigned seekTo(int position, SeekPosition whence) throw(CException) = 0;
555 virtual void reset() throw(CException); ///< reset-to-zero
556 virtual unsigned duration() = 0; ///< number of frames in the Seekable
557 };
558
559 ///
560 /// Cacheable -- a mix-in for caching streams
561 ///
562
563 class Cacheable {
564 public:
565 Cacheable() : mUseCache(false) { } ; ///< Constructors
566 Cacheable(bool uC) : mUseCache(uC) { };
567
568 bool mUseCache; ///< whether I'm to cache (vs. compute)
569 };
570
571 /////////////// Utility UnitGenerator Classes ///////////////////////
572
573 ///
574 /// A fan-out generator for DSP graphs with loops
575 /// This takes a single input, and provides mNumFanOuts outputs;
576 /// it only calls its input every mNumFanOuts frames.
577 /// This behavior is now standard on UnitGenerators, using their mOutputs UGenVector
578 /// (see UnitGenerators::nextBuffer).
579 ///
580
581 class FanOut : public Effect {
582 public:
583 FanOut(UnitGenerator & in, unsigned taps); ///< Constructors
584 ~FanOut() { };
585
586 virtual void nextBuffer(Buffer & outputBuffer) throw(CException);
587 virtual void nextBuffer(Buffer & outputBuffer, unsigned outBufNum) throw(CException);
588
589 protected:
590 Buffer mBuffer; ///< my temp buffer
591 unsigned mNumFanOuts; ///< the number of outputs
592 unsigned mCurrent; ///< the current output
593 };
594
595 ///
596 /// Splitter class -- a de-multiplexer for multi-channel signals
597 ///
598
599 class Splitter : public FanOut {
600 public:
601 Splitter(UnitGenerator & in); ///< Constructor
602 ~Splitter() { };
603
604 unsigned numChannels() { return 1; }; ///< I'm mono
605 /// nextBuffer processes splitter channels
606 virtual void nextBuffer(Buffer & outputBuffer) throw(CException);
607 virtual void nextBuffer(Buffer & outputBuffer, unsigned outBufNum) throw(CException);
608 };
609
610 ///
611 /// Joiner class -- a multiplexer for multi-channel signals
612 ///
613
614 class Joiner : public Effect {
615 public: ///< loop through my vector of inputs
616 Joiner() : Effect() { mNumChannels = 0; }; ///< Constructors
617 Joiner(UnitGenerator & in1, UnitGenerator & in2);
618 ~Joiner() { };
619 /// nextBuffer processes joiner channels
620 virtual void nextBuffer(Buffer & outputBuffer) throw(CException);
621 virtual void nextBuffer(Buffer & outputBuffer, unsigned outBufNum) throw(CException);
622 void addInput(UnitGenerator & in); ///< add the argument to vector of inputs
623 bool isActive();
624 virtual void trigger(); ///< trigger passed on here
625 // unsigned numChannels() { return mNumChannels; };
626 // inline Port * inPort() { return mInputs[CSL_INPUT]; };
627 // virtual unsigned numOutputs() { return mNumOutputs; };
628
629 protected:
630 // UGenVector mInputs; ///< my vector of inputs
631 };
632
633 ///
634 /// Interleaver handles copying interleaved sample buffers (like sound files and inter-process sockets)
635 /// to/from non-interleaved CSL-style Buffer objects.
636 ///
637
638 class Interleaver {
639
640 public:
641 /// Interleave = copy from CSL-style Buffer object to an interleaved sample vector
642 void interleave(Buffer & output, SampleBuffer samples, unsigned numFrames,
643 unsigned numChannels) throw (CException);
644 void interleave(Buffer & output, short * samples, unsigned numFrames,
645 unsigned numChannels) throw (CException);
646
647 /// Interleave = copy from CSL-style Buffer object to an interleaved sample vector
648 /// Remap = re-assign channels from the source buffer to the target while interleaving
649 void interleaveAndRemap(Buffer & output, SampleBuffer samples, unsigned numFrames, unsigned numChannels,
650 unsigned *channelMap) throw (CException);
651
652 /// De-interleave = copy from interleaved SampleBuffer to CSL Buffer object
653 void deinterleave(Buffer & output, SampleBuffer samples, unsigned numFrames,
654 unsigned numChannels) throw (CException);
655 void deinterleave(Buffer & output, short * samples, unsigned numFrames,
656 unsigned numChannels) throw (CException);
657 };
658
659 //-------------------------------------------------------------------------------------------------//
660 ///// Support for the IO classes
661
662 #ifndef CSL_WINDOWS // on "normal" platforms
663
664 #ifdef DO_TIMING // Here are the macros and globals for the timing code
665 #include <sys/time.h>
666 #define GET_TIME(val) if (gettimeofday(val, 0) != 0) logMsg(kLogError, "Output: Error reading current time");
667 #define SUB_TIMES(t1, t2) (((t1->tv_sec - t2->tv_sec) * 1000000) + (t1->tv_usec - t2->tv_usec))
668 #endif
669
670 #else // If on Windows
671
672 #ifdef DO_TIMING // Here are the macros and globals for the timing code
673 #include <Winsock2.h>
674 #include <winsock.h>
675 #include <time.h>
676 int getSysTime(timeval *val, void * e);
677 #define GET_TIME(val) if (getSysTime(val, 0) != 0) logMsg(kLogError, "Output: Error reading current time");
678 #define SUB_TIMES(t1, t2) (((t1->tv_sec - t2->tv_sec) * 1000000) + (t1->tv_usec - t2->tv_usec))
679 #endif
680
681 #endif // Windows
682
683 /// IO Status flag
684
685 #ifdef CSL_ENUMS
686 typedef enum {
687 kIONew,
688 kIOInit,
689 kIOOpen,
690 kIORunning,
691 kIOClosed,
692 kIOExit
693 } IO_Status;
694 #else
695 #define kIONew 0
696 #define kIOInit 1
697 #define kIOOpen 2
698 #define kIORunning 3
699 #define kIOClosed 4
700 #define kIOExit 5
701 typedef int IO_Status;
702 #endif
703
704 //-------------------------------------------------------------------------------------------------//
705 ///
706 /// IO -- the abstract I/O scheduling class; subclasses interface to specific I/O APIs.
707 /// An IO object has a graph (a ptr to a UGen), and it registers itself with some call-back API
708 /// (like PortAudio, CoreAudio, Jack, VST, JUCE), setting up a callback function that in turn
709 /// calls the nextBuffer() method of its graph root.
710 /// One creates an IO with the desired rate, block size (optional) I/O device keys, and the number of
711 /// in and out channels; you then set its root to be your DSP graph and send it start/stop messages.
712 ///
713 /// All this is public because it's used by static call-back functions.
714 ///
715
716 class IO : public Model { /// superclass = Model
717 public:
718 IO(unsigned s_rate = 44100, unsigned b_size = CSL_mBlockSize,
719 int in_device = -1, int out_device = -1,
720 unsigned in_chans = 2, unsigned out_chans = 2); /// default is stereo input & output
721 virtual ~IO() { };
722 // Control methods
723 virtual void open() throw(CException) { mStatus = kIOOpen; }; ///< open/close start/stop methods
724 virtual void close() throw(CException) { mStatus = kIOClosed; };
725 virtual void start() throw(CException) { mStatus = kIORunning; };
726 virtual void stop() throw(CException) { mStatus = kIOOpen; };
727 virtual void test() throw(CException) { }; ///< test the IO's graph
728
729 void setRoot(UnitGenerator & root); /// set/clear my graph root generator
730 void clearRoot();
731 /// get a buffer from the CSL graph
732 void pullInput(Buffer & outBuffer, SampleBuffer out = 0) throw(CException);
733
734 virtual Buffer & getInput() throw(CException); ///< Get the current input from the sound card
735 virtual Buffer & getInput(unsigned numFrames, unsigned numChannels) throw(CException);
736 unsigned getAndIncrementSequence(); ///< increment and answer my seq #
737
738 // Data members
739 UnitGenerator * mGraph; ///< the root of my client DSP graph, often a mixer or panner
740 Buffer mInputBuffer; ///< the most recent input buffer (if it's turned on)
741 Buffer mOutputBuffer; ///< the output buffer I use (passed to nextBuffer calls)
742 SampleBuffer mInputPointer; ///< the buffer for holding the sound card input (if open)
743 unsigned * mChannelMap; ///< the output channel remapping array
744
745 unsigned mNumFramesPlayed; ///< counter of frames I've played
746 unsigned mSequence; ///< sequence counter
747 unsigned mLoggingPeriod; ///< logging period in seconds
748 unsigned mNumInChannels; ///< # inputs
749 unsigned mNumOutChannels; ///< # outputs
750 unsigned mNumRealInChannels; ///< # physical inputs
751 unsigned mNumRealOutChannels; ///< # physical outputs
752 IO_Status mStatus; ///< status flag
753 bool mInterleaved; ///< flag if IO is interleaved
754
755 #ifdef DO_TIMING // This is for the performance timing code
756 struct timeval mThen, mNow; ///< used for getting the real time
757 long mTimeVals, mThisSec, mTimeSum; ///< for printing run-time statistics
758 float mUsage; ///< cpu usage %
759 /// print the CPU usage message
760 void printTimeStatistics(struct timeval * tthen, struct timeval * tnow, long * tsecond,
761 long * ttimeSum, long * ttimeVals);
762 #endif
763
764 protected: /// initialize overridden in subclasses
765 virtual void initialize(unsigned sr, unsigned bs, int is, int os, unsigned ic, unsigned oc) { };
766 };
767
768 //-------------------------------------------------------------------------------------------------//
769 ///
770 /// IO Device class -- a holder for a sound interface with name, id, # IO channels, etc.
771 ///
772
773 class IODevice {
774 public:
775 IODevice() { } ; /// Constructor takes all variables, calls initialize()
776 IODevice(char * name, unsigned index, unsigned maxIn, unsigned maxOut, bool isIn, bool isOut);
777 IODevice(string name, unsigned index, unsigned maxIn, unsigned maxOut, bool isIn, bool isOut);
778 /// public members
779 char mName[CSL_NAME_LEN]; ///< my device name
780 unsigned mIndex; ///< index (API-specific)
781 unsigned mMaxInputChannels; ///< # HW ins
782 unsigned mMaxOutputChannels; ///<# HW outs
783 float mFrameRate; ///< current SR
784 vector<float> mFrameRates; ///< the vector of frame rates I support
785 bool mIsDefaultIn; ///< am i the default in?
786 bool mIsDefaultOut; ///< am i the default out?
787 void dump(); ///< pretty-print the receiver' device
788 };
789
790 } // end of namespace
791
792 #endif // CSL_CORE_H