opus/libcelt/mathops.h
Jean-Marc Valin ca53b7c919 Squashed commit of the following:
commit ea807b68678dd76175def2c5eb006c6bdb16679e
Author: Jean-Marc Valin <jean-marc.valin@usherbrooke.ca>
Date:   Wed Mar 25 23:24:41 2009 -0400

    cleanup before merge

commit 73ad1a0202641be6a23903e464ece21fe332a131
Author: Jean-Marc Valin <jean-marc.valin@usherbrooke.ca>
Date:   Sat Mar 21 00:02:16 2009 -0400

    Some tuning of the new stereo

commit c05057eb57a7723045214a2f830fd561388ae48a
Author: Jean-Marc Valin <jean-marc.valin@usherbrooke.ca>
Date:   Sun Mar 15 19:56:11 2009 -0400

    fixed-point: atan2() converted

commit a8476cf8be55b0612d42df98d9807ca1335adfe3
Author: Jean-Marc Valin <jean-marc.valin@usherbrooke.ca>
Date:   Sat Mar 14 23:10:04 2009 -0400

    fixed-point: Getting the new stereo code working in fixed-point (still more
    work left)

commit 70a452761a5ce15700664e7167886dce5914cbd0
Author: Jean-Marc Valin <jean-marc.valin@usherbrooke.ca>
Date:   Mon Mar 2 23:36:25 2009 -0500

    Coding left and right independently for lower bands

commit 4efd1e6385c7d036749080265a8d26668312b91b
Author: Jean-Marc Valin <jean-marc.valin@usherbrooke.ca>
Date:   Sun Mar 1 23:56:46 2009 -0500

    Removed the sqrt(C) from the normalisation, which simplifies a lot of things.

commit a4f3c5c60bc396bf644afa49b49e6b24ccf144f8
Author: Jean-Marc Valin <jean-marc.valin@usherbrooke.ca>
Date:   Fri Feb 20 20:49:38 2009 -0500

    Better point stereo calculation when we don't encode the side anyway

commit f08525de4739f4017d19ec2e2022883deda8f826
Author: Jean-Marc Valin <jean-marc.valin@usherbrooke.ca>
Date:   Thu Feb 19 19:43:09 2009 -0500

    Apparently, Timothy's calculations for fine energy allocation also apply
    to the quantisation of theta.

commit 6548cffc9d3f996b8a8dbfab982f0da0bc6c2dc2
Author: Jean-Marc Valin <jean-marc.valin@usherbrooke.ca>
Date:   Thu Feb 19 07:35:24 2009 -0500

    Better handling of the "theta bits" and disabling the orthogonalize()

commit 7aa82c694967afa85dd30be8cc670663f98829fe
Author: Jean-Marc Valin <jean-marc.valin@usherbrooke.ca>
Date:   Wed Feb 18 08:01:07 2009 -0500

    tuning the new stereo

commit c2b780a773de66fd9613c7cd54c09b705fe9ce45
Author: Jean-Marc Valin <jean-marc.valin@usherbrooke.ca>
Date:   Sun Feb 15 22:24:52 2009 -0500

    The new stereo coupling actually decodes properly now.

commit 85513c203d773bebcf0a6055f953170d563d890c
Author: Jean-Marc Valin <jean-marc.valin@usherbrooke.ca>
Date:   Sun Feb 15 21:31:16 2009 -0500

    First attempt at a new "constrained" MS stereo scheme
2009-03-26 20:23:14 -04:00

325 lines
8.7 KiB
C

