shithub: sox

ref: b03e0534d7d2ab306b584296bf0af011db85bf55
dir: /amr-wb/decim54.c/

View raw version
/*-------------------------------------------------------------------*
 *                         DECIM54.C                                 *
 *-------------------------------------------------------------------*
 * Decim_12k8   : decimation of 16kHz signal to 12.8kHz.             *
 * Oversamp_16k : oversampling from 12.8kHz to 16kHz.                *
 *-------------------------------------------------------------------*/

#include "typedef.h"
#include "basic_op.h"
#include "acelp.h"
#include "count.h"
#include "cnst.h"

#define FAC4   4
#define FAC5   5
#define INV_FAC5   6554                    /* 1/5 in Q15 */
#define DOWN_FAC  26215                    /* 4/5 in Q15 */
#define UP_FAC    20480                    /* 5/4 in Q14 */

#define NB_COEF_DOWN  15
#define NB_COEF_UP    12

/* Local functions */
static void Down_samp(
     Word16 * sig,                         /* input:  signal to downsampling  */
     Word16 * sig_d,                       /* output: downsampled signal      */
     Word16 L_frame_d                      /* input:  length of output        */
);
static void Up_samp(
     Word16 * sig_d,                       /* input:  signal to oversampling  */
     Word16 * sig_u,                       /* output: oversampled signal      */
     Word16 L_frame                        /* input:  length of output        */
);
static Word16 Interpol(                    /* return result of interpolation */
     Word16 * x,                           /* input vector                   */
     Word16 * fir,                         /* filter coefficient             */
     Word16 frac,                          /* fraction (0..resol)            */
     Word16 resol,                         /* resolution                     */
     Word16 nb_coef                        /* number of coefficients         */
);


/* 1/5 resolution interpolation filter  (in Q14)  */
/* -1.5dB @ 6kHz, -6dB @ 6.4kHz, -10dB @ 6.6kHz, -20dB @ 6.9kHz, -25dB @ 7kHz, -55dB @ 8kHz */

static Word16 fir_up[120] =
{
    -1, -4, -7, -6, 0,
    12, 24, 30, 23, 0,
    -33, -62, -73, -52, 0,
    68, 124, 139, 96, 0,
    -119, -213, -235, -160, 0,
    191, 338, 368, 247, 0,
    -291, -510, -552, -369, 0,
    430, 752, 812, 542, 0,
    -634, -1111, -1204, -809, 0,
    963, 1708, 1881, 1288, 0,
    -1616, -2974, -3432, -2496, 0,
    3792, 8219, 12368, 15317, 16384,
    15317, 12368, 8219, 3792, 0,
    -2496, -3432, -2974, -1616, 0,
    1288, 1881, 1708, 963, 0,
    -809, -1204, -1111, -634, 0,
    542, 812, 752, 430, 0,
    -369, -552, -510, -291, 0,
    247, 368, 338, 191, 0,
    -160, -235, -213, -119, 0,
    96, 139, 124, 68, 0,
    -52, -73, -62, -33, 0,
    23, 30, 24, 12, 0,
    -6, -7, -4, -1, 0
};

static Word16 fir_down[120] =
{            /* table x4/5 */
    -1, -3, -6, -5,
    0, 9, 19, 24,
    18, 0, -26, -50,
    -58, -41, 0, 54,
    99, 111, 77, 0,
    -95, -170, -188, -128,
    0, 153, 270, 294,
    198, 0, -233, -408,
    -441, -295, 0, 344,
    601, 649, 434, 0,
    -507, -888, -964, -647,
    0, 770, 1366, 1505,
    1030, 0, -1293, -2379,
    -2746, -1997, 0, 3034,
    6575, 9894, 12254, 13107,
    12254, 9894, 6575, 3034,
    0, -1997, -2746, -2379,
    -1293, 0, 1030, 1505,
    1366, 770, 0, -647,
    -964, -888, -507, 0,
    434, 649, 601, 344,
    0, -295, -441, -408,
    -233, 0, 198, 294,
    270, 153, 0, -128,
    -188, -170, -95, 0,
    77, 111, 99, 54,
    0, -41, -58, -50,
    -26, 0, 18, 24,
    19, 9, 0, -5,
    -6, -3, -1, 0
};



void Init_Decim_12k8(
     Word16 mem[]                          /* output: memory (2*NB_COEF_DOWN) set to zeros */
)
{
    Set_zero(mem, 2 * NB_COEF_DOWN);
    return;
}

