shun_iwasawa a35b8f
/*
shun_iwasawa a35b8f
Copyright (c) 2003-2004, Mark Borgerding
shun_iwasawa a35b8f
shun_iwasawa a35b8f
All rights reserved.
shun_iwasawa a35b8f
shun_iwasawa a35b8f
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
shun_iwasawa a35b8f
    * 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.
shun_iwasawa a35b8f
    * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
shun_iwasawa a35b8f
shun_iwasawa a35b8f
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 COPYRIGHT OWNER 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.
shun_iwasawa a35b8f
*/
shun_iwasawa a35b8f
shun_iwasawa a35b8f
#include "_kiss_fft_guts.h"
shun_iwasawa a35b8f
shun_iwasawa a35b8f
shun_iwasawa a35b8f
/*
shun_iwasawa a35b8f
 Some definitions that allow real or complex filtering
shun_iwasawa a35b8f
*/
shun_iwasawa a35b8f
#ifdef REAL_FASTFIR
shun_iwasawa a35b8f
#define MIN_FFT_LEN 2048
shun_iwasawa a35b8f
#include "kiss_fftr.h"
shun_iwasawa a35b8f
typedef kiss_fft_scalar kffsamp_t;
shun_iwasawa a35b8f
typedef kiss_fftr_cfg kfcfg_t;
shun_iwasawa a35b8f
#define FFT_ALLOC kiss_fftr_alloc
shun_iwasawa a35b8f
#define FFTFWD kiss_fftr
shun_iwasawa a35b8f
#define FFTINV kiss_fftri
shun_iwasawa a35b8f
#else
shun_iwasawa a35b8f
#define MIN_FFT_LEN 1024
shun_iwasawa a35b8f
typedef kiss_fft_cpx kffsamp_t;
shun_iwasawa a35b8f
typedef kiss_fft_cfg kfcfg_t;
shun_iwasawa a35b8f
#define FFT_ALLOC kiss_fft_alloc
shun_iwasawa a35b8f
#define FFTFWD kiss_fft
shun_iwasawa a35b8f
#define FFTINV kiss_fft
shun_iwasawa a35b8f
#endif
shun_iwasawa a35b8f
shun_iwasawa a35b8f
typedef struct kiss_fastfir_state *kiss_fastfir_cfg;
shun_iwasawa a35b8f
shun_iwasawa a35b8f
shun_iwasawa a35b8f
shun_iwasawa a35b8f
kiss_fastfir_cfg kiss_fastfir_alloc(const kffsamp_t * imp_resp,size_t n_imp_resp,
shun_iwasawa a35b8f
        size_t * nfft,void * mem,size_t*lenmem);
shun_iwasawa a35b8f
shun_iwasawa a35b8f
/* see do_file_filter for usage */
shun_iwasawa a35b8f
size_t kiss_fastfir( kiss_fastfir_cfg cfg, kffsamp_t * inbuf, kffsamp_t * outbuf, size_t n, size_t *offset);
shun_iwasawa a35b8f
shun_iwasawa a35b8f
shun_iwasawa a35b8f
shun_iwasawa a35b8f
static int verbose=0;
shun_iwasawa a35b8f
shun_iwasawa a35b8f
shun_iwasawa a35b8f
struct kiss_fastfir_state{
shun_iwasawa a35b8f
    size_t nfft;
shun_iwasawa a35b8f
    size_t ngood;
shun_iwasawa a35b8f
    kfcfg_t fftcfg;
shun_iwasawa a35b8f
    kfcfg_t ifftcfg;
shun_iwasawa a35b8f
    kiss_fft_cpx * fir_freq_resp;
shun_iwasawa a35b8f
    kiss_fft_cpx * freqbuf;
shun_iwasawa a35b8f
    size_t n_freq_bins;
shun_iwasawa a35b8f
    kffsamp_t * tmpbuf;
shun_iwasawa a35b8f
};
shun_iwasawa a35b8f
shun_iwasawa a35b8f
shun_iwasawa a35b8f
kiss_fastfir_cfg kiss_fastfir_alloc(
shun_iwasawa a35b8f
        const kffsamp_t * imp_resp,size_t n_imp_resp,
shun_iwasawa a35b8f
        size_t *pnfft, /* if <= 0, an appropriate size will be chosen */
shun_iwasawa a35b8f
        void * mem,size_t*lenmem)
