1 /*
2 File: AUBase.h
3 Abstract: Part of CoreAudio Utility Classes
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 #ifndef __AUBase_h__
48 #define __AUBase_h__
49
50 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
51
52 #include <TargetConditionals.h>
53 #include <juce_core/native/juce_mac_ClangBugWorkaround.h>
54
55 #if TARGET_OS_MAC
56 #include <pthread.h>
57 #elif TARGET_OS_WIN32
58 #include <windows.h>
59 #else
60 #error Unsupported Operating System
61 #endif
62
63 #include <vector>
64
65 #include "AUScopeElement.h"
66 #include "AUInputElement.h"
67 #include "AUOutputElement.h"
68 #include "AUBuffer.h"
69 #include "CAMath.h"
70 #include "CAThreadSafeList.h"
71 #include "CAVectorUnit.h"
72 #include "CAMutex.h"
73 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
74 #include <AudioUnit/AudioUnit.h>
75 #if !CA_BASIC_AU_FEATURES
76 #include <AudioUnit/MusicDevice.h>
77 #endif
78 #else
79 #include "AudioUnit.h"
80 #if !CA_BASIC_AU_FEATURES
81 #include "MusicDevice.h"
82 #endif
83 #endif
84
85 #ifndef AUTRACE
86 #define AUTRACE(code, obj, a, b, c, d)
87 #endif
88
89 #include "AUPlugInDispatch.h"
90
91
92
93 // ________________________________________________________________________
94 // These are to be moved to the public AudioUnit headers
95
96 #define kAUDefaultSampleRate 44100.0
97 #if !TARGET_OS_WIN32
98 #define kAUDefaultMaxFramesPerSlice 1156
99 //this allows enough default frames for a 512 dest 44K and SRC from 96K
100 // add a padding of 4 frames for any altivec rounding
101 #else
102 #define kAUDefaultMaxFramesPerSlice 2048
103 #endif
104
105 // ________________________________________________________________________
106
107 /*! @class AUBase */
108 class AUBase : public ComponentBase {
109 public:
110
111 /*! @ctor AUBase */
112 AUBase( AudioComponentInstance inInstance,
113 UInt32 numInputElements,
114 UInt32 numOutputElements,
115 UInt32 numGroupElements = 0);
116 /*! @dtor AUBase */
117 virtual ~AUBase();
118
119 /*! @method PostConstructor */
PostConstructor()120 virtual void PostConstructor() { CreateElements(); }
121
122 /*! @method PreDestructor */
123 virtual void PreDestructor();
124
125 /*! @method CreateElements */
126 void CreateElements();
127 // Called immediately after construction, when virtual methods work.
128 // Or, a subclass may call this in order to have access to elements
129 // in its constructor.
130
131 /*! @method CreateExtendedElements */
CreateExtendedElements()132 virtual void CreateExtendedElements() {}
133
134 #pragma mark -
135 #pragma mark AU dispatch
136 // ________________________________________________________________________
137 // Virtual methods (mostly) directly corresponding to the entry points. Many of these
138 // have useful implementations here and will not need overriding.
139
140 /*! @method DoInitialize */
141 OSStatus DoInitialize();
142 // this implements the entry point and makes sure that initialization
143 // is only attempted exactly once...
144
145 /*! @method Initialize */
146 virtual OSStatus Initialize();
147 // ... so that overrides to this method can assume that they will only
148 // be called exactly once.
149
150 /*! @method IsInitialized */
IsInitialized()151 bool IsInitialized() const { return mInitialized; }
152 /*! @method HasBegunInitializing */
HasBegunInitializing()153 bool HasBegunInitializing() const { return mHasBegunInitializing; }
154
155 /*! @method DoCleanup */
156 void DoCleanup();
157 // same pattern as with Initialize
158
159 /*! @method Cleanup */
160 virtual void Cleanup();
161
162 /*! @method Reset */
163 virtual OSStatus Reset( AudioUnitScope inScope,
164 AudioUnitElement inElement);
165
166 // Note about GetPropertyInfo, GetProperty, SetProperty:
167 // Certain properties are trapped out in these dispatch functions and handled with different virtual
168 // methods. (To discourage hacks and keep vtable size down, these are non-virtual)
169
170 /*! @method DispatchGetPropertyInfo */
171 OSStatus DispatchGetPropertyInfo(AudioUnitPropertyID inID,
172 AudioUnitScope inScope,
173 AudioUnitElement inElement,
174 UInt32 & outDataSize,
175 Boolean & outWritable);
176
177 /*! @method DispatchGetProperty */
178 OSStatus DispatchGetProperty( AudioUnitPropertyID inID,
179 AudioUnitScope inScope,
180 AudioUnitElement inElement,
181 void * outData);
182
183 /*! @method DispatchSetProperty */
184 OSStatus DispatchSetProperty( AudioUnitPropertyID inID,
185 AudioUnitScope inScope,
186 AudioUnitElement inElement,
187 const void * inData,
188 UInt32 inDataSize);
189
190 OSStatus DispatchRemovePropertyValue( AudioUnitPropertyID inID,
191 AudioUnitScope inScope,
192 AudioUnitElement inElement);
193
194 /*! @method GetPropertyInfo */
195 virtual OSStatus GetPropertyInfo( AudioUnitPropertyID inID,
196 AudioUnitScope inScope,
197 AudioUnitElement inElement,
198 UInt32 & outDataSize,
199 Boolean & outWritable);
200
201 /*! @method GetProperty */
202 virtual OSStatus GetProperty( AudioUnitPropertyID inID,
203 AudioUnitScope inScope,
204 AudioUnitElement inElement,
205 void * outData);
206
207 /*! @method SetProperty */
208 virtual OSStatus SetProperty( AudioUnitPropertyID inID,
209 AudioUnitScope inScope,
210 AudioUnitElement inElement,
211 const void * inData,
212 UInt32 inDataSize);
213
214 /*! @method ClearPropertyUsage */
215 virtual OSStatus RemovePropertyValue ( AudioUnitPropertyID inID,
216 AudioUnitScope inScope,
217 AudioUnitElement inElement);
218
219 /*! @method AddPropertyListener */
220 virtual OSStatus AddPropertyListener( AudioUnitPropertyID inID,
221 AudioUnitPropertyListenerProc inProc,
222 void * inProcRefCon);
223
224 /*! @method RemovePropertyListener */
225 virtual OSStatus RemovePropertyListener( AudioUnitPropertyID inID,
226 AudioUnitPropertyListenerProc inProc,
227 void * inProcRefCon,
228 bool refConSpecified);
229
230 /*! @method SetRenderNotification */
231 virtual OSStatus SetRenderNotification( AURenderCallback inProc,
232 void * inRefCon);
233
234 /*! @method RemoveRenderNotification */
235 virtual OSStatus RemoveRenderNotification(
236 AURenderCallback inProc,
237 void * inRefCon);
238
239 /*! @method GetParameter */
240 virtual OSStatus GetParameter( AudioUnitParameterID inID,
241 AudioUnitScope inScope,
242 AudioUnitElement inElement,
243 AudioUnitParameterValue & outValue);
244
245 /*! @method SetParameter */
246 virtual OSStatus SetParameter( AudioUnitParameterID inID,
247 AudioUnitScope inScope,
248 AudioUnitElement inElement,
249 AudioUnitParameterValue inValue,
250 UInt32 inBufferOffsetInFrames);
251
252 /*! @method CanScheduleParams */
253 virtual bool CanScheduleParameters() const = 0;
254
255 /*! @method ScheduleParameter */
256 virtual OSStatus ScheduleParameter ( const AudioUnitParameterEvent *inParameterEvent,
257 UInt32 inNumEvents);
258
259
260 /*! @method DoRender */
261 OSStatus DoRender( AudioUnitRenderActionFlags & ioActionFlags,
262 const AudioTimeStamp & inTimeStamp,
263 UInt32 inBusNumber,
264 UInt32 inNumberFrames,
265 AudioBufferList & ioData);
266
267
268 /*! @method Process */
269 OSStatus DoProcess ( AudioUnitRenderActionFlags & ioActionFlags,
270 const AudioTimeStamp & inTimeStamp,
271 UInt32 inFramesToProcess,
272 AudioBufferList & ioData);
273
274 /*! @method ProcessMultiple */
275 OSStatus DoProcessMultiple ( AudioUnitRenderActionFlags & ioActionFlags,
276 const AudioTimeStamp & inTimeStamp,
277 UInt32 inFramesToProcess,
278 UInt32 inNumberInputBufferLists,
279 const AudioBufferList ** inInputBufferLists,
280 UInt32 inNumberOutputBufferLists,
281 AudioBufferList ** ioOutputBufferLists);
282
283 /*! @method ProcessBufferLists */
ProcessBufferLists(AudioUnitRenderActionFlags & ioActionFlags,const AudioBufferList & inBuffer,AudioBufferList & outBuffer,UInt32 inFramesToProcess)284 virtual OSStatus ProcessBufferLists( AudioUnitRenderActionFlags & ioActionFlags,
285 const AudioBufferList & inBuffer,
286 AudioBufferList & outBuffer,
287 UInt32 inFramesToProcess )
288 {
289 return kAudio_UnimplementedError;
290 }
291
292 /*! @method ProcessMultipleBufferLists */
ProcessMultipleBufferLists(AudioUnitRenderActionFlags & ioActionFlags,UInt32 inFramesToProcess,UInt32 inNumberInputBufferLists,const AudioBufferList ** inInputBufferLists,UInt32 inNumberOutputBufferLists,AudioBufferList ** ioOutputBufferLists)293 virtual OSStatus ProcessMultipleBufferLists( AudioUnitRenderActionFlags & ioActionFlags,
294 UInt32 inFramesToProcess,
295 UInt32 inNumberInputBufferLists,
296 const AudioBufferList ** inInputBufferLists,
297 UInt32 inNumberOutputBufferLists,
298 AudioBufferList ** ioOutputBufferLists)
299 {
300 return kAudio_UnimplementedError;
301 }
302
303 /*! @method ComplexRender */
ComplexRender(AudioUnitRenderActionFlags & ioActionFlags,const AudioTimeStamp & inTimeStamp,UInt32 inOutputBusNumber,UInt32 inNumberOfPackets,UInt32 * outNumberOfPackets,AudioStreamPacketDescription * outPacketDescriptions,AudioBufferList & ioData,void * outMetadata,UInt32 * outMetadataByteSize)304 virtual OSStatus ComplexRender( AudioUnitRenderActionFlags & ioActionFlags,
305 const AudioTimeStamp & inTimeStamp,
306 UInt32 inOutputBusNumber,
307 UInt32 inNumberOfPackets,
308 UInt32 * outNumberOfPackets,
309 AudioStreamPacketDescription * outPacketDescriptions,
310 AudioBufferList & ioData,
311 void * outMetadata,
312 UInt32 * outMetadataByteSize)
313 {
314 return kAudio_UnimplementedError;
315 }
316
317 // Override this method if your AU processes multiple output busses completely independently --
318 // you'll want to just call Render without the NeedsToRender check.
319 // Otherwise, override Render().
320 //
321 // N.B. Implementations of this method can assume that the output's buffer list has already been
322 // prepared and access it with GetOutput(inBusNumber)->GetBufferList() instead of
323 // GetOutput(inBusNumber)->PrepareBuffer(nFrames) -- if PrepareBuffer is called, a
324 // copy may occur after rendering.
325 /*! @method RenderBus */
RenderBus(AudioUnitRenderActionFlags & ioActionFlags,const AudioTimeStamp & inTimeStamp,UInt32 inBusNumber,UInt32 inNumberFrames)326 virtual OSStatus RenderBus( AudioUnitRenderActionFlags & ioActionFlags,
327 const AudioTimeStamp & inTimeStamp,
328 UInt32 inBusNumber,
329 UInt32 inNumberFrames)
330 {
331 if (NeedsToRender(inTimeStamp))
332 return Render(ioActionFlags, inTimeStamp, inNumberFrames);
333 return noErr; // was presumably already rendered via another bus
334 }
335
336 // N.B. For a unit with only one output bus, it can assume in its implementation of this
337 // method that the output's buffer list has already been prepared and access it with
338 // GetOutput(0)->GetBufferList() instead of GetOutput(0)->PrepareBuffer(nFrames)
339 // -- if PrepareBuffer is called, a copy may occur after rendering.
340 /*! @method Render */
Render(AudioUnitRenderActionFlags & ioActionFlags,const AudioTimeStamp & inTimeStamp,UInt32 inNumberFrames)341 virtual OSStatus Render( AudioUnitRenderActionFlags & ioActionFlags,
342 const AudioTimeStamp & inTimeStamp,
343 UInt32 inNumberFrames)
344 {
345 return noErr;
346 }
347
348
349 #pragma mark -
350 #pragma mark Property Dispatch
351
352 static const Float64 kNoLastRenderedSampleTime;
353
354 // ________________________________________________________________________
355 // These are generated from DispatchGetProperty/DispatchGetPropertyInfo/DispatchSetProperty
356
357 /*! @method BusCountWritable */
BusCountWritable(AudioUnitScope inScope)358 virtual bool BusCountWritable( AudioUnitScope inScope)
359 {
360 return false;
361 }
362 virtual OSStatus SetBusCount( AudioUnitScope inScope,
363 UInt32 inCount);
364
365 /*! @method SetConnection */
366 virtual OSStatus SetConnection( const AudioUnitConnection & inConnection);
367
368 /*! @method SetInputCallback */
369 virtual OSStatus SetInputCallback( UInt32 inPropertyID,
370 AudioUnitElement inElement,
371 AURenderCallback inProc,
372 void * inRefCon);
373
374 /*! @method GetParameterList */
375 virtual OSStatus GetParameterList( AudioUnitScope inScope,
376 AudioUnitParameterID * outParameterList,
377 UInt32 & outNumParameters);
378 // outParameterList may be a null pointer
379
380 /*! @method GetParameterInfo */
381 virtual OSStatus GetParameterInfo( AudioUnitScope inScope,
382 AudioUnitParameterID inParameterID,
383 AudioUnitParameterInfo & outParameterInfo);
384
385 virtual OSStatus GetParameterHistoryInfo(AudioUnitScope inScope,
386 AudioUnitParameterID inParameterID,
387 Float32 & outUpdatesPerSecond,
388 Float32 & outHistoryDurationInSeconds);
389
390 /*! @method SaveState */
391 virtual OSStatus SaveState( CFPropertyListRef * outData);
392
393 /*! @method SaveExtendedScopes */
SaveExtendedScopes(CFMutableDataRef outData)394 virtual void SaveExtendedScopes( CFMutableDataRef outData) {};
395
396 /*! @method RestoreState */
397 virtual OSStatus RestoreState( CFPropertyListRef inData);
398
399 /*! @method GetParameterValueStrings */
400 virtual OSStatus GetParameterValueStrings(AudioUnitScope inScope,
401 AudioUnitParameterID inParameterID,
402 CFArrayRef * outStrings);
403
404 /*! @method CopyClumpName */
405 virtual OSStatus CopyClumpName( AudioUnitScope inScope,
406 UInt32 inClumpID,
407 UInt32 inDesiredNameLength,
408 CFStringRef * outClumpName);
409
410 /*! @method GetPresets */
411 virtual OSStatus GetPresets ( CFArrayRef * outData) const;
412
413 // set the default preset for the unit -> the number of the preset MUST be >= 0
414 // and the name should be valid, or the preset WON'T take
415 /*! @method SetAFactoryPresetAsCurrent */
416 bool SetAFactoryPresetAsCurrent (const AUPreset & inPreset);
417
418 // Called when someone sets a new, valid preset
419 // If this is a valid preset, then the subclass sets its state to that preset
420 // and returns noErr.
421 // If not a valid preset, return an error, and the pre-existing preset is restored
422 /*! @method NewFactoryPresetSet */
423 virtual OSStatus NewFactoryPresetSet (const AUPreset & inNewFactoryPreset);
424
425 /*! @method NewCustomPresetSet */
426 virtual OSStatus NewCustomPresetSet (const AUPreset & inNewCustomPreset);
427
428 #if !CA_USE_AUDIO_PLUGIN_ONLY
429 /*! @method GetNumCustomUIComponents */
430 virtual int GetNumCustomUIComponents ();
431
432 /*! @method GetUIComponentDescs */
433 virtual void GetUIComponentDescs (ComponentDescription* inDescArray);
434 #endif
435
436 /*! @method CopyIconLocation */
437 virtual CFURLRef CopyIconLocation ();
438
439 // default is no latency, and unimplemented tail time
440 /*! @method GetLatency */
GetLatency()441 virtual Float64 GetLatency() {return 0.0;}
442 /*! @method GetTailTime */
GetTailTime()443 virtual Float64 GetTailTime() {return 0;}
444 /*! @method SupportsRampAndTail */
SupportsTail()445 virtual bool SupportsTail () { return false; }
446
447 /*! @method IsStreamFormatWritable */
448 bool IsStreamFormatWritable( AudioUnitScope scope,
449 AudioUnitElement element);
450
451 /*! @method StreamFormatWritable */
452 virtual bool StreamFormatWritable( AudioUnitScope scope,
453 AudioUnitElement element) = 0;
454 // scope will always be input or output
455
456 // pass in a pointer to get the struct, and num channel infos
457 // you can pass in NULL to just get the number
458 // a return value of 0 (the default in AUBase) means the property is not supported...
459 /*! @method SupportedNumChannels */
460 virtual UInt32 SupportedNumChannels ( const AUChannelInfo** outInfo);
461
462 /*! @method ValidFormat */
463 virtual bool ValidFormat( AudioUnitScope inScope,
464 AudioUnitElement inElement,
465 const CAStreamBasicDescription & inNewFormat);
466 // Will only be called after StreamFormatWritable
467 // has succeeded.
468 // Default implementation requires canonical format:
469 // native-endian 32-bit float, any sample rate,
470 // any number of channels; override when other
471 // formats are supported. A subclass's override can
472 // choose to always return true and trap invalid
473 // formats in ChangeStreamFormat.
474
475
476 /*! @method FormatIsCanonical */
477 bool FormatIsCanonical( const CAStreamBasicDescription &format);
478
479 /*! @method MakeCanonicalFormat */
480 void MakeCanonicalFormat( CAStreamBasicDescription & outDesc,
481 int numChannels = 2);
482
483 /*! @method GetStreamFormat */
484 virtual const CAStreamBasicDescription &
485 GetStreamFormat( AudioUnitScope inScope,
486 AudioUnitElement inElement);
487
488 /*! @method ChangeStreamFormat */
489 virtual OSStatus ChangeStreamFormat( AudioUnitScope inScope,
490 AudioUnitElement inElement,
491 const CAStreamBasicDescription & inPrevFormat,
492 const CAStreamBasicDescription & inNewFormat);
493 // Will only be called after StreamFormatWritable
494 // and ValidFormat have succeeded.
495
496 // ________________________________________________________________________
497
498 #if !CA_USE_AUDIO_PLUGIN_ONLY
499 /*! @method ComponentEntryDispatch */
500 static OSStatus ComponentEntryDispatch( ComponentParameters * params,
501 AUBase * This);
502 #endif
503
504 // ________________________________________________________________________
505 // Methods useful for subclasses
506
507 /*! @method GetScope */
GetScope(AudioUnitScope inScope)508 AUScope & GetScope( AudioUnitScope inScope)
509 {
510 if (inScope >= kNumScopes) {
511 AUScope * scope = GetScopeExtended(inScope);
512 if (!scope) COMPONENT_THROW(kAudioUnitErr_InvalidScope);
513 return *scope;
514 }
515 return mScopes[inScope];
516 }
517
518 /*! @method GetScopeExtended */
GetScopeExtended(AudioUnitScope inScope)519 virtual AUScope * GetScopeExtended (AudioUnitScope inScope) { return NULL; }
520
521 /*! @method GlobalScope */
GlobalScope()522 AUScope & GlobalScope() { return mScopes[kAudioUnitScope_Global]; }
523 /*! @method Inputs */
Inputs()524 AUScope & Inputs() { return mScopes[kAudioUnitScope_Input]; }
525 /*! @method Outputs */
Outputs()526 AUScope & Outputs() { return mScopes[kAudioUnitScope_Output]; }
527 #if !CA_BASIC_AU_FEATURES
528 /*! @method Groups */
Groups()529 AUScope & Groups() { return mScopes[kAudioUnitScope_Group]; }
530 #endif
531 /*! @method Globals */
Globals()532 AUElement * Globals() { return mScopes[kAudioUnitScope_Global].GetElement(0); }
533
534 /*! @method SetNumberOfElements */
535 void SetNumberOfElements( AudioUnitScope inScope,
536 UInt32 numElements);
537
538 /*! @method GetElement */
GetElement(AudioUnitScope inScope,AudioUnitElement inElement)539 AUElement * GetElement( AudioUnitScope inScope,
540 AudioUnitElement inElement)
541 {
542 return GetScope(inScope).GetElement(inElement);
543 }
544
545 /*! @method GetIOElement */
GetIOElement(AudioUnitScope inScope,AudioUnitElement inElement)546 AUIOElement * GetIOElement( AudioUnitScope inScope,
547 AudioUnitElement inElement)
548 {
549 return GetScope(inScope).GetIOElement(inElement);
550 }
551
552 /*! @method SafeGetElement */
SafeGetElement(AudioUnitScope inScope,AudioUnitElement inElement)553 AUElement * SafeGetElement( AudioUnitScope inScope,
554 AudioUnitElement inElement)
555 {
556 return GetScope(inScope).SafeGetElement(inElement);
557 }
558
559 /*! @method GetInput */
GetInput(AudioUnitElement inElement)560 AUInputElement * GetInput( AudioUnitElement inElement)
561 {
562 return static_cast<AUInputElement *>(Inputs().SafeGetElement(inElement));
563 }
564
565 /*! @method GetOutput */
GetOutput(AudioUnitElement inElement)566 AUOutputElement * GetOutput( AudioUnitElement inElement)
567 {
568 return static_cast<AUOutputElement *>(Outputs().SafeGetElement(inElement));
569 }
570
571 #if !CA_BASIC_AU_FEATURES
572 /*! @method GetGroup */
GetGroup(AudioUnitElement inElement)573 AUElement * GetGroup( AudioUnitElement inElement)
574 {
575 return Groups().SafeGetElement(inElement);
576 }
577 #endif
578
579 /*! @method PullInput */
PullInput(UInt32 inBusNumber,AudioUnitRenderActionFlags & ioActionFlags,const AudioTimeStamp & inTimeStamp,UInt32 inNumberFrames)580 OSStatus PullInput( UInt32 inBusNumber,
581 AudioUnitRenderActionFlags &ioActionFlags,
582 const AudioTimeStamp & inTimeStamp,
583 UInt32 inNumberFrames)
584 {
585 AUInputElement *input = GetInput(inBusNumber); // throws if error
586 return input->PullInput(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames);
587 }
588
589 /*! @method GetMaxFramesPerSlice */
GetMaxFramesPerSlice()590 UInt32 GetMaxFramesPerSlice() const { return mMaxFramesPerSlice; }
591 /*! @method UsesFixedBlockSize */
UsesFixedBlockSize()592 bool UsesFixedBlockSize() const { return mUsesFixedBlockSize; }
593 /*! @method SetUsesFixedBlockSize */
SetUsesFixedBlockSize(bool inUsesFixedBlockSize)594 void SetUsesFixedBlockSize(bool inUsesFixedBlockSize) { mUsesFixedBlockSize = inUsesFixedBlockSize; }
595
596 /*! @method GetVectorUnitType */
GetVectorUnitType()597 static SInt32 GetVectorUnitType() { return sVectorUnitType; }
598 /*! @method HasVectorUnit */
HasVectorUnit()599 static bool HasVectorUnit() { return sVectorUnitType > 0; }
600 /*! @method HasAltivec */
HasAltivec()601 static bool HasAltivec() { return sVectorUnitType == kVecAltivec; }
602 /*! @method HasSSE2 */
HasSSE2()603 static bool HasSSE2() { return sVectorUnitType >= kVecSSE2; }
604 /*! @method HasSSE3 */
HasSSE3()605 static bool HasSSE3() { return sVectorUnitType >= kVecSSE3; }
606
607 /*! @method AudioUnitAPIVersion */
AudioUnitAPIVersion()608 UInt8 AudioUnitAPIVersion() const { return mAudioUnitAPIVersion; }
609
610 /*! @method IsRenderThread */
InRenderThread()611 bool InRenderThread () const
612 {
613 #if TARGET_OS_MAC
614 return (mRenderThreadID ? pthread_equal (mRenderThreadID, pthread_self()) : false);
615 #elif TARGET_OS_WIN32
616 return (mRenderThreadID ? mRenderThreadID == GetCurrentThreadId() : false);
617 #endif
618 }
619
620 /*! @method HasInput */
HasInput(AudioUnitElement inElement)621 bool HasInput( AudioUnitElement inElement) {
622 AUInputElement *in = static_cast<AUInputElement *>(Inputs().GetElement(inElement));
623 return in != NULL && in->IsActive();
624 }
625 // says whether an input is connected or has a callback
626
627 /*! @method PropertyChanged */
628 virtual void PropertyChanged( AudioUnitPropertyID inID,
629 AudioUnitScope inScope,
630 AudioUnitElement inElement);
631
632 #if !CA_NO_AU_UI_FEATURES
633 // These calls can be used to call a Host's Callbacks. The method returns -1 if the host
634 // hasn't supplied the callback. Any other result is returned by the host.
635 // As in the API contract, for a parameter's value, you specify a pointer
636 // to that data type. Specify NULL for a parameter that you are not interested
637 // as this can save work in the host.
638
639 /*! @method CallHostBeatAndTempo */
CallHostBeatAndTempo(Float64 * outCurrentBeat,Float64 * outCurrentTempo)640 OSStatus CallHostBeatAndTempo (Float64 *outCurrentBeat,
641 Float64 *outCurrentTempo)
642 {
643 return (mHostCallbackInfo.beatAndTempoProc
644 ? (*mHostCallbackInfo.beatAndTempoProc) (mHostCallbackInfo.hostUserData,
645 outCurrentBeat,
646 outCurrentTempo)
647 : -1);
648 }
649
650 /*! @method CallHostMusicalTimeLocation */
CallHostMusicalTimeLocation(UInt32 * outDeltaSampleOffsetToNextBeat,Float32 * outTimeSig_Numerator,UInt32 * outTimeSig_Denominator,Float64 * outCurrentMeasureDownBeat)651 OSStatus CallHostMusicalTimeLocation (UInt32 *outDeltaSampleOffsetToNextBeat,
652 Float32 *outTimeSig_Numerator,
653 UInt32 *outTimeSig_Denominator,
654 Float64 *outCurrentMeasureDownBeat)
655 {
656 return (mHostCallbackInfo.musicalTimeLocationProc
657 ? (*mHostCallbackInfo.musicalTimeLocationProc) (mHostCallbackInfo.hostUserData,
658 outDeltaSampleOffsetToNextBeat,
659 outTimeSig_Numerator,
660 outTimeSig_Denominator,
661 outCurrentMeasureDownBeat)
662 : -1);
663 }
664
665 /*! @method CallHostTransportState */
CallHostTransportState(Boolean * outIsPlaying,Boolean * outTransportStateChanged,Float64 * outCurrentSampleInTimeLine,Boolean * outIsCycling,Float64 * outCycleStartBeat,Float64 * outCycleEndBeat)666 OSStatus CallHostTransportState (Boolean *outIsPlaying,
667 Boolean *outTransportStateChanged,
668 Float64 *outCurrentSampleInTimeLine,
669 Boolean *outIsCycling,
670 Float64 *outCycleStartBeat,
671 Float64 *outCycleEndBeat)
672 {
673 return (mHostCallbackInfo.transportStateProc
674 ? (*mHostCallbackInfo.transportStateProc) (mHostCallbackInfo.hostUserData,
675 outIsPlaying,
676 outTransportStateChanged,
677 outCurrentSampleInTimeLine,
678 outIsCycling,
679 outCycleStartBeat,
680 outCycleEndBeat)
681 : -1);
682 }
683 #endif
684
685 char* GetLoggingString () const;
686
GetMutex()687 CAMutex* GetMutex() { return mAUMutex; }
688
689 // ________________________________________________________________________
690 /*! @method CreateElement */
691 virtual AUElement * CreateElement( AudioUnitScope scope,
692 AudioUnitElement element);
693
694 #pragma mark -
695 #pragma mark AU Output Base Dispatch
696 // ________________________________________________________________________
697 // ________________________________________________________________________
698 // ________________________________________________________________________
699 // output unit methods
700 /*! @method Start */
Start()701 virtual OSStatus Start() { return kAudio_UnimplementedError; }
702 /*! @method Stop */
Stop()703 virtual OSStatus Stop() { return kAudio_UnimplementedError; }
704
705 #if !CA_BASIC_AU_FEATURES
706 #pragma mark -
707 #pragma mark AU Music Base Dispatch
708
709 #if !TARGET_OS_IPHONE
710 // these methods are deprecated, so we don't include them except for compatability
711 /*! @method PrepareInstrument */
PrepareInstrument(MusicDeviceInstrumentID inInstrument)712 virtual OSStatus PrepareInstrument(MusicDeviceInstrumentID inInstrument) { return kAudio_UnimplementedError; }
713
714 /*! @method PrepareInstrument */
ReleaseInstrument(MusicDeviceInstrumentID inInstrument)715 virtual OSStatus ReleaseInstrument(MusicDeviceInstrumentID inInstrument) { return kAudio_UnimplementedError; }
716 #endif
717
718 // ________________________________________________________________________
719 // ________________________________________________________________________
720 // ________________________________________________________________________
721 // music device/music effect methods -- incomplete
722 /*! @method MIDIEvent */
MIDIEvent(UInt32 inStatus,UInt32 inData1,UInt32 inData2,UInt32 inOffsetSampleFrame)723 virtual OSStatus MIDIEvent( UInt32 inStatus,
724 UInt32 inData1,
725 UInt32 inData2,
726 UInt32 inOffsetSampleFrame) { return kAudio_UnimplementedError; }
727
728 /*! @method SysEx */
SysEx(const UInt8 * inData,UInt32 inLength)729 virtual OSStatus SysEx( const UInt8 * inData,
730 UInt32 inLength) { return kAudio_UnimplementedError;}
731
732 /*! @method StartNote */
StartNote(MusicDeviceInstrumentID inInstrument,MusicDeviceGroupID inGroupID,NoteInstanceID * outNoteInstanceID,UInt32 inOffsetSampleFrame,const MusicDeviceNoteParams & inParams)733 virtual OSStatus StartNote( MusicDeviceInstrumentID inInstrument,
734 MusicDeviceGroupID inGroupID,
735 NoteInstanceID * outNoteInstanceID,
736 UInt32 inOffsetSampleFrame,
737 const MusicDeviceNoteParams &inParams) { return kAudio_UnimplementedError; }
738
739 /*! @method StopNote */
StopNote(MusicDeviceGroupID inGroupID,NoteInstanceID inNoteInstanceID,UInt32 inOffsetSampleFrame)740 virtual OSStatus StopNote( MusicDeviceGroupID inGroupID,
741 NoteInstanceID inNoteInstanceID,
742 UInt32 inOffsetSampleFrame) { return kAudio_UnimplementedError; }
743 #endif
744
745 // ________________________________________________________________________
746 // ________________________________________________________________________
747 // ________________________________________________________________________
748
749 protected:
750 #pragma mark -
751 #pragma mark Implementation methods
752
753 /*! @method ReallocateBuffers */
754 virtual void ReallocateBuffers();
755 // needs to be called when mMaxFramesPerSlice changes
756 virtual void DeallocateIOBuffers();
757
758 /*! @method FillInParameterName */
FillInParameterName(AudioUnitParameterInfo & ioInfo,CFStringRef inName,bool inShouldRelease)759 static void FillInParameterName (AudioUnitParameterInfo& ioInfo, CFStringRef inName, bool inShouldRelease)
760 {
761 ioInfo.cfNameString = inName;
762 ioInfo.flags |= kAudioUnitParameterFlag_HasCFNameString;
763 if (inShouldRelease)
764 ioInfo.flags |= kAudioUnitParameterFlag_CFNameRelease;
765 CFStringGetCString (inName, ioInfo.name, offsetof (AudioUnitParameterInfo, clumpID), kCFStringEncodingUTF8);
766 }
767
HasClump(AudioUnitParameterInfo & ioInfo,UInt32 inClumpID)768 static void HasClump (AudioUnitParameterInfo& ioInfo, UInt32 inClumpID)
769 {
770 ioInfo.clumpID = inClumpID;
771 ioInfo.flags |= kAudioUnitParameterFlag_HasClump;
772 }
773
774 /*! @method SetMaxFramesPerSlice */
775 virtual void SetMaxFramesPerSlice(UInt32 nFrames);
776
777 /*! @method CanSetMaxFrames */
778 virtual OSStatus CanSetMaxFrames() const;
779
780 /*! @method WantsRenderThreadID */
WantsRenderThreadID()781 bool WantsRenderThreadID () const { return mWantsRenderThreadID; }
782
783 /*! @method SetWantsRenderThreadID */
784 void SetWantsRenderThreadID (bool inFlag);
785
786 /*! @method SetRenderError */
SetRenderError(OSStatus inErr)787 OSStatus SetRenderError (OSStatus inErr)
788 {
789 if (inErr && mLastRenderError == 0) {
790 mLastRenderError = inErr;
791 PropertyChanged(kAudioUnitProperty_LastRenderError, kAudioUnitScope_Global, 0);
792 }
793 return inErr;
794 }
795
796 private:
797 /*! @method DoRenderBus */
798 // shared between Render and RenderSlice, inlined to minimize function call overhead
DoRenderBus(AudioUnitRenderActionFlags & ioActionFlags,const AudioTimeStamp & inTimeStamp,UInt32 inBusNumber,AUOutputElement * theOutput,UInt32 inNumberFrames,AudioBufferList & ioData)799 OSStatus DoRenderBus( AudioUnitRenderActionFlags & ioActionFlags,
800 const AudioTimeStamp & inTimeStamp,
801 UInt32 inBusNumber,
802 AUOutputElement * theOutput,
803 UInt32 inNumberFrames,
804 AudioBufferList & ioData)
805 {
806 if (theOutput != NULL)
807 {
808 if (ioData.mBuffers[0].mData == NULL || (theOutput->WillAllocateBuffer() && Outputs().GetNumberOfElements() > 1))
809 // will render into cache buffer
810 theOutput->PrepareBuffer(inNumberFrames);
811 else
812 // will render into caller's buffer
813 theOutput->SetBufferList(ioData);
814 }
815
816 OSStatus result = RenderBus(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames);
817 if (result == noErr && theOutput != NULL) {
818 if (ioData.mBuffers[0].mData == NULL) {
819 theOutput->CopyBufferListTo(ioData);
820 AUTRACE(kCATrace_AUBaseDoRenderBus, mComponentInstance, inNumberFrames, (intptr_t)theOutput->GetBufferList().mBuffers[0].mData, 0, *(UInt32 *)ioData.mBuffers[0].mData);
821 } else {
822 theOutput->CopyBufferContentsTo(ioData);
823 AUTRACE(kCATrace_AUBaseDoRenderBus, mComponentInstance, inNumberFrames, (intptr_t)theOutput->GetBufferList().mBuffers[0].mData, (intptr_t)ioData.mBuffers[0].mData, *(UInt32 *)ioData.mBuffers[0].mData);
824 theOutput->InvalidateBufferList();
825 }
826 }
827 return result;
828 }
829
830 /*! @method HasIcon */
831 bool HasIcon ();
832
833 /*! @method ResetRenderTime */
ResetRenderTime()834 void ResetRenderTime ()
835 {
836 memset (&mCurrentRenderTime, 0, sizeof(mCurrentRenderTime));
837 mCurrentRenderTime.mSampleTime = kNoLastRenderedSampleTime;
838 }
839
840 protected:
841 /*! @method GetAudioChannelLayout */
842 virtual UInt32 GetChannelLayoutTags( AudioUnitScope scope,
843 AudioUnitElement element,
844 AudioChannelLayoutTag * outLayoutTags);
845
846 /*! @method GetAudioChannelLayout */
847 virtual UInt32 GetAudioChannelLayout( AudioUnitScope scope,
848 AudioUnitElement element,
849 AudioChannelLayout * outLayoutPtr,
850 Boolean & outWritable);
851
852 /*! @method SetAudioChannelLayout */
853 virtual OSStatus SetAudioChannelLayout( AudioUnitScope scope,
854 AudioUnitElement element,
855 const AudioChannelLayout * inLayout);
856
857 /*! @method RemoveAudioChannelLayout */
858 virtual OSStatus RemoveAudioChannelLayout(AudioUnitScope scope, AudioUnitElement element);
859
860 /*! @method NeedsToRender */
NeedsToRender(const AudioTimeStamp & inTimeStamp)861 bool NeedsToRender( const AudioTimeStamp & inTimeStamp)
862 {
863 bool needsToRender = fnotequal(inTimeStamp.mSampleTime, mCurrentRenderTime.mSampleTime);
864 if (needsToRender) // only copy this if we need to render
865 mCurrentRenderTime = inTimeStamp;
866 return needsToRender;
867 }
868
869 // Scheduled parameter implementation:
870
871 typedef std::vector<AudioUnitParameterEvent> ParameterEventList;
872
873 // Usually, you won't override this method. You only need to call this if your DSP code
874 // is prepared to handle scheduled immediate and ramped parameter changes.
875 // Before calling this method, it is assumed you have already called PullInput() on the input busses
876 // for which the DSP code depends. ProcessForScheduledParams() will call (potentially repeatedly)
877 // virtual method ProcessScheduledSlice() to perform the actual DSP for a given sub-division of
878 // the buffer. The job of ProcessForScheduledParams() is to sub-divide the buffer into smaller
879 // pieces according to the scheduled times found in the ParameterEventList (usually coming
880 // directly from a previous call to ScheduleParameter() ), setting the appropriate immediate or
881 // ramped parameter values for the corresponding scopes and elements, then calling ProcessScheduledSlice()
882 // to do the actual DSP for each of these divisions.
883 virtual OSStatus ProcessForScheduledParams( ParameterEventList &inParamList,
884 UInt32 inFramesToProcess,
885 void *inUserData );
886
887 // This method is called (potentially repeatedly) by ProcessForScheduledParams()
888 // in order to perform the actual DSP required for this portion of the entire buffer
889 // being processed. The entire buffer can be divided up into smaller "slices"
890 // according to the timestamps on the scheduled parameters...
891 //
892 // sub-classes wishing to handle scheduled parameter changes should override this method
893 // in order to do the appropriate DSP. AUEffectBase already overrides this for standard
894 // effect AudioUnits.
ProcessScheduledSlice(void * inUserData,UInt32 inStartFrameInBuffer,UInt32 inSliceFramesToProcess,UInt32 inTotalBufferFrames)895 virtual OSStatus ProcessScheduledSlice( void *inUserData,
896 UInt32 inStartFrameInBuffer,
897 UInt32 inSliceFramesToProcess,
898 UInt32 inTotalBufferFrames ) {return noErr;}; // default impl does nothing...
899
900
901 /*! @method CurrentRenderTime */
CurrentRenderTime()902 const AudioTimeStamp & CurrentRenderTime () const { return mCurrentRenderTime; }
903
904 // ________________________________________________________________________
905 // Private data members to discourage hacking in subclasses
906 private:
907 struct RenderCallback {
RenderCallbackRenderCallback908 RenderCallback(AURenderCallback proc, void *ref) :
909 mRenderNotify(proc),
910 mRenderNotifyRefCon(ref)
911 { }
912
913 AURenderCallback mRenderNotify;
914 void * mRenderNotifyRefCon;
915
916 bool operator == (const RenderCallback &other) {
917 return this->mRenderNotify == other.mRenderNotify &&
918 this->mRenderNotifyRefCon == other.mRenderNotifyRefCon;
919 }
920 };
921 typedef TThreadSafeList<RenderCallback> RenderCallbackList;
922
923 #if !CA_BASIC_AU_FEATURES
924 enum { kNumScopes = 4 };
925 #else
926 enum { kNumScopes = 3 };
927 #endif
928
929 /*! @var mElementsCreated */
930 bool mElementsCreated;
931 protected:
932 /*! @var mInitialized */
933 bool mInitialized;
934 /*! @var mHasBegunInitializing */
935 bool mHasBegunInitializing;
936 private:
937 /*! @var mAudioUnitAPIVersion */
938 UInt8 mAudioUnitAPIVersion;
939
940 /*! @var mInitNumInputEls */
941 const UInt32 mInitNumInputEls;
942 /*! @var mInitNumOutputEls */
943 const UInt32 mInitNumOutputEls;
944 #if !CA_BASIC_AU_FEATURES
945 /*! @var mInitNumGroupEls */
946 const UInt32 mInitNumGroupEls;
947 #endif
948 /*! @var mScopes */
949 AUScope mScopes[kNumScopes];
950
951 /*! @var mRenderCallbacks */
952 RenderCallbackList mRenderCallbacks;
953 bool mRenderCallbacksTouched;
954
955 /*! @var mRenderThreadID */
956 #if TARGET_OS_MAC
957 pthread_t mRenderThreadID;
958 #elif TARGET_OS_WIN32
959 UInt32 mRenderThreadID;
960 #endif
961
962 /*! @var mWantsRenderThreadID */
963 bool mWantsRenderThreadID;
964
965 /*! @var mCurrentRenderTime */
966 AudioTimeStamp mCurrentRenderTime;
967
968 /*! @var mMaxFramesPerSlice */
969 UInt32 mMaxFramesPerSlice;
970
971 /*! @var mLastRenderError */
972 OSStatus mLastRenderError;
973 /*! @var mCurrentPreset */
974 AUPreset mCurrentPreset;
975
976 protected:
977 /*! @var mUsesFixedBlockSize */
978 bool mUsesFixedBlockSize;
979
980 struct PropertyListener {
981 AudioUnitPropertyID propertyID;
982 AudioUnitPropertyListenerProc listenerProc;
983 void * listenerRefCon;
984 };
985 typedef std::vector<PropertyListener> PropertyListeners;
986
987 /*! @var mParamList */
988 ParameterEventList mParamList;
989 /*! @var mPropertyListeners */
990 PropertyListeners mPropertyListeners;
991
992 /*! @var mBuffersAllocated */
993 bool mBuffersAllocated;
994
995 /*! @var mLogString */
996 // if this is NOT null, it will contain identifying info about this AU.
997 char* mLogString;
998
999 /*! @var mNickName */
1000 CFStringRef mNickName;
1001
1002 /*! @var mAUMutex */
1003 CAMutex * mAUMutex;
1004
1005 private:
1006 /*! @var sVectorUnitType */
1007 static SInt32 sVectorUnitType;
1008
1009 #if !CA_NO_AU_HOST_CALLBACKS
1010 protected:
1011 /*! @var mHostCallbackInfo */
1012 HostCallbackInfo mHostCallbackInfo;
1013
1014 #endif
1015 #if !CA_NO_AU_UI_FEATURES
1016 protected:
1017 /*! @var mContextInfo */
1018 CFStringRef mContextName;
1019 #endif
1020 };
1021
PullInputWithBufferList(AudioUnitRenderActionFlags & ioActionFlags,const AudioTimeStamp & inTimeStamp,AudioUnitElement inElement,UInt32 nFrames,AudioBufferList * inBufferList)1022 inline OSStatus AUInputElement::PullInputWithBufferList(
1023 AudioUnitRenderActionFlags & ioActionFlags,
1024 const AudioTimeStamp & inTimeStamp,
1025 AudioUnitElement inElement,
1026 UInt32 nFrames,
1027 AudioBufferList * inBufferList)
1028 {
1029 OSStatus theResult;
1030
1031 if (HasConnection()) {
1032 // only support connections for V2 audio units
1033 #if !CA_USE_AUDIO_PLUGIN_ONLY
1034 if (mConnRenderProc != NULL)
1035 theResult = reinterpret_cast<AudioUnitRenderProc>(mConnRenderProc)(
1036 mConnInstanceStorage, &ioActionFlags, &inTimeStamp, mConnection.sourceOutputNumber, nFrames, inBufferList);
1037 else
1038 #endif
1039 theResult = AudioUnitRender(
1040 mConnection.sourceAudioUnit, &ioActionFlags, &inTimeStamp, mConnection.sourceOutputNumber, nFrames, inBufferList);
1041 } else {
1042 // kFromCallback:
1043 theResult = (mInputProc)(
1044 mInputProcRefCon, &ioActionFlags, &inTimeStamp, inElement, nFrames, inBufferList);
1045 }
1046
1047 if (mInputType == kNoInput) // defense: the guy upstream could have disconnected
1048 // it's a horrible thing to do, but may happen!
1049 return kAudioUnitErr_NoConnection;
1050
1051
1052 return theResult;
1053 }
1054
1055 #endif // __AUBase_h__
1056