3 Abstract: AUPannerBase.h
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.
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.
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.
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.
44 Copyright (C) 2014 Apple Inc. All Rights Reserved.
47 #include "AUPannerBase.h"
48 #include "CABundleLocker.h"
49 #include <AudioToolbox/AudioToolbox.h>
50 #include <Accelerate/Accelerate.h>
52 static bool sLocalized = false;
54 static CFStringRef kPanner_Azimuth_Name = CFSTR("azimuth");
55 static CFStringRef kPanner_Elevation_Name = CFSTR("elevation");
56 static CFStringRef kPanner_Distance_Name = CFSTR("distance");
58 static CFStringRef kPanner_CoordScale_Name = CFSTR("coordinate scale");
59 static CFStringRef kPanner_RefDistance_Name = CFSTR("reference distance");
60 static CFStringRef kPanner_Gain_Name = CFSTR("gain");
62 static Float32 kPannerParamDefault_Azimuth = 0.;
63 static Float32 kPannerParamDefault_Elevation = 0.;
64 static Float32 kPannerParamDefault_Distance = 1.;
66 static Float32 kPannerParamDefault_CoordScale = 10.;
67 static Float32 kPannerParamDefault_RefDistance = 1.;
68 static Float32 kPannerParamDefault_Gain = 1.;
70 //_____________________________________________________________________________
72 AUPannerBase::AUPannerBase(AudioComponentInstance inAudioUnit)
73 : AUBase(inAudioUnit, 1, 1), mBypassEffect(false)
79 CFBundleRef bundle = CFBundleGetBundleWithIdentifier( CFSTR("com.apple.audio.units.Components") );
82 kPanner_Azimuth_Name = CFCopyLocalizedStringFromTableInBundle(kPanner_Azimuth_Name, CFSTR("AudioUnits"), bundle, CFSTR(""));
83 kPanner_Elevation_Name = CFCopyLocalizedStringFromTableInBundle(kPanner_Elevation_Name, CFSTR("AudioUnits"), bundle, CFSTR(""));
84 kPanner_Distance_Name = CFCopyLocalizedStringFromTableInBundle(kPanner_Distance_Name, CFSTR("AudioUnits"), bundle, CFSTR(""));
86 kPanner_CoordScale_Name = CFCopyLocalizedStringFromTableInBundle(kPanner_CoordScale_Name, CFSTR("AudioUnits"), bundle, CFSTR(""));
87 kPanner_RefDistance_Name = CFCopyLocalizedStringFromTableInBundle(kPanner_RefDistance_Name, CFSTR("AudioUnits"), bundle, CFSTR(""));
88 kPanner_Gain_Name = CFCopyLocalizedStringFromTableInBundle(kPanner_Gain_Name, CFSTR("AudioUnits"), bundle, CFSTR(""));
98 SetParameter(kPannerParam_Azimuth, kPannerParamDefault_Azimuth);
99 SetParameter(kPannerParam_Elevation, kPannerParamDefault_Elevation);
100 SetParameter(kPannerParam_Distance, kPannerParamDefault_Distance);
102 SetParameter(kPannerParam_CoordScale, kPannerParamDefault_CoordScale);
103 SetParameter(kPannerParam_RefDistance, kPannerParamDefault_RefDistance);
104 SetParameter(kPannerParam_Gain, kPannerParamDefault_Gain);
107 //_____________________________________________________________________________
109 AUPannerBase::~AUPannerBase()
114 //_____________________________________________________________________________
116 /*! @method Initialize */
117 OSStatus AUPannerBase::Initialize()
119 OSStatus err = noErr;
121 err = UpdateBypassMatrix();
125 //_____________________________________________________________________________
127 /*! @method AllocBypassMatrix */
128 void AUPannerBase::AllocBypassMatrix()
130 UInt32 inChannels = GetNumberOfInputChannels();
131 UInt32 outChannels = GetNumberOfOutputChannels();
132 mBypassMatrix.alloc(inChannels * outChannels, true);
135 static AudioChannelLayoutTag DefaultTagForNumberOfChannels(UInt32 inNumberChannels)
137 switch (inNumberChannels) {
138 case 1: return kAudioChannelLayoutTag_Mono;
139 case 2: return kAudioChannelLayoutTag_Stereo;
140 case 4: return kAudioChannelLayoutTag_Quadraphonic;
141 case 5: return kAudioChannelLayoutTag_AudioUnit_5_0;
142 case 6: return kAudioChannelLayoutTag_AudioUnit_6_0;
143 case 7: return kAudioChannelLayoutTag_AudioUnit_7_0;
144 case 8: return kAudioChannelLayoutTag_AudioUnit_8;
146 default: return 0xFFFF0000 | inNumberChannels;
150 //_____________________________________________________________________________
152 /*! @method UpdateBypassMatrix */
153 OSStatus AUPannerBase::SetDefaultChannelLayoutsIfNone()
155 OSStatus err = noErr;
157 // if layout has not been set, then guess layout from number of channels
158 UInt32 inChannels = GetNumberOfInputChannels();
159 AudioChannelLayout inputLayoutSubstitute;
160 const AudioChannelLayout* inputLayout = &GetInputLayout();
161 if (inputLayout == NULL || inputLayout->mChannelLayoutTag == 0) {
162 inputLayout = &inputLayoutSubstitute;
163 inputLayoutSubstitute.mNumberChannelDescriptions = 0;
164 inputLayoutSubstitute.mChannelBitmap = 0;
165 inputLayoutSubstitute.mChannelLayoutTag = DefaultTagForNumberOfChannels(inChannels);
167 mInputLayout = &inputLayoutSubstitute;
168 err = SetAudioChannelLayout(kAudioUnitScope_Input, 0, &GetInputLayout());
172 // if layout has not been set, then guess layout from number of channels
173 UInt32 outChannels = GetNumberOfOutputChannels();
174 AudioChannelLayout outputLayoutSubstitute;
175 const AudioChannelLayout* outputLayout = &GetOutputLayout();
176 if (outputLayout == NULL || outputLayout->mChannelLayoutTag == 0) {
177 outputLayout = &outputLayoutSubstitute;
178 outputLayoutSubstitute.mNumberChannelDescriptions = 0;
179 outputLayoutSubstitute.mChannelBitmap = 0;
180 outputLayoutSubstitute.mChannelLayoutTag = DefaultTagForNumberOfChannels(outChannels);
182 mOutputLayout = &outputLayoutSubstitute;
183 err = SetAudioChannelLayout(kAudioUnitScope_Output, 0, &GetOutputLayout());
192 OSStatus AUPannerBase::UpdateBypassMatrix()
194 OSStatus err = SetDefaultChannelLayoutsIfNone();
197 UInt32 inChannels = GetNumberOfInputChannels();
198 UInt32 outChannels = GetNumberOfOutputChannels();
200 const AudioChannelLayout* inoutACL[2];
202 inoutACL[0] = &GetInputLayout();
203 inoutACL[1] = &GetOutputLayout();
205 mBypassMatrix.alloc(inChannels * outChannels, true);
207 UInt32 propSize = inChannels * outChannels * sizeof(Float32);
209 err = AudioFormatGetProperty(kAudioFormatProperty_MatrixMixMap, sizeof(inoutACL), inoutACL, &propSize, mBypassMatrix());
211 // if there is an error, use a diagonal matrix.
212 Float32* bypass = mBypassMatrix();
213 for (UInt32 chan = 0; chan < std::min(inChannels, outChannels); ++chan)
215 float *amp = bypass + (chan * outChannels + chan);
223 //_____________________________________________________________________________
225 /*! @method Cleanup */
226 void AUPannerBase::Cleanup()
232 //_____________________________________________________________________________
235 OSStatus AUPannerBase::Reset( AudioUnitScope inScope,
236 AudioUnitElement inElement)
238 return AUBase::Reset(inScope, inElement);
241 //_____________________________________________________________________________
243 /*! @method GetParameterInfo */
244 OSStatus AUPannerBase::GetParameterInfo( AudioUnitScope inScope,
245 AudioUnitParameterID inParameterID,
246 AudioUnitParameterInfo &outParameterInfo )
248 OSStatus result = noErr;
250 outParameterInfo.flags = kAudioUnitParameterFlag_IsWritable
251 + kAudioUnitParameterFlag_IsReadable;
253 if (inScope == kAudioUnitScope_Global) {
255 switch(inParameterID)
257 case kPannerParam_Azimuth:
258 AUBase::FillInParameterName (outParameterInfo, kPanner_Azimuth_Name, false);
259 outParameterInfo.unit = kAudioUnitParameterUnit_Degrees;
260 outParameterInfo.minValue = -180.;
261 outParameterInfo.maxValue = 180;
262 outParameterInfo.defaultValue = kPannerParamDefault_Azimuth;
265 case kPannerParam_Elevation:
266 AUBase::FillInParameterName (outParameterInfo, kPanner_Elevation_Name, false);
267 outParameterInfo.unit = kAudioUnitParameterUnit_Degrees;
268 outParameterInfo.minValue = -90.;
269 outParameterInfo.maxValue = 90;
270 outParameterInfo.defaultValue = kPannerParamDefault_Elevation;
273 case kPannerParam_Distance:
274 AUBase::FillInParameterName (outParameterInfo, kPanner_Distance_Name, false);
275 outParameterInfo.unit = kAudioUnitParameterUnit_Generic;
276 outParameterInfo.minValue = 0.0;
277 outParameterInfo.maxValue = 1.;
278 outParameterInfo.defaultValue = kPannerParamDefault_Distance;
279 outParameterInfo.flags += kAudioUnitParameterFlag_IsHighResolution;
280 //outParameterInfo.flags += kAudioUnitParameterFlag_DisplayLogarithmic;
283 case kPannerParam_CoordScale:
284 AUBase::FillInParameterName (outParameterInfo, kPanner_CoordScale_Name, false);
285 outParameterInfo.unit = kAudioUnitParameterUnit_Meters;
286 outParameterInfo.minValue = 0.01;
287 outParameterInfo.maxValue = 1000.;
288 outParameterInfo.defaultValue = kPannerParamDefault_CoordScale;
289 outParameterInfo.flags += kAudioUnitParameterFlag_DisplayLogarithmic;
292 case kPannerParam_RefDistance:
293 AUBase::FillInParameterName (outParameterInfo, kPanner_RefDistance_Name, false);
294 outParameterInfo.unit = kAudioUnitParameterUnit_Meters;
295 outParameterInfo.minValue = 0.01;
296 outParameterInfo.maxValue = 1000.;
297 outParameterInfo.defaultValue = kPannerParamDefault_RefDistance;
298 outParameterInfo.flags += kAudioUnitParameterFlag_DisplayLogarithmic;
301 case kPannerParam_Gain:
302 AUBase::FillInParameterName (outParameterInfo, kPanner_Gain_Name, false);
303 outParameterInfo.unit = kAudioUnitParameterUnit_Generic;
304 outParameterInfo.minValue = 0.;
305 outParameterInfo.maxValue = 1.;
306 outParameterInfo.defaultValue = kPannerParamDefault_Gain;
310 result = kAudioUnitErr_InvalidParameter;
314 result = kAudioUnitErr_InvalidParameter;
320 //_____________________________________________________________________________
322 OSStatus AUPannerBase::GetParameter( AudioUnitParameterID inParamID,
323 AudioUnitScope inScope,
324 AudioUnitElement inElement,
327 if (inScope != kAudioUnitScope_Global)
328 return kAudioUnitErr_InvalidScope;
330 outValue = Globals()->GetParameter(inParamID);
336 //_____________________________________________________________________________
338 OSStatus AUPannerBase::SetParameter( AudioUnitParameterID inParamID,
339 AudioUnitScope inScope,
340 AudioUnitElement inElement,
342 UInt32 inBufferOffsetInFrames)
344 if (inScope != kAudioUnitScope_Global)
345 return kAudioUnitErr_InvalidScope;
347 Globals()->SetParameter(inParamID, inValue);
354 //_____________________________________________________________________________
356 /*! @method GetPropertyInfo */
357 OSStatus AUPannerBase::GetPropertyInfo (AudioUnitPropertyID inID,
358 AudioUnitScope inScope,
359 AudioUnitElement inElement,
360 UInt32 & outDataSize,
361 Boolean & outWritable)
363 OSStatus err = noErr;
365 case kAudioUnitProperty_BypassEffect:
366 if (inScope != kAudioUnitScope_Global)
367 return kAudioUnitErr_InvalidScope;
370 outDataSize = sizeof (UInt32);
373 err = AUBase::GetPropertyInfo(inID, inScope, inElement, outDataSize, outWritable);
378 //_____________________________________________________________________________
380 /*! @method GetProperty */
381 OSStatus AUPannerBase::GetProperty (AudioUnitPropertyID inID,
382 AudioUnitScope inScope,
383 AudioUnitElement inElement,
386 OSStatus err = noErr;
389 case kAudioUnitProperty_BypassEffect:
390 if (inScope != kAudioUnitScope_Global)
391 return kAudioUnitErr_InvalidScope;
393 *((UInt32*)outData) = (IsBypassEffect() ? 1 : 0);
396 err = AUBase::GetProperty(inID, inScope, inElement, outData);
401 //_____________________________________________________________________________
403 /*! @method SetProperty */
404 OSStatus AUPannerBase::SetProperty(AudioUnitPropertyID inID,
405 AudioUnitScope inScope,
406 AudioUnitElement inElement,
412 case kAudioUnitProperty_BypassEffect:
413 if (inDataSize < sizeof(UInt32))
414 return kAudioUnitErr_InvalidPropertyValue;
415 bool tempNewSetting = *((UInt32*)inData) != 0;
416 // we're changing the state of bypass
417 if (tempNewSetting != IsBypassEffect())
419 if (!tempNewSetting && IsBypassEffect() && IsInitialized()) // turning bypass off and we're initialized
421 SetBypassEffect (tempNewSetting);
425 return AUBase::SetProperty(inID, inScope, inElement, inData, inDataSize);
429 //_____________________________________________________________________________
431 /*! @method StreamFormatWritable */
432 bool AUPannerBase::StreamFormatWritable (AudioUnitScope scope,
433 AudioUnitElement element)
438 //_____________________________________________________________________________
440 /*! @method ChangeStreamFormat */
441 OSStatus AUPannerBase::ChangeStreamFormat (
442 AudioUnitScope inScope,
443 AudioUnitElement inElement,
444 const CAStreamBasicDescription & inPrevFormat,
445 const CAStreamBasicDescription & inNewFormat)
447 if (inScope == kAudioUnitScope_Input && !InputChannelConfigIsSupported(inNewFormat.NumberChannels()))
448 return kAudioUnitErr_FormatNotSupported;
450 if (inScope == kAudioUnitScope_Output && !OutputChannelConfigIsSupported(inNewFormat.NumberChannels()))
451 return kAudioUnitErr_FormatNotSupported;
453 if (inNewFormat.NumberChannels() != inPrevFormat.NumberChannels())
454 RemoveAudioChannelLayout(inScope, inElement);
456 return AUBase::ChangeStreamFormat(inScope, inElement, inPrevFormat, inNewFormat);
459 //_____________________________________________________________________________
461 /*! @method Render */
462 OSStatus AUPannerBase::Render(AudioUnitRenderActionFlags & ioActionFlags,
463 const AudioTimeStamp & inTimeStamp,
464 UInt32 inNumberFrames)
466 if (IsBypassEffect())
467 return BypassRender(ioActionFlags, inTimeStamp, inNumberFrames);
469 return PannerRender(ioActionFlags, inTimeStamp, inNumberFrames);
472 //_____________________________________________________________________________
474 /*! @method Render */
475 OSStatus AUPannerBase::BypassRender(AudioUnitRenderActionFlags & ioActionFlags,
476 const AudioTimeStamp & inTimeStamp,
477 UInt32 inNumberFrames)
479 AudioUnitRenderActionFlags xflags = 0;
480 OSStatus result = PullInput(0, xflags, inTimeStamp, inNumberFrames);
481 if (result) return false;
482 bool isSilent = xflags & kAudioUnitRenderAction_OutputIsSilence;
484 AudioBufferList& outputBufferList = GetOutput(0)->GetBufferList();
485 AUBufferList::ZeroBuffer(outputBufferList);
489 UInt32 inChannels = GetNumberOfInputChannels();
490 UInt32 outChannels = GetNumberOfOutputChannels();
491 Float32* bypass = mBypassMatrix();
492 for (UInt32 outChan = 0; outChan < outChannels; ++outChan)
494 float* outData = GetOutput(0)->GetChannelData(outChan);
496 for (UInt32 inChan = 0; inChan < inChannels; ++inChan)
498 float* inData = GetInput(0)->GetChannelData(inChan);
499 float *amp = bypass + (inChan * outChannels + outChan);
500 vDSP_vsma(inData, 1, amp, outData, 1, outData, 1, inNumberFrames);
507 //_____________________________________________________________________________
509 UInt32 AUPannerBase::GetAudioChannelLayout( AudioUnitScope inScope,
510 AudioUnitElement inElement,
511 AudioChannelLayout * outLayoutPtr,
512 Boolean & outWritable)
514 SetDefaultChannelLayoutsIfNone();
518 CAAudioChannelLayout* caacl = NULL;
521 case kAudioUnitScope_Input:
522 caacl = &mInputLayout;
524 case kAudioUnitScope_Output:
525 caacl = &mOutputLayout;
528 COMPONENT_THROW(kAudioUnitErr_InvalidScope);
532 COMPONENT_THROW(kAudioUnitErr_InvalidElement);
534 UInt32 size = caacl->IsValid() ? caacl->Size() : 0;
535 if (size > 0 && outLayoutPtr)
536 memcpy(outLayoutPtr, &caacl->Layout(), size);
541 //_____________________________________________________________________________
543 OSStatus AUPannerBase::RemoveAudioChannelLayout( AudioUnitScope inScope,
544 AudioUnitElement inElement)
546 CAAudioChannelLayout* caacl = NULL;
549 case kAudioUnitScope_Input:
550 caacl = &mInputLayout;
552 case kAudioUnitScope_Output:
553 caacl = &mOutputLayout;
556 return kAudioUnitErr_InvalidScope;
560 return kAudioUnitErr_InvalidElement;
566 //_____________________________________________________________________________
568 OSStatus AUPannerBase::SetAudioChannelLayout( AudioUnitScope inScope,
569 AudioUnitElement inElement,
570 const AudioChannelLayout * inLayout)
573 return RemoveAudioChannelLayout(inScope, inElement);
575 if (!ChannelLayoutTagIsSupported(inScope, inElement, inLayout->mChannelLayoutTag))
576 return kAudioUnitErr_FormatNotSupported;
578 CAAudioChannelLayout* caacl = NULL;
579 UInt32 currentChannels;
582 case kAudioUnitScope_Input:
583 caacl = &mInputLayout;
584 currentChannels = GetNumberOfInputChannels();
586 case kAudioUnitScope_Output:
587 caacl = &mOutputLayout;
588 currentChannels = GetNumberOfOutputChannels();
591 return kAudioUnitErr_InvalidScope;
595 return kAudioUnitErr_InvalidElement;
597 UInt32 numChannelsInLayout = CAAudioChannelLayout::NumberChannels(*inLayout);
598 if (currentChannels != numChannelsInLayout)
599 return kAudioUnitErr_InvalidPropertyValue;
603 UpdateBypassMatrix();
608 //_____________________________________________________________________________
610 UInt32 AUPannerBase::GetChannelLayoutTags( AudioUnitScope inScope,
611 AudioUnitElement inElement,
612 AudioChannelLayoutTag* outTags)
616 case kAudioUnitScope_Input:
618 outTags[0] = kAudioChannelLayoutTag_Mono;
619 outTags[1] = kAudioChannelLayoutTag_Stereo;
620 outTags[2] = kAudioChannelLayoutTag_Ambisonic_B_Format;
623 case kAudioUnitScope_Output:
625 outTags[0] = kAudioChannelLayoutTag_Stereo;
626 outTags[1] = kAudioChannelLayoutTag_Quadraphonic;
627 outTags[2] = kAudioChannelLayoutTag_AudioUnit_5_0;
628 outTags[3] = kAudioChannelLayoutTag_AudioUnit_6_0;
629 outTags[4] = kAudioChannelLayoutTag_AudioUnit_7_0;
630 outTags[5] = kAudioChannelLayoutTag_AudioUnit_7_0_Front;
631 outTags[6] = kAudioChannelLayoutTag_AudioUnit_8;
635 OSStatus err = kAudioUnitErr_InvalidScope;
643 //_____________________________________________________________________________
645 bool AUPannerBase::ChannelConfigIsSupported()
647 UInt32 inChannels = GetNumberOfInputChannels();
648 UInt32 outChannels = GetNumberOfOutputChannels();
649 const AUChannelInfo* cinfo = NULL;
650 UInt32 numConfigs = SupportedNumChannels(&cinfo);
651 for (UInt32 i = 0; i < numConfigs; ++i)
653 if (cinfo[i].inChannels == (SInt16)inChannels && cinfo[i].outChannels == (SInt16)outChannels)
660 //_____________________________________________________________________________
662 bool AUPannerBase::InputChannelConfigIsSupported(UInt32 inNumberChannels)
664 const AUChannelInfo* cinfo = NULL;
665 UInt32 numConfigs = SupportedNumChannels(&cinfo);
666 for (UInt32 i = 0; i < numConfigs; ++i)
668 if (cinfo[i].inChannels == (SInt16)inNumberChannels)
674 //_____________________________________________________________________________
676 bool AUPannerBase::OutputChannelConfigIsSupported(UInt32 inNumberChannels)
678 const AUChannelInfo* cinfo = NULL;
679 UInt32 numConfigs = SupportedNumChannels(&cinfo);
680 for (UInt32 i = 0; i < numConfigs; ++i)
682 if (cinfo[i].outChannels == (SInt16)inNumberChannels)
688 //_____________________________________________________________________________
690 bool AUPannerBase::ChannelLayoutTagIsSupported( AudioUnitScope inScope,
691 AudioUnitElement inElement,
692 AudioChannelLayoutTag inTag)
694 UInt32 numTags = GetChannelLayoutTags(inScope, inElement, NULL);
695 CAAutoFree<AudioChannelLayoutTag> tags(numTags);
696 GetChannelLayoutTags(inScope, inElement, tags());
698 for (UInt32 i = 0; i < numTags; ++i)
700 if (tags[i] == inTag)