shun_iwasawa a35b8f
{
shun_iwasawa a35b8f
    kiss_fastfir_cfg st = NULL;
shun_iwasawa a35b8f
    size_t len_fftcfg,len_ifftcfg;
shun_iwasawa a35b8f
    size_t memneeded = sizeof(struct kiss_fastfir_state);
shun_iwasawa a35b8f
    char * ptr;
shun_iwasawa a35b8f
    size_t i;
shun_iwasawa a35b8f
    size_t nfft=0;
shun_iwasawa a35b8f
    float scale;
shun_iwasawa a35b8f
    int n_freq_bins;
shun_iwasawa a35b8f
    if (pnfft)
shun_iwasawa a35b8f
        nfft=*pnfft;
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    if (nfft<=0) {
shun_iwasawa a35b8f
        /* determine fft size as next power of two at least 2x 
shun_iwasawa a35b8f
         the impulse response length*/
shun_iwasawa a35b8f
        i=n_imp_resp-1;
shun_iwasawa a35b8f
        nfft=2;
shun_iwasawa a35b8f
        do{
shun_iwasawa a35b8f
             nfft<<=1;
shun_iwasawa a35b8f
        }while (i>>=1);
shun_iwasawa a35b8f
#ifdef MIN_FFT_LEN
shun_iwasawa a35b8f
        if ( nfft < MIN_FFT_LEN )
shun_iwasawa a35b8f
            nfft=MIN_FFT_LEN;
shun_iwasawa a35b8f
#endif        
shun_iwasawa a35b8f
    }
shun_iwasawa a35b8f
    if (pnfft)
shun_iwasawa a35b8f
        *pnfft = nfft;
shun_iwasawa a35b8f
shun_iwasawa a35b8f
#ifdef REAL_FASTFIR
shun_iwasawa a35b8f
    n_freq_bins = nfft/2 + 1;
shun_iwasawa a35b8f
#else
shun_iwasawa a35b8f
    n_freq_bins = nfft;
shun_iwasawa a35b8f
#endif
shun_iwasawa a35b8f
    /*fftcfg*/
shun_iwasawa a35b8f
    FFT_ALLOC (nfft, 0, NULL, &len_fftcfg);
shun_iwasawa a35b8f
    memneeded += len_fftcfg;  
shun_iwasawa a35b8f
    /*ifftcfg*/
shun_iwasawa a35b8f
    FFT_ALLOC (nfft, 1, NULL, &len_ifftcfg);
shun_iwasawa a35b8f
    memneeded += len_ifftcfg;  
shun_iwasawa a35b8f
    /* tmpbuf */
shun_iwasawa a35b8f
    memneeded += sizeof(kffsamp_t) * nfft;
shun_iwasawa a35b8f
    /* fir_freq_resp */
shun_iwasawa a35b8f
    memneeded += sizeof(kiss_fft_cpx) * n_freq_bins;
shun_iwasawa a35b8f
    /* freqbuf */
shun_iwasawa a35b8f
    memneeded += sizeof(kiss_fft_cpx) * n_freq_bins;
shun_iwasawa a35b8f
    
shun_iwasawa a35b8f
    if (lenmem == NULL) {
shun_iwasawa a35b8f
        st = (kiss_fastfir_cfg) malloc (memneeded);
shun_iwasawa a35b8f
    } else {
shun_iwasawa a35b8f
        if (*lenmem >= memneeded)
shun_iwasawa a35b8f
            st = (kiss_fastfir_cfg) mem;
shun_iwasawa a35b8f
        *lenmem = memneeded;
shun_iwasawa a35b8f
    }
shun_iwasawa a35b8f
    if (!st)
shun_iwasawa a35b8f
        return NULL;
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    st->nfft = nfft;
shun_iwasawa a35b8f
    st->ngood = nfft - n_imp_resp + 1;
shun_iwasawa a35b8f
    st->n_freq_bins = n_freq_bins;
shun_iwasawa a35b8f
    ptr=(char*)(st+1);
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    st->fftcfg = (kfcfg_t)ptr;
shun_iwasawa a35b8f
    ptr += len_fftcfg;
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    st->ifftcfg = (kfcfg_t)ptr;
shun_iwasawa a35b8f
    ptr += len_ifftcfg;
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    st->tmpbuf = (kffsamp_t*)ptr;
shun_iwasawa a35b8f
    ptr += sizeof(kffsamp_t) * nfft;
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    st->freqbuf = (kiss_fft_cpx*)ptr;
shun_iwasawa a35b8f
    ptr += sizeof(kiss_fft_cpx) * n_freq_bins;
shun_iwasawa a35b8f
    
shun_iwasawa a35b8f
    st->fir_freq_resp = (kiss_fft_cpx*)ptr;
shun_iwasawa a35b8f
    ptr += sizeof(kiss_fft_cpx) * n_freq_bins;
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    FFT_ALLOC (nfft,0,st->fftcfg , &len_fftcfg);
shun_iwasawa a35b8f
    FFT_ALLOC (nfft,1,st->ifftcfg , &len_ifftcfg);
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    memset(st->tmpbuf,0,sizeof(kffsamp_t)*nfft);
shun_iwasawa a35b8f
    /*zero pad in the middle to left-rotate the impulse response 
shun_iwasawa a35b8f
      This puts the scrap samples at the end of the inverse fft'd buffer */
shun_iwasawa a35b8f
    st->tmpbuf[0] = imp_resp[ n_imp_resp - 1 ];
shun_iwasawa a35b8f
    for (i=0;i
shun_iwasawa a35b8f
        st->tmpbuf[ nfft - n_imp_resp + 1 + i ] = imp_resp[ i ];
shun_iwasawa a35b8f
    }
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    FFTFWD(st->fftcfg,st->tmpbuf,st->fir_freq_resp);
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    /* TODO: this won't work for fixed point */
shun_iwasawa a35b8f
    scale = 1.0 / st->nfft;
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    for ( i=0; i < st->n_freq_bins; ++i ) {
shun_iwasawa a35b8f
#ifdef USE_SIMD
shun_iwasawa a35b8f
        st->fir_freq_resp[i].r *= _mm_set1_ps(scale);
shun_iwasawa a35b8f
        st->fir_freq_resp[i].i *= _mm_set1_ps(scale);
shun_iwasawa a35b8f
#else
shun_iwasawa a35b8f
        st->fir_freq_resp[i].r *= scale;
shun_iwasawa a35b8f
        st->fir_freq_resp[i].i *= scale;
shun_iwasawa a35b8f
#endif
shun_iwasawa a35b8f
    }
shun_iwasawa a35b8f
    return st;
shun_iwasawa a35b8f
}
shun_iwasawa a35b8f
shun_iwasawa a35b8f
static void fastconv1buf(const kiss_fastfir_cfg st,const kffsamp_t * in,kffsamp_t * out)
shun_iwasawa a35b8f
{
shun_iwasawa a35b8f
    size_t i;
shun_iwasawa a35b8f
    /* multiply the frequency response of the input signal by
shun_iwasawa a35b8f
     that of the fir filter*/
shun_iwasawa a35b8f
    FFTFWD( st->fftcfg, in , st->freqbuf );
shun_iwasawa a35b8f
    for ( i=0; i<st->n_freq_bins; ++i ) {</st->
shun_iwasawa a35b8f
        kiss_fft_cpx tmpsamp; 
shun_iwasawa a35b8f
        C_MUL(tmpsamp,st->freqbuf[i],st->fir_freq_resp[i]);
shun_iwasawa a35b8f
        st->freqbuf[i] = tmpsamp;
shun_iwasawa a35b8f
    }
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    /* perform the inverse fft*/
shun_iwasawa a35b8f
    FFTINV(st->ifftcfg,st->freqbuf,out);
shun_iwasawa a35b8f
}
shun_iwasawa a35b8f
shun_iwasawa a35b8f
/* n : the size of inbuf and outbuf in samples
shun_iwasawa a35b8f
   return value: the number of samples completely processed
shun_iwasawa a35b8f
   n-retval samples should be copied to the front of the next input buffer */
