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