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