fconv-fftw.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. /*
  2. * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
  3. * http://people.bath.ac.uk/masrwd
  4. * http://www.composersdesktop.com
  5. * This file is part of the CDP System.
  6. * The CDP System is free software; you can redistribute it
  7. * and/or modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * The CDP System is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. * See the GNU Lesser General Public License for more details.
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with the CDP System; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. *
  19. */
  20. /* fastconv.cpp: */
  21. /* self-contained prog for fast convolution (reverb, FIR filtering, bformat etc)
  22. *
  23. */
  24. /* um, there is nothing C++ish about this code apart from use of new, delete! */
  25. /*TODO: control wet/dry mix with something... */
  26. /* auto-rescale arbitrary impulse responses? */
  27. /* Feb 2013: rebuilt with updated portsf */
  28. /* August 2013 epanded usage message re text file. */
  29. extern "C"
  30. {
  31. #include <portsf.h>
  32. }
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <math.h>
  36. #include <string.h>
  37. #include <time.h>
  38. #include <sys/types.h>
  39. #include <sys/timeb.h>
  40. #ifdef _DEBUG
  41. #include <assert.h>
  42. #endif
  43. #ifdef unix
  44. #include <ctype.h>
  45. int stricmp(const char *a, const char *b);
  46. int strnicmp(const char *a, const char *b, const int length);
  47. #endif
  48. #include <rfftw.h>
  49. #ifndef WAVE_FORMAT_IEEE_FLOAT
  50. #define WAVE_FORMAT_IEEE_FLOAT (0x0003)
  51. #endif
  52. //#define FFTTEST
  53. /* convert from mono text impulse file */
  54. long genimpframe1(double *insbuf, double*** outbuf, long npoints, double scalefac);
  55. /* convert from multichan soundfile */
  56. long genimpframe2(int ifd,double*** outframe, double* rms,long imchans,double scalefac);
  57. void mc_split(double* inbuf,double** out,long insize,long chans);
  58. void mc_interl(double** in,double* out,long insize,long chans);
  59. void complexmult(double *frame,const double *impulse,long length);
  60. #ifdef FFTTEST
  61. extern "C"{
  62. void fft_(double *, double *,int,int,int,int);
  63. void fftmx(double *,double *,int,int,int,int,int,int *,double *,double *,double *,double *,int *,int[]);
  64. void reals_(double *,double *,int,int);
  65. }
  66. #endif
  67. #define DEFAULT_BUFLEN (32768)
  68. enum {ARG_NAME,ARG_INFILE,ARG_IMPFILE,ARG_OUTFILE,ARG_NARGS};
  69. void usage(const char *progname)
  70. {
  71. printf("\n\n%s v1.2 RWD,CDP July 2010,2013",progname);
  72. printf("\nMulti-channel FFT-based convolver");
  73. printf("\nUsage: \n %s [-aX][-f] infile impulsefile outfile [dry]\n"
  74. " -aX : scale output amplitude by X\n"
  75. " -f : write output as floats (no clipping)\n"
  76. " infile : input soundfile to be processed.\n"
  77. " impulsefile : m/c soundfile or mono text file containing impulse response,\n"
  78. " e.g. reverb or FIR filter.\n"
  79. " Text file name must have extension .txt.\n"
  80. " File must contain 1 column of floating point values,\n"
  81. " typically in the range -1.0 to 1.0.\n"
  82. " Supported channel combinations:\n"
  83. " (a) mono infile, N-channel impulsefile;\n"
  84. " (b) channels are the same;\n"
  85. " (c) mono impulsefile, N-channel infile.\n"
  86. " [dry] : set dry/wet mix (e.g. for reverb)\n"
  87. " Range: 0.0 - 1.0, default = 0.0\n"
  88. " (uses sin/cos law for constant power mix)\n"
  89. "Note: some recorded reverb impulses effectively include the direct signal.\n"
  90. "In such cases <dry> need not be used\n"
  91. "Where impulsefile is filter response (FIR), optimum length is power-of-two - 1.\n",progname
  92. );
  93. }
  94. double
  95. timer()
  96. {
  97. struct timeb now;
  98. double secs, ticks;
  99. ftime(&now);
  100. ticks = (double)now.millitm/(1000.0);
  101. secs = (double) now.time;
  102. return secs + ticks;
  103. }
  104. void
  105. stopwatch(int flag)
  106. {
  107. static double start;
  108. long mins=0,hours=0;
  109. double end, secs=0;
  110. if(flag)
  111. start = timer();
  112. else
  113. {
  114. end = timer();
  115. secs = end - start;
  116. mins = (long)(secs/60.0);
  117. secs -= mins*60.0;
  118. hours = mins/60;
  119. mins -= hours*60;
  120. fprintf(stderr,"\nElapsed time: ");
  121. if(hours > 0)
  122. fprintf(stderr,"%ld h ", hours);
  123. if(mins > 0)
  124. fprintf(stderr,"%ld m ", mins);
  125. fprintf(stderr,"%2.3lf s\n\n",secs);
  126. }
  127. }
  128. /* how do we want this to work?
  129. (1) multi-chan impulse: EITHER: mono infile OR infile with same chan count
  130. (2) mono impulse: expanded to infile chancount
  131. Therefore: need to open both infiles before deciding action
  132. */
  133. #define PI2 (1.570796327)
  134. int main(int argc,char **argv)
  135. {
  136. long fftlen = 1,imlen = 0,chans = 0,srate;
  137. long buflen = 0;
  138. double scalefac = 1.0f;
  139. double ampfac = 1.0;
  140. double Ninv = 1.0;
  141. int insndfile = -1,inimpfile = -1,outsndfile = -1;
  142. int dorms = 0;
  143. int nameoffset = 0;
  144. PSF_PROPS inprops,outprops, impulseprops;
  145. psf_format format;
  146. PSF_CHPEAK *fpeaks = NULL;
  147. MYLONG peaktime;
  148. int i,jj,minheader = 0,do_timer = 1;
  149. int writefloats = 0;
  150. long framesneeded;
  151. double oneovrsr;
  152. double *inmonobuf = 0;
  153. double *insbuf=0,*outsbuf = 0;
  154. double **inbuf = 0, **outbuf = 0;
  155. double **imbuf = 0;
  156. double **overlapbuf = 0;
  157. double rms = 0.0;
  158. double dry = 0.0;
  159. double wet = 1.0;
  160. #ifdef FFTTEST
  161. double *anal = 0;
  162. #endif
  163. rfftwnd_plan* forward_plan = 0;
  164. rfftwnd_plan* inverse_plan = 0;
  165. if(argv[0][0]=='.' && argv[0][1]=='/'){
  166. nameoffset = 2;
  167. }
  168. if(argc==2){
  169. if(strcmp(argv[1],"--version")==0){
  170. printf("1.2.0.\n");
  171. return 0;
  172. }
  173. }
  174. if(psf_init()){
  175. puts("unable to start portsf\n");
  176. return 1;
  177. }
  178. if(argc < ARG_NARGS){
  179. usage(argv[0]+nameoffset);
  180. return(1);
  181. }
  182. while(argc > 1 && argv[1][0]=='-'){
  183. switch(argv[1][1]){
  184. case 'a':
  185. scalefac = atof(&(argv[1][2]));
  186. if(scalefac <=0.0){
  187. printf("Error: scalefac must be positive!\n");
  188. return 1;
  189. }
  190. break;
  191. case 'f':
  192. writefloats = 1;
  193. break;
  194. default:
  195. break;
  196. }
  197. argv++;
  198. argc--;
  199. }
  200. /* 2 legal possibilities: infile and outfile, or -I used with infile only */
  201. if(argc< ARG_NARGS){
  202. fprintf(stderr,"\nInsufficient arguments.");
  203. usage(argv[0]+nameoffset);
  204. return(1);
  205. }
  206. if(argc==ARG_NARGS+1){
  207. double dryarg;
  208. dryarg = atof(argv[ARG_NARGS]);
  209. if(dryarg < 0.0 || dryarg > 1.0){
  210. printf("dry value out of range.\n");
  211. return 0;
  212. }
  213. if(dryarg==1.0){
  214. printf("Warning: dry=1 copies input!\n");
  215. wet = 0.0;
  216. }
  217. else{
  218. dry = sin(PI2 * dryarg);
  219. wet = cos(PI2 * dryarg);
  220. }
  221. }
  222. /* TODO: where -F[file] is combined with -A, it signifies create analysis file
  223. compatible with impulse file (e.g 50% overlap, etc) */
  224. /* open infile, check props */
  225. if((insndfile = psf_sndOpen(argv[ARG_INFILE],&inprops, 0)) < 0){
  226. fprintf(stderr,"\nUnable to open input soundfile %s",argv[1]);
  227. delete []imbuf;
  228. return 1;
  229. }
  230. srate = inprops.srate;
  231. if(srate <=0){
  232. fprintf(stderr,"\nBad srate found: corrupted file?\n");
  233. delete []imbuf;
  234. return 1;
  235. }
  236. chans = inprops.chans;
  237. framesneeded = psf_sndSize(insndfile);
  238. if(framesneeded <= 0){
  239. printf("Error in input file - no data!\n");
  240. psf_sndClose(insndfile);
  241. return 1;
  242. }
  243. /* open impulse file */
  244. /* check for soundfile */
  245. format = psf_getFormatExt(argv[ARG_IMPFILE]);
  246. if(format==PSF_FMT_UNKNOWN){ /* must be a text file */
  247. FILE *fp = 0;
  248. char tmp[80];
  249. char* dot;
  250. int size = 0,got = 0;
  251. int read = 0;
  252. dot = strrchr(argv[ARG_IMPFILE],'.');
  253. if(dot==NULL || stricmp(dot,".txt") != 0){
  254. fprintf(stderr,"Error: impulse text file must have .txt extension.\n");
  255. return 1;
  256. }
  257. fp = fopen(argv[ARG_IMPFILE],"r");
  258. if(fp==0){
  259. printf("Cannot open impulse text file %s\n.",argv[ARG_IMPFILE]);
  260. return 1;
  261. }
  262. /* count lines! */
  263. while(fgets(tmp,80,fp) != NULL)
  264. size++;
  265. if(size==0){
  266. printf("Impulse textfile %s has no data!.\n",argv[ARG_IMPFILE]);
  267. return 1;
  268. }
  269. rewind(fp);
  270. inmonobuf = new double[size+1];
  271. for(i=0;i < size;i++) {
  272. read = fscanf(fp,"%lf",&inmonobuf[i]);
  273. if(read==0){
  274. i--;
  275. continue;
  276. }
  277. if(read==EOF)
  278. break;
  279. got++;
  280. }
  281. imlen = got;
  282. impulseprops.chans = 1;
  283. fclose(fp);
  284. }
  285. else{
  286. if((inimpfile = psf_sndOpen(argv[ARG_IMPFILE],&impulseprops, 0))< 0){
  287. fprintf(stderr,"\nUnable to open impulse file %s",argv[ARG_IMPFILE]);
  288. return 0;
  289. }
  290. //printf("impulse file sr = %d\n",impulseprops.srate);
  291. if(srate != impulseprops.srate){
  292. printf("Error: files must have same sample rate");
  293. delete []imbuf;
  294. return 1;
  295. }
  296. long len = psf_sndSize(inimpfile);
  297. if(len <= 0){
  298. printf("Error in impulse soundfile - no data!\n");
  299. return 1;
  300. }
  301. if(impulseprops.chans > 1){
  302. if(! (chans == 1 || chans == impulseprops.chans)){
  303. fprintf(stderr,"\nChannel mismatch.\n Infile must be mono or have same channels as irfile.\n");
  304. return(1);
  305. }
  306. chans = impulseprops.chans;
  307. }
  308. }
  309. imbuf = new double*[chans];
  310. /* if impulse file is mono, we will need to copy data to the other buffers */
  311. // allocate impulseprops.chans buffers ; may need more
  312. if(inimpfile >=0){
  313. if((imlen = genimpframe2(inimpfile,&imbuf,&rms,impulseprops.chans, scalefac)) == 0){
  314. fprintf(stderr,"Error reading impulse file\n");
  315. return(1);
  316. }
  317. }
  318. else if(imlen){
  319. genimpframe1(inmonobuf,&imbuf,imlen,scalefac);
  320. }
  321. printf("mean rms level = %.4lf (%.2lf dB)\n",rms, 20.0 * log10(rms));
  322. framesneeded += imlen; /* can close outfile, when this length reached */
  323. while(fftlen < imlen*2) /* convolution style - double-length */
  324. fftlen <<= 1;
  325. double norm = sqrt(2.0); /* relative: rms of 0dBFS sine is 0.707 = 1/root2 */
  326. Ninv = 1.0 / sqrt(imlen*2);
  327. Ninv *= norm;
  328. Ninv /= imlen;
  329. // take simple avg of rms for adjustment factor.
  330. // may not adequately represent some responses, e.g. with strong attack/earlies, soft reverb tail */
  331. double rmsdif2 = (-20.0 * log10(rms)) * 0.5;
  332. double rmsadjust = pow(10, rmsdif2/20.0);
  333. #ifdef _DEBUG
  334. printf("rescaling factor = %.6e\n",Ninv);
  335. printf("rmsadjust = %.4lf\n",rmsadjust);
  336. #endif
  337. Ninv /= rmsadjust;
  338. /* copy buffers if required */
  339. for(i = impulseprops.chans;i < chans;i++){
  340. imbuf[i] = new double[fftlen+2];
  341. memcpy(imbuf[i],imbuf[0],(fftlen+2)* sizeof(double));
  342. }
  343. oneovrsr = 1.0 / (double) srate;
  344. /*make sure buflen is at least fftlen */
  345. // if(fftlen > buflen)
  346. // buflen = fftlen;
  347. /* main i/o buffers */
  348. insbuf = new double [fftlen * chans];
  349. outsbuf = new double [fftlen * chans];
  350. inbuf = new double*[chans];
  351. outbuf = new double*[chans]; /* overlap-add buffers */
  352. overlapbuf = new double*[chans];
  353. for(i=0;i < chans;i++){
  354. inbuf[i] = new double[fftlen+2]; // main in-place buf
  355. outbuf[i] = new double[fftlen+2];
  356. /* channel buffers */
  357. overlapbuf[i] = new double[fftlen/2];
  358. memset(overlapbuf[i],0,sizeof(double)*(fftlen/2));
  359. }
  360. #ifdef FFTTEST
  361. anal = new double[fftlen+2];
  362. #endif
  363. forward_plan = new rfftwnd_plan[chans];
  364. inverse_plan = new rfftwnd_plan[chans];
  365. int insize = (int) fftlen;
  366. for(i=0;i < chans;i++){
  367. memset(inbuf[i], 0, sizeof(double) * (fftlen+2));
  368. memset(outbuf[i],0,sizeof(double) * (fftlen+2));
  369. forward_plan[i] = rfftwnd_create_plan_specific(1,&insize,
  370. FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE | FFTW_IN_PLACE,
  371. inbuf[i],1,NULL,1);
  372. inverse_plan[i] = rfftwnd_create_plan_specific(1,&insize,
  373. FFTW_COMPLEX_TO_REAL, FFTW_ESTIMATE | FFTW_IN_PLACE,
  374. inbuf[i],1,NULL,1);
  375. }
  376. /* use generic init function */
  377. /*bool phasevocoder::init(long outsrate,long fftlen,long winlen,long decfac,float scalefac,
  378. pvoc_scaletype stype,pvoc_windowtype wtype,pvocmode mode)
  379. */
  380. /*create output sfile */
  381. psf_stype smptype;
  382. psf_format outformat;
  383. /* will it be aiff, wav, etc? */
  384. outformat = psf_getFormatExt(argv[ARG_OUTFILE]);
  385. if(outformat==PSF_FMT_UNKNOWN){
  386. fprintf(stderr,"\nOutfile name has unrecognized extension.");
  387. delete []imbuf;
  388. return(1);
  389. }
  390. smptype = inprops.samptype;
  391. if(writefloats)
  392. smptype= PSF_SAMP_IEEE_FLOAT;
  393. /*the one gotcha: if output is floats and format is aiff, change to aifc */
  394. if(smptype==PSF_SAMP_IEEE_FLOAT && outformat==PSF_AIFF){
  395. fprintf(stderr,"Warning: AIFF output written as AIFC for float samples\n");
  396. outformat = PSF_AIFC;
  397. }
  398. outprops = inprops;
  399. outprops.chans = chans;
  400. outprops.srate = srate;
  401. outprops.format = outformat;
  402. outprops.samptype = smptype;
  403. outprops.chformat = STDWAVE;
  404. /* if irfile is BFormat, need to set outfile fmt likewise */
  405. if(impulseprops.chformat==MC_BFMT)
  406. outprops.chformat = MC_BFMT;
  407. /* I suppose people will want automatic decoding too...grrr */
  408. fpeaks = new PSF_CHPEAK[chans];
  409. if(fpeaks==NULL){
  410. puts("no memory for fpeak data buffer\n");
  411. return 1;
  412. }
  413. /*last arg: no clipping of f/p samples: we use PEAK chunk */
  414. if((outsndfile = psf_sndCreate(argv[ARG_OUTFILE],&outprops,0,minheader,PSF_CREATE_RDWR)) <0 ){
  415. fprintf(stderr,"\nUnable to open outfile %s",argv[ARG_OUTFILE]);
  416. delete []imbuf;
  417. return(1);
  418. }
  419. printf("\n");
  420. stopwatch(1);
  421. long written,thisblock,framesread;
  422. long frameswritten = 0;
  423. double intime= 0.0,outtime = 0.0;
  424. int last = 0;
  425. while((framesread = psf_sndReadDoubleFrames(insndfile,insbuf,imlen)) > 0){
  426. written = thisblock = 0;
  427. for(i = framesread * inprops.chans; i< fftlen * inprops.chans; i++)
  428. insbuf[i] = 0.0f;
  429. framesread = imlen;
  430. memset(inbuf[0],0,(fftlen+2) * sizeof(double));
  431. if(chans == inprops.chans) {
  432. /* must clean buffers! */
  433. for(i=0;i < chans;i++)
  434. memset(inbuf[i],0,(fftlen+2) * sizeof(double));
  435. mc_split(insbuf,inbuf,imlen * chans, chans);
  436. }
  437. else{
  438. for(i=0;i < chans;i++) {
  439. memset(inbuf[i],0,(fftlen+2) * sizeof(double));
  440. memcpy(inbuf[i],insbuf,imlen * sizeof(double));
  441. memset(outbuf[i],0,sizeof(double) * (fftlen+2));
  442. }
  443. }
  444. if(impulseprops.chans==1){
  445. for(jj = 0; jj < chans;jj++){
  446. #ifdef FFTTEST
  447. int zz;
  448. memcpy(anal,inbuf[jj],(fftlen+2) * sizeof(double));
  449. fft_(anal,anal+1,1,fftlen/2,1,-2);
  450. reals_(anal,anal+1,fftlen/2,-2);
  451. for(zz=0;zz < fftlen+2;zz++)
  452. anal[zz] *= 0.001;
  453. #endif
  454. rfftwnd_one_real_to_complex(forward_plan[jj],inbuf[jj],NULL);
  455. complexmult(inbuf[jj],imbuf[0],fftlen+2);
  456. rfftwnd_one_complex_to_real(inverse_plan[jj],(fftw_complex * )inbuf[jj],NULL);
  457. }
  458. }
  459. else{
  460. for(jj = 0; jj < chans;jj++){
  461. rfftwnd_one_real_to_complex(forward_plan[jj],inbuf[jj],NULL);
  462. complexmult(inbuf[jj],imbuf[jj],fftlen+2);
  463. rfftwnd_one_complex_to_real(inverse_plan[jj],(fftw_complex * )inbuf[jj],NULL);
  464. }
  465. }
  466. /* overlap-add for each channel */
  467. /* TODO: verify use of imlen here - should it be fftlen/2 -1 ? */
  468. for(jj=0;jj < chans;jj++){
  469. for(i=0;i < imlen;i++) {
  470. outbuf[jj][i] = inbuf[jj][i] + overlapbuf[jj][i];
  471. overlapbuf[jj][i] = inbuf[jj][i+imlen];
  472. }
  473. }
  474. mc_interl(outbuf,outsbuf,imlen,chans);
  475. if(inprops.chans == chans){
  476. for(i=0;i < framesread; i++) {
  477. for(jj=0;jj < chans;jj++){
  478. long outindex = i*chans + jj;
  479. outsbuf[outindex] *= Ninv;
  480. outsbuf[outindex] *= wet;
  481. outsbuf[outindex] += dry * insbuf[outindex];
  482. }
  483. }
  484. }
  485. /* elso mono input */
  486. else {
  487. for(i=0;i < framesread; i++) {
  488. for(jj=0;jj < chans;jj++){
  489. long outindex = i*chans + jj;
  490. double inval = dry * insbuf[i];
  491. outsbuf[outindex] *= Ninv;
  492. outsbuf[outindex] *= wet;
  493. outsbuf[outindex] += inval;
  494. }
  495. }
  496. }
  497. if((written = psf_sndWriteDoubleFrames(outsndfile,outsbuf,framesread)) != framesread){
  498. fprintf(stderr,"\nerror writing to outfile");
  499. return(1);
  500. }
  501. frameswritten += written;
  502. if(do_timer){
  503. intime += (double)framesread * oneovrsr;
  504. printf("Input time: %.2lf\r",intime);
  505. }
  506. }
  507. /* complete tail */
  508. if(frameswritten < framesneeded){
  509. // TODO: imlen? see above
  510. mc_interl(overlapbuf,outsbuf,imlen,chans);
  511. long towrite = framesneeded - frameswritten;
  512. for(i=0;i < towrite * chans; i++) {
  513. outsbuf[i] *= Ninv;
  514. outsbuf[i] *= wet;
  515. }
  516. if((written = psf_sndWriteDoubleFrames(outsndfile,outsbuf,towrite)) != towrite){
  517. fprintf(stderr,"\nerror writing to outfile");
  518. return(1);
  519. }
  520. }
  521. stopwatch(0);
  522. if(psf_sndReadPeaks( outsndfile,fpeaks,&peaktime)){
  523. double peakmax = 0.0;
  524. printf("PEAK values:\n");
  525. for(i=0; i < chans; i++) {
  526. peakmax = fpeaks[i].val > peakmax ? fpeaks[i].val : peakmax;
  527. if(fpeaks[i].val < 0.0001f)
  528. printf("CH %d:\t%e (%.2lf dB)\tat frame %10lu :\t%.4lf secs\n",i+1,
  529. fpeaks[i].val,20.0*log10(fpeaks[i].val),fpeaks[i].pos,(double) (fpeaks[i].pos) / (double)srate);
  530. else
  531. printf("CH %d:\t%.4lf (%.2lf dB)\tat frame %10lu :\t%.4lf secs\n",i+1,
  532. fpeaks[i].val,20.0 * log10(fpeaks[i].val),fpeaks[i].pos,(double) (fpeaks[i].pos) / (double)srate);
  533. }
  534. if(peakmax > 1.0)
  535. printf("Overflows! Rescale by %.10lf\n",1.0 / peakmax);
  536. }
  537. if(insndfile >=0)
  538. psf_sndClose(insndfile);
  539. if(outsndfile >=0)
  540. psf_sndClose(outsndfile);
  541. if(inimpfile >=0)
  542. psf_sndClose(inimpfile);
  543. psf_finish();
  544. delete [] fpeaks;
  545. if(insbuf)
  546. delete [] insbuf;
  547. if(outsbuf)
  548. delete [] outsbuf;
  549. for(i=0;i < chans;i++){
  550. if(inbuf){
  551. delete [] inbuf[i];
  552. }
  553. if(outbuf){
  554. delete [] outbuf[i];
  555. }
  556. if(imbuf){
  557. delete [] imbuf[i];
  558. }
  559. if(overlapbuf)
  560. delete [] overlapbuf[i];
  561. if(forward_plan)
  562. rfftwnd_destroy_plan(forward_plan[i]);
  563. if(inverse_plan)
  564. rfftwnd_destroy_plan(inverse_plan[i]);
  565. }
  566. delete [] outbuf;
  567. delete [] inbuf;
  568. delete [] imbuf;
  569. delete [] overlapbuf;
  570. return 0;
  571. }
  572. // insize is raw samplecount,buflen is insize/chans
  573. void mc_split(double* inbuf,double** out,long insize,long chans)
  574. {
  575. long i,j,buflen = insize/chans;
  576. double* pinbuf;
  577. for(j=0;j < chans;j++){
  578. pinbuf = inbuf+j;
  579. for(i=0;i < buflen;i++){
  580. out[j][i] = *pinbuf;
  581. pinbuf += chans;
  582. }
  583. }
  584. }
  585. /* insize is m/c frame count */
  586. void mc_interl(double** in,double* out,long insize,long chans)
  587. {
  588. long i,j;
  589. double* poutbuf;
  590. for(j = 0;j < chans;j++){
  591. poutbuf = out+j;
  592. for(i=0;i < insize;i++){
  593. *poutbuf = in[j][i];
  594. poutbuf += chans;
  595. }
  596. }
  597. }
  598. /* OR: apply scalefac to impulse responses */
  599. void complexmult(double *frame,const double *impulse,long length)
  600. {
  601. double re,im;
  602. int i,j;
  603. for(i=0,j = 1;i < length;i+=2,j+=2){
  604. re = frame[i] * impulse[i] - frame[j] * impulse[j];
  605. im = frame[i] * impulse[j] + frame[j]* impulse[i];
  606. frame[i] = re;
  607. frame[j] = im;
  608. }
  609. }
  610. #ifdef unix
  611. int stricmp(const char *a, const char *b)
  612. {
  613. while(*a != '\0' && *b != '\0') {
  614. int ca = islower(*a) ? toupper(*a) : *a;
  615. int cb = islower(*b) ? toupper(*b) : *b;
  616. if(ca < cb)
  617. return -1;
  618. if(ca > cb)
  619. return 1;
  620. a++;
  621. b++;
  622. }
  623. if(*a == '\0' && *b == '\0')
  624. return 0;
  625. if(*a != '\0')
  626. return 1;
  627. return -1;
  628. }
  629. int
  630. strnicmp(const char *a, const char *b, const int length)
  631. {
  632. int len = length;
  633. while(*a != '\0' && *b != '\0') {
  634. int ca = islower(*a) ? toupper(*a) : *a;
  635. int cb = islower(*b) ? toupper(*b) : *b;
  636. if(len-- < 1)
  637. return 0;
  638. if(ca < cb)
  639. return -1;
  640. if(ca > cb)
  641. return 1;
  642. a++;
  643. b++;
  644. }
  645. if(*a == '\0' && *b == '\0')
  646. return 0;
  647. if(*a != '\0')
  648. return 1;
  649. return -1;
  650. }
  651. #endif