rmverb.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949
  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. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <math.h>
  23. #include <string.h>
  24. #ifdef _DEBUG
  25. #include <assert.h>
  26. #endif
  27. #include <algorithm>
  28. #include <vector>
  29. using namespace std;
  30. // TODO: clean up "new" handling, move to VC7 and get to use exceptions!
  31. enum cmdargs {
  32. PROGNAME,
  33. INFILE,
  34. OUTFILE,
  35. REVERBTYPE,
  36. RGAIN,
  37. MIX,
  38. FEEDBACK,
  39. LPABSORB,
  40. LPFREQ,
  41. TRTIME,
  42. CONFIG
  43. };
  44. enum reverb_type {
  45. DIFF_SMALL,
  46. DIFF_MEDIUM,
  47. DIFF_LARGE
  48. };
  49. extern "C" {
  50. #include "portsf.h"
  51. //NB requires stdio.h etc - time to change this?
  52. }
  53. #include "reverberator.h"
  54. //RWD.10.98 TODO: for final versions, MUST limit input delay times! can't have 108sec delays.....
  55. //get all reflection data
  56. #include "reflect.cpp"
  57. long readtaps(FILE *fp, deltap **taps,double sr);
  58. const char* cdp_version = "6.0.0";
  59. void usage(void);
  60. int
  61. main(int argc,char *argv[])
  62. {
  63. int i,ifd, ofd,reverbtype = DIFF_SMALL;
  64. FILE *fp = 0;
  65. long chans,outchans = 2;
  66. double sr,trailertime;
  67. cdp_processor *cdpdiff = 0;
  68. NESTDATA data1,data2;
  69. PSF_CHPEAK *peaks;
  70. PSF_PROPS props;
  71. unsigned int time1a,time1b,time1c,time2a,time2b,time2c;
  72. double feedback,fb_lpfreq, lp_freq,predelay = -1.0;
  73. double nyquist,pseudo_nyquist;
  74. double dry_gain,wet_gain;
  75. //double early_gain = 1.0;
  76. double diff_gain = 1.0;
  77. // nested-allpass diffusers
  78. small_diffuser *s_diffuser = 0;
  79. medium_diffuser *m_diffuser = 0;
  80. large_diffuser *l_diffuser = 0;
  81. // traioling plain allpasses for front pair de-correlation
  82. allpassfilter *ap1_l = 0,*ap2_l = 0;
  83. allpassfilter *ap1_r = 0,*ap2_r = 0;
  84. // decorrelation for other channels (surround)
  85. allpassfilter **chan_ap = 0;
  86. onepole *lp = 0;
  87. // tonecontrols max -12dB slope, variable;
  88. tonecontrol *tc_l_lowcut = 0, *tc_r_lowcut = 0;
  89. tonecontrol *l_highcut = 0, *r_highcut = 0;
  90. double lowcut_freq = 0.0,highcut_freq = 0.0;
  91. tapdelay *tdelay = 0;
  92. long ntaps = 0;
  93. deltap *ptaps = 0;
  94. bool want_mono = false;
  95. bool want_floats = false;
  96. bool usertaps = false;
  97. bool double_damping = false;
  98. if((argc==2) && strcmp(argv[1],"--version")==0) {
  99. fprintf(stdout,"%s\n",cdp_version);
  100. fflush(stdout);
  101. return 0;
  102. }
  103. if(psf_init()){
  104. fprintf(stderr,"rmverb: initialisation failed\n");
  105. return 1;
  106. }
  107. if(argc < CONFIG){
  108. if(argc > 1)
  109. fprintf(stderr,"rmverb: insufficient arguments\n");
  110. usage();
  111. }
  112. while((argc > 1) && argv[1][0]=='-'){
  113. char *arg = argv[1];
  114. switch(*(++arg)){
  115. case('p'):
  116. if(*(++arg) =='\0'){
  117. fprintf(stderr,"rmverb: predelay requires a parameter\n");
  118. usage();
  119. }
  120. predelay = atof(arg);
  121. if(predelay <0.0){
  122. fprintf(stderr,"rmverb: predelay must be >= 0.0\n");
  123. usage();
  124. }
  125. predelay *= 0.001; //get msecs from user
  126. break;
  127. case('c'):
  128. if(*(++arg) == '\0') {
  129. fprintf(stderr,"rmverb: -c flag requires a value\n");
  130. usage();
  131. }
  132. outchans = atoi(arg);
  133. if(outchans < 1 || outchans > 16){
  134. fprintf(stderr,"rmverb: impossible channel value requested\n");
  135. usage();
  136. }
  137. if(outchans==1)
  138. want_mono = true;
  139. break;
  140. case('d'):
  141. double_damping = true;
  142. break;
  143. case('e'):
  144. if(*(++arg)=='\0'){
  145. fprintf(stderr,"rmverb: -e flag needs a filename\n");
  146. usage();
  147. }
  148. if((fp = fopen(arg,"r")) ==0){
  149. fprintf(stderr,"rmverb: unable to open breakpoint file %s\n",arg);
  150. exit(1);
  151. }
  152. usertaps = true;
  153. break;
  154. // -f is CDP-specific: read old 32bit int format as floats
  155. case('f'):
  156. want_floats = true;
  157. if(*(++arg) != '\0')
  158. fprintf(stderr,"rmverb WARNING: -f flag does not take a parameter\n");
  159. break;
  160. case('L'):
  161. if(*(++arg) == '\0'){
  162. fprintf(stderr,"rmverb: -L flag needs frequency argument\n");
  163. usage();
  164. }
  165. lowcut_freq = atof(arg);
  166. if(lowcut_freq <= 0.0){
  167. fprintf(stderr,"rmverb: Lowcut freq must be greater than zero\n");
  168. usage();
  169. }
  170. break;
  171. case('H'):
  172. if(*(++arg) == '\0'){
  173. fprintf(stderr,"rmverb: -H flag needs frequency argument\n");
  174. usage();
  175. }
  176. highcut_freq = atof(arg);
  177. if(highcut_freq <= 0.0){
  178. fprintf(stderr,"rmverb: Highcut freq must be greater than zero\n");
  179. usage();
  180. }
  181. break;
  182. default:
  183. fprintf(stderr,"rmverb: illegal flag option %s\n",argv[1]);
  184. usage();
  185. break;
  186. }
  187. argc--;
  188. argv++;
  189. }
  190. if(argc < CONFIG){
  191. printf("rmverb: insufficient arguments\n");
  192. usage();
  193. }
  194. #ifdef _DEBUG
  195. if(predelay > 0.0)
  196. printf("got predelay = %.4lf\n",predelay);
  197. #endif
  198. chan_ap = new allpassfilter*[outchans];
  199. if(chan_ap==0){
  200. fprintf(stderr,"rmverb: no memory for multi-channel diffusion\n");
  201. exit(1);
  202. }
  203. if((ifd = psf_sndOpen(argv[INFILE],&props,0)) < 0) {
  204. fprintf(stderr,"\nrmverb: cannot open input file %s", argv[INFILE]);
  205. exit(1);
  206. }
  207. if(props.format <= PSF_FMT_UNKNOWN || props.format > PSF_AIFC){
  208. fprintf(stderr,"infile is not a recognised soundfile\n");
  209. psf_sndClose(ifd);
  210. return 1;
  211. }
  212. sr = (double) props.srate;
  213. nyquist = sr / 2.0;
  214. pseudo_nyquist = nyquist * 0.7; // filters not reliable close to nyquist
  215. chans = props.chans;
  216. if(chans > 2){
  217. fprintf(stderr,"rmverb can only accept mono or stereo files\n");
  218. exit(1);
  219. }
  220. reverbtype = atoi(argv[REVERBTYPE]) - 1;
  221. if((reverbtype < DIFF_SMALL) || (reverbtype > DIFF_LARGE)){
  222. fprintf(stderr,"rmverb: rmsize must be 1,2 or 3\n");
  223. exit(1);
  224. }
  225. diff_gain = atof(argv[RGAIN]);
  226. if(diff_gain <= 0.0 || diff_gain > 1.0){
  227. fprintf(stderr,"rgain must be > 0 and <= 1.0\n");
  228. exit(1);
  229. }
  230. dry_gain = atof(argv[MIX]); //global output gain from diffuser
  231. if(dry_gain < 0.0 || dry_gain > 1.0 ){
  232. printf("reverb: mix must be between 0.0 and 1.0\n");
  233. usage();
  234. }
  235. wet_gain = 1.0f - dry_gain;
  236. // some odd people like to have 100% wet signal...
  237. wet_gain *= 2.0; //not v scientific, but works...
  238. feedback = atof(argv[FEEDBACK]); //feedback in diffuser
  239. if(feedback < 0.0 || feedback >1.0){
  240. printf("rmverb: feedback must be within 0.0 - 1.0\n");
  241. usage();
  242. }
  243. fb_lpfreq = atof(argv[LPABSORB]); //feedback lp-filter in diffuser
  244. if(fb_lpfreq < 0.0 || fb_lpfreq > pseudo_nyquist){
  245. printf("rmverb: absorb must be within 0 to %f\n",pseudo_nyquist);
  246. usage();
  247. }
  248. lp_freq = atof(argv[LPFREQ]);
  249. if(lp_freq < 0.0 || lp_freq > pseudo_nyquist){
  250. printf("rmverb: lpfreq must be within 0.0 to %.4lfHz\n",pseudo_nyquist);
  251. usage();
  252. }
  253. trailertime = atof(argv[TRTIME]);
  254. if(trailertime < 0.0){
  255. fprintf(stderr,"rmverb: trtime must be >= 0.0\n");
  256. usage();
  257. }
  258. //from -m flag; will override a stereo input too
  259. if(want_mono)
  260. outchans = 1;
  261. // NB: now specifying two trailing allpasses for diffuser
  262. // handles front pair; currently using chan_ap[] only for remaining channels
  263. // values are experimental!
  264. double apdelay = 0.02;
  265. double apfac = 0.02 / outchans;
  266. for(i = 0; i < outchans; i++){ // or use a random modifier?
  267. chan_ap[i] = new allpassfilter(sr,to_prime(apdelay - apfac * (double)i,sr),0.4,0);
  268. if(chan_ap[i] ==0){
  269. fprintf(stderr,"rmverb: no memory for output diffusers\n");
  270. exit(1);
  271. }
  272. if(!chan_ap[i]->create()){
  273. fprintf(stderr,"rmverb: no memory for output diffusers\n");
  274. exit(1);
  275. }
  276. }
  277. // custom early reflections from time/value text-file
  278. if(usertaps){
  279. #ifdef _DEBUG
  280. assert(fp);
  281. #endif
  282. ntaps = readtaps(fp,&ptaps,sr);
  283. if(ntaps==0){
  284. fprintf(stderr,"rmverb: error reading tapfile\n");
  285. exit(1);
  286. }
  287. printf("rmverb: loaded %ld early reflections from tapfile\n",ntaps);
  288. fclose(fp);
  289. fp = 0;
  290. }
  291. //create input low/high filters, if wanted
  292. if(lowcut_freq > 0.0){
  293. if(highcut_freq > 0.0 && highcut_freq <= lowcut_freq){
  294. fprintf(stderr,"rmverb: Highcut frequency must be higher than Lowcut frequency\n");
  295. usage();
  296. }
  297. //lowcut is based on low shelving eq filter; here fixed at 12dB
  298. // but can easily add this as user param
  299. tc_l_lowcut = new tonecontrol(lowcut_freq,-12.0,LOW_SHELVE,sr);
  300. if(!tc_l_lowcut->create()){
  301. fprintf(stderr,"rmverb: unable to create Lowcut filter\n");
  302. exit(1);
  303. }
  304. if(chans==2){
  305. tc_r_lowcut = new tonecontrol(lowcut_freq,-12.0,LOW_SHELVE,sr);
  306. if(!tc_r_lowcut->create()){
  307. fprintf(stderr,"rmverb: unable to create Lowcut filter\n");
  308. exit(1);
  309. }
  310. }
  311. }
  312. if(highcut_freq > 0.0){
  313. l_highcut = new tonecontrol(highcut_freq,-12.0,HIGH_SHELVE,sr);
  314. if(!l_highcut->create()){
  315. fprintf(stderr,"rmverb: unable to create Highcut filter\n");
  316. exit(1);
  317. }
  318. if(chans==2){
  319. r_highcut = new tonecontrol(highcut_freq,-12.0,HIGH_SHELVE,sr);
  320. if(!r_highcut->create()){
  321. fprintf(stderr,"\nrmverb: unable to create Highcut filter");
  322. exit(1);
  323. }
  324. }
  325. }
  326. //now create diffuser
  327. switch(reverbtype){
  328. case(DIFF_SMALL):
  329. time1a = to_prime(0.0047, sr);
  330. time1b = to_prime(0.022, sr);
  331. time1c = to_prime(0.0083,sr);
  332. time2a = to_prime(0.036,sr);
  333. time2b = to_prime(0.03,sr);
  334. time2c = 0;//dummy
  335. data1.time1 = time1a;
  336. data1.time2 = time1b;
  337. data1.time3 = time1c;
  338. data1.gain1 = 0.3;
  339. data1.gain2 = 0.4;
  340. data1.gain3 = 0.6;
  341. data1.delay1 = 0;
  342. data1.delay2 = 0;
  343. data2.time1 = time2a;
  344. data2.time2 = time2b;
  345. data2.time3 = time2c;
  346. data2.gain1 = 0.1;
  347. data2.gain2 = 0.4;
  348. data2.gain3 = 0.0; //not used by gardner
  349. data2.delay1 = 0;
  350. data2.delay2 = 0;
  351. break;
  352. case(DIFF_MEDIUM):
  353. time1a = to_prime(/*0.0047*/0.035, sr);
  354. time1b = to_prime(0.0083, sr);
  355. time1c = to_prime(0.022,sr);
  356. time2a = to_prime(/*0.0292*/0.039,sr);
  357. time2b = to_prime(0.0098,sr);
  358. time2c = 0;//dummy
  359. data1.time1 = time1a;
  360. data1.time2 = time1b;
  361. data1.time3 = time1c;
  362. data1.gain1 = 0.3;
  363. data1.gain2 = 0.7;
  364. data1.gain3 = 0.5;
  365. data1.delay1 = 0;
  366. data1.delay2 = 0;
  367. data2.time1 = time2a;
  368. data2.time2 = time2b;
  369. data2.time3 = time2c;
  370. data2.gain1 = 0.3;
  371. data2.gain2 = 0.6;
  372. data2.gain3 = 0.0; //not used by gardner
  373. data2.delay1 = 0;
  374. data2.delay2 = 0;
  375. break;
  376. case(DIFF_LARGE):
  377. // VERY LARGE!
  378. // NB: orig outer delays from Gardner generate very strong discrete echoes,
  379. // and hence also some pulsing in the dense reverb
  380. // for really large spaces (caverns) this is OK, otherwise we ant to control this
  381. // via predelay, and earlies
  382. // NOTE: this will NOT WORK when sharing a single delay line!
  383. // in that case, outer delay MUST be > internal ones
  384. // TODO: devise user param to control a range of delay values
  385. // (maybe derived from feedback level?), to further scale room size
  386. time1a = to_prime(0.03 /*0.087*/, sr);
  387. time1b = to_prime(0.062, sr);
  388. time1c = to_prime(0.022,sr); //dummy: not used
  389. time2a = to_prime(0.018/*0.12*/,sr);
  390. time2b = to_prime(0.076,sr);
  391. time2c = to_prime(0.03,sr);
  392. data1.time1 = time1a;
  393. data1.time2 = time1b;
  394. data1.time3 = time1c;
  395. data1.gain1 = 0.5;
  396. data1.gain2 = 0.25;
  397. data1.gain3 = 0.0; //not used
  398. data1.delay1 = 0;
  399. data1.delay2 = 0;
  400. data2.time1 = time2a;
  401. data2.time2 = time2b;
  402. data2.time3 = time2c;
  403. data2.gain1 = 0.5;
  404. data2.gain2 = 0.25;
  405. data2.gain3 = 0.25;
  406. data2.delay1 = 0;
  407. data2.delay2 = 0;
  408. break;
  409. default:
  410. #ifdef _DEBUG
  411. assert(false);
  412. #endif
  413. break;
  414. }
  415. #ifdef _DEBUG
  416. //RWD: development only!
  417. if(argc==CONFIG+1){
  418. int got = 0;
  419. double time1a,time1b,time1c,time2a,time2b,time2c,gain1a,gain1b,gain1c,gain2a,gain2b,gain2c;
  420. FILE *fp = fopen(argv[CONFIG],"r");
  421. if(!fp)
  422. printf("rmverb: can't open datafile %s, using presets\n",argv[CONFIG]);
  423. else {
  424. // time1a,gain1a,time2a,gain2a,time3a,gain3a...
  425. printf("loading diffusion data...\n");
  426. got = fscanf(fp,"%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf",
  427. &time1a,&gain1a,
  428. &time1b,&gain1b,
  429. &time1c,&gain1c,
  430. &time2a,&gain2a,
  431. &time2b,&gain2b,
  432. &time2c,&gain2c);
  433. fclose(fp);
  434. if(got != 12)
  435. printf("rmverb: error reading data values\n");
  436. else {
  437. data1.time1 = to_prime(time1a,sr);
  438. data1.time2 = to_prime(time1b,sr);
  439. data1.time3 = to_prime(time1c,sr);
  440. data1.gain1 = gain1a;
  441. data1.gain2 = gain1b;
  442. data1.gain3 = gain1c;
  443. data2.time1 = to_prime(time2a,sr);
  444. data2.time2 = to_prime(time2b,sr);
  445. data2.time3 = to_prime(time2c,sr);
  446. data2.gain1 = gain2a;
  447. data2.gain2 = gain2b;
  448. data2.gain3 = gain2c;
  449. }
  450. }
  451. }
  452. else{
  453. printf("using preset parameters:\n");
  454. printf("DATA 1: time1 = %u\n\ttime2 = %u\n\ttime3 = %u\n",data1.time1,data1.time2,data1.time3);
  455. printf("DATA 2: time1 = %u\n\ttime2 = %u\n\ttime3 = %u\n",data2.time1,data2.time2,data2.time3);
  456. printf("feedback = %.4lf,fb_lpfreq = %.4lf\n",feedback,fb_lpfreq);
  457. printf("dry gain = %.4lf, wet gain = %.4lf\n",dry_gain,wet_gain);
  458. }
  459. #endif
  460. switch(reverbtype){
  461. case(DIFF_SMALL):
  462. printf("rmverb: using small room model\n");
  463. s_diffuser = new small_diffuser((unsigned int)(0.024 * sr),&data1,&data2,feedback,fb_lpfreq,sr);
  464. s_diffuser->set_damping(double_damping);
  465. cdpdiff = dynamic_cast<cdp_processor *>(s_diffuser);
  466. if(!usertaps){
  467. ptaps = smalltaps;
  468. ntaps = sizeof(smalltaps) / sizeof(deltap);
  469. }
  470. break;
  471. case(DIFF_MEDIUM):
  472. printf("rmverb: using medium room model\n");
  473. m_diffuser = new medium_diffuser(0.108,&data1,&data2,feedback,fb_lpfreq,sr);
  474. m_diffuser->set_damping(double_damping);
  475. cdpdiff = dynamic_cast<cdp_processor *>(m_diffuser);
  476. if(!usertaps){
  477. ptaps = mediumtaps;
  478. ntaps = sizeof(mediumtaps) / sizeof(deltap);
  479. }
  480. //ptaps = longtaps;
  481. //ntaps = sizeof(longtaps) / sizeof(deltap);
  482. break;
  483. case(DIFF_LARGE):
  484. printf("using large room model\n");
  485. //fb_lpfreq = 2600.0; // Gardner fixed val
  486. l_diffuser = new large_diffuser(&data1,&data2,feedback,fb_lpfreq,sr);
  487. l_diffuser->set_damping(double_damping);
  488. cdpdiff = dynamic_cast<cdp_processor *>(l_diffuser);
  489. if(!usertaps){
  490. ptaps = largetaps;
  491. ntaps = sizeof(largetaps) / sizeof(deltap);
  492. }
  493. break;
  494. default:
  495. #ifdef _DEBUG
  496. assert(false);
  497. #endif
  498. break;
  499. }
  500. if(!cdpdiff){
  501. puts("rmverb: no memory for reverberator\n");
  502. exit(1);
  503. }
  504. if(!cdpdiff->create()){
  505. puts("rmverb: no memory for reverberator buffers\n");
  506. exit(1);
  507. }
  508. /*********** GLOBAL COMPONENTS *************/
  509. if(lp_freq > 0.0)
  510. lp = new onepole(lp_freq,sr,LOW_PASS);
  511. //if user prescribes a predelay, adjust all taptimes
  512. if(predelay >= 0.0){
  513. double current_delay = ptaps[0].pos;
  514. double adjust = predelay - current_delay;
  515. for(int i = 0; i < ntaps; i++)
  516. ptaps[i].pos += adjust;
  517. }
  518. else
  519. predelay = ptaps[0].pos; //to report to user
  520. tdelay = new tapdelay(ptaps,ntaps,sr);
  521. if(!tdelay->create()) {
  522. fputs("rmverb: no memory for early reflections\n",stderr);
  523. return 1;
  524. }
  525. //max_gain = tdelay->get_maxgain();
  526. //if(max_gain > 1.0)
  527. // tdelay->set_gain(max_gain * early_gain);
  528. // final allpass chain: 0.02,0.014,0.009,0.006
  529. ap1_l = new allpassfilter(sr,to_prime(0.02,sr),-0.6,0);
  530. ap2_l = new allpassfilter(sr,to_prime(0.014,sr),0.4,0);
  531. // ap3_l = new allpassfilter(to_prime(0.009,sr),-0.6,0);
  532. // ap4_l = new allpassfilter(to_prime(0.006,sr),0.4,0);
  533. if(!(ap1_l->create()
  534. && ap2_l->create()
  535. // && ap3_l->create()
  536. // && ap4_l->create()
  537. )){
  538. fprintf(stderr,"rmverb: no memory for allpass chain\n");
  539. exit(1);
  540. }
  541. if(outchans >=2){
  542. // slightly different params to make stereo!
  543. // tune front pair precisely; further chans use formula
  544. ap1_r = new allpassfilter(sr,to_prime(0.025,sr),-0.6,0);
  545. ap2_r = new allpassfilter(sr,to_prime(0.0145,sr),0.4,0);
  546. // ap3_r = new allpassfilter(to_prime(0.0095,sr),-0.6,0);
  547. // ap4_r = new allpassfilter(to_prime(0.0065,sr),0.4,0);
  548. if(!(ap1_r->create()
  549. && ap2_r->create()
  550. // && ap3_r->create()
  551. // && ap4_r->create()
  552. )){
  553. fprintf(stderr,"rmverb: no memory for allpass chain\n");
  554. exit(1);
  555. }
  556. }
  557. printf("using %ld early reflections: predelay = %.2lf msecs\n",ntaps,predelay * 1000.0);
  558. int clipfloats = 1;
  559. int minheader = 0;
  560. if(want_floats) {
  561. props.samptype =PSF_SAMP_IEEE_FLOAT;
  562. clipfloats = 0;
  563. }
  564. props.chans = outchans;
  565. if((ofd = psf_sndCreate(argv[OUTFILE],&props,clipfloats,minheader,PSF_CREATE_RDWR)) < 0) {
  566. fprintf(stderr,"rmverb: cannot open output file %s\n",argv[OUTFILE]);
  567. return 1;
  568. }
  569. /****
  570. |wet
  571. ***** in-> ---o-->pre_lp -->earlies-o--->diffuser-->*diffgain-->--+--*---+----out
  572. | | | |
  573. | |>--------*-(earlies)->-------| *--dry
  574. | ^earlygain |
  575. |__________________________________________________________|
  576. ****/
  577. printf("\ninfile chans = %ld, outfile chans = %ld",chans,outchans);
  578. printf("\n");
  579. long outframes = 0;
  580. long step = (long)(0.25 * sr);
  581. float insamps[2], outsamps[16];
  582. double l_out,r_out;
  583. // float finsamp, foutsamp;
  584. for(;;){
  585. int rv;
  586. double l_ip,r_ip, out,l_direct,r_direct,mono_direct,earlies = 0.0f;
  587. //read mono/left
  588. if((rv = psf_sndReadFloatFrames(ifd,insamps,1)) < 0){
  589. fprintf(stderr,"rmverb: error reading file\n");
  590. exit(1);
  591. }
  592. if(rv==0) break; // end of inputfile - handle any trailertime
  593. l_ip = (double) insamps[0];
  594. //apply any conditioning to direct signal
  595. if(tc_l_lowcut)
  596. l_ip = tc_l_lowcut->tick(l_ip);
  597. if(l_highcut)
  598. l_ip = l_highcut->tick(l_ip);
  599. l_direct = l_ip;
  600. mono_direct = l_direct;
  601. r_direct = l_direct;
  602. //handle R channnel if active
  603. if(chans==2){
  604. r_ip = (double) insamps[1];
  605. //apply any conditioning to direct signal
  606. if(tc_r_lowcut)
  607. r_ip = tc_r_lowcut->tick(r_ip);
  608. if(r_highcut)
  609. r_ip = r_highcut->tick(r_ip);
  610. r_direct = r_ip;
  611. if(want_mono) //input merged sig to reverbreator
  612. mono_direct = (l_direct + r_direct) * 0.5;
  613. }
  614. // mono_direct = (mixed) mono input to reverb
  615. //possibly also filter it...
  616. if(lp)
  617. mono_direct = lp->tick(mono_direct); //input lowpass
  618. earlies = tdelay->tick(mono_direct); //early reflections
  619. //send (filtered) mono output from reverberator
  620. // TODO: find formula for diffgain...
  621. out = earlies + (cdpdiff->tick(earlies + mono_direct) * diff_gain * 0.707); //the dense reverberation
  622. // output:: use 2 allpasses per chan to generate stereo reverb, wider diffusion
  623. l_out = wet_gain * ap2_l->tick(ap1_l->tick(out));
  624. // old method - 1 allpass per channel
  625. //l_out = chan_ap[0]->tick(out) * wet_gain;
  626. if(outchans == 1)
  627. l_out += (mono_direct * dry_gain);
  628. else
  629. l_out += l_direct * dry_gain;
  630. outsamps[0] = (float) l_out;
  631. if(outchans>=2){
  632. r_out = wet_gain * ap2_r->tick(ap1_r->tick(out));
  633. // old version
  634. //r_out = chan_ap[1]->tick(out) * wet_gain;
  635. r_out += r_direct * dry_gain;
  636. outsamps[1] = (float) r_out;
  637. }
  638. //now any further channels; reduced level of direct sig
  639. for(i=2;i < outchans; i++){
  640. out = earlies + (cdpdiff->tick(earlies + (mono_direct * 0.3)) * diff_gain * 0.707);
  641. l_out = wet_gain * chan_ap[i]->tick(out);
  642. outsamps[i] = (float) l_out;
  643. }
  644. if(psf_sndWriteFloatFrames(ofd,outsamps,1) != 1){
  645. fprintf(stderr,"rmverb: error writing output file\n");
  646. return 1;
  647. }
  648. outframes++;
  649. if((outframes % step) == 0)
  650. fprintf(stdout,"%.2f\r",(double)outframes/(double)sr);
  651. }
  652. int trtime = (int)( trailertime * sr);
  653. for(i = 0; i < trtime; i++){
  654. double tr_l_ip,tr_r_ip = 0.0f,tr_out,tr_l_direct,tr_r_direct,
  655. tr_mono_direct,tr_earlies = 0.0f,tr_l_out,tr_r_out;
  656. //need last active samps from input filter(s)
  657. tr_l_ip = 0.0;
  658. if(tc_l_lowcut)
  659. tr_l_ip = tc_l_lowcut->tick(tr_l_ip);
  660. if(l_highcut)
  661. tr_l_ip = l_highcut->tick(tr_l_ip);
  662. tr_l_direct = tr_l_ip;
  663. tr_mono_direct = tr_l_direct;
  664. tr_r_direct = tr_l_direct;
  665. //handle R channnel if active
  666. if(chans==2){
  667. tr_r_ip = 0.0; // inout is zero, except if using input filters
  668. // get any samples from input conditioning filters
  669. if(tc_r_lowcut)
  670. tr_r_ip = tc_r_lowcut->tick(0.0);
  671. if(r_highcut)
  672. tr_r_ip = r_highcut->tick(tr_r_ip);
  673. tr_r_direct = tr_r_ip;
  674. if(want_mono)
  675. tr_mono_direct = (tr_l_direct + tr_r_direct) *0.5f;
  676. }
  677. // mono_direct = (mixed) mono input to reverb
  678. //possibly also filter it...
  679. if(lp)
  680. tr_mono_direct = lp->tick(tr_mono_direct);
  681. tr_earlies = tdelay->tick(tr_mono_direct);
  682. //send (filtered) mono output from reverberator
  683. tr_out = tr_earlies + (cdpdiff->tick(tr_earlies + tr_mono_direct) * diff_gain * 0.707);
  684. // output:: use 2 allpasses to generate stereo reverb, further diffusion
  685. // new version
  686. tr_l_out = wet_gain * ap2_l->tick(ap1_l->tick(tr_out));
  687. // old version
  688. //tr_l_out = chan_ap[0]->tick(tr_out) * wet_gain;
  689. if(want_mono)
  690. tr_l_out += (tr_mono_direct * dry_gain);
  691. else
  692. tr_l_out += tr_l_direct * dry_gain;
  693. outsamps[0] = (float) tr_l_out;
  694. if(outchans>=2){
  695. tr_r_out = wet_gain * ap2_r->tick(ap1_r->tick(tr_out));
  696. // old version:
  697. //tr_r_out = chan_ap[1]->tick(tr_out) * wet_gain;
  698. tr_r_out += tr_r_direct * dry_gain; // still need this cos of input filters
  699. outsamps[1] = (float) tr_r_out;
  700. }
  701. for(int j = 2; j < outchans; j++){
  702. tr_r_out = chan_ap[j]->tick(tr_out) * wet_gain;
  703. outsamps[j] = (float) tr_r_out;
  704. }
  705. if(psf_sndWriteFloatFrames(ofd,outsamps,1) != 1){
  706. fprintf(stderr,"rmverb: error writing output file\n");
  707. return 1;
  708. }
  709. outframes++;
  710. if((outframes % step)==0)
  711. //inform(step,sr);
  712. fprintf(stdout,"%.2f\r",(double)outframes/(double)sr);
  713. }
  714. fprintf(stdout,"%.2f\n",(double)outframes/(double)sr);
  715. //stopwatch(0);
  716. peaks = (PSF_CHPEAK *) malloc(sizeof(PSF_CHPEAK) * outchans);
  717. if(peaks && psf_sndReadPeaks(ofd,peaks,NULL)) {
  718. printf("\nPEAK data:\n");
  719. for(i=0;i < outchans;i++)
  720. printf("Channel %d: %.4f at frame %u: %.4lf secs\n",i+1,
  721. peaks[i].val,peaks[i].pos, (double) peaks[i].pos / (double)props.srate);
  722. }
  723. else {
  724. fputs("rmverb: warning: unable to read PEAK data\n",stderr);
  725. }
  726. psf_sndClose(ifd);
  727. if(psf_sndClose(ofd) < 0)
  728. fprintf(stderr,"rmverb: error closing outfile\n");
  729. printf("\n");
  730. psf_finish();
  731. free(peaks);
  732. delete tdelay;
  733. if(usertaps)
  734. delete [] ptaps;
  735. //can I call delete on base-class ptr?
  736. if(s_diffuser)
  737. delete s_diffuser;
  738. if(m_diffuser)
  739. delete m_diffuser;
  740. if(l_diffuser)
  741. delete l_diffuser;
  742. if(lp)
  743. delete lp;
  744. if(outchans > 1){
  745. for(i=0;i < outchans; i++)
  746. delete chan_ap[i];
  747. delete [] chan_ap;
  748. }
  749. delete tc_l_lowcut;
  750. delete tc_r_lowcut;
  751. delete l_highcut;
  752. delete r_highcut;
  753. return 0;
  754. }
  755. void
  756. usage(void)
  757. {
  758. fprintf(stderr,"\nrmverb: Multi-channel reverb with room simulation\n\tVersion 1.3 Release 5 CDP 1998,1999,2011");
  759. fprintf(stderr,
  760. "\nusage:\nrmverb [flags] infile outfile rmsize rgain mix fback absorb lpfreq trtime"
  761. "\nflags : any or all of the following"
  762. "\n -cN : create outfile with N channels (1 <= N <= 16 : default =2)"
  763. "\n -d : apply double lowpass damping (internal to nested allpasses)"
  764. "\n (see <absorb>. NB: reduces reverb time: "
  765. "\n increase feedback to compensate)"
  766. "\n -eFILE: read early reflections data from breakpoint textfile FILE"
  767. "\n -f : force floating-point output (default: infile format)"
  768. "\n -HN : apply 12dB Highcut filter with cutoff freq N Hz) to infile"
  769. "\n -LN : apply 12dB Lowcut filter with cutoff freq N Hz to infile"
  770. "\n (NB: currently fixed at 12dB/oct - could be made variable)\n"
  771. "\n -pN : force reverb predelay to N msecs (shifts early reflections)"
  772. "\nrmsize : 1,2 or 3: small, medium or large"
  773. "\nrgain : set level of dense reverb (0.0 < egain <= 1.0)"
  774. "\nmix : dry/wet balance (source and reverb). 1.0<-- mix -->=0.0"
  775. "\nfback : reverb feedback level: controls decay time. 0.0 <= fback <= 1.0"
  776. "\nabsorb : cutoff freq (Hz) of internal lowpass filters (models air absorption)\n"
  777. " (typ: 2500 for large room --- 4200 for small room "
  778. "\nlpfreq : lowpass filter cutoff freq(Hz) applied at input to reverb"
  779. "\n NB: to disable either filter (absorb,lpfreq), use the value 0"
  780. "\ntrtime : trailer time added to outfile for reverb tail (secs)\n");
  781. exit(0);
  782. }
  783. long readtaps(FILE *fp, deltap **taps,double sr)
  784. {
  785. vector<deltap> vtaps;
  786. deltap thistap;
  787. char line[256];
  788. int ntaps = 0;
  789. int linecount = 1;
  790. bool error = false;
  791. double time= 0.0, current_time = 0.0, val = 0.0;
  792. double sample_duration = 1.0 / sr;
  793. if(fp==0 || sr <= 0.0){
  794. *taps = 0;
  795. return 0;
  796. }
  797. while(fgets(line,256,fp)) {
  798. int got;
  799. if(line[0] == '\n' || line[0]== ';'){ //allow comment lines; this does not check for leading white-space...
  800. linecount++;
  801. continue;
  802. }
  803. if((got = sscanf(line,"%lf%lf",&time,&val))<2){
  804. fprintf(stderr,"\nerror in reflections file: line %d",linecount);
  805. error =true;
  806. break;
  807. }
  808. if(time < 0.0){
  809. fprintf(stderr,"\nerror in tapfile: line %d: bad time value",linecount);
  810. error = true;
  811. break;
  812. }
  813. //if (first) val = 0.0, or VERY close
  814. if(time < sample_duration) { //non-zero time must be at least one sample on!
  815. fprintf(stderr,"\nWARNING: very small taptime %.4lf treated as zero",time);
  816. time = 0.0;
  817. }
  818. if(current_time != 0.0 && time==current_time){
  819. fprintf(stderr,"\nWARNING: duplicate time in line %d: ignored",linecount);
  820. linecount++;
  821. continue;
  822. }
  823. if(time < current_time){
  824. fprintf(stderr,"\nerror in tapfile: time out of sequence: line %d",linecount);
  825. error = true;
  826. break;
  827. }
  828. current_time = time;
  829. thistap.pos = time;
  830. if(val <=0.0 || val > 1.0){
  831. fprintf(stderr,"\nerror: bad amplitude in tapfile: line %d",linecount);
  832. error = true;
  833. break;
  834. }
  835. thistap.val = val;
  836. vtaps.push_back(thistap);
  837. linecount++;
  838. }
  839. ntaps = vtaps.size();
  840. if(ntaps==0){
  841. fprintf(stderr,"\ntapfile contains no data!");
  842. error = true;
  843. }
  844. if(error){
  845. *taps = 0;
  846. return 0;
  847. }
  848. *taps = new deltap[ntaps];
  849. if(taps==0)
  850. return 0;
  851. vector<deltap>::iterator I = vtaps.begin();
  852. for(int i = 0; I != vtaps.end();i++, I++){
  853. (*taps)[i].pos = I->pos;
  854. (*taps)[i].val = I->val;
  855. }
  856. return ntaps;
  857. }