delay.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. /*
  2. * Copyright (c) 1983-2013 Composers Desktop Project Ltd
  3. * http://www.composersdesktop.com
  4. * This file is part of the CDP System.
  5. * The CDP System is free software; you can redistribute it
  6. * and/or modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2.1 of the License, or (at your option) any later version.
  9. *
  10. * The CDP System is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. * See the GNU Lesser General Public License for more details.
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with the CDP System; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *
  18. */
  19. /* delay.c
  20. * generalised delay line featuring
  21. * feedthrough, feedforward and feedback
  22. * A. Bentley, Composers' Desktop Project, Nov 1987.
  23. * Revised and extended to stereo and command-line mode
  24. * by Richard Dobson Oct 1993.
  25. */
  26. static char *rcsid = "$Id: delay.c%v 3.3 1994/10/31 22:30:12 martin Exp $";
  27. /*
  28. * $Log: delay.c%v $
  29. * Revision 3.3 1994/10/31 22:30:12 martin
  30. * first rcs version
  31. *
  32. */
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <math.h>
  36. #include "sfsys.h"
  37. #include "cdplib.h"
  38. static char *sfsys_h_rcsid = SFSYS_H_RCSID;
  39. static char *cdplib_h_rcsid = CDPLIB_H_RCSID;
  40. #define remainder my_remainder
  41. #define BUFLEN (4096)
  42. #define DELBUFSIZ (176400) /* allows 2sec delay in stereo */
  43. #define ONE_FLT (65536.0)
  44. void domono();
  45. void dostereo();
  46. void usage();
  47. void delinit(int cmndline,char *argv[]);
  48. void initfbuf();
  49. void initlbuf();
  50. int Funcflag = 0;
  51. int Quickflag = 1;
  52. long Nchans;
  53. long Delaysamps;
  54. long bufcnt;
  55. long remainder;
  56. float *Fdelbuf;
  57. long *Ldelbuf;
  58. double Sr;
  59. double Delay;
  60. float Feedforgain;
  61. float Feedbckgain;
  62. float Delaygain;
  63. float Prescale = 1.0F;
  64. double Invert =1.0;
  65. double Rescale;
  66. long Lfeedforgain;
  67. long Lfeedbckgain;
  68. long Ldelaygain;
  69. long Lprescale;
  70. double Trailtime = 0.;
  71. long Trailsamps = 0;
  72. int ifd; /* input file descriptor */
  73. int ofd; /* output file descriptor */
  74. long isr;
  75. long sampsize;
  76. short *inbuf;
  77. short *outbuf;
  78. static char version[] =
  79. "~CDPVER~GROUCHO: DELAY Portable version 3.0, REVISED BY R. DOBSON OCT 1993.";
  80. PROGRAM_NUMBER(0xf93c2705);
  81. void
  82. main(argc,argv)
  83. int argc;
  84. char *argv[];
  85. {
  86. int cmndline = 0;
  87. char *ptr;
  88. if(sflinit("delay")) {
  89. sfperror("Delay: initialisation");
  90. exit(1);
  91. }
  92. while(argv[1] != 0 && argv[1][0] == '-') {
  93. switch(argv[1][1]) {
  94. case 'f':
  95. Quickflag--;
  96. break;
  97. case 'p':
  98. ptr = (char *) &(argv[1][2]);
  99. if(*ptr==0)
  100. {
  101. usage();
  102. }
  103. Prescale = (float)atof(ptr);
  104. if(Prescale==0.0)
  105. {
  106. printf("\ndelay: -p error, prescale = 0.0!\n");
  107. usage();
  108. }
  109. break;
  110. case 'i':
  111. Invert = -1.0;
  112. break;
  113. default:
  114. usage();
  115. break;
  116. }
  117. argv++; argc--;
  118. }
  119. if(argc < 3) usage();
  120. if(argc>4)
  121. {
  122. if(argc<7)
  123. {
  124. fprintf(stderr,"\ndelay: incorrect no of parameters");
  125. usage();
  126. }
  127. else
  128. {
  129. cmndline=1;
  130. }
  131. }
  132. if((inbuf =
  133. (short *) malloc((BUFLEN) * sizeof(short))) == NULL) {
  134. fprintf(stderr,"\ndelay: not enough memory for input buffer");
  135. exit(1);
  136. }
  137. if((outbuf =
  138. (short *) malloc(BUFLEN * sizeof(short))) == NULL) {
  139. fprintf(stderr,"\ndelay: not enough memory for output buffer");
  140. exit(1);
  141. }
  142. if((ifd = sndopen(argv[1])) < 0) {
  143. fprintf(stderr,"\ndelay: unable to open input file\n");
  144. exit(1);
  145. }
  146. if(sndgetprop(ifd,"sample rate",(char *) &isr, sizeof(long)) < 0) {
  147. fprintf(stderr,"\ndelay: failed to get sample rate");
  148. exit(1);
  149. }
  150. if(sndgetprop(ifd,"channels",(char *) &Nchans, sizeof(long)) < 0) {
  151. fprintf(stderr,"\ndelay: failed to get channel data");
  152. exit(1);
  153. }
  154. if(sndgetprop(ifd,"sample type",(char *) &sampsize, sizeof(long)) < 0){
  155. fprintf(stderr,"\ndelay: failed to get sample type");
  156. exit(1);
  157. }
  158. if(Nchans > 2) {
  159. fprintf(stderr,"\ndelay: too many channels! Mono or stereo only.\n");
  160. exit(1);
  161. }
  162. Sr = (double) isr;
  163. delinit(cmndline,argv);
  164. if((ofd = sndcreat(argv[2],-1,sampsize)) < 0) {
  165. fprintf(stderr,"\ndelay: unable to open output file\n");
  166. exit(1);
  167. }
  168. if(!Quickflag)
  169. initfbuf();
  170. else
  171. initlbuf();
  172. stopwatch(1);
  173. if(Nchans==1) {domono();} else {dostereo();}
  174. stopwatch(0);
  175. sndclose(ifd);
  176. if(sndputprop(ofd,"sample rate",(char *) &isr, sizeof(long)) < 0){
  177. fprintf(stderr,"\ndelay: failed to write sample rate");
  178. }
  179. if(sndputprop(ofd,"channels", (char *) &Nchans, sizeof(long)) < 0){
  180. fprintf(stderr,"\ndelay: failed to write channel data");
  181. }
  182. free(inbuf);
  183. free(outbuf);
  184. if(!Quickflag) {free(Fdelbuf);} else {free(Ldelbuf);}
  185. sndclose(ofd);
  186. sffinish();
  187. }
  188. void
  189. domono()
  190. {
  191. int i;
  192. long rdsamps;
  193. float input,output;
  194. long linput,loutput;
  195. long ltemp1,ltemp2;
  196. long ipptr=0,opptr=0;
  197. do /* while rdsamps */
  198. {
  199. if((rdsamps = fgetsbuf(inbuf, BUFLEN, ifd)) < 0) {
  200. fprintf(stderr,"\ndelay: failure to read input file\n");
  201. exit(1);
  202. }
  203. for(i=0;i<rdsamps;i++)
  204. {
  205. /* delay line */
  206. input = inbuf[i] * Prescale;
  207. output = (input * Feedforgain) + //dry signal
  208. (Fdelbuf[opptr] * Delaygain);
  209. Fdelbuf[ipptr] = Fdelbuf[opptr++] * Feedbckgain;
  210. Fdelbuf[ipptr++] += input ;
  211. outbuf[i] = (short) output; //dry + wet
  212. if(ipptr >= Delaysamps) ipptr -= Delaysamps;
  213. if(opptr >= Delaysamps) opptr -= Delaysamps;
  214. if(ipptr < 0 || opptr < 0) {
  215. printf(
  216. "\ninternal error, ipptr=%d,opptr=%d\n",ipptr,opptr);
  217. }
  218. }
  219. if(fputsbuf(outbuf,rdsamps,ofd) < rdsamps) {
  220. fprintf(stderr,
  221. "\ndelay: failure in writing to output file\n");
  222. exit(1);
  223. }
  224. inform(rdsamps,Sr);
  225. } while(rdsamps > 0);
  226. /* now do trailer */
  227. rdsamps=BUFLEN;
  228. if (Trailsamps>0) {
  229. do { /* while bufcnt */
  230. if(!bufcnt)
  231. rdsamps = remainder;
  232. for(i=0;i<rdsamps;i++) {
  233. output=(Fdelbuf[opptr] * Delaygain);
  234. Fdelbuf[ipptr++] =
  235. Fdelbuf[opptr++] *Feedbckgain;
  236. outbuf[i] = (short) output;
  237. if(ipptr >= Delaysamps) ipptr -= Delaysamps;
  238. if(opptr >= Delaysamps) opptr -= Delaysamps;
  239. }
  240. if(fputsbuf(outbuf,rdsamps,ofd) < rdsamps){
  241. fprintf(stderr,
  242. "\ndelay: failure in writing to output file\n");
  243. exit(1);
  244. }
  245. inform(BUFLEN,Sr);
  246. bufcnt -=1;
  247. } while(bufcnt>=0);
  248. } /* end if Trailsamps */
  249. } /* end domono */
  250. void
  251. dostereo() /* do stereo delay */
  252. {
  253. int i;
  254. long rdsamps;
  255. float Linput,Rinput;
  256. float Loutput,Routput;
  257. long Llinput,Rlinput;
  258. long Lloutput,Rloutput;
  259. long Ltemp1,Ltemp2;
  260. long Rtemp1,Rtemp2;
  261. long Lipptr = 0,Ripptr = 1;
  262. long Lopptr = 0,Ropptr = 1;
  263. do /* while rdsamps */
  264. {
  265. if((rdsamps = fgetsbuf(inbuf,BUFLEN,ifd)) < 0)
  266. {
  267. fprintf(stderr,"\ndelay: failure to read input file\n");
  268. exit(1);
  269. }
  270. for(i=0;i<(rdsamps-1);i+=2)
  271. {
  272. if(!Quickflag)
  273. {
  274. Linput=inbuf[i]*Prescale;
  275. Rinput=inbuf[i+1]*Prescale;
  276. Loutput=(Linput*Feedforgain) +
  277. (Fdelbuf[Lopptr]*Delaygain);
  278. Routput=(Rinput*Feedforgain) +
  279. (Fdelbuf[Ropptr]*Delaygain);
  280. Fdelbuf[Lipptr] = Fdelbuf[Lopptr]*Feedbckgain;
  281. Lopptr+=2;
  282. Fdelbuf[Ripptr] = Fdelbuf[Ropptr]*Feedbckgain;
  283. Ropptr+=2;
  284. Fdelbuf[Lipptr]+=Linput;
  285. Fdelbuf[Ripptr]+=Rinput;
  286. Lipptr+=2;
  287. Ripptr+=2;
  288. outbuf[i] = (short) Loutput;
  289. outbuf[i+1] = (short) Routput;
  290. if(Lipptr >= Delaysamps) Lipptr -= Delaysamps;
  291. if(Ripptr >= Delaysamps) Ripptr -= Delaysamps;
  292. if(Lopptr >= Delaysamps) Lopptr -= Delaysamps;
  293. if(Ropptr >= Delaysamps) Ropptr -= Delaysamps;
  294. }
  295. else
  296. {
  297. Llinput = inbuf[i] * Lprescale;
  298. Rlinput = inbuf[i+1] * Lprescale;
  299. Ltemp1 = Llinput >> 16;
  300. Rtemp1 = Rlinput >> 16;
  301. Ltemp2 = Ldelbuf[Lopptr] >> 16;
  302. Rtemp2 = Ldelbuf[Ropptr] >> 16;
  303. Lopptr += 2;
  304. Ropptr += 2;
  305. Lloutput = (Ltemp1 * Lfeedforgain) +
  306. (Ltemp2 * Ldelaygain);
  307. Rloutput = (Rtemp1 * Lfeedforgain) +
  308. (Rtemp2 * Ldelaygain);
  309. Ldelbuf[Lipptr] = Ltemp2 * Lfeedbckgain;
  310. Ldelbuf[Ripptr] = Rtemp2 * Lfeedbckgain;
  311. Ldelbuf[Lipptr] += Llinput;
  312. Ldelbuf[Ripptr] += Rlinput;
  313. Lipptr += 2;
  314. Ripptr += 2;
  315. outbuf[i] = (short)(Lloutput>>16);
  316. outbuf[i+1] = (short)(Rloutput>>16);
  317. if(Lipptr >= Delaysamps) Lipptr -= Delaysamps;
  318. if(Ripptr >= Delaysamps) Ripptr -= Delaysamps;
  319. if(Lopptr >= Delaysamps) Lopptr -= Delaysamps;
  320. if(Ropptr >= Delaysamps) Ropptr -= Delaysamps;
  321. }
  322. }
  323. if(fputsbuf(outbuf,rdsamps,ofd) < rdsamps) {
  324. fprintf(stderr,"\ndelay: failure in writing to output file\n");
  325. exit(1);
  326. }
  327. inform(rdsamps/2,Sr);
  328. }while(rdsamps > 0); /* end do */
  329. /* now do trailer */
  330. rdsamps=BUFLEN;
  331. if(Trailsamps>0)
  332. {
  333. do
  334. {
  335. if(!bufcnt) rdsamps = remainder;
  336. if(!Quickflag)
  337. {
  338. for(i=0;i<(rdsamps-1);i+=2)
  339. {
  340. Loutput = Fdelbuf[Lopptr]*Delaygain;
  341. Routput = Fdelbuf[Ropptr]*Delaygain;
  342. Fdelbuf[Lipptr] = Fdelbuf[Lopptr]*Feedbckgain;
  343. Fdelbuf[Ripptr] = Fdelbuf[Ropptr]*Feedbckgain;
  344. Lopptr+=2;
  345. Ropptr+=2;
  346. Lipptr+=2;
  347. Ripptr+=2;
  348. outbuf[i] = (short) Loutput;
  349. outbuf[i+1] = (short) Routput;
  350. if(Lipptr >= Delaysamps) Lipptr -= Delaysamps;
  351. if(Ripptr >= Delaysamps) Ripptr -= Delaysamps;
  352. if(Lopptr >= Delaysamps) Lopptr -= Delaysamps;
  353. if(Ropptr >= Delaysamps) Ropptr -= Delaysamps;
  354. }
  355. }
  356. else
  357. {
  358. for(i=0;i<(rdsamps-1);i+=2)
  359. {
  360. Ltemp2 = Ldelbuf[Lopptr] >> 16;
  361. Lopptr+=2;
  362. Rtemp2 = Ldelbuf[Ropptr] >> 16;
  363. Ropptr+=2;
  364. Lloutput = Ltemp2 * Ldelaygain;
  365. Rloutput = Rtemp2 * Ldelaygain;
  366. Ldelbuf[Lipptr] = Ltemp2*Lfeedbckgain;
  367. Ldelbuf[Ripptr] = Rtemp2*Lfeedbckgain;
  368. Lipptr +=2;
  369. Ripptr +=2;
  370. outbuf[i] = (short)(Lloutput>>16);
  371. outbuf[i+1] = (short)(Rloutput>>16);
  372. if(Lipptr >= Delaysamps) Lipptr -= Delaysamps;
  373. if(Ripptr >= Delaysamps) Ripptr -= Delaysamps;
  374. if(Lopptr >= Delaysamps) Lopptr -= Delaysamps;
  375. if(Ropptr >= Delaysamps) Ropptr -= Delaysamps;
  376. }
  377. }
  378. if(fputsbuf(outbuf,rdsamps,ofd) < rdsamps) {
  379. fprintf(stderr,"\ndelay: failure in writing to output file\n");
  380. exit(1);
  381. }
  382. inform(rdsamps/2,Sr);
  383. bufcnt -=1;
  384. } while (bufcnt>=0);
  385. } /* end if */
  386. } /* end dostereo */
  387. void
  388. usage()
  389. {
  390. fprintf(stderr,"delay - A Groucho Program: $Revision: 3.3 $\n");
  391. fprintf(stderr,
  392. "usage: delay [-f][-pN][-i] infile outfile [4 cmndline parameters]\n");
  393. fprintf(stderr,
  394. " where -f sets output in floatsams, -p sets prescale = N for infile,\n");
  395. fprintf(stderr,
  396. " and -i inverts dry signal (for allpass filters).\n");
  397. fprintf(stderr,"\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
  398. "Cmndline option: after [flags] filenames, enter all parameters in this order:",
  399. " delaytime mix feedbackgain trailertime",
  400. " 0.0 < delaytime (msecs) <= maxdelay",
  401. " 0.0 <= mix <= 1.0",
  402. " -1.0 <= feedbackgain <= 1.0",
  403. " 0.0 <= trailertime (secs) <= 30.0",
  404. "where maxdelay = 8000ms @22050 mono",
  405. " = 4000ms @22050 stereo, and 44100 mono",
  406. " = 2000ms @44100 stereo");
  407. exit(0);
  408. }
  409. void
  410. delinit(int cmndlin, char *argv[])
  411. {
  412. double temp,maxdelay,mix;
  413. char msg[80];
  414. /* Some jiggery pokery is needed in setting the
  415. * fixed point variables to avoid overloading
  416. * the input to the delay line. The input is
  417. * divided by two in conjunction with prescaling
  418. * and the feedthrough and delay outputs are
  419. * raised by two to compensate.
  420. */
  421. maxdelay = ((double) (DELBUFSIZ) / Sr) * 1000.0; /* milliseconds */
  422. if(Nchans==2) {maxdelay /= 2;}
  423. if(cmndlin)
  424. {
  425. temp = atof(argv[3]);
  426. if (temp > maxdelay)
  427. {
  428. printf("delay: delay time too long\n");
  429. exit(1);
  430. }
  431. Delaysamps = (long) ((Sr *temp) / 1000.0);
  432. mix = atof(argv[4]);
  433. if((mix < 0.0) || (mix > 1.0))
  434. {
  435. printf("delay: mix value out of range\n");
  436. exit(1);
  437. }
  438. Feedbckgain = (float)atof(argv[5]);
  439. if((Feedbckgain < -1.0) || (Feedbckgain > 1.0))
  440. {
  441. printf("delay: feedbackgain out of range\n");
  442. exit(1);
  443. }
  444. Trailtime = atof(argv[6]);
  445. if((Trailtime < 0.0) || (Trailtime > 1000.0))
  446. {
  447. printf("delay: trailtime out of range\n");
  448. exit(1);
  449. }
  450. }
  451. else /* ask for params from terminal */
  452. {
  453. printf("max delay in msec = %f\n",maxdelay);
  454. sprintf(msg,
  455. "Give delay time in milliseconds :");
  456. temp = accexpr(msg,0.0,maxdelay,0.0,0,Sr);
  457. if(temp==0.0)
  458. {
  459. printf("\nzero delay time!!! No point in running program. Bye!\n");
  460. exit(1);
  461. }
  462. Delaysamps = (long) ((Sr * temp) / 1000.0);
  463. printf("\ndelay length in samples = %ld \n",Delaysamps);
  464. sprintf(msg,
  465. "Give mix proportion (0.0 <= level <= 1.0) :");
  466. mix = accexpr(msg,0.0,1.0,0.0,0,Sr);
  467. sprintf(msg,
  468. "Give feedback gain (-1.0 <= level <= 1.0) :");
  469. Feedbckgain = (float)accexpr(msg,-1.0,1.0,0.0,0,Sr);
  470. sprintf(msg,
  471. "Give trailer time (default = 0 <= trailtime <= 30.0) :");
  472. Trailtime = accexpr(msg, 0.0,30.0,0.0,1,Sr);
  473. }
  474. /* now massage parameters */
  475. /* nb delaysamps is per channel here */
  476. Feedforgain = (float)((1.0 - mix)*Invert);
  477. Lfeedbckgain = (long) (Feedbckgain * ONE_FLT);
  478. Delaygain = (float)mix;
  479. Ldelaygain = (long) (Delaygain * ONE_FLT * 2.0);
  480. Rescale = (1.0 / (Feedbckgain + 1.0)); /* i/p compensation */
  481. Prescale *= (float)Rescale;
  482. Lprescale= (long) (Prescale * ONE_FLT * .5);
  483. Feedforgain /= (float)Rescale;
  484. Lfeedforgain = (long) (Feedforgain * ONE_FLT * 2.0);
  485. Trailsamps = (long) (Trailtime * Sr);
  486. if(Nchans==2) Trailsamps *= 2;
  487. bufcnt = Trailsamps/BUFLEN;
  488. remainder = Trailsamps % BUFLEN;
  489. }
  490. void
  491. initfbuf()
  492. {
  493. Delaysamps*=Nchans;
  494. if((Fdelbuf = (float *) calloc(Delaysamps+2, sizeof(float))) == NULL){
  495. fprintf(stderr,"\ndelay: not enough memory for main delay buffer");
  496. exit(1);
  497. }
  498. }
  499. void
  500. initlbuf()
  501. {
  502. Delaysamps*=Nchans;
  503. if((Ldelbuf = (long *) calloc(Delaysamps+4, sizeof(long))) == NULL){
  504. fprintf(stderr,"\ndelay: not enough memory for main delay buffer");
  505. exit(1);
  506. }
  507. }