fix logical-op-parentheses
[ardour.git] / libs / appleutility / CAAudioUnit.cpp
1 /*      Copyright:      � Copyright 2005 Apple Computer, Inc. All rights reserved.
2
3         Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
4                         ("Apple") in consideration of your agreement to the following terms, and your
5                         use, installation, modification or redistribution of this Apple software
6                         constitutes acceptance of these terms.  If you do not agree with these terms,
7                         please do not use, install, modify or redistribute this Apple software.
8
9                         In consideration of your agreement to abide by the following terms, and subject
10                         to these terms, Apple grants you a personal, non-exclusive license, under Apple�s
11                         copyrights in this original Apple software (the "Apple Software"), to use,
12                         reproduce, modify and redistribute the Apple Software, with or without
13                         modifications, in source and/or binary forms; provided that if you redistribute
14                         the Apple Software in its entirety and without modifications, you must retain
15                         this notice and the following text and disclaimers in all such redistributions of
16                         the Apple Software.  Neither the name, trademarks, service marks or logos of
17                         Apple Computer, Inc. may be used to endorse or promote products derived from the
18                         Apple Software without specific prior written permission from Apple.  Except as
19                         expressly stated in this notice, no other rights or licenses, express or implied,
20                         are granted by Apple herein, including but not limited to any patent rights that
21                         may be infringed by your derivative works or by other works in which the Apple
22                         Software may be incorporated.
23
24                         The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
25                         WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
26                         WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27                         PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
28                         COMBINATION WITH YOUR PRODUCTS.
29
30                         IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
31                         CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
32                         GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33                         ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
34                         OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
35                         (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
36                         ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38 /*=============================================================================
39         CAAudioUnit.cpp
40  
41 =============================================================================*/
42
43 #include "CAAudioUnit.h"
44
45 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
46         #include <AudioUnit/MusicDevice.h>
47 #else
48         #include <MusicDevice.h>
49 #endif
50
51 #include "CAReferenceCounted.h"
52 #include "AUOutputBL.h" //this is for the Preroll only
53
54
55 struct StackAUChannelInfo {
56                 StackAUChannelInfo (UInt32 inSize) : mChanInfo ((AUChannelInfo*)malloc (inSize)) {}
57                 ~StackAUChannelInfo() { free (mChanInfo); }
58                 
59         AUChannelInfo* mChanInfo;
60 };
61
62
63
64 class CAAudioUnit::AUState : public CAReferenceCounted  {
65 public:
66         AUState (Component inComp)
67                                                 : mUnit(0), mNode (0)
68                                                 { 
69                                                         OSStatus result = ::OpenAComponent (inComp, &mUnit); 
70                                                         if (result)
71                                                                 throw result;
72                                                         Init();
73                                                 }
74
75         AUState (const AUNode &inNode, const AudioUnit& inUnit)
76                                                 : mUnit (inUnit), mNode (inNode) 
77                                                 {
78                                                         Init();
79                                                 }
80                                                 
81         ~AUState();
82                                                                                         
83         AudioUnit                       mUnit;
84         AUNode                          mNode;
85
86         OSStatus                        GetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
87                                                                                         Float32 &outValue) const
88         {
89                         if (mGetParamProc != NULL) {
90                                 return reinterpret_cast<AudioUnitGetParameterProc>(mGetParamProc) (mConnInstanceStorage, 
91                                                                                 inID, scope, element, &outValue);
92                         }                                                       
93                 return AudioUnitGetParameter(mUnit, inID, scope, element, &outValue);
94         }
95
96         OSStatus                        SetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
97                                                                                         Float32 value, UInt32 bufferOffsetFrames)
98         {
99                         if (mSetParamProc != NULL) {
100                                 return reinterpret_cast<AudioUnitSetParameterProc>(mSetParamProc) (mConnInstanceStorage, 
101                                                                                 inID, scope, element, value, bufferOffsetFrames);
102                         }                                                       
103                         return AudioUnitSetParameter(mUnit, inID, scope, element, value, bufferOffsetFrames);
104         }
105         
106         OSStatus                        Render (AudioUnitRenderActionFlags *  ioActionFlags,
107                                                                 const AudioTimeStamp *        inTimeStamp,
108                                                                 UInt32                        inOutputBusNumber,
109                                                                 UInt32                        inNumberFrames,
110                                                                 AudioBufferList *             ioData)
111         {
112                 if (mRenderProc != NULL) {
113                         return reinterpret_cast<AudioUnitRenderProc>(mRenderProc) (mConnInstanceStorage, 
114                                                                         ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData);
115                 }                                                       
116                 return AudioUnitRender(mUnit, ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData);
117         }
118         
119         OSStatus                MIDIEvent (UInt32                                       inStatus,
120                                                                 UInt32                                  inData1,
121                                                                 UInt32                                  inData2,
122                                                                 UInt32                                  inOffsetSampleFrame)
123         {
124 #if !TARGET_OS_WIN32
125                 if (mMIDIEventProc != NULL) {
126                         return reinterpret_cast<MusicDeviceMIDIEventProc>(mMIDIEventProc) (mConnInstanceStorage, 
127                                                                         inStatus, inData1, inData2, inOffsetSampleFrame);
128                 }
129                 return MusicDeviceMIDIEvent (mUnit, inStatus, inData1, inData2, inOffsetSampleFrame);
130 #else
131                 return paramErr;
132 #endif
133         }
134
135         OSStatus                                StartNote (MusicDeviceInstrumentID      inInstrument,
136                                                                         MusicDeviceGroupID                      inGroupID,
137                                                                         NoteInstanceID *                        outNoteInstanceID,
138                                                                         UInt32                                          inOffsetSampleFrame,
139                                                                         const MusicDeviceNoteParams * inParams)
140         {
141 #if !TARGET_OS_WIN32
142                 return MusicDeviceStartNote (mUnit, inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, inParams);
143 #else
144                 return paramErr;
145 #endif
146         }
147         OSStatus                                StopNote (MusicDeviceGroupID            inGroupID,
148                                                                         NoteInstanceID                          inNoteInstanceID,
149                                                                         UInt32                                          inOffsetSampleFrame)
150         {
151 #if !TARGET_OS_WIN32
152                 return MusicDeviceStopNote (mUnit, inGroupID, inNoteInstanceID, inOffsetSampleFrame);
153 #else
154                 return paramErr;
155 #endif
156         }
157
158 private:
159         // get the fast dispatch pointers
160         void Init() 
161         {
162                 UInt32 size = sizeof(AudioUnitRenderProc);
163                 if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch,
164                                                                 kAudioUnitScope_Global, kAudioUnitRenderSelect,
165                                                                 &mRenderProc, &size) != noErr)
166                         mRenderProc = NULL;
167                 if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch,
168                                                                 kAudioUnitScope_Global, kAudioUnitGetParameterSelect,
169                                                                 &mGetParamProc, &size) != noErr)
170                         mGetParamProc = NULL;
171                 if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch,
172                                                                 kAudioUnitScope_Global, kAudioUnitSetParameterSelect,
173                                                                 &mSetParamProc, &size) != noErr)
174                         mSetParamProc = NULL;
175
176                 if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch,
177                                                                 kAudioUnitScope_Global, kMusicDeviceMIDIEventSelect,
178                                                                 &mMIDIEventProc, &size) != noErr)
179                         mMIDIEventProc = NULL;
180                 
181                 if (mRenderProc || mGetParamProc || mSetParamProc || mMIDIEventProc)
182                         mConnInstanceStorage = GetComponentInstanceStorage(mUnit);
183                 else
184                         mConnInstanceStorage = NULL;
185         }
186         
187         ProcPtr                                         mRenderProc, mGetParamProc, mSetParamProc, mMIDIEventProc;
188
189         void *                                          mConnInstanceStorage;
190
191 private:
192                 // get the compiler to tell us when we do a bad thing!!!
193         AUState () {}
194         AUState (const AUState& other) : CAReferenceCounted (other) {}
195         AUState& operator= (const AUState&) { return *this; } 
196 };                                              
197                                                 
198                                                 
199 CAAudioUnit::AUState::~AUState ()
200 {
201         if (mUnit && (mNode == 0)) {
202                 ::CloseComponent (mUnit);
203         }
204         mNode = 0;
205         mUnit = 0;
206 }
207
208 OSStatus                CAAudioUnit::Open (const CAComponent& inComp, CAAudioUnit &outUnit)
209 {
210         try {
211                 outUnit = inComp; 
212                 return noErr;
213         } catch (OSStatus res) {
214                 return res;
215         } catch (...) {
216                 return -1;
217         }
218 }
219
220 CAAudioUnit::CAAudioUnit (const AudioUnit& inUnit)
221         : mComp (inUnit), mDataPtr (new AUState (-1, inUnit))
222 {
223 }
224
225 CAAudioUnit::CAAudioUnit (const CAComponent& inComp)
226         : mComp (inComp), mDataPtr (0)
227 {
228         mDataPtr = new AUState (mComp.Comp());
229 }
230
231 CAAudioUnit::CAAudioUnit (const AUNode &inNode, const AudioUnit& inUnit)
232         : mComp (inUnit), mDataPtr(new AUState (inNode, inUnit)) 
233 {
234 }
235
236 CAAudioUnit::~CAAudioUnit ()
237 {
238         if (mDataPtr) {
239                 mDataPtr->release();
240                 mDataPtr = NULL;
241         }
242 }
243
244 CAAudioUnit&    CAAudioUnit::operator= (const CAAudioUnit &a)
245 {
246         if (mDataPtr != a.mDataPtr) {
247                 if (mDataPtr)
248                         mDataPtr->release();
249         
250                 if ((mDataPtr = a.mDataPtr) != NULL)
251                         mDataPtr->retain();
252                 
253                 mComp = a.mComp;
254         }
255         
256         return *this;
257 }
258
259 bool                    CAAudioUnit::operator== (const CAAudioUnit& y) const
260 {
261         if (mDataPtr == y.mDataPtr) return true;
262         AudioUnit au1 = mDataPtr ? mDataPtr->mUnit : 0;
263         AudioUnit au2 = y.mDataPtr ? y.mDataPtr->mUnit : 0;
264         return au1 == au2;
265 }
266
267 bool                    CAAudioUnit::operator== (const AudioUnit& y) const
268 {
269         if (!mDataPtr) return false;
270         return mDataPtr->mUnit == y;
271 }
272
273 #pragma mark __State Management 
274
275 bool                    CAAudioUnit::IsValid () const 
276
277         return mDataPtr ? mDataPtr->mUnit != 0 : false; 
278 }
279         
280 AudioUnit               CAAudioUnit::AU() const 
281
282         return mDataPtr ? mDataPtr->mUnit : 0; 
283 }
284
285 AUNode                  CAAudioUnit::GetAUNode () const
286 {
287         return mDataPtr ? mDataPtr->mNode : 0; 
288 }
289
290 #pragma mark __Format Handling
291         
292 bool            CAAudioUnit::CanDo (    int                             inChannelsIn, 
293                                                                         int                             inChannelsOut) const
294 {               
295         // this is the default assumption of an audio effect unit
296         Boolean* isWritable = 0;
297         UInt32  dataSize = 0;
298                 // lets see if the unit has any channel restrictions
299         OSStatus result = AudioUnitGetPropertyInfo (AU(),
300                                                                         kAudioUnitProperty_SupportedNumChannels,
301                                                                         kAudioUnitScope_Global, 0,
302                                                                         &dataSize, isWritable); //don't care if this is writable
303                 
304                 // if this property is NOT implemented an FX unit
305                 // is expected to deal with same channel valance in and out
306         if (result) 
307         {
308                 if ((Comp().Desc().IsEffect() && (inChannelsIn == inChannelsOut))
309                         || (Comp().Desc().IsOffline() && (inChannelsIn == inChannelsOut)))
310                 {
311                         return true;
312                 }
313                 else 
314                 {
315                         // the au should either really tell us about this
316                         // or we will assume the worst
317                         return false;
318                 }
319         }
320         
321         StackAUChannelInfo info (dataSize);
322         
323         result = GetProperty (kAudioUnitProperty_SupportedNumChannels,
324                                                         kAudioUnitScope_Global, 0,
325                                                         info.mChanInfo, &dataSize);
326         if (result) { return false; }
327         
328         return ValidateChannelPair (inChannelsIn, inChannelsOut, info.mChanInfo, (dataSize / sizeof (AUChannelInfo)));
329 }
330
331 int    CAAudioUnit::GetChannelInfo (AUChannelInfo** chaninfo, UInt32& cnt)
332 {
333         // this is the default assumption of an audio effect unit
334         Boolean* isWritable = 0;
335         UInt32  dataSize = 0;
336                 // lets see if the unit has any channel restrictions
337         OSStatus result = AudioUnitGetPropertyInfo (AU(),
338                                                     kAudioUnitProperty_SupportedNumChannels,
339                                                     kAudioUnitScope_Global, 0,
340                                                     &dataSize, isWritable); //don't care if this is writable
341         
342         // if this property is NOT implemented an FX unit
343         // is expected to deal with same channel valance in and out
344         
345         if (result) 
346         {
347                 if (Comp().Desc().IsEffect()) 
348                 {
349                         return 1;
350                 }
351                 else if (Comp().Desc().IsGenerator() || Comp().Desc().IsMusicDevice()) {
352                         // directly query Bus Formats
353                         // Note that that these may refer to different subBusses
354                         // (eg. Kick, Snare,.. on a Drummachine)
355                         // eventually the Bus-Name for each configuration should be exposed
356                         // for the User to select..
357
358                         UInt32 elCountIn, elCountOut, elCount;
359
360                         if (GetElementCount (kAudioUnitScope_Input, elCountIn)) return 1;
361                         if (GetElementCount (kAudioUnitScope_Output, elCountOut)) return 1;
362
363                         elCount = std::max(elCountIn, elCountOut);
364
365                         *chaninfo = (AUChannelInfo*) malloc (sizeof (AUChannelInfo) * elCount);
366
367                         for (unsigned int i = 0; i < elCountIn; ++i) {
368                                 UInt32 numChans;
369                                 if (NumberChannels (kAudioUnitScope_Input, i, numChans)) return 1;
370                                 (*chaninfo)[i].inChannels = numChans;
371                         }
372                         for (unsigned int i = elCountIn; i < elCount; ++i) {
373                                 (*chaninfo)[i].inChannels = 0;
374                         }
375
376
377                         for (unsigned int i = 0; i < elCountOut; ++i) {
378                                 UInt32 numChans;
379                                 if (NumberChannels (kAudioUnitScope_Output, i, numChans)) return 1;
380                                 (*chaninfo)[i].outChannels = numChans;
381                         }
382                         for (unsigned int i = elCountOut; i < elCount; ++i) {
383                                 (*chaninfo)[i].outChannels = 0;
384                         }
385                         return 0;
386                 }
387                 else 
388                 {
389                         // the au should either really tell us about this
390                         // or we will assume the worst
391                         return -1;
392                 }
393         }
394
395         *chaninfo = (AUChannelInfo*) malloc (dataSize);
396         cnt = dataSize / sizeof (AUChannelInfo);
397
398         result = GetProperty (kAudioUnitProperty_SupportedNumChannels,
399                               kAudioUnitScope_Global, 0,
400                               *chaninfo, &dataSize);
401
402         if (result) { return -1; }
403         return 0;
404 }
405
406
407 bool    CAAudioUnit::ValidateChannelPair (int                           inChannelsIn, 
408                                                                                 int                             inChannelsOut,
409                                                                                 const AUChannelInfo * info,
410                                                                                 UInt32                          numChanInfo) const
411 {
412 // we've the following cases (some combinations) to test here:
413 /*
414 >0              An explicit number of channels on either side
415 0               that side (generally input!) has no elements
416 -1              wild card:
417 -1,-1   any num channels as long as same channels on in and out
418 -1,-2   any num channels channels on in and out - special meaning
419 -2+     indicates total num channs AU can handle 
420                         - elements configurable to any num channels, 
421                         - element count in scope must be writable
422 */
423
424         //now chan layout can contain -1 for either scope (ie. doesn't care)
425         for (unsigned int i = 0; i < numChanInfo; ++i)
426         {
427                         //less than zero on both sides - check for special attributes
428                 if ((info[i].inChannels < 0) && (info[i].outChannels < 0))
429                 {
430                                 // these are our wild card matches
431                         if (info[i].inChannels == -1 && info[i].outChannels == -1) {
432                                 if (inChannelsOut == inChannelsIn) {
433                                         return true;
434                                 }
435                         }
436                         else if ((info[i].inChannels == -1 && info[i].outChannels == -2)
437                                         || (info[i].inChannels == -2 && info[i].outChannels == -1)) 
438                         {
439                                 return true;
440                         }
441                                 // these are our total num channels matches
442                                 // element count MUST be writable
443                         else {
444                                 bool outWrite = false; bool inWrite = false;
445                                 IsElementCountWritable (kAudioUnitScope_Output, outWrite);
446                                 IsElementCountWritable (kAudioUnitScope_Input, inWrite);
447                                 if (inWrite && outWrite) {
448                                         if ((inChannelsOut <= abs(info[i].outChannels))
449                                                 && (inChannelsIn <= abs(info[i].inChannels))) 
450                                         {
451                                                 return true;
452                                         }
453                                 }
454                         }
455                 }
456                         
457                         // special meaning on input, specific num on output
458                 else if (info[i].inChannels < 0) {
459                         if (info[i].outChannels == inChannelsOut) 
460                         {
461                                         // can do any in channels
462                                 if (info[i].inChannels == -1) {
463                                         return true;
464                                 } 
465                                         // total chans on input
466                                 else {
467                                         bool inWrite = false;
468                                         IsElementCountWritable (kAudioUnitScope_Input, inWrite);
469                                         if (inWrite && (inChannelsIn <= abs(info[i].inChannels))) {
470                                                 return true;
471                                         }
472                                 }
473                         }
474                 }
475                 
476                         // special meaning on output, specific num on input
477                 else if (info[i].outChannels < 0) {
478                         if (info[i].inChannels == inChannelsIn) 
479                         {
480                                         // can do any out channels
481                                 if (info[i].outChannels == -1) {
482                                         return true;
483                                 } 
484                                         // total chans on output
485                                 else {
486                                         bool outWrite = false;
487                                         IsElementCountWritable (kAudioUnitScope_Output, outWrite);
488                                         if (outWrite && (inChannelsOut <= abs(info[i].outChannels))) {
489                                                 return true;
490                                         }
491                                 }
492                         }
493                 }
494
495                         // both chans in struct >= 0 - thus has to explicitly match
496                 else if ((info[i].inChannels == inChannelsIn) && (info[i].outChannels == inChannelsOut)) {
497                         return true;
498                 } 
499                 
500                         // now check to see if a wild card on the args (inChannelsIn or inChannelsOut chans is zero) is found 
501                         // tells us to match just one side of the scopes
502                 else if (inChannelsIn == 0) {
503                         if (info[i].outChannels == inChannelsOut) {
504                                 return true;
505                         }
506                 }
507                 else if (inChannelsOut == 0) {
508                         if (info[i].inChannels == inChannelsIn) {
509                                 return true;
510                         }
511                 }
512         }
513         
514         return false;
515 }
516
517 bool CheckDynCount (SInt32 inTotalChans, const CAAUChanHelper &inHelper)
518 {
519         int totalChans = 0;
520         for (unsigned int i = 0; i < inHelper.mNumEls; ++i)
521                 totalChans += inHelper.mChans[i];
522         return (totalChans <= inTotalChans);
523 }
524
525 bool    CAAudioUnit::CheckOneSide (const CAAUChanHelper         &inHelper, 
526                                                                         bool                                    checkOutput, 
527                                                                         const AUChannelInfo             *info, 
528                                                                         UInt32                                  numInfo) const
529 {
530                 // now we can use the wildcard option (see above impl) to see if this matches
531         for (unsigned int el = 0; el < inHelper.mNumEls; ++el) {
532                 bool testAlready = false;
533                 for (unsigned int i = 0; i < el; ++i) {
534                         if (inHelper.mChans[i] == inHelper.mChans[el]) {
535                                 testAlready = true;
536                                 break;
537                         }
538                 }
539                 if (!testAlready) {
540                         if (checkOutput) {
541                                 if (!ValidateChannelPair (0, inHelper.mChans[el], info, numInfo)) return false;
542                         } else {
543                                 if (!ValidateChannelPair (inHelper.mChans[el], 0, info, numInfo)) return false;
544                         }
545                 }
546         }
547         return true;
548 }
549
550 bool            CAAudioUnit::CanDo (const CAAUChanHelper                &inputs,  
551                                                                 const CAAUChanHelper            &outputs) const
552
553 {
554 // first check our state
555                 // huh!
556         if (inputs.mNumEls == 0 && outputs.mNumEls == 0) return false;
557         
558         UInt32 elCount;
559         if (GetElementCount (kAudioUnitScope_Input, elCount)) { return false; }
560         if (elCount != inputs.mNumEls) return false;
561
562         if (GetElementCount (kAudioUnitScope_Output, elCount)) { return false; }
563         if (elCount != outputs.mNumEls) return false;
564                 
565 // (1) special cases (effects and sources (generators and instruments) only)
566         UInt32  dataSize = 0;
567         if (GetPropertyInfo (kAudioUnitProperty_SupportedNumChannels,
568                                                                         kAudioUnitScope_Global, 0, &dataSize, NULL) != noErr) 
569         {
570                 if (Comp().Desc().IsEffect() || Comp().Desc().IsOffline()) {
571                         UInt32 numChan = outputs.mNumEls > 0 ? outputs.mChans[0] : inputs.mChans[0];
572                         for (unsigned int in = 0; in < inputs.mNumEls; ++in)
573                                 if (numChan != inputs.mChans[in]) return false;
574                         for (unsigned int out = 0; out < outputs.mNumEls; ++out)
575                                 if (numChan != outputs.mChans[out]) return false;
576                         return true;
577                 }
578                 
579                         // in this case, all the channels have to match the current config
580                 if (Comp().Desc().IsGenerator() || Comp().Desc().IsMusicDevice()) {
581                         for (unsigned int in = 0; in < inputs.mNumEls; ++in) {
582                                 UInt32 chan;
583                                 if (NumberChannels (kAudioUnitScope_Input, in, chan)) return false;
584                                 if (chan != UInt32(inputs.mChans[in])) return false;
585                         }
586                         for (unsigned int out = 0; out < outputs.mNumEls; ++out) {
587                                 UInt32 chan;
588                                 if (NumberChannels (kAudioUnitScope_Output, out, chan)) return false;
589                                 if (chan != UInt32(outputs.mChans[out])) return false;
590                         }
591                         return true;
592                 }
593                 
594                         // if we get here we can't determine anything about channel capabilities
595                 return false;
596         }
597
598         StackAUChannelInfo info (dataSize);
599         
600         if (GetProperty (kAudioUnitProperty_SupportedNumChannels,
601                                                         kAudioUnitScope_Global, 0,
602                                                         info.mChanInfo, &dataSize) != noErr)
603         { 
604                 return false; 
605         }
606         
607         int numInfo = dataSize / sizeof(AUChannelInfo);
608         
609 // (2) Test for dynamic capability (or no elements on that scope)
610         SInt32 dynInChans = 0;
611         if (ValidateDynamicScope (kAudioUnitScope_Input, dynInChans, info.mChanInfo, numInfo)) {
612                 if (CheckDynCount (dynInChans, inputs) == false) return false;
613         }
614
615         SInt32 dynOutChans = 0;
616         if (ValidateDynamicScope (kAudioUnitScope_Output, dynOutChans, info.mChanInfo, numInfo)) {
617                 if (CheckDynCount (dynOutChans, outputs) == false) return false;
618         }
619
620         if (dynOutChans && dynInChans) { return true; }
621
622 // (3)  Just need to test one side
623         if (dynInChans || (inputs.mNumEls == 0)) {
624                 return CheckOneSide (outputs, true, info.mChanInfo, numInfo);
625         }
626
627         if (dynOutChans || (outputs.mNumEls == 0)) {
628                 return CheckOneSide (inputs, false, info.mChanInfo, numInfo);
629         }
630
631 // (4) - not a dynamic AU, has ins and outs, and has channel constraints so we test every possible pairing
632         for (unsigned int in = 0; in < inputs.mNumEls; ++in) 
633         {
634                 bool testInAlready = false;
635                 for (unsigned int i = 0; i < in; ++i) {
636                         if (inputs.mChans[i] == inputs.mChans[in]) {
637                                 testInAlready = true;
638                                 break;
639                         }
640                 }
641                 if (!testInAlready) {
642                         for (unsigned int out = 0; out < outputs.mNumEls; ++out) {
643                                         // try to save a little bit and not test the same pairing multiple times...
644                                 bool testOutAlready = false;
645                                 for (unsigned int i = 0; i < out; ++i) {
646                                         if (outputs.mChans[i] == outputs.mChans[out]) {
647                                                 testOutAlready = true;
648                                                 break;
649                                         }
650                                 }
651                                 if (!testOutAlready) {
652                                         if (!ValidateChannelPair (inputs.mChans[in], outputs.mChans[out],info.mChanInfo, numInfo)) {
653                                                 return false;
654                                         }
655                                 }
656                         }
657                 }
658         }
659         
660         return true;
661 }
662
663 bool            CAAudioUnit::SupportsNumChannels () const
664 {
665         // this is the default assumption of an audio effect unit
666         Boolean* isWritable = 0;
667         UInt32  dataSize = 0;
668                 // lets see if the unit has any channel restrictions
669         OSStatus result = AudioUnitGetPropertyInfo (AU(),
670                                                                         kAudioUnitProperty_SupportedNumChannels,
671                                                                         kAudioUnitScope_Global, 0,
672                                                                         &dataSize, isWritable); //don't care if this is writable
673                 
674                 // if this property is NOT implemented an FX unit
675                 // is expected to deal with same channel valance in and out
676         if (result) {
677                 if (Comp().Desc().IsEffect() || Comp().Desc().IsOffline())
678                         return true;
679         }
680         return result == noErr;
681 }
682
683 bool            CAAudioUnit::GetChannelLayouts (AudioUnitScope                  inScope,
684                                                                                 AudioUnitElement                        inEl,
685                                                                                 ChannelTagVector                        &outChannelVector) const
686 {
687         if (HasChannelLayouts (inScope, inEl) == false) return false; 
688
689         UInt32 dataSize;
690         OSStatus result = AudioUnitGetPropertyInfo (AU(),
691                                                                 kAudioUnitProperty_SupportedChannelLayoutTags,
692                                                                 inScope, inEl,
693                                                                 &dataSize, NULL);
694
695         if (result == kAudioUnitErr_InvalidProperty) {
696                 // if we get here we can do layouts but we've got the speaker config property
697                 outChannelVector.erase (outChannelVector.begin(), outChannelVector.end());
698                 outChannelVector.push_back (kAudioChannelLayoutTag_Stereo);
699                 outChannelVector.push_back (kAudioChannelLayoutTag_StereoHeadphones);
700                 outChannelVector.push_back (kAudioChannelLayoutTag_Quadraphonic);
701                 outChannelVector.push_back (kAudioChannelLayoutTag_AudioUnit_5_0);
702                 return true;
703         }
704
705         if (result) return false;
706         
707         bool canDo = false;
708                 // OK lets get our channel layouts and see if the one we want is present
709         AudioChannelLayoutTag* info = (AudioChannelLayoutTag*)malloc (dataSize);
710         result = AudioUnitGetProperty (AU(),
711                                                         kAudioUnitProperty_SupportedChannelLayoutTags,
712                                                         inScope, inEl,
713                                                         info, &dataSize);
714         if (result) goto home;
715         
716         outChannelVector.erase (outChannelVector.begin(), outChannelVector.end());
717         for (unsigned int i = 0; i < (dataSize / sizeof (AudioChannelLayoutTag)); ++i)
718                 outChannelVector.push_back (info[i]);
719
720 home:
721         free (info);
722         return canDo;
723 }
724
725 bool            CAAudioUnit::HasChannelLayouts (AudioUnitScope          inScope, 
726                                                                                 AudioUnitElement                inEl) const
727 {
728         OSStatus result = AudioUnitGetPropertyInfo (AU(),
729                                                                         kAudioUnitProperty_SupportedChannelLayoutTags,
730                                                                         inScope, inEl,
731                                                                         NULL, NULL);
732         return !result;
733 }
734
735 OSStatus        CAAudioUnit::GetChannelLayout (AudioUnitScope           inScope,
736                                                                                 AudioUnitElement                inEl,
737                                                                                 CAAudioChannelLayout    &outLayout) const
738 {
739         UInt32 size;
740         OSStatus result = AudioUnitGetPropertyInfo (AU(), kAudioUnitProperty_AudioChannelLayout,
741                                                                         inScope, inEl, &size, NULL);
742         if (result) return result;
743         
744         AudioChannelLayout *layout = (AudioChannelLayout*)malloc (size);
745
746         require_noerr (result = AudioUnitGetProperty (AU(), kAudioUnitProperty_AudioChannelLayout,
747                                                                         inScope, inEl, layout, &size), home);
748
749         outLayout = CAAudioChannelLayout (layout);
750         
751 home:
752         free (layout);
753         return result;
754 }
755
756 OSStatus        CAAudioUnit::SetChannelLayout (AudioUnitScope           inScope,
757                                                                         AudioUnitElement                        inEl,
758                                                                         CAAudioChannelLayout            &inLayout)
759 {
760         OSStatus result = AudioUnitSetProperty (AU(),
761                                                                         kAudioUnitProperty_AudioChannelLayout,
762                                                                         inScope, inEl,
763                                                                         inLayout, inLayout.Size());
764         return result;
765 }
766
767 OSStatus        CAAudioUnit::SetChannelLayout (AudioUnitScope                   inScope, 
768                                                                                         AudioUnitElement                inEl,
769                                                                                         AudioChannelLayout              &inLayout,
770                                                                                         UInt32                                  inSize)
771 {
772         OSStatus result = AudioUnitSetProperty (AU(),
773                                                                         kAudioUnitProperty_AudioChannelLayout,
774                                                                         inScope, inEl,
775                                                                         &inLayout, inSize);
776         return result;
777 }
778
779 OSStatus                CAAudioUnit::ClearChannelLayout (AudioUnitScope inScope,
780                                                                                         AudioUnitElement        inEl)
781 {
782         return AudioUnitSetProperty (AU(),
783                                                         kAudioUnitProperty_AudioChannelLayout,
784                                                         inScope, inEl, NULL, 0);
785 }
786
787 OSStatus        CAAudioUnit::GetFormat (AudioUnitScope                          inScope,
788                                                                         AudioUnitElement                        inEl,
789                                                                         AudioStreamBasicDescription     &outFormat) const
790 {
791         UInt32 dataSize = sizeof (AudioStreamBasicDescription);
792         return AudioUnitGetProperty (AU(), kAudioUnitProperty_StreamFormat,
793                                                                 inScope, inEl, 
794                                                                 &outFormat, &dataSize);
795 }
796
797 OSStatus        CAAudioUnit::SetFormat (AudioUnitScope                                          inScope,
798                                                                         AudioUnitElement                                        inEl,
799                                                                         const AudioStreamBasicDescription       &inFormat)
800 {
801         return AudioUnitSetProperty (AU(), kAudioUnitProperty_StreamFormat,
802                                                                 inScope, inEl,
803                                                                 const_cast<AudioStreamBasicDescription*>(&inFormat), 
804                                                                 sizeof (AudioStreamBasicDescription));
805 }
806
807 OSStatus        CAAudioUnit::GetSampleRate (AudioUnitScope              inScope,
808                                                                                 AudioUnitElement        inEl,
809                                                                                 Float64                         &outRate) const
810 {
811         UInt32 dataSize = sizeof (Float64);
812         return AudioUnitGetProperty (AU(), kAudioUnitProperty_SampleRate,
813                                                                 inScope, inEl, 
814                                                                 &outRate, &dataSize);
815 }
816
817 OSStatus        CAAudioUnit::SetSampleRate (AudioUnitScope              inScope,
818                                                                                 AudioUnitElement        inEl,
819                                                                                 Float64                         inRate)
820 {
821         AudioStreamBasicDescription desc;
822         OSStatus result = GetFormat (inScope, inEl, desc);
823         if (result) return result;
824         desc.mSampleRate = inRate;
825         return SetFormat (inScope, inEl, desc);
826 }
827
828 OSStatus        CAAudioUnit::SetSampleRate (Float64                     inSampleRate)
829 {
830         OSStatus result;
831         
832         UInt32 elCount;
833         require_noerr (result = GetElementCount(kAudioUnitScope_Input, elCount), home);
834         if (elCount) {
835                 for (unsigned int i = 0; i < elCount; ++i) {
836                         require_noerr (result = SetSampleRate (kAudioUnitScope_Input, i, inSampleRate), home);
837                 }
838         }
839
840         require_noerr (result = GetElementCount(kAudioUnitScope_Output, elCount), home);
841         if (elCount) {
842                 for (unsigned int i = 0; i < elCount; ++i) {
843                         require_noerr (result = SetSampleRate (kAudioUnitScope_Output, i, inSampleRate), home);
844                 }
845         }
846         
847 home:
848         return result;
849 }
850
851 OSStatus        CAAudioUnit::NumberChannels (AudioUnitScope             inScope,
852                                                                                 AudioUnitElement        inEl,
853                                                                                 UInt32                          &outChans) const
854 {
855         AudioStreamBasicDescription desc;
856         OSStatus result = GetFormat (inScope, inEl, desc);
857         if (!result)
858                 outChans = desc.mChannelsPerFrame;
859         return result;
860 }
861
862 OSStatus        CAAudioUnit::SetNumberChannels (AudioUnitScope  inScope,
863                                                                                 AudioUnitElement        inEl,
864                                                                                 UInt32                          inChans)
865 {
866                         // set this as the output of the AU
867         CAStreamBasicDescription desc;
868         OSStatus result = GetFormat (inScope, inEl, desc);
869                 if (result) return result;
870         desc.SetCanonical (inChans, desc.IsInterleaved());
871         result = SetFormat (inScope, inEl, desc);
872         return result;
873 }
874
875 OSStatus                CAAudioUnit::IsElementCountWritable (AudioUnitScope inScope, bool &outWritable) const
876 {
877         Boolean isWritable;
878         UInt32 outDataSize;
879         OSStatus result = GetPropertyInfo (kAudioUnitProperty_ElementCount, inScope, 0, &outDataSize, &isWritable);
880         if (result)
881                 return result;
882         outWritable = isWritable ? true : false;
883         return noErr;   
884 }
885
886 OSStatus                CAAudioUnit::GetElementCount (AudioUnitScope inScope, UInt32 &outCount) const
887 {
888         UInt32 propSize = sizeof(outCount);
889         return GetProperty (kAudioUnitProperty_ElementCount, inScope, 0, &outCount, &propSize);
890 }
891
892 OSStatus                CAAudioUnit::SetElementCount (AudioUnitScope inScope, UInt32 inCount)
893 {
894         return SetProperty (kAudioUnitProperty_ElementCount, inScope, 0, &inCount, sizeof(inCount));
895 }
896
897 bool                    CAAudioUnit::HasDynamicScope (AudioUnitScope inScope, SInt32 &outTotalNumChannels) const
898 {
899         // ok - now we need to check the AU's capability here.
900         // this is the default assumption of an audio effect unit
901         Boolean* isWritable = 0;
902         UInt32  dataSize = 0;
903         OSStatus result = GetPropertyInfo (kAudioUnitProperty_SupportedNumChannels,
904                                                                 kAudioUnitScope_Global, 0,
905                                                                 &dataSize, isWritable); //don't care if this is writable
906                 
907                 // AU has to explicitly tell us about this.
908         if (result) return false;
909
910         StackAUChannelInfo info (dataSize);
911         
912         result = GetProperty (kAudioUnitProperty_SupportedNumChannels,
913                                                         kAudioUnitScope_Global, 0,
914                                                         info.mChanInfo, &dataSize);
915         if (result) return false;
916
917         return ValidateDynamicScope (inScope, outTotalNumChannels, info.mChanInfo, (dataSize / sizeof(AUChannelInfo)));
918 }
919
920 // as we've already checked that the element count is writable
921 // the following conditions will match this..
922 /*
923 -1, -2 ->       signifies no restrictions
924 -2, -1 ->       signifies no restrictions -> in this case outTotalNumChannels == -1 (any num channels)
925
926 -N      (where N is less than -2), signifies the total channel count on the scope side (in or out)
927 */
928 bool    CAAudioUnit::ValidateDynamicScope (AudioUnitScope               inScope, 
929                                                                                         SInt32                          &outTotalNumChannels, 
930                                                                                         const AUChannelInfo *info, 
931                                                                                         UInt32                          numInfo) const
932 {
933         bool writable = false;
934         OSStatus result = IsElementCountWritable (inScope, writable);
935         if (result || (writable == false))
936                 return false;
937
938         //now chan layout can contain -1 for either scope (ie. doesn't care)
939         for (unsigned int i = 0; i < numInfo; ++i)
940         {
941                 // lets test the special wild card case first...
942                 // this says the AU can do any num channels on input or output - for eg. Matrix Mixer
943                 if (((info[i].inChannels == -1) && (info[i].outChannels == -2))
944                         || ((info[i].inChannels == -2) && (info[i].outChannels == -1)))
945                 {
946                         outTotalNumChannels = -1;
947                         return true;
948                 }
949                 
950                 // ok lets now test our special case....
951                 if (inScope == kAudioUnitScope_Input) {
952                                 // isn't dynamic on this side at least
953                         if (info[i].inChannels >= 0)
954                                 continue;
955                                 
956                         if (info[i].inChannels < -2) {
957                                 outTotalNumChannels = abs (info[i].inChannels);
958                                 return true;
959                         }
960                 } 
961                 
962                 else if (inScope == kAudioUnitScope_Output) {
963                                 // isn't dynamic on this side at least
964                         if (info[i].outChannels >= 0)
965                                 continue;
966                                 
967                         if (info[i].outChannels < -2) {
968                                 outTotalNumChannels = abs (info[i].outChannels);
969                                 return true;
970                         }
971                 } 
972                 
973                 else {
974                         break; // wrong scope was specified
975                 }
976         }
977         
978         return false;   
979 }
980
981 OSStatus        CAAudioUnit::ConfigureDynamicScope (AudioUnitScope              inScope, 
982                                                                                         UInt32                                  inNumElements, 
983                                                                                         UInt32                                  *inChannelsPerElement, 
984                                                                                         Float64                                 inSampleRate)
985 {
986         SInt32 numChannels = 0;
987         bool isDyamic = HasDynamicScope (inScope, numChannels);
988         if (isDyamic == false)
989                 return kAudioUnitErr_InvalidProperty;
990         
991         //lets to a sanity check...
992         // if numChannels == -1, then it can do "any"...
993         if (numChannels > 0) {
994                 SInt32 count = 0;
995                 for (unsigned int i = 0; i < inNumElements; ++i)
996                         count += inChannelsPerElement[i];
997                 if (count > numChannels)
998                         return kAudioUnitErr_InvalidPropertyValue;
999         }
1000         
1001         OSStatus result = SetElementCount (inScope, inNumElements);
1002         if (result)
1003                 return result;
1004                 
1005         CAStreamBasicDescription desc;
1006         desc.mSampleRate = inSampleRate;
1007         for (unsigned int i = 0; i < inNumElements; ++i) {
1008                 desc.SetCanonical (inChannelsPerElement[i], false);
1009                 result = SetFormat (inScope, i, desc);
1010                 if (result)
1011                         return result;
1012         }
1013         return noErr;
1014 }
1015
1016 #pragma mark __Properties
1017
1018 bool            CAAudioUnit::CanBypass () const
1019 {
1020         Boolean outWritable;
1021         OSStatus result = AudioUnitGetPropertyInfo (AU(), kAudioUnitProperty_BypassEffect,
1022                                                                         kAudioUnitScope_Global, 0,
1023                                                                         NULL, &outWritable);
1024         return (!result && outWritable);
1025 }
1026
1027 bool            CAAudioUnit::GetBypass          () const
1028 {
1029         UInt32 dataSize = sizeof (UInt32);
1030         UInt32 outBypass;
1031         OSStatus result = AudioUnitGetProperty (AU(), kAudioUnitProperty_BypassEffect,
1032                                                                 kAudioUnitScope_Global, 0,
1033                                                                 &outBypass, &dataSize);
1034         return (result ? false : outBypass);
1035 }
1036
1037 OSStatus        CAAudioUnit::SetBypass          (bool   inBypass) const
1038 {       
1039         UInt32 bypass = inBypass ? 1 : 0;
1040         return AudioUnitSetProperty (AU(), kAudioUnitProperty_BypassEffect,
1041                                                                 kAudioUnitScope_Global, 0,
1042                                                                 &bypass, sizeof (UInt32));
1043 }
1044
1045 Float64         CAAudioUnit::Latency () const
1046 {
1047         Float64 secs;
1048         UInt32 size = sizeof(secs);
1049         if (GetProperty (kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0, &secs, &size))
1050                 return 0;
1051         return secs;
1052 }
1053
1054 OSStatus        CAAudioUnit::GetAUPreset (CFPropertyListRef &outData) const
1055 {
1056         UInt32 dataSize = sizeof(outData);
1057         return AudioUnitGetProperty (AU(), kAudioUnitProperty_ClassInfo,
1058                                                                 kAudioUnitScope_Global, 0,
1059                                                                 &outData, &dataSize);
1060 }
1061
1062 OSStatus        CAAudioUnit::SetAUPreset (CFPropertyListRef &inData)
1063 {
1064         return AudioUnitSetProperty (AU(), kAudioUnitProperty_ClassInfo,
1065                                                                 kAudioUnitScope_Global, 0,
1066                                                                 &inData, sizeof (CFPropertyListRef));
1067 }
1068
1069 OSStatus        CAAudioUnit::GetPresentPreset (AUPreset &outData) const
1070 {
1071         UInt32 dataSize = sizeof(outData);
1072         OSStatus result = AudioUnitGetProperty (AU(), kAudioUnitProperty_PresentPreset,
1073                                                                 kAudioUnitScope_Global, 0,
1074                                                                 &outData, &dataSize);
1075         if (result == kAudioUnitErr_InvalidProperty) {
1076                 dataSize = sizeof(outData);
1077                 result = AudioUnitGetProperty (AU(), kAudioUnitProperty_CurrentPreset,
1078                                                                         kAudioUnitScope_Global, 0,
1079                                                                         &outData, &dataSize);
1080                 if (result == noErr) {
1081                         // we now retain the CFString in the preset so for the client of this API
1082                         // it is consistent (ie. the string should be released when done)
1083                         if (outData.presetName)
1084                                 CFRetain (outData.presetName);
1085                 }
1086         }
1087         return result;
1088 }
1089         
1090 OSStatus        CAAudioUnit::SetPresentPreset (AUPreset &inData)
1091 {
1092         OSStatus result = AudioUnitSetProperty (AU(), kAudioUnitProperty_PresentPreset,
1093                                                                 kAudioUnitScope_Global, 0,
1094                                                                 &inData, sizeof (AUPreset));
1095         if (result == kAudioUnitErr_InvalidProperty) {
1096                 result = AudioUnitSetProperty (AU(), kAudioUnitProperty_CurrentPreset,
1097                                                                 kAudioUnitScope_Global, 0,
1098                                                                 &inData, sizeof (AUPreset));
1099         }
1100         return result;
1101 }
1102
1103 bool            CAAudioUnit::HasCustomView () const
1104 {
1105         UInt32 dataSize = 0;
1106         OSStatus result = GetPropertyInfo(kAudioUnitProperty_GetUIComponentList,
1107                                         kAudioUnitScope_Global, 0,
1108                                         &dataSize, NULL);
1109         if (result || !dataSize) {
1110                 dataSize = 0;
1111                 result = GetPropertyInfo(kAudioUnitProperty_CocoaUI,
1112                                         kAudioUnitScope_Global, 0,
1113                                         &dataSize, NULL);
1114                 if (result || !dataSize)
1115                         return false;
1116         }
1117         return true;
1118 }
1119
1120 OSStatus                CAAudioUnit::GetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
1121                                                                                         Float32 &outValue) const
1122 {
1123         return mDataPtr ? (OSStatus) mDataPtr->GetParameter (inID, scope, element, outValue) : paramErr;
1124 }
1125
1126 OSStatus                CAAudioUnit::SetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
1127                                                                                         Float32 value, UInt32 bufferOffsetFrames)
1128 {
1129         return mDataPtr ? (OSStatus) mDataPtr->SetParameter (inID, scope, element, value, bufferOffsetFrames) : paramErr;
1130 }
1131
1132 OSStatus                CAAudioUnit::MIDIEvent (UInt32                  inStatus,
1133                                                                 UInt32                                  inData1,
1134                                                                 UInt32                                  inData2,
1135                                                                 UInt32                                  inOffsetSampleFrame)
1136 {
1137         return mDataPtr ? (OSStatus) mDataPtr->MIDIEvent (inStatus, inData1, inData2, inOffsetSampleFrame) : paramErr;
1138 }
1139
1140 OSStatus        CAAudioUnit::StartNote (MusicDeviceInstrumentID         inInstrument,
1141                                                                         MusicDeviceGroupID                      inGroupID,
1142                                                                         NoteInstanceID *                        outNoteInstanceID,
1143                                                                         UInt32                                          inOffsetSampleFrame,
1144                                                                         const MusicDeviceNoteParams * inParams)
1145 {
1146         return mDataPtr ? (OSStatus) mDataPtr->StartNote (inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, inParams) 
1147                 : paramErr;
1148 }
1149
1150 OSStatus        CAAudioUnit::StopNote (MusicDeviceGroupID               inGroupID,
1151                                                                         NoteInstanceID                          inNoteInstanceID,
1152                                                                         UInt32                                          inOffsetSampleFrame)
1153 {
1154         return mDataPtr ? (OSStatus) mDataPtr->StopNote (inGroupID, inNoteInstanceID, inOffsetSampleFrame) : paramErr;
1155 }
1156
1157 #pragma mark __Render
1158
1159 OSStatus                CAAudioUnit::Render (AudioUnitRenderActionFlags                         * ioActionFlags,
1160                                                                                                 const AudioTimeStamp            * inTimeStamp,
1161                                                                                                 UInt32                                          inOutputBusNumber,
1162                                                                                                 UInt32                                          inNumberFrames,
1163                                                                                                 AudioBufferList                         * ioData)
1164 {
1165         return mDataPtr ? (OSStatus) mDataPtr->Render (ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData) : paramErr;
1166 }
1167
1168 static AURenderCallbackStruct sRenderCallback;
1169 static OSStatus PrerollRenderProc (     void                                            * /*inRefCon*/, 
1170                                                                 AudioUnitRenderActionFlags              * /*inActionFlags*/,
1171                                                                 const AudioTimeStamp                    * /*inTimeStamp*/, 
1172                                                                 UInt32                                                  /*inBusNumber*/,
1173                                                                 UInt32                                                  /*inNumFrames*/, 
1174                                                                 AudioBufferList                                 *ioData)
1175 {
1176         AudioBuffer *buf = ioData->mBuffers;
1177         for (UInt32 i = ioData->mNumberBuffers; i--; ++buf)
1178                 memset((Byte *)buf->mData, 0, buf->mDataByteSize);
1179
1180         return noErr;
1181 }
1182
1183 OSStatus        CAAudioUnit::Preroll (UInt32 inFrameSize)
1184 {
1185         CAStreamBasicDescription desc;
1186         OSStatus result = GetFormat (kAudioUnitScope_Input, 0, desc);
1187         bool hasInput = false;
1188                         //we have input 
1189         if (result == noErr) 
1190         {
1191                 sRenderCallback.inputProc = PrerollRenderProc;
1192                 sRenderCallback.inputProcRefCon = 0;
1193                 
1194                 result = SetProperty (kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 
1195                                                                 0, &sRenderCallback, sizeof(sRenderCallback));
1196                 if (result) return result;
1197                 hasInput = true;
1198         }
1199         
1200         AudioUnitRenderActionFlags flags = 0;
1201         AudioTimeStamp time;
1202         memset (&time, 0, sizeof(time));
1203         time.mFlags = kAudioTimeStampSampleTimeValid;
1204
1205         CAStreamBasicDescription outputFormat;
1206         require_noerr (result = GetFormat (kAudioUnitScope_Output, 0, outputFormat), home);
1207         {
1208                 AUOutputBL list (outputFormat, inFrameSize);
1209                 list.Prepare ();
1210                 
1211                 require_noerr (result = Render (&flags, &time, 0, inFrameSize, list.ABL()), home);
1212                 require_noerr (result = GlobalReset(), home);
1213         }
1214
1215 home:
1216         if (hasInput) {
1217             // remove our installed callback
1218                 sRenderCallback.inputProc = 0;
1219                 sRenderCallback.inputProcRefCon = 0;
1220                 
1221                 SetProperty (kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 
1222                                                                 0, &sRenderCallback, sizeof(sRenderCallback));
1223         }
1224         return result;
1225 }
1226
1227 #pragma mark __CAAUChanHelper
1228
1229 CAAUChanHelper::CAAUChanHelper(const CAAudioUnit &inAU, AudioUnitScope inScope)
1230         :mChans(NULL), mNumEls(0), mDidAllocate(false)
1231 {
1232         UInt32 elCount;
1233         if (inAU.GetElementCount (inScope, elCount)) return;
1234         if (elCount > 8) {
1235                 mChans = new UInt32[elCount];
1236                 mDidAllocate = true;
1237                 memset (mChans, 0, sizeof(int) * elCount);
1238         } else {
1239                 mChans = mStaticChans;
1240                 memset (mChans, 0, sizeof(int) * 8);
1241         }
1242         for (unsigned int i = 0; i < elCount; ++i) {
1243                 UInt32 numChans;
1244                 if (inAU.NumberChannels (inScope, i, numChans)) return;
1245                 mChans[i] = numChans;
1246         }
1247         mNumEls = elCount;
1248 }
1249
1250 CAAUChanHelper::~CAAUChanHelper()
1251 {
1252         if (mDidAllocate) delete [] mChans;
1253 }
1254
1255 CAAUChanHelper&         CAAUChanHelper::operator= (const CAAUChanHelper &c) 
1256
1257         if (mDidAllocate) delete [] mChans;
1258         if (c.mDidAllocate) {
1259                 mChans = new UInt32[c.mNumEls];
1260                 mDidAllocate = true;
1261         } else {
1262                 mDidAllocate = false;
1263                 mChans = mStaticChans;
1264         }
1265         memcpy (mChans, c.mChans, c.mNumEls * sizeof(int));
1266         
1267         return *this; 
1268 }
1269
1270 #pragma mark __Print Utilities
1271
1272 void            CAAudioUnit::Print (FILE* file) const
1273 {
1274         fprintf (file, "AudioUnit:%p\n", AU());
1275         if (IsValid()) { 
1276                 fprintf (file, "\tnode=%ld\t", (long)GetAUNode()); Comp().Print (file);
1277         }
1278 }