fconv.cpp 21 KB

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