annotate src/ext/kissfft/tools/kiss_fastfir.c @ 196:da283326bcd3 tip master

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