Home | History | Annotate | Download | only in src
      1 /*---------------------------------------------------------------------------*
      2  *  filter.c  *
      3  *                                                                           *
      4  *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
      5  *                                                                           *
      6  *  Licensed under the Apache License, Version 2.0 (the 'License');          *
      7  *  you may not use this file except in compliance with the License.         *
      8  *                                                                           *
      9  *  You may obtain a copy of the License at                                  *
     10  *      http://www.apache.org/licenses/LICENSE-2.0                           *
     11  *                                                                           *
     12  *  Unless required by applicable law or agreed to in writing, software      *
     13  *  distributed under the License is distributed on an 'AS IS' BASIS,        *
     14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
     15  *  See the License for the specific language governing permissions and      *
     16  *  limitations under the License.                                           *
     17  *                                                                           *
     18  *---------------------------------------------------------------------------*/
     19 
     20 #define _ROUNDOFF
     21 
     22 /****************************************************************************
     23  * FILENAME
     24  *     pcm44pcm11.c
     25  *
     26  * DESCRIPTION
     27  *
     28  *     Apply FIR filter to 44 kHz raw 16-bit PCM linear audio then
     29  *     downsample to 11 kHz.
     30  ****************************************************************************/
     31 
     32 #include <stdio.h>
     33 #include <stdlib.h>
     34 #include <string.h>
     35 #include <ctype.h>
     36 #include <time.h>
     37 
     38 #include "filter.h"
     39 
     40 /****************************************************************************
     41  *                                 FIR FILTER                               *
     42  ****************************************************************************/
     43 
     44 /* b = firls(120, [0 5000 6000 44000/2]/44000*2, [1 1 0 0]);   */
     45 /* bRounded = round(b*2^15);                                   */
     46 
     47 const typeCoeff ps16FilterCoeff_up1_down4[] = {
     48 
     49         1,      9,     13,     10,     -1,    -16,    -24,    -18,      2,     25,
     50        38,     28,     -2,    -38,    -57,    -42,      3,     55,     81,     60,
     51        -3,    -76,   -113,    -84,      4,    104,    153,    114,     -5,   -138,
     52      -205,   -152,      5,    183,    271,    202,     -6,   -241,   -360,   -269,
     53         6,    321,    482,    364,     -6,   -438,   -667,   -511,      7,    632,
     54       986,    778,     -7,  -1030,  -1704,  -1450,      7,   2451,   5204,   7366,
     55      8185,   7366,   5204,   2451,      7,  -1450,  -1704,  -1030,     -7,    778,
     56       986,    632,      7,   -511,   -667,   -438,     -6,    364,    482,    321,
     57         6,   -269,   -360,   -241,     -6,    202,    271,    183,      5,   -152,
     58      -205,   -138,     -5,    114,    153,    104,      4,    -84,   -113,    -76,
     59        -3,     60,     81,     55,      3,    -42,    -57,    -38,     -2,     28,
     60        38,     25,      2,    -18,    -24,    -16,     -1,     10,     13,      9,
     61         1,
     62 };
     63 unsigned int filter_length = sizeof(ps16FilterCoeff_up1_down4)/sizeof(typeCoeff);
     64 
     65 /****************************************************************************
     66  * FIR_struct *FIR_construct(unsigned int nTaps, FIR_type *pCoeffs)
     67  *
     68  * DESCRIPTION
     69  *     allocate and initialize FIR structure
     70  *
     71  * INPUT
     72  *     nTaps    - length of FIR filter
     73  *     pCoeffs  - pointer to FIR filter coefficients
     74  *     scale    - fixed point scale factor
     75  *
     76  * OUTPUT
     77  *     returns pointer to FIR structure; NULL if error
     78  ****************************************************************************/
     79 FIR_struct* FIR_construct(unsigned int nTaps, const typeCoeff *pCoeffs, int scale, int factor_up, int factor_down)
     80 {
     81 FIR_struct *pFIR;
     82 
     83     if (nTaps == 0)
     84         return NULL;
     85 
     86     pFIR = malloc(sizeof(FIR_struct));
     87     if (pFIR == NULL)
     88         return NULL;
     89 
     90     // alloocate space for delay line use calloc to avoid uninitialized memory
     91     // that causes an audible "pop" at the beginning of audio.  SteveR
     92     pFIR->z = calloc(nTaps * sizeof(typeSample), 1);
     93     if (pFIR->z == NULL)
     94     {
     95         free(pFIR);
     96         return NULL;
     97     }
     98 
     99     pFIR->factor_up   = factor_up;
    100     pFIR->factor_down = factor_down;
    101 
    102     pFIR->state       = 0;
    103     pFIR->h           = pCoeffs;
    104     pFIR->nTaps       = nTaps;
    105     pFIR->scale       = scale;
    106     pFIR->round       = (1 << (scale-1));
    107 
    108     return pFIR;
    109 }
    110 
    111 /****************************************************************************
    112  * int FIR_deconstruct(FIR_struct *pFIR)
    113  *
    114  * DESCRIPTION
    115  *     deallocate FIR structure
    116  *
    117  * INPUT
    118  *     pFIR     - pointer to FIR structure
    119  *
    120  * OUTPUT
    121  *     returns 0 for success; 1 for failure
    122  ****************************************************************************/
    123 
    124 int FIR_deconstruct(FIR_struct *pFIR)
    125 {
    126     if (pFIR == NULL)
    127         return 1;
    128 
    129     if (pFIR->z == NULL)
    130         return 1;
    131 
    132     free(pFIR->z);
    133     free(pFIR);
    134 
    135     return 0;
    136 }
    137 
    138 /****************************************************************************
    139  * void FIR_reset(FIR_struct *pFIR)
    140  *
    141  * DESCRIPTION
    142  *
    143  *     reset FIR state
    144  *
    145  * INPUT
    146  *     pFIR     - pointer to FIR structure
    147  *
    148  * OUTPUT
    149  *     pFIR->state initialized
    150  ****************************************************************************/
    151 
    152 void FIR_reset(FIR_struct *pFIR)
    153 {
    154    pFIR->state = 0;
    155 
    156    memset(pFIR->z, pFIR->nTaps, sizeof(typeSample));
    157 }
    158 
    159 /*****************************************************************************
    160  * FIR_type FIR_downsample(unsigned int nInput, typeSample *pInput,
    161  *                         typeSample *pOutput, FIR_struct *pFIR)
    162  *
    163  * DESCRIPTION
    164  *
    165  *     Apply FIR filter to input data.  If nInput > 1, this will also
    166  *     decimate by a factor of nInput.  That is, the filter will only be
    167  *     evaluated every nInput samples, not at each of the nInput samples.
    168  *
    169  *     Breakup filter computation into 2 parts to avoid doing a wraparound
    170  *     check inside the loop.
    171  *
    172  *     Example:
    173  *
    174  *         pFIR->nTaps   = 8
    175  *         pFIR->state   = 2
    176  *         nInput        = 1
    177  *         *pInput       = s20
    178  *
    179  *      (a) Store new sample(s) in delay buffer z[]
    180  *
    181  *          Since pFIR->state == 2, store new sample s20 at location z[2]
    182  *
    183  *                           *** latest input stored at z[pFIR->state]
    184  *                           *
    185  *            -------------------------------------------------
    186  *          z | s14 | s13 | s20 | s19 | s18 | s17 | s16 | s15 |
    187  *            -------------------------------------------------
    188  *          h | h0  | h1  | h2  | h3  | h4  | h5  | h6  | h7  |
    189  *            -------------------------------------------------
    190  *               0     1     2     3     4     5     6     7
    191  *
    192  *      (b) Update state to point to newest sample, wrap if < 0
    193  *
    194  *          Since nInput == 1, state for newest sample is still 2
    195  *          (otherwise, update state -= nInput-1; wrap by adding nTaps if < 0)
    196  *
    197  *      (c) Accumulate "end part" first
    198  *
    199  *           z: start with latest sample at z[pFIR->state], then advance to right
    200  *           h: start with 1st filter coefficient, then advance to right
    201  *
    202  *          acc = h0*s20 + h1*s19 + h2*s18 + h3*s17 + h4*s16 + h5*s15
    203  *
    204  *      (d) Accumulate "beginning part"
    205 
    206  *           z: start with sample at beginning of delay buffer, then advance
    207  *              to sample before latest one at z[pFIR->state]
    208  *           h: continue with next filter coefficient from step (a)
    209  *
    210  *          acc += (h6*s14 + h7*s13)      FIR filter output
    211  *          *pOutput = acc
    212  *
    213  *      (e) Update FIR state
    214  *
    215  *             state--, wrapping if < 0 to simulate circular buffer
    216  *
    217  * INPUT
    218  *
    219  *     nInput   - number of new input samples; evaluate FIR at this point
    220  *     pInput   - pointer to input sample buffer
    221  *     pOutput  - pointer to output sample buffer
    222  *     pFIR     - pointer to FIR structure
    223  *
    224  * OUTPUT
    225  *
    226  *****************************************************************************/
    227 
    228 void FIR_downsample(unsigned int nInput, typeSample *pInput,
    229                     typeSample *pOutput, FIR_struct *pFIR)
    230 {
    231 typeAccum        accum;
    232 typeCoeff const *ph;      // pointer to coefficients
    233 typeSample      *pz;      // pointer to delay line
    234 typeSample      *pz_beg;  // pointer to beginning of delay line
    235 typeSample      *pz_end;  // pointer to last slot in delay line
    236 unsigned int     nTaps_end;
    237 unsigned int     nTaps_beg;
    238 unsigned int     i;
    239 
    240     // initialize
    241     accum  = 0;
    242     ph     = pFIR->h;                    // point to coefficients
    243     pz_beg = pFIR->z;                    // start of delay line
    244     pz_end = pFIR->z + pFIR->nTaps - 1;  // end of delay line
    245 
    246     // (a) Store new input samples in delay line (circular addressing would help a lot)
    247     pz = pFIR->z + pFIR->state;      // point to next empty slot in delay line
    248     for (i = 0; i < nInput; i++)
    249     {
    250        *pz-- = *pInput++;
    251        if (pz < pz_beg)
    252           pz = pz_end;    // wrap around (circular buffer)
    253     }
    254 
    255     // (b) adjust state to reflect addition of samples
    256     pFIR->state -= nInput-1;
    257     if (pFIR->state < 0)
    258        pFIR->state += pFIR->nTaps;  // wrap
    259 
    260     // (c) Accumulate "end part"
    261     pz = pFIR->z + pFIR->state;
    262     nTaps_end = pFIR->nTaps - pFIR->state;
    263     for (i = 0; i < nTaps_end; i++)
    264     {
    265         accum += *ph++ * *pz++;
    266     }
    267 
    268     // (d) Accumulate "beginning part"
    269     pz = pFIR->z;
    270     nTaps_beg = pFIR->state;
    271     for (i = 0; i < nTaps_beg; i++)
    272     {
    273         accum += *ph++ * *pz++;
    274     }
    275 
    276     // (e) Update FIR state for next batch of incoming samples
    277     pFIR->state--;
    278     if (pFIR->state < 0)
    279        pFIR->state += pFIR->nTaps;  // wrap
    280 
    281 #ifdef _ROUNDOFF
    282     if (accum >= 0)
    283        accum += pFIR->round;
    284     else
    285        accum -= pFIR->round;
    286 #endif
    287 
    288     *pOutput = (typeSample) (accum >> pFIR->scale);
    289 }
    290 
    291 #if 0
    292 /*****************************************************************************
    293  * main
    294  *****************************************************************************/
    295 
    296 int main(int argc, char* argv[])
    297 {
    298 FILE         *fpInputSamples;    // input raw PCM file
    299 FILE         *fpOutputSamples;   // output raw PCM file
    300 
    301 typeSample    s_in[FACTOR_DOWN]; // input samples
    302 typeSample    s_out;             // filtered sample
    303 FIR_struct   *pFIR;              // pointer to FIR structure
    304 int           nSampleGet;        // number of samples to read from input speech file
    305 int           nSampleRead;       // number of samples read from input speech file
    306 unsigned long nSampleTot;        // total number of samples read so far
    307 time_t        t0;                // time upon entry
    308 
    309    t0 = time(NULL);     // get time upon entry
    310 
    311     // Check Command-line Parameters
    312     if (argc != 3)
    313     {
    314         fprintf(stderr, "pcm44pcm11 v1.0\n");
    315         fprintf(stderr, "  - downsamples 44 kHz to 11 kHz (16-bit PCM, Intel byte order)\n");
    316         fprintf(stderr, "Usage: pcm44pcm11 <input PCM file> <output PCM file>\n\n");
    317         return 0;
    318     }
    319 
    320     // Open input sample file
    321     if ((fpInputSamples = fopen(argv[1], "rb")) == NULL)
    322     {
    323         fprintf(stderr, "Error reading input sample file: %s\n\n", argv[1]);
    324         exit(1);                                // abnormal exit
    325     }
    326 
    327     // Create output sample file
    328     if ((fpOutputSamples = fopen(argv[2], "wb")) == NULL)
    329     {
    330         fprintf(stderr, "Error creating output file: %s\n\n", argv[2]);
    331         fclose(fpInputSamples);
    332         exit(1);                                // abnormal exit
    333     }
    334 
    335    // **************************************************************************************
    336    // Begin filtering...
    337    // **************************************************************************************
    338 
    339    pFIR = FIR_construct(filter_length,
    340                         ps16FilterCoeff_up1_down4,
    341                         u16ScaleFilterCoeff_up1_down4,
    342                         FACTOR_UP,
    343                         FACTOR_DOWN);
    344 
    345    fprintf(stdout, "Filtering...\n");
    346 
    347    FIR_reset(pFIR);
    348 
    349    nSampleTot = 0;
    350    while (!feof(fpInputSamples))
    351    {
    352       nSampleGet = pFIR->factor_down;   // if downsampling, only filter every factor_down samples
    353       nSampleRead = fread(s_in, sizeof(typeSample), nSampleGet, fpInputSamples);
    354       if (feof(fpInputSamples) || (nSampleRead != nSampleGet))
    355          break;   // done with input file
    356       nSampleTot += nSampleRead;
    357 
    358       FIR_downsample(nSampleRead, s_in, &s_out, pFIR);
    359 
    360       if (nSampleTot < pFIR->nTaps)
    361          continue;   // wait until delay buffer has been filled to skip transients
    362 
    363       fwrite(&s_out, sizeof(typeSample), 1, fpOutputSamples);
    364    }
    365 
    366    fprintf(stdout, "\n\nTime elapsed: %d sec\n", time(NULL)-t0);
    367 
    368    FIR_deconstruct(pFIR);
    369 
    370    fclose(fpInputSamples);
    371    fclose(fpOutputSamples);
    372 
    373    return 0;
    374 }
    375 
    376 #endif
    377