Home | History | Annotate | Download | only in libspeex
      1 /* Copyright (C) 2002 Jean-Marc Valin */
      2 /**
      3    @file math_approx.h
      4    @brief Various math approximation functions for Speex
      5 */
      6 /*
      7    Redistribution and use in source and binary forms, with or without
      8    modification, are permitted provided that the following conditions
      9    are met:
     10 
     11    - Redistributions of source code must retain the above copyright
     12    notice, this list of conditions and the following disclaimer.
     13 
     14    - Redistributions in binary form must reproduce the above copyright
     15    notice, this list of conditions and the following disclaimer in the
     16    documentation and/or other materials provided with the distribution.
     17 
     18    - Neither the name of the Xiph.org Foundation nor the names of its
     19    contributors may be used to endorse or promote products derived from
     20    this software without specific prior written permission.
     21 
     22    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     23    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     24    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     25    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
     26    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     27    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     28    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     29    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     30    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     31    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     32    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     33 */
     34 
     35 #ifndef MATH_APPROX_H
     36 #define MATH_APPROX_H
     37 
     38 #include "arch.h"
     39 
     40 #ifndef FIXED_POINT
     41 
     42 #define spx_sqrt sqrt
     43 #define spx_acos acos
     44 #define spx_exp exp
     45 #define spx_cos_norm(x) (cos((.5f*M_PI)*(x)))
     46 #define spx_atan atan
     47 
     48 /** Generate a pseudo-random number */
     49 static inline spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed)
     50 {
     51    const unsigned int jflone = 0x3f800000;
     52    const unsigned int jflmsk = 0x007fffff;
     53    union {int i; float f;} ran;
     54    *seed = 1664525 * *seed + 1013904223;
     55    ran.i = jflone | (jflmsk & *seed);
     56    ran.f -= 1.5;
     57    return 3.4642*std*ran.f;
     58 }
     59 
     60 
     61 #endif
     62 
     63 
     64 static inline spx_int16_t spx_ilog2(spx_uint32_t x)
     65 {
     66    int r=0;
     67    if (x>=(spx_int32_t)65536)
     68    {
     69       x >>= 16;
     70       r += 16;
     71    }
     72    if (x>=256)
     73    {
     74       x >>= 8;
     75       r += 8;
     76    }
     77    if (x>=16)
     78    {
     79       x >>= 4;
     80       r += 4;
     81    }
     82    if (x>=4)
     83    {
     84       x >>= 2;
     85       r += 2;
     86    }
     87    if (x>=2)
     88    {
     89       r += 1;
     90    }
     91    return r;
     92 }
     93 
     94 static inline spx_int16_t spx_ilog4(spx_uint32_t x)
     95 {
     96    int r=0;
     97    if (x>=(spx_int32_t)65536)
     98    {
     99       x >>= 16;
    100       r += 8;
    101    }
    102    if (x>=256)
    103    {
    104       x >>= 8;
    105       r += 4;
    106    }
    107    if (x>=16)
    108    {
    109       x >>= 4;
    110       r += 2;
    111    }
    112    if (x>=4)
    113    {
    114       r += 1;
    115    }
    116    return r;
    117 }
    118 
    119 #ifdef FIXED_POINT
    120 
    121 /** Generate a pseudo-random number */
    122 static inline spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed)
    123 {
    124    spx_word32_t res;
    125    *seed = 1664525 * *seed + 1013904223;
    126    res = MULT16_16(EXTRACT16(SHR32(*seed,16)),std);
    127    return EXTRACT16(PSHR32(SUB32(res, SHR32(res, 3)),14));
    128 }
    129 
    130 /* sqrt(x) ~= 0.22178 + 1.29227*x - 0.77070*x^2 + 0.25723*x^3 (for .25 < x < 1) */
    131 /*#define C0 3634
    132 #define C1 21173
    133 #define C2 -12627
    134 #define C3 4215*/
    135 
    136 /* sqrt(x) ~= 0.22178 + 1.29227*x - 0.77070*x^2 + 0.25659*x^3 (for .25 < x < 1) */
    137 #define C0 3634
    138 #define C1 21173
    139 #define C2 -12627
    140 #define C3 4204
    141 
    142 static inline spx_word16_t spx_sqrt(spx_word32_t x)
    143 {
    144    int k;
    145    spx_word32_t rt;
    146    k = spx_ilog4(x)-6;
    147    x = VSHR32(x, (k<<1));
    148    rt = ADD16(C0, MULT16_16_Q14(x, ADD16(C1, MULT16_16_Q14(x, ADD16(C2, MULT16_16_Q14(x, (C3)))))));
    149    rt = VSHR32(rt,7-k);
    150    return rt;
    151 }
    152 
    153 /* log(x) ~= -2.18151 + 4.20592*x - 2.88938*x^2 + 0.86535*x^3 (for .5 < x < 1) */
    154 
    155 
    156 #define A1 16469
    157 #define A2 2242
    158 #define A3 1486
    159 
    160 static inline spx_word16_t spx_acos(spx_word16_t x)
    161 {
    162    int s=0;
    163    spx_word16_t ret;
    164    spx_word16_t sq;
    165    if (x<0)
    166    {
    167       s=1;
    168       x = NEG16(x);
    169    }
    170    x = SUB16(16384,x);
    171 
    172    x = x >> 1;
    173    sq = MULT16_16_Q13(x, ADD16(A1, MULT16_16_Q13(x, ADD16(A2, MULT16_16_Q13(x, (A3))))));
    174    ret = spx_sqrt(SHL32(EXTEND32(sq),13));
    175 
    176    /*ret = spx_sqrt(67108864*(-1.6129e-04 + 2.0104e+00*f + 2.7373e-01*f*f + 1.8136e-01*f*f*f));*/
    177    if (s)
    178       ret = SUB16(25736,ret);
    179    return ret;
    180 }
    181 
    182 
    183 #define K1 8192
    184 #define K2 -4096
    185 #define K3 340
    186 #define K4 -10
    187 
    188 static inline spx_word16_t spx_cos(spx_word16_t x)
    189 {
    190    spx_word16_t x2;
    191 
    192    if (x<12868)
    193    {
    194       x2 = MULT16_16_P13(x,x);
    195       return ADD32(K1, MULT16_16_P13(x2, ADD32(K2, MULT16_16_P13(x2, ADD32(K3, MULT16_16_P13(K4, x2))))));
    196    } else {
    197       x = SUB16(25736,x);
    198       x2 = MULT16_16_P13(x,x);
    199       return SUB32(-K1, MULT16_16_P13(x2, ADD32(K2, MULT16_16_P13(x2, ADD32(K3, MULT16_16_P13(K4, x2))))));
    200    }
    201 }
    202 
    203 #define L1 32767
    204 #define L2 -7651
    205 #define L3 8277
    206 #define L4 -626
    207 
    208 static inline spx_word16_t _spx_cos_pi_2(spx_word16_t x)
    209 {
    210    spx_word16_t x2;
    211 
    212    x2 = MULT16_16_P15(x,x);
    213    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))))))));
    214 }
    215 
    216 static inline spx_word16_t spx_cos_norm(spx_word32_t x)
    217 {
    218    x = x&0x0001ffff;
    219    if (x>SHL32(EXTEND32(1), 16))
    220       x = SUB32(SHL32(EXTEND32(1), 17),x);
    221    if (x&0x00007fff)
    222    {
    223       if (x<SHL32(EXTEND32(1), 15))
    224       {
    225          return _spx_cos_pi_2(EXTRACT16(x));
    226       } else {
    227          return NEG32(_spx_cos_pi_2(EXTRACT16(65536-x)));
    228       }
    229    } else {
    230       if (x&0x0000ffff)
    231          return 0;
    232       else if (x&0x0001ffff)
    233          return -32767;
    234       else
    235          return 32767;
    236    }
    237 }
    238 
    239 /*
    240  K0 = 1
    241  K1 = log(2)
    242  K2 = 3-4*log(2)
    243  K3 = 3*log(2) - 2
    244 */
    245 #define D0 16384
    246 #define D1 11356
    247 #define D2 3726
    248 #define D3 1301
    249 /* Input in Q11 format, output in Q16 */
    250 static inline spx_word32_t spx_exp2(spx_word16_t x)
    251 {
    252    int integer;
    253    spx_word16_t frac;
    254    integer = SHR16(x,11);
    255    if (integer>14)
    256       return 0x7fffffff;
    257    else if (integer < -15)
    258       return 0;
    259    frac = SHL16(x-SHL16(integer,11),3);
    260    frac = ADD16(D0, MULT16_16_Q14(frac, ADD16(D1, MULT16_16_Q14(frac, ADD16(D2 , MULT16_16_Q14(D3,frac))))));
    261    return VSHR32(EXTEND32(frac), -integer-2);
    262 }
    263 
    264 /* Input in Q11 format, output in Q16 */
    265 static inline spx_word32_t spx_exp(spx_word16_t x)
    266 {
    267    if (x>21290)
    268       return 0x7fffffff;
    269    else if (x<-21290)
    270       return 0;
    271    else
    272       return spx_exp2(MULT16_16_P14(23637,x));
    273 }
    274 #define M1 32767
    275 #define M2 -21
    276 #define M3 -11943
    277 #define M4 4936
    278 
    279 static inline spx_word16_t spx_atan01(spx_word16_t x)
    280 {
    281    return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x)))))));
    282 }
    283 
    284 #undef M1
    285 #undef M2
    286 #undef M3
    287 #undef M4
    288 
    289 /* Input in Q15, output in Q14 */
    290 static inline spx_word16_t spx_atan(spx_word32_t x)
    291 {
    292    if (x <= 32767)
    293    {
    294       return SHR16(spx_atan01(x),1);
    295    } else {
    296       int e = spx_ilog2(x);
    297       if (e>=29)
    298          return 25736;
    299       x = DIV32_16(SHL32(EXTEND32(32767),29-e), EXTRACT16(SHR32(x, e-14)));
    300       return SUB16(25736, SHR16(spx_atan01(x),1));
    301    }
    302 }
    303 #else
    304 
    305 #ifndef M_PI
    306 #define M_PI           3.14159265358979323846  /* pi */
    307 #endif
    308 
    309 #define C1 0.9999932946f
    310 #define C2 -0.4999124376f
    311 #define C3 0.0414877472f
    312 #define C4 -0.0012712095f
    313 
    314 
    315 #define SPX_PI_2 1.5707963268
    316 static inline spx_word16_t spx_cos(spx_word16_t x)
    317 {
    318    if (x<SPX_PI_2)
    319    {
    320       x *= x;
    321       return C1 + x*(C2+x*(C3+C4*x));
    322    } else {
    323       x = M_PI-x;
    324       x *= x;
    325       return NEG16(C1 + x*(C2+x*(C3+C4*x)));
    326    }
    327 }
    328 
    329 #endif
    330 
    331 
    332 #endif
    333