shun_iwasawa a35b8f
static size_t kff_nocopy(
shun_iwasawa a35b8f
        kiss_fastfir_cfg st,
shun_iwasawa a35b8f
        const kffsamp_t * inbuf, 
shun_iwasawa a35b8f
        kffsamp_t * outbuf,
shun_iwasawa a35b8f
        size_t n)
shun_iwasawa a35b8f
{
shun_iwasawa a35b8f
    size_t norig=n;
shun_iwasawa a35b8f
    while (n >= st->nfft ) {
shun_iwasawa a35b8f
        fastconv1buf(st,inbuf,outbuf);
shun_iwasawa a35b8f
        inbuf += st->ngood;
shun_iwasawa a35b8f
        outbuf += st->ngood;
shun_iwasawa a35b8f
        n -= st->ngood;
shun_iwasawa a35b8f
    }
shun_iwasawa a35b8f
    return norig - n;
shun_iwasawa a35b8f
}
shun_iwasawa a35b8f
shun_iwasawa a35b8f
static
shun_iwasawa a35b8f
size_t kff_flush(kiss_fastfir_cfg st,const kffsamp_t * inbuf,kffsamp_t * outbuf,size_t n)
shun_iwasawa a35b8f
{
shun_iwasawa a35b8f
    size_t zpad=0,ntmp;
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    ntmp = kff_nocopy(st,inbuf,outbuf,n);
shun_iwasawa a35b8f
    n -= ntmp;
shun_iwasawa a35b8f
    inbuf += ntmp;
shun_iwasawa a35b8f
    outbuf += ntmp;
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    zpad = st->nfft - n;
shun_iwasawa a35b8f
    memset(st->tmpbuf,0,sizeof(kffsamp_t)*st->nfft );
shun_iwasawa a35b8f
    memcpy(st->tmpbuf,inbuf,sizeof(kffsamp_t)*n );
shun_iwasawa a35b8f
    
shun_iwasawa a35b8f
    fastconv1buf(st,st->tmpbuf,st->tmpbuf);
shun_iwasawa a35b8f
    
shun_iwasawa a35b8f
    memcpy(outbuf,st->tmpbuf,sizeof(kffsamp_t)*( st->ngood - zpad ));
shun_iwasawa a35b8f
    return ntmp + st->ngood - zpad;
shun_iwasawa a35b8f
}
shun_iwasawa a35b8f
shun_iwasawa a35b8f
size_t kiss_fastfir(
shun_iwasawa a35b8f
        kiss_fastfir_cfg vst,
shun_iwasawa a35b8f
        kffsamp_t * inbuf,
shun_iwasawa a35b8f
        kffsamp_t * outbuf,
shun_iwasawa a35b8f
        size_t n_new,
shun_iwasawa a35b8f
        size_t *offset)
