1 /* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 */ 5 6 #ifndef DRC_MATH_H_ 7 #define DRC_MATH_H_ 8 9 #ifdef __cplusplus 10 extern "C" { 11 #endif 12 13 #include <stddef.h> 14 #include <math.h> 15 16 /* Uncomment to use the slow but accurate functions. */ 17 /* #define SLOW_DB_TO_LINEAR */ 18 /* #define SLOW_LINEAR_TO_DB */ 19 /* #define SLOW_WARP_SIN */ 20 /* #define SLOW_KNEE_EXP */ 21 /* #define SLOW_FREXPF */ 22 23 #define PI_FLOAT 3.141592653589793f 24 #define PI_OVER_TWO_FLOAT 1.57079632679489661923f 25 #define TWO_OVER_PI_FLOAT 0.63661977236758134f 26 #define NEG_TWO_DB 0.7943282347242815f /* -2dB = 10^(-2/20) */ 27 28 #ifndef max 29 #define max(a, b) ({ __typeof__(a) _a = (a); \ 30 __typeof__(b) _b = (b); \ 31 _a > _b ? _a : _b; }) 32 #endif 33 34 #ifndef min 35 #define min(a, b) ({ __typeof__(a) _a = (a); \ 36 __typeof__(b) _b = (b); \ 37 _a < _b ? _a : _b; }) 38 #endif 39 40 #ifndef M_PI 41 #define M_PI 3.14159265358979323846 42 #endif 43 44 #define PURE __attribute__ ((pure)) 45 static inline float decibels_to_linear(float decibels) PURE; 46 static inline float linear_to_decibels(float linear) PURE; 47 static inline float warp_sinf(float x) PURE; 48 static inline float warp_asinf(float x) PURE; 49 static inline float knee_expf(float input) PURE; 50 51 extern float db_to_linear[201]; /* from -100dB to 100dB */ 52 53 void drc_math_init(); 54 55 union ieee754_float { 56 float f; 57 58 /* This is the IEEE 754 single-precision format. */ 59 struct 60 { 61 /* Little endian. */ 62 unsigned int mantissa:23; 63 unsigned int exponent:8; 64 unsigned int negative:1; 65 } ieee; 66 }; 67 68 /* Rounds the input number to the nearest integer */ 69 #ifdef __arm__ 70 static inline float round_int(float x) 71 { 72 return x < 0 ? (int)(x - 0.5f) : (int)(x + 0.5f); 73 } 74 #else 75 #define round_int rintf /* glibc will use roundss if SSE4.1 is available */ 76 #endif 77 78 static inline float decibels_to_linear(float decibels) 79 { 80 #ifdef SLOW_DB_TO_LINEAR 81 /* 10^(x/20) = e^(x * log(10^(1/20))) */ 82 return expf(0.1151292546497022f * decibels); 83 #else 84 float x; 85 float fi; 86 int i; 87 88 fi = round_int(decibels); 89 x = decibels - fi; 90 i = (int)fi; 91 i = max(min(i, 100), -100); 92 93 /* Coefficients obtained from: 94 * fpminimax(10^(x/20), [|1,2,3|], [|SG...|], [-0.5;0.5], 1, absolute); 95 * max error ~= 7.897e-8 96 */ 97 const float A3 = 2.54408805631101131439208984375e-4f; 98 const float A2 = 6.628888659179210662841796875e-3f; 99 const float A1 = 0.11512924730777740478515625f; 100 const float A0 = 1.0f; 101 102 float x2 = x * x; 103 return ((A3 * x + A2)*x2 + (A1 * x + A0)) * db_to_linear[i+100]; 104 #endif 105 } 106 107 static inline float frexpf_fast(float x, int *e) 108 { 109 #ifdef SLOW_FREXPF 110 return frexpf(x, e); 111 #else 112 union ieee754_float u; 113 u.f = x; 114 int exp = u.ieee.exponent; 115 if (exp == 0xff) 116 return NAN; 117 *e = exp - 126; 118 u.ieee.exponent = 126; 119 return u.f; 120 #endif 121 } 122 123 static inline float linear_to_decibels(float linear) 124 { 125 /* For negative or zero, just return a very small dB value. */ 126 if (linear <= 0) 127 return -1000; 128 129 #ifdef SLOW_LINEAR_TO_DB 130 /* 20 * log10(x) = 20 / log(10) * log(x) */ 131 return 8.6858896380650366f * logf(linear); 132 #else 133 int e = 0; 134 float x = frexpf_fast(linear, &e); 135 float exp = e; 136 137 if (x > 0.707106781186548f) { 138 x *= 0.707106781186548f; 139 exp += 0.5f; 140 } 141 142 /* Coefficients obtained from: 143 * fpminimax(log10(x), 5, [|SG...|], [1/2;sqrt(2)/2], absolute); 144 * max err ~= 6.088e-8 145 */ 146 const float A5 = 1.131880283355712890625f; 147 const float A4 = -4.258677959442138671875f; 148 const float A3 = 6.81631565093994140625f; 149 const float A2 = -6.1185703277587890625f; 150 const float A1 = 3.6505267620086669921875f; 151 const float A0 = -1.217894077301025390625f; 152 153 float x2 = x * x; 154 float x4 = x2 * x2; 155 return ((A5 * x + A4)*x4 + (A3 * x + A2)*x2 + (A1 * x + A0)) * 20.0f 156 + exp * 6.0205999132796239f; 157 #endif 158 } 159 160 161 static inline float warp_sinf(float x) 162 { 163 #ifdef SLOW_WARP_SIN 164 return sinf(PI_OVER_TWO_FLOAT * x); 165 #else 166 /* Coefficients obtained from: 167 * fpminimax(sin(x*pi/2), [|1,3,5,7|], [|SG...|], [-1e-30;1], absolute) 168 * max err ~= 5.901e-7 169 */ 170 const float A7 = -4.3330336920917034149169921875e-3f; 171 const float A5 = 7.9434238374233245849609375e-2f; 172 const float A3 = -0.645892798900604248046875f; 173 const float A1 = 1.5707910060882568359375f; 174 175 float x2 = x * x; 176 float x4 = x2 * x2; 177 return x * ((A7 * x2 + A5) * x4 + (A3 * x2 + A1)); 178 #endif 179 } 180 181 static inline float warp_asinf(float x) 182 { 183 return asinf(x) * TWO_OVER_PI_FLOAT; 184 } 185 186 static inline float knee_expf(float input) 187 { 188 #ifdef SLOW_KNEE_EXP 189 return expf(input); 190 #else 191 /* exp(x) = decibels_to_linear(20*log10(e)*x) */ 192 return decibels_to_linear(8.685889638065044f * input); 193 #endif 194 } 195 196 /* Returns 1 for nan or inf, 0 otherwise. This is faster than the alternative 197 * return x != 0 && !isnormal(x); 198 */ 199 static inline int isbadf(float x) 200 { 201 union ieee754_float u; 202 u.f = x; 203 return u.ieee.exponent == 0xff; 204 } 205 206 #ifdef __cplusplus 207 } /* extern "C" */ 208 #endif 209 210 #endif /* DRC_MATH_H_ */ 211