annotate constant-q-cpp/src/ext/kissfft/tools/kiss_fastfir.c @ 372:af71cbdab621 tip

Update bqvec code
author Chris Cannam
date Tue, 19 Nov 2019 10:13:32 +0000
parents 5d0a2ebb4d17
children
rev   line source
Chris@366 1 /*
Chris@366 2 Copyright (c) 2003-2004, Mark Borgerding
Chris@366 3
Chris@366 4 All rights reserved.
Chris@366 5
Chris@366 6 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Chris@366 7
Chris@366 8 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Chris@366 9 * 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.
Chris@366 10 * 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.
Chris@366 11
Chris@366 12 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.
Chris@366 13 */
Chris@366 14
Chris@366 15 #include "_kiss_fft_guts.h"
Chris@366 16
Chris@366 17
Chris@366 18 /*
Chris@366 19 Some definitions that allow real or complex filtering
Chris@366 20 */
Chris@366 21 #ifdef REAL_FASTFIR
Chris@366 22 #define MIN_FFT_LEN 2048
Chris@366 23 #include "kiss_fftr.h"
Chris@366 24 typedef kiss_fft_scalar kffsamp_t;
Chris@366 25 typedef kiss_fftr_cfg kfcfg_t;
Chris@366 26 #define FFT_ALLOC kiss_fftr_alloc
Chris@366 27 #define FFTFWD kiss_fftr
Chris@366 28 #define FFTINV kiss_fftri
Chris@366 29 #else
Chris@366 30 #define MIN_FFT_LEN 1024
Chris@366 31 typedef kiss_fft_cpx kffsamp_t;
Chris@366 32 typedef kiss_fft_cfg kfcfg_t;
Chris@366 33 #define FFT_ALLOC kiss_fft_alloc
Chris@366 34 #define FFTFWD kiss_fft
Chris@366 35 #define FFTINV kiss_fft
Chris@366 36 #endif
Chris@366 37
Chris@366 38 typedef struct kiss_fastfir_state *kiss_fastfir_cfg;
Chris@366 39
Chris@366 40
Chris@366 41
Chris@366 42 kiss_fastfir_cfg kiss_fastfir_alloc(const kffsamp_t * imp_resp,size_t n_imp_resp,
Chris@366 43 size_t * nfft,void * mem,size_t*lenmem);
Chris@366 44
Chris@366 45 /* see do_file_filter for usage */
Chris@366 46 size_t kiss_fastfir( kiss_fastfir_cfg cfg, kffsamp_t * inbuf, kffsamp_t * outbuf, size_t n, size_t *offset);
Chris@366 47
Chris@366 48
Chris@366 49
Chris@366 50 static int verbose=0;
Chris@366 51
Chris@366 52
Chris@366 53 struct kiss_fastfir_state{
Chris@366 54 size_t nfft;
Chris@366 55 size_t ngood;
Chris@366 56 kfcfg_t fftcfg;
Chris@366 57 kfcfg_t ifftcfg;
Chris@366 58 kiss_fft_cpx * fir_freq_resp;
Chris@366 59 kiss_fft_cpx * freqbuf;
Chris@366 60 size_t n_freq_bins;
Chris@366 61 kffsamp_t * tmpbuf;
Chris@366 62 };
Chris@366 63
Chris@366 64
Chris@366 65 kiss_fastfir_cfg kiss_fastfir_alloc(
Chris@366 66 const kffsamp_t * imp_resp,size_t n_imp_resp,
Chris@366 67 size_t *pnfft, /* if <= 0, an appropriate size will be chosen */
Chris@366 68 void * mem,size_t*lenmem)
Chris@366 69 {
Chris@366 70 kiss_fastfir_cfg st = NULL;
Chris@366 71 size_t len_fftcfg,len_ifftcfg;
Chris@366 72 size_t memneeded = sizeof(struct kiss_fastfir_state);
Chris@366 73 char * ptr;
Chris@366 74 size_t i;
Chris@366 75 size_t nfft=0;
Chris@366 76 float scale;
Chris@366 77 int n_freq_bins;
Chris@366 78 if (pnfft)
Chris@366 79 nfft=*pnfft;
Chris@366 80
Chris@366 81 if (nfft<=0) {
Chris@366 82 /* determine fft size as next power of two at least 2x
Chris@366 83 the impulse response length*/
Chris@366 84 i=n_imp_resp-1;
Chris@366 85 nfft=2;
Chris@366 86 do{
Chris@366 87 nfft<<=1;
Chris@366 88 }while (i>>=1);
Chris@366 89 #ifdef MIN_FFT_LEN
Chris@366 90 if ( nfft < MIN_FFT_LEN )
Chris@366 91 nfft=MIN_FFT_LEN;
Chris@366 92 #endif
Chris@366 93 }
Chris@366 94 if (pnfft)
Chris@366 95 *pnfft = nfft;
Chris@366 96
Chris@366 97 #ifdef REAL_FASTFIR
Chris@366 98 n_freq_bins = nfft/2 + 1;
Chris@366 99 #else
Chris@366 100 n_freq_bins = nfft;
Chris@366 101 #endif
Chris@366 102 /*fftcfg*/
Chris@366 103 FFT_ALLOC (nfft, 0, NULL, &len_fftcfg);
Chris@366 104 memneeded += len_fftcfg;
Chris@366 105 /*ifftcfg*/
Chris@366 106 FFT_ALLOC (nfft, 1, NULL, &len_ifftcfg);
Chris@366 107 memneeded += len_ifftcfg;
Chris@366 108 /* tmpbuf */
Chris@366 109 memneeded += sizeof(kffsamp_t) * nfft;
Chris@366 110 /* fir_freq_resp */
Chris@366 111 memneeded += sizeof(kiss_fft_cpx) * n_freq_bins;
Chris@366 112 /* freqbuf */
Chris@366 113 memneeded += sizeof(kiss_fft_cpx) * n_freq_bins;
Chris@366 114
Chris@366 115 if (lenmem == NULL) {
Chris@366 116 st = (kiss_fastfir_cfg) malloc (memneeded);
Chris@366 117 } else {
Chris@366 118 if (*lenmem >= memneeded)
Chris@366 119 st = (kiss_fastfir_cfg) mem;
Chris@366 120 *lenmem = memneeded;
Chris@366 121 }
Chris@366 122 if (!st)
Chris@366 123 return NULL;
Chris@366 124
Chris@366 125 st->nfft = nfft;
Chris@366 126 st->ngood = nfft - n_imp_resp + 1;
Chris@366 127 st->n_freq_bins = n_freq_bins;
Chris@366 128 ptr=(char*)(st+1);
Chris@366 129
Chris@366 130 st->fftcfg = (kfcfg_t)ptr;
Chris@366 131 ptr += len_fftcfg;
Chris@366 132
Chris@366 133 st->ifftcfg = (kfcfg_t)ptr;
Chris@366 134 ptr += len_ifftcfg;
Chris@366 135
Chris@366 136 st->tmpbuf = (kffsamp_t*)ptr;
Chris@366 137 ptr += sizeof(kffsamp_t) * nfft;
Chris@366 138
Chris@366 139 st->freqbuf = (kiss_fft_cpx*)ptr;
Chris@366 140 ptr += sizeof(kiss_fft_cpx) * n_freq_bins;
Chris@366 141
Chris@366 142 st->fir_freq_resp = (kiss_fft_cpx*)ptr;
Chris@366 143 ptr += sizeof(kiss_fft_cpx) * n_freq_bins;
Chris@366 144
Chris@366 145 FFT_ALLOC (nfft,0,st->fftcfg , &len_fftcfg);
Chris@366 146 FFT_ALLOC (nfft,1,st->ifftcfg , &len_ifftcfg);
Chris@366 147
Chris@366 148 memset(st->tmpbuf,0,sizeof(kffsamp_t)*nfft);
Chris@366 149 /*zero pad in the middle to left-rotate the impulse response
Chris@366 150 This puts the scrap samples at the end of the inverse fft'd buffer */
Chris@366 151 st->tmpbuf[0] = imp_resp[ n_imp_resp - 1 ];
Chris@366 152 for (i=0;i<n_imp_resp - 1; ++i) {
Chris@366 153 st->tmpbuf[ nfft - n_imp_resp + 1 + i ] = imp_resp[ i ];
Chris@366 154 }
Chris@366 155
Chris@366 156 FFTFWD(st->fftcfg,st->tmpbuf,st->fir_freq_resp);
Chris@366 157
Chris@366 158 /* TODO: this won't work for fixed point */
Chris@366 159 scale = 1.0 / st->nfft;
Chris@366 160
Chris@366 161 for ( i=0; i < st->n_freq_bins; ++i ) {
Chris@366 162 #ifdef USE_SIMD
Chris@366 163 st->fir_freq_resp[i].r *= _mm_set1_ps(scale);
Chris@366 164 st->fir_freq_resp[i].i *= _mm_set1_ps(scale);
Chris@366 165 #else
Chris@366 166 st->fir_freq_resp[i].r *= scale;
Chris@366 167 st->fir_freq_resp[i].i *= scale;
Chris@366 168 #endif
Chris@366 169 }
Chris@366 170 return st;
Chris@366 171 }
Chris@366 172
Chris@366 173 static void fastconv1buf(const kiss_fastfir_cfg st,const kffsamp_t * in,kffsamp_t * out)
Chris@366 174 {
Chris@366 175 size_t i;
Chris@366 176 /* multiply the frequency response of the input signal by
Chris@366 177 that of the fir filter*/
Chris@366 178 FFTFWD( st->fftcfg, in , st->freqbuf );
Chris@366 179 for ( i=0; i<st->n_freq_bins; ++i ) {
Chris@366 180 kiss_fft_cpx tmpsamp;
Chris@366 181 C_MUL(tmpsamp,st->freqbuf[i],st->fir_freq_resp[i]);
Chris@366 182 st->freqbuf[i] = tmpsamp;
Chris@366 183 }
Chris@366 184
Chris@366 185 /* perform the inverse fft*/
Chris@366 186 FFTINV(st->ifftcfg,st->freqbuf,out);
Chris@366 187 }
Chris@366 188
Chris@366 189 /* n : the size of inbuf and outbuf in samples
Chris@366 190 return value: the number of samples completely processed
Chris@366 191 n-retval samples should be copied to the front of the next input buffer */
Chris@366 192 static size_t kff_nocopy(
Chris@366 193 kiss_fastfir_cfg st,
Chris@366 194 const kffsamp_t * inbuf,
Chris@366 195 kffsamp_t * outbuf,
Chris@366 196 size_t n)
Chris@366 197 {
Chris@366 198 size_t norig=n;
Chris@366 199 while (n >= st->nfft ) {
Chris@366 200 fastconv1buf(st,inbuf,outbuf);
Chris@366 201 inbuf += st->ngood;
Chris@366 202 outbuf += st->ngood;
Chris@366 203 n -= st->ngood;
Chris@366 204 }
Chris@366 205 return norig - n;
Chris@366 206 }
Chris@366 207
Chris@366 208 static
Chris@366 209 size_t kff_flush(kiss_fastfir_cfg st,const kffsamp_t * inbuf,kffsamp_t * outbuf,size_t n)
Chris@366 210 {
Chris@366 211 size_t zpad=0,ntmp;
Chris@366 212
Chris@366 213 ntmp = kff_nocopy(st,inbuf,outbuf,n);
Chris@366 214 n -= ntmp;
Chris@366 215 inbuf += ntmp;
Chris@366 216 outbuf += ntmp;
Chris@366 217
Chris@366 218 zpad = st->nfft - n;
Chris@366 219 memset(st->tmpbuf,0,sizeof(kffsamp_t)*st->nfft );
Chris@366 220 memcpy(st->tmpbuf,inbuf,sizeof(kffsamp_t)*n );
Chris@366 221
Chris@366 222 fastconv1buf(st,st->tmpbuf,st->tmpbuf);
Chris@366 223
Chris@366 224 memcpy(outbuf,st->tmpbuf,sizeof(kffsamp_t)*( st->ngood - zpad ));
Chris@366 225 return ntmp + st->ngood - zpad;
Chris@366 226 }
Chris@366 227
Chris@366 228 size_t kiss_fastfir(
Chris@366 229 kiss_fastfir_cfg vst,
Chris@366 230 kffsamp_t * inbuf,
Chris@366 231 kffsamp_t * outbuf,
Chris@366 232 size_t n_new,
Chris@366 233 size_t *offset)
Chris@366 234 {
Chris@366 235 size_t ntot = n_new + *offset;
Chris@366 236 if (n_new==0) {
Chris@366 237 return kff_flush(vst,inbuf,outbuf,ntot);
Chris@366 238 }else{
Chris@366 239 size_t nwritten = kff_nocopy(vst,inbuf,outbuf,ntot);
Chris@366 240 *offset = ntot - nwritten;
Chris@366 241 /*save the unused or underused samples at the front of the input buffer */
Chris@366 242 memcpy( inbuf , inbuf+nwritten , *offset * sizeof(kffsamp_t) );
Chris@366 243 return nwritten;
Chris@366 244 }
Chris@366 245 }
Chris@366 246
Chris@366 247 #ifdef FAST_FILT_UTIL
Chris@366 248 #include <unistd.h>
Chris@366 249 #include <sys/types.h>
Chris@366 250 #include <sys/mman.h>
Chris@366 251 #include <assert.h>
Chris@366 252
Chris@366 253 static
Chris@366 254 void direct_file_filter(
Chris@366 255 FILE * fin,
Chris@366 256 FILE * fout,
Chris@366 257 const kffsamp_t * imp_resp,
Chris@366 258 size_t n_imp_resp)
Chris@366 259 {
Chris@366 260 size_t nlag = n_imp_resp - 1;
Chris@366 261
Chris@366 262 const kffsamp_t *tmph;
Chris@366 263 kffsamp_t *buf, *circbuf;
Chris@366 264 kffsamp_t outval;
Chris@366 265 size_t nread;
Chris@366 266 size_t nbuf;
Chris@366 267 size_t oldestlag = 0;
Chris@366 268 size_t k, tap;
Chris@366 269 #ifndef REAL_FASTFIR
Chris@366 270 kffsamp_t tmp;
Chris@366 271 #endif
Chris@366 272
Chris@366 273 nbuf = 4096;
Chris@366 274 buf = (kffsamp_t *) malloc ( sizeof (kffsamp_t) * nbuf);
Chris@366 275 circbuf = (kffsamp_t *) malloc (sizeof (kffsamp_t) * nlag);
Chris@366 276 if (!circbuf || !buf) {
Chris@366 277 perror("circbuf allocation");
Chris@366 278 exit(1);
Chris@366 279 }
Chris@366 280
Chris@366 281 if ( fread (circbuf, sizeof (kffsamp_t), nlag, fin) != nlag ) {
Chris@366 282 perror ("insufficient data to overcome transient");
Chris@366 283 exit (1);
Chris@366 284 }
Chris@366 285
Chris@366 286 do {
Chris@366 287 nread = fread (buf, sizeof (kffsamp_t), nbuf, fin);
Chris@366 288 if (nread <= 0)
Chris@366 289 break;
Chris@366 290
Chris@366 291 for (k = 0; k < nread; ++k) {
Chris@366 292 tmph = imp_resp+nlag;
Chris@366 293 #ifdef REAL_FASTFIR
Chris@366 294 # ifdef USE_SIMD
Chris@366 295 outval = _mm_set1_ps(0);
Chris@366 296 #else
Chris@366 297 outval = 0;
Chris@366 298 #endif
Chris@366 299 for (tap = oldestlag; tap < nlag; ++tap)
Chris@366 300 outval += circbuf[tap] * *tmph--;
Chris@366 301 for (tap = 0; tap < oldestlag; ++tap)
Chris@366 302 outval += circbuf[tap] * *tmph--;
Chris@366 303 outval += buf[k] * *tmph;
Chris@366 304 #else
Chris@366 305 # ifdef USE_SIMD
Chris@366 306 outval.r = outval.i = _mm_set1_ps(0);
Chris@366 307 #else
Chris@366 308 outval.r = outval.i = 0;
Chris@366 309 #endif
Chris@366 310 for (tap = oldestlag; tap < nlag; ++tap){
Chris@366 311 C_MUL(tmp,circbuf[tap],*tmph);
Chris@366 312 --tmph;
Chris@366 313 C_ADDTO(outval,tmp);
Chris@366 314 }
Chris@366 315
Chris@366 316 for (tap = 0; tap < oldestlag; ++tap) {
Chris@366 317 C_MUL(tmp,circbuf[tap],*tmph);
Chris@366 318 --tmph;
Chris@366 319 C_ADDTO(outval,tmp);
Chris@366 320 }
Chris@366 321 C_MUL(tmp,buf[k],*tmph);
Chris@366 322 C_ADDTO(outval,tmp);
Chris@366 323 #endif
Chris@366 324
Chris@366 325 circbuf[oldestlag++] = buf[k];
Chris@366 326 buf[k] = outval;
Chris@366 327
Chris@366 328 if (oldestlag == nlag)
Chris@366 329 oldestlag = 0;
Chris@366 330 }
Chris@366 331
Chris@366 332 if (fwrite (buf, sizeof (buf[0]), nread, fout) != nread) {
Chris@366 333 perror ("short write");
Chris@366 334 exit (1);
Chris@366 335 }
Chris@366 336 } while (nread);
Chris@366 337 free (buf);
Chris@366 338 free (circbuf);
Chris@366 339 }
Chris@366 340
Chris@366 341 static
Chris@366 342 void do_file_filter(
Chris@366 343 FILE * fin,
Chris@366 344 FILE * fout,
Chris@366 345 const kffsamp_t * imp_resp,
Chris@366 346 size_t n_imp_resp,
Chris@366 347 size_t nfft )
Chris@366 348 {
Chris@366 349 int fdout;
Chris@366 350 size_t n_samps_buf;
Chris@366 351
Chris@366 352 kiss_fastfir_cfg cfg;
Chris@366 353 kffsamp_t *inbuf,*outbuf;
Chris@366 354 int nread,nwrite;
Chris@366 355 size_t idx_inbuf;
Chris@366 356
Chris@366 357 fdout = fileno(fout);
Chris@366 358
Chris@366 359 cfg=kiss_fastfir_alloc(imp_resp,n_imp_resp,&nfft,0,0);
Chris@366 360
Chris@366 361 /* use length to minimize buffer shift*/
Chris@366 362 n_samps_buf = 8*4096/sizeof(kffsamp_t);
Chris@366 363 n_samps_buf = nfft + 4*(nfft-n_imp_resp+1);
Chris@366 364
Chris@366 365 if (verbose) fprintf(stderr,"bufsize=%d\n",(int)(sizeof(kffsamp_t)*n_samps_buf) );
Chris@366 366
Chris@366 367
Chris@366 368 /*allocate space and initialize pointers */
Chris@366 369 inbuf = (kffsamp_t*)malloc(sizeof(kffsamp_t)*n_samps_buf);
Chris@366 370 outbuf = (kffsamp_t*)malloc(sizeof(kffsamp_t)*n_samps_buf);
Chris@366 371
Chris@366 372 idx_inbuf=0;
Chris@366 373 do{
Chris@366 374 /* start reading at inbuf[idx_inbuf] */
Chris@366 375 nread = fread( inbuf + idx_inbuf, sizeof(kffsamp_t), n_samps_buf - idx_inbuf,fin );
Chris@366 376
Chris@366 377 /* If nread==0, then this is a flush.
Chris@366 378 The total number of samples in input is idx_inbuf + nread . */
Chris@366 379 nwrite = kiss_fastfir(cfg, inbuf, outbuf,nread,&idx_inbuf) * sizeof(kffsamp_t);
Chris@366 380 /* kiss_fastfir moved any unused samples to the front of inbuf and updated idx_inbuf */
Chris@366 381
Chris@366 382 if ( write(fdout, outbuf, nwrite) != nwrite ) {
Chris@366 383 perror("short write");
Chris@366 384 exit(1);
Chris@366 385 }
Chris@366 386 }while ( nread );
Chris@366 387 free(cfg);
Chris@366 388 free(inbuf);
Chris@366 389 free(outbuf);
Chris@366 390 }
Chris@366 391
Chris@366 392 int main(int argc,char**argv)
Chris@366 393 {
Chris@366 394 kffsamp_t * h;
Chris@366 395 int use_direct=0;
Chris@366 396 size_t nh,nfft=0;
Chris@366 397 FILE *fin=stdin;
Chris@366 398 FILE *fout=stdout;
Chris@366 399 FILE *filtfile=NULL;
Chris@366 400 while (1) {
Chris@366 401 int c=getopt(argc,argv,"n:h:i:o:vd");
Chris@366 402 if (c==-1) break;
Chris@366 403 switch (c) {
Chris@366 404 case 'v':
Chris@366 405 verbose=1;
Chris@366 406 break;
Chris@366 407 case 'n':
Chris@366 408 nfft=atoi(optarg);
Chris@366 409 break;
Chris@366 410 case 'i':
Chris@366 411 fin = fopen(optarg,"rb");
Chris@366 412 if (fin==NULL) {
Chris@366 413 perror(optarg);
Chris@366 414 exit(1);
Chris@366 415 }
Chris@366 416 break;
Chris@366 417 case 'o':
Chris@366 418 fout = fopen(optarg,"w+b");
Chris@366 419 if (fout==NULL) {
Chris@366 420 perror(optarg);
Chris@366 421 exit(1);
Chris@366 422 }
Chris@366 423 break;
Chris@366 424 case 'h':
Chris@366 425 filtfile = fopen(optarg,"rb");
Chris@366 426 if (filtfile==NULL) {
Chris@366 427 perror(optarg);
Chris@366 428 exit(1);
Chris@366 429 }
Chris@366 430 break;
Chris@366 431 case 'd':
Chris@366 432 use_direct=1;
Chris@366 433 break;
Chris@366 434 case '?':
Chris@366 435 fprintf(stderr,"usage options:\n"
Chris@366 436 "\t-n nfft: fft size to use\n"
Chris@366 437 "\t-d : use direct FIR filtering, not fast convolution\n"
Chris@366 438 "\t-i filename: input file\n"
Chris@366 439 "\t-o filename: output(filtered) file\n"
Chris@366 440 "\t-n nfft: fft size to use\n"
Chris@366 441 "\t-h filename: impulse response\n");
Chris@366 442 exit (1);
Chris@366 443 default:fprintf(stderr,"bad %c\n",c);break;
Chris@366 444 }
Chris@366 445 }
Chris@366 446 if (filtfile==NULL) {
Chris@366 447 fprintf(stderr,"You must supply the FIR coeffs via -h\n");
Chris@366 448 exit(1);
Chris@366 449 }
Chris@366 450 fseek(filtfile,0,SEEK_END);
Chris@366 451 nh = ftell(filtfile) / sizeof(kffsamp_t);
Chris@366 452 if (verbose) fprintf(stderr,"%d samples in FIR filter\n",(int)nh);
Chris@366 453 h = (kffsamp_t*)malloc(sizeof(kffsamp_t)*nh);
Chris@366 454 fseek(filtfile,0,SEEK_SET);
Chris@366 455 if (fread(h,sizeof(kffsamp_t),nh,filtfile) != nh)
Chris@366 456 fprintf(stderr,"short read on filter file\n");
Chris@366 457
Chris@366 458 fclose(filtfile);
Chris@366 459
Chris@366 460 if (use_direct)
Chris@366 461 direct_file_filter( fin, fout, h,nh);
Chris@366 462 else
Chris@366 463 do_file_filter( fin, fout, h,nh,nfft);
Chris@366 464
Chris@366 465 if (fout!=stdout) fclose(fout);
Chris@366 466 if (fin!=stdin) fclose(fin);
Chris@366 467
Chris@366 468 return 0;
Chris@366 469 }
Chris@366 470 #endif