| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749 |
- /*
- * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
- * http://people.bath.ac.uk/masrwd
- * http://www.composersdesktop.com
- * This file is part of the CDP System.
- * The CDP System is free software; you can redistribute it
- * and/or modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * The CDP System is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public
- * License along with the CDP System; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
- /* MODULE FOR REVERB.EXE */
- /* RWD Nov 2025 moved to top to avoid low-level cpp lib definition ambiguities in MinGW */
- extern "C" {
- #include <sfsys.h>
- #include <stddef.h>
- #include <osbind.h>
- #include <cdplib.h> //NB requires stdio.h etc - time to change this?
- }
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #ifdef _DEBUG
- #include <assert.h>
- #endif
- #include <algorithm>
- #include <vector>
- using namespace std;
- /***** FORMULA FOR LOOP GAIN *****
- g = pow(10, - ( ((60*ilooptime)/reverbtime) / 20))
- derived from Moore:
- reverbtime = 60/(-20.log10(g)) * ilooptime
- then we set igain = g(1 - filtgain), officially...
- */
- #include "reverberator.h"
- #include <string.h>
- void usage(void);
- long readtaps(FILE *fp, deltap **taps,double sr);
- //my library of early reflections...
- //by doing it this way I can use the sizeof() operator on the array names
- #include "reflect.cpp"
- enum cmdargs {
- PROGNAME,
- INFILE,
- OUTFILE,
- RGAIN,
- MIX,
- REVERBTIME,
- DAMPING,
- LPFREQ,
- TRTIME,
- CONFIG
- };
- const char* cdp_version = "5.0.0";
- ///////////// Moorer reverb
- int
- main(int argc,char *argv[])
- {
- int ifd=-1, ofd=-1,i;
- //double delaytime,gain;
- double rvbtime, damping, trailertime = 0.0;
- long chans,outchans = 2;
- double sr;
- //all this stuff from Brandt Csound implementation of posh Moorer
- MOORERDATA mrdata = {0.050,0.056,0.061,0.068,0.072,0.078,0.02,0.014,0.009,0.006};
- double predelay = 0.0;
- moorer *moorerverb = 0;
- tapdelay *tdelay = 0;
- deltap *ptaps = 0;
- allpassfilter **chan_ap = 0; //ptr to array of allpassfilter ptrs
- tonecontrol *tc_l_lowcut = 0, *tc_r_lowcut = 0;
- // could be replaced with a tonecontrol for deeper slope
- onepole *l_highcut = 0, *r_highcut = 0, *lp = 0;
- FILE *fp_earlies = 0;
- long ntaps;
- bool want_mono = false;
- bool want_floats = false;
- bool usertaps = false;
- double lowcut_freq = 0.0,highcut_freq = 0.0,lp_freq = 0.0;
- float dry_gain,wet_gain,diff_gain;
- CHPEAK *peaks;
- SFPROPS props;
- // test vcomb with variable delay taps
- //vmtcomb4 vcomb;
- //fastlfo lfo1,lfo2,lfo3,lfo4;
- if((argc==2) && strcmp(argv[1],"--version")==0) {
- fprintf(stdout,"%s\n",cdp_version);
- fflush(stdout);
- return 0;
- }
- if(sflinit("reverb")){
- sfperror("reverb: initialisation");
- exit(1);
- }
- if(argc < CONFIG) usage();
- while((argc > 1) && argv[1][0]=='-'){
- char *arg = argv[1];
- switch(*(++arg)){
- case('p'):
- if(*(++arg) =='\0'){
- fprintf(stderr,"\npredelay requires a parameter");
- usage();
- }
- predelay = atof(arg);
- if(predelay <0.0){
- fprintf(stderr,"\npredelay must be >= 0.0");
- usage();
- }
- predelay *= 0.001; //arg is in msecs
- break;
- case('c'):
- if(*(++arg) == '\0') {
- fprintf(stderr,"\n:reverb: -c flag requires a value");
- usage();
- }
- outchans = atoi(arg);
- if(outchans < 1 || outchans > 16){
- fprintf(stderr,"\nreverb: impossible channel value requested");
- usage();
- }
- if(outchans==1)
- want_mono = true;
- break;
- case('e'):
- if(*(++arg)=='\0'){
- fprintf(stderr,"\nreverb: -e flag needs a filename");
- usage();
- }
- if((fp_earlies = fopen(arg,"r")) ==0){
- fprintf(stderr,"\nreverb: unable to open breakpoint file %s",arg);
- exit(1);
- }
- usertaps = true;
- break;
- case('f'):
- want_floats = true;
- if(*(++arg) != '\0')
- fprintf(stderr,"\nreverb: WARNING: -f flag does not take a parameter");
- break;
- case('L'):
- if(*(++arg) == '\0'){
- fprintf(stderr,"\nreverb: Lowcut flag needs frequency argument");
- usage();
- }
- lowcut_freq = atof(arg);
- if(lowcut_freq <= 0.0){
- fprintf(stderr,"\nreverb: Lowcut freq must be greater than zero");
- usage();
- }
- break;
- case('H'):
- if(*(++arg) == '\0'){
- fprintf(stderr,"\nreverb: Highcut flag needs frequency argument");
- usage();
- }
- highcut_freq = atof(arg);
- if(highcut_freq <= 0.0){
- fprintf(stderr,"\nreverb: Highcut freq must be greater than zero");
- usage();
- }
- break;
- default:
- fprintf(stderr,"\nreverb: illegal flag option %s",argv[1]);
- usage();
- break;
- }
- argc--;
- argv++;
- }
- peaks = (CHPEAK *) malloc(sizeof(CHPEAK) * outchans);
- if(peaks==NULL){
- fputs("\nNo memory for PEAK data\n",stderr);
- exit(1);
- }
- chan_ap = new allpassfilter*[outchans];
- if(chan_ap==0){
- fputs("\nreverb: no memory for multi-channel diffusion",stderr);
- exit(1);
- }
- if(argc < CONFIG)
- usage();
- if(argv[INFILE] != 0) {
- if((ifd = sndopenEx(argv[INFILE],0,CDP_OPEN_RDONLY)) < 0) {
- fprintf(stderr,"\nreverb: cannot open input file %s\n", argv[INFILE]);
- exit(1);
- }
- }
- if(!snd_headread(ifd,&props)){
- fprintf(stderr,"\nerror reading infile header: %s\n",rsferrstr);
- sndcloseEx(ifd);
- exit(1);
- }
- if(props.type != wt_wave){
- fprintf(stderr,"\ninfile is not a waveform file");
- sndcloseEx(ifd);
- exit(1);
- }
-
- sr = (double) props.srate;
- chans = props.chans;
- if(chans > 2){
- fprintf(stderr,"\nreverb works only on mono or stereo files");
- exit(1);
- }
-
-
- diff_gain = atof(argv[RGAIN]);
- if(diff_gain < 0.0 || diff_gain > 1.0 ){
- printf("\nreverb: rgain must be >= 0.0 and <= 1.0");
- usage();
- }
- dry_gain = (float) atof(argv[MIX]); //global output gain from diffuser
- if(dry_gain < 0.0 || dry_gain >= 1.0 ){
- printf("\nreverb: mix must be between 0.0 and 1.0");
- usage();
- }
- wet_gain = 1.0f - dry_gain;
- //probably not very scientific, but it works intuitively...
- //wet_gain *= 2;
-
- rvbtime = atof(argv[REVERBTIME]);
- if(rvbtime <= 0.0){
- fprintf(stderr,
- "\nreverb: rvbtime must be > 0\n");
- exit(1);
- }
- damping = atof(argv[DAMPING]);
- if(damping < 0.0 || damping > 1.0){
- fprintf(stderr,"\nreverb: absorb must be in the range 0.0 - 1.0\n");
- exit(1);
- }
- double filt_limit = sr / 3.0;
- lp_freq = atof(argv[LPFREQ]);
- if(lp_freq < 0.0 || lp_freq > filt_limit){
- printf("\napass: lp_freq must be within 0.0 to %.4lfHz",filt_limit);
- usage();
- }
- trailertime = atof(argv[TRTIME]);
- if(trailertime < 0.0)
- trailertime = 0.0;
-
- if(argc==CONFIG+1){
- int got = 0;
- double dtime1,dtime2,dtime3,dtime4,dtime5,dtime6,
- adtime1,adtime2,adtime3,adtime4;
- FILE *fp = fopen(argv[CONFIG],"r");
- if(!fp)
- printf("\nreverb: can't open datafile %s: using presets",argv[CONFIG]);
- else{
- got = fscanf(fp,"%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf",
- &dtime1,
- &dtime2,
- &dtime3,
- &dtime4,
- &dtime5,
- &dtime6,
- &adtime1, //allpasses
- &adtime2,
- &adtime3,
- &adtime4
- );
- fclose(fp);
- if(got != 10)
- printf("\nreverb: error reading looptime values");
- else {
- //create prime delay times from the msec vals
- //get this in a loop later on...
- //RWD TODO: check times are not too huge!
- mrdata.ctime1 = dtime1 * 0.001;
- mrdata.ctime2 = dtime2 * 0.001;
- mrdata.ctime3 = dtime3 * 0.001;
- mrdata.ctime4 = dtime4 * 0.001;
- mrdata.ctime5 = dtime5 * 0.001;
- mrdata.ctime6 = dtime6 * 0.001;
- mrdata.atime1 = adtime1 * 0.001;
- mrdata.atime2 = adtime2 * 0.001;
- mrdata.atime3 = adtime3 * 0.001;
- mrdata.atime4 = adtime4 * 0.001;
- }
- }
- }
- //create input low/high filters, if wanted
- if(lowcut_freq > 0.0){
- if(highcut_freq > 0.0 && highcut_freq <= lowcut_freq){
- fprintf(stderr,"\nreverb: Highcut frequency must be higher than Lowcut frequency");
- usage();
- }
- //lowcut is based on low shelving eq filter; here fixed at 12dB
- tc_l_lowcut = new tonecontrol(lowcut_freq,-12.0,LOW_SHELVE,sr);
- if(!tc_l_lowcut->create()){
- fprintf(stderr,"\nreverb: unable to create Lowcut filter");
- exit(1);
- }
- if(chans==2){
- tc_r_lowcut = new tonecontrol(lowcut_freq,-12.0,LOW_SHELVE,sr);
- if(!tc_r_lowcut->create()){
- fprintf(stderr,"\nreverb: unable to create Lowcut filter");
- exit(1);
- }
- }
- }
- if(highcut_freq > 0.0){
- l_highcut = new onepole(highcut_freq,sr,LOW_PASS);
- if(chans==2)
- r_highcut = new onepole(highcut_freq,sr,LOW_PASS);
- }
- if(lp_freq > 0.0)
- lp = new onepole(lp_freq,sr,LOW_PASS);
- moorerverb = new moorer(&mrdata,rvbtime,damping,sr);
- //further external allpasses will be used to create multi-channel diffusion
-
- for(i = 0; i < outchans; i++){
- chan_ap[i] = new allpassfilter(sr,to_prime(0.005 + 0.00025 * (double)i,sr),0.4 ,0);
- if(chan_ap[i] == 0) {
- fprintf(stderr,"\nreverb: no memory for output diffusers");
- exit(1);
- }
- if(!chan_ap[i]->create()){
- fprintf(stderr,"\nreverb: no memory for output diffusers");
- exit(1);
- }
- }
- if(usertaps){
- #ifdef _DEBUG
- assert(fp_earlies);
- #endif
- ntaps = readtaps(fp_earlies,&ptaps,sr);
- if(ntaps==0){
- fprintf(stderr,"\nreverb: error reading tapfile");
- exit(1);
- }
- printf("\nloaded %ld early reflections from tapfile",ntaps);
- fclose(fp_earlies);
- fp_earlies = 0;
- }
- else {
- if(rvbtime <= 0.6){
- ntaps = sizeof(smalltaps) / sizeof(deltap);
- ptaps = smalltaps;
- printf("\nsmall-room: using %ld early reflections",ntaps);
- }
- else if(rvbtime > 0.6 && rvbtime <= 1.3){
- ntaps = sizeof(mediumtaps) / sizeof(deltap);
- ptaps = mediumtaps;
- printf("\nmedium-room: using %ld early reflections",ntaps);
- }
- else{
- ntaps = sizeof(largetaps) / sizeof(deltap);
- ptaps = largetaps;
- printf("\nlarge-room: using %ld early reflections",ntaps);
- }
- }
- tdelay = new tapdelay(ptaps,ntaps,sr);
- //if user prescribes a predelay, adjust all taptimes
- if(predelay > 0.0){
- double current_delay = ptaps[0].pos;
- double adjust = predelay - current_delay;
- for(int i = 0; i < ntaps; i++)
- ptaps[i].pos += adjust;
- }
-
- if(!moorerverb->create()){
- fprintf(stderr,"\nreverb: unable to create reverberator");
- exit(1);
- }
- if(!tdelay->create()){
- fprintf(stderr,"\nreverb: unable to create early reflections");
- exit(1);
- }
-
- //double maxgain = tdelay->get_maxgain();
- //if(maxgain > 1.0)
- // tdelay->set_gain(maxgain * early_gain);
- printf("\npredelay = %.4lf secs",ptaps[0].pos);
- //wet_gain *= floor(maxgain);
- if(want_floats)
- props.samptype =FLOAT32;
- props.chans = outchans;
- if((ofd = sndcreat_ex(argv[OUTFILE],-1,&props,SFILE_CDP,CDP_CREATE_NORMAL)) < 0) {
- fprintf(stderr,"\nreverb: cannot open output file %s\n",argv[OUTFILE]);
- exit(1);
- }
- printf("\n");
- long outsamps = 0;
- long step = (long) (0.25 * sr);
- #ifdef NOTDEF
- // vcomb test
- long seed = lfo1.init((double)inprops.srate,0.0,seed);
- lfo1.set_WaveType(LFO_RANDOM);
- lfo1.set_freq(0.5);
- lfo1.set_mod(1.0); /* no change - we control modf range externally */
- lfo2.init((double)inprops.srate,0.0,seed);
- lfo2.set_WaveType(LFO_RANDOM);
- lfo2.set_freq(0.55);
- lfo2.set_mod(1.0);
- lfo3.init((double)inprops.srate,0.0,seed);
- lfo3.set_WaveType(LFO_RANDOM);
- lfo3.set_freq(0.61);
- lfo3.set_mod(1.0);
- lfo4.init((double)inprops.srate,0.0,seed);
- lfo4.set_WaveType(LFO_RANDOM);
- lfo4.set_freq(0.66);
- lfo4.set_mod(1.0);
- vcomb.init(double)srate,0.8);
- double delay1,delay2,delay3,delay4;
- double delaymod = 0.05;
- delay1 = 0.05;
- delay2 = 0.056;
- delay3 = 0,061;
- delay4 = 0.068;
- vcomb.init(double)srate,delay4 + (delay4 * delaymod));
- vcomb.setfgains(
- #endif
- //stopwatch(1);
- //run main single-sample loop
- float l_ip,r_ip,l_out,r_out,l_direct,r_direct,mono_direct;
- for(;;){
- int rv;
- float out,earlies;
- //read mon/left channnel
- if((rv = fgetfloatEx(&l_ip,ifd,0)) < 0){
- fprintf(stderr,"\nreverb: error reading infile");
- exit(1);
- }
- if(!rv) break; // end of inputfile - handle any trailertime
- //apply any conditioning to direct signal
- if(tc_l_lowcut)
- l_ip = (float) tc_l_lowcut->tick((double)l_ip);
- if(l_highcut)
- l_ip = (float) l_highcut->tick((double)l_ip);
- l_direct = l_ip;
- mono_direct = l_direct;
- r_direct = l_direct;
- //handle R channnel if active
- if(chans==2){
- if((rv = fgetfloatEx(&r_ip,ifd,0)) < 0){
- fprintf(stderr,"\nError in reading file");
- exit(1);
- }
- if(!rv) break;
- //apply any conditioning to direct signal
- if(tc_r_lowcut)
- r_ip = (float) tc_r_lowcut->tick((double)r_ip);
- if(r_highcut)
- r_ip = (float) r_highcut->tick((double)r_ip);
- r_direct = r_ip;
- if(want_mono)
- mono_direct = (l_direct + r_direct) * 0.5f;
- }
- //mono_direct = (mixed) input to reverberator
- //possibly also filter it...
- if(lp)
- mono_direct = (float) lp->tick(mono_direct); //input lowpass
- earlies = tdelay->tick(mono_direct); // ---> early reflections
- //send (filtered) mono output from reverberator
- out = earlies + moorerverb->tick(earlies + mono_direct) * diff_gain;
- //and send thru multi_channel diffusers
- //NB must handle first 2 chans as special cases, then loop thru the rest
- //l_out = want_mono ? mono_direct : l_direct;
- //l_out *= dry_gain;
- l_out = chan_ap[0]->tick(out) * wet_gain;
- if(want_mono)
- l_out += (mono_direct * dry_gain);
- else
- l_out += l_direct * dry_gain;
-
-
- if((float)fabs((double)l_out) > peaks[0].value) {
- peaks[0].value = (float)fabs((double)l_out);
- peaks[0].position = outsamps;
- }
- if(fputfloatEx(&l_out,ofd) < 1){
- fprintf(stderr,"\nreverb: error writing output file");
- exit(1);
- }
-
- if(outchans>=2){
- r_out = r_direct * dry_gain;
- r_out += chan_ap[1]->tick(out) * wet_gain;
- if((float)fabs((double)r_out) > peaks[1].value) {
- peaks[1].value = (float)fabs((double)r_out);
- peaks[1].position = outsamps;
- }
- if(fputfloatEx(&r_out,ofd) < 1){
- fprintf(stderr,"\nreverb: error writing output file");
- exit(1);
- }
- }
- //now any further channels
- for(i=2;i < outchans; i++){
- l_out = chan_ap[i]->tick(out) * wet_gain;
- if((float)fabs((double)l_out) > peaks[i].value) {
- peaks[i].value = (float)fabs((double)l_out);
- peaks[i].position = outsamps;
- }
- if(fputfloatEx(&out,ofd) < 1){
- fprintf(stderr,"\nreverb: error writing output file");
- exit(1);
- }
- }
- outsamps++;
- if((outsamps % step) == 0)
- //inform(step,sr);
- fprintf(stdout,"%.2f\r",(double)outsamps/(double)sr);
- }
- //end of infile; play out reverb tail as much as we're allowed
- int trtime = (int)( trailertime * sr);
- for(i = 0; i < trtime; i++){
- float tr_l_ip,tr_r_ip = 0.0f, tr_out,tr_earlies,tr_l_direct,tr_mono_direct,tr_r_direct,
- tr_l_out,tr_r_out;
- tr_l_ip = 0.0;
- if(tc_l_lowcut)
- tr_l_ip = (float) tc_l_lowcut->tick(tr_l_ip);
- if(l_highcut)
- tr_l_ip = (float) l_highcut->tick(tr_l_ip);
- tr_l_direct = tr_l_ip;
- tr_mono_direct = tr_l_direct;
- tr_r_direct = tr_l_direct;
- //handle R channnel if active
- if(chans==2){
- tr_r_ip = 0.0; // inout is zero, except if using input filters
- // get any samples from input conditioning filters
- if(tc_r_lowcut)
- tr_r_ip = (float) tc_r_lowcut->tick(tr_r_ip);
- if(r_highcut)
- tr_r_ip = (float) r_highcut->tick(tr_r_ip);
- tr_r_direct = tr_r_ip;
- if(want_mono)
- tr_mono_direct = (tr_l_direct + tr_r_direct) *0.5f;
- }
- if(lp)
- tr_mono_direct = (float) lp->tick(tr_mono_direct);
- tr_earlies = tdelay->tick(tr_mono_direct);
- //send (filtered) mono output from reverberator
- tr_out = tr_earlies + moorerverb->tick(tr_earlies * tr_mono_direct) * diff_gain;
- tr_l_out = chan_ap[0]->tick(tr_out) * wet_gain;
- if(want_mono)
- tr_l_out += (tr_mono_direct * dry_gain);
- else
- tr_l_out += tr_l_direct * dry_gain;
- if((float)fabs((double)tr_l_out) > peaks[0].value) {
- peaks[0].value = (float)fabs((double)tr_l_out);
- peaks[0].position = outsamps;
- }
- if(fputfloatEx(&tr_l_out,ofd) < 1){
- fprintf(stderr,"\nreverb: error writing to output file");
- exit(1);
- }
- if(outchans>=2){
- tr_r_out = tr_r_direct * dry_gain;
- tr_r_out += chan_ap[1]->tick(tr_out) * wet_gain;
- if((float)fabs((double)tr_r_out) > peaks[1].value) {
- peaks[1].value = (float)fabs((double)tr_r_out);
- peaks[1].position = outsamps;
- }
- if(fputfloatEx(&tr_r_out,ofd) < 1){
- fprintf(stderr,"\nreverb: error writing to output file");
- exit(1);
- }
- }
- for(int j = 2;j < outchans;j++){
- float ch_out;
- ch_out = chan_ap[j]->tick(tr_out) * wet_gain;
- if((float)fabs((double)ch_out) > peaks[j].value) {
- peaks[j].value = (float)fabs((double)ch_out);
- peaks[j].position = outsamps;
- }
- if(fputfloatEx(&ch_out,ofd) < 1){
- fprintf(stderr,"\nreverb: error writing to output file");
- exit(1);
- }
- }
- outsamps++;
- if((outsamps % step) ==0)
- //inform(step,sr);
- fprintf(stdout,"%.2f\r",(double)outsamps/(double)sr);
- }
- //stopwatch(0);
- printf("\nPEAK data:\n");
- for(i=0;i < outchans;i++)
- printf("Channel %d: %.4f at frame %d: %.4lf secs\n",i+1,
- peaks[i].value,peaks[i].position, (double) peaks[i].position / (double)props.srate);
- sndputpeaks(ofd,outchans,peaks);
- sndcloseEx(ifd);
-
- if(sndcloseEx(ofd) < 0)
- fprintf(stderr,"\nwarning: error closing outfile");
- delete [] peaks;
- if(moorerverb)
- delete moorerverb;
- for(i=0;i < outchans;i++)
- delete chan_ap[i];
- delete [] chan_ap;
- delete tdelay;
- if(usertaps)
- delete [] ptaps;
- return 0;
- }
- void
- usage(void)
- {
- fprintf(stderr,"\nreverb: Multi-channel reverberator\n\tVersion 1.1 Release 4 CDP 1998,1999\n");
- fprintf(stderr,
- "usage: reverb [flags] infile outfile rgain mix rvbtime absorb\n"
- " lpfreq trailertime [times.txt]\n"
- "flags : any or all of the following:\n"
- " -cN : create outfile with N channels (1 <= N <= 16 : default = 2)\n"
- " -eFILE: read early reflections from breakpoint textfile FILE\n"
- " -f : force floating-point output (default: infile format)\n"
- " -HN : apply Highcut filter with cutoff freq N Hz to infile (6db/oct)\n"
- " -LN : apply Lowcut filter with cutoff freq N Hz to infile (12dB/oct)\n"
- " -pN : force reverb predelay to N msecs (shifts early reflections)\n"
- "rgain : set level of dense reverb (0.0 <= rgain <= 1.0)\n"
- "mix : dry/wet balance (source and reverb): 1.0<-- mix -->= 0.0\n"
- "rvbtime : reverb decay time (to -60dB) in seconds\n"
- "absorb : degree of hf damping to suggest air absorption: 0.0 <= absorb <= 1.0\n"
- "lpfreq : lowpass filter cutoff freq (Hz) applied at input to reverb\n"
- " to disable either filter (absorb, lpfreq), use the value 0\n"
- "trtime : trailer time added to outfile for reverb tail (secs)\n"
- "times.txt: list of delay times (msecs) for 6 comb and 4 allpass filters\n"
- );
- exit(0);
- }
- long readtaps(FILE *fp, deltap **taps,double sr)
- {
- vector<deltap> vtaps;
- deltap thistap;
- char line[256];
- int ntaps = 0;
- int linecount = 1;
- bool error = false;
- double time= 0.0, current_time = 0.0, val = 0.0;
- double sample_duration = 1.0 / sr;
- if(fp==0 || sr <= 0.0){
- *taps = 0;
- return 0;
- }
- while(fgets(line,256,fp)) {
- int got;
- if(line[0] == '\n' || line[0]== ';'){ //allow comment lines; this does not check for leading white-space...
- linecount++;
- continue;
- }
- if((got = sscanf(line,"%lf%lf",&time,&val))<2){
- fprintf(stderr,"\nerror in reflections file: line %d",linecount);
- error =true;
- break;
- }
- if(time < 0.0){
- fprintf(stderr,"\nerror in tapfile: line %d: bad time value",linecount);
- error = true;
- break;
- }
- //if (first) val = 0.0, or VERY close
- if(time < sample_duration) { //non-zero time must be at least one sample on!
- fprintf(stderr,"\nWARNING: very small taptime %.4lf treated as zero",time);
- time = 0.0;
- }
- if(current_time != 0.0 && time==current_time){
- fprintf(stderr,"\nWARNING: duplicate time in line %d: ignored",linecount);
- linecount++;
- continue;
- }
- if(time < current_time){
- fprintf(stderr,"\nerror in tapfile: time out of sequence: line %d",linecount);
- error = true;
- break;
- }
- current_time = time;
- thistap.pos = time;
- if(val <=0.0 || val > 1.0){
- fprintf(stderr,"\nerror: bad amplitude in tapfile: line %d",linecount);
- error = true;
- break;
- }
- thistap.val = val;
- vtaps.push_back(thistap);
- linecount++;
- }
-
- ntaps = vtaps.size();
- if(ntaps==0){
- fprintf(stderr,"\ntapfile contains no data!");
- error = true;
- }
- if(error){
- *taps = 0;
- return 0;
- }
- *taps = new deltap[ntaps];
- if(taps==0)
- return 0;
- vector<deltap>::iterator I = vtaps.begin();
- for(int i = 0; I != vtaps.end();i++, I++){
- (*taps)[i].pos = I->pos;
- (*taps)[i].val = I->val;
- }
- return ntaps;
- }
|