annotate ext/kissfft/tools/kiss_fastfir.c @ 206:335be766a54d

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