globally remove all trailing whitespace from ardour code base.
[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;
359
360                         if (GetElementCount (kAudioUnitScope_Input, elCountIn)) return -1;
361                         if (GetElementCount (kAudioUnitScope_Output, elCountOut)) return -1;
362
363                         cnt = std::max(elCountIn, elCountOut);
364
365                         *chaninfo = (AUChannelInfo*) malloc (sizeof (AUChannelInfo) * cnt);
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 < cnt; ++i) {
373                                 (*chaninfo)[i].inChannels = 0;
374                         }
375
376                         for (unsigned int i = 0; i < elCountOut; ++i) {
377                                 UInt32 numChans;
378                                 if (NumberChannels (kAudioUnitScope_Output, i, numChans)) return -1;
379                                 (*chaninfo)[i].outChannels = numChans;
380                         }
381                         for (unsigned int i = elCountOut; i < cnt; ++i) {
382                                 (*chaninfo)[i].outChannels = 0;
383                         }
384                         return 0;
385                 }
386                 else 
387                 {
388                         // the au should either really tell us about this
389                         // or we will assume the worst
390                         return -1;
391                 }
392         }
393
394         *chaninfo = (AUChannelInfo*) malloc (dataSize);
395         cnt = dataSize / sizeof (AUChannelInfo);
396
397         result = GetProperty (kAudioUnitProperty_SupportedNumChannels,
398                               kAudioUnitScope_Global, 0,
399                               *chaninfo, &dataSize);
400
401         if (result) { return -1; }
402         return 0;
403 }
404
405
406 bool    CAAudioUnit::ValidateChannelPair (int                           inChannelsIn, 
407                                                                                 int                             inChannelsOut,
408                                                                                 const AUChannelInfo * info,
409                                                                                 UInt32                          numChanInfo) const
410 {
411 // we've the following cases (some combinations) to test here:
412 /*
413 >0              An explicit number of channels on either side
414 0               that side (generally input!) has no elements
415 -1              wild card:
416 -1,-1   any num channels as long as same channels on in and out
417 -1,-2   any num channels channels on in and out - special meaning
418 -2+     indicates total num channs AU can handle 
419                         - elements configurable to any num channels, 
420                         - element count in scope must be writable
421 */
422
423         //now chan layout can contain -1 for either scope (ie. doesn't care)
424         for (unsigned int i = 0; i < numChanInfo; ++i)
425         {
426                         //less than zero on both sides - check for special attributes
427                 if ((info[i].inChannels < 0) && (info[i].outChannels < 0))
428                 {
429                                 // these are our wild card matches
430                         if (info[i].inChannels == -1 && info[i].outChannels == -1) {
431                                 if (inChannelsOut == inChannelsIn) {
432                                         return true;
433                                 }
434                         }
435                         else if ((info[i].inChannels == -1 && info[i].outChannels == -2)
436                                         || (info[i].inChannels == -2 && info[i].outChannels == -1)) 
437                         {
438                                 return true;
439                         }
440                                 // these are our total num channels matches
441                                 // element count MUST be writable
442                         else {
443                                 bool outWrite = false; bool inWrite = false;
444                                 IsElementCountWritable (kAudioUnitScope_Output, outWrite);
445                                 IsElementCountWritable (kAudioUnitScope_Input, inWrite);
446                                 if (inWrite && outWrite) {
447                                         if ((inChannelsOut <= abs(info[i].outChannels))
448                                                 && (inChannelsIn <= abs(info[i].inChannels))) 
449                                         {
450                                                 return true;
451                                         }
452                                 }
453                         }
454                 }
455                         
456                         // special meaning on input, specific num on output
457                 else if (info[i].inChannels < 0) {
458                         if (info[i].outChannels == inChannelsOut) 
459                         {
460                                         // can do any in channels
461                                 if (info[i].inChannels == -1) {
462                                         return true;
463                                 } 
464                                         // total chans on input
465                                 else {
466                                         bool inWrite = false;
467                                         IsElementCountWritable (kAudioUnitScope_Input, inWrite);
468                                         if (inWrite && (inChannelsIn <= abs(info[i].inChannels))) {
469                                                 return true;
470                                         }
471                                 }
472                         }
473                 }
474                 
475                         // special meaning on output, specific num on input
476                 else if (info[i].outChannels < 0) {
477                         if (info[i].inChannels == inChannelsIn) 
478                         {
479                                         // can do any out channels
480                                 if (info[i].outChannels == -1) {
481                                         return true;
482                                 } 
483                                         // total chans on output
484                                 else {
485                                         bool outWrite = false;
486                                         IsElementCountWritable (kAudioUnitScope_Output, outWrite);
487                                         if (outWrite && (inChannelsOut <= abs(info[i].outChannels))) {
488                                                 return true;
489                                         }
490                                 }
491                         }
492                 }
493
494                         // both chans in struct >= 0 - thus has to explicitly match
495                 else if ((info[i].inChannels == inChannelsIn) && (info[i].outChannels == inChannelsOut)) {
496                         return true;
497                 } 
498                 
499                         // now check to see if a wild card on the args (inChannelsIn or inChannelsOut chans is zero) is found 
500                         // tells us to match just one side of the scopes
501                 else if (inChannelsIn == 0) {
502                         if (info[i].outChannels == inChannelsOut) {
503                                 return true;
504                         }
505                 }
506                 else if (inChannelsOut == 0) {
507                         if (info[i].inChannels == inChannelsIn) {
508                                 return true;
509                         }
510                 }
511         }
512         
513         return false;
514 }
515
516 bool CheckDynCount (SInt32 inTotalChans, const CAAUChanHelper &inHelper)
517 {
518         int totalChans = 0;
519         for (unsigned int i = 0; i < inHelper.mNumEls; ++i)
520                 totalChans += inHelper.mChans[i];
521         return (totalChans <= inTotalChans);
522 }
523
524 bool    CAAudioUnit::CheckOneSide (const CAAUChanHelper         &inHelper, 
525                                                                         bool                                    checkOutput, 
526                                                                         const AUChannelInfo             *info, 
527                                                                         UInt32                                  numInfo) const
528 {
529                 // now we can use the wildcard option (see above impl) to see if this matches
530         for (unsigned int el = 0; el < inHelper.mNumEls; ++el) {
531                 bool testAlready = false;
532                 for (unsigned int i = 0; i < el; ++i) {
533                         if (inHelper.mChans[i] == inHelper.mChans[el]) {
534                                 testAlready = true;
535                                 break;
536                         }
537                 }
538                 if (!testAlready) {
539                         if (checkOutput) {
540                                 if (!ValidateChannelPair (0, inHelper.mChans[el], info, numInfo)) return false;
541                         } else {
542                                 if (!ValidateChannelPair (inHelper.mChans[el], 0, info, numInfo)) return false;
543                         }
544                 }
545         }
546         return true;
547 }
548
549 bool            CAAudioUnit::CanDo (const CAAUChanHelper                &inputs,  
550                                                                 const CAAUChanHelper            &outputs) const
551
552 {
553 // first check our state
554                 // huh!
555         if (inputs.mNumEls == 0 && outputs.mNumEls == 0) return false;
556         
557         UInt32 elCount;
558         if (GetElementCount (kAudioUnitScope_Input, elCount)) { return false; }
559         if (elCount != inputs.mNumEls) return false;
560
561         if (GetElementCount (kAudioUnitScope_Output, elCount)) { return false; }
562         if (elCount != outputs.mNumEls) return false;
563                 
564 // (1) special cases (effects and sources (generators and instruments) only)
565         UInt32  dataSize = 0;
566         if (GetPropertyInfo (kAudioUnitProperty_SupportedNumChannels,
567                                                                         kAudioUnitScope_Global, 0, &dataSize, NULL) != noErr) 
568         {
569                 if (Comp().Desc().IsEffect() || Comp().Desc().IsOffline()) {
570                         UInt32 numChan = outputs.mNumEls > 0 ? outputs.mChans[0] : inputs.mChans[0];
571                         for (unsigned int in = 0; in < inputs.mNumEls; ++in)
572                                 if (numChan != inputs.mChans[in]) return false;
573                         for (unsigned int out = 0; out < outputs.mNumEls; ++out)
574                                 if (numChan != outputs.mChans[out]) return false;
575                         return true;
576                 }
577                 
578                         // in this case, all the channels have to match the current config
579                 if (Comp().Desc().IsGenerator() || Comp().Desc().IsMusicDevice()) {
580                         for (unsigned int in = 0; in < inputs.mNumEls; ++in) {
581                                 UInt32 chan;
582                                 if (NumberChannels (kAudioUnitScope_Input, in, chan)) return false;
583                                 if (chan != UInt32(inputs.mChans[in])) return false;
584                         }
585                         for (unsigned int out = 0; out < outputs.mNumEls; ++out) {
586                                 UInt32 chan;
587                                 if (NumberChannels (kAudioUnitScope_Output, out, chan)) return false;
588                                 if (chan != UInt32(outputs.mChans[out])) return false;
589                         }
590                         return true;
591                 }
592                 
593                         // if we get here we can't determine anything about channel capabilities
594                 return false;
595         }
596
597         StackAUChannelInfo info (dataSize);
598         
599         if (GetProperty (kAudioUnitProperty_SupportedNumChannels,
600                                                         kAudioUnitScope_Global, 0,
601                                                         info.mChanInfo, &dataSize) != noErr)
602         { 
603                 return false; 
604         }
605         
606         int numInfo = dataSize / sizeof(AUChannelInfo);
607         
608 // (2) Test for dynamic capability (or no elements on that scope)
609         SInt32 dynInChans = 0;
610         if (ValidateDynamicScope (kAudioUnitScope_Input, dynInChans, info.mChanInfo, numInfo)) {
611                 if (CheckDynCount (dynInChans, inputs) == false) return false;
612         }
613
614         SInt32 dynOutChans = 0;
615         if (ValidateDynamicScope (kAudioUnitScope_Output, dynOutChans, info.mChanInfo, numInfo)) {
616                 if (CheckDynCount (dynOutChans, outputs) == false) return false;
617         }
618
619         if (dynOutChans && dynInChans) { return true; }
620
621 // (3)  Just need to test one side
622         if (dynInChans || (inputs.mNumEls == 0)) {
623                 return CheckOneSide (outputs, true, info.mChanInfo, numInfo);
624         }
625
626         if (dynOutChans || (outputs.mNumEls == 0)) {
627                 return CheckOneSide (inputs, false, info.mChanInfo, numInfo);
628         }
629
630 // (4) - not a dynamic AU, has ins and outs, and has channel constraints so we test every possible pairing
631         for (unsigned int in = 0; in < inputs.mNumEls; ++in) 
632         {
633                 bool testInAlready = false;
634                 for (unsigned int i = 0; i < in; ++i) {
635                         if (inputs.mChans[i] == inputs.mChans[in]) {
636                                 testInAlready = true;
637                                 break;
638                         }
639                 }
640                 if (!testInAlready) {
641                         for (unsigned int out = 0; out < outputs.mNumEls; ++out) {
642                                         // try to save a little bit and not test the same pairing multiple times...
643                                 bool testOutAlready = false;
644                                 for (unsigned int i = 0; i < out; ++i) {
645                                         if (outputs.mChans[i] == outputs.mChans[out]) {
646                                                 testOutAlready = true;
647                                                 break;
648                                         }
649                                 }
650                                 if (!testOutAlready) {
651                                         if (!ValidateChannelPair (inputs.mChans[in], outputs.mChans[out],info.mChanInfo, numInfo)) {
652                                                 return false;
653                                         }
654                                 }
655                         }
656                 }
657         }
658         
659         return true;
660 }
661
662 bool            CAAudioUnit::SupportsNumChannels () const
663 {
664         // this is the default assumption of an audio effect unit
665         Boolean* isWritable = 0;
666         UInt32  dataSize = 0;
667                 // lets see if the unit has any channel restrictions
668         OSStatus result = AudioUnitGetPropertyInfo (AU(),
669                                                                         kAudioUnitProperty_SupportedNumChannels,
670                                                                         kAudioUnitScope_Global, 0,
671                                                                         &dataSize, isWritable); //don't care if this is writable
672                 
673                 // if this property is NOT implemented an FX unit
674                 // is expected to deal with same channel valance in and out
675         if (result) {
676                 if (Comp().Desc().IsEffect() || Comp().Desc().IsOffline())
677                         return true;
678         }
679         return result == noErr;
680 }
681
682 bool            CAAudioUnit::GetChannelLayouts (AudioUnitScope                  inScope,
683                                                                                 AudioUnitElement                        inEl,
684                                                                                 ChannelTagVector                        &outChannelVector) const
685 {
686         if (HasChannelLayouts (inScope, inEl) == false) return false; 
687
688         UInt32 dataSize;
689         OSStatus result = AudioUnitGetPropertyInfo (AU(),
690                                                                 kAudioUnitProperty_SupportedChannelLayoutTags,
691                                                                 inScope, inEl,
692                                                                 &dataSize, NULL);
693
694         if (result == kAudioUnitErr_InvalidProperty) {
695                 // if we get here we can do layouts but we've got the speaker config property
696                 outChannelVector.erase (outChannelVector.begin(), outChannelVector.end());
697                 outChannelVector.push_back (kAudioChannelLayoutTag_Stereo);
698                 outChannelVector.push_back (kAudioChannelLayoutTag_StereoHeadphones);
699                 outChannelVector.push_back (kAudioChannelLayoutTag_Quadraphonic);
700                 outChannelVector.push_back (kAudioChannelLayoutTag_AudioUnit_5_0);
701                 return true;
702         }
703
704         if (result) return false;
705         
706         bool canDo = false;
707                 // OK lets get our channel layouts and see if the one we want is present
708         AudioChannelLayoutTag* info = (AudioChannelLayoutTag*)malloc (dataSize);
709         result = AudioUnitGetProperty (AU(),
710                                                         kAudioUnitProperty_SupportedChannelLayoutTags,
711                                                         inScope, inEl,
712                                                         info, &dataSize);
713         if (result) goto home;
714         
715         outChannelVector.erase (outChannelVector.begin(), outChannelVector.end());
716         for (unsigned int i = 0; i < (dataSize / sizeof (AudioChannelLayoutTag)); ++i)
717                 outChannelVector.push_back (info[i]);
718
719 home:
720         free (info);
721         return canDo;
722 }
723
724 bool            CAAudioUnit::HasChannelLayouts (AudioUnitScope          inScope, 
725                                                                                 AudioUnitElement                inEl) const
726 {
727         OSStatus result = AudioUnitGetPropertyInfo (AU(),
728                                                                         kAudioUnitProperty_SupportedChannelLayoutTags,
729                                                                         inScope, inEl,
730                                                                         NULL, NULL);
731         return !result;
732 }
733
734 OSStatus        CAAudioUnit::GetChannelLayout (AudioUnitScope           inScope,
735                                                                                 AudioUnitElement                inEl,
736                                                                                 CAAudioChannelLayout    &outLayout) const
737 {
738         UInt32 size;
739         OSStatus result = AudioUnitGetPropertyInfo (AU(), kAudioUnitProperty_AudioChannelLayout,
740                                                                         inScope, inEl, &size, NULL);
741         if (result) return result;
742         
743         AudioChannelLayout *layout = (AudioChannelLayout*)malloc (size);
744
745         require_noerr (result = AudioUnitGetProperty (AU(), kAudioUnitProperty_AudioChannelLayout,
746                                                                         inScope, inEl, layout, &size), home);
747
748         outLayout = CAAudioChannelLayout (layout);
749         
750 home:
751         free (layout);
752         return result;
753 }
754
755 OSStatus        CAAudioUnit::SetChannelLayout (AudioUnitScope           inScope,
756                                                                         AudioUnitElement                        inEl,
757                                                                         CAAudioChannelLayout            &inLayout)
758 {
759         OSStatus result = AudioUnitSetProperty (AU(),
760                                                                         kAudioUnitProperty_AudioChannelLayout,
761                                                                         inScope, inEl,
762                                                                         inLayout, inLayout.Size());
763         return result;
764 }
765
766 OSStatus        CAAudioUnit::SetChannelLayout (AudioUnitScope                   inScope, 
767                                                                                         AudioUnitElement                inEl,
768                                                                                         AudioChannelLayout              &inLayout,
769                                                                                         UInt32                                  inSize)
770 {
771         OSStatus result = AudioUnitSetProperty (AU(),
772                                                                         kAudioUnitProperty_AudioChannelLayout,
773                                                                         inScope, inEl,
774                                                                         &inLayout, inSize);
775         return result;
776 }
777
778 OSStatus                CAAudioUnit::ClearChannelLayout (AudioUnitScope inScope,
779                                                                                         AudioUnitElement        inEl)
780 {
781         return AudioUnitSetProperty (AU(),
782                                                         kAudioUnitProperty_AudioChannelLayout,
783                                                         inScope, inEl, NULL, 0);
784 }
785
786 OSStatus        CAAudioUnit::GetFormat (AudioUnitScope                          inScope,
787                                                                         AudioUnitElement                        inEl,
788                                                                         AudioStreamBasicDescription     &outFormat) const
789 {
790         UInt32 dataSize = sizeof (AudioStreamBasicDescription);
791         return AudioUnitGetProperty (AU(), kAudioUnitProperty_StreamFormat,
792                                                                 inScope, inEl, 
793                                                                 &outFormat, &dataSize);
794 }
795
796 OSStatus        CAAudioUnit::SetFormat (AudioUnitScope                                          inScope,
797                                                                         AudioUnitElement                                        inEl,
798                                                                         const AudioStreamBasicDescription       &inFormat)
799 {
800         return AudioUnitSetProperty (AU(), kAudioUnitProperty_StreamFormat,
801                                                                 inScope, inEl,
802                                                                 const_cast<AudioStreamBasicDescription*>(&inFormat), 
803                                                                 sizeof (AudioStreamBasicDescription));
804 }
805
806 OSStatus        CAAudioUnit::GetSampleRate (AudioUnitScope              inScope,
807                                                                                 AudioUnitElement        inEl,
808                                                                                 Float64                         &outRate) const
809 {
810         UInt32 dataSize = sizeof (Float64);
811         return AudioUnitGetProperty (AU(), kAudioUnitProperty_SampleRate,
812                                                                 inScope, inEl, 
813                                                                 &outRate, &dataSize);
814 }
815
816 OSStatus        CAAudioUnit::SetSampleRate (AudioUnitScope              inScope,
817                                                                                 AudioUnitElement        inEl,
818                                                                                 Float64                         inRate)
819 {
820         AudioStreamBasicDescription desc;
821         OSStatus result = GetFormat (inScope, inEl, desc);
822         if (result) return result;
823         desc.mSampleRate = inRate;
824         return SetFormat (inScope, inEl, desc);
825 }
826
827 OSStatus        CAAudioUnit::SetSampleRate (Float64                     inSampleRate)
828 {
829         OSStatus result;
830         
831         UInt32 elCount;
832         require_noerr (result = GetElementCount(kAudioUnitScope_Input, elCount), home);
833         if (elCount) {
834                 for (unsigned int i = 0; i < elCount; ++i) {
835                         require_noerr (result = SetSampleRate (kAudioUnitScope_Input, i, inSampleRate), home);
836                 }
837         }
838
839         require_noerr (result = GetElementCount(kAudioUnitScope_Output, elCount), home);
840         if (elCount) {
841                 for (unsigned int i = 0; i < elCount; ++i) {
842                         require_noerr (result = SetSampleRate (kAudioUnitScope_Output, i, inSampleRate), home);
843                 }
844         }
845         
846 home:
847         return result;
848 }
849
850 OSStatus        CAAudioUnit::NumberChannels (AudioUnitScope             inScope,
851                                                                                 AudioUnitElement        inEl,
852                                                                                 UInt32                          &outChans) const
853 {
854         AudioStreamBasicDescription desc;
855         OSStatus result = GetFormat (inScope, inEl, desc);
856         if (!result)
857                 outChans = desc.mChannelsPerFrame;
858         return result;
859 }
860
861 OSStatus        CAAudioUnit::SetNumberChannels (AudioUnitScope  inScope,
862                                                                                 AudioUnitElement        inEl,
863                                                                                 UInt32                          inChans)
864 {
865                         // set this as the output of the AU
866         CAStreamBasicDescription desc;
867         OSStatus result = GetFormat (inScope, inEl, desc);
868                 if (result) return result;
869         desc.SetCanonical (inChans, desc.IsInterleaved());
870         result = SetFormat (inScope, inEl, desc);
871         return result;
872 }
873
874 OSStatus                CAAudioUnit::IsElementCountWritable (AudioUnitScope inScope, bool &outWritable) const
875 {
876         Boolean isWritable;
877         UInt32 outDataSize;
878         OSStatus result = GetPropertyInfo (kAudioUnitProperty_ElementCount, inScope, 0, &outDataSize, &isWritable);
879         if (result)
880                 return result;
881         outWritable = isWritable ? true : false;
882         return noErr;   
883 }
884
885 OSStatus                CAAudioUnit::GetElementCount (AudioUnitScope inScope, UInt32 &outCount) const
886 {
887         UInt32 propSize = sizeof(outCount);
888         return GetProperty (kAudioUnitProperty_ElementCount, inScope, 0, &outCount, &propSize);
889 }
890
891 OSStatus                CAAudioUnit::SetElementCount (AudioUnitScope inScope, UInt32 inCount)
892 {
893         return SetProperty (kAudioUnitProperty_ElementCount, inScope, 0, &inCount, sizeof(inCount));
894 }
895
896 bool                    CAAudioUnit::HasDynamicScope (AudioUnitScope inScope, SInt32 &outTotalNumChannels) const
897 {
898         // ok - now we need to check the AU's capability here.
899         // this is the default assumption of an audio effect unit
900         Boolean* isWritable = 0;
901         UInt32  dataSize = 0;
902         OSStatus result = GetPropertyInfo (kAudioUnitProperty_SupportedNumChannels,
903                                                                 kAudioUnitScope_Global, 0,
904                                                                 &dataSize, isWritable); //don't care if this is writable
905                 
906                 // AU has to explicitly tell us about this.
907         if (result) return false;
908
909         StackAUChannelInfo info (dataSize);
910         
911         result = GetProperty (kAudioUnitProperty_SupportedNumChannels,
912                                                         kAudioUnitScope_Global, 0,
913                                                         info.mChanInfo, &dataSize);
914         if (result) return false;
915
916         return ValidateDynamicScope (inScope, outTotalNumChannels, info.mChanInfo, (dataSize / sizeof(AUChannelInfo)));
917 }
918
919 // as we've already checked that the element count is writable
920 // the following conditions will match this..
921 /*
922 -1, -2 ->       signifies no restrictions
923 -2, -1 ->       signifies no restrictions -> in this case outTotalNumChannels == -1 (any num channels)
924
925 -N      (where N is less than -2), signifies the total channel count on the scope side (in or out)
926 */
927 bool    CAAudioUnit::ValidateDynamicScope (AudioUnitScope               inScope, 
928                                                                                         SInt32                          &outTotalNumChannels, 
929                                                                                         const AUChannelInfo *info, 
930                                                                                         UInt32                          numInfo) const
931 {
932         bool writable = false;
933         OSStatus result = IsElementCountWritable (inScope, writable);
934         if (result || (writable == false))
935                 return false;
936
937         //now chan layout can contain -1 for either scope (ie. doesn't care)
938         for (unsigned int i = 0; i < numInfo; ++i)
939         {
940                 // lets test the special wild card case first...
941                 // this says the AU can do any num channels on input or output - for eg. Matrix Mixer
942                 if (((info[i].inChannels == -1) && (info[i].outChannels == -2))
943                         || ((info[i].inChannels == -2) && (info[i].outChannels == -1)))
944                 {
945                         outTotalNumChannels = -1;
946                         return true;
947                 }
948                 
949                 // ok lets now test our special case....
950                 if (inScope == kAudioUnitScope_Input) {
951                                 // isn't dynamic on this side at least
952                         if (info[i].inChannels >= 0)
953                                 continue;
954                                 
955                         if (info[i].inChannels < -2) {
956                                 outTotalNumChannels = abs (info[i].inChannels);
957                                 return true;
958                         }
959                 } 
960                 
961                 else if (inScope == kAudioUnitScope_Output) {
962                                 // isn't dynamic on this side at least
963                         if (info[i].outChannels >= 0)
964                                 continue;
965                                 
966                         if (info[i].outChannels < -2) {
967                                 outTotalNumChannels = abs (info[i].outChannels);
968                                 return true;
969                         }
970                 } 
971                 
972                 else {
973                         break; // wrong scope was specified
974                 }
975         }
976         
977         return false;   
978 }
979
980 OSStatus        CAAudioUnit::ConfigureDynamicScope (AudioUnitScope              inScope, 
981                                                                                         UInt32                                  inNumElements, 
982                                                                                         UInt32                                  *inChannelsPerElement, 
983                                                                                         Float64                                 inSampleRate)
984 {
985         SInt32 numChannels = 0;
986         bool isDyamic = HasDynamicScope (inScope, numChannels);
987         if (isDyamic == false)
988                 return kAudioUnitErr_InvalidProperty;
989         
990         //lets to a sanity check...
991         // if numChannels == -1, then it can do "any"...
992         if (numChannels > 0) {
993                 SInt32 count = 0;
994                 for (unsigned int i = 0; i < inNumElements; ++i)
995                         count += inChannelsPerElement[i];
996                 if (count > numChannels)
997                         return kAudioUnitErr_InvalidPropertyValue;
998         }
999         
1000         OSStatus result = SetElementCount (inScope, inNumElements);
1001         if (result)
1002                 return result;
1003                 
1004         CAStreamBasicDescription desc;
1005         desc.mSampleRate = inSampleRate;
1006         for (unsigned int i = 0; i < inNumElements; ++i) {
1007                 desc.SetCanonical (inChannelsPerElement[i], false);
1008                 result = SetFormat (inScope, i, desc);
1009                 if (result)
1010                         return result;
1011         }
1012         return noErr;
1013 }
1014
1015 #pragma mark __Properties
1016
1017 bool            CAAudioUnit::CanBypass () const
1018 {
1019         Boolean outWritable;
1020         OSStatus result = AudioUnitGetPropertyInfo (AU(), kAudioUnitProperty_BypassEffect,
1021                                                                         kAudioUnitScope_Global, 0,
1022                                                                         NULL, &outWritable);
1023         return (!result && outWritable);
1024 }
1025
1026 bool            CAAudioUnit::GetBypass          () const
1027 {
1028         UInt32 dataSize = sizeof (UInt32);
1029         UInt32 outBypass;
1030         OSStatus result = AudioUnitGetProperty (AU(), kAudioUnitProperty_BypassEffect,
1031                                                                 kAudioUnitScope_Global, 0,
1032                                                                 &outBypass, &dataSize);
1033         return (result ? false : outBypass);
1034 }
1035
1036 OSStatus        CAAudioUnit::SetBypass          (bool   inBypass) const
1037 {       
1038         UInt32 bypass = inBypass ? 1 : 0;
1039         return AudioUnitSetProperty (AU(), kAudioUnitProperty_BypassEffect,
1040                                                                 kAudioUnitScope_Global, 0,
1041                                                                 &bypass, sizeof (UInt32));
1042 }
1043
1044 Float64         CAAudioUnit::Latency () const
1045 {
1046         Float64 secs;
1047         UInt32 size = sizeof(secs);
1048         if (GetProperty (kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0, &secs, &size))
1049                 return 0;
1050         return secs;
1051 }
1052
1053 OSStatus        CAAudioUnit::GetAUPreset (CFPropertyListRef &outData) const
1054 {
1055         UInt32 dataSize = sizeof(outData);
1056         return AudioUnitGetProperty (AU(), kAudioUnitProperty_ClassInfo,
1057                                                                 kAudioUnitScope_Global, 0,
1058                                                                 &outData, &dataSize);
1059 }
1060
1061 OSStatus        CAAudioUnit::SetAUPreset (CFPropertyListRef &inData)
1062 {
1063         return AudioUnitSetProperty (AU(), kAudioUnitProperty_ClassInfo,
1064                                                                 kAudioUnitScope_Global, 0,
1065                                                                 &inData, sizeof (CFPropertyListRef));
1066 }
1067
1068 OSStatus        CAAudioUnit::GetPresentPreset (AUPreset &outData) const
1069 {
1070         UInt32 dataSize = sizeof(outData);
1071         OSStatus result = AudioUnitGetProperty (AU(), kAudioUnitProperty_PresentPreset,
1072                                                                 kAudioUnitScope_Global, 0,
1073                                                                 &outData, &dataSize);
1074         if (result == kAudioUnitErr_InvalidProperty) {
1075                 dataSize = sizeof(outData);
1076                 result = AudioUnitGetProperty (AU(), kAudioUnitProperty_CurrentPreset,
1077                                                                         kAudioUnitScope_Global, 0,
1078                                                                         &outData, &dataSize);
1079                 if (result == noErr) {
1080                         // we now retain the CFString in the preset so for the client of this API
1081                         // it is consistent (ie. the string should be released when done)
1082                         if (outData.presetName)
1083                                 CFRetain (outData.presetName);
1084                 }
1085         }
1086         return result;
1087 }
1088         
1089 OSStatus        CAAudioUnit::SetPresentPreset (AUPreset &inData)
1090 {
1091         OSStatus result = AudioUnitSetProperty (AU(), kAudioUnitProperty_PresentPreset,
1092                                                                 kAudioUnitScope_Global, 0,
1093                                                                 &inData, sizeof (AUPreset));
1094         if (result == kAudioUnitErr_InvalidProperty) {
1095                 result = AudioUnitSetProperty (AU(), kAudioUnitProperty_CurrentPreset,
1096                                                                 kAudioUnitScope_Global, 0,
1097                                                                 &inData, sizeof (AUPreset));
1098         }
1099         return result;
1100 }
1101
1102 bool            CAAudioUnit::HasCustomView () const
1103 {
1104         UInt32 dataSize = 0;
1105         OSStatus result = GetPropertyInfo(kAudioUnitProperty_GetUIComponentList,
1106                                         kAudioUnitScope_Global, 0,
1107                                         &dataSize, NULL);
1108         if (result || !dataSize) {
1109                 dataSize = 0;
1110                 result = GetPropertyInfo(kAudioUnitProperty_CocoaUI,
1111                                         kAudioUnitScope_Global, 0,
1112                                         &dataSize, NULL);
1113                 if (result || !dataSize)
1114                         return false;
1115         }
1116         return true;
1117 }
1118
1119 OSStatus                CAAudioUnit::GetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
1120                                                                                         Float32 &outValue) const
1121 {
1122         return mDataPtr ? (OSStatus) mDataPtr->GetParameter (inID, scope, element, outValue) : paramErr;
1123 }
1124
1125 OSStatus                CAAudioUnit::SetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
1126                                                                                         Float32 value, UInt32 bufferOffsetFrames)
1127 {
1128         return mDataPtr ? (OSStatus) mDataPtr->SetParameter (inID, scope, element, value, bufferOffsetFrames) : paramErr;
1129 }
1130
1131 OSStatus                CAAudioUnit::MIDIEvent (UInt32                  inStatus,
1132                                                                 UInt32                                  inData1,
1133                                                                 UInt32                                  inData2,
1134                                                                 UInt32                                  inOffsetSampleFrame)
1135 {
1136         return mDataPtr ? (OSStatus) mDataPtr->MIDIEvent (inStatus, inData1, inData2, inOffsetSampleFrame) : paramErr;
1137 }
1138
1139 OSStatus        CAAudioUnit::StartNote (MusicDeviceInstrumentID         inInstrument,
1140                                                                         MusicDeviceGroupID                      inGroupID,
1141                                                                         NoteInstanceID *                        outNoteInstanceID,
1142                                                                         UInt32                                          inOffsetSampleFrame,
1143                                                                         const MusicDeviceNoteParams * inParams)
1144 {
1145         return mDataPtr ? (OSStatus) mDataPtr->StartNote (inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, inParams) 
1146                 : paramErr;
1147 }
1148
1149 OSStatus        CAAudioUnit::StopNote (MusicDeviceGroupID               inGroupID,
1150                                                                         NoteInstanceID                          inNoteInstanceID,
1151                                                                         UInt32                                          inOffsetSampleFrame)
1152 {
1153         return mDataPtr ? (OSStatus) mDataPtr->StopNote (inGroupID, inNoteInstanceID, inOffsetSampleFrame) : paramErr;
1154 }
1155
1156 #pragma mark __Render
1157
1158 OSStatus                CAAudioUnit::Render (AudioUnitRenderActionFlags                         * ioActionFlags,
1159                                                                                                 const AudioTimeStamp            * inTimeStamp,
1160                                                                                                 UInt32                                          inOutputBusNumber,
1161                                                                                                 UInt32                                          inNumberFrames,
1162                                                                                                 AudioBufferList                         * ioData)
1163 {
1164         return mDataPtr ? (OSStatus) mDataPtr->Render (ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData) : paramErr;
1165 }
1166
1167 static AURenderCallbackStruct sRenderCallback;
1168 static OSStatus PrerollRenderProc (     void                                            * /*inRefCon*/, 
1169                                                                 AudioUnitRenderActionFlags              * /*inActionFlags*/,
1170                                                                 const AudioTimeStamp                    * /*inTimeStamp*/, 
1171                                                                 UInt32                                                  /*inBusNumber*/,
1172                                                                 UInt32                                                  /*inNumFrames*/, 
1173                                                                 AudioBufferList                                 *ioData)
1174 {
1175         AudioBuffer *buf = ioData->mBuffers;
1176         for (UInt32 i = ioData->mNumberBuffers; i--; ++buf)
1177                 memset((Byte *)buf->mData, 0, buf->mDataByteSize);
1178
1179         return noErr;
1180 }
1181
1182 OSStatus        CAAudioUnit::Preroll (UInt32 inFrameSize)
1183 {
1184         CAStreamBasicDescription desc;
1185         OSStatus result = GetFormat (kAudioUnitScope_Input, 0, desc);
1186         bool hasInput = false;
1187                         //we have input 
1188         if (result == noErr) 
1189         {
1190                 sRenderCallback.inputProc = PrerollRenderProc;
1191                 sRenderCallback.inputProcRefCon = 0;
1192                 
1193                 result = SetProperty (kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 
1194                                                                 0, &sRenderCallback, sizeof(sRenderCallback));
1195                 if (result) return result;
1196                 hasInput = true;
1197         }
1198         
1199         AudioUnitRenderActionFlags flags = 0;
1200         AudioTimeStamp time;
1201         memset (&time, 0, sizeof(time));
1202         time.mFlags = kAudioTimeStampSampleTimeValid;
1203
1204         CAStreamBasicDescription outputFormat;
1205         require_noerr (result = GetFormat (kAudioUnitScope_Output, 0, outputFormat), home);
1206         {
1207                 AUOutputBL list (outputFormat, inFrameSize);
1208                 list.Prepare ();
1209                 
1210                 require_noerr (result = Render (&flags, &time, 0, inFrameSize, list.ABL()), home);
1211                 require_noerr (result = GlobalReset(), home);
1212         }
1213
1214 home:
1215         if (hasInput) {
1216             // remove our installed callback
1217                 sRenderCallback.inputProc = 0;
1218                 sRenderCallback.inputProcRefCon = 0;
1219                 
1220                 SetProperty (kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 
1221                                                                 0, &sRenderCallback, sizeof(sRenderCallback));
1222         }
1223         return result;
1224 }
1225
1226 #pragma mark __CAAUChanHelper
1227
1228 CAAUChanHelper::CAAUChanHelper(const CAAudioUnit &inAU, AudioUnitScope inScope)
1229         :mChans(NULL), mNumEls(0), mDidAllocate(false)
1230 {
1231         UInt32 elCount;
1232         if (inAU.GetElementCount (inScope, elCount)) return;
1233         if (elCount > 8) {
1234                 mChans = new UInt32[elCount];
1235                 mDidAllocate = true;
1236                 memset (mChans, 0, sizeof(int) * elCount);
1237         } else {
1238                 mChans = mStaticChans;
1239                 memset (mChans, 0, sizeof(int) * 8);
1240         }
1241         for (unsigned int i = 0; i < elCount; ++i) {
1242                 UInt32 numChans;
1243                 if (inAU.NumberChannels (inScope, i, numChans)) return;
1244                 mChans[i] = numChans;
1245         }
1246         mNumEls = elCount;
1247 }
1248
1249 CAAUChanHelper::~CAAUChanHelper()
1250 {
1251         if (mDidAllocate) delete [] mChans;
1252 }
1253
1254 CAAUChanHelper&         CAAUChanHelper::operator= (const CAAUChanHelper &c) 
1255
1256         if (mDidAllocate) delete [] mChans;
1257         if (c.mDidAllocate) {
1258                 mChans = new UInt32[c.mNumEls];
1259                 mDidAllocate = true;
1260         } else {
1261                 mDidAllocate = false;
1262                 mChans = mStaticChans;
1263         }
1264         memcpy (mChans, c.mChans, c.mNumEls * sizeof(int));
1265         
1266         return *this; 
1267 }
1268
1269 #pragma mark __Print Utilities
1270
1271 void            CAAudioUnit::Print (FILE* file) const
1272 {
1273         fprintf (file, "AudioUnit:%p\n", AU());
1274         if (IsValid()) { 
1275                 fprintf (file, "\tnode=%ld\t", (long)GetAUNode()); Comp().Print (file);
1276         }
1277 }