blob: 62e29e7835ac4eda8d74c7374808b2466c2a66f0 [file] [log] [blame]
/*
** Copyright 2003-2010, VisualOn, Inc.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
/***********************************************************************
* File: isp_az.c *
* *
* Description:Compute the LPC coefficients from isp (order=M) *
* *
************************************************************************/
#include "typedef.h"
#include "basic_op.h"
#include "oper_32b.h"
#include "cnst.h"
#define NC (M/2)
#define NC16k (M16k/2)
/* local function */
static void Get_isp_pol(Word16 * isp, Word32 * f, Word16 n);
static void Get_isp_pol_16kHz(Word16 * isp, Word32 * f, Word16 n);
void Isp_Az(
Word16 isp[], /* (i) Q15 : Immittance spectral pairs */
Word16 a[], /* (o) Q12 : predictor coefficients (order = M) */
Word16 m,
Word16 adaptive_scaling /* (i) 0 : adaptive scaling disabled */
/* 1 : adaptive scaling enabled */
)
{
Word32 i, j;
Word16 hi, lo;
Word32 f1[NC16k + 1], f2[NC16k];
Word16 nc;
Word32 t0;
Word16 q, q_sug;
Word32 tmax;
nc = (m >> 1);
if(nc > 8)
{
Get_isp_pol_16kHz(&isp[0], f1, nc);
for (i = 0; i <= nc; i++)
{
f1[i] = f1[i] << 2;
}
} else
Get_isp_pol(&isp[0], f1, nc);
if (nc > 8)
{
Get_isp_pol_16kHz(&isp[1], f2, (nc - 1));
for (i = 0; i <= nc - 1; i++)
{
f2[i] = f2[i] << 2;
}
} else
Get_isp_pol(&isp[1], f2, (nc - 1));
/*-----------------------------------------------------*
* Multiply F2(z) by (1 - z^-2) *
*-----------------------------------------------------*/
for (i = (nc - 1); i > 1; i--)
{
f2[i] = vo_L_sub(f2[i], f2[i - 2]); /* f2[i] -= f2[i-2]; */
}
/*----------------------------------------------------------*
* Scale F1(z) by (1+isp[m-1]) and F2(z) by (1-isp[m-1]) *
*----------------------------------------------------------*/
for (i = 0; i < nc; i++)
{
/* f1[i] *= (1.0 + isp[M-1]); */
hi = f1[i] >> 16;
lo = (f1[i] & 0xffff)>>1;
t0 = Mpy_32_16(hi, lo, isp[m - 1]);
f1[i] = vo_L_add(f1[i], t0);
/* f2[i] *= (1.0 - isp[M-1]); */
hi = f2[i] >> 16;
lo = (f2[i] & 0xffff)>>1;
t0 = Mpy_32_16(hi, lo, isp[m - 1]);
f2[i] = vo_L_sub(f2[i], t0);
}
/*-----------------------------------------------------*
* A(z) = (F1(z)+F2(z))/2 *
* F1(z) is symmetric and F2(z) is antisymmetric *
*-----------------------------------------------------*/
/* a[0] = 1.0; */
a[0] = 4096;
tmax = 1;
for (i = 1, j = m - 1; i < nc; i++, j--)
{
/* a[i] = 0.5*(f1[i] + f2[i]); */
t0 = vo_L_add(f1[i], f2[i]); /* f1[i] + f2[i] */
tmax |= L_abs(t0);
a[i] = (Word16)(vo_L_shr_r(t0, 12)); /* from Q23 to Q12 and * 0.5 */
/* a[j] = 0.5*(f1[i] - f2[i]); */
t0 = vo_L_sub(f1[i], f2[i]); /* f1[i] - f2[i] */
tmax |= L_abs(t0);
a[j] = (Word16)(vo_L_shr_r(t0, 12)); /* from Q23 to Q12 and * 0.5 */
}
/* rescale data if overflow has occured and reprocess the loop */
if(adaptive_scaling == 1)
q = 4 - norm_l(tmax); /* adaptive scaling enabled */
else
q = 0; /* adaptive scaling disabled */
if (q > 0)
{
q_sug = (12 + q);
for (i = 1, j = m - 1; i < nc; i++, j--)
{
/* a[i] = 0.5*(f1[i] + f2[i]); */
t0 = vo_L_add(f1[i], f2[i]); /* f1[i] + f2[i] */
a[i] = (Word16)(vo_L_shr_r(t0, q_sug)); /* from Q23 to Q12 and * 0.5 */
/* a[j] = 0.5*(f1[i] - f2[i]); */
t0 = vo_L_sub(f1[i], f2[i]); /* f1[i] - f2[i] */
a[j] = (Word16)(vo_L_shr_r(t0, q_sug)); /* from Q23 to Q12 and * 0.5 */
}
a[0] = shr(a[0], q);
}
else
{
q_sug = 12;
q = 0;
}
/* a[NC] = 0.5*f1[NC]*(1.0 + isp[M-1]); */
hi = f1[nc] >> 16;
lo = (f1[nc] & 0xffff)>>1;
t0 = Mpy_32_16(hi, lo, isp[m - 1]);
t0 = vo_L_add(f1[nc], t0);
a[nc] = (Word16)(L_shr_r(t0, q_sug)); /* from Q23 to Q12 and * 0.5 */
/* a[m] = isp[m-1]; */
a[m] = vo_shr_r(isp[m - 1], (3 + q)); /* from Q15 to Q12 */
return;
}
/*-----------------------------------------------------------*
* procedure Get_isp_pol: *
* ~~~~~~~~~~~ *
* Find the polynomial F1(z) or F2(z) from the ISPs. *
* This is performed by expanding the product polynomials: *
* *
* F1(z) = product ( 1 - 2 isp_i z^-1 + z^-2 ) *
* i=0,2,4,6,8 *
* F2(z) = product ( 1 - 2 isp_i z^-1 + z^-2 ) *
* i=1,3,5,7 *
* *
* where isp_i are the ISPs in the cosine domain. *
*-----------------------------------------------------------*
* *
* Parameters: *
* isp[] : isp vector (cosine domaine) in Q15 *
* f[] : the coefficients of F1 or F2 in Q23 *
* n : == NC for F1(z); == NC-1 for F2(z) *
*-----------------------------------------------------------*/
static void Get_isp_pol(Word16 * isp, Word32 * f, Word16 n)
{
Word16 hi, lo;
Word32 i, j, t0;
/* All computation in Q23 */
f[0] = vo_L_mult(4096, 1024); /* f[0] = 1.0; in Q23 */
f[1] = vo_L_mult(isp[0], -256); /* f[1] = -2.0*isp[0] in Q23 */
f += 2; /* Advance f pointer */
isp += 2; /* Advance isp pointer */
for (i = 2; i <= n; i++)
{
*f = f[-2];
for (j = 1; j < i; j++, f--)
{
hi = f[-1]>>16;
lo = (f[-1] & 0xffff)>>1;
t0 = Mpy_32_16(hi, lo, *isp); /* t0 = f[-1] * isp */
t0 = t0 << 1;
*f = vo_L_sub(*f, t0); /* *f -= t0 */
*f = vo_L_add(*f, f[-2]); /* *f += f[-2] */
}
*f -= (*isp << 9); /* *f -= isp<<8 */
f += i; /* Advance f pointer */
isp += 2; /* Advance isp pointer */
}
return;
}
static void Get_isp_pol_16kHz(Word16 * isp, Word32 * f, Word16 n)
{
Word16 hi, lo;
Word32 i, j, t0;
/* All computation in Q23 */
f[0] = L_mult(4096, 256); /* f[0] = 1.0; in Q23 */
f[1] = L_mult(isp[0], -64); /* f[1] = -2.0*isp[0] in Q23 */
f += 2; /* Advance f pointer */
isp += 2; /* Advance isp pointer */
for (i = 2; i <= n; i++)
{
*f = f[-2];
for (j = 1; j < i; j++, f--)
{
VO_L_Extract(f[-1], &hi, &lo);
t0 = Mpy_32_16(hi, lo, *isp); /* t0 = f[-1] * isp */
t0 = L_shl2(t0, 1);
*f = L_sub(*f, t0); /* *f -= t0 */
*f = L_add(*f, f[-2]); /* *f += f[-2] */
}
*f = L_msu(*f, *isp, 64); /* *f -= isp<<8 */
f += i; /* Advance f pointer */
isp += 2; /* Advance isp pointer */
}
return;
}