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