153a5a1b3Sopenharmony_ci/* Copyright (C) 2002 Jean-Marc Valin */ 253a5a1b3Sopenharmony_ci/** 353a5a1b3Sopenharmony_ci @file math_approx.h 453a5a1b3Sopenharmony_ci @brief Various math approximation functions for Speex 553a5a1b3Sopenharmony_ci*/ 653a5a1b3Sopenharmony_ci/* 753a5a1b3Sopenharmony_ci Redistribution and use in source and binary forms, with or without 853a5a1b3Sopenharmony_ci modification, are permitted provided that the following conditions 953a5a1b3Sopenharmony_ci are met: 1053a5a1b3Sopenharmony_ci 1153a5a1b3Sopenharmony_ci - Redistributions of source code must retain the above copyright 1253a5a1b3Sopenharmony_ci notice, this list of conditions and the following disclaimer. 1353a5a1b3Sopenharmony_ci 1453a5a1b3Sopenharmony_ci - Redistributions in binary form must reproduce the above copyright 1553a5a1b3Sopenharmony_ci notice, this list of conditions and the following disclaimer in the 1653a5a1b3Sopenharmony_ci documentation and/or other materials provided with the distribution. 1753a5a1b3Sopenharmony_ci 1853a5a1b3Sopenharmony_ci - Neither the name of the Xiph.org Foundation nor the names of its 1953a5a1b3Sopenharmony_ci contributors may be used to endorse or promote products derived from 2053a5a1b3Sopenharmony_ci this software without specific prior written permission. 2153a5a1b3Sopenharmony_ci 2253a5a1b3Sopenharmony_ci THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2353a5a1b3Sopenharmony_ci ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2453a5a1b3Sopenharmony_ci LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2553a5a1b3Sopenharmony_ci A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR 2653a5a1b3Sopenharmony_ci CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 2753a5a1b3Sopenharmony_ci EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2853a5a1b3Sopenharmony_ci PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 2953a5a1b3Sopenharmony_ci PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 3053a5a1b3Sopenharmony_ci LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 3153a5a1b3Sopenharmony_ci NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 3253a5a1b3Sopenharmony_ci SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3353a5a1b3Sopenharmony_ci*/ 3453a5a1b3Sopenharmony_ci 3553a5a1b3Sopenharmony_ci#ifndef MATH_APPROX_H 3653a5a1b3Sopenharmony_ci#define MATH_APPROX_H 3753a5a1b3Sopenharmony_ci 3853a5a1b3Sopenharmony_ci#include "arch.h" 3953a5a1b3Sopenharmony_ci 4053a5a1b3Sopenharmony_ci#ifndef FIXED_POINT 4153a5a1b3Sopenharmony_ci 4253a5a1b3Sopenharmony_ci#define spx_sqrt sqrt 4353a5a1b3Sopenharmony_ci#define spx_acos acos 4453a5a1b3Sopenharmony_ci#define spx_exp exp 4553a5a1b3Sopenharmony_ci#define spx_cos_norm(x) (cos((.5f*M_PI)*(x))) 4653a5a1b3Sopenharmony_ci#define spx_atan atan 4753a5a1b3Sopenharmony_ci 4853a5a1b3Sopenharmony_ci/** Generate a pseudo-random number */ 4953a5a1b3Sopenharmony_cistatic inline spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed) 5053a5a1b3Sopenharmony_ci{ 5153a5a1b3Sopenharmony_ci const unsigned int jflone = 0x3f800000; 5253a5a1b3Sopenharmony_ci const unsigned int jflmsk = 0x007fffff; 5353a5a1b3Sopenharmony_ci union {int i; float f;} ran; 5453a5a1b3Sopenharmony_ci *seed = 1664525 * *seed + 1013904223; 5553a5a1b3Sopenharmony_ci ran.i = jflone | (jflmsk & *seed); 5653a5a1b3Sopenharmony_ci ran.f -= 1.5; 5753a5a1b3Sopenharmony_ci return 3.4642*std*ran.f; 5853a5a1b3Sopenharmony_ci} 5953a5a1b3Sopenharmony_ci 6053a5a1b3Sopenharmony_ci 6153a5a1b3Sopenharmony_ci#endif 6253a5a1b3Sopenharmony_ci 6353a5a1b3Sopenharmony_ci 6453a5a1b3Sopenharmony_cistatic inline spx_int16_t spx_ilog2(spx_uint32_t x) 6553a5a1b3Sopenharmony_ci{ 6653a5a1b3Sopenharmony_ci int r=0; 6753a5a1b3Sopenharmony_ci if (x>=(spx_int32_t)65536) 6853a5a1b3Sopenharmony_ci { 6953a5a1b3Sopenharmony_ci x >>= 16; 7053a5a1b3Sopenharmony_ci r += 16; 7153a5a1b3Sopenharmony_ci } 7253a5a1b3Sopenharmony_ci if (x>=256) 7353a5a1b3Sopenharmony_ci { 7453a5a1b3Sopenharmony_ci x >>= 8; 7553a5a1b3Sopenharmony_ci r += 8; 7653a5a1b3Sopenharmony_ci } 7753a5a1b3Sopenharmony_ci if (x>=16) 7853a5a1b3Sopenharmony_ci { 7953a5a1b3Sopenharmony_ci x >>= 4; 8053a5a1b3Sopenharmony_ci r += 4; 8153a5a1b3Sopenharmony_ci } 8253a5a1b3Sopenharmony_ci if (x>=4) 8353a5a1b3Sopenharmony_ci { 8453a5a1b3Sopenharmony_ci x >>= 2; 8553a5a1b3Sopenharmony_ci r += 2; 8653a5a1b3Sopenharmony_ci } 8753a5a1b3Sopenharmony_ci if (x>=2) 8853a5a1b3Sopenharmony_ci { 8953a5a1b3Sopenharmony_ci r += 1; 9053a5a1b3Sopenharmony_ci } 9153a5a1b3Sopenharmony_ci return r; 9253a5a1b3Sopenharmony_ci} 9353a5a1b3Sopenharmony_ci 9453a5a1b3Sopenharmony_cistatic inline spx_int16_t spx_ilog4(spx_uint32_t x) 9553a5a1b3Sopenharmony_ci{ 9653a5a1b3Sopenharmony_ci int r=0; 9753a5a1b3Sopenharmony_ci if (x>=(spx_int32_t)65536) 9853a5a1b3Sopenharmony_ci { 9953a5a1b3Sopenharmony_ci x >>= 16; 10053a5a1b3Sopenharmony_ci r += 8; 10153a5a1b3Sopenharmony_ci } 10253a5a1b3Sopenharmony_ci if (x>=256) 10353a5a1b3Sopenharmony_ci { 10453a5a1b3Sopenharmony_ci x >>= 8; 10553a5a1b3Sopenharmony_ci r += 4; 10653a5a1b3Sopenharmony_ci } 10753a5a1b3Sopenharmony_ci if (x>=16) 10853a5a1b3Sopenharmony_ci { 10953a5a1b3Sopenharmony_ci x >>= 4; 11053a5a1b3Sopenharmony_ci r += 2; 11153a5a1b3Sopenharmony_ci } 11253a5a1b3Sopenharmony_ci if (x>=4) 11353a5a1b3Sopenharmony_ci { 11453a5a1b3Sopenharmony_ci r += 1; 11553a5a1b3Sopenharmony_ci } 11653a5a1b3Sopenharmony_ci return r; 11753a5a1b3Sopenharmony_ci} 11853a5a1b3Sopenharmony_ci 11953a5a1b3Sopenharmony_ci#ifdef FIXED_POINT 12053a5a1b3Sopenharmony_ci 12153a5a1b3Sopenharmony_ci/** Generate a pseudo-random number */ 12253a5a1b3Sopenharmony_cistatic inline spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed) 12353a5a1b3Sopenharmony_ci{ 12453a5a1b3Sopenharmony_ci spx_word32_t res; 12553a5a1b3Sopenharmony_ci *seed = 1664525 * *seed + 1013904223; 12653a5a1b3Sopenharmony_ci res = MULT16_16(EXTRACT16(SHR32(*seed,16)),std); 12753a5a1b3Sopenharmony_ci return EXTRACT16(PSHR32(SUB32(res, SHR32(res, 3)),14)); 12853a5a1b3Sopenharmony_ci} 12953a5a1b3Sopenharmony_ci 13053a5a1b3Sopenharmony_ci/* sqrt(x) ~= 0.22178 + 1.29227*x - 0.77070*x^2 + 0.25723*x^3 (for .25 < x < 1) */ 13153a5a1b3Sopenharmony_ci/*#define C0 3634 13253a5a1b3Sopenharmony_ci#define C1 21173 13353a5a1b3Sopenharmony_ci#define C2 -12627 13453a5a1b3Sopenharmony_ci#define C3 4215*/ 13553a5a1b3Sopenharmony_ci 13653a5a1b3Sopenharmony_ci/* sqrt(x) ~= 0.22178 + 1.29227*x - 0.77070*x^2 + 0.25659*x^3 (for .25 < x < 1) */ 13753a5a1b3Sopenharmony_ci#define C0 3634 13853a5a1b3Sopenharmony_ci#define C1 21173 13953a5a1b3Sopenharmony_ci#define C2 -12627 14053a5a1b3Sopenharmony_ci#define C3 4204 14153a5a1b3Sopenharmony_ci 14253a5a1b3Sopenharmony_cistatic inline spx_word16_t spx_sqrt(spx_word32_t x) 14353a5a1b3Sopenharmony_ci{ 14453a5a1b3Sopenharmony_ci int k; 14553a5a1b3Sopenharmony_ci spx_word32_t rt; 14653a5a1b3Sopenharmony_ci k = spx_ilog4(x)-6; 14753a5a1b3Sopenharmony_ci x = VSHR32(x, (k<<1)); 14853a5a1b3Sopenharmony_ci rt = ADD16(C0, MULT16_16_Q14(x, ADD16(C1, MULT16_16_Q14(x, ADD16(C2, MULT16_16_Q14(x, (C3))))))); 14953a5a1b3Sopenharmony_ci rt = VSHR32(rt,7-k); 15053a5a1b3Sopenharmony_ci return rt; 15153a5a1b3Sopenharmony_ci} 15253a5a1b3Sopenharmony_ci 15353a5a1b3Sopenharmony_ci/* log(x) ~= -2.18151 + 4.20592*x - 2.88938*x^2 + 0.86535*x^3 (for .5 < x < 1) */ 15453a5a1b3Sopenharmony_ci 15553a5a1b3Sopenharmony_ci 15653a5a1b3Sopenharmony_ci#define A1 16469 15753a5a1b3Sopenharmony_ci#define A2 2242 15853a5a1b3Sopenharmony_ci#define A3 1486 15953a5a1b3Sopenharmony_ci 16053a5a1b3Sopenharmony_cistatic inline spx_word16_t spx_acos(spx_word16_t x) 16153a5a1b3Sopenharmony_ci{ 16253a5a1b3Sopenharmony_ci int s=0; 16353a5a1b3Sopenharmony_ci spx_word16_t ret; 16453a5a1b3Sopenharmony_ci spx_word16_t sq; 16553a5a1b3Sopenharmony_ci if (x<0) 16653a5a1b3Sopenharmony_ci { 16753a5a1b3Sopenharmony_ci s=1; 16853a5a1b3Sopenharmony_ci x = NEG16(x); 16953a5a1b3Sopenharmony_ci } 17053a5a1b3Sopenharmony_ci x = SUB16(16384,x); 17153a5a1b3Sopenharmony_ci 17253a5a1b3Sopenharmony_ci x = x >> 1; 17353a5a1b3Sopenharmony_ci sq = MULT16_16_Q13(x, ADD16(A1, MULT16_16_Q13(x, ADD16(A2, MULT16_16_Q13(x, (A3)))))); 17453a5a1b3Sopenharmony_ci ret = spx_sqrt(SHL32(EXTEND32(sq),13)); 17553a5a1b3Sopenharmony_ci 17653a5a1b3Sopenharmony_ci /*ret = spx_sqrt(67108864*(-1.6129e-04 + 2.0104e+00*f + 2.7373e-01*f*f + 1.8136e-01*f*f*f));*/ 17753a5a1b3Sopenharmony_ci if (s) 17853a5a1b3Sopenharmony_ci ret = SUB16(25736,ret); 17953a5a1b3Sopenharmony_ci return ret; 18053a5a1b3Sopenharmony_ci} 18153a5a1b3Sopenharmony_ci 18253a5a1b3Sopenharmony_ci 18353a5a1b3Sopenharmony_ci#define K1 8192 18453a5a1b3Sopenharmony_ci#define K2 -4096 18553a5a1b3Sopenharmony_ci#define K3 340 18653a5a1b3Sopenharmony_ci#define K4 -10 18753a5a1b3Sopenharmony_ci 18853a5a1b3Sopenharmony_cistatic inline spx_word16_t spx_cos(spx_word16_t x) 18953a5a1b3Sopenharmony_ci{ 19053a5a1b3Sopenharmony_ci spx_word16_t x2; 19153a5a1b3Sopenharmony_ci 19253a5a1b3Sopenharmony_ci if (x<12868) 19353a5a1b3Sopenharmony_ci { 19453a5a1b3Sopenharmony_ci x2 = MULT16_16_P13(x,x); 19553a5a1b3Sopenharmony_ci return ADD32(K1, MULT16_16_P13(x2, ADD32(K2, MULT16_16_P13(x2, ADD32(K3, MULT16_16_P13(K4, x2)))))); 19653a5a1b3Sopenharmony_ci } else { 19753a5a1b3Sopenharmony_ci x = SUB16(25736,x); 19853a5a1b3Sopenharmony_ci x2 = MULT16_16_P13(x,x); 19953a5a1b3Sopenharmony_ci return SUB32(-K1, MULT16_16_P13(x2, ADD32(K2, MULT16_16_P13(x2, ADD32(K3, MULT16_16_P13(K4, x2)))))); 20053a5a1b3Sopenharmony_ci } 20153a5a1b3Sopenharmony_ci} 20253a5a1b3Sopenharmony_ci 20353a5a1b3Sopenharmony_ci#define L1 32767 20453a5a1b3Sopenharmony_ci#define L2 -7651 20553a5a1b3Sopenharmony_ci#define L3 8277 20653a5a1b3Sopenharmony_ci#define L4 -626 20753a5a1b3Sopenharmony_ci 20853a5a1b3Sopenharmony_cistatic inline spx_word16_t _spx_cos_pi_2(spx_word16_t x) 20953a5a1b3Sopenharmony_ci{ 21053a5a1b3Sopenharmony_ci spx_word16_t x2; 21153a5a1b3Sopenharmony_ci 21253a5a1b3Sopenharmony_ci x2 = MULT16_16_P15(x,x); 21353a5a1b3Sopenharmony_ci return ADD16(1,MIN16(32766,ADD32(SUB16(L1,x2), MULT16_16_P15(x2, ADD32(L2, MULT16_16_P15(x2, ADD32(L3, MULT16_16_P15(L4, x2)))))))); 21453a5a1b3Sopenharmony_ci} 21553a5a1b3Sopenharmony_ci 21653a5a1b3Sopenharmony_cistatic inline spx_word16_t spx_cos_norm(spx_word32_t x) 21753a5a1b3Sopenharmony_ci{ 21853a5a1b3Sopenharmony_ci x = x&0x0001ffff; 21953a5a1b3Sopenharmony_ci if (x>SHL32(EXTEND32(1), 16)) 22053a5a1b3Sopenharmony_ci x = SUB32(SHL32(EXTEND32(1), 17),x); 22153a5a1b3Sopenharmony_ci if (x&0x00007fff) 22253a5a1b3Sopenharmony_ci { 22353a5a1b3Sopenharmony_ci if (x<SHL32(EXTEND32(1), 15)) 22453a5a1b3Sopenharmony_ci { 22553a5a1b3Sopenharmony_ci return _spx_cos_pi_2(EXTRACT16(x)); 22653a5a1b3Sopenharmony_ci } else { 22753a5a1b3Sopenharmony_ci return NEG32(_spx_cos_pi_2(EXTRACT16(65536-x))); 22853a5a1b3Sopenharmony_ci } 22953a5a1b3Sopenharmony_ci } else { 23053a5a1b3Sopenharmony_ci if (x&0x0000ffff) 23153a5a1b3Sopenharmony_ci return 0; 23253a5a1b3Sopenharmony_ci else if (x&0x0001ffff) 23353a5a1b3Sopenharmony_ci return -32767; 23453a5a1b3Sopenharmony_ci else 23553a5a1b3Sopenharmony_ci return 32767; 23653a5a1b3Sopenharmony_ci } 23753a5a1b3Sopenharmony_ci} 23853a5a1b3Sopenharmony_ci 23953a5a1b3Sopenharmony_ci/* 24053a5a1b3Sopenharmony_ci K0 = 1 24153a5a1b3Sopenharmony_ci K1 = log(2) 24253a5a1b3Sopenharmony_ci K2 = 3-4*log(2) 24353a5a1b3Sopenharmony_ci K3 = 3*log(2) - 2 24453a5a1b3Sopenharmony_ci*/ 24553a5a1b3Sopenharmony_ci#define D0 16384 24653a5a1b3Sopenharmony_ci#define D1 11356 24753a5a1b3Sopenharmony_ci#define D2 3726 24853a5a1b3Sopenharmony_ci#define D3 1301 24953a5a1b3Sopenharmony_ci/* Input in Q11 format, output in Q16 */ 25053a5a1b3Sopenharmony_cistatic inline spx_word32_t spx_exp2(spx_word16_t x) 25153a5a1b3Sopenharmony_ci{ 25253a5a1b3Sopenharmony_ci int integer; 25353a5a1b3Sopenharmony_ci spx_word16_t frac; 25453a5a1b3Sopenharmony_ci integer = SHR16(x,11); 25553a5a1b3Sopenharmony_ci if (integer>14) 25653a5a1b3Sopenharmony_ci return 0x7fffffff; 25753a5a1b3Sopenharmony_ci else if (integer < -15) 25853a5a1b3Sopenharmony_ci return 0; 25953a5a1b3Sopenharmony_ci frac = SHL16(x-SHL16(integer,11),3); 26053a5a1b3Sopenharmony_ci frac = ADD16(D0, MULT16_16_Q14(frac, ADD16(D1, MULT16_16_Q14(frac, ADD16(D2 , MULT16_16_Q14(D3,frac)))))); 26153a5a1b3Sopenharmony_ci return VSHR32(EXTEND32(frac), -integer-2); 26253a5a1b3Sopenharmony_ci} 26353a5a1b3Sopenharmony_ci 26453a5a1b3Sopenharmony_ci/* Input in Q11 format, output in Q16 */ 26553a5a1b3Sopenharmony_cistatic inline spx_word32_t spx_exp(spx_word16_t x) 26653a5a1b3Sopenharmony_ci{ 26753a5a1b3Sopenharmony_ci if (x>21290) 26853a5a1b3Sopenharmony_ci return 0x7fffffff; 26953a5a1b3Sopenharmony_ci else if (x<-21290) 27053a5a1b3Sopenharmony_ci return 0; 27153a5a1b3Sopenharmony_ci else 27253a5a1b3Sopenharmony_ci return spx_exp2(MULT16_16_P14(23637,x)); 27353a5a1b3Sopenharmony_ci} 27453a5a1b3Sopenharmony_ci#define M1 32767 27553a5a1b3Sopenharmony_ci#define M2 -21 27653a5a1b3Sopenharmony_ci#define M3 -11943 27753a5a1b3Sopenharmony_ci#define M4 4936 27853a5a1b3Sopenharmony_ci 27953a5a1b3Sopenharmony_cistatic inline spx_word16_t spx_atan01(spx_word16_t x) 28053a5a1b3Sopenharmony_ci{ 28153a5a1b3Sopenharmony_ci return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x))))))); 28253a5a1b3Sopenharmony_ci} 28353a5a1b3Sopenharmony_ci 28453a5a1b3Sopenharmony_ci#undef M1 28553a5a1b3Sopenharmony_ci#undef M2 28653a5a1b3Sopenharmony_ci#undef M3 28753a5a1b3Sopenharmony_ci#undef M4 28853a5a1b3Sopenharmony_ci 28953a5a1b3Sopenharmony_ci/* Input in Q15, output in Q14 */ 29053a5a1b3Sopenharmony_cistatic inline spx_word16_t spx_atan(spx_word32_t x) 29153a5a1b3Sopenharmony_ci{ 29253a5a1b3Sopenharmony_ci if (x <= 32767) 29353a5a1b3Sopenharmony_ci { 29453a5a1b3Sopenharmony_ci return SHR16(spx_atan01(x),1); 29553a5a1b3Sopenharmony_ci } else { 29653a5a1b3Sopenharmony_ci int e = spx_ilog2(x); 29753a5a1b3Sopenharmony_ci if (e>=29) 29853a5a1b3Sopenharmony_ci return 25736; 29953a5a1b3Sopenharmony_ci x = DIV32_16(SHL32(EXTEND32(32767),29-e), EXTRACT16(SHR32(x, e-14))); 30053a5a1b3Sopenharmony_ci return SUB16(25736, SHR16(spx_atan01(x),1)); 30153a5a1b3Sopenharmony_ci } 30253a5a1b3Sopenharmony_ci} 30353a5a1b3Sopenharmony_ci#else 30453a5a1b3Sopenharmony_ci 30553a5a1b3Sopenharmony_ci#ifndef M_PI 30653a5a1b3Sopenharmony_ci#define M_PI 3.14159265358979323846 /* pi */ 30753a5a1b3Sopenharmony_ci#endif 30853a5a1b3Sopenharmony_ci 30953a5a1b3Sopenharmony_ci#define C1 0.9999932946f 31053a5a1b3Sopenharmony_ci#define C2 -0.4999124376f 31153a5a1b3Sopenharmony_ci#define C3 0.0414877472f 31253a5a1b3Sopenharmony_ci#define C4 -0.0012712095f 31353a5a1b3Sopenharmony_ci 31453a5a1b3Sopenharmony_ci 31553a5a1b3Sopenharmony_ci#define SPX_PI_2 1.5707963268 31653a5a1b3Sopenharmony_cistatic inline spx_word16_t spx_cos(spx_word16_t x) 31753a5a1b3Sopenharmony_ci{ 31853a5a1b3Sopenharmony_ci if (x<SPX_PI_2) 31953a5a1b3Sopenharmony_ci { 32053a5a1b3Sopenharmony_ci x *= x; 32153a5a1b3Sopenharmony_ci return C1 + x*(C2+x*(C3+C4*x)); 32253a5a1b3Sopenharmony_ci } else { 32353a5a1b3Sopenharmony_ci x = M_PI-x; 32453a5a1b3Sopenharmony_ci x *= x; 32553a5a1b3Sopenharmony_ci return NEG16(C1 + x*(C2+x*(C3+C4*x))); 32653a5a1b3Sopenharmony_ci } 32753a5a1b3Sopenharmony_ci} 32853a5a1b3Sopenharmony_ci 32953a5a1b3Sopenharmony_ci#endif 33053a5a1b3Sopenharmony_ci 33153a5a1b3Sopenharmony_ci 33253a5a1b3Sopenharmony_ci#endif 333