/* Copyright (C) 2002-2008 Jean-Marc Valin */
/**
@file mathops.h
@brief Various math functions
*/
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MATHOPS_H
#define MATHOPS_H
#include "arch.h"
#include "entcode.h"
#include "os_support.h"
#ifndef OVERRIDE_CELT_ILOG2
/** Integer log in base2. Undefined for zero and negative numbers */
static inline celt_int16_t celt_ilog2(celt_word32_t x)
{
celt_assert2(x>0, "celt_ilog2() only defined for strictly positive numbers");
return EC_ILOG(x)-1;
}
#endif
#ifndef OVERRIDE_FIND_MAX16
static inline int find_max16(celt_word16_t *x, int len)
{
celt_word16_t max_corr=-VERY_LARGE16;
int i, id = 0;
for (i=0;i<len;i++)
{
if (x[i] > max_corr)
{
id = i;
max_corr = x[i];
}
}
return id;
}
#endif
#ifndef OVERRIDE_FIND_MAX32
static inline int find_max32(celt_word32_t *x, int len)
{
celt_word32_t max_corr=-VERY_LARGE32;
int i, id = 0;
for (i=0;i<len;i++)
{
if (x[i] > max_corr)
{
id = i;
max_corr = x[i];
}
}
return id;
}
#endif
#define FRAC_MUL16(a,b) ((16384+((celt_int32_t)(celt_int16_t)(a)*(celt_int16_t)(b)))>>15)
static inline celt_int16_t bitexact_cos(celt_int16_t x)
{
celt_int32_t tmp;
celt_int16_t x2;
tmp = (4096+((celt_int32_t)(x)*(x)))>>13;
if (tmp > 32767)
tmp = 32767;
x2 = tmp;
x2 = (32767-x2) + FRAC_MUL16(x2, (-7651 + FRAC_MUL16(x2, (8277 + FRAC_MUL16(-626, x2)))));
if (x2 > 32766)
x2 = 32766;
return 1+x2;
}
#ifndef FIXED_POINT
#define celt_sqrt(x) ((float)sqrt(x))
#define celt_psqrt(x) ((float)sqrt(x))
#define celt_rsqrt(x) (1.f/celt_sqrt(x))
#define celt_acos acos
#define celt_exp exp
#define celt_cos_norm(x) (cos((.5f*M_PI)*(x)))
#define celt_atan atan
#define celt_rcp(x) (1.f/(x))
#define celt_div(a,b) ((a)/(b))
#endif
#ifdef FIXED_POINT
#include "os_support.h"
#ifndef OVERRIDE_CELT_MAXABS16
static inline celt_word16_t celt_maxabs16(celt_word16_t *x, int len)
{
int i;
celt_word16_t maxval = 0;
for (i=0;i<len;i++)
maxval = MAX16(maxval, ABS16(x[i]));
return maxval;
}
#endif
/** Integer log in base2. Defined for zero, but not for negative numbers */
static inline celt_int16_t celt_zlog2(celt_word32_t x)
{
return x <= 0 ? 0 : celt_ilog2(x);
}
/** Reciprocal sqrt approximation (Q30 input, Q0 output or equivalent) */
static inline celt_word32_t celt_rsqrt(celt_word32_t x)
{
int k;
celt_word16_t n;
celt_word32_t rt;
const celt_word16_t C[5] = {23126, -11496, 9812, -9097, 4100};
k = celt_ilog2(x)>>1;
x = VSHR32(x, (k-7)<<1);
/* Range of n is [-16384,32767] */
n = x-32768;
rt = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2],
MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, (C[4])))))))));
rt = VSHR32(rt,k);
return rt;
}
/** Sqrt approximation (QX input, QX/2 output) */
static inline celt_word32_t celt_sqrt(celt_word32_t x)
{
int k;
celt_word16_t n;
celt_word32_t rt;
const celt_word16_t C[5] = {23174, 11584, -3011, 1570, -557};
if (x==0)
return 0;
k = (celt_ilog2(x)>>1)-7;
x = VSHR32(x, (k<<1));
n = x-32768;
rt = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2],
MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, (C[4])))))))));
rt = VSHR32(rt,7-k);
return rt;
}
/** Sqrt approximation (QX input, QX/2 output) that assumes that the input is
strictly positive */
static inline celt_word32_t celt_psqrt(celt_word32_t x)
{
int k;
celt_word16_t n;
celt_word32_t rt;
const celt_word16_t C[5] = {23174, 11584, -3011, 1570, -557};
k = (celt_ilog2(x)>>1)-7;
x = VSHR32(x, (k<<1));
n = x-32768;
rt = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2],
MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, (C[4])))))))));
rt = VSHR32(rt,7-k);
return rt;
}
#define L1 32767
#define L2 -7651
#define L3 8277
#define L4 -626
static inline celt_word16_t _celt_cos_pi_2(celt_word16_t x)
{
celt_word16_t x2;
x2 = MULT16_16_P15(x,x);
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
))))))));
}
#undef L1
#undef L2
#undef L3
#undef L4
static inline celt_word16_t celt_cos_norm(celt_word32_t x)
{
x = x&0x0001ffff;
if (x>SHL32(EXTEND32(1), 16))
x = SUB32(SHL32(EXTEND32(1), 17),x);
if (x&0x00007fff)
{
if (x<SHL32(EXTEND32(1), 15))
{
return _celt_cos_pi_2(EXTRACT16(x));
} else {
return NEG32(_celt_cos_pi_2(EXTRACT16(65536-x)));
}
} else {
if (x&0x0000ffff)
return 0;
else if (x&0x0001ffff)
return -32767;
else
return 32767;
}
}
static inline celt_word16_t celt_log2(celt_word32_t x)
{
int i;
celt_word16_t n, frac;
/*-0.41446 0.96093 -0.33981 0.15600 */
const celt_word16_t C[4] = {-6791, 7872, -1392, 319};
if (x==0)
return -32767;
i = celt_ilog2(x);
n = VSHR32(x,i-15)-32768-16384;
frac = ADD16(C[0], MULT16_16_Q14(n, ADD16(C[1], MULT16_16_Q14(n, ADD16(C[2], MULT16_16_Q14(n, (C[3])))))));
/*printf ("%d %d %d %d\n", x, n, ret, SHL16(i-13,8)+SHR16(ret,14-8));*/
return SHL16(i-13,8)+SHR16(frac,14-8);
}
/*
K0 = 1
K1 = log(2)
K2 = 3-4*log(2)
K3 = 3*log(2) - 2
*/
#define D0 16384
#define D1 11356
#define D2 3726
#define D3 1301
/** Base-2 exponential approximation (2^x). (Q11 input, Q16 output) */
static inline celt_word32_t celt_exp2(celt_word16_t x)
{
int integer;
celt_word16_t frac;
integer = SHR16(x,11);
if (integer>14)
return 0x7f000000;
else if (integer < -15)
return 0;
frac = SHL16(x-SHL16(integer,11),3);
frac = ADD16(D0, MULT16_16_Q14(frac, ADD16(D1, MULT16_16_Q14(frac, ADD16(D2 , MULT16_16_Q14(D3,frac))))));
return VSHR32(EXTEND32(frac), -integer-2);
}
/** Reciprocal approximation (Q15 input, Q16 output) */
static inline celt_word32_t celt_rcp(celt_word32_t x)
{
int i;
celt_word16_t n, frac;
const celt_word16_t C[5] = {21848, -7251, 2403, -934, 327};
celt_assert2(x>0, "celt_rcp() only defined for positive values");
i = celt_ilog2(x);
n = VSHR32(x,i-16)-SHL32(EXTEND32(3),15);
frac = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2],
MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, (C[4])))))))));
return VSHR32(EXTEND32(frac),i-16);
}
#define celt_div(a,b) MULT32_32_Q31((celt_word32_t)(a),celt_rcp(b))
#define M1 32767
#define M2 -21
#define M3 -11943
#define M4 4936
static inline celt_word16_t celt_atan01(celt_word16_t x)
{
return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x)))))));
}
#undef M1
#undef M2
#undef M3
#undef M4
static inline celt_word16_t celt_atan2p(celt_word16_t y, celt_word16_t x)
{
if (y < x)
{
celt_word32_t arg;
arg = celt_div(SHL32(EXTEND32(y),15),x);
if (arg >= 32767)
arg = 32767;
return SHR16(celt_atan01(EXTRACT16(arg)),1);
} else {
celt_word32_t arg;
arg = celt_div(SHL32(EXTEND32(x),15),y);
if (arg >= 32767)
arg = 32767;
return 25736-SHR16(celt_atan01(EXTRACT16(arg)),1);
}
}
#endif /* FIXED_POINT */
#endif /* MATHOPS_H */