Jamoma API  0.6.0.a19
CAAUParameter.cpp
1 /* Copyright © 2007 Apple Inc. All Rights Reserved.
2 
3  Disclaimer: IMPORTANT: This Apple software is supplied to you by
4  Apple Inc. ("Apple") in consideration of your agreement to the
5  following terms, and your use, installation, modification or
6  redistribution of this Apple software constitutes acceptance of these
7  terms. If you do not agree with these terms, please do not use,
8  install, modify or redistribute this Apple software.
9 
10  In consideration of your agreement to abide by the following terms, and
11  subject to these terms, Apple grants you a personal, non-exclusive
12  license, under Apple's copyrights in this original Apple software (the
13  "Apple Software"), to use, reproduce, modify and redistribute the Apple
14  Software, with or without modifications, in source and/or binary forms;
15  provided that if you redistribute the Apple Software in its entirety and
16  without modifications, you must retain this notice and the following
17  text and disclaimers in all such redistributions of the Apple Software.
18  Neither the name, trademarks, service marks or logos of Apple Inc.
19  may be used to endorse or promote products derived from the Apple
20  Software without specific prior written permission from Apple. Except
21  as expressly stated in this notice, no other rights or licenses, express
22  or implied, are granted by Apple herein, including but not limited to
23  any patent rights that may be infringed by your derivative works or by
24  other works in which the Apple Software may be incorporated.
25 
26  The Apple Software is provided by Apple on an "AS IS" basis. APPLE
27  MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
28  THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
29  FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
30  OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
31 
32  IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
33  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
36  MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
37  AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
38  STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
39  POSSIBILITY OF SUCH DAMAGE.
40 */
41 #include "CAAUParameter.h"
42 
43 CAAUParameter::CAAUParameter()
44 {
45  memset(this, 0, sizeof(CAAUParameter));
46 }
47 
48 CAAUParameter::CAAUParameter(AudioUnit au, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement element)
49 {
50  memset(this, 0, sizeof(CAAUParameter));
51  Init (au, param, scope, element);
52 }
53 
54 CAAUParameter::CAAUParameter (AudioUnitParameter &inParam)
55 {
56  memset(this, 0, sizeof(CAAUParameter));
57  Init (inParam.mAudioUnit, inParam.mParameterID, inParam.mScope, inParam.mElement);
58 }
59 
60 CAAUParameter::CAAUParameter(const CAAUParameter &a)
61 {
62  memset(this, 0, sizeof(CAAUParameter));
63  *this = a;
64 }
65 
66 CAAUParameter & CAAUParameter::operator = (const CAAUParameter &a)
67 {
68  if (mParamName) CFRelease(mParamName);
69  if (mParamTag) CFRelease(mParamTag);
70  if (mNamedParams) CFRelease(mNamedParams);
71 
72  memcpy(this, &a, sizeof(CAAUParameter));
73 
74  if (mParamName) CFRetain(mParamName);
75  if (mParamTag) CFRetain(mParamTag);
76  if (mNamedParams) CFRetain(mNamedParams);
77 
78  return *this;
79 }
80 
81 CAAUParameter::~CAAUParameter()
82 {
83  if (mParamName) CFRelease(mParamName);
84  if (mParamTag) CFRelease(mParamTag);
85  if (mNamedParams) CFRelease (mNamedParams);
86 }
87 
88 void CAAUParameter::Init (AudioUnit au, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement element)
89 {
90  mAudioUnit = au;
91  mParameterID = param;
92  mScope = scope;
93  mElement = element;
94 
95  UInt32 propertySize = sizeof(mParamInfo);
96  OSStatus err = AudioUnitGetProperty(au, kAudioUnitProperty_ParameterInfo,
97  scope, param, &mParamInfo, &propertySize);
98  if (err)
99  memset(&mParamInfo, 0, sizeof(mParamInfo));
100  if (mParamInfo.flags & kAudioUnitParameterFlag_HasCFNameString) {
101  mParamName = mParamInfo.cfNameString;
102  if (!(mParamInfo.flags & kAudioUnitParameterFlag_CFNameRelease))
103  CFRetain (mParamName);
104  } else
105  mParamName = CFStringCreateWithCString(NULL, mParamInfo.name, kCFStringEncodingUTF8);
106 
107  const char* str = 0;
108  switch (mParamInfo.unit)
109  {
110  case kAudioUnitParameterUnit_Boolean:
111  str = "T/F";
112  break;
113  case kAudioUnitParameterUnit_Percent:
114  case kAudioUnitParameterUnit_EqualPowerCrossfade:
115  str = "%";
116  break;
117  case kAudioUnitParameterUnit_Seconds:
118  str = "Secs";
119  break;
120  case kAudioUnitParameterUnit_SampleFrames:
121  str = "Samps";
122  break;
123  case kAudioUnitParameterUnit_Phase:
124  case kAudioUnitParameterUnit_Degrees:
125  str = "Degr.";
126  break;
127  case kAudioUnitParameterUnit_Hertz:
128  str = "Hz";
129  break;
130  case kAudioUnitParameterUnit_Cents:
131  case kAudioUnitParameterUnit_AbsoluteCents:
132  str = "Cents";
133  break;
134  case kAudioUnitParameterUnit_RelativeSemiTones:
135  str = "S-T";
136  break;
137  case kAudioUnitParameterUnit_MIDINoteNumber:
138  case kAudioUnitParameterUnit_MIDIController:
139  str = "MIDI";
140  //these are inclusive, so add one value here
141  mNumIndexedParams = short(mParamInfo.maxValue+1 - mParamInfo.minValue);
142  break;
143  case kAudioUnitParameterUnit_Decibels:
144  str = "dB";
145  break;
146  case kAudioUnitParameterUnit_MixerFaderCurve1:
147  case kAudioUnitParameterUnit_LinearGain:
148  str = "Gain";
149  break;
150  case kAudioUnitParameterUnit_Pan:
151  str = "L/R";
152  break;
153  case kAudioUnitParameterUnit_Meters:
154  str = "Mtrs";
155  break;
156  case kAudioUnitParameterUnit_Octaves:
157  str = "8ve";
158  break;
159  case kAudioUnitParameterUnit_BPM:
160  str = "BPM";
161  break;
162  case kAudioUnitParameterUnit_Beats:
163  str = "Beats";
164  break;
165  case kAudioUnitParameterUnit_Milliseconds:
166  str = "msecs";
167  break;
168  case kAudioUnitParameterUnit_Ratio:
169  str = "Ratio";
170  break;
171  case kAudioUnitParameterUnit_Indexed:
172  {
173  propertySize = sizeof(mNamedParams);
174  err = AudioUnitGetProperty (au,
175  kAudioUnitProperty_ParameterValueStrings,
176  scope,
177  param,
178  &mNamedParams,
179  &propertySize);
180  if (!err && mNamedParams) {
181  mNumIndexedParams = CFArrayGetCount(mNamedParams);
182  } else {
183  //these are inclusive, so add one value here
184  mNumIndexedParams = short(mParamInfo.maxValue+1 - mParamInfo.minValue);
185  }
186  str = NULL;
187  }
188  break;
189  case kAudioUnitParameterUnit_CustomUnit:
190  {
191  CFStringRef unitName = mParamInfo.unitName;
192  static char paramStr[256];
193  CFStringGetCString (unitName, paramStr, 256, kCFStringEncodingUTF8);
194  if (mParamInfo.flags & kAudioUnitParameterFlag_CFNameRelease)
195  CFRelease (unitName);
196  str = paramStr;
197  break;
198  }
199  case kAudioUnitParameterUnit_Generic:
200  case kAudioUnitParameterUnit_Rate:
201  default:
202  str = NULL;
203  break;
204  }
205 
206  if (str)
207  mParamTag = CFStringCreateWithCString(NULL, str, kCFStringEncodingUTF8);
208  else
209  mParamTag = NULL;
210 }
211 
212 
213 Float32 CAAUParameter::GetValue() const
214 {
215  Float32 value = 0.;
216  //OSStatus err =
217  AudioUnitGetParameter(mAudioUnit, mParameterID, mScope, mElement, &value);
218  return value;
219 }
220 
221 CFStringRef CreateLocalizedStringForParameterValue ( double inParameterValue,
222  const CAAUParameter * inParameter,
223  UInt32 inDigits,
224  UInt32 minDigits) {
225  if (!inParameter) return nil;
226 
227  AudioUnitParameterInfo info = inParameter->ParamInfo();
228  int pow10;
229 
230  switch (info.unit) {
231  case kAudioUnitParameterUnit_Hertz:
232  // number of significant digits based on value
233  pow10 = int(log10(fmax(inParameterValue, .000001)));
234  break;
235  default:
236  // number of significant digits based on parameter range
237  pow10 = int(log10(fmax(double(info.maxValue - info.minValue), .000001)));
238  break;
239  }
240 
241  // pow10 range nDigitsAfterDecimal
242  // -2 .0100-.0999 4
243  // -1 .100-.999 3
244  // 0 1.00-9.99 2
245  // 1 10.0-99.9 1
246  // 2 100-999 0
247  // 3 1000-9990 -1
248  // 4 10000-99900 -2
249 
250  int nDigitsAfterDecimal = inDigits - (pow10 + 1);
251  if (nDigitsAfterDecimal < 0)
252  nDigitsAfterDecimal = 0; // the least number of digits possible is zero
253 
254  if (info.flags & kAudioUnitParameterFlag_IsHighResolution)
255  nDigitsAfterDecimal = 4;
256 
257  CFLocaleRef currentLocale = CFLocaleCopyCurrent();
258  CFNumberFormatterRef numberFormatter = CFNumberFormatterCreate (NULL, currentLocale, kCFNumberFormatterDecimalStyle);
259 
260  CFNumberRef maxFractionDigits = CFNumberCreate (NULL, kCFNumberIntType, &nDigitsAfterDecimal);
261 
262  if (nDigitsAfterDecimal > 0)
263  nDigitsAfterDecimal = minDigits;
264 
265  CFNumberRef minFractionDigits = CFNumberCreate (NULL, kCFNumberIntType, &nDigitsAfterDecimal);
266 
267  CFNumberFormatterSetProperty (numberFormatter, kCFNumberFormatterMinFractionDigits, minFractionDigits);
268  CFNumberFormatterSetProperty (numberFormatter, kCFNumberFormatterMaxFractionDigits, maxFractionDigits);
269  CFStringRef formattedNumberString = CFNumberFormatterCreateStringWithValue (NULL, numberFormatter, kCFNumberDoubleType, &inParameterValue);
270 
271  CFRelease(currentLocale);
272  CFRelease(numberFormatter);
273  CFRelease(maxFractionDigits);
274  CFRelease(minFractionDigits);
275 
276  return formattedNumberString;
277 }
278 
279 CFStringRef CreateLocalizedStringForParameterValue ( double inParameterValue,
280  const CAAUParameter * inParameter,
281  UInt32 inDigits) {
282  return CreateLocalizedStringForParameterValue (inParameterValue, inParameter, inDigits, 1);
283 }
284 
285 double ValueForLocalizedParameterString (CFStringRef string, const CAAUParameter * inParameter) {
286  CFLocaleRef currentLocale = CFLocaleCopyCurrent();
287  CFNumberFormatterRef numberFormatter = CFNumberFormatterCreate (NULL, currentLocale, kCFNumberFormatterDecimalStyle);
288 
289  double value = 0;
290  Boolean worked = CFNumberFormatterGetValueFromString (numberFormatter, string, NULL, kCFNumberDoubleType, &value);
291 
292  CFRelease(currentLocale);
293  CFRelease(numberFormatter);
294 
295  if (worked)
296  return value;
297  else {
298  AudioUnitParameterInfo info = inParameter->ParamInfo();
299  return info.defaultValue;
300  }
301 }
302 
303 CFStringRef CAAUParameter::GetStringFromValueCopy(const Float32 *value) const
304 {
305  if (HasNamedParams())
306  {
307  Float32 val = (value == NULL ? GetValue() : *value);
308  int index = int(mParamInfo.minValue) + int(val);
309  CFStringRef str = GetParamName (index);
310  if (str) {
311  CFRetain (str);
312  return str;
313  }
314  }
315  else if (ValuesHaveStrings())
316  {
317  AudioUnitParameterStringFromValue stringValue;
318  stringValue.inParamID = mParameterID;
319  stringValue.inValue = value;
320  stringValue.outString = NULL;
321  UInt32 propertySize = sizeof(stringValue);
322 
323  OSStatus err = AudioUnitGetProperty (mAudioUnit,
324  kAudioUnitProperty_ParameterStringFromValue,
325  mScope,
326  mParameterID,
327  &stringValue,
328  &propertySize);
329 
330  if (!err && stringValue.outString != NULL)
331  return stringValue.outString;
332  }
333 
334  Float32 val = (value == NULL ? GetValue() : *value);
335  AudioUnitParameterUnit unit = this->ParamInfo().unit;
336  if (unit == kAudioUnitParameterUnit_Cents || unit == kAudioUnitParameterUnit_AbsoluteCents)
337  return CreateLocalizedStringForParameterValue(val, this, 4, 0);
338  else
339  return CreateLocalizedStringForParameterValue(val, this, 4);
340 }
341 
342 Float32 CAAUParameter::GetValueFromString(CFStringRef str) const
343 {
344  if (ValuesHaveStrings())
345  {
346  AudioUnitParameterValueFromString valueString;
347  valueString.inParamID = mParameterID;
348  valueString.inString = str;
349  UInt32 propertySize = sizeof(valueString);
350 
351  OSStatus err = AudioUnitGetProperty (mAudioUnit,
352  kAudioUnitProperty_ParameterValueFromString,
353  mScope,
354  mParameterID,
355  &valueString,
356  &propertySize);
357 
358  if (!err) {
359  return valueString.outValue;
360  }
361  }
362 
363  return (Float32) ValueForLocalizedParameterString(str, this);
364 }
365 
366 void CAAUParameter::SetValue( AUParameterListenerRef inListener,
367  void * inObject,
368  Float32 inValue) const
369 {
370  // clip inValue as: maxValue >= inValue >= minValue before setting
371  Float32 valueToSet = inValue;
372  if (valueToSet > mParamInfo.maxValue)
373  valueToSet = mParamInfo.maxValue;
374  if (valueToSet < mParamInfo.minValue)
375  valueToSet = mParamInfo.minValue;
376 
377  AUParameterSet(inListener, inObject, this, valueToSet, 0);
378 }
379 
380 #if DEBUG
381 void CAAUParameter::Print() const
382 {
383  UInt32 clump = 0;
384  GetClumpID (clump);
385 
386  UInt32 len = CFStringGetLength(mParamName);
387  char* chars = (char*)malloc (len * 2); // give us plenty of room for unichar chars
388  if (!CFStringGetCString (mParamName, chars, len * 2, kCFStringEncodingUTF8))
389  chars[0] = 0;
390 
391  printf ("ID: %ld, Clump: %u, Name: %s\n", (long unsigned int) mParameterID, (unsigned int) clump, chars);
392  free (chars);
393 }
394 #endif