#include #include /* The coefficients of the chebychev polynomial to approximate 10^x in the interval [-1,1]. This polynomial was calculated using the mpmath library in Python: from mpmath import * mp.dps = 15 mp.pretty = True poly, err = chebyfit(lambda x: pow(10,x), [-1,1], 14, error=True) nprint([int(x * pow(2,28)) for x in poly]) */ #define COEF_PREC 28 static unsigned coef[14] = {2407, 13778, 64588, 308051, 1346110, 5261991, 18277531, 55564576, 144789513, 314406484, 546179875, 711608713, 618095479, 268435456}; #define DB_CALC_PREC 28 /* Function: db_to_mult This function converts decibels into a volume multiplier. It uses a fixed-point polynomial approximation to 10^(db/10). Parameters: db - The db value to convert. db_frac_bits - The number of binary fractional bits in the supplied decibel value result_frac_bits - The number of required fractional bits in the result. Returns: The multiplier value as a fixed point value with the number of fractional bits as specified by the result_frac_bits parameter. */ unsigned db_to_mult(int db, int db_frac_bits, int result_frac_bits) { int intpart; int val = 0; int val0=0; unsigned ret; unsigned mask = ~((1<> DB_CALC_PREC; if (intpart) { val0 = 1 << DB_CALC_PREC; for (int i=0;i> DB_CALC_PREC; if (intpart) { val0 = 1 << DB_CALC_PREC; for (int i=0;i> DB_CALC_PREC); val += coef[i] >> (COEF_PREC - DB_CALC_PREC); } /* Finally multiply by the integer power (if there was an integer part) */ if (val0) { int hi=0; unsigned lo=0; {hi, lo} = macs(val0,val,hi,lo); val = (hi << (32-DB_CALC_PREC)) | (lo >> DB_CALC_PREC); } /* We now have the result, just need to scale it to the required precision */ ret = val; if (result_frac_bits > DB_CALC_PREC) { return ret<<(result_frac_bits-DB_CALC_PREC); } else { return ret>>(DB_CALC_PREC-result_frac_bits); } } #ifdef TEST_DBCALC #include int main() { /* Check that we don't overflow up to 9db Should give a value just under 0x80000 */ printhexln(db_to_mult(9,0,16)); /* This test recreates the old db lookup table */ printuintln(0xffffffff); for (int i=1;i<128;i++) { printuintln(db_to_mult(-i,0,32)); } return 0; } #endif