alternative new version of the AppleUtility library
[ardour.git] / libs / appleutility / CoreAudio / AudioUnits / AUPublic / AUBase / AUBase.cpp
1 /*
2      File: AUBase.cpp
3  Abstract: AUBase.h
4   Version: 1.1
5  
6  Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
7  Inc. ("Apple") in consideration of your agreement to the following
8  terms, and your use, installation, modification or redistribution of
9  this Apple software constitutes acceptance of these terms.  If you do
10  not agree with these terms, please do not use, install, modify or
11  redistribute this Apple software.
12  
13  In consideration of your agreement to abide by the following terms, and
14  subject to these terms, Apple grants you a personal, non-exclusive
15  license, under Apple's copyrights in this original Apple software (the
16  "Apple Software"), to use, reproduce, modify and redistribute the Apple
17  Software, with or without modifications, in source and/or binary forms;
18  provided that if you redistribute the Apple Software in its entirety and
19  without modifications, you must retain this notice and the following
20  text and disclaimers in all such redistributions of the Apple Software.
21  Neither the name, trademarks, service marks or logos of Apple Inc. may
22  be used to endorse or promote products derived from the Apple Software
23  without specific prior written permission from Apple.  Except as
24  expressly stated in this notice, no other rights or licenses, express or
25  implied, are granted by Apple herein, including but not limited to any
26  patent rights that may be infringed by your derivative works or by other
27  works in which the Apple Software may be incorporated.
28  
29  The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
30  MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
31  THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
32  FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
33  OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
34  
35  IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
36  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38  INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
39  MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
40  AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
41  STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
42  POSSIBILITY OF SUCH DAMAGE.
43  
44  Copyright (C) 2014 Apple Inc. All Rights Reserved.
45  
46 */
47 #include "AUBase.h"
48 #include "AUDispatch.h"
49 #include "AUInputElement.h"
50 #include "AUOutputElement.h"
51 #include <algorithm>
52 #include <syslog.h>
53 #include "CAAudioChannelLayout.h"
54 #include "CAHostTimeBase.h"
55 #include "CAVectorUnit.h"
56 #include "CAXException.h"
57
58
59
60 #if TARGET_OS_MAC && (TARGET_CPU_X86 || TARGET_CPU_X86_64)
61         // our compiler does ALL floating point with SSE
62         inline int  GETCSR ()    { int _result; asm volatile ("stmxcsr %0" : "=m" (*&_result) ); return _result; }
63         inline void SETCSR (int a)    { int _temp = a; asm volatile( "ldmxcsr %0" : : "m" (*&_temp ) ); }
64
65         #define DISABLE_DENORMALS int _savemxcsr = GETCSR(); SETCSR(_savemxcsr | 0x8040);
66         #define RESTORE_DENORMALS SETCSR(_savemxcsr);
67 #else
68         #define DISABLE_DENORMALS
69         #define RESTORE_DENORMALS
70 #endif
71
72 static bool sAUBaseCFStringsInitialized = false;
73 // this is used for the presets
74 static CFStringRef kUntitledString = NULL;
75 //these are the current keys for the class info document
76 static CFStringRef kVersionString = NULL;
77 static CFStringRef kTypeString = NULL;
78 static CFStringRef kSubtypeString = NULL;
79 static CFStringRef kManufacturerString = NULL;
80 static CFStringRef kDataString = NULL;
81 static CFStringRef kNameString = NULL;
82 static CFStringRef kRenderQualityString = NULL;
83 static CFStringRef kCPULoadString = NULL;
84 static CFStringRef kElementNameString = NULL;
85 static CFStringRef kPartString = NULL;
86
87 SInt32 AUBase::sVectorUnitType = kVecUninitialized;
88
89 //_____________________________________________________________________________
90 //
91 AUBase::AUBase( AudioComponentInstance                  inInstance, 
92                                 UInt32                                                  numInputElements,
93                                 UInt32                                                  numOutputElements,
94                                 UInt32                                                  numGroupElements) :
95         ComponentBase(inInstance),
96         mElementsCreated(false),
97         mInitialized(false),
98         mHasBegunInitializing(false),
99         mInitNumInputEls(numInputElements), mInitNumOutputEls(numOutputElements), 
100 #if !CA_BASIC_AU_FEATURES
101         mInitNumGroupEls(numGroupElements),
102 #endif
103         mRenderCallbacksTouched(false),
104         mRenderThreadID (NULL),
105         mWantsRenderThreadID (false),
106         mLastRenderError(0),
107         mUsesFixedBlockSize(false),
108         mBuffersAllocated(false),
109         mLogString (NULL),
110     mNickName (NULL),
111         mAUMutex(NULL)
112         #if !CA_NO_AU_UI_FEATURES
113                 ,
114                 mContextName(NULL)
115         #endif
116 {
117         ResetRenderTime ();
118         
119         if(!sAUBaseCFStringsInitialized)
120         {
121                 kUntitledString = CFSTR("Untitled");
122                 kVersionString = CFSTR(kAUPresetVersionKey);
123                 kTypeString = CFSTR(kAUPresetTypeKey);
124                 kSubtypeString = CFSTR(kAUPresetSubtypeKey);
125                 kManufacturerString = CFSTR(kAUPresetManufacturerKey);
126                 kDataString = CFSTR(kAUPresetDataKey);
127                 kNameString = CFSTR(kAUPresetNameKey);
128                 kRenderQualityString = CFSTR(kAUPresetRenderQualityKey);
129                 kCPULoadString = CFSTR(kAUPresetCPULoadKey);
130                 kElementNameString = CFSTR(kAUPresetElementNameKey);
131                 kPartString = CFSTR(kAUPresetPartKey);
132                 sAUBaseCFStringsInitialized = true;
133         }
134
135         if (sVectorUnitType == kVecUninitialized) {
136                 sVectorUnitType = CAVectorUnit::GetVectorUnitType() ;
137         }
138
139         mAudioUnitAPIVersion = 2;
140         
141         SetMaxFramesPerSlice(kAUDefaultMaxFramesPerSlice);
142
143         GlobalScope().Initialize(this, kAudioUnitScope_Global, 1);
144         
145 #if !CA_NO_AU_UI_FEATURES
146         memset (&mHostCallbackInfo, 0, sizeof (mHostCallbackInfo));
147 #endif
148
149
150         mCurrentPreset.presetNumber = -1;
151         mCurrentPreset.presetName = kUntitledString;
152         CFRetain (mCurrentPreset.presetName);
153 }
154
155 //_____________________________________________________________________________
156 //
157 AUBase::~AUBase()
158 {
159         if (mCurrentPreset.presetName) CFRelease (mCurrentPreset.presetName);
160 #if !CA_NO_AU_UI_FEATURES
161         if (mContextName) CFRelease (mContextName);
162 #endif
163         if (mLogString) delete [] mLogString;
164     if (mNickName) CFRelease(mNickName);
165 }
166
167 //_____________________________________________________________________________
168 //
169 void    AUBase::CreateElements()
170 {
171         if (!mElementsCreated) {
172                 Inputs().Initialize(this, kAudioUnitScope_Input, mInitNumInputEls);
173                 Outputs().Initialize(this, kAudioUnitScope_Output, mInitNumOutputEls);
174 #if !CA_BASIC_AU_FEATURES
175                 Groups().Initialize(this, kAudioUnitScope_Group, mInitNumGroupEls);
176 #endif
177                 CreateExtendedElements();
178                 
179                 mElementsCreated = true;
180         }
181 }
182
183 //_____________________________________________________________________________
184 //
185 void    AUBase::SetMaxFramesPerSlice(UInt32 nFrames)
186 {
187         mMaxFramesPerSlice = nFrames;
188         if (mBuffersAllocated)
189                 ReallocateBuffers();
190         PropertyChanged(kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0);
191 }
192
193 //_____________________________________________________________________________
194 //
195 OSStatus                        AUBase::CanSetMaxFrames() const
196 {
197         return IsInitialized() ? kAudioUnitErr_Initialized : OSStatus(noErr);
198 }
199
200 //_____________________________________________________________________________
201 //
202 void                            AUBase::ReallocateBuffers()
203 {
204         CreateElements();
205         
206         UInt32 nOutputs = Outputs().GetNumberOfElements();
207         for (UInt32 i = 0; i < nOutputs; ++i) {
208                 AUOutputElement *output = GetOutput(i);
209                 output->AllocateBuffer();       // does no work if already allocated
210         }
211         UInt32 nInputs = Inputs().GetNumberOfElements();
212         for (UInt32 i = 0; i < nInputs; ++i) {
213                 AUInputElement *input = GetInput(i);
214                 input->AllocateBuffer();        // does no work if already allocated
215         }
216         mBuffersAllocated = true;
217 }
218
219 //_____________________________________________________________________________
220 //
221 void                            AUBase::DeallocateIOBuffers()
222 {
223         if (!mBuffersAllocated)
224                 return;
225
226         UInt32 nOutputs = Outputs().GetNumberOfElements();
227         for (UInt32 i = 0; i < nOutputs; ++i) {
228                 AUOutputElement *output = GetOutput(i);
229                 output->DeallocateBuffer();
230         }
231         UInt32 nInputs = Inputs().GetNumberOfElements();
232         for (UInt32 i = 0; i < nInputs; ++i) {
233                 AUInputElement *input = GetInput(i);
234                 input->DeallocateBuffer();
235         }
236         mBuffersAllocated = false;
237 }
238
239 //_____________________________________________________________________________
240 //
241 OSStatus                        AUBase::DoInitialize()
242 {
243         OSStatus result = noErr;
244         
245         if (!mInitialized) {
246                 result = Initialize();
247                 if (result == noErr) {
248                         if (CanScheduleParameters())
249                                 mParamList.reserve(24);
250                         mHasBegunInitializing = true;
251                         ReallocateBuffers();    // calls CreateElements()
252                         mInitialized = true;    // signal that it's okay to render
253                         CAMemoryBarrier();
254                 }
255         }
256
257         return result;
258 }
259
260 //_____________________________________________________________________________
261 //
262 OSStatus                        AUBase::Initialize()
263 {
264         return noErr;
265 }
266
267 //_____________________________________________________________________________
268 //
269 void                            AUBase::PreDestructor()
270 {
271         // this is called from the ComponentBase dispatcher, which doesn't know anything about our (optional) lock
272         CAMutex::Locker lock(mAUMutex);
273         DoCleanup();
274 }
275
276 //_____________________________________________________________________________
277 //
278 void                            AUBase::DoCleanup()
279 {
280         if (mInitialized)
281                 Cleanup();
282         
283         DeallocateIOBuffers();
284         ResetRenderTime ();
285
286         mInitialized = false;
287         mHasBegunInitializing = false;
288 }
289
290 //_____________________________________________________________________________
291 //
292 void                            AUBase::Cleanup()
293 {
294 }
295
296 //_____________________________________________________________________________
297 //
298 OSStatus                        AUBase::Reset(                                  AudioUnitScope                                  inScope,
299                                                                                                         AudioUnitElement                                inElement)
300 {
301         ResetRenderTime ();
302         return noErr;
303 }
304
305 //_____________________________________________________________________________
306 //
307 OSStatus                        AUBase::DispatchGetPropertyInfo(AudioUnitPropertyID                             inID,
308                                                                                                         AudioUnitScope                                  inScope,
309                                                                                                         AudioUnitElement                                inElement,
310                                                                                                         UInt32 &                                                outDataSize,
311                                                                                                         Boolean &                                               outWritable)
312 {
313         OSStatus result = noErr;
314         bool validateElement = true;
315         
316         switch (inID) {
317         case kAudioUnitProperty_MakeConnection:
318                 ca_require(inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Global, InvalidScope);
319                 outDataSize = sizeof(AudioUnitConnection);
320                 outWritable = true;
321                 break;
322                 
323                 
324         case kAudioUnitProperty_SetRenderCallback:
325                 ca_require(AudioUnitAPIVersion() > 1, InvalidProperty);
326                 ca_require(inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Global, InvalidScope);
327                 outDataSize = sizeof(AURenderCallbackStruct);
328                 outWritable = true;
329                 break;
330                 
331         case kAudioUnitProperty_StreamFormat:
332                 outDataSize = sizeof(CAStreamBasicDescription);
333                 outWritable = IsStreamFormatWritable(inScope, inElement);
334                 break;
335
336         case kAudioUnitProperty_SampleRate:
337                 outDataSize = sizeof(Float64);
338                 outWritable = IsStreamFormatWritable(inScope, inElement);
339                 break;
340
341         case kAudioUnitProperty_ClassInfo:
342                 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
343                 outDataSize = sizeof(CFPropertyListRef);
344                 outWritable = true;
345                 break;
346
347         case kAudioUnitProperty_FactoryPresets:
348                 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
349                 result = GetPresets(NULL);
350                 if (!result) {
351                         outDataSize = sizeof(CFArrayRef);
352                         outWritable = false;
353                 }
354                 break;
355                 
356         case kAudioUnitProperty_PresentPreset:
357 #if !CA_USE_AUDIO_PLUGIN_ONLY
358 #ifndef __LP64__
359         case kAudioUnitProperty_CurrentPreset:
360 #endif
361 #endif
362                 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
363                 outDataSize = sizeof(AUPreset);
364                 outWritable = true;
365                 break;
366         
367         case kAudioUnitProperty_ElementName:
368                 outDataSize = sizeof (CFStringRef);
369                 outWritable = true;
370                 break;
371         
372         case kAudioUnitProperty_ParameterList:
373                 {
374                         UInt32 nparams = 0;
375                         result = GetParameterList(inScope, NULL, nparams);
376                         
377                         outDataSize = sizeof(AudioUnitParameterID) * nparams;
378                         outWritable = false;
379                         validateElement = false;
380                 }
381                 break;
382                 
383         case kAudioUnitProperty_ParameterInfo:
384                 outDataSize = sizeof(AudioUnitParameterInfo);
385                 outWritable = false;
386                 validateElement = false;
387                 break;
388
389         case kAudioUnitProperty_ParameterHistoryInfo:
390                 outDataSize = sizeof(AudioUnitParameterHistoryInfo);
391                 outWritable = false;
392                 validateElement = false;
393                 break;
394
395         case kAudioUnitProperty_ElementCount:
396                 outDataSize = sizeof(UInt32);
397                 outWritable = BusCountWritable(inScope);
398                 validateElement = false;
399                 break;
400         
401         case kAudioUnitProperty_Latency:
402                 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
403                 outDataSize = sizeof(Float64);
404                 outWritable = false;
405                 break;
406         
407         case kAudioUnitProperty_TailTime:
408                 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
409                 if (SupportsTail()) {
410                         outDataSize = sizeof(Float64);
411                         outWritable = false;
412                 } else
413                         goto InvalidProperty;
414                 break;
415         
416         case kAudioUnitProperty_MaximumFramesPerSlice:
417                 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
418                 outDataSize = sizeof(UInt32);
419                 outWritable = true;
420                 break;
421         
422         case kAudioUnitProperty_LastRenderError:
423                 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
424                 outDataSize = sizeof(OSStatus);
425                 outWritable = false;
426                 break;
427                 
428         case kAudioUnitProperty_SupportedNumChannels:
429         {
430                 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
431                 UInt32 num = SupportedNumChannels (NULL);
432                 if (num) {
433                         outDataSize = sizeof (AUChannelInfo) * num;
434                         result = noErr;
435                 } else
436                         goto InvalidProperty;
437                 outWritable = false;
438                 break;
439         }
440         
441         case kAudioUnitProperty_SupportedChannelLayoutTags:
442         {
443                 UInt32 numLayouts = GetChannelLayoutTags(inScope, inElement, NULL);
444                 if (numLayouts) {
445                         outDataSize = numLayouts * sizeof(AudioChannelLayoutTag);
446                         result = noErr;
447                 } else
448                         goto InvalidProperty;
449                 outWritable = false;
450                 validateElement = false; //already done it
451                 break;
452         }
453         
454         case kAudioUnitProperty_AudioChannelLayout:
455         {
456                 outWritable = false;
457                 outDataSize = GetAudioChannelLayout(inScope, inElement, NULL, outWritable);
458                 if (outDataSize) {
459                         result = noErr;
460                 } else {
461                         if (GetChannelLayoutTags(inScope, inElement, NULL) == 0)
462                                 goto InvalidProperty;
463                         else
464                                 result = kAudioUnitErr_InvalidPropertyValue;
465                 }
466                 validateElement = false; //already done it
467                 break;
468         }
469
470 #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || TARGET_OS_IPHONE
471         case kAudioUnitProperty_ShouldAllocateBuffer:
472                 ca_require((inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Output), InvalidScope);
473                 outWritable = true;
474                 outDataSize = sizeof(UInt32);
475                 break;
476 #endif
477
478 #if !CA_USE_AUDIO_PLUGIN_ONLY
479         case kAudioUnitProperty_FastDispatch:
480                 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
481                 if (!IsCMgrObject()) goto InvalidProperty;
482                 outDataSize = sizeof(void *);
483                 outWritable = false;
484                 validateElement = false;
485                 break;
486
487         case kAudioUnitProperty_GetUIComponentList:
488                 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
489                 outDataSize = GetNumCustomUIComponents();
490                 if (outDataSize == 0)
491                         goto InvalidProperty;
492                 outDataSize *= sizeof (AudioComponentDescription);
493                 
494                 outWritable = false;
495                 break;
496 #endif
497         
498         case kAudioUnitProperty_ParameterValueStrings:
499                 result = GetParameterValueStrings(inScope, inElement, NULL);
500                 if (result == noErr) {
501                         outDataSize = sizeof(CFArrayRef);
502                         outWritable = false;
503                         validateElement = false;
504                 }
505                 break;
506
507 #if !CA_NO_AU_HOST_CALLBACKS
508         case kAudioUnitProperty_HostCallbacks:
509                 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
510                 outDataSize = sizeof(mHostCallbackInfo);
511                 outWritable = true;
512                 break;
513 #endif
514 #if !CA_NO_AU_UI_FEATURES
515         case kAudioUnitProperty_ContextName:
516                 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
517                 outDataSize = sizeof(CFStringRef);
518                 outWritable = true;
519                 break;
520         
521         case kAudioUnitProperty_IconLocation:
522                 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
523                 outWritable = false;
524                 if (!HasIcon())
525                         goto InvalidProperty;
526                 outDataSize = sizeof(CFURLRef);
527                 break;
528
529         case kAudioUnitProperty_ParameterClumpName:
530                 outDataSize = sizeof(AudioUnitParameterNameInfo );
531                 outWritable = false;
532                 break;
533
534 #endif // !CA_NO_AU_UI_FEATURES
535
536         case 'lrst' :  // kAudioUnitProperty_LastRenderedSampleTime
537                 outDataSize = sizeof(Float64);
538                 outWritable = false;
539                 break;
540         
541     case kAudioUnitProperty_NickName:
542         ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
543         outDataSize = sizeof(CFStringRef);
544         outWritable = true;
545         break;
546
547         default:
548                 result = GetPropertyInfo(inID, inScope, inElement, outDataSize, outWritable);
549                 validateElement = false;
550                 break;
551         }
552
553         if (result == noErr && validateElement) {
554                 ca_require(GetElement(inScope, inElement) != NULL, InvalidElement);     
555         }
556         
557         return result;
558 InvalidProperty:
559         return kAudioUnitErr_InvalidProperty;
560 InvalidScope:
561         return kAudioUnitErr_InvalidScope;
562 InvalidElement:
563         return kAudioUnitErr_InvalidElement;
564 }
565
566 //_____________________________________________________________________________
567 //
568 OSStatus                        AUBase::DispatchGetProperty(    AudioUnitPropertyID                     inID,
569                                                                                                         AudioUnitScope                                  inScope,
570                                                                                                         AudioUnitElement                                inElement,
571                                                                                                         void *                                                  outData)
572 {
573         // NOTE: We're currently only called from AUBase::ComponentEntryDispatch, which
574         // calls DispatchGetPropertyInfo first, which performs validation of the scope/element,
575         // and ensures that the outData buffer is non-null and large enough.
576         OSStatus result = noErr;
577
578         switch (inID) {
579         case kAudioUnitProperty_StreamFormat:
580                 *(CAStreamBasicDescription *)outData = GetStreamFormat(inScope, inElement);
581                 break;
582         
583         case kAudioUnitProperty_SampleRate:
584                 *(Float64 *)outData = GetStreamFormat(inScope, inElement).mSampleRate;
585                 break;
586         
587         case kAudioUnitProperty_ParameterList:
588                 {
589                         UInt32 nparams = 0;
590                         result = GetParameterList(inScope, (AudioUnitParameterID *)outData, nparams);
591                 }
592                 break;
593
594         case kAudioUnitProperty_ParameterInfo:
595                 result = GetParameterInfo(inScope, inElement, *(AudioUnitParameterInfo *)outData);
596                 break;
597
598         case kAudioUnitProperty_ParameterHistoryInfo:
599                 {
600                         AudioUnitParameterHistoryInfo* info = (AudioUnitParameterHistoryInfo*)outData;
601                         result = GetParameterHistoryInfo(inScope, inElement, info->updatesPerSecond, info->historyDurationInSeconds);
602                 }
603                 break;
604
605         case kAudioUnitProperty_ClassInfo:
606                 {
607                         *(CFPropertyListRef *)outData = NULL;
608                         result = SaveState((CFPropertyListRef *)outData);
609                 }
610                 break;
611
612         case kAudioUnitProperty_FactoryPresets:
613                 {
614                         *(CFArrayRef *)outData = NULL;
615                         result = GetPresets ((CFArrayRef *)outData);
616                 }
617                 break;
618         
619         case kAudioUnitProperty_PresentPreset:
620 #if !CA_USE_AUDIO_PLUGIN_ONLY
621 #ifndef __LP64__
622         case kAudioUnitProperty_CurrentPreset:
623 #endif
624 #endif
625                 {
626                         *(AUPreset *)outData = mCurrentPreset;
627                                 
628                                 // retain current string (as client owns a reference to it and will release it)
629                         if (inID == kAudioUnitProperty_PresentPreset && mCurrentPreset.presetName) 
630                                 CFRetain (mCurrentPreset.presetName);
631
632                         result = noErr;
633                 }
634                 break;
635         
636         case kAudioUnitProperty_ElementName:
637                 {
638                         AUElement * element = GetElement(inScope, inElement);
639                         if (element->HasName()) {
640                                 *(CFStringRef *)outData = element->GetName();
641                                 CFRetain (element->GetName());
642                                 result = noErr;
643                         } else
644                                 result = kAudioUnitErr_InvalidPropertyValue;
645                 }
646                 break;
647
648         case kAudioUnitProperty_ElementCount:
649                 *(UInt32 *)outData = GetScope(inScope).GetNumberOfElements();
650                 break;
651         
652         case kAudioUnitProperty_Latency:
653                 *(Float64 *)outData = GetLatency();
654                 break;
655
656         case kAudioUnitProperty_TailTime:
657                 if (SupportsTail())
658                         *(Float64 *)outData = GetTailTime();
659                 else
660                         result = kAudioUnitErr_InvalidProperty;
661                 break;
662         
663         case kAudioUnitProperty_MaximumFramesPerSlice:
664                 *(UInt32 *)outData = mMaxFramesPerSlice;
665                 break;
666
667         case kAudioUnitProperty_LastRenderError:
668                 *(OSStatus *)outData = mLastRenderError;
669                 mLastRenderError = 0;
670                 break;
671
672         case kAudioUnitProperty_SupportedNumChannels:
673                 {
674                         const AUChannelInfo* infoPtr = NULL;
675                         UInt32 num = SupportedNumChannels (&infoPtr);
676                         if(num != 0 && infoPtr != NULL)
677                                 memcpy (outData, infoPtr, num * sizeof (AUChannelInfo));
678                 }
679                 break;
680
681         case kAudioUnitProperty_SupportedChannelLayoutTags:
682                 {
683                         AudioChannelLayoutTag* ptr = outData ? static_cast<AudioChannelLayoutTag*>(outData) : NULL;
684                         UInt32 numLayouts = GetChannelLayoutTags (inScope, inElement, ptr);
685                         if (numLayouts == 0)
686                                 result = kAudioUnitErr_InvalidProperty;
687                 }
688                 break;
689                 
690         case kAudioUnitProperty_AudioChannelLayout:
691         {       
692                 AudioChannelLayout* ptr = outData ? static_cast<AudioChannelLayout*>(outData) : NULL;
693                 Boolean writable;
694                 UInt32 dataSize = GetAudioChannelLayout(inScope, inElement, ptr, writable);
695                 if (!dataSize) {
696                         result = kAudioUnitErr_InvalidProperty;
697                 }
698                 break;
699         }
700
701 #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || TARGET_OS_IPHONE
702         case kAudioUnitProperty_ShouldAllocateBuffer:
703         {
704                 AUIOElement * element = GetIOElement(inScope, inElement);
705                 *(UInt32*)outData = element->WillAllocateBuffer();
706                 break;
707         }
708 #endif
709
710         case kAudioUnitProperty_ParameterValueStrings:
711                 result = GetParameterValueStrings(inScope, inElement, (CFArrayRef *)outData);
712                 break;
713                 
714 #if !CA_USE_AUDIO_PLUGIN_ONLY
715         case kAudioUnitProperty_FastDispatch:
716                 if (!IsCMgrObject()) result = kAudioUnitErr_InvalidProperty;
717                 else {
718                         switch (inElement) {
719                         case kAudioUnitGetParameterSelect:
720                                 *(AudioUnitGetParameterProc *)outData = (AudioUnitGetParameterProc)CMgr_AudioUnitBaseGetParameter;
721                                 break;
722                         case kAudioUnitSetParameterSelect:
723                                 *(AudioUnitSetParameterProc *)outData = (AudioUnitSetParameterProc)CMgr_AudioUnitBaseSetParameter;
724                                 break;
725                         case kAudioUnitRenderSelect:
726                                 if (AudioUnitAPIVersion() > 1)
727                                         *(AudioUnitRenderProc *)outData = (AudioUnitRenderProc)CMgr_AudioUnitBaseRender;
728                                 else result = kAudioUnitErr_InvalidElement;
729                                 break;
730                         default:
731                                 result = GetProperty(inID, inScope, inElement, outData);
732                                 break;
733                         }
734                 }
735                 break;
736
737         case kAudioUnitProperty_GetUIComponentList:
738                 GetUIComponentDescs ((ComponentDescription*)outData);
739                 break;
740 #endif
741
742 #if !CA_NO_AU_HOST_CALLBACKS
743         case kAudioUnitProperty_HostCallbacks:
744                 memcpy(outData, &mHostCallbackInfo, sizeof(mHostCallbackInfo));
745                 break;
746 #endif
747 #if !CA_NO_AU_UI_FEATURES
748         case kAudioUnitProperty_IconLocation:
749                 {
750                         CFURLRef iconLocation = CopyIconLocation();
751                         if (iconLocation) {
752                                 *(CFURLRef*)outData = iconLocation;
753                         } else
754                                 result = kAudioUnitErr_InvalidProperty;
755                 }
756                 break;
757
758         case kAudioUnitProperty_ContextName:
759                 *(CFStringRef *)outData = mContextName;
760                 if (mContextName) {
761                         CFRetain(mContextName);
762                         // retain CFString (if exists) since client will be responsible for its release
763                         result = noErr;
764                 } else {
765                         result = kAudioUnitErr_InvalidPropertyValue;
766                 }
767                 break;
768                 
769         case kAudioUnitProperty_ParameterClumpName:
770                 {
771                         AudioUnitParameterNameInfo * ioClumpInfo = (AudioUnitParameterNameInfo*) outData;
772                         if (ioClumpInfo->inID == kAudioUnitClumpID_System)      // this ID value is reserved
773                                 result = kAudioUnitErr_InvalidPropertyValue;
774                         else 
775                         {
776                                 result = CopyClumpName(inScope, ioClumpInfo->inID, ioClumpInfo->inDesiredLength, &ioClumpInfo->outName);
777                                         
778                                         // this is provided for compatbility with existing implementations that don't know
779                                         // about this new mechanism
780                                 if (result == kAudioUnitErr_InvalidProperty)
781                                         result = GetProperty (inID, inScope, inElement, outData);
782                         }       
783                 }
784                 break;
785
786 #endif  // !CA_NO_AU_UI_FEATURES
787
788         case 'lrst' : // kAudioUnitProperty_LastRenderedSampleTime
789                 *(Float64*)outData = mCurrentRenderTime.mSampleTime;
790                 break;
791
792     case kAudioUnitProperty_NickName:
793         // Ownership follows Core Foundation's 'Copy Rule'
794         if (mNickName) CFRetain(mNickName);
795         *(CFStringRef*)outData = mNickName;
796         break;
797             
798         default:
799                 result = GetProperty(inID, inScope, inElement, outData);
800                 break;
801         }
802         return result;
803 }
804
805
806 //_____________________________________________________________________________
807 //
808 OSStatus                        AUBase::DispatchSetProperty(    AudioUnitPropertyID                     inID,
809                                                                                                         AudioUnitScope                                  inScope,
810                                                                                                         AudioUnitElement                                inElement,
811                                                                                                         const void *                                    inData,
812                                                                                                         UInt32                                                  inDataSize)
813 {
814         OSStatus result = noErr;
815
816         switch (inID) {
817         case kAudioUnitProperty_MakeConnection:
818                 ca_require(inDataSize >= sizeof(AudioUnitConnection), InvalidPropertyValue);
819                 {
820                         AudioUnitConnection &connection = *(AudioUnitConnection *)inData;
821                         result = SetConnection(connection);
822                 }
823                 break;
824
825                 
826         case kAudioUnitProperty_SetRenderCallback:
827                 {
828                         ca_require(inDataSize >= sizeof(AURenderCallbackStruct), InvalidPropertyValue);
829                         ca_require(AudioUnitAPIVersion() > 1, InvalidProperty);
830                         AURenderCallbackStruct &callback = *(AURenderCallbackStruct*)inData;
831                         result = SetInputCallback(kAudioUnitProperty_SetRenderCallback, inElement, callback.inputProc, callback.inputProcRefCon);
832                 }
833                 break;
834
835         case kAudioUnitProperty_ElementCount:
836                 ca_require(inDataSize == sizeof(UInt32), InvalidPropertyValue);
837                 ca_require(BusCountWritable(inScope), NotWritable);
838                 result = SetBusCount(inScope, *(UInt32*)inData);
839                 if (result == noErr) {
840                         PropertyChanged(inID, inScope, inElement);
841                 }
842                 break;
843         
844         case kAudioUnitProperty_MaximumFramesPerSlice:
845                 ca_require(inDataSize == sizeof(UInt32), InvalidPropertyValue);
846                 result = CanSetMaxFrames();
847                 if (result) return result;
848                 SetMaxFramesPerSlice(*(UInt32 *)inData);
849                 break;
850
851         case kAudioUnitProperty_StreamFormat:
852                 {
853                         if (inDataSize < 36) goto InvalidPropertyValue;
854                         ca_require(GetElement(inScope, inElement) != NULL, InvalidElement);
855
856                         CAStreamBasicDescription newDesc;
857                                 // now we're going to be ultra conservative! because of discrepancies between
858                                 // sizes of this struct based on aligment padding inconsistencies
859                         memset (&newDesc, 0, sizeof(newDesc));
860                         memcpy (&newDesc, inData, 36);
861
862                         ca_require(ValidFormat(inScope, inElement, newDesc), InvalidFormat);
863
864                         const CAStreamBasicDescription curDesc = GetStreamFormat(inScope, inElement);
865                         
866                         if ( !curDesc.IsEqual(newDesc, false) ) {
867                                 ca_require(IsStreamFormatWritable(inScope, inElement), NotWritable);
868                                 result = ChangeStreamFormat(inScope, inElement, curDesc, newDesc);
869                         }
870                 }
871                 break;
872         
873         case kAudioUnitProperty_SampleRate:
874                 {
875                         ca_require(inDataSize == sizeof(Float64), InvalidPropertyValue);
876                         ca_require(GetElement(inScope, inElement) != NULL, InvalidElement);
877
878                         const CAStreamBasicDescription curDesc = GetStreamFormat(inScope, inElement);
879                         CAStreamBasicDescription newDesc = curDesc;
880                         newDesc.mSampleRate = *(Float64 *)inData;
881                         
882                         ca_require(ValidFormat(inScope, inElement, newDesc), InvalidFormat);
883                         
884                         if ( !curDesc.IsEqual(newDesc, false) ) {
885                                 ca_require(IsStreamFormatWritable(inScope, inElement), NotWritable);
886                                 result = ChangeStreamFormat(inScope, inElement, curDesc, newDesc);
887                         }
888                 }
889                 break;
890
891         case kAudioUnitProperty_AudioChannelLayout:
892                 {
893                         const AudioChannelLayout *layout = static_cast<const AudioChannelLayout *>(inData);
894                         size_t headerSize = sizeof(AudioChannelLayout) - sizeof(AudioChannelDescription);
895                         
896                         ca_require(inDataSize >= headerSize + layout->mNumberChannelDescriptions * sizeof(AudioChannelDescription), InvalidPropertyValue);
897                         result = SetAudioChannelLayout(inScope, inElement, layout);
898                         if (result == noErr)
899                                 PropertyChanged(inID, inScope, inElement);
900                         break;
901                 }
902         
903         case kAudioUnitProperty_ClassInfo:
904                 ca_require(inDataSize == sizeof(CFPropertyListRef *), InvalidPropertyValue);
905                 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
906                 result = RestoreState(*(CFPropertyListRef *)inData);
907                 break;
908
909         case kAudioUnitProperty_PresentPreset:
910 #if !CA_USE_AUDIO_PLUGIN_ONLY
911 #ifndef __LP64__
912         case kAudioUnitProperty_CurrentPreset:
913 #endif
914 #endif
915                 {
916                         ca_require(inDataSize == sizeof(AUPreset), InvalidPropertyValue);
917                         ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
918                         AUPreset & newPreset = *(AUPreset *)inData;
919                         
920                         if (newPreset.presetNumber >= 0)
921                         {
922                                 result = NewFactoryPresetSet(newPreset);
923                                 // NewFactoryPresetSet SHOULD call SetAFactoryPreset if the preset is valid
924                                 // from its own list of preset number->name
925                                 if (!result)
926                                         PropertyChanged(inID, inScope, inElement);
927                         }
928                         else if (newPreset.presetName)
929                         {
930                                 result = NewCustomPresetSet(newPreset);
931                 if (!result)
932                     PropertyChanged(inID, inScope, inElement);
933                         }
934                         else
935                                 result = kAudioUnitErr_InvalidPropertyValue;
936                 }
937                 break;
938         
939         case kAudioUnitProperty_ElementName:
940                 {
941                         ca_require(GetElement(inScope, inElement) != NULL, InvalidElement);
942                         ca_require(inDataSize == sizeof(CFStringRef), InvalidPropertyValue);
943                         AUElement * element = GetScope(inScope).GetElement (inElement);
944                         element->SetName (*(CFStringRef *)inData);
945                         PropertyChanged(inID, inScope, inElement);
946                 }
947                 break;
948
949 #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || TARGET_OS_IPHONE
950         case kAudioUnitProperty_ShouldAllocateBuffer:
951                 {
952                         ca_require((inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Output), InvalidScope);
953                         ca_require(GetElement(inScope, inElement) != NULL, InvalidElement);
954                         ca_require(inDataSize == sizeof(UInt32), InvalidPropertyValue);
955                         ca_require(!IsInitialized(), Initialized);
956
957                         AUIOElement * element = GetIOElement(inScope, inElement);
958                         element->SetWillAllocateBuffer(*(UInt32 *)inData != 0);
959                 }
960                 break;
961 #endif
962
963 #if !CA_NO_AU_HOST_CALLBACKS
964         case kAudioUnitProperty_HostCallbacks:
965         {
966                 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
967                 UInt32 availSize = std::min(inDataSize, (UInt32)sizeof(HostCallbackInfo));
968                 bool hasChanged = !memcmp (&mHostCallbackInfo, inData, availSize);
969                 memset (&mHostCallbackInfo, 0, sizeof (mHostCallbackInfo));
970                 memcpy (&mHostCallbackInfo, inData, availSize);
971                 if (hasChanged)
972                         PropertyChanged(inID, inScope, inElement);
973                 break;
974         }
975 #endif
976 #if !CA_NO_AU_UI_FEATURES
977         case kAudioUnitProperty_SetExternalBuffer:
978                 ca_require(inDataSize >= sizeof(AudioUnitExternalBuffer), InvalidPropertyValue);
979                 ca_require(IsInitialized(), Uninitialized);
980                 {
981                         AudioUnitExternalBuffer &buf = *(AudioUnitExternalBuffer*)inData;
982                         if (intptr_t(buf.buffer) & 0x0F) result = kAudio_ParamError;
983                         else if (inScope == kAudioUnitScope_Input) {
984                                 AUInputElement *input = GetInput(inElement);
985                                 input->UseExternalBuffer(buf);
986                         } else {
987                                 AUOutputElement *output = GetOutput(inElement);
988                                 output->UseExternalBuffer(buf);
989                         }
990                 }
991                 break;
992
993         case kAudioUnitProperty_ContextName:
994                 {
995                         ca_require(inDataSize == sizeof(CFStringRef), InvalidPropertyValue);
996                         ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
997                         CFStringRef inStr = *(CFStringRef *)inData;
998                         if (mContextName) CFRelease(mContextName);
999                         if (inStr) CFRetain(inStr);
1000                         mContextName = inStr;
1001                         PropertyChanged(inID, inScope, inElement);
1002                 }
1003                 break;
1004
1005 #endif // !CA_NO_AU_UI_FEATURES
1006         
1007     case kAudioUnitProperty_NickName:
1008     {
1009                 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
1010         ca_require(inDataSize == sizeof(CFStringRef), InvalidPropertyValue);
1011         CFStringRef inStr = *(CFStringRef *)inData;
1012         if (mNickName) CFRelease(mNickName);
1013         if (inStr) CFRetain(inStr);
1014         mNickName = inStr;
1015         PropertyChanged(inID, inScope, inElement);
1016         break;
1017     }
1018             
1019         default:
1020                 result = SetProperty(inID, inScope, inElement, inData, inDataSize);
1021                 if (result == noErr)
1022                         PropertyChanged(inID, inScope, inElement);
1023                 
1024                 break;
1025         }
1026         return result;
1027 NotWritable:
1028         return kAudioUnitErr_PropertyNotWritable;
1029 InvalidFormat:
1030         return kAudioUnitErr_FormatNotSupported;
1031 #if !CA_NO_AU_UI_FEATURES
1032 Uninitialized:
1033         return kAudioUnitErr_Uninitialized;
1034 #endif
1035 #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || CA_USE_AUDIO_PLUGIN_ONLY
1036 Initialized:
1037         return kAudioUnitErr_Initialized;
1038 #endif
1039 InvalidScope:
1040         return kAudioUnitErr_InvalidScope;
1041 InvalidProperty:
1042         return kAudioUnitErr_InvalidProperty;
1043 InvalidPropertyValue:
1044         return kAudioUnitErr_InvalidPropertyValue;
1045 InvalidElement:
1046         return kAudioUnitErr_InvalidElement;
1047 }
1048
1049 //_____________________________________________________________________________
1050 //
1051 OSStatus                        AUBase::DispatchRemovePropertyValue (AudioUnitPropertyID                inID,
1052                                                                                                         AudioUnitScope                                  inScope,
1053                                                                                                         AudioUnitElement                                inElement)
1054 {
1055         OSStatus result = noErr;
1056         switch (inID)
1057         {
1058         case kAudioUnitProperty_AudioChannelLayout:
1059         {
1060                 result = RemoveAudioChannelLayout(inScope, inElement);
1061                 if (result == noErr)
1062                         PropertyChanged(inID, inScope, inElement);
1063                 break;
1064         }
1065         
1066 #if !CA_NO_AU_HOST_CALLBACKS
1067         case kAudioUnitProperty_HostCallbacks:
1068         {
1069                 ca_require(inScope == kAudioUnitScope_Global, InvalidScope);
1070                 bool hasValue = false;
1071                 void* ptr = &mHostCallbackInfo;
1072                 for (unsigned int i = 0; i <  sizeof (HostCallbackInfo); ++i) {
1073                         if (static_cast<char*>(ptr)[i]) {
1074                                 hasValue = true;
1075                                 break;
1076                         }
1077                 }
1078                 if (hasValue) {
1079                         memset (&mHostCallbackInfo, 0, sizeof (HostCallbackInfo));
1080                         PropertyChanged(inID, inScope, inElement);
1081                 }
1082                 break;
1083         }
1084 #endif
1085 #if !CA_NO_AU_UI_FEATURES
1086         case kAudioUnitProperty_ContextName:
1087                 if (mContextName) CFRelease(mContextName);
1088                 mContextName = NULL;
1089                 result = noErr;
1090                 break;
1091         
1092 #endif // !CA_NO_AU_UI_FEATURES
1093
1094     case kAudioUnitProperty_NickName:
1095     {
1096         if(inScope == kAudioUnitScope_Global) {
1097             if (mNickName) CFRelease(mNickName);
1098             mNickName = NULL;
1099             PropertyChanged(inID, inScope, inElement);
1100         } else {
1101             result = kAudioUnitErr_InvalidScope;
1102         }
1103         break;
1104     }
1105
1106         default:
1107                 result = RemovePropertyValue (inID, inScope, inElement);                
1108                 break;
1109         }
1110                 
1111         return result;
1112 #if !CA_NO_AU_UI_FEATURES || !CA_NO_AU_HOST_CALLBACKS
1113 InvalidScope:
1114         return kAudioUnitErr_InvalidScope;
1115 #endif
1116 }
1117
1118 //_____________________________________________________________________________
1119 //
1120 OSStatus                        AUBase::GetPropertyInfo(                AudioUnitPropertyID                             inID,
1121                                                                                                         AudioUnitScope                                  inScope,
1122                                                                                                         AudioUnitElement                                inElement,
1123                                                                                                         UInt32 &                                                outDataSize,
1124                                                                                                         Boolean &                                               outWritable)
1125 {
1126         return kAudioUnitErr_InvalidProperty;
1127 }
1128
1129
1130 //_____________________________________________________________________________
1131 //
1132 OSStatus                        AUBase::GetProperty(                    AudioUnitPropertyID                     inID,
1133                                                                                                         AudioUnitScope                                  inScope,
1134                                                                                                         AudioUnitElement                                inElement,
1135                                                                                                         void *                                                  outData)
1136 {
1137         return kAudioUnitErr_InvalidProperty;
1138 }
1139
1140
1141 //_____________________________________________________________________________
1142 //
1143 OSStatus                        AUBase::SetProperty(                    AudioUnitPropertyID                     inID,
1144                                                                                                         AudioUnitScope                                  inScope,
1145                                                                                                         AudioUnitElement                                inElement,
1146                                                                                                         const void *                                    inData,
1147                                                                                                         UInt32                                                  inDataSize)
1148 {
1149         return kAudioUnitErr_InvalidProperty;
1150 }
1151
1152 //_____________________________________________________________________________
1153 //
1154 OSStatus                        AUBase::RemovePropertyValue (   AudioUnitPropertyID                             inID,
1155                                                                                                         AudioUnitScope                                  inScope,
1156                                                                                                         AudioUnitElement                                inElement)
1157 {
1158         return kAudioUnitErr_InvalidPropertyValue;
1159 }
1160                                                                                                 
1161 //_____________________________________________________________________________
1162 //
1163 OSStatus                        AUBase::AddPropertyListener(    AudioUnitPropertyID                             inID,
1164                                                                                                         AudioUnitPropertyListenerProc   inProc,
1165                                                                                                         void *                                                  inProcRefCon)
1166 {
1167         PropertyListener pl;
1168         
1169         pl.propertyID = inID;
1170         pl.listenerProc = inProc;
1171         pl.listenerRefCon = inProcRefCon;
1172         
1173         if (mPropertyListeners.empty())
1174                 mPropertyListeners.reserve(32);
1175         mPropertyListeners.push_back(pl);
1176
1177         return noErr;
1178 }
1179
1180 //_____________________________________________________________________________
1181 //
1182 OSStatus                        AUBase::RemovePropertyListener(         AudioUnitPropertyID                             inID,
1183                                                                                                                 AudioUnitPropertyListenerProc   inProc,
1184                                                                                                                 void *                                                  inProcRefCon,
1185                                                                                                                 bool                                                    refConSpecified)
1186 {
1187         // iterate in reverse so that it's safe to erase in the middle of the vector
1188         for (int i = (int)mPropertyListeners.size(); --i >=0; ) {
1189                 PropertyListeners::iterator it = mPropertyListeners.begin() + i;
1190                 if ((*it).propertyID == inID && (*it).listenerProc == inProc && (!refConSpecified || (*it).listenerRefCon == inProcRefCon))
1191                         mPropertyListeners.erase(it);
1192         }
1193         return noErr;
1194 }
1195
1196 //_____________________________________________________________________________
1197 //
1198 void                            AUBase::PropertyChanged(                        AudioUnitPropertyID                             inID,
1199                                                                                                                 AudioUnitScope                                  inScope, 
1200                                                                                                                 AudioUnitElement                                inElement)
1201 {
1202         for (PropertyListeners::iterator it = mPropertyListeners.begin(); it != mPropertyListeners.end(); ++it)
1203                 if ((*it).propertyID == inID)
1204                         ((*it).listenerProc)((*it).listenerRefCon, mComponentInstance, inID, inScope, inElement);
1205 }
1206
1207 //_____________________________________________________________________________
1208 //
1209 OSStatus                        AUBase::SetRenderNotification(  AURenderCallback                                inProc,
1210                                                                                                         void *                                                  inRefCon)
1211 {
1212         if (inProc == NULL)
1213                 return kAudio_ParamError;
1214
1215         mRenderCallbacksTouched = true;
1216         mRenderCallbacks.deferred_add(RenderCallback(inProc, inRefCon));
1217                         // this will do nothing if it's already in the list
1218         return noErr;
1219 }
1220
1221 //_____________________________________________________________________________
1222 //
1223 OSStatus                        AUBase::RemoveRenderNotification(       AURenderCallback                        inProc,
1224                                                                                                                 void *                                          inRefCon)
1225 {
1226         mRenderCallbacks.deferred_remove(RenderCallback(inProc, inRefCon));
1227         return noErr;   // error?
1228 }
1229
1230 //_____________________________________________________________________________
1231 //
1232 OSStatus        AUBase::GetParameter(                   AudioUnitParameterID                    inID,
1233                                                                                                         AudioUnitScope                                  inScope,
1234                                                                                                         AudioUnitElement                                inElement,
1235                                                                                                         AudioUnitParameterValue &               outValue)
1236 {
1237         AUElement *elem = SafeGetElement(inScope, inElement);
1238         outValue = elem->GetParameter(inID);
1239         return noErr;
1240 }
1241
1242                                                                                         
1243 //_____________________________________________________________________________
1244 //
1245 OSStatus        AUBase::SetParameter(                   AudioUnitParameterID                    inID,
1246                                                                                                         AudioUnitScope                                  inScope,
1247                                                                                                         AudioUnitElement                                inElement,
1248                                                                                                         AudioUnitParameterValue                 inValue,
1249                                                                                                         UInt32                                                  inBufferOffsetInFrames)
1250 {
1251         AUElement *elem = SafeGetElement(inScope, inElement);
1252         elem->SetParameter(inID, inValue);
1253         return noErr;
1254 }
1255
1256 //_____________________________________________________________________________
1257 //
1258 OSStatus        AUBase::ScheduleParameter (     const AudioUnitParameterEvent           *inParameterEvent,
1259                                                                                                         UInt32                                                  inNumEvents)
1260 {
1261         bool canScheduleParameters = CanScheduleParameters();
1262                 
1263         for (UInt32 i = 0; i < inNumEvents; ++i) 
1264         {
1265                 if (inParameterEvent[i].eventType == kParameterEvent_Immediate)
1266                 {
1267                         SetParameter (inParameterEvent[i].parameter,
1268                                                         inParameterEvent[i].scope, 
1269                                                         inParameterEvent[i].element,
1270                                                         inParameterEvent[i].eventValues.immediate.value, 
1271                                                         inParameterEvent[i].eventValues.immediate.bufferOffset);
1272                 }
1273                 if (canScheduleParameters) {
1274                         mParamList.push_back (inParameterEvent[i]);
1275                 }
1276         }
1277         
1278         return noErr;
1279 }
1280
1281 // ____________________________________________________________________________
1282 //
1283 static bool SortParameterEventList(const AudioUnitParameterEvent &ev1, const AudioUnitParameterEvent &ev2 )
1284 {
1285         int offset1 = ev1.eventType == kParameterEvent_Immediate ?  ev1.eventValues.immediate.bufferOffset : ev1.eventValues.ramp.startBufferOffset;
1286         int offset2 = ev2.eventType == kParameterEvent_Immediate ?  ev2.eventValues.immediate.bufferOffset : ev2.eventValues.ramp.startBufferOffset;
1287
1288         if(offset1 < offset2) return true;
1289         return false;
1290 }
1291
1292
1293 // ____________________________________________________________________________
1294 //
1295 OSStatus        AUBase::ProcessForScheduledParams(      ParameterEventList              &inParamList,
1296                                                                                                                 UInt32                                  inFramesToProcess,
1297                                                                                                                 void                                    *inUserData )
1298 {
1299         OSStatus result = noErr;
1300         
1301         int totalFramesToProcess = inFramesToProcess;
1302         
1303         int framesRemaining = totalFramesToProcess;
1304
1305         unsigned int currentStartFrame = 0;     // start of the whole buffer
1306
1307
1308
1309         // sort the ParameterEventList by startBufferOffset
1310         std::sort(inParamList.begin(), inParamList.end(), SortParameterEventList);
1311
1312         ParameterEventList::iterator iter = inParamList.begin();
1313         
1314         
1315         while(framesRemaining > 0 )
1316         {
1317                 // first of all, go through the ramped automation events and find out where the next
1318                 // division of our whole buffer will be
1319                 
1320                 int currentEndFrame = totalFramesToProcess;     // start out assuming we'll process all the way to
1321                                                                                                         // the end of the buffer
1322                 
1323                 iter = inParamList.begin();
1324                 
1325                 // find the next break point
1326                 while(iter != inParamList.end() )
1327                 {
1328                         AudioUnitParameterEvent &event = *iter;
1329                         
1330                         int offset = event.eventType == kParameterEvent_Immediate ?  event.eventValues.immediate.bufferOffset : event.eventValues.ramp.startBufferOffset;
1331
1332                         if(offset > (int)currentStartFrame && offset < currentEndFrame )
1333                         {
1334                                 currentEndFrame = offset;
1335                                 break;
1336                         }
1337
1338                         // consider ramp end to be a possible choice (there may be gaps in the supplied ramp events)
1339                         if(event.eventType == kParameterEvent_Ramped )
1340                         {
1341                                 offset = event.eventValues.ramp.startBufferOffset + event.eventValues.ramp.durationInFrames;
1342         
1343                                 if(offset > (int)currentStartFrame && offset < currentEndFrame )
1344                                 {
1345                                         currentEndFrame = offset;
1346                                 }
1347                         }
1348
1349                         iter++;
1350                 }
1351         
1352                 int framesThisTime = currentEndFrame - currentStartFrame;
1353
1354                 // next, setup the parameter maps to be current for the ramp parameters active during 
1355                 // this time segment...
1356                 
1357                 for(ParameterEventList::iterator iter2 = inParamList.begin(); iter2 != inParamList.end(); iter2++ )
1358                 {
1359                         AudioUnitParameterEvent &event = *iter2;
1360                         
1361                         bool eventFallsInSlice;
1362                         
1363                         
1364                         if(event.eventType == kParameterEvent_Ramped)
1365                                 eventFallsInSlice = event.eventValues.ramp.startBufferOffset < currentEndFrame 
1366                                         && event.eventValues.ramp.startBufferOffset + event.eventValues.ramp.durationInFrames > currentStartFrame;
1367                         else /* kParameterEvent_Immediate */
1368                                 // actually, for the same parameter, there may be future immediate events which override this one,
1369                                 // but it's OK since the event list is sorted in time order, we're guaranteed to end up with the current one
1370                                 eventFallsInSlice = event.eventValues.immediate.bufferOffset <= currentStartFrame;
1371                                 
1372                         if(eventFallsInSlice)
1373                         {
1374                                 AUElement *element = GetElement(event.scope, event.element );
1375                                 
1376                                 if(element) element->SetScheduledEvent( event.parameter,
1377                                                                                                                 event,
1378                                                                                                                 currentStartFrame,
1379                                                                                                                 currentEndFrame - currentStartFrame );
1380                         }
1381                 }
1382
1383
1384
1385                 // Finally, actually do the processing for this slice.....
1386                 
1387                 result = ProcessScheduledSlice( inUserData,
1388                                                                                 currentStartFrame,
1389                                                                                 framesThisTime,
1390                                                                                 inFramesToProcess );
1391                                                                 
1392                 if(result != noErr) break;
1393                 
1394                 framesRemaining -= framesThisTime;
1395                 currentStartFrame = currentEndFrame;    // now start from where we left off last time
1396         }
1397         
1398         return result;
1399 }
1400
1401 //_____________________________________________________________________________
1402 //
1403 void                            AUBase::SetWantsRenderThreadID (bool inFlag)
1404 {
1405         if (inFlag == mWantsRenderThreadID)     
1406                 return;
1407         
1408         mWantsRenderThreadID = inFlag;
1409         if (!mWantsRenderThreadID)
1410                 mRenderThreadID = NULL;
1411 }
1412
1413 //_____________________________________________________________________________
1414 //
1415
1416 //_____________________________________________________________________________
1417 //
1418 OSStatus                        AUBase::DoRender(               AudioUnitRenderActionFlags &    ioActionFlags,
1419                                                                                         const AudioTimeStamp &                  inTimeStamp,
1420                                                                                         UInt32                                                  inBusNumber,
1421                                                                                         UInt32                                                  inFramesToProcess,
1422                                                                                         AudioBufferList &                               ioData)
1423 {
1424         OSStatus theError;
1425         RenderCallbackList::iterator rcit;
1426         
1427         AUTRACE(kCATrace_AUBaseRenderStart, mComponentInstance, (uintptr_t)this, inBusNumber, inFramesToProcess, (uintptr_t)ioData.mBuffers[0].mData);
1428         DISABLE_DENORMALS
1429         
1430         try {
1431                 ca_require(IsInitialized(), Uninitialized);
1432                 ca_require(mAudioUnitAPIVersion >= 2, ParamErr);
1433                 if (inFramesToProcess > mMaxFramesPerSlice) {
1434                         static time_t lastTimeMessagePrinted = 0;
1435                         time_t now = time(NULL);
1436                         if (now != lastTimeMessagePrinted) {
1437                                 lastTimeMessagePrinted = now;
1438                                 syslog(LOG_ERR, "kAudioUnitErr_TooManyFramesToProcess : inFramesToProcess=%u, mMaxFramesPerSlice=%u", (unsigned)inFramesToProcess, (unsigned)mMaxFramesPerSlice);
1439                                 DebugMessageN4("%s:%d inFramesToProcess=%u, mMaxFramesPerSlice=%u; TooManyFrames", __FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)mMaxFramesPerSlice);
1440                         }
1441                         goto TooManyFrames;
1442                 }
1443                 ca_require (!UsesFixedBlockSize() || inFramesToProcess == GetMaxFramesPerSlice(), ParamErr);
1444
1445                 AUOutputElement *output = GetOutput(inBusNumber);       // will throw if non-existant
1446                 if (output->GetStreamFormat().NumberChannelStreams() != ioData.mNumberBuffers) {
1447                         DebugMessageN4("%s:%d ioData.mNumberBuffers=%u, output->GetStreamFormat().NumberChannelStreams()=%u; kAudio_ParamError",
1448                                 __FILE__, __LINE__, (unsigned)ioData.mNumberBuffers, (unsigned)output->GetStreamFormat().NumberChannelStreams());
1449                         goto ParamErr;
1450                 }
1451
1452                 unsigned expectedBufferByteSize = inFramesToProcess * output->GetStreamFormat().mBytesPerFrame;
1453                 for (unsigned ibuf = 0; ibuf < ioData.mNumberBuffers; ++ibuf) {
1454                         AudioBuffer &buf = ioData.mBuffers[ibuf];
1455                         if (buf.mData != NULL) {
1456                                 // only care about the size if the buffer is non-null
1457                                 if (buf.mDataByteSize < expectedBufferByteSize) {
1458                                         // if the buffer is too small, we cannot render safely. kAudio_ParamError.
1459                                         DebugMessageN7("%s:%d %u frames, %u bytes/frame, expected %u-byte buffer; ioData.mBuffers[%u].mDataByteSize=%u; kAudio_ParamError",
1460                                                 __FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)output->GetStreamFormat().mBytesPerFrame, expectedBufferByteSize, ibuf, (unsigned)buf.mDataByteSize);
1461                                         goto ParamErr;
1462                                 }
1463                                 // Some clients incorrectly pass bigger buffers than expectedBufferByteSize.
1464                                 // We will generally set the buffer size at the end of rendering, before we return.
1465                                 // However we should ensure that no one, DURING rendering, READS a
1466                                 // potentially incorrect size. This can lead to doing too much work, or
1467                                 // reading past the end of an input buffer into unmapped memory.
1468                                 buf.mDataByteSize = expectedBufferByteSize;
1469                         }
1470                 }
1471                 
1472                 if (WantsRenderThreadID())
1473                 {
1474                         #if TARGET_OS_MAC
1475                                 mRenderThreadID = pthread_self();
1476                         #elif TARGET_OS_WIN32
1477                                 mRenderThreadID = GetCurrentThreadId();
1478                         #endif
1479                 }
1480                 
1481                 AudioUnitRenderActionFlags flags;
1482                 if (mRenderCallbacksTouched) {
1483                         mRenderCallbacks.update();
1484                         flags = ioActionFlags | kAudioUnitRenderAction_PreRender;
1485                         for (rcit = mRenderCallbacks.begin(); rcit != mRenderCallbacks.end(); ++rcit) {
1486                                 RenderCallback &rc = *rcit;
1487                                 AUTRACE(kCATrace_AUBaseRenderCallbackStart, mComponentInstance, (intptr_t)this, (intptr_t)rc.mRenderNotify, 1, 0);
1488                                 (*(AURenderCallback)rc.mRenderNotify)(rc.mRenderNotifyRefCon, 
1489                                                                 &flags,
1490                                                                 &inTimeStamp, inBusNumber, inFramesToProcess, &ioData);
1491                                 AUTRACE(kCATrace_AUBaseRenderCallbackEnd, mComponentInstance, (intptr_t)this, (intptr_t)rc.mRenderNotify, 1, 0);
1492                         }
1493                 }
1494                 
1495                 theError = DoRenderBus(ioActionFlags, inTimeStamp, inBusNumber, output, inFramesToProcess, ioData);
1496                 
1497                 if (mRenderCallbacksTouched) {
1498                         flags = ioActionFlags | kAudioUnitRenderAction_PostRender;
1499                         
1500                         if (SetRenderError (theError)) {
1501                                 flags |= kAudioUnitRenderAction_PostRenderError;                
1502                         }
1503                         
1504                         for (rcit = mRenderCallbacks.begin(); rcit != mRenderCallbacks.end(); ++rcit) {
1505                                 RenderCallback &rc = *rcit;
1506                                 AUTRACE(kCATrace_AUBaseRenderCallbackStart, mComponentInstance, (intptr_t)this, (intptr_t)rc.mRenderNotify, 2, 0);
1507                                 (*(AURenderCallback)rc.mRenderNotify)(rc.mRenderNotifyRefCon, 
1508                                                                 &flags,
1509                                                                 &inTimeStamp, inBusNumber, inFramesToProcess, &ioData);
1510                                 AUTRACE(kCATrace_AUBaseRenderCallbackEnd, mComponentInstance, (intptr_t)this, (intptr_t)rc.mRenderNotify, 2, 0);
1511                         }
1512                 }
1513
1514                 // The vector's being emptied
1515                 // because these events should only apply to this Render cycle, so anything
1516                 // left over is from a preceding cycle and should be dumped.  New scheduled
1517                 // parameters must be scheduled from the next pre-render callback.
1518                 if (!mParamList.empty())
1519                         mParamList.clear();
1520
1521         }
1522         catch (OSStatus err) {
1523                 theError = err;
1524                 goto errexit;
1525         }
1526         catch (...) {
1527                 theError = -1;
1528                 goto errexit;
1529         }
1530 done:   
1531         RESTORE_DENORMALS
1532         AUTRACE(kCATrace_AUBaseRenderEnd, mComponentInstance, (intptr_t)this, theError, ioActionFlags, CATrace::ablData(ioData));
1533         
1534         return theError;
1535         
1536 Uninitialized:  theError = kAudioUnitErr_Uninitialized;                         goto errexit;
1537 ParamErr:               theError = kAudio_ParamError;                                           goto errexit;
1538 TooManyFrames:  theError = kAudioUnitErr_TooManyFramesToProcess;        goto errexit;
1539 errexit:
1540         DebugMessageN2 ("  from %s, render err: %d", GetLoggingString(), (int)theError);
1541         SetRenderError(theError);
1542         goto done;
1543 }
1544
1545 //_____________________________________________________________________________
1546 //
1547 OSStatus        AUBase::DoProcess (     AudioUnitRenderActionFlags  &           ioActionFlags,
1548                                                                 const AudioTimeStamp &                          inTimeStamp,
1549                                                                 UInt32                                                          inFramesToProcess,
1550                                                                 AudioBufferList &                                       ioData)
1551 {
1552         OSStatus theError;
1553         AUTRACE(kCATrace_AUBaseRenderStart, mComponentInstance, (intptr_t)this, -1, inFramesToProcess, 0);
1554         DISABLE_DENORMALS
1555
1556         try {           
1557         
1558                 if (!(ioActionFlags & (1 << 9)/*kAudioUnitRenderAction_DoNotCheckRenderArgs*/)) {
1559                         ca_require(IsInitialized(), Uninitialized);
1560                         ca_require(inFramesToProcess <= mMaxFramesPerSlice, TooManyFrames);
1561                         ca_require(!UsesFixedBlockSize() || inFramesToProcess == GetMaxFramesPerSlice(), ParamErr);
1562
1563                         AUInputElement *input = GetInput(0);    // will throw if non-existant
1564                         if (input->GetStreamFormat().NumberChannelStreams() != ioData.mNumberBuffers) {
1565                                 DebugMessageN4("%s:%d ioData.mNumberBuffers=%u, input->GetStreamFormat().NumberChannelStreams()=%u; kAudio_ParamError",
1566                                         __FILE__, __LINE__, (unsigned)ioData.mNumberBuffers, (unsigned)input->GetStreamFormat().NumberChannelStreams());
1567                                 goto ParamErr;
1568                         }
1569
1570                         unsigned expectedBufferByteSize = inFramesToProcess * input->GetStreamFormat().mBytesPerFrame;
1571                         for (unsigned ibuf = 0; ibuf < ioData.mNumberBuffers; ++ibuf) {
1572                                 AudioBuffer &buf = ioData.mBuffers[ibuf];
1573                                 if (buf.mData != NULL) {
1574                                         // only care about the size if the buffer is non-null
1575                                         if (buf.mDataByteSize < expectedBufferByteSize) {
1576                                                 // if the buffer is too small, we cannot render safely. kAudio_ParamError.
1577                                                 DebugMessageN7("%s:%d %u frames, %u bytes/frame, expected %u-byte buffer; ioData.mBuffers[%u].mDataByteSize=%u; kAudio_ParamError",
1578                                                         __FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)input->GetStreamFormat().mBytesPerFrame, expectedBufferByteSize, ibuf, (unsigned)buf.mDataByteSize);
1579                                                 goto ParamErr;
1580                                         }
1581                                         // Some clients incorrectly pass bigger buffers than expectedBufferByteSize.
1582                                         // We will generally set the buffer size at the end of rendering, before we return.
1583                                         // However we should ensure that no one, DURING rendering, READS a
1584                                         // potentially incorrect size. This can lead to doing too much work, or
1585                                         // reading past the end of an input buffer into unmapped memory.
1586                                         buf.mDataByteSize = expectedBufferByteSize;
1587                                 }
1588                         }
1589                 }
1590                 
1591                 if (WantsRenderThreadID())
1592                 {
1593                         #if TARGET_OS_MAC
1594                                 mRenderThreadID = pthread_self();
1595                         #elif TARGET_OS_WIN32
1596                                 mRenderThreadID = GetCurrentThreadId();
1597                         #endif
1598                 }
1599                 
1600                 if (NeedsToRender (inTimeStamp)) {
1601                         theError = ProcessBufferLists (ioActionFlags, ioData, ioData, inFramesToProcess);
1602                 } else
1603                         theError = noErr;
1604                         
1605         }
1606         catch (OSStatus err) {
1607                 theError = err;
1608                 goto errexit;
1609         }
1610         catch (...) {
1611                 theError = -1;
1612                 goto errexit;
1613         }
1614 done:   
1615         RESTORE_DENORMALS
1616         AUTRACE(kCATrace_AUBaseRenderEnd, mComponentInstance, (intptr_t)this, theError, ioActionFlags, CATrace::ablData(ioData));
1617         
1618         return theError;
1619         
1620 Uninitialized:  theError = kAudioUnitErr_Uninitialized;                         goto errexit;
1621 ParamErr:               theError = kAudio_ParamError;                                           goto errexit;
1622 TooManyFrames:  theError = kAudioUnitErr_TooManyFramesToProcess;        goto errexit;
1623 errexit:
1624         DebugMessageN2 ("  from %s, process err: %d", GetLoggingString(), (int)theError);
1625         SetRenderError(theError);
1626         goto done;
1627 }
1628
1629 OSStatus        AUBase::DoProcessMultiple (     AudioUnitRenderActionFlags  & ioActionFlags,
1630                                                            const AudioTimeStamp &                               inTimeStamp,
1631                                                            UInt32                                                               inFramesToProcess,
1632                                                            UInt32                                                               inNumberInputBufferLists,
1633                                                            const AudioBufferList **                             inInputBufferLists,
1634                                                            UInt32                                                               inNumberOutputBufferLists,
1635                                                            AudioBufferList **                                   ioOutputBufferLists)
1636 {
1637         OSStatus theError;
1638         DISABLE_DENORMALS
1639         
1640         try {
1641                 
1642                 if (!(ioActionFlags & (1 << 9)/*kAudioUnitRenderAction_DoNotCheckRenderArgs*/)) {
1643                         ca_require(IsInitialized(), Uninitialized);
1644                         ca_require(inFramesToProcess <= mMaxFramesPerSlice, TooManyFrames);
1645                         ca_require (!UsesFixedBlockSize() || inFramesToProcess == GetMaxFramesPerSlice(), ParamErr);
1646                         
1647                         for (unsigned ibl = 0; ibl < inNumberInputBufferLists; ++ibl) {
1648                                 if (inInputBufferLists[ibl] != NULL) {
1649                                         AUInputElement *input = GetInput(ibl);  // will throw if non-existant
1650                                         unsigned expectedBufferByteSize = inFramesToProcess * input->GetStreamFormat().mBytesPerFrame;
1651                                         
1652                                         if (input->GetStreamFormat().NumberChannelStreams() != inInputBufferLists[ibl]->mNumberBuffers) {
1653                                                 DebugMessageN5("%s:%d inInputBufferLists[%u]->mNumberBuffers=%u, input->GetStreamFormat().NumberChannelStreams()=%u; kAudio_ParamError",
1654                                                                            __FILE__, __LINE__, ibl, (unsigned)inInputBufferLists[ibl]->mNumberBuffers, (unsigned)input->GetStreamFormat().NumberChannelStreams());
1655                                                 goto ParamErr;
1656                                         }
1657                                         
1658                                         for (unsigned ibuf = 0; ibuf < inInputBufferLists[ibl]->mNumberBuffers; ++ibuf) {
1659                                                 const AudioBuffer &buf = inInputBufferLists[ibl]->mBuffers[ibuf];
1660                                                 if (buf.mData != NULL) {
1661                                                         if (buf.mDataByteSize < expectedBufferByteSize) {
1662                                                                 // the buffer is too small
1663                                                                 DebugMessageN8("%s:%d %u frames, %u bytes/frame, expected %u-byte buffer; inInputBufferLists[%u].mBuffers[%u].mDataByteSize=%u; kAudio_ParamError",
1664                                                                                            __FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)input->GetStreamFormat().mBytesPerFrame, expectedBufferByteSize, ibl, ibuf, (unsigned)buf.mDataByteSize);
1665                                                                 goto ParamErr;
1666                                                         }
1667                                                 } else {
1668                                                         // the buffer must exist
1669                                                         goto ParamErr;
1670                                                 }
1671                                         }
1672                                 } else {
1673                                         // skip NULL input audio buffer list
1674                                 }
1675                         }
1676                         
1677                         for (unsigned obl = 0; obl < inNumberOutputBufferLists; ++obl) {
1678                                 if (ioOutputBufferLists[obl] != NULL) {
1679                                         AUOutputElement *output = GetOutput(obl);       // will throw if non-existant
1680                                         unsigned expectedBufferByteSize = inFramesToProcess * output->GetStreamFormat().mBytesPerFrame;
1681
1682                                         if (output->GetStreamFormat().NumberChannelStreams() != ioOutputBufferLists[obl]->mNumberBuffers) {
1683                                                 DebugMessageN5("%s:%d ioOutputBufferLists[%u]->mNumberBuffers=%u, output->GetStreamFormat().NumberChannelStreams()=%u; kAudio_ParamError",
1684                                                                            __FILE__, __LINE__, obl, (unsigned)ioOutputBufferLists[obl]->mNumberBuffers, (unsigned)output->GetStreamFormat().NumberChannelStreams());
1685                                                 goto ParamErr;
1686                                         }
1687                                         
1688                                         for (unsigned obuf = 0; obuf < ioOutputBufferLists[obl]->mNumberBuffers; ++obuf) {
1689                                                 AudioBuffer &buf = ioOutputBufferLists[obl]->mBuffers[obuf];
1690                                                 if (buf.mData != NULL) {
1691                                                         // only care about the size if the buffer is non-null
1692                                                         if (buf.mDataByteSize < expectedBufferByteSize) {
1693                                                                 // if the buffer is too small, we cannot render safely. kAudio_ParamError.
1694                                                                 DebugMessageN8("%s:%d %u frames, %u bytes/frame, expected %u-byte buffer; ioOutputBufferLists[%u]->mBuffers[%u].mDataByteSize=%u; kAudio_ParamError",
1695                                                                                            __FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)output->GetStreamFormat().mBytesPerFrame, expectedBufferByteSize, obl, obuf, (unsigned)buf.mDataByteSize);
1696                                                                 goto ParamErr;
1697                                                         }
1698                                                         // Some clients incorrectly pass bigger buffers than expectedBufferByteSize.
1699                                                         // We will generally set the buffer size at the end of rendering, before we return.
1700                                                         // However we should ensure that no one, DURING rendering, READS a
1701                                                         // potentially incorrect size. This can lead to doing too much work, or
1702                                                         // reading past the end of an input buffer into unmapped memory.
1703                                                         buf.mDataByteSize = expectedBufferByteSize;
1704                                                 }
1705                                         }
1706                                 } else {
1707                                         // skip NULL output audio buffer list
1708                                 }
1709                         }
1710                 }
1711                 
1712                 if (WantsRenderThreadID())
1713                 {
1714 #if TARGET_OS_MAC
1715                         mRenderThreadID = pthread_self();
1716 #elif TARGET_OS_WIN32
1717                         mRenderThreadID = GetCurrentThreadId();
1718 #endif
1719                 }
1720                 
1721                 if (NeedsToRender (inTimeStamp)) {
1722                         theError = ProcessMultipleBufferLists (ioActionFlags, inFramesToProcess, inNumberInputBufferLists, inInputBufferLists, inNumberOutputBufferLists, ioOutputBufferLists);
1723                 } else
1724                         theError = noErr;
1725         }
1726         catch (OSStatus err) {
1727                 theError = err;
1728                 goto errexit;
1729         }
1730         catch (...) {
1731                 theError = -1;
1732                 goto errexit;
1733         }
1734 done:   
1735         RESTORE_DENORMALS
1736         
1737         return theError;
1738         
1739 Uninitialized:  theError = kAudioUnitErr_Uninitialized;                         goto errexit;
1740 ParamErr:               theError = kAudio_ParamError;                                           goto errexit;
1741 TooManyFrames:  theError = kAudioUnitErr_TooManyFramesToProcess;        goto errexit;
1742 errexit:
1743         DebugMessageN2 ("  from %s, processmultiple err: %d", GetLoggingString(), (int)theError);
1744         SetRenderError(theError);
1745         goto done;
1746 }
1747
1748 //_____________________________________________________________________________
1749 //
1750 OSStatus                        AUBase::SetInputCallback(               UInt32                                                  inPropertyID,
1751                                                                                                         AudioUnitElement                                inElement, 
1752                                                                                                         AURenderCallback                                inProc,
1753                                                                                                         void *                                                  inRefCon)
1754 {
1755         AUInputElement *input = GetInput(inElement);    // may throw
1756         
1757         input->SetInputCallback(inProc, inRefCon);
1758         PropertyChanged(inPropertyID, kAudioUnitScope_Input, inElement);
1759         
1760         return noErr;
1761 }
1762
1763 //_____________________________________________________________________________
1764 //
1765 OSStatus                        AUBase::SetConnection(                  const AudioUnitConnection &             inConnection)
1766 {
1767
1768         OSStatus err;
1769         AUInputElement *input = GetInput(inConnection.destInputNumber); // may throw
1770                 
1771         if (inConnection.sourceAudioUnit) {
1772                 // connecting, not disconnecting
1773                 CAStreamBasicDescription sourceDesc;
1774                 UInt32 size = sizeof(CAStreamBasicDescription);
1775                 ca_require_noerr(err = AudioUnitGetProperty(
1776                                                                                 inConnection.sourceAudioUnit,
1777                                                                                 kAudioUnitProperty_StreamFormat,
1778                                                                                 kAudioUnitScope_Output,
1779                                                                                 inConnection.sourceOutputNumber,
1780                                                                                 &sourceDesc,
1781                                                                                 &size), errexit);
1782                 ca_require_noerr(err = DispatchSetProperty (kAudioUnitProperty_StreamFormat, 
1783                                                                 kAudioUnitScope_Input, inConnection.destInputNumber, 
1784                                                                 &sourceDesc, sizeof(CAStreamBasicDescription)), errexit);
1785         }
1786         input->SetConnection(inConnection);
1787                 
1788         PropertyChanged(kAudioUnitProperty_MakeConnection, kAudioUnitScope_Input, inConnection.destInputNumber);
1789         return noErr;
1790
1791 errexit:
1792         return err;
1793 }
1794  
1795 //_____________________________________________________________________________
1796 //
1797 UInt32                          AUBase::SupportedNumChannels (  const AUChannelInfo**                   outInfo)
1798 {
1799         return 0;
1800 }
1801
1802 //_____________________________________________________________________________
1803 //
1804 bool                            AUBase::ValidFormat(                    AudioUnitScope                                  inScope,
1805                                                                                                         AudioUnitElement                                inElement,
1806                                                                                                         const CAStreamBasicDescription &                inNewFormat)
1807 {
1808         return FormatIsCanonical(inNewFormat);
1809 }
1810
1811 //_____________________________________________________________________________
1812 //
1813 bool                            AUBase::IsStreamFormatWritable( AudioUnitScope                                  scope,
1814                                                                                                         AudioUnitElement                                element)
1815 {
1816         switch (scope) {
1817         case kAudioUnitScope_Input:
1818                 {
1819                         AUInputElement *input = GetInput(element);
1820                         if (input->HasConnection()) return false;       // can't write format when input comes from connection
1821                 }
1822                 // ... fall ...
1823         case kAudioUnitScope_Output:
1824                 return StreamFormatWritable(scope, element);
1825
1826 //#warning "aliasing of global scope format should be pushed to subclasses"
1827         case kAudioUnitScope_Global:
1828                 return StreamFormatWritable(kAudioUnitScope_Output, 0);
1829         }
1830         return false;
1831 }
1832
1833 //_____________________________________________________________________________
1834 //
1835 const CAStreamBasicDescription &
1836                                         AUBase::GetStreamFormat(                AudioUnitScope                                  inScope,
1837                                                                                                         AudioUnitElement                                inElement)
1838 {
1839 //#warning "aliasing of global scope format should be pushed to subclasses"
1840         AUIOElement *element;
1841         
1842         switch (inScope) {
1843         case kAudioUnitScope_Input:
1844                 element = Inputs().GetIOElement(inElement);
1845                 break;
1846         case kAudioUnitScope_Output:
1847                 element = Outputs().GetIOElement(inElement);
1848                 break;
1849         case kAudioUnitScope_Global:    // global stream description is an alias for that of output 0
1850                 element = Outputs().GetIOElement(0);
1851                 break;
1852         default:
1853                 COMPONENT_THROW(kAudioUnitErr_InvalidScope);
1854         }
1855         return element->GetStreamFormat();
1856 }
1857
1858 OSStatus                        AUBase::SetBusCount(    AudioUnitScope                                  inScope,
1859                                                                                         UInt32                                                  inCount)
1860 {
1861         if (IsInitialized()) 
1862                 return kAudioUnitErr_Initialized;
1863                 
1864         GetScope(inScope).SetNumberOfElements(inCount);
1865         return noErr;
1866 }
1867
1868 //_____________________________________________________________________________
1869 //
1870 OSStatus                        AUBase::ChangeStreamFormat(             AudioUnitScope                                  inScope,
1871                                                                                                         AudioUnitElement                                inElement,
1872                                                                                                         const CAStreamBasicDescription & inPrevFormat,
1873                                                                                                         const CAStreamBasicDescription &        inNewFormat)
1874 {
1875 //#warning "aliasing of global scope format should be pushed to subclasses"
1876         AUIOElement *element;
1877         
1878         switch (inScope) {
1879         case kAudioUnitScope_Input:
1880                 element = Inputs().GetIOElement(inElement);
1881                 break;
1882         case kAudioUnitScope_Output:
1883                 element = Outputs().GetIOElement(inElement);
1884                 break;
1885         case kAudioUnitScope_Global:
1886                 element = Outputs().GetIOElement(0);
1887                 break;
1888         default:
1889                 COMPONENT_THROW(kAudioUnitErr_InvalidScope);
1890         }
1891         element->SetStreamFormat(inNewFormat);
1892         PropertyChanged(kAudioUnitProperty_StreamFormat, inScope, inElement);
1893         return noErr;
1894 }
1895
1896 UInt32          AUBase::GetChannelLayoutTags(   AudioUnitScope                          inScope,
1897                                                                                         AudioUnitElement                        inElement,
1898                                                                                         AudioChannelLayoutTag *         outLayoutTags)
1899 {
1900         return GetIOElement(inScope, inElement)->GetChannelLayoutTags(outLayoutTags);
1901 }
1902
1903 UInt32          AUBase::GetAudioChannelLayout(  AudioUnitScope                          scope,
1904                                                                                         AudioUnitElement                        element,
1905                                                                                         AudioChannelLayout *            outLayoutPtr,
1906                                                                                         Boolean &                                       outWritable)
1907 {
1908         AUIOElement * el = GetIOElement(scope, element);
1909         return el->GetAudioChannelLayout(outLayoutPtr, outWritable);
1910 }
1911
1912 OSStatus        AUBase::RemoveAudioChannelLayout(                       AudioUnitScope                          inScope,
1913                                                                                                                 AudioUnitElement                        inElement)
1914 {
1915         OSStatus result = noErr;
1916         AUIOElement * el = GetIOElement(inScope, inElement);
1917         Boolean writable;
1918         if (el->GetAudioChannelLayout(NULL, writable)) {
1919                 result = el->RemoveAudioChannelLayout();
1920         }
1921         return result;
1922 }
1923
1924 OSStatus        AUBase::SetAudioChannelLayout(                          AudioUnitScope                          inScope, 
1925                                                                                                                 AudioUnitElement                        inElement,
1926                                                                                                                 const AudioChannelLayout *      inLayout)
1927 {
1928         AUIOElement* ioEl = GetIOElement (inScope, inElement);
1929
1930         // the num channels of the layout HAS TO MATCH the current channels of the Element's stream format
1931         UInt32 currentChannels = ioEl->GetStreamFormat().NumberChannels();
1932         UInt32 numChannelsInLayout = CAAudioChannelLayout::NumberChannels(*inLayout);
1933         if (currentChannels != numChannelsInLayout)
1934                 return kAudioUnitErr_InvalidPropertyValue;
1935
1936         UInt32 numLayouts = GetChannelLayoutTags (inScope, inElement, NULL);
1937         if (numLayouts == 0)
1938                 return kAudioUnitErr_InvalidProperty;
1939         AudioChannelLayoutTag *tags = (AudioChannelLayoutTag *)CA_malloc (numLayouts * sizeof (AudioChannelLayoutTag));
1940         GetChannelLayoutTags (inScope, inElement, tags);
1941         bool foundTag = false;
1942         for (unsigned int i = 0; i < numLayouts; ++i) {
1943                 if (tags[i] == inLayout->mChannelLayoutTag || tags[i] == kAudioChannelLayoutTag_UseChannelDescriptions) {
1944                         foundTag = true;
1945                         break;
1946                 }
1947         }
1948         free(tags);
1949         
1950         if (foundTag == false)
1951                 return kAudioUnitErr_InvalidPropertyValue;
1952
1953         return ioEl->SetAudioChannelLayout(*inLayout);
1954 }
1955
1956 static void AddNumToDictionary (CFMutableDictionaryRef dict, CFStringRef key, SInt32 value)
1957 {
1958         CFNumberRef num = CFNumberCreate (NULL, kCFNumberSInt32Type, &value);
1959         CFDictionarySetValue (dict, key, num);
1960         CFRelease (num);
1961 }
1962
1963 #define kCurrentSavedStateVersion 0
1964
1965 OSStatus                        AUBase::SaveState(              CFPropertyListRef * outData)
1966 {
1967         AudioComponentDescription desc = GetComponentDescription();
1968
1969         CFMutableDictionaryRef dict = CFDictionaryCreateMutable (NULL, 0, 
1970                                                                 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1971
1972 // first step -> save the version to the data ref
1973         SInt32 value = kCurrentSavedStateVersion;
1974         AddNumToDictionary (dict, kVersionString, value);
1975
1976 // second step -> save the component type, subtype, manu to the data ref
1977         value = desc.componentType;
1978         AddNumToDictionary (dict, kTypeString, value);
1979
1980         value = desc.componentSubType;
1981         AddNumToDictionary (dict, kSubtypeString, value);
1982         
1983         value = desc.componentManufacturer;
1984         AddNumToDictionary (dict, kManufacturerString, value);
1985         
1986 // fourth step -> save the state of all parameters on all scopes and elements
1987         CFMutableDataRef data = CFDataCreateMutable(NULL, 0);
1988         for (AudioUnitScope iscope = 0; iscope < 3; ++iscope) {
1989                 AUScope &scope = GetScope(iscope);
1990                 scope.SaveState (data);
1991         }
1992     
1993     SaveExtendedScopes(data);
1994
1995 // save all this in the data section of the dictionary
1996         CFDictionarySetValue(dict, kDataString, data);
1997         CFRelease (data);
1998         
1999 //OK - now we're going to do some properties    
2000 //save the preset name...
2001         CFDictionarySetValue (dict, kNameString, mCurrentPreset.presetName);
2002
2003 // Does the unit support the RenderQuality property - if so, save it...
2004         value = 0;
2005         OSStatus result = DispatchGetProperty (kAudioUnitProperty_RenderQuality,
2006                                                                 kAudioUnitScope_Global,
2007                                                                 0,
2008                                                                 &value);
2009         
2010         if (result == noErr) {
2011                 AddNumToDictionary (dict, kRenderQualityString, value);
2012         }
2013         
2014 // Does the unit support the CPULoad Quality property - if so, save it...
2015         Float32 cpuLoad;
2016         result = DispatchGetProperty (6/*kAudioUnitProperty_CPULoad*/,
2017                                                                 kAudioUnitScope_Global,
2018                                                                 0,
2019                                                                 &cpuLoad);
2020         
2021         if (result == noErr) {
2022                 CFNumberRef num = CFNumberCreate (NULL, kCFNumberFloatType, &cpuLoad);
2023                 CFDictionarySetValue (dict, kCPULoadString, num);
2024                 CFRelease (num);
2025         }
2026
2027 // Do we have any element names for any of our scopes?  
2028         // first check to see if we have any names...
2029         bool foundName = false;
2030         for (AudioUnitScope i = 0; i < kNumScopes; ++i) {
2031                 foundName = GetScope (i).HasElementWithName();
2032                 if (foundName) 
2033                         break;
2034         }
2035                 // OK - we found a name away we go...
2036         if (foundName) {
2037                 CFMutableDictionaryRef nameDict = CFDictionaryCreateMutable     (NULL, 0, 
2038                                                                 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2039                 for (AudioUnitScope i = 0; i < kNumScopes; ++i) {
2040                         GetScope (i).AddElementNamesToDict (nameDict);
2041                 }
2042                 
2043                 CFDictionarySetValue (dict, kElementNameString, nameDict);
2044                 CFRelease (nameDict);
2045         }
2046         
2047 // we're done!!!
2048         *outData = dict;
2049
2050         return noErr;
2051 }
2052
2053 //_____________________________________________________________________________
2054 //
2055 OSStatus                        AUBase::RestoreState(   CFPropertyListRef       plist)
2056 {
2057         if (CFGetTypeID(plist) != CFDictionaryGetTypeID()) return kAudioUnitErr_InvalidPropertyValue;
2058         
2059         AudioComponentDescription desc = GetComponentDescription();
2060         
2061         CFDictionaryRef dict = static_cast<CFDictionaryRef>(plist);
2062
2063 // zeroeth step - make sure the Part key is NOT present, as this method is used
2064 // to restore the GLOBAL state of the dictionary        
2065         if (CFDictionaryContainsKey (dict, kPartString))
2066                 return kAudioUnitErr_InvalidPropertyValue;
2067                 
2068 // first step -> check the saved version in the data ref
2069 // at this point we're only dealing with version==0
2070         CFNumberRef cfnum = reinterpret_cast<CFNumberRef>(CFDictionaryGetValue (dict, kVersionString));
2071         if (cfnum == NULL) return kAudioUnitErr_InvalidPropertyValue;
2072         SInt32 value;
2073         CFNumberGetValue (cfnum, kCFNumberSInt32Type, &value);
2074         if (value != kCurrentSavedStateVersion) return kAudioUnitErr_InvalidPropertyValue;
2075
2076 // second step -> check that this data belongs to this kind of audio unit
2077 // by checking the component subtype and manuID
2078 // We're not checking the type, since there may be different versions (effect, format-converter, offline)
2079 // of essentially the same AU
2080         cfnum = reinterpret_cast<CFNumberRef>(CFDictionaryGetValue (dict, kSubtypeString));
2081         if (cfnum == NULL) return kAudioUnitErr_InvalidPropertyValue;
2082         CFNumberGetValue (cfnum, kCFNumberSInt32Type, &value);
2083         if (UInt32(value) != desc.componentSubType) return kAudioUnitErr_InvalidPropertyValue;
2084
2085         cfnum = reinterpret_cast<CFNumberRef>(CFDictionaryGetValue (dict, kManufacturerString));
2086         if (cfnum == NULL) return kAudioUnitErr_InvalidPropertyValue;
2087         CFNumberGetValue (cfnum, kCFNumberSInt32Type, &value);
2088         if (UInt32(value) != desc.componentManufacturer) return kAudioUnitErr_InvalidPropertyValue;
2089
2090 // fourth step -> restore the state of all of the parameters for each scope and element 
2091         CFDataRef data = reinterpret_cast<CFDataRef>(CFDictionaryGetValue (dict, kDataString));
2092         if (data != NULL) 
2093         {
2094                 const UInt8 *p, *pend;
2095                 
2096                 p = CFDataGetBytePtr(data);
2097                 pend = p + CFDataGetLength(data);
2098                 
2099                 // we have a zero length data, which may just mean there were no parameters to save!
2100                 //      if (p >= pend) return noErr; 
2101         
2102                 while (p < pend) {
2103             UInt32 scopeIdx = CFSwapInt32BigToHost(*(UInt32 *)p);
2104             p += sizeof(UInt32);
2105             
2106                         AUScope &scope = GetScope(scopeIdx);
2107             p = scope.RestoreState(p);
2108         }
2109         }
2110
2111 //OK - now we're going to do some properties
2112 //restore the preset name...
2113         CFStringRef name = reinterpret_cast<CFStringRef>(CFDictionaryGetValue (dict, kNameString));
2114         if (mCurrentPreset.presetName) CFRelease (mCurrentPreset.presetName);
2115         if (name)
2116         {
2117                 mCurrentPreset.presetName = name;
2118                 mCurrentPreset.presetNumber = -1;
2119         } 
2120         else { // no name entry make the default one
2121                 mCurrentPreset.presetName = kUntitledString;
2122                 mCurrentPreset.presetNumber = -1;
2123         }
2124         
2125         CFRetain (mCurrentPreset.presetName);
2126 #if !CA_USE_AUDIO_PLUGIN_ONLY
2127 #ifndef __LP64__
2128         PropertyChanged(kAudioUnitProperty_CurrentPreset, kAudioUnitScope_Global, 0);
2129 #endif
2130 #endif
2131         PropertyChanged(kAudioUnitProperty_PresentPreset, kAudioUnitScope_Global, 0);
2132
2133 // Does the dict contain render quality information?            
2134         if (CFDictionaryGetValueIfPresent (dict, kRenderQualityString, reinterpret_cast<const void**>(&cfnum))) 
2135         {
2136                 CFNumberGetValue (cfnum, kCFNumberSInt32Type, &value);
2137                 DispatchSetProperty (kAudioUnitProperty_RenderQuality,
2138                                                                 kAudioUnitScope_Global,
2139                                                                 0,
2140                                                                 &value,
2141                                                                 sizeof(value));
2142         }
2143         
2144 // Does the unit support the CPULoad Quality property - if so, save it...
2145         if (CFDictionaryGetValueIfPresent (dict, kCPULoadString, reinterpret_cast<const void**>(&cfnum))) 
2146         {
2147                 Float32 floatValue;
2148                 CFNumberGetValue (cfnum, kCFNumberFloatType, &floatValue);
2149                 DispatchSetProperty (6/*kAudioUnitProperty_CPULoad*/,
2150                                                                 kAudioUnitScope_Global,
2151                                                                 0,
2152                                                                 &floatValue,
2153                                                                 sizeof(floatValue));
2154         }
2155
2156 // Do we have any element names for any of our scopes?
2157         CFDictionaryRef nameDict;
2158         if (CFDictionaryGetValueIfPresent (dict, kElementNameString, reinterpret_cast<const void**>(&nameDict))) 
2159         {
2160                 char string[64];
2161                 for (int i = 0; i < kNumScopes; ++i) 
2162                 {
2163                         snprintf (string, sizeof(string), "%d", i);
2164                         CFStringRef key = CFStringCreateWithCString (NULL, string, kCFStringEncodingASCII);
2165                         CFDictionaryRef elementDict;
2166                         if (CFDictionaryGetValueIfPresent (nameDict, key, reinterpret_cast<const void**>(&elementDict))) 
2167                         {
2168                                 bool didAddElements = GetScope (i).RestoreElementNames (elementDict);
2169                                 if (didAddElements)
2170                                         PropertyChanged (kAudioUnitProperty_ElementCount, i, 0);
2171                         }
2172                         CFRelease (key);                                
2173                 }
2174         }
2175         
2176         return noErr;
2177 }
2178
2179 OSStatus                        AUBase::GetPresets (                    CFArrayRef *                                    outData) const
2180 {
2181         return kAudioUnitErr_InvalidProperty;
2182 }
2183
2184 OSStatus                        AUBase::NewFactoryPresetSet (const AUPreset & inNewFactoryPreset)
2185 {
2186         return kAudioUnitErr_InvalidProperty;
2187 }
2188
2189 OSStatus            AUBase::NewCustomPresetSet (const AUPreset & inNewCustomPreset)
2190 {
2191     CFRelease (mCurrentPreset.presetName);
2192     mCurrentPreset = inNewCustomPreset;
2193     CFRetain (mCurrentPreset.presetName);
2194     return noErr;
2195 }
2196
2197                 // set the default preset for the unit -> the number of the preset MUST be >= 0
2198                 // and the name should be valid, or the preset WON'T take
2199 bool                            AUBase::SetAFactoryPresetAsCurrent (const AUPreset & inPreset)
2200 {
2201         if (inPreset.presetNumber < 0 || inPreset.presetName == NULL) return false;
2202         CFRelease (mCurrentPreset.presetName);
2203         mCurrentPreset = inPreset;
2204         CFRetain (mCurrentPreset.presetName);
2205         return true;
2206 }
2207
2208 #if !CA_USE_AUDIO_PLUGIN_ONLY
2209 int                     AUBase::GetNumCustomUIComponents () 
2210 {
2211         return 0;
2212 }
2213
2214 void            AUBase::GetUIComponentDescs (ComponentDescription* inDescArray) {}
2215 #endif
2216         
2217 bool            AUBase::HasIcon () 
2218 {
2219 #if !CA_NO_AU_UI_FEATURES
2220         CFURLRef url = CopyIconLocation(); 
2221         if (url) {
2222                 CFRelease (url);
2223                 return true;
2224         }
2225 #endif
2226         return false;
2227 }
2228
2229 CFURLRef        AUBase::CopyIconLocation () 
2230 {
2231         return NULL;
2232 }
2233         
2234 //_____________________________________________________________________________
2235 //
2236 OSStatus                        AUBase::GetParameterList(               AudioUnitScope                                  inScope,
2237                                                                                                         AudioUnitParameterID *                  outParameterList,
2238                                                                                                         UInt32 &                                                outNumParameters)
2239 {
2240         AUScope &scope = GetScope(inScope);
2241         AUElement *elementWithMostParameters = NULL;
2242         UInt32 maxNumParams = 0;
2243         
2244         int nElems = scope.GetNumberOfElements();
2245         for (int ielem = 0; ielem < nElems; ++ielem) {
2246                 AUElement *element = scope.GetElement(ielem);
2247                 UInt32 nParams = element->GetNumberOfParameters();
2248                 if (nParams > maxNumParams) {
2249                         maxNumParams = nParams;
2250                         elementWithMostParameters = element;
2251                 }
2252         }
2253         
2254         if (outParameterList != NULL && elementWithMostParameters != NULL)
2255                 elementWithMostParameters->GetParameterList(outParameterList);
2256         
2257         outNumParameters = maxNumParams;
2258         return noErr;
2259 }
2260
2261 //_____________________________________________________________________________
2262 //
2263 OSStatus                        AUBase::GetParameterInfo(               AudioUnitScope                  inScope,
2264                                                                                                         AudioUnitParameterID    inParameterID,
2265                                                                                                         AudioUnitParameterInfo  &outParameterInfo )
2266 {
2267         return kAudioUnitErr_InvalidParameter;
2268 }
2269
2270 //_____________________________________________________________________________
2271 //
2272 OSStatus                        AUBase::GetParameterValueStrings(AudioUnitScope                 inScope,
2273                                                                                                         AudioUnitParameterID    inParameterID,
2274                                                                                                         CFArrayRef *                    outStrings)
2275 {
2276         return kAudioUnitErr_InvalidProperty;
2277 }
2278
2279 //_____________________________________________________________________________
2280 //
2281 OSStatus                        AUBase::GetParameterHistoryInfo(        AudioUnitScope                                  inScope,
2282                                                                                                                 AudioUnitParameterID                    inParameterID,
2283                                                                                                                 Float32 &                                               outUpdatesPerSecond,
2284                                                                                                                 Float32 &                                               outHistoryDurationInSeconds)
2285 {
2286         return kAudioUnitErr_InvalidProperty;
2287 }
2288
2289
2290 //_____________________________________________________________________________
2291 //
2292 OSStatus                        AUBase::CopyClumpName(                  AudioUnitScope                  inScope, 
2293                                                                                                         UInt32                                  inClumpID, 
2294                                                                                                         UInt32                                  inDesiredNameLength,
2295                                                                                                         CFStringRef *                   outClumpName)
2296 {
2297         return kAudioUnitErr_InvalidProperty;
2298 }
2299
2300 //_____________________________________________________________________________
2301 //
2302 void                            AUBase::SetNumberOfElements(    AudioUnitScope                                  inScope,
2303                                                                                                         UInt32                                                  numElements)
2304 {
2305         if (inScope == kAudioUnitScope_Global && numElements != 1)
2306                 COMPONENT_THROW(kAudioUnitErr_InvalidScope);
2307
2308         GetScope(inScope).SetNumberOfElements(numElements);
2309 }
2310
2311 //_____________________________________________________________________________
2312 //
2313 AUElement *                     AUBase::CreateElement(                  AudioUnitScope                                  scope,
2314                                                                                                         AudioUnitElement                                element)
2315 {
2316         switch (scope) {
2317         case kAudioUnitScope_Global:
2318                 return new AUElement(this);
2319         case kAudioUnitScope_Input:
2320                 return new AUInputElement(this);
2321         case kAudioUnitScope_Output:
2322                 return new AUOutputElement(this);
2323 #if !CA_BASIC_AU_FEATURES
2324         case kAudioUnitScope_Group:
2325                 return new AUElement(this);
2326         case kAudioUnitScope_Part:
2327                 return new AUElement(this);
2328 #endif
2329         }
2330         COMPONENT_THROW(kAudioUnitErr_InvalidScope);
2331         
2332         return NULL;    // get rid of compiler warning
2333 }
2334
2335 //_____________________________________________________________________________
2336 //
2337 bool    AUBase::FormatIsCanonical(              const CAStreamBasicDescription &f)
2338 {
2339         return (f.mFormatID == kAudioFormatLinearPCM
2340                 &&      f.mFramesPerPacket == 1
2341                 &&      f.mBytesPerPacket == f.mBytesPerFrame
2342 //              &&      f.mChannelsPerFrame >= 0        -- this is always true since it's unsigned
2343                 // so far, it's a valid PCM format
2344 #if CA_PREFER_FIXED_POINT
2345                 &&      (f.mFormatFlags & kLinearPCMFormatFlagIsFloat) == 0
2346                 &&      (((f.mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift) == kAudioUnitSampleFractionBits)
2347 #else
2348                 &&      (f.mFormatFlags & kLinearPCMFormatFlagIsFloat) != 0
2349 #endif
2350                 &&      ((f.mChannelsPerFrame == 1) || ((f.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0) == (mAudioUnitAPIVersion == 1))
2351 #if TARGET_RT_BIG_ENDIAN
2352                 &&      (f.mFormatFlags & kLinearPCMFormatFlagIsBigEndian) != 0
2353 #else
2354                 &&      (f.mFormatFlags & kLinearPCMFormatFlagIsBigEndian) == 0
2355 #endif
2356                 &&      f.mBitsPerChannel == 8 * sizeof(AudioUnitSampleType)
2357                 &&      f.mBytesPerFrame == f.NumberInterleavedChannels() * sizeof(AudioUnitSampleType)
2358                 );
2359 }
2360
2361 //_____________________________________________________________________________
2362 //
2363 void    AUBase::MakeCanonicalFormat(    CAStreamBasicDescription &              f,
2364                                                                                 int                                                             nChannels)
2365 {
2366         f.SetAUCanonical(nChannels, mAudioUnitAPIVersion < 2);  // interleaved for v1, non for v2
2367         f.mSampleRate = 0.0;
2368 }
2369
2370 const Float64 AUBase::kNoLastRenderedSampleTime = -1.;
2371
2372 #include "AUBaseHelper.h"
2373
2374 char*   AUBase::GetLoggingString () const
2375 {
2376         if (mLogString) return mLogString;
2377         
2378         AudioComponentDescription desc = GetComponentDescription();
2379         
2380         const size_t logStringSize = 256;
2381         const_cast<AUBase*>(this)->mLogString = new char[logStringSize];
2382         char str[24];
2383         char str1[24];
2384         char str2[24];
2385         snprintf (const_cast<AUBase*>(this)->mLogString, logStringSize, "AU (%p): %s %s %s",
2386                 GetComponentInstance(),
2387                 CAStringForOSType(desc.componentType, str, sizeof(str)),
2388                 CAStringForOSType(desc.componentSubType, str1, sizeof(str1)),
2389                 CAStringForOSType(desc.componentManufacturer, str2, sizeof(str2)));
2390
2391         return mLogString;
2392 }
2393