/** * @file ds48to16.c * * * @brief 48kHz -> 16kHz ダウンサンプリング * * * * @brief Down sampling from 48kHz to 16kHz * * * * @author Akinobu LEE * @date Sun Feb 13 16:18:26 2005 * * $Revision: 1.4 $ * */ /* * Copyright (c) 1991-2012 Kawahara Lab., Kyoto University * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology * Copyright (c) 2005-2012 Julius project team, Nagoya Institute of Technology * All rights reserved */ #include #include /// TRUE if use embedded values on header #define USE_HEADER_COEF /// USB device sampling rate #ifdef USE_HEADER_COEF /// filter parameters in header #include "lpfcoef_3to4.h" #include "lpfcoef_2to1.h" #endif /* work area for down sampling */ #define mod(x) ((x) & (DS_RBSIZE -1)) ///< Buffer index cycler #ifdef USE_HEADER_COEF /** * Set 1/2 filter coefficients from header values. * * @param f [out] filter info */ static void load_filter_from_header_2to1(DS_FILTER *f) { int i; /* read the filter coefficients from header file */ for(i=0;i= lpfcoef_2to1_num) break; f->hdn[i] = lpfcoef_2to1[i]; } f->hdn_len = i - 1; } /** * Set 4/2 filter coefficients from header values. * * @param f [out] filter info */ static void load_filter_from_header_3to4(DS_FILTER *f) { int i; /* read the filter coefficients from header file */ for(i=0;i= lpfcoef_3to4_num) break; f->hdn[i] = lpfcoef_3to4[i]; } f->hdn_len = i - 1; } #else /* ~USE_HEADER_COEF */ /** * Read filter coefficients from file. * * @param f [out] filter info * @param coeffile [in] filename */ static boolean load_filter(DS_FILTER *f, char *coeffile) { FILE *fp; static char buf[512]; int i; /* read the filter coefficients */ if ((fp = fopen(coeffile, "r")) == NULL) { jlog("Error: ds48to16: failed to open filter coefficient file \"%s\"\n", coeffile); return FALSE; } for(i=0;ihdn[i] = atof(buf); } fclose(fp); if (i <= 0) { jlog("Error: ds48to16: failed to read filter coefficient from \"%s\"\n", coeffile); return FALSE; } f->hdn_len = i - 1; return TRUE; } #endif /** * Initialize filter values * * @param f [i/o] filter info * @param u [in] up sampling rate * @param d [in] down sampling rate */ static void init_filter(DS_FILTER *f, int d, int u) { f->decrate = d; f->intrate = u; /* set filter starting point */ f->delay = f->hdn_len / (2 * f->decrate); /* reset index */ f->indx = 0; /* reset pointer */ f->bp = 0; /* reset output counter */ f->count = 1; } /** * Store input for FIR filter * * @param f [i/o] filter info * @param in [in] an input sample * */ static void firin(DS_FILTER *f, double in) { f->indx = mod(f->indx - 1); f->rb[f->indx] = in; } /** * Get filtered output from FIR filter * * @param f [i/o] filter info * @param os [in] point * * @return output value */ static double firout(DS_FILTER *f, int os) { double out; int k, l; out = 0.0; for(k = os, l = f->indx ; k <= f->hdn_len; k += f->intrate, l = mod(l + 1)) { out += f->rb[l] * f->hdn[k]; } return(out); } /** * Perform down sampling of input samples. * * @param f [i/o] filter info * @param dst [out] store the resulting samples * @param src [in] input samples * @param len [in] number of input samples * @param maxlen [in] maximum length of dst * * @return the number of samples written to dst, or -1 on errror. * */ static int do_filter(DS_FILTER *f, double *dst, double *src, int len, int maxlen) { int dstlen; int s; int d; int i, k; s = 0; dstlen = 0; while(1) { /* fulfill temporal buffer */ /* at this point, x[0..bp-1] may contain the left samples of last call */ while (f->bp < DS_BUFSIZE) { if (s >= len) break; f->x[f->bp++] = src[s++]; } if (f->bp < DS_BUFSIZE) { /* when reached last of sample, leave the rest in x[] and exit */ break; } /* do conversion from x[0..bp-1] to y[] */ d = 0; for(k=0;kbp;k++) { firin(f, f->x[k]); for(i=0;iintrate;i++) { f->count--; if(f->count == 0) { f->y[d++] = firout(f, i); f->count = f->decrate; } } } /* store the result to dst[] */ if(f->delay) { if(d > f->delay) { /* input samples > delay, store the overed samples and enter no-delay state */ d -= f->delay; for(i=0;i= maxlen) break; dst[dstlen++] = f->y[f->delay + i]; } f->delay = 0; if (dstlen >= maxlen) { jlog("Error: ds48to16: buffer overflow in down sampling, inputs may be lost!\n"); return -1; } } else { /* input samples < delay, decrease delay and wait */ f->delay -= d; } } else { /* no-delay state: store immediately */ for(i=0;i= maxlen) break; dst[dstlen++] = f->y[i]; } if (dstlen >= maxlen) { jlog("Error: ds48to16: buffer overflow in down sampling, inputs may be lost!\n"); return -1; } } /* reset pointer */ f->bp -= DS_BUFSIZE; } return dstlen; } /** * Setup for down sampling * * @return newly allocated buffer for down sampling */ DS_BUFFER * ds48to16_new() { DS_BUFFER *ds; int i; /* define 3 filters: 48kHz --f1(3/4)-> 64kHz --f2(1/2)-> 32kHz --f3(1/2)-> 16kHz */ ds = (DS_BUFFER *)mymalloc(sizeof(DS_BUFFER)); for(i=0;i<3;i++) ds->fir[i] = (DS_FILTER *)mymalloc(sizeof(DS_FILTER)); #ifdef USE_HEADER_COEF /* set from embedded header */ load_filter_from_header_3to4(ds->fir[0]); load_filter_from_header_2to1(ds->fir[1]); load_filter_from_header_2to1(ds->fir[2]); jlog("Stat: ds48to16: loaded FIR filters for down sampling\n"); #else /* read from file */ if (load_filter(ds->fir[0], "lpfcoef.3to4") == FALSE) return FALSE; if (load_filter(ds->fir[1], "lpfcoef.2to1") == FALSE) return FALSE; if (load_filter(ds->fir[2], "lpfcoef.2to1") == FALSE) return FALSE; jlog("Stat: ds48to16: initialize FIR filters for down sampling\n"); #endif init_filter(ds->fir[0], 3, 4); init_filter(ds->fir[1], 2, 1); init_filter(ds->fir[2], 2, 1); ds->buflen = 0; return(ds); } /** * Free the down sampling buffer. * * @param ds [i/o] down sampling buffer to free * */ void ds48to16_free(DS_BUFFER *ds) { int i; if (ds->buflen != 0) { for(i=0;i<4;i++) free(ds->buf[i]); } for(i=0;i<3;i++) free(ds->fir[i]); free(ds); } /** * Perform down sampling of input samples to 1/3. * * @param dst [out] store the resulting samples * @param src [in] input samples * @param srclen [in] number of input samples * @param maxdstlen [in] maximum length of dst * @param ds [i/o] down sampling buffer * * @return the number of samples written to dst, or -1 on errror. * */ int ds48to16(SP16 *dst, SP16 *src, int srclen, int maxdstlen, DS_BUFFER *ds) { int i, n, tmplen; if (ds->buflen == 0) { ds->buflen = srclen * 2; /* longer buffer required for 3/4 upsamling */ for(n=0;n<4;n++) { ds->buf[n] = (double *)mymalloc(sizeof(double) * ds->buflen); } } else if (ds->buflen < srclen * 2) { ds->buflen = srclen * 2; for(n=0;n<4;n++) { ds->buf[n] = (double *)myrealloc(ds->buf[n], sizeof(double) * ds->buflen); } } for(i=0;ibuf[0][i] = src[i]; tmplen = srclen; for(n=0;n<3;n++) { tmplen = do_filter(ds->fir[n], ds->buf[n+1], ds->buf[n], tmplen, ds->buflen); } if (maxdstlen < tmplen) { jlog("Error: ds48to16: down sampled num > required!\n"); return -1; } for(i=0;ibuf[3][i]; return(tmplen); }