1 /* Copyright © 2007 Apple Inc. All Rights Reserved.
3 Disclaimer: IMPORTANT: This Apple software is supplied to you by
4 Apple Inc. ("Apple") in consideration of your agreement to the
5 following terms, and your use, installation, modification or
6 redistribution of this Apple software constitutes acceptance of these
7 terms. If you do not agree with these terms, please do not use,
8 install, modify or redistribute this Apple software.
10 In consideration of your agreement to abide by the following terms, and
11 subject to these terms, Apple grants you a personal, non-exclusive
12 license, under Apple's copyrights in this original Apple software (the
13 "Apple Software"), to use, reproduce, modify and redistribute the Apple
14 Software, with or without modifications, in source and/or binary forms;
15 provided that if you redistribute the Apple Software in its entirety and
16 without modifications, you must retain this notice and the following
17 text and disclaimers in all such redistributions of the Apple Software.
18 Neither the name, trademarks, service marks or logos of Apple Inc.
19 may be used to endorse or promote products derived from the Apple
20 Software without specific prior written permission from Apple. Except
21 as expressly stated in this notice, no other rights or licenses, express
22 or implied, are granted by Apple herein, including but not limited to
23 any patent rights that may be infringed by your derivative works or by
24 other works in which the Apple Software may be incorporated.
26 The Apple Software is provided by Apple on an "AS IS" basis. APPLE
27 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
28 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
29 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
30 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
32 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
33 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
36 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
37 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
38 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
39 POSSIBILITY OF SUCH DAMAGE.
41 /*=============================================================================
44 =============================================================================*/
46 #include "AUScopeElement.h"
48 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
49 #include <CoreServices/CoreServices.h>
54 //_____________________________________________________________________________
56 // By default, parameterIDs may be arbitrarily spaced, and an STL map
57 // will be used for access. Calling UseIndexedParameters() will
58 // instead use an STL vector for faster indexed access.
59 // This assumes the paramIDs are numbered 0.....inNumberOfParameters-1
60 // Call this before defining/adding any parameters with SetParameter()
62 void AUElement::UseIndexedParameters(int inNumberOfParameters
)
64 mIndexedParameters
.resize (inNumberOfParameters
);
65 mUseIndexedParameters
= true;
68 //_____________________________________________________________________________
71 // returns the ParameterMapEvent object associated with the paramID
73 inline ParameterMapEvent
& AUElement::GetParamEvent(AudioUnitParameterID paramID
)
75 ParameterMapEvent
*event
;
77 if(mUseIndexedParameters
)
79 if(paramID
>= mIndexedParameters
.size() )
80 COMPONENT_THROW(kAudioUnitErr_InvalidParameter
);
82 event
= &mIndexedParameters
[paramID
];
86 ParameterMap::iterator i
= mParameters
.find(paramID
);
87 if (i
== mParameters
.end())
88 COMPONENT_THROW(kAudioUnitErr_InvalidParameter
);
96 //_____________________________________________________________________________
98 // caller assumes that this is actually an immediate parameter
100 AudioUnitParameterValue
AUElement::GetParameter(AudioUnitParameterID paramID
)
102 ParameterMapEvent
&event
= GetParamEvent(paramID
);
104 return event
.GetValue();
108 //_____________________________________________________________________________
110 void AUElement::GetRampSliceStartEnd( AudioUnitParameterID paramID
,
111 AudioUnitParameterValue
& outStartValue
,
112 AudioUnitParameterValue
& outEndValue
,
113 AudioUnitParameterValue
& outValuePerFrameDelta
)
116 ParameterMapEvent
&event
= GetParamEvent(paramID
);
118 // works even if the value is constant (immediate parameter value)
119 event
.GetRampSliceStartEnd(outStartValue
, outEndValue
, outValuePerFrameDelta
);
122 //_____________________________________________________________________________
124 void AUElement::SetParameter(AudioUnitParameterID paramID
, AudioUnitParameterValue inValue
)
126 if(mUseIndexedParameters
)
128 ParameterMapEvent
&event
= GetParamEvent(paramID
);
129 event
.SetValue(inValue
);
133 ParameterMap::iterator i
= mParameters
.find(paramID
);
135 if (i
== mParameters
.end())
137 // create new entry in map for the paramID (only happens first time)
138 ParameterMapEvent
event(inValue
);
139 mParameters
[paramID
] = event
;
143 // paramID already exists in map so simply change its value
144 ParameterMapEvent
&event
= (*i
).second
;
145 event
.SetValue(inValue
);
150 //_____________________________________________________________________________
152 void AUElement::SetScheduledEvent( AudioUnitParameterID paramID
,
153 const AudioUnitParameterEvent
&inEvent
,
154 UInt32 inSliceOffsetInBuffer
,
155 UInt32 inSliceDurationFrames
)
157 if(mUseIndexedParameters
)
159 ParameterMapEvent
&event
= GetParamEvent(paramID
);
160 event
.SetScheduledEvent(inEvent
, inSliceOffsetInBuffer
, inSliceDurationFrames
);
164 ParameterMap::iterator i
= mParameters
.find(paramID
);
166 if (i
== mParameters
.end())
168 // create new entry in map for the paramID (only happens first time)
169 ParameterMapEvent
event(inEvent
, inSliceOffsetInBuffer
, inSliceDurationFrames
);
170 mParameters
[paramID
] = event
;
174 // paramID already exists in map so simply change its value
175 ParameterMapEvent
&event
= (*i
).second
;
177 event
.SetScheduledEvent(inEvent
, inSliceOffsetInBuffer
, inSliceDurationFrames
);
184 //_____________________________________________________________________________
186 void AUElement::GetParameterList(AudioUnitParameterID
*outList
)
188 if(mUseIndexedParameters
)
190 UInt32 nparams
= mIndexedParameters
.size();
191 for (UInt32 i
= 0; i
< nparams
; i
++ )
192 *outList
++ = (AudioUnitParameterID
)i
;
196 for (ParameterMap::iterator i
= mParameters
.begin(); i
!= mParameters
.end(); ++i
)
197 *outList
++ = (*i
).first
;
201 //_____________________________________________________________________________
203 void AUElement::SaveState(CFMutableDataRef data
)
205 if(mUseIndexedParameters
)
207 UInt32 nparams
= mIndexedParameters
.size();
208 UInt32 theData
= CFSwapInt32HostToBig(nparams
);
209 CFDataAppendBytes(data
, (UInt8
*)&theData
, sizeof(nparams
));
211 for (UInt32 i
= 0; i
< nparams
; i
++)
215 //CFSwappedFloat32 value; crashes gcc3 PFE
216 UInt32 value
; // really a big-endian float
219 entry
.paramID
= CFSwapInt32HostToBig(i
);
221 AudioUnitParameterValue v
= mIndexedParameters
[i
].GetValue();
222 entry
.value
= CFSwapInt32HostToBig(*(UInt32
*)&v
);
224 CFDataAppendBytes(data
, (UInt8
*)&entry
, sizeof(entry
));
229 UInt32 nparams
= CFSwapInt32HostToBig(mParameters
.size());
230 CFDataAppendBytes(data
, (UInt8
*)&nparams
, sizeof(nparams
));
232 for (ParameterMap::iterator i
= mParameters
.begin(); i
!= mParameters
.end(); ++i
) {
235 //CFSwappedFloat32 value; crashes gcc3 PFE
236 UInt32 value
; // really a big-endian float
239 entry
.paramID
= CFSwapInt32HostToBig((*i
).first
);
241 AudioUnitParameterValue v
= (*i
).second
.GetValue();
242 entry
.value
= CFSwapInt32HostToBig(*(UInt32
*)&v
);
244 CFDataAppendBytes(data
, (UInt8
*)&entry
, sizeof(entry
));
249 //_____________________________________________________________________________
251 const UInt8
* AUElement::RestoreState(const UInt8
*state
)
253 union FloatInt32
{ UInt32 i
; AudioUnitParameterValue f
; };
254 const UInt8
*p
= state
;
255 UInt32 nparams
= CFSwapInt32BigToHost(*(UInt32
*)p
);
258 for (UInt32 i
= 0; i
< nparams
; ++i
) {
260 AudioUnitParameterID paramID
;
261 AudioUnitParameterValue value
;
264 entry
.paramID
= CFSwapInt32BigToHost(*(UInt32
*)p
);
267 temp
.i
= CFSwapInt32BigToHost(*(UInt32
*)p
);
268 entry
.value
= temp
.f
;
269 p
+= sizeof(AudioUnitParameterValue
);
271 SetParameter(entry
.paramID
, entry
.value
);
276 //_____________________________________________________________________________
278 void AUElement::SetName (CFStringRef inName
)
280 if (mElementName
) CFRelease (mElementName
);
281 mElementName
= inName
;
282 if (mElementName
) CFRetain (mElementName
);
286 //_____________________________________________________________________________
288 AUIOElement::AUIOElement(AUBase
*audioUnit
) :
291 mStreamFormat
.SetCanonical(2, // stereo
292 audioUnit
->AudioUnitAPIVersion() == 1);
293 // interleaved if API version 1, deinterleaved if version 2
294 mStreamFormat
.mSampleRate
= kAUDefaultSampleRate
;
297 //_____________________________________________________________________________
299 OSStatus
AUIOElement::SetStreamFormat(const CAStreamBasicDescription
&desc
)
301 mStreamFormat
= desc
;
305 //_____________________________________________________________________________
306 // inFramesToAllocate == 0 implies the AudioUnit's max-frames-per-slice will be used
307 void AUIOElement::AllocateBuffer(UInt32 inFramesToAllocate
)
309 if (GetAudioUnit()->IsInitialized())
311 UInt32 framesToAllocate
= inFramesToAllocate
> 0 ? inFramesToAllocate
: GetAudioUnit()->GetMaxFramesPerSlice();
313 mIOBuffer
.Allocate(mStreamFormat
, NeedsBufferSpace() ? framesToAllocate
: 0);
317 //_____________________________________________________________________________
319 void AUIOElement::DeallocateBuffer()
321 mIOBuffer
.Deallocate();
324 //_____________________________________________________________________________
326 // AudioChannelLayout support
328 // outLayoutTagsPtr WILL be NULL if called to find out how many
329 // layouts that Audio Unit will report
330 // return 0 (ie. NO channel layouts) if the AU doesn't require channel layout knowledge
331 UInt32
AUIOElement::GetChannelLayoutTags (AudioChannelLayoutTag
*outLayoutTagsPtr
)
336 // As the AudioChannelLayout can be a variable length structure
337 // (though in most cases it won't be!!!)
338 // the AU should return the address of the current ACM in use (in outMapPtr) AND if it is writable
339 // The size of the ACM is returned by the method
340 // If the AU doesn't require an AudioChannelLayout, then just return 0.
341 UInt32
AUIOElement::GetAudioChannelLayout (AudioChannelLayout
*outMapPtr
,
342 Boolean
&outWritable
)
347 // the incoming channel map will be at least as big as a basic AudioChannelLayout
348 // but its contents will determine its actual size
349 // Subclass should overide if channel map is writable
350 OSStatus
AUIOElement::SetAudioChannelLayout (const AudioChannelLayout
&inData
)
352 return kAudioUnitErr_InvalidProperty
;
355 // Some units support optional usage of channel maps - typically converter units
356 // that can do channel remapping between different maps. In that optional case
357 // the user should be able to remove a channel map if that is possible.
358 // Typically this is NOT the case (e.g., the 3DMixer even in the stereo case
359 // needs to know if it is rendering to speakers or headphones)
360 OSStatus
AUIOElement::RemoveAudioChannelLayout ()
362 return kAudioUnitErr_InvalidPropertyValue
;
366 //_____________________________________________________________________________
370 for (ElementVector::iterator it
= mElements
.begin(); it
!= mElements
.end(); ++it
)
374 //_____________________________________________________________________________
376 void AUScope::SetNumberOfElements(UInt32 numElements
)
379 return mDelegate
->SetNumberOfElements(numElements
);
381 if (numElements
> mElements
.size()) {
382 mElements
.reserve(numElements
);
383 while (numElements
> mElements
.size()) {
384 AUElement
*elem
= GetCreator()->CreateElement(GetScope(), mElements
.size());
385 mElements
.push_back(elem
);
388 while (numElements
< mElements
.size()) {
389 AUElement
*elem
= mElements
.back();
390 mElements
.pop_back();
395 //_____________________________________________________________________________
397 bool AUScope::HasElementWithName () const
399 for (UInt32 i
= 0; i
< GetNumberOfElements(); ++i
) {
400 AUElement
* el
= const_cast<AUScope
*>(this)->GetElement (i
);
401 if (el
&& el
->HasName()) {
408 //_____________________________________________________________________________
411 void AUScope::AddElementNamesToDict (CFMutableDictionaryRef
& inNameDict
)
413 if (HasElementWithName())
415 static char string
[32];
416 CFMutableDictionaryRef elementDict
= CFDictionaryCreateMutable (NULL
, 0,
417 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
419 for (UInt32 i
= 0; i
< GetNumberOfElements(); ++i
) {
420 AUElement
* el
= GetElement (i
);
421 if (el
&& el
->HasName()) {
422 sprintf (string
, "%d", int(i
));
423 str
= CFStringCreateWithCString (NULL
, string
, kCFStringEncodingASCII
);
424 CFDictionarySetValue (elementDict
, str
, el
->GetName());
429 sprintf (string
, "%d", int(mScope
));
430 str
= CFStringCreateWithCString (NULL
, string
, kCFStringEncodingASCII
);
431 CFDictionarySetValue (inNameDict
, str
, elementDict
);
433 CFRelease (elementDict
);
437 //_____________________________________________________________________________
439 bool AUScope::RestoreElementNames (CFDictionaryRef
& inNameDict
)
441 static char string
[32];
443 //first we have to see if we have enough elements and if not create them
444 bool didAddElements
= false;
445 unsigned int maxElNum
= 0;
447 int dictSize
= CFDictionaryGetCount(inNameDict
);
448 CFStringRef
* keys
= (CFStringRef
*)malloc (dictSize
* sizeof (CFStringRef
));
449 CFDictionaryGetKeysAndValues (inNameDict
, reinterpret_cast<const void**>(keys
), NULL
);
450 for (int i
= 0; i
< dictSize
; i
++)
453 CFStringGetCString (keys
[i
], string
, 32, kCFStringEncodingASCII
);
454 sscanf (string
, "%d", &intKey
);
455 if (UInt32(intKey
) > maxElNum
)
459 if (maxElNum
>= GetNumberOfElements()) {
460 SetNumberOfElements (maxElNum
+1);
461 didAddElements
= true;
464 // OK, now we have the number of elements that we need - lets restate their names
465 for (int i
= 0; i
< dictSize
; i
++)
467 CFStringRef elName
= reinterpret_cast<CFStringRef
>(CFDictionaryGetValue (inNameDict
, keys
[i
]));
469 CFStringGetCString (keys
[i
], string
, 32, kCFStringEncodingASCII
);
470 sscanf (string
, "%d", &intKey
);
471 GetElement (intKey
)->SetName (elName
);
475 return didAddElements
;