shun_iwasawa a35b8f
{
shun_iwasawa a35b8f
    size_t ntot = n_new + *offset;
shun_iwasawa a35b8f
    if (n_new==0) {
shun_iwasawa a35b8f
        return kff_flush(vst,inbuf,outbuf,ntot);
shun_iwasawa a35b8f
    }else{
shun_iwasawa a35b8f
        size_t nwritten = kff_nocopy(vst,inbuf,outbuf,ntot);
shun_iwasawa a35b8f
        *offset = ntot - nwritten;
shun_iwasawa a35b8f
        /*save the unused or underused samples at the front of the input buffer */
shun_iwasawa a35b8f
        memcpy( inbuf , inbuf+nwritten , *offset * sizeof(kffsamp_t) );
shun_iwasawa a35b8f
        return nwritten;
shun_iwasawa a35b8f
    }
shun_iwasawa a35b8f
}
shun_iwasawa a35b8f
shun_iwasawa a35b8f
#ifdef FAST_FILT_UTIL
shun_iwasawa a35b8f
#include <unistd.h></unistd.h>
shun_iwasawa a35b8f
#include <sys types.h=""></sys>
shun_iwasawa a35b8f
#include <sys mman.h=""></sys>
shun_iwasawa a35b8f
#include <assert.h></assert.h>
shun_iwasawa a35b8f
shun_iwasawa a35b8f
static
shun_iwasawa a35b8f
void direct_file_filter(
shun_iwasawa a35b8f
        FILE * fin,
shun_iwasawa a35b8f
        FILE * fout,
shun_iwasawa a35b8f
        const kffsamp_t * imp_resp,
shun_iwasawa a35b8f
        size_t n_imp_resp)
