Jamoma API  0.6.0.a19
CAVolumeCurve.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 //=============================================================================
42 // Includes
43 //=============================================================================
44 
45 #include "CAVolumeCurve.h"
46 #include "CADebugMacros.h"
47 #include <math.h>
48 
49 //=============================================================================
50 // CAVolumeCurve
51 //=============================================================================
52 
53 CAVolumeCurve::CAVolumeCurve()
54 :
55  mTag(0),
56  mCurveMap(),
57  mIsApplyingTransferFunction(true),
58  mTransferFunction(kPow2Over1Curve),
59  mRawToScalarExponentNumerator(2.0),
60  mRawToScalarExponentDenominator(1.0)
61 {
62 }
63 
64 CAVolumeCurve::~CAVolumeCurve()
65 {
66 }
67 
68 SInt32 CAVolumeCurve::GetMinimumRaw() const
69 {
70  SInt32 theAnswer = 0;
71 
72  if(!mCurveMap.empty())
73  {
74  CurveMap::const_iterator theIterator = mCurveMap.begin();
75  theAnswer = theIterator->first.mMinimum;
76  }
77 
78  return theAnswer;
79 }
80 
81 SInt32 CAVolumeCurve::GetMaximumRaw() const
82 {
83  SInt32 theAnswer = 0;
84 
85  if(!mCurveMap.empty())
86  {
87  CurveMap::const_iterator theIterator = mCurveMap.begin();
88  std::advance(theIterator, mCurveMap.size() - 1);
89  theAnswer = theIterator->first.mMaximum;
90  }
91 
92  return theAnswer;
93 }
94 
95 Float64 CAVolumeCurve::GetMinimumDB() const
96 {
97  Float64 theAnswer = 0;
98 
99  if(!mCurveMap.empty())
100  {
101  CurveMap::const_iterator theIterator = mCurveMap.begin();
102  theAnswer = theIterator->second.mMinimum;
103  }
104 
105  return theAnswer;
106 }
107 
108 Float64 CAVolumeCurve::GetMaximumDB() const
109 {
110  Float64 theAnswer = 0;
111 
112  if(!mCurveMap.empty())
113  {
114  CurveMap::const_iterator theIterator = mCurveMap.begin();
115  std::advance(theIterator, mCurveMap.size() - 1);
116  theAnswer = theIterator->second.mMaximum;
117  }
118 
119  return theAnswer;
120 }
121 
122 void CAVolumeCurve::SetTransferFunction(int inTransferFunction)
123 {
124  mTransferFunction = inTransferFunction;
125 
126  // figure out the co-efficients
127  switch(inTransferFunction)
128  {
129  case kLinearCurve:
130  mIsApplyingTransferFunction = false;
131  mRawToScalarExponentNumerator = 1.0;
132  mRawToScalarExponentDenominator = 1.0;
133  break;
134 
135  case kPow1Over3Curve:
136  mIsApplyingTransferFunction = true;
137  mRawToScalarExponentNumerator = 1.0;
138  mRawToScalarExponentDenominator = 3.0;
139  break;
140 
141  case kPow1Over2Curve:
142  mIsApplyingTransferFunction = true;
143  mRawToScalarExponentNumerator = 1.0;
144  mRawToScalarExponentDenominator = 2.0;
145  break;
146 
147  case kPow3Over4Curve:
148  mIsApplyingTransferFunction = true;
149  mRawToScalarExponentNumerator = 3.0;
150  mRawToScalarExponentDenominator = 4.0;
151  break;
152 
153  case kPow3Over2Curve:
154  mIsApplyingTransferFunction = true;
155  mRawToScalarExponentNumerator = 3.0;
156  mRawToScalarExponentDenominator = 2.0;
157  break;
158 
159  case kPow2Over1Curve:
160  mIsApplyingTransferFunction = true;
161  mRawToScalarExponentNumerator = 2.0;
162  mRawToScalarExponentDenominator = 1.0;
163  break;
164 
165  case kPow3Over1Curve:
166  mIsApplyingTransferFunction = true;
167  mRawToScalarExponentNumerator = 3.0;
168  mRawToScalarExponentDenominator = 1.0;
169  break;
170 
171  case kPow4Over1Curve:
172  mIsApplyingTransferFunction = true;
173  mRawToScalarExponentNumerator = 4.0;
174  mRawToScalarExponentDenominator = 1.0;
175  break;
176 
177  case kPow5Over1Curve:
178  mIsApplyingTransferFunction = true;
179  mRawToScalarExponentNumerator = 5.0;
180  mRawToScalarExponentDenominator = 1.0;
181  break;
182 
183  case kPow6Over1Curve:
184  mIsApplyingTransferFunction = true;
185  mRawToScalarExponentNumerator = 6.0;
186  mRawToScalarExponentDenominator = 1.0;
187  break;
188 
189  case kPow7Over1Curve:
190  mIsApplyingTransferFunction = true;
191  mRawToScalarExponentNumerator = 7.0;
192  mRawToScalarExponentDenominator = 1.0;
193  break;
194 
195  case kPow8Over1Curve:
196  mIsApplyingTransferFunction = true;
197  mRawToScalarExponentNumerator = 8.0;
198  mRawToScalarExponentDenominator = 1.0;
199  break;
200 
201  case kPow9Over1Curve:
202  mIsApplyingTransferFunction = true;
203  mRawToScalarExponentNumerator = 9.0;
204  mRawToScalarExponentDenominator = 1.0;
205  break;
206 
207  case kPow10Over1Curve:
208  mIsApplyingTransferFunction = true;
209  mRawToScalarExponentNumerator = 10.0;
210  mRawToScalarExponentDenominator = 1.0;
211  break;
212 
213  case kPow11Over1Curve:
214  mIsApplyingTransferFunction = true;
215  mRawToScalarExponentNumerator = 11.0;
216  mRawToScalarExponentDenominator = 1.0;
217  break;
218 
219  case kPow12Over1Curve:
220  mIsApplyingTransferFunction = true;
221  mRawToScalarExponentNumerator = 12.0;
222  mRawToScalarExponentDenominator = 1.0;
223  break;
224 
225  default:
226  mIsApplyingTransferFunction = true;
227  mRawToScalarExponentNumerator = 2.0;
228  mRawToScalarExponentDenominator = 1.0;
229  break;
230  };
231 }
232 
233 void CAVolumeCurve::AddRange(SInt32 inMinRaw, SInt32 inMaxRaw, Float64 inMinDB, Float64 inMaxDB)
234 {
235  CARawPoint theRaw(inMinRaw, inMaxRaw);
236  CADBPoint theDB(inMinDB, inMaxDB);
237 
238  bool isOverlapped = false;
239  bool isDone = false;
240  CurveMap::iterator theIterator = mCurveMap.begin();
241  while((theIterator != mCurveMap.end()) && !isOverlapped && !isDone)
242  {
243  isOverlapped = CARawPoint::Overlap(theRaw, theIterator->first);
244  isDone = theRaw >= theIterator->first;
245 
246  if(!isOverlapped && !isDone)
247  {
248  std::advance(theIterator, 1);
249  }
250  }
251 
252  if(!isOverlapped)
253  {
254  mCurveMap.insert(CurveMap::value_type(theRaw, theDB));
255  }
256  else
257  {
258  DebugMessage("CAVolumeCurve::AddRange: new point overlaps");
259  }
260 }
261 
262 void CAVolumeCurve::ResetRange()
263 {
264  mCurveMap.clear();
265 }
266 
267 bool CAVolumeCurve::CheckForContinuity() const
268 {
269  bool theAnswer = true;
270 
271  CurveMap::const_iterator theIterator = mCurveMap.begin();
272  if(theIterator != mCurveMap.end())
273  {
274  SInt32 theRaw = theIterator->first.mMinimum;
275  Float64 theDB = theIterator->second.mMinimum;
276  do
277  {
278  SInt32 theRawMin = theIterator->first.mMinimum;
279  SInt32 theRawMax = theIterator->first.mMaximum;
280  SInt32 theRawRange = theRawMax - theRawMin;
281 
282  Float64 theDBMin = theIterator->second.mMinimum;
283  Float64 theDBMax = theIterator->second.mMaximum;
284  Float64 theDBRange = theDBMax - theDBMin;
285 
286  theAnswer = theRaw == theRawMin;
287  theAnswer = theDB == theDBMin;
288 
289  theRaw += theRawRange;
290  theDB += theDBRange;
291 
292  std::advance(theIterator, 1);
293  }
294  while((theIterator != mCurveMap.end()) && theAnswer);
295  }
296 
297  return theAnswer;
298 }
299 
300 SInt32 CAVolumeCurve::ConvertDBToRaw(Float64 inDB) const
301 {
302  // clamp the value to the dB range
303  Float64 theOverallDBMin = GetMinimumDB();
304  Float64 theOverallDBMax = GetMaximumDB();
305 
306  if(inDB < theOverallDBMin) inDB = theOverallDBMin;
307  if(inDB > theOverallDBMax) inDB = theOverallDBMax;
308 
309  // get the first entry in the curve map;
310  CurveMap::const_iterator theIterator = mCurveMap.begin();
311 
312  // initialize the answer to the minimum raw of the first item in the curve map
313  SInt32 theAnswer = theIterator->first.mMinimum;
314 
315  // iterate through the curve map until we run out of dB
316  bool isDone = false;
317  while(!isDone && (theIterator != mCurveMap.end()))
318  {
319  SInt32 theRawMin = theIterator->first.mMinimum;
320  SInt32 theRawMax = theIterator->first.mMaximum;
321  SInt32 theRawRange = theRawMax - theRawMin;
322 
323  Float64 theDBMin = theIterator->second.mMinimum;
324  Float64 theDBMax = theIterator->second.mMaximum;
325  Float64 theDBRange = theDBMax - theDBMin;
326 
327  Float64 theDBPerRaw = theDBRange / static_cast<Float64>(theRawRange);
328 
329  // figure out how many steps we are into this entry in the curve map
330  if(inDB > theDBMax)
331  {
332  // we're past the end of this one, so add in the whole range for this entry
333  theAnswer += theRawRange;
334  }
335  else
336  {
337  // it's somewhere within the current entry
338  // figure out how many steps it is
339  Float64 theNumberRawSteps = inDB - theDBMin;
340  theNumberRawSteps /= theDBPerRaw;
341 
342  // only move in whole steps
343  theNumberRawSteps = round(theNumberRawSteps);
344 
345  // add this many steps to the answer
346  theAnswer += static_cast<SInt32>(theNumberRawSteps);
347 
348  // mark that we are done
349  isDone = true;
350  }
351 
352  // go to the next entry in the curve map
353  std::advance(theIterator, 1);
354  }
355 
356  return theAnswer;
357 }
358 
359 Float64 CAVolumeCurve::ConvertRawToDB(SInt32 inRaw) const
360 {
361  Float64 theAnswer = 0;
362 
363  // clamp the raw value
364  SInt32 theOverallRawMin = GetMinimumRaw();
365  SInt32 theOverallRawMax = GetMaximumRaw();
366 
367  if(inRaw < theOverallRawMin) inRaw = theOverallRawMin;
368  if(inRaw > theOverallRawMax) inRaw = theOverallRawMax;
369 
370  // figure out how many raw steps need to be taken from the first one
371  SInt32 theNumberRawSteps = inRaw - theOverallRawMin;
372 
373  // get the first item in the curve map
374  CurveMap::const_iterator theIterator = mCurveMap.begin();
375 
376  // initialize the answer to the minimum dB of the first item in the curve map
377  theAnswer = theIterator->second.mMinimum;
378 
379  // iterate through the curve map until we run out of steps
380  while((theNumberRawSteps > 0) && (theIterator != mCurveMap.end()))
381  {
382  // compute some values
383  SInt32 theRawMin = theIterator->first.mMinimum;
384  SInt32 theRawMax = theIterator->first.mMaximum;
385  SInt32 theRawRange = theRawMax - theRawMin;
386 
387  Float64 theDBMin = theIterator->second.mMinimum;
388  Float64 theDBMax = theIterator->second.mMaximum;
389  Float64 theDBRange = theDBMax - theDBMin;
390 
391  Float64 theDBPerRaw = theDBRange / static_cast<Float64>(theRawRange);
392 
393  // there might be more steps than the current map entry accounts for
394  SInt32 theRawStepsToAdd = std::min(theRawRange, theNumberRawSteps);
395 
396  // add this many steps worth of db to the answer;
397  theAnswer += theRawStepsToAdd * theDBPerRaw;
398 
399  // figure out how many steps are left
400  theNumberRawSteps -= theRawStepsToAdd;
401 
402  // go to the next map entry
403  std::advance(theIterator, 1);
404  }
405 
406  return theAnswer;
407 }
408 
409 Float64 CAVolumeCurve::ConvertRawToScalar(SInt32 inRaw) const
410 {
411  // get some important values
412  Float64 theDBMin = GetMinimumDB();
413  Float64 theDBMax = GetMaximumDB();
414  Float64 theDBRange = theDBMax - theDBMin;
415  SInt32 theRawMin = GetMinimumRaw();
416  SInt32 theRawMax = GetMaximumRaw();
417  SInt32 theRawRange = theRawMax - theRawMin;
418 
419  // range the raw value
420  if(inRaw < theRawMin) inRaw = theRawMin;
421  if(inRaw > theRawMax) inRaw = theRawMax;
422 
423  // calculate the distance in the range inRaw is
424  Float64 theAnswer = static_cast<Float64>(inRaw - theRawMin) / static_cast<Float64>(theRawRange);
425 
426  // only apply a curve to the scalar values if the dB range is greater than 30
427  if(mIsApplyingTransferFunction && (theDBRange > 30.0))
428  {
429  theAnswer = pow(theAnswer, mRawToScalarExponentNumerator / mRawToScalarExponentDenominator);
430  }
431 
432  return theAnswer;
433 }
434 
435 Float64 CAVolumeCurve::ConvertDBToScalar(Float64 inDB) const
436 {
437  SInt32 theRawValue = ConvertDBToRaw(inDB);
438  Float64 theAnswer = ConvertRawToScalar(theRawValue);
439  return theAnswer;
440 }
441 
442 SInt32 CAVolumeCurve::ConvertScalarToRaw(Float64 inScalar) const
443 {
444  // range the scalar value
445  inScalar = std::min(1.0, std::max(0.0, inScalar));
446 
447  // get some important values
448  Float64 theDBMin = GetMinimumDB();
449  Float64 theDBMax = GetMaximumDB();
450  Float64 theDBRange = theDBMax - theDBMin;
451  SInt32 theRawMin = GetMinimumRaw();
452  SInt32 theRawMax = GetMaximumRaw();
453  SInt32 theRawRange = theRawMax - theRawMin;
454 
455  // have to undo the curve if the dB range is greater than 30
456  if(mIsApplyingTransferFunction && (theDBRange > 30.0))
457  {
458  inScalar = pow(inScalar, mRawToScalarExponentDenominator / mRawToScalarExponentNumerator);
459  }
460 
461  // now we can figure out how many raw steps this is
462  Float64 theNumberRawSteps = inScalar * static_cast<Float64>(theRawRange);
463  theNumberRawSteps = round(theNumberRawSteps);
464 
465  // the answer is the minimum raw value plus the number of raw steps
466  SInt32 theAnswer = theRawMin + static_cast<SInt32>(theNumberRawSteps);
467 
468  return theAnswer;
469 }
470 
471 Float64 CAVolumeCurve::ConvertScalarToDB(Float64 inScalar) const
472 {
473  SInt32 theRawValue = ConvertScalarToRaw(inScalar);
474  Float64 theAnswer = ConvertRawToDB(theRawValue);
475  return theAnswer;
476 }