1 /*
2 File: CAAudioUnit.cpp
3 Abstract: CAAudioUnit.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 "CAAudioUnit.h"
48
49 #if !TARGET_OS_IPHONE
50 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
51 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/Components.h>
52 #include <dlfcn.h>
53 #else
54 #include <Components.h>
55 #endif
56 #endif
57
58 #include "CAXException.h"
59 #include "CAReferenceCounted.h"
60 #include "AUOutputBL.h" //this is for the Preroll only
61
62 struct StackAUChannelInfo {
StackAUChannelInfoStackAUChannelInfo63 StackAUChannelInfo (UInt32 inSize) : mChanInfo ((AUChannelInfo*)malloc (inSize)) {}
~StackAUChannelInfoStackAUChannelInfo64 ~StackAUChannelInfo() { free (mChanInfo); }
65
66 AUChannelInfo* mChanInfo;
67 };
68
69 // is this symbol is not defined then we use the default setting which is that fast dispatch
70 // is supported on a desktop environment
71 #ifndef CA_AU_USE_FAST_DISPATCH
72 #define CA_AU_USE_FAST_DISPATCH !TARGET_OS_IPHONE
73 #endif
74
75 #if CA_AU_USE_FAST_DISPATCH
76 static void *LoadGetComponentInstanceStorage (void *inst);
77 #endif
78
79
80 class CAAudioUnit::AUState : public CAReferenceCounted {
81 public:
AUState(AudioComponent inComp)82 AUState (AudioComponent inComp)
83 : mUnit(0), mNode (0)
84 {
85 OSStatus result = ::AudioComponentInstanceNew (inComp, &mUnit);
86 if (result)
87 throw result;
88 Init();
89 }
90
AUState(const AUNode & inNode,const AudioUnit & inUnit)91 AUState (const AUNode &inNode, const AudioUnit& inUnit)
92 : mUnit (inUnit), mNode (inNode)
93 {
94 Init();
95 }
96
97 ~AUState();
98
99 AudioUnit mUnit;
100 AUNode mNode;
101
GetParameter(AudioUnitParameterID inID,AudioUnitScope scope,AudioUnitElement element,Float32 & outValue) const102 OSStatus GetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
103 Float32 &outValue) const
104 {
105 #if CA_AU_USE_FAST_DISPATCH
106 if (mGetParamProc != NULL) {
107 return (mGetParamProc) (mConnInstanceStorage, inID, scope, element, &outValue);
108 }
109 #endif
110 return AudioUnitGetParameter(mUnit, inID, scope, element, &outValue);
111 }
112
SetParameter(AudioUnitParameterID inID,AudioUnitScope scope,AudioUnitElement element,Float32 value,UInt32 bufferOffsetFrames)113 OSStatus SetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
114 Float32 value, UInt32 bufferOffsetFrames)
115 {
116 #if CA_AU_USE_FAST_DISPATCH
117 if (mSetParamProc != NULL) {
118 return (mSetParamProc) (mConnInstanceStorage, inID, scope, element, value, bufferOffsetFrames);
119 }
120 #endif
121 return AudioUnitSetParameter(mUnit, inID, scope, element, value, bufferOffsetFrames);
122 }
123
Render(AudioUnitRenderActionFlags * ioActionFlags,const AudioTimeStamp * inTimeStamp,UInt32 inOutputBusNumber,UInt32 inNumberFrames,AudioBufferList * ioData)124 OSStatus Render (AudioUnitRenderActionFlags * ioActionFlags,
125 const AudioTimeStamp * inTimeStamp,
126 UInt32 inOutputBusNumber,
127 UInt32 inNumberFrames,
128 AudioBufferList * ioData)
129 {
130 #if CA_AU_USE_FAST_DISPATCH
131 if (mRenderProc != NULL) {
132 return (mRenderProc) (mConnInstanceStorage, ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData);
133 }
134 #endif
135 return AudioUnitRender(mUnit, ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData);
136 }
137
MIDIEvent(UInt32 inStatus,UInt32 inData1,UInt32 inData2,UInt32 inOffsetSampleFrame)138 OSStatus MIDIEvent (UInt32 inStatus,
139 UInt32 inData1,
140 UInt32 inData2,
141 UInt32 inOffsetSampleFrame)
142 {
143 #if !TARGET_OS_WIN32
144 #if CA_AU_USE_FAST_DISPATCH
145 if (mMIDIEventProc != NULL) {
146 return (mMIDIEventProc) (mConnInstanceStorage, inStatus, inData1, inData2, inOffsetSampleFrame);
147 }
148 #endif
149 return MusicDeviceMIDIEvent (mUnit, inStatus, inData1, inData2, inOffsetSampleFrame);
150 #else // ON WINDOWS _ NO MIDI EVENT dispatch
151 return paramErr;
152 #endif
153 }
154
StartNote(MusicDeviceInstrumentID inInstrument,MusicDeviceGroupID inGroupID,NoteInstanceID * outNoteInstanceID,UInt32 inOffsetSampleFrame,const MusicDeviceNoteParams * inParams)155 OSStatus StartNote (MusicDeviceInstrumentID inInstrument,
156 MusicDeviceGroupID inGroupID,
157 NoteInstanceID * outNoteInstanceID,
158 UInt32 inOffsetSampleFrame,
159 const MusicDeviceNoteParams * inParams)
160 {
161 #if !TARGET_OS_WIN32
162 #if CA_AU_USE_FAST_DISPATCH
163 if (mStartNoteProc != NULL) {
164 return (mStartNoteProc) (mConnInstanceStorage, inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, inParams);
165 }
166 #endif
167 return MusicDeviceStartNote (mUnit, inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, inParams);
168 #else
169 return paramErr;
170 #endif
171 }
StopNote(MusicDeviceGroupID inGroupID,NoteInstanceID inNoteInstanceID,UInt32 inOffsetSampleFrame)172 OSStatus StopNote (MusicDeviceGroupID inGroupID,
173 NoteInstanceID inNoteInstanceID,
174 UInt32 inOffsetSampleFrame)
175 {
176 #if !TARGET_OS_WIN32
177 #if CA_AU_USE_FAST_DISPATCH
178 if (mStopNoteProc != NULL) {
179 return (mStopNoteProc) (mConnInstanceStorage, inGroupID, inNoteInstanceID, inOffsetSampleFrame);
180 }
181 #endif
182 return MusicDeviceStopNote (mUnit, inGroupID, inNoteInstanceID, inOffsetSampleFrame);
183 #else
184 return paramErr;
185 #endif
186 }
187
188 private:
189 // get the fast dispatch pointers
Init()190 void Init()
191 {
192 #if CA_AU_USE_FAST_DISPATCH
193 UInt32 size = sizeof(AudioUnitRenderProc);
194 if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch,
195 kAudioUnitScope_Global, kAudioUnitRenderSelect,
196 &mRenderProc, &size) != noErr)
197 mRenderProc = NULL;
198
199 size = sizeof(AudioUnitGetParameterProc);
200 if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch,
201 kAudioUnitScope_Global, kAudioUnitGetParameterSelect,
202 &mGetParamProc, &size) != noErr)
203 mGetParamProc = NULL;
204
205 size = sizeof(AudioUnitSetParameterProc);
206 if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch,
207 kAudioUnitScope_Global, kAudioUnitSetParameterSelect,
208 &mSetParamProc, &size) != noErr)
209 mSetParamProc = NULL;
210
211 size = sizeof(MusicDeviceMIDIEventProc);
212 if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch,
213 kAudioUnitScope_Global, kMusicDeviceMIDIEventSelect,
214 &mMIDIEventProc, &size) != noErr)
215 mMIDIEventProc = NULL;
216
217 size = sizeof(MusicDeviceStartNoteProc);
218 if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch,
219 kAudioUnitScope_Global, kMusicDeviceStartNoteSelect,
220 &mStartNoteProc, &size) != noErr)
221 mStartNoteProc = NULL;
222
223 size = sizeof(MusicDeviceStopNoteProc);
224 if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch,
225 kAudioUnitScope_Global, kMusicDeviceStopNoteSelect,
226 &mStopNoteProc, &size) != noErr)
227 mStopNoteProc = NULL;
228
229 if (mRenderProc || mGetParamProc || mSetParamProc || mMIDIEventProc || mStartNoteProc || mStopNoteProc) {
230 mConnInstanceStorage = LoadGetComponentInstanceStorage ( mUnit );
231 } else
232 mConnInstanceStorage = NULL;
233 #else
234 mConnInstanceStorage = NULL;
235 #endif
236 }
237
238 #if CA_AU_USE_FAST_DISPATCH
239 AudioUnitRenderProc mRenderProc;
240 AudioUnitGetParameterProc mGetParamProc;
241 AudioUnitSetParameterProc mSetParamProc;
242 MusicDeviceMIDIEventProc mMIDIEventProc;
243 MusicDeviceStartNoteProc mStartNoteProc;
244 MusicDeviceStopNoteProc mStopNoteProc;
245 #endif
246
247 void * mConnInstanceStorage;
248
249 private:
250 // get the compiler to tell us when we do a bad thing!!!
AUState()251 AUState () {}
252 AUState (const AUState&);
253 AUState& operator= (const AUState&);
254 };
255
256
~AUState()257 CAAudioUnit::AUState::~AUState ()
258 {
259 if (mUnit && (mNode == 0)) {
260 ::AudioComponentInstanceDispose (mUnit);
261 }
262 mNode = 0;
263 mUnit = 0;
264 }
265
Open(const CAComponent & inComp,CAAudioUnit & outUnit)266 OSStatus CAAudioUnit::Open (const CAComponent& inComp, CAAudioUnit &outUnit)
267 {
268 try {
269 outUnit = inComp;
270 return noErr;
271 } catch (OSStatus res) {
272 return res;
273 } catch (...) {
274 return -1;
275 }
276 }
277
CAAudioUnit(const AudioUnit & inUnit)278 CAAudioUnit::CAAudioUnit (const AudioUnit& inUnit)
279 : mComp (inUnit), mDataPtr (new AUState (kCAAU_DoNotKnowIfAUNode, inUnit))
280 {
281 }
282
CAAudioUnit(const CAComponent & inComp)283 CAAudioUnit::CAAudioUnit (const CAComponent& inComp)
284 : mComp (inComp), mDataPtr (new AUState (mComp.Comp()))
285 {
286 }
287
CAAudioUnit(const AUNode & inNode,const AudioUnit & inUnit)288 CAAudioUnit::CAAudioUnit (const AUNode &inNode, const AudioUnit& inUnit)
289 : mComp (inUnit), mDataPtr(new AUState (inNode, inUnit))
290 {
291 }
292
~CAAudioUnit()293 CAAudioUnit::~CAAudioUnit ()
294 {
295 Close();
296 }
297
Close()298 void CAAudioUnit::Close()
299 {
300 if (mDataPtr) {
301 mDataPtr->release();
302 mDataPtr = NULL;
303 }
304 }
305
operator =(const CAAudioUnit & a)306 CAAudioUnit& CAAudioUnit::operator= (const CAAudioUnit &a)
307 {
308 if (mDataPtr != a.mDataPtr) {
309 if (mDataPtr)
310 mDataPtr->release();
311
312 if ((mDataPtr = a.mDataPtr) != NULL)
313 mDataPtr->retain();
314
315 mComp = a.mComp;
316 }
317
318 return *this;
319 }
320
operator ==(const CAAudioUnit & y) const321 bool CAAudioUnit::operator== (const CAAudioUnit& y) const
322 {
323 if (mDataPtr == y.mDataPtr) return true;
324 AudioUnit au1 = mDataPtr ? mDataPtr->mUnit : 0;
325 AudioUnit au2 = y.mDataPtr ? y.mDataPtr->mUnit : 0;
326 return au1 == au2;
327 }
328
operator ==(const AudioUnit & y) const329 bool CAAudioUnit::operator== (const AudioUnit& y) const
330 {
331 if (!mDataPtr) return false;
332 return mDataPtr->mUnit == y;
333 }
334
RemovePropertyListener(AudioUnitPropertyID inID,AudioUnitPropertyListenerProc inProc,void * inProcUserData)335 OSStatus CAAudioUnit::RemovePropertyListener (AudioUnitPropertyID inID,
336 AudioUnitPropertyListenerProc inProc,
337 void * inProcUserData)
338 {
339 // we call this first. If it fails we call the old API as the failure can
340 // mean that the AU doesn't implement that selector.
341 OSStatus result = AudioUnitRemovePropertyListenerWithUserData(AU(), inID,
342 inProc, inProcUserData);
343 #if !__LP64__ && !TARGET_OS_IPHONE
344 if (result) result = AudioUnitRemovePropertyListener (AU(), inID, inProc);
345 #endif
346 return result;
347 }
348
349 #pragma mark __State Management
350
IsValid() const351 bool CAAudioUnit::IsValid () const
352 {
353 return mDataPtr ? mDataPtr->mUnit != 0 : false;
354 }
355
AU() const356 AudioUnit CAAudioUnit::AU() const
357 {
358 return mDataPtr ? mDataPtr->mUnit : 0;
359 }
360
GetAUNode() const361 AUNode CAAudioUnit::GetAUNode () const
362 {
363 return mDataPtr ? mDataPtr->mNode : 0;
364 }
365
366 #pragma mark __Format Handling
367
CanDo(int inChannelsIn,int inChannelsOut) const368 bool CAAudioUnit::CanDo ( int inChannelsIn,
369 int inChannelsOut) const
370 {
371 // this is the default assumption of an audio effect unit
372 Boolean* isWritable = 0;
373 UInt32 dataSize = 0;
374 // lets see if the unit has any channel restrictions
375 OSStatus result = AudioUnitGetPropertyInfo (AU(),
376 kAudioUnitProperty_SupportedNumChannels,
377 kAudioUnitScope_Global, 0,
378 &dataSize, isWritable); //don't care if this is writable
379
380 // if this property is NOT implemented an FX unit
381 // is expected to deal with same channel valance in and out
382 if (result)
383 {
384 if ((Comp().Desc().IsEffect() && inChannelsIn == inChannelsOut)
385 || (Comp().Desc().IsOffline() && inChannelsIn == inChannelsOut))
386 {
387 return true;
388 }
389 else
390 {
391 // the au should either really tell us about this
392 // or we will assume the worst
393 return false;
394 }
395 }
396
397 StackAUChannelInfo info (dataSize);
398
399 result = GetProperty (kAudioUnitProperty_SupportedNumChannels,
400 kAudioUnitScope_Global, 0,
401 info.mChanInfo, &dataSize);
402 if (result) { return false; }
403
404 return ValidateChannelPair (inChannelsIn, inChannelsOut, info.mChanInfo, (dataSize / sizeof (AUChannelInfo)));
405 }
406
GetChannelInfo(AUChannelInfo ** chaninfo,UInt32 & cnt)407 int CAAudioUnit::GetChannelInfo (AUChannelInfo** chaninfo, UInt32& cnt)
408 {
409 // this is the default assumption of an audio effect unit
410 Boolean* isWritable = 0;
411 UInt32 dataSize = 0;
412 // lets see if the unit has any channel restrictions
413 OSStatus result = AudioUnitGetPropertyInfo (AU(),
414 kAudioUnitProperty_SupportedNumChannels,
415 kAudioUnitScope_Global, 0,
416 &dataSize, isWritable); //don't care if this is writable
417
418 // if this property is NOT implemented an FX unit
419 // is expected to deal with same channel valance in and out
420
421 if (result)
422 {
423 if (Comp().Desc().IsEffect())
424 {
425 return 1;
426 }
427 else if (Comp().Desc().IsGenerator() || Comp().Desc().IsMusicDevice()) {
428 // directly query Bus Formats
429 // Note that that these may refer to different subBusses
430 // (eg. Kick, Snare,.. on a Drummachine)
431 // eventually the Bus-Name for each configuration should be exposed
432 // for the User to select..
433
434 UInt32 elCountIn, elCountOut;
435
436 if (GetElementCount (kAudioUnitScope_Input, elCountIn)) return -1;
437 if (GetElementCount (kAudioUnitScope_Output, elCountOut)) return -1;
438
439 cnt = std::max(elCountIn, elCountOut);
440
441 *chaninfo = (AUChannelInfo*) malloc (sizeof (AUChannelInfo) * cnt);
442
443 for (unsigned int i = 0; i < elCountIn; ++i) {
444 UInt32 numChans;
445 if (NumberChannels (kAudioUnitScope_Input, i, numChans)) return -1;
446 (*chaninfo)[i].inChannels = numChans;
447 }
448 for (unsigned int i = elCountIn; i < cnt; ++i) {
449 (*chaninfo)[i].inChannels = 0;
450 }
451
452 for (unsigned int i = 0; i < elCountOut; ++i) {
453 UInt32 numChans;
454 if (NumberChannels (kAudioUnitScope_Output, i, numChans)) return -1;
455 (*chaninfo)[i].outChannels = numChans;
456 }
457 for (unsigned int i = elCountOut; i < cnt; ++i) {
458 (*chaninfo)[i].outChannels = 0;
459 }
460 return 0;
461 }
462 else
463 {
464 // the au should either really tell us about this
465 // or we will assume the worst
466 return -1;
467 }
468 }
469
470 *chaninfo = (AUChannelInfo*) malloc (dataSize);
471 cnt = dataSize / sizeof (AUChannelInfo);
472
473 result = GetProperty (kAudioUnitProperty_SupportedNumChannels,
474 kAudioUnitScope_Global, 0,
475 *chaninfo, &dataSize);
476
477 if (result) { return -1; }
478 return 0;
479 }
480
ValidateChannelPair(int inChannelsIn,int inChannelsOut,const AUChannelInfo * info,UInt32 numChanInfo) const481 bool CAAudioUnit::ValidateChannelPair (int inChannelsIn,
482 int inChannelsOut,
483 const AUChannelInfo * info,
484 UInt32 numChanInfo) const
485 {
486 // we've the following cases (some combinations) to test here:
487 /*
488 >0 An explicit number of channels on either side
489 0 that side (generally input!) has no elements
490 -1 wild card:
491 -1,-1 any num channels as long as same channels on in and out
492 -1,-2 any num channels channels on in and out - special meaning
493 -2+ indicates total num channs AU can handle
494 - elements configurable to any num channels,
495 - element count in scope must be writable
496 */
497
498 //now chan layout can contain -1 for either scope (ie. doesn't care)
499 for (unsigned int i = 0; i < numChanInfo; ++i)
500 {
501 //less than zero on both sides - check for special attributes
502 if ((info[i].inChannels < 0) && (info[i].outChannels < 0))
503 {
504 // these are our wild card matches
505 if (info[i].inChannels == -1 && info[i].outChannels == -1) {
506 if (inChannelsIn && inChannelsOut) {
507 if (inChannelsOut == inChannelsIn)
508 return true;
509 } else
510 return true; // if one of these is zero, then a -1 means any
511 }
512 else if ((info[i].inChannels == -1 && info[i].outChannels == -2)
513 || (info[i].inChannels == -2 && info[i].outChannels == -1))
514 {
515 return true;
516 }
517 // these are our total num channels matches
518 // element count MUST be writable
519 else {
520 bool outWrite = false; bool inWrite = false;
521 IsElementCountWritable (kAudioUnitScope_Output, outWrite);
522 IsElementCountWritable (kAudioUnitScope_Input, inWrite);
523 if (inWrite && outWrite) {
524 if ((inChannelsOut <= abs(info[i].outChannels))
525 && (inChannelsIn <= abs(info[i].inChannels)))
526 {
527 return true;
528 }
529 }
530 }
531 }
532
533 // special meaning on input, specific num on output
534 else if (info[i].inChannels < 0) {
535 if (info[i].outChannels == inChannelsOut)
536 {
537 // can do any in channels
538 if (info[i].inChannels == -1) {
539 return true;
540 }
541 // total chans on input
542 else {
543 bool inWrite = false;
544 IsElementCountWritable (kAudioUnitScope_Input, inWrite);
545 if (inWrite && (inChannelsIn <= abs(info[i].inChannels))) {
546 return true;
547 }
548 }
549 }
550 }
551
552 // special meaning on output, specific num on input
553 else if (info[i].outChannels < 0) {
554 if (info[i].inChannels == inChannelsIn)
555 {
556 // can do any out channels
557 if (info[i].outChannels == -1) {
558 return true;
559 }
560 // total chans on output
561 else {
562 bool outWrite = false;
563 IsElementCountWritable (kAudioUnitScope_Output, outWrite);
564 if (outWrite && (inChannelsOut <= abs(info[i].outChannels))) {
565 return true;
566 }
567 }
568 }
569 }
570
571 // both chans in struct >= 0 - thus has to explicitly match
572 else if ((info[i].inChannels == inChannelsIn) && (info[i].outChannels == inChannelsOut)) {
573 return true;
574 }
575
576 // now check to see if a wild card on the args (inChannelsIn or inChannelsOut chans is zero) is found
577 // tells us to match just one side of the scopes
578 else if (inChannelsIn == 0) {
579 if (info[i].outChannels == inChannelsOut) {
580 return true;
581 }
582 }
583 else if (inChannelsOut == 0) {
584 if (info[i].inChannels == inChannelsIn) {
585 return true;
586 }
587 }
588 }
589
590 return false;
591 }
592
593 static
CheckDynCount(SInt32 inTotalChans,const CAAUChanHelper & inHelper)594 bool CheckDynCount (SInt32 inTotalChans, const CAAUChanHelper &inHelper)
595 {
596 int totalChans = 0;
597 for (unsigned int i = 0; i < inHelper.mNumEls; ++i)
598 totalChans += inHelper.mChans[i];
599 return (totalChans <= inTotalChans);
600 }
601
CheckOneSide(const CAAUChanHelper & inHelper,bool checkOutput,const AUChannelInfo * info,UInt32 numInfo) const602 bool CAAudioUnit::CheckOneSide (const CAAUChanHelper &inHelper,
603 bool checkOutput,
604 const AUChannelInfo *info,
605 UInt32 numInfo) const
606 {
607 // now we can use the wildcard option (see above impl) to see if this matches
608 for (unsigned int el = 0; el < inHelper.mNumEls; ++el) {
609 bool testAlready = false;
610 for (unsigned int i = 0; i < el; ++i) {
611 if (inHelper.mChans[i] == inHelper.mChans[el]) {
612 testAlready = true;
613 break;
614 }
615 }
616 if (!testAlready) {
617 if (checkOutput) {
618 if (!ValidateChannelPair (0, inHelper.mChans[el], info, numInfo)) return false;
619 } else {
620 if (!ValidateChannelPair (inHelper.mChans[el], 0, info, numInfo)) return false;
621 }
622 }
623 }
624 return true;
625 }
626
CanDo(const CAAUChanHelper & inputs,const CAAUChanHelper & outputs) const627 bool CAAudioUnit::CanDo (const CAAUChanHelper &inputs,
628 const CAAUChanHelper &outputs) const
629
630 {
631 // first check our state
632 // huh!
633 if (inputs.mNumEls == 0 && outputs.mNumEls == 0) return false;
634
635 UInt32 elCount;
636 if (GetElementCount (kAudioUnitScope_Input, elCount)) { return false; }
637 if (elCount != inputs.mNumEls) return false;
638
639 if (GetElementCount (kAudioUnitScope_Output, elCount)) { return false; }
640 if (elCount != outputs.mNumEls) return false;
641
642 // (1) special cases (effects and sources (generators and instruments) only)
643 UInt32 dataSize = 0;
644 if (GetPropertyInfo (kAudioUnitProperty_SupportedNumChannels,
645 kAudioUnitScope_Global, 0, &dataSize, NULL) != noErr)
646 {
647 if (Comp().Desc().IsEffect() || Comp().Desc().IsOffline()) {
648 UInt32 numChan = outputs.mNumEls > 0 ? outputs.mChans[0] : inputs.mChans[0];
649 for (unsigned int in = 0; in < inputs.mNumEls; ++in)
650 if (numChan != inputs.mChans[in]) return false;
651 for (unsigned int out = 0; out < outputs.mNumEls; ++out)
652 if (numChan != outputs.mChans[out]) return false;
653 return true;
654 }
655
656 // in this case, all the channels have to match the current config
657 if (Comp().Desc().IsGenerator() || Comp().Desc().IsMusicDevice()) {
658 for (unsigned int in = 0; in < inputs.mNumEls; ++in) {
659 UInt32 chan;
660 if (NumberChannels (kAudioUnitScope_Input, in, chan)) return false;
661 if (chan != UInt32(inputs.mChans[in])) return false;
662 }
663 for (unsigned int out = 0; out < outputs.mNumEls; ++out) {
664 UInt32 chan;
665 if (NumberChannels (kAudioUnitScope_Output, out, chan)) return false;
666 if (chan != UInt32(outputs.mChans[out])) return false;
667 }
668 return true;
669 }
670
671 // if we get here we can't determine anything about channel capabilities
672 return false;
673 }
674
675 StackAUChannelInfo info (dataSize);
676
677 if (GetProperty (kAudioUnitProperty_SupportedNumChannels,
678 kAudioUnitScope_Global, 0,
679 info.mChanInfo, &dataSize) != noErr)
680 {
681 return false;
682 }
683
684 int numInfo = dataSize / sizeof(AUChannelInfo);
685
686 // (2) Test for dynamic capability (or no elements on that scope)
687 SInt32 dynInChans = 0;
688 if (ValidateDynamicScope (kAudioUnitScope_Input, dynInChans, info.mChanInfo, numInfo)) {
689 if (CheckDynCount (dynInChans, inputs) == false) return false;
690 }
691
692 SInt32 dynOutChans = 0;
693 if (ValidateDynamicScope (kAudioUnitScope_Output, dynOutChans, info.mChanInfo, numInfo)) {
694 if (CheckDynCount (dynOutChans, outputs) == false) return false;
695 }
696
697 if (dynOutChans && dynInChans) { return true; }
698
699 // (3) Just need to test one side
700 if (dynInChans || (inputs.mNumEls == 0)) {
701 return CheckOneSide (outputs, true, info.mChanInfo, numInfo);
702 }
703
704 if (dynOutChans || (outputs.mNumEls == 0)) {
705 return CheckOneSide (inputs, false, info.mChanInfo, numInfo);
706 }
707
708 // (4) - not a dynamic AU, has ins and outs, and has channel constraints so we test every possible pairing
709 for (unsigned int in = 0; in < inputs.mNumEls; ++in)
710 {
711 bool testInAlready = false;
712 for (unsigned int i = 0; i < in; ++i) {
713 if (inputs.mChans[i] == inputs.mChans[in]) {
714 testInAlready = true;
715 break;
716 }
717 }
718 if (!testInAlready) {
719 for (unsigned int out = 0; out < outputs.mNumEls; ++out) {
720 // try to save a little bit and not test the same pairing multiple times...
721 bool testOutAlready = false;
722 for (unsigned int i = 0; i < out; ++i) {
723 if (outputs.mChans[i] == outputs.mChans[out]) {
724 testOutAlready = true;
725 break;
726 }
727 }
728 if (!testOutAlready) {
729 if (!ValidateChannelPair (inputs.mChans[in], outputs.mChans[out],info.mChanInfo, numInfo)) {
730 return false;
731 }
732 }
733 }
734 }
735 }
736
737 return true;
738 }
739
SupportsNumChannels() const740 bool CAAudioUnit::SupportsNumChannels () const
741 {
742 // this is the default assumption of an audio effect unit
743 Boolean* isWritable = 0;
744 UInt32 dataSize = 0;
745 // lets see if the unit has any channel restrictions
746 OSStatus result = AudioUnitGetPropertyInfo (AU(),
747 kAudioUnitProperty_SupportedNumChannels,
748 kAudioUnitScope_Global, 0,
749 &dataSize, isWritable); //don't care if this is writable
750
751 // if this property is NOT implemented an FX unit
752 // is expected to deal with same channel valance in and out
753 if (result) {
754 if (Comp().Desc().IsEffect() || Comp().Desc().IsOffline())
755 return true;
756 }
757 return result == noErr;
758 }
759
GetChannelLayoutTags(AudioUnitScope inScope,AudioUnitElement inEl,ChannelTagVector & outChannelVector) const760 OSStatus CAAudioUnit::GetChannelLayoutTags (AudioUnitScope inScope,
761 AudioUnitElement inEl,
762 ChannelTagVector &outChannelVector) const
763 {
764 if (HasChannelLayouts (inScope, inEl) == false) return kAudioUnitErr_InvalidProperty;
765
766 UInt32 dataSize;
767 OSStatus result = AudioUnitGetPropertyInfo (AU(),
768 kAudioUnitProperty_SupportedChannelLayoutTags,
769 inScope, inEl,
770 &dataSize, NULL);
771
772 if (result) return result;
773
774 // OK lets get our channel layouts and see if the one we want is present
775 AudioChannelLayoutTag* info = (AudioChannelLayoutTag*)malloc (dataSize);
776 result = AudioUnitGetProperty (AU(),
777 kAudioUnitProperty_SupportedChannelLayoutTags,
778 inScope, inEl,
779 info, &dataSize);
780 if (result) goto home;
781
782 outChannelVector.erase (outChannelVector.begin(), outChannelVector.end());
783 for (unsigned int i = 0; i < (dataSize / sizeof (AudioChannelLayoutTag)); ++i)
784 outChannelVector.push_back (info[i]);
785
786 home:
787 free (info);
788 return result;
789 }
790
HasChannelLayouts(AudioUnitScope inScope,AudioUnitElement inEl) const791 bool CAAudioUnit::HasChannelLayouts (AudioUnitScope inScope,
792 AudioUnitElement inEl) const
793 {
794 OSStatus result = AudioUnitGetPropertyInfo (AU(),
795 kAudioUnitProperty_SupportedChannelLayoutTags,
796 inScope, inEl,
797 NULL, NULL);
798 return !result;
799 }
800
HasChannelLayout(AudioUnitScope inScope,AudioUnitElement inEl) const801 bool CAAudioUnit::HasChannelLayout (AudioUnitScope inScope,
802 AudioUnitElement inEl) const
803 {
804 Boolean writable;
805 UInt32 size;
806
807 return AudioUnitGetPropertyInfo (AU(),
808 kAudioUnitProperty_AudioChannelLayout,
809 inScope, inEl,
810 &size, &writable) == noErr;
811 }
812
GetChannelLayout(AudioUnitScope inScope,AudioUnitElement inEl,CAAudioChannelLayout & outLayout) const813 OSStatus CAAudioUnit::GetChannelLayout (AudioUnitScope inScope,
814 AudioUnitElement inEl,
815 CAAudioChannelLayout &outLayout) const
816 {
817 UInt32 size;
818 OSStatus result = AudioUnitGetPropertyInfo (AU(), kAudioUnitProperty_AudioChannelLayout,
819 inScope, inEl, &size, NULL);
820 if (result) return result;
821
822 AudioChannelLayout *layout = (AudioChannelLayout*)malloc (size);
823
824 ca_require_noerr (result = AudioUnitGetProperty (AU(), kAudioUnitProperty_AudioChannelLayout,
825 inScope, inEl, layout, &size), home);
826
827 outLayout = CAAudioChannelLayout (layout);
828
829 home:
830 free (layout);
831 return result;
832 }
833
SetChannelLayout(AudioUnitScope inScope,AudioUnitElement inEl,const CAAudioChannelLayout & inLayout)834 OSStatus CAAudioUnit::SetChannelLayout (AudioUnitScope inScope,
835 AudioUnitElement inEl,
836 const CAAudioChannelLayout &inLayout)
837 {
838 OSStatus result = AudioUnitSetProperty (AU(),
839 kAudioUnitProperty_AudioChannelLayout,
840 inScope, inEl,
841 inLayout, inLayout.Size());
842 return result;
843 }
844
SetChannelLayout(AudioUnitScope inScope,AudioUnitElement inEl,const AudioChannelLayout & inLayout,UInt32 inSize)845 OSStatus CAAudioUnit::SetChannelLayout (AudioUnitScope inScope,
846 AudioUnitElement inEl,
847 const AudioChannelLayout &inLayout,
848 UInt32 inSize)
849 {
850 OSStatus result = AudioUnitSetProperty (AU(),
851 kAudioUnitProperty_AudioChannelLayout,
852 inScope, inEl,
853 &inLayout, inSize);
854 return result;
855 }
856
ClearChannelLayout(AudioUnitScope inScope,AudioUnitElement inEl)857 OSStatus CAAudioUnit::ClearChannelLayout (AudioUnitScope inScope,
858 AudioUnitElement inEl)
859 {
860 return AudioUnitSetProperty (AU(),
861 kAudioUnitProperty_AudioChannelLayout,
862 inScope, inEl, NULL, 0);
863 }
864
GetFormat(AudioUnitScope inScope,AudioUnitElement inEl,AudioStreamBasicDescription & outFormat) const865 OSStatus CAAudioUnit::GetFormat (AudioUnitScope inScope,
866 AudioUnitElement inEl,
867 AudioStreamBasicDescription &outFormat) const
868 {
869 UInt32 dataSize = sizeof (AudioStreamBasicDescription);
870 return AudioUnitGetProperty (AU(), kAudioUnitProperty_StreamFormat,
871 inScope, inEl,
872 &outFormat, &dataSize);
873 }
874
SetFormat(AudioUnitScope inScope,AudioUnitElement inEl,const AudioStreamBasicDescription & inFormat)875 OSStatus CAAudioUnit::SetFormat (AudioUnitScope inScope,
876 AudioUnitElement inEl,
877 const AudioStreamBasicDescription &inFormat)
878 {
879 return AudioUnitSetProperty (AU(), kAudioUnitProperty_StreamFormat,
880 inScope, inEl,
881 const_cast<AudioStreamBasicDescription*>(&inFormat),
882 sizeof (AudioStreamBasicDescription));
883 }
884
GetSampleRate(AudioUnitScope inScope,AudioUnitElement inEl,Float64 & outRate) const885 OSStatus CAAudioUnit::GetSampleRate (AudioUnitScope inScope,
886 AudioUnitElement inEl,
887 Float64 &outRate) const
888 {
889 UInt32 dataSize = sizeof (Float64);
890 return AudioUnitGetProperty (AU(), kAudioUnitProperty_SampleRate,
891 inScope, inEl,
892 &outRate, &dataSize);
893 }
894
SetSampleRate(AudioUnitScope inScope,AudioUnitElement inEl,Float64 inRate)895 OSStatus CAAudioUnit::SetSampleRate (AudioUnitScope inScope,
896 AudioUnitElement inEl,
897 Float64 inRate)
898 {
899 AudioStreamBasicDescription desc;
900 OSStatus result = GetFormat (inScope, inEl, desc);
901 if (result) return result;
902 desc.mSampleRate = inRate;
903 return SetFormat (inScope, inEl, desc);
904 }
905
SetSampleRate(Float64 inSampleRate)906 OSStatus CAAudioUnit::SetSampleRate (Float64 inSampleRate)
907 {
908 OSStatus result;
909
910 UInt32 elCount;
911 ca_require_noerr (result = GetElementCount(kAudioUnitScope_Input, elCount), home);
912 if (elCount) {
913 for (unsigned int i = 0; i < elCount; ++i) {
914 ca_require_noerr (result = SetSampleRate (kAudioUnitScope_Input, i, inSampleRate), home);
915 }
916 }
917
918 ca_require_noerr (result = GetElementCount(kAudioUnitScope_Output, elCount), home);
919 if (elCount) {
920 for (unsigned int i = 0; i < elCount; ++i) {
921 ca_require_noerr (result = SetSampleRate (kAudioUnitScope_Output, i, inSampleRate), home);
922 }
923 }
924
925 home:
926 return result;
927 }
928
NumberChannels(AudioUnitScope inScope,AudioUnitElement inEl,UInt32 & outChans) const929 OSStatus CAAudioUnit::NumberChannels (AudioUnitScope inScope,
930 AudioUnitElement inEl,
931 UInt32 &outChans) const
932 {
933 AudioStreamBasicDescription desc;
934 OSStatus result = GetFormat (inScope, inEl, desc);
935 if (!result)
936 outChans = desc.mChannelsPerFrame;
937 return result;
938 }
939
SetNumberChannels(AudioUnitScope inScope,AudioUnitElement inEl,UInt32 inChans)940 OSStatus CAAudioUnit::SetNumberChannels (AudioUnitScope inScope,
941 AudioUnitElement inEl,
942 UInt32 inChans)
943 {
944 // set this as the output of the AU
945 CAStreamBasicDescription desc;
946 OSStatus result = GetFormat (inScope, inEl, desc);
947 if (result) return result;
948 desc.ChangeNumberChannels (inChans, desc.IsInterleaved());
949 result = SetFormat (inScope, inEl, desc);
950 return result;
951 }
952
IsElementCountWritable(AudioUnitScope inScope,bool & outWritable) const953 OSStatus CAAudioUnit::IsElementCountWritable (AudioUnitScope inScope, bool &outWritable) const
954 {
955 Boolean isWritable;
956 UInt32 outDataSize;
957 OSStatus result = GetPropertyInfo (kAudioUnitProperty_ElementCount, inScope, 0, &outDataSize, &isWritable);
958 if (result)
959 return result;
960 outWritable = isWritable ? true : false;
961 return noErr;
962 }
963
GetElementCount(AudioUnitScope inScope,UInt32 & outCount) const964 OSStatus CAAudioUnit::GetElementCount (AudioUnitScope inScope, UInt32 &outCount) const
965 {
966 UInt32 propSize = sizeof(outCount);
967 return GetProperty (kAudioUnitProperty_ElementCount, inScope, 0, &outCount, &propSize);
968 }
969
SetElementCount(AudioUnitScope inScope,UInt32 inCount)970 OSStatus CAAudioUnit::SetElementCount (AudioUnitScope inScope, UInt32 inCount)
971 {
972 return SetProperty (kAudioUnitProperty_ElementCount, inScope, 0, &inCount, sizeof(inCount));
973 }
974
HasDynamicScope(AudioUnitScope inScope,SInt32 & outTotalNumChannels) const975 bool CAAudioUnit::HasDynamicScope (AudioUnitScope inScope, SInt32 &outTotalNumChannels) const
976 {
977 // ok - now we need to check the AU's capability here.
978 // this is the default assumption of an audio effect unit
979 Boolean* isWritable = 0;
980 UInt32 dataSize = 0;
981 OSStatus result = GetPropertyInfo (kAudioUnitProperty_SupportedNumChannels,
982 kAudioUnitScope_Global, 0,
983 &dataSize, isWritable); //don't care if this is writable
984
985 // AU has to explicitly tell us about this.
986 if (result) return false;
987
988 StackAUChannelInfo info (dataSize);
989
990 result = GetProperty (kAudioUnitProperty_SupportedNumChannels,
991 kAudioUnitScope_Global, 0,
992 info.mChanInfo, &dataSize);
993 if (result) return false;
994
995 return ValidateDynamicScope (inScope, outTotalNumChannels, info.mChanInfo, (dataSize / sizeof(AUChannelInfo)));
996 }
997
998 // as we've already checked that the element count is writable
999 // the following conditions will match this..
1000 /*
1001 -1, -2 -> signifies no restrictions
1002 -2, -1 -> signifies no restrictions -> in this case outTotalNumChannels == -1 (any num channels)
1003
1004 -N (where N is less than -2), signifies the total channel count on the scope side (in or out)
1005 */
ValidateDynamicScope(AudioUnitScope inScope,SInt32 & outTotalNumChannels,const AUChannelInfo * info,UInt32 numInfo) const1006 bool CAAudioUnit::ValidateDynamicScope (AudioUnitScope inScope,
1007 SInt32 &outTotalNumChannels,
1008 const AUChannelInfo *info,
1009 UInt32 numInfo) const
1010 {
1011 bool writable = false;
1012 OSStatus result = IsElementCountWritable (inScope, writable);
1013 if (result || (writable == false))
1014 return false;
1015
1016 //now chan layout can contain -1 for either scope (ie. doesn't care)
1017 for (unsigned int i = 0; i < numInfo; ++i)
1018 {
1019 // lets test the special wild card case first...
1020 // this says the AU can do any num channels on input or output - for eg. Matrix Mixer
1021 if (((info[i].inChannels == -1) && (info[i].outChannels == -2))
1022 || ((info[i].inChannels == -2) && (info[i].outChannels == -1)))
1023 {
1024 outTotalNumChannels = -1;
1025 return true;
1026 }
1027
1028 // ok lets now test our special case....
1029 if (inScope == kAudioUnitScope_Input) {
1030 // isn't dynamic on this side at least
1031 if (info[i].inChannels >= 0)
1032 continue;
1033
1034 if (info[i].inChannels < -2) {
1035 outTotalNumChannels = abs (info[i].inChannels);
1036 return true;
1037 }
1038 }
1039
1040 else if (inScope == kAudioUnitScope_Output) {
1041 // isn't dynamic on this side at least
1042 if (info[i].outChannels >= 0)
1043 continue;
1044
1045 if (info[i].outChannels < -2) {
1046 outTotalNumChannels = abs (info[i].outChannels);
1047 return true;
1048 }
1049 }
1050
1051 else {
1052 break; // wrong scope was specified
1053 }
1054 }
1055
1056 return false;
1057 }
1058
ConfigureDynamicScope(AudioUnitScope inScope,UInt32 inNumElements,UInt32 * inChannelsPerElement,Float64 inSampleRate)1059 OSStatus CAAudioUnit::ConfigureDynamicScope (AudioUnitScope inScope,
1060 UInt32 inNumElements,
1061 UInt32 *inChannelsPerElement,
1062 Float64 inSampleRate)
1063 {
1064 SInt32 numChannels = 0;
1065 bool isDyamic = HasDynamicScope (inScope, numChannels);
1066 if (isDyamic == false)
1067 return kAudioUnitErr_InvalidProperty;
1068
1069 //lets to a sanity check...
1070 // if numChannels == -1, then it can do "any"...
1071 if (numChannels > 0) {
1072 SInt32 count = 0;
1073 for (unsigned int i = 0; i < inNumElements; ++i)
1074 count += inChannelsPerElement[i];
1075 if (count > numChannels)
1076 return kAudioUnitErr_InvalidPropertyValue;
1077 }
1078
1079 OSStatus result = SetElementCount (inScope, inNumElements);
1080 if (result)
1081 return result;
1082
1083 for (unsigned int i = 0; i < inNumElements; ++i) {
1084 CAStreamBasicDescription desc;
1085 result = GetFormat (inScope, i, desc);
1086 if (result) return result;
1087 desc.ChangeNumberChannels (inChannelsPerElement[i], desc.IsInterleaved());
1088 desc.mSampleRate = inSampleRate;
1089 result = SetFormat (inScope, i, desc);
1090 if (result)
1091 return result;
1092 }
1093 return noErr;
1094 }
1095
1096 #pragma mark __Properties
1097
CanBypass() const1098 bool CAAudioUnit::CanBypass () const
1099 {
1100 Boolean outWritable;
1101 OSStatus result = AudioUnitGetPropertyInfo (AU(), kAudioUnitProperty_BypassEffect,
1102 kAudioUnitScope_Global, 0,
1103 NULL, &outWritable);
1104 return (!result && outWritable);
1105 }
1106
GetBypass() const1107 bool CAAudioUnit::GetBypass () const
1108 {
1109 UInt32 dataSize = sizeof (UInt32);
1110 UInt32 outBypass;
1111 OSStatus result = AudioUnitGetProperty (AU(), kAudioUnitProperty_BypassEffect,
1112 kAudioUnitScope_Global, 0,
1113 &outBypass, &dataSize);
1114 return (result ? false : outBypass);
1115 }
1116
SetBypass(bool inBypass) const1117 OSStatus CAAudioUnit::SetBypass (bool inBypass) const
1118 {
1119 UInt32 bypass = inBypass ? 1 : 0;
1120 return AudioUnitSetProperty (AU(), kAudioUnitProperty_BypassEffect,
1121 kAudioUnitScope_Global, 0,
1122 &bypass, sizeof (UInt32));
1123 }
1124
GetMaxFramesPerSlice(UInt32 & outMaxFrames) const1125 OSStatus CAAudioUnit::GetMaxFramesPerSlice (UInt32& outMaxFrames) const
1126 {
1127 UInt32 dataSize = sizeof(outMaxFrames);
1128 return AudioUnitGetProperty (AU(), kAudioUnitProperty_MaximumFramesPerSlice,
1129 kAudioUnitScope_Global, 0,
1130 &outMaxFrames, &dataSize);
1131 }
1132
SetMaxFramesPerSlice(UInt32 inMaxFrames)1133 OSStatus CAAudioUnit::SetMaxFramesPerSlice (UInt32 inMaxFrames)
1134 {
1135 return AudioUnitSetProperty (AU(), kAudioUnitProperty_MaximumFramesPerSlice,
1136 kAudioUnitScope_Global, 0,
1137 &inMaxFrames, sizeof (UInt32));
1138 }
1139
Latency() const1140 Float64 CAAudioUnit::Latency () const
1141 {
1142 Float64 secs;
1143 UInt32 size = sizeof(secs);
1144 if (GetProperty (kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0, &secs, &size))
1145 return 0;
1146 return secs;
1147 }
1148
GetAUPreset(CFPropertyListRef & outData) const1149 OSStatus CAAudioUnit::GetAUPreset (CFPropertyListRef &outData) const
1150 {
1151 UInt32 dataSize = sizeof(outData);
1152 return AudioUnitGetProperty (AU(), kAudioUnitProperty_ClassInfo,
1153 kAudioUnitScope_Global, 0,
1154 &outData, &dataSize);
1155 }
1156
SetAUPreset(CFPropertyListRef & inData)1157 OSStatus CAAudioUnit::SetAUPreset (CFPropertyListRef &inData)
1158 {
1159 return AudioUnitSetProperty (AU(), kAudioUnitProperty_ClassInfo,
1160 kAudioUnitScope_Global, 0,
1161 &inData, sizeof (CFPropertyListRef));
1162 }
1163
1164 #if !TARGET_OS_IPHONE
SetAUPresetFromDocument(CFPropertyListRef & inData)1165 OSStatus CAAudioUnit::SetAUPresetFromDocument (CFPropertyListRef &inData)
1166 {
1167 return AudioUnitSetProperty (AU(), kAudioUnitProperty_ClassInfoFromDocument,
1168 kAudioUnitScope_Global, 0,
1169 &inData, sizeof (CFPropertyListRef));
1170 }
1171 #endif
1172
GetPresentPreset(AUPreset & outData) const1173 OSStatus CAAudioUnit::GetPresentPreset (AUPreset &outData) const
1174 {
1175 UInt32 dataSize = sizeof(outData);
1176 OSStatus result = AudioUnitGetProperty (AU(), kAudioUnitProperty_PresentPreset,
1177 kAudioUnitScope_Global, 0,
1178 &outData, &dataSize);
1179 #if !TARGET_OS_IPHONE
1180 #ifndef __LP64__
1181 if (result == kAudioUnitErr_InvalidProperty) {
1182 dataSize = sizeof(outData);
1183 result = AudioUnitGetProperty (AU(), kAudioUnitProperty_CurrentPreset,
1184 kAudioUnitScope_Global, 0,
1185 &outData, &dataSize);
1186 if (result == noErr) {
1187 // we now retain the CFString in the preset so for the client of this API
1188 // it is consistent (ie. the string should be released when done)
1189 if (outData.presetName)
1190 CFRetain (outData.presetName);
1191 }
1192 }
1193 #endif
1194 #endif
1195 return result;
1196 }
1197
SetPresentPreset(AUPreset & inData)1198 OSStatus CAAudioUnit::SetPresentPreset (AUPreset &inData)
1199 {
1200 OSStatus result = AudioUnitSetProperty (AU(), kAudioUnitProperty_PresentPreset,
1201 kAudioUnitScope_Global, 0,
1202 &inData, sizeof (AUPreset));
1203 #if !TARGET_OS_IPHONE
1204 #ifndef __LP64__
1205 if (result == kAudioUnitErr_InvalidProperty) {
1206 result = AudioUnitSetProperty (AU(), kAudioUnitProperty_CurrentPreset,
1207 kAudioUnitScope_Global, 0,
1208 &inData, sizeof (AUPreset));
1209 }
1210 #endif
1211 #endif
1212 return result;
1213 }
1214
HasCustomView() const1215 bool CAAudioUnit::HasCustomView () const
1216 {
1217 #if !TARGET_OS_IPHONE
1218 UInt32 dataSize = 0;
1219 OSStatus result = -4/*unimpErr*/;
1220 #ifndef __LP64__
1221 result = GetPropertyInfo(kAudioUnitProperty_GetUIComponentList,
1222 kAudioUnitScope_Global, 0,
1223 &dataSize, NULL);
1224 #endif
1225 if (result || !dataSize) {
1226 dataSize = 0;
1227 result = GetPropertyInfo(kAudioUnitProperty_CocoaUI,
1228 kAudioUnitScope_Global, 0,
1229 &dataSize, NULL);
1230 if (result || !dataSize)
1231 return false;
1232 }
1233 return true;
1234 #else
1235 return false;
1236 #endif
1237
1238 }
1239
GetParameter(AudioUnitParameterID inID,AudioUnitScope scope,AudioUnitElement element,Float32 & outValue) const1240 OSStatus CAAudioUnit::GetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
1241 Float32 &outValue) const
1242 {
1243 return mDataPtr ? mDataPtr->GetParameter (inID, scope, element, outValue) : static_cast<OSStatus>(paramErr);
1244 }
1245
SetParameter(AudioUnitParameterID inID,AudioUnitScope scope,AudioUnitElement element,Float32 value,UInt32 bufferOffsetFrames)1246 OSStatus CAAudioUnit::SetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element,
1247 Float32 value, UInt32 bufferOffsetFrames)
1248 {
1249 return mDataPtr ? mDataPtr->SetParameter (inID, scope, element, value, bufferOffsetFrames) : static_cast<OSStatus>(paramErr);
1250 }
1251
MIDIEvent(UInt32 inStatus,UInt32 inData1,UInt32 inData2,UInt32 inOffsetSampleFrame)1252 OSStatus CAAudioUnit::MIDIEvent (UInt32 inStatus,
1253 UInt32 inData1,
1254 UInt32 inData2,
1255 UInt32 inOffsetSampleFrame)
1256 {
1257 return mDataPtr ? mDataPtr->MIDIEvent (inStatus, inData1, inData2, inOffsetSampleFrame) : paramErr;
1258 }
1259
StartNote(MusicDeviceInstrumentID inInstrument,MusicDeviceGroupID inGroupID,NoteInstanceID * outNoteInstanceID,UInt32 inOffsetSampleFrame,const MusicDeviceNoteParams * inParams)1260 OSStatus CAAudioUnit::StartNote (MusicDeviceInstrumentID inInstrument,
1261 MusicDeviceGroupID inGroupID,
1262 NoteInstanceID * outNoteInstanceID,
1263 UInt32 inOffsetSampleFrame,
1264 const MusicDeviceNoteParams * inParams)
1265 {
1266 return mDataPtr ? mDataPtr->StartNote (inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, inParams)
1267 : paramErr;
1268 }
1269
StopNote(MusicDeviceGroupID inGroupID,NoteInstanceID inNoteInstanceID,UInt32 inOffsetSampleFrame)1270 OSStatus CAAudioUnit::StopNote (MusicDeviceGroupID inGroupID,
1271 NoteInstanceID inNoteInstanceID,
1272 UInt32 inOffsetSampleFrame)
1273 {
1274 return mDataPtr ? mDataPtr->StopNote (inGroupID, inNoteInstanceID, inOffsetSampleFrame) : paramErr;
1275 }
1276
1277
1278 #pragma mark __Render
1279
Render(AudioUnitRenderActionFlags * ioActionFlags,const AudioTimeStamp * inTimeStamp,UInt32 inOutputBusNumber,UInt32 inNumberFrames,AudioBufferList * ioData)1280 OSStatus CAAudioUnit::Render (AudioUnitRenderActionFlags * ioActionFlags,
1281 const AudioTimeStamp * inTimeStamp,
1282 UInt32 inOutputBusNumber,
1283 UInt32 inNumberFrames,
1284 AudioBufferList * ioData)
1285 {
1286 return mDataPtr ? mDataPtr->Render (ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData) : static_cast<OSStatus>(paramErr);
1287 }
1288
1289 extern "C" OSStatus
1290 AudioUnitProcess ( AudioUnit inUnit,
1291 AudioUnitRenderActionFlags * ioActionFlags,
1292 const AudioTimeStamp * inTimeStamp,
1293 UInt32 inNumberFrames,
1294 AudioBufferList * ioData);
1295
Process(AudioUnitRenderActionFlags & ioActionFlags,const AudioTimeStamp & inTimeStamp,UInt32 inNumberFrames,AudioBufferList & ioData)1296 OSStatus CAAudioUnit::Process (AudioUnitRenderActionFlags & ioActionFlags,
1297 const AudioTimeStamp & inTimeStamp,
1298 UInt32 inNumberFrames,
1299 AudioBufferList & ioData)
1300 {
1301 #if defined(__MAC_10_7) || defined(__IPHONE_4_0)
1302 return AudioUnitProcess (AU(), &ioActionFlags, &inTimeStamp, inNumberFrames, &ioData);
1303 #else
1304 return -4/*unimpErr*/;
1305 #endif
1306 }
1307
1308 extern "C" OSStatus
1309 AudioUnitProcessMultiple ( AudioUnit inUnit,
1310 AudioUnitRenderActionFlags * ioActionFlags,
1311 const AudioTimeStamp * inTimeStamp,
1312 UInt32 inNumberFrames,
1313 UInt32 inNumberInputBufferLists,
1314 const AudioBufferList ** inInputBufferLists,
1315 UInt32 inNumberOutputBufferLists,
1316 AudioBufferList ** ioOutputBufferLists);
1317
ProcessMultiple(AudioUnitRenderActionFlags & ioActionFlags,const AudioTimeStamp & inTimeStamp,UInt32 inNumberFrames,UInt32 inNumberInputBufferLists,const AudioBufferList ** inInputBufferLists,UInt32 inNumberOutputBufferLists,AudioBufferList ** ioOutputBufferLists)1318 OSStatus CAAudioUnit::ProcessMultiple (AudioUnitRenderActionFlags & ioActionFlags,
1319 const AudioTimeStamp & inTimeStamp,
1320 UInt32 inNumberFrames,
1321 UInt32 inNumberInputBufferLists,
1322 const AudioBufferList ** inInputBufferLists,
1323 UInt32 inNumberOutputBufferLists,
1324 AudioBufferList ** ioOutputBufferLists)
1325 {
1326 #if defined(__MAC_10_7) || defined(__IPHONE_4_0)
1327 return AudioUnitProcessMultiple (AU(), &ioActionFlags, &inTimeStamp, inNumberFrames,
1328 inNumberInputBufferLists, inInputBufferLists, inNumberOutputBufferLists, ioOutputBufferLists);
1329 #else
1330 return -4/*unimpErr*/;
1331 #endif
1332 }
1333
1334 #pragma mark __CAAUChanHelper
1335
CAAUChanHelper(const CAAudioUnit & inAU,AudioUnitScope inScope)1336 CAAUChanHelper::CAAUChanHelper(const CAAudioUnit &inAU, AudioUnitScope inScope)
1337 :mChans(NULL), mNumEls(0), mDidAllocate(false)
1338 {
1339 UInt32 elCount;
1340 if (inAU.GetElementCount (inScope, elCount)) return;
1341 if (elCount > kStaticElCount) {
1342 mChans = new UInt32[elCount];
1343 mDidAllocate = true;
1344 memset (mChans, 0, sizeof(int) * elCount);
1345 } else {
1346 mChans = mStaticChans;
1347 memset (mChans, 0, sizeof(int) * kStaticElCount);
1348 }
1349 for (unsigned int i = 0; i < elCount; ++i) {
1350 UInt32 numChans;
1351 if (inAU.NumberChannels (inScope, i, numChans)) return;
1352 mChans[i] = numChans;
1353 }
1354 mNumEls = elCount;
1355 }
1356
CAAUChanHelper(UInt32 inMaxElems)1357 CAAUChanHelper::CAAUChanHelper(UInt32 inMaxElems)
1358 : mNumEls(inMaxElems), mDidAllocate(false)
1359 {
1360 if (inMaxElems > kStaticElCount) {
1361 mChans = new UInt32[inMaxElems];
1362 mDidAllocate = true;
1363 memset (mChans, 0, sizeof(int) * inMaxElems);
1364 } else {
1365 mChans = mStaticChans;
1366 memset (mChans, 0, sizeof(int) * kStaticElCount);
1367 }
1368 }
1369
~CAAUChanHelper()1370 CAAUChanHelper::~CAAUChanHelper()
1371 {
1372 if (mDidAllocate) delete [] mChans;
1373 }
1374
operator =(const CAAUChanHelper & c)1375 CAAUChanHelper& CAAUChanHelper::operator= (const CAAUChanHelper &c)
1376 {
1377 if (mDidAllocate) delete [] mChans;
1378 if (c.mDidAllocate) {
1379 mChans = new UInt32[c.mNumEls];
1380 mDidAllocate = true;
1381 } else {
1382 mDidAllocate = false;
1383 mChans = mStaticChans;
1384 }
1385 memcpy (mChans, c.mChans, c.mNumEls * sizeof(int));
1386
1387 return *this;
1388 }
1389
1390
1391 #pragma mark __Print Utilities
1392
Print(FILE * file) const1393 void CAAudioUnit::Print (FILE* file) const
1394 {
1395 fprintf (file, "AudioUnit:%p\n", AU());
1396 if (IsValid()) {
1397 fprintf (file, "\tnode=%ld\t", (long)GetAUNode()); Comp().Print (file);
1398 }
1399 }
1400
1401 #if CA_AU_USE_FAST_DISPATCH
1402 // Handle GetComponentInstanceStorage(ComponentInstance aComponentInstance)
LoadGetComponentInstanceStorage(void * inst)1403 static void *LoadGetComponentInstanceStorage (void *inst)
1404 {
1405 typedef void* (*GetComponentInstanceStorageProc)(void* aComponentInstance);
1406 static GetComponentInstanceStorageProc sGetComponentInstanceStorageProc = NULL;
1407
1408 static int sDoCSLoad = 1;
1409 if (sDoCSLoad) {
1410 sDoCSLoad = 0;
1411 void *theImage = dlopen("/System/Library/Frameworks/CoreServices.framework/CoreServices", RTLD_LAZY);
1412 if (!theImage) return NULL;
1413
1414 sGetComponentInstanceStorageProc = (GetComponentInstanceStorageProc) dlsym(theImage, "GetComponentInstanceStorage");
1415 }
1416 if (sGetComponentInstanceStorageProc)
1417 return (*sGetComponentInstanceStorageProc)(inst);
1418 return NULL;
1419 }
1420 #endif
1421
1422