shun_iwasawa a35b8f
{
shun_iwasawa a35b8f
    size_t nlag = n_imp_resp - 1;
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    const kffsamp_t *tmph;
shun_iwasawa a35b8f
    kffsamp_t *buf, *circbuf;
shun_iwasawa a35b8f
    kffsamp_t outval;
shun_iwasawa a35b8f
    size_t nread;
shun_iwasawa a35b8f
    size_t nbuf;
shun_iwasawa a35b8f
    size_t oldestlag = 0;
shun_iwasawa a35b8f
    size_t k, tap;
shun_iwasawa a35b8f
#ifndef REAL_FASTFIR
shun_iwasawa a35b8f
    kffsamp_t tmp;
shun_iwasawa a35b8f
#endif    
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    nbuf = 4096;
shun_iwasawa a35b8f
    buf = (kffsamp_t *) malloc ( sizeof (kffsamp_t) * nbuf);
shun_iwasawa a35b8f
    circbuf = (kffsamp_t *) malloc (sizeof (kffsamp_t) * nlag);
shun_iwasawa a35b8f
    if (!circbuf || !buf) {
shun_iwasawa a35b8f
        perror("circbuf allocation");
shun_iwasawa a35b8f
        exit(1);
shun_iwasawa a35b8f
    }
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    if ( fread (circbuf, sizeof (kffsamp_t), nlag, fin) !=  nlag ) {
shun_iwasawa a35b8f
        perror ("insufficient data to overcome transient");
shun_iwasawa a35b8f
        exit (1);
shun_iwasawa a35b8f
    }
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    do {
shun_iwasawa a35b8f
        nread = fread (buf, sizeof (kffsamp_t), nbuf, fin);
shun_iwasawa a35b8f
        if (nread <= 0)
shun_iwasawa a35b8f
            break;
shun_iwasawa a35b8f
shun_iwasawa a35b8f
        for (k = 0; k < nread; ++k) {
shun_iwasawa a35b8f
            tmph = imp_resp+nlag;
shun_iwasawa a35b8f
#ifdef REAL_FASTFIR
shun_iwasawa a35b8f
# ifdef USE_SIMD
shun_iwasawa a35b8f
            outval = _mm_set1_ps(0);
shun_iwasawa a35b8f
#else
shun_iwasawa a35b8f
            outval = 0;
shun_iwasawa a35b8f
#endif
shun_iwasawa a35b8f
            for (tap = oldestlag; tap < nlag; ++tap)
shun_iwasawa a35b8f
                outval += circbuf[tap] * *tmph--;
shun_iwasawa a35b8f
            for (tap = 0; tap < oldestlag; ++tap)
shun_iwasawa a35b8f
                outval += circbuf[tap] * *tmph--;
shun_iwasawa a35b8f
            outval += buf[k] * *tmph;
shun_iwasawa a35b8f
#else
shun_iwasawa a35b8f
# ifdef USE_SIMD
shun_iwasawa a35b8f
            outval.r = outval.i = _mm_set1_ps(0);
shun_iwasawa a35b8f
#else            
shun_iwasawa a35b8f
            outval.r = outval.i = 0;
shun_iwasawa a35b8f
#endif            
shun_iwasawa a35b8f
            for (tap = oldestlag; tap < nlag; ++tap){
shun_iwasawa a35b8f
                C_MUL(tmp,circbuf[tap],*tmph);
shun_iwasawa a35b8f
                --tmph;
shun_iwasawa a35b8f
                C_ADDTO(outval,tmp);
shun_iwasawa a35b8f
            }
shun_iwasawa a35b8f
            
shun_iwasawa a35b8f
            for (tap = 0; tap < oldestlag; ++tap) {
shun_iwasawa a35b8f
                C_MUL(tmp,circbuf[tap],*tmph);
shun_iwasawa a35b8f
                --tmph;
shun_iwasawa a35b8f
                C_ADDTO(outval,tmp);
shun_iwasawa a35b8f
            }
shun_iwasawa a35b8f
            C_MUL(tmp,buf[k],*tmph);
shun_iwasawa a35b8f
            C_ADDTO(outval,tmp);
shun_iwasawa a35b8f
#endif
shun_iwasawa a35b8f
shun_iwasawa a35b8f
            circbuf[oldestlag++] = buf[k];
shun_iwasawa a35b8f
            buf[k] = outval;
shun_iwasawa a35b8f
shun_iwasawa a35b8f
            if (oldestlag == nlag)
shun_iwasawa a35b8f
                oldestlag = 0;
shun_iwasawa a35b8f
        }
shun_iwasawa a35b8f
shun_iwasawa a35b8f
        if (fwrite (buf, sizeof (buf[0]), nread, fout) != nread) {
shun_iwasawa a35b8f
            perror ("short write");
shun_iwasawa a35b8f
            exit (1);
shun_iwasawa a35b8f
        }
shun_iwasawa a35b8f
    } while (nread);
shun_iwasawa a35b8f
    free (buf);
shun_iwasawa a35b8f
    free (circbuf);
shun_iwasawa a35b8f
}
shun_iwasawa a35b8f
shun_iwasawa a35b8f
static
shun_iwasawa a35b8f
void do_file_filter(
shun_iwasawa a35b8f
        FILE * fin,
shun_iwasawa a35b8f
        FILE * fout,
shun_iwasawa a35b8f
        const kffsamp_t * imp_resp,
shun_iwasawa a35b8f
        size_t n_imp_resp,
shun_iwasawa a35b8f
        size_t nfft )
