Overte C++ Documentation
AudioHelpers.h
1 //
2 // AudioHelpers.h
3 // libraries/shared/src
4 //
5 // Created by Ken Cooke on 1/4/17.
6 // Copyright 2017 High Fidelity, Inc.
7 //
8 // Distributed under the Apache License, Version 2.0.
9 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10 //
11 
12 #ifndef hifi_AudioHelpers_h
13 #define hifi_AudioHelpers_h
14 
15 #include <stdint.h>
16 
17 #include <NumericalConstants.h>
18 #include <cmath>
19 
20 const int IEEE754_MANT_BITS = 23;
21 const int IEEE754_EXPN_BIAS = 127;
22 
23 //
24 // for x > 0.0f, returns log2(x)
25 // for x <= 0.0f, returns large negative value
26 //
27 // abs |error| < 2e-4, smooth (exact for x=2^N)
28 // rel |error| < 0.4 from precision loss very close to 1.0f
29 //
30 static inline float fastLog2f(float x) {
31 
32  union { float f; int32_t i; } mant, bits = { x };
33 
34  // split into mantissa and exponent
35  mant.i = (bits.i & ((1 << IEEE754_MANT_BITS) - 1)) | (IEEE754_EXPN_BIAS << IEEE754_MANT_BITS);
36  int32_t expn = (bits.i >> IEEE754_MANT_BITS) - IEEE754_EXPN_BIAS;
37 
38  mant.f -= 1.0f;
39 
40  // polynomial for log2(1+x) over x=[0,1]
41  x = (((-0.0821307180f * mant.f + 0.321188984f) * mant.f - 0.677784014f) * mant.f + 1.43872575f) * mant.f;
42 
43  return x + expn;
44 }
45 
46 //
47 // for -126 <= x < 128, returns exp2(x)
48 // for x < -126, returns 0
49 // for x >= 128, returns undefined
50 //
51 // rel |error| < 9e-6, smooth (exact for x=N)
52 //
53 static inline float fastExp2f(float x) {
54 
55  union { float f; int32_t i; } xi;
56 
57  // bias such that x > 0
58  x += IEEE754_EXPN_BIAS;
59 
60  // split into integer and fraction
61  xi.i = (int32_t)x;
62  x -= xi.i;
63 
64  // construct exp2(xi) as a float
65  xi.i &= ~(xi.i >> 31); // MAX(xi.i, 0)
66  xi.i <<= IEEE754_MANT_BITS;
67 
68  // polynomial for exp2(x) over x=[0,1]
69  x = (((0.0135557472f * x + 0.0520323690f) * x + 0.241379763f) * x + 0.693032121f) * x + 1.0f;
70 
71  return x * xi.f;
72 }
73 
74 //
75 // on x86 architecture, assume that SSE2 is present
76 //
77 #if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__)
78 
79 #include <xmmintrin.h>
80 // inline sqrtss, without requiring /fp:fast
81 static inline float fastSqrtf(float x) {
82  return _mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ss(x)));
83 }
84 
85 #else
86 
87 static inline float fastSqrtf(float x) {
88  return sqrtf(x);
89 }
90 
91 #endif
92 
93 //
94 // for -1 <= x <= 1, returns acos(x)
95 // otherwise, returns NaN
96 //
97 // abs |error| < 7e-5, smooth
98 //
99 static inline float fastAcosf(float x) {
100 
101  union { float f; int32_t i; } xi = { x };
102 
103  int32_t sign = xi.i & 0x80000000;
104  xi.i ^= sign; // fabs(x)
105 
106  // compute sqrt(1-x) in parallel
107  float r = fastSqrtf(1.0f - xi.f);
108 
109  // polynomial for acos(x)/sqrt(1-x) over x=[0,1]
110  xi.f = ((-0.0198439236f * xi.f + 0.0762021306f) * xi.f + -0.212940971f) * xi.f + 1.57079633f;
111 
112  xi.f *= r;
113  return (sign ? PI - xi.f : xi.f);
114 }
115 
116 //
117 // Quantize a non-negative gain value to the nearest 0.5dB, and pack to a byte.
118 //
119 // Values above +30dB are clamped to +30dB
120 // Values below -97dB are clamped to -inf
121 // Value of 1.0 (+0dB) is reconstructed exactly
122 //
123 const float GAIN_CONVERSION_RATIO = 2.0f * 6.02059991f; // scale log2 to 0.5dB
124 const float GAIN_CONVERSION_OFFSET = 255 - 60.0f; // translate +30dB to max
125 
126 static inline uint8_t packFloatGainToByte(float gain) {
127  float f = fastLog2f(gain) * GAIN_CONVERSION_RATIO + GAIN_CONVERSION_OFFSET;
128  int32_t i = std::lround(f); // quantize
129 
130  uint8_t byte = std::clamp(i, 0, 255);
131  return byte;
132 }
133 
134 static inline float unpackFloatGainFromByte(uint8_t byte) {
135 
136  float gain = (byte == 0) ? 0.0f : fastExp2f((byte - GAIN_CONVERSION_OFFSET) * (1.0f/GAIN_CONVERSION_RATIO));
137  return gain;
138 }
139 
140 #endif // hifi_AudioHelpers_h