void Decim_12k8(
     Word16 sig16k[],                      /* input:  signal to downsampling  */
     Word16 lg,                            /* input:  length of input         */
     Word16 sig12k8[],                     /* output: decimated signal        */
     Word16 mem[]                          /* in/out: memory (2*NB_COEF_DOWN) */
)
{
    Word16 lg_down;
    Word16 signal[L_FRAME16k + (2 * NB_COEF_DOWN)];

    Copy(mem, signal, 2 * NB_COEF_DOWN);

    Copy(sig16k, signal + (2 * NB_COEF_DOWN), lg);

    lg_down = mult(lg, DOWN_FAC);

    Down_samp(signal + NB_COEF_DOWN, sig12k8, lg_down);

    Copy(signal + lg, mem, 2 * NB_COEF_DOWN);

    return;
}


void Init_Oversamp_16k(
     Word16 mem[]                          /* output: memory (2*NB_COEF_UP) set to zeros  */
)
{
    Set_zero(mem, 2 * NB_COEF_UP);
    return;
}

void Oversamp_16k(
     Word16 sig12k8[],                     /* input:  signal to oversampling  */
     Word16 lg,                            /* input:  length of input         */
     Word16 sig16k[],                      /* output: oversampled signal      */
     Word16 mem[]                          /* in/out: memory (2*NB_COEF_UP)   */
)
{
    Word16 lg_up;
    Word16 signal[L_SUBFR + (2 * NB_COEF_UP)];

    Copy(mem, signal, 2 * NB_COEF_UP);

    Copy(sig12k8, signal + (2 * NB_COEF_UP), lg);

    lg_up = shl(mult(lg, UP_FAC), 1);

    Up_samp(signal + NB_COEF_UP, sig16k, lg_up);

    Copy(signal + lg, mem, 2 * NB_COEF_UP);

    return;
}


static void Down_samp(
     Word16 * sig,                         /* input:  signal to downsampling  */
     Word16 * sig_d,                       /* output: downsampled signal      */
     Word16 L_frame_d                      /* input:  length of output        */
)
{
    Word16 i, j, frac, pos;

    pos = 0;                               move16();  /* position is in Q2 -> 1/4 resolution  */
    for (j = 0; j < L_frame_d; j++)
    {
        i = shr(pos, 2);                   /* integer part     */
        frac = (Word16) (pos & 3);         logic16();  /* fractional part */

        sig_d[j] = Interpol(&sig[i], fir_down, frac, FAC4, NB_COEF_DOWN);       move16();

        pos = add(pos, FAC5);              /* pos + 5/4 */
    }

    return;
}


static void Up_samp(
     Word16 * sig_d,                       /* input:  signal to oversampling  */
     Word16 * sig_u,                       /* output: oversampled signal      */
     Word16 L_frame                        /* input:  length of output        */
)
{
    Word16 i, j, pos, frac;

    pos = 0;                               move16();  /* position with 1/5 resolution */

    for (j = 0; j < L_frame; j++)
    {
        i = mult(pos, INV_FAC5);           /* integer part = pos * 1/5 */
        frac = sub(pos, add(shl(i, 2), i));/* frac = pos - (pos/5)*5   */

        sig_u[j] = Interpol(&sig_d[i], fir_up, frac, FAC5, NB_COEF_UP); move16();

        pos = add(pos, FAC4);              /* position + 4/5 */
    }

    return;
}

/* Fractional interpolation of signal at position (frac/resol) */

static Word16 Interpol(                    /* return result of interpolation */
     Word16 * x,                           /* input vector                   */
     Word16 * fir,                         /* filter coefficient             */
     Word16 frac,                          /* fraction (0..resol)            */
     Word16 resol,                         /* resolution                     */
     Word16 nb_coef                        /* number of coefficients         */
)
{
    Word16 i, k;
    Word32 L_sum;

    x = x - nb_coef + 1;                   move16();

    L_sum = 0L;                            move32();
    for (i = 0, k = sub(sub(resol, 1), frac); i < 2 * nb_coef; i++, k = (Word16) (k + resol))
    {
        L_sum = L_mac(L_sum, x[i], fir[k]);
    }
    L_sum = L_shl(L_sum, 1);               /* saturation can occur here */

    return (round(L_sum));
}