shun_iwasawa a35b8f
{
shun_iwasawa a35b8f
    int fdout;
shun_iwasawa a35b8f
    size_t n_samps_buf;
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    kiss_fastfir_cfg cfg;
shun_iwasawa a35b8f
    kffsamp_t *inbuf,*outbuf;
shun_iwasawa a35b8f
    int nread,nwrite;
shun_iwasawa a35b8f
    size_t idx_inbuf;
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    fdout = fileno(fout);
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    cfg=kiss_fastfir_alloc(imp_resp,n_imp_resp,&nfft,0,0);
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    /* use length to minimize buffer shift*/
shun_iwasawa a35b8f
    n_samps_buf = 8*4096/sizeof(kffsamp_t); 
shun_iwasawa a35b8f
    n_samps_buf = nfft + 4*(nfft-n_imp_resp+1);
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    if (verbose) fprintf(stderr,"bufsize=%d\n",(int)(sizeof(kffsamp_t)*n_samps_buf) );
shun_iwasawa a35b8f
     
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    /*allocate space and initialize pointers */
shun_iwasawa a35b8f
    inbuf = (kffsamp_t*)malloc(sizeof(kffsamp_t)*n_samps_buf);
shun_iwasawa a35b8f
    outbuf = (kffsamp_t*)malloc(sizeof(kffsamp_t)*n_samps_buf);
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    idx_inbuf=0;
shun_iwasawa a35b8f
    do{
shun_iwasawa a35b8f
        /* start reading at inbuf[idx_inbuf] */
shun_iwasawa a35b8f
        nread = fread( inbuf + idx_inbuf, sizeof(kffsamp_t), n_samps_buf - idx_inbuf,fin );
shun_iwasawa a35b8f
shun_iwasawa a35b8f
        /* If nread==0, then this is a flush.
shun_iwasawa a35b8f
            The total number of samples in input is idx_inbuf + nread . */
shun_iwasawa a35b8f
        nwrite = kiss_fastfir(cfg, inbuf, outbuf,nread,&idx_inbuf) * sizeof(kffsamp_t);
shun_iwasawa a35b8f
        /* kiss_fastfir moved any unused samples to the front of inbuf and updated idx_inbuf */
shun_iwasawa a35b8f
shun_iwasawa a35b8f
        if ( write(fdout, outbuf, nwrite) != nwrite ) {
shun_iwasawa a35b8f
            perror("short write");
shun_iwasawa a35b8f
            exit(1);
shun_iwasawa a35b8f
        }
shun_iwasawa a35b8f
    }while ( nread );
shun_iwasawa a35b8f
    free(cfg);
shun_iwasawa a35b8f
    free(inbuf);
shun_iwasawa a35b8f
    free(outbuf);
shun_iwasawa a35b8f
}
shun_iwasawa a35b8f
shun_iwasawa a35b8f
int main(int argc,char**argv)
shun_iwasawa a35b8f
{
shun_iwasawa a35b8f
    kffsamp_t * h;
shun_iwasawa a35b8f
    int use_direct=0;
shun_iwasawa a35b8f
    size_t nh,nfft=0;
shun_iwasawa a35b8f
    FILE *fin=stdin;
shun_iwasawa a35b8f
    FILE *fout=stdout;
shun_iwasawa a35b8f
    FILE *filtfile=NULL;
shun_iwasawa a35b8f
    while (1) {
shun_iwasawa a35b8f
        int c=getopt(argc,argv,"n:h:i:o:vd");
shun_iwasawa a35b8f
        if (c==-1) break;
shun_iwasawa a35b8f
        switch (c) {
shun_iwasawa a35b8f
            case 'v':
shun_iwasawa a35b8f
                verbose=1;
shun_iwasawa a35b8f
                break;
shun_iwasawa a35b8f
            case 'n':
shun_iwasawa a35b8f
                nfft=atoi(optarg);
shun_iwasawa a35b8f
                break;
shun_iwasawa a35b8f
            case 'i':
shun_iwasawa a35b8f
                fin = fopen(optarg,"rb");
shun_iwasawa a35b8f
                if (fin==NULL) {
shun_iwasawa a35b8f
                    perror(optarg);
shun_iwasawa a35b8f
                    exit(1);
shun_iwasawa a35b8f
                }
shun_iwasawa a35b8f
                break;
shun_iwasawa a35b8f
            case 'o':
shun_iwasawa a35b8f
                fout = fopen(optarg,"w+b");
shun_iwasawa a35b8f
                if (fout==NULL) {
shun_iwasawa a35b8f
                    perror(optarg);
shun_iwasawa a35b8f
                    exit(1);
shun_iwasawa a35b8f
                }
shun_iwasawa a35b8f
                break;
shun_iwasawa a35b8f
            case 'h':
shun_iwasawa a35b8f
                filtfile = fopen(optarg,"rb");
shun_iwasawa a35b8f
                if (filtfile==NULL) {
shun_iwasawa a35b8f
                    perror(optarg);
shun_iwasawa a35b8f
                    exit(1);
shun_iwasawa a35b8f
                }
shun_iwasawa a35b8f
                break;
shun_iwasawa a35b8f
            case 'd':
shun_iwasawa a35b8f
                use_direct=1;
shun_iwasawa a35b8f
                break;
shun_iwasawa a35b8f
            case '?':
shun_iwasawa a35b8f
                     fprintf(stderr,"usage options:\n"
shun_iwasawa a35b8f
                            "\t-n nfft: fft size to use\n"
shun_iwasawa a35b8f
                            "\t-d : use direct FIR filtering, not fast convolution\n"
shun_iwasawa a35b8f
                            "\t-i filename: input file\n"
shun_iwasawa a35b8f
                            "\t-o filename: output(filtered) file\n"
shun_iwasawa a35b8f
                            "\t-n nfft: fft size to use\n"
shun_iwasawa a35b8f
                            "\t-h filename: impulse response\n");
shun_iwasawa a35b8f
                     exit (1);
shun_iwasawa a35b8f
            default:fprintf(stderr,"bad %c\n",c);break;
shun_iwasawa a35b8f
        }
shun_iwasawa a35b8f
    }
shun_iwasawa a35b8f
    if (filtfile==NULL) {
shun_iwasawa a35b8f
        fprintf(stderr,"You must supply the FIR coeffs via -h\n");
shun_iwasawa a35b8f
        exit(1);
shun_iwasawa a35b8f
    }
shun_iwasawa a35b8f
    fseek(filtfile,0,SEEK_END);
shun_iwasawa a35b8f
    nh = ftell(filtfile) / sizeof(kffsamp_t);
shun_iwasawa a35b8f
    if (verbose) fprintf(stderr,"%d samples in FIR filter\n",(int)nh);
shun_iwasawa a35b8f
    h = (kffsamp_t*)malloc(sizeof(kffsamp_t)*nh);
shun_iwasawa a35b8f
    fseek(filtfile,0,SEEK_SET);
shun_iwasawa a35b8f
    if (fread(h,sizeof(kffsamp_t),nh,filtfile) != nh)
shun_iwasawa a35b8f
        fprintf(stderr,"short read on filter file\n");
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    fclose(filtfile);
shun_iwasawa a35b8f
 
shun_iwasawa a35b8f
    if (use_direct)
shun_iwasawa a35b8f
        direct_file_filter( fin, fout, h,nh);
shun_iwasawa a35b8f
    else
shun_iwasawa a35b8f
        do_file_filter( fin, fout, h,nh,nfft);
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    if (fout!=stdout) fclose(fout);
shun_iwasawa a35b8f
    if (fin!=stdin) fclose(fin);
shun_iwasawa a35b8f
shun_iwasawa a35b8f
    return 0;
shun_iwasawa a35b8f
}
shun_iwasawa a35b8f
#endif