texture5mc.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. /*
  2. * Copyright (c) 1983-2023 Trevor Wishart and Composers Desktop Project Ltd
  3. * http://www.trevorwishart.co.uk
  4. * http://www.composersdesktop.com
  5. *
  6. This file is part of the CDP System.
  7. The CDP System is free software; you can redistribute it
  8. and/or modify it under the terms of the GNU Lesser General Public
  9. License as published by the Free Software Foundation; either
  10. version 2.1 of the License, or (at your option) any later version.
  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. See the
  14. GNU Lesser General Public License for more details.
  15. You should have received a copy of the GNU Lesser General Public
  16. License aint with the CDP System; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  18. 02111-1307 USA
  19. *
  20. */
  21. /* floatsam version */
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <memory.h> /*RWD*/
  25. #include <structures.h>
  26. #include <tkglobals.h>
  27. #include <globcon.h>
  28. #include <processno.h>
  29. #include <modeno.h>
  30. #include <arrays.h>
  31. #include <texture.h>
  32. #include <cdpmain.h>
  33. #include <osbind.h>
  34. #include <standalone.h>
  35. #include <sfsys.h>
  36. #ifdef _DEBUG
  37. #include <assert.h>
  38. #endif
  39. //#ifdef unix
  40. #define round(x) lround((x))
  41. //#endif
  42. #ifndef HUGE
  43. #define HUGE 3.40282347e+38F
  44. #endif
  45. #define permcnt rampbrksize
  46. static int setup_splice(int st_splicecnt,double **splicebuf);
  47. static int generate_origdur_and_frq(double **origdur,double **origfrq,dataptr dz);
  48. static int init_soundout_set(sndoutmchptr *sndout);
  49. static int replace_tset_by_soundout_set(noteptr thisnote,sndoutmchptr *sndout,
  50. double *origdur,double *origfrq,double mindur,int st_splicecnt,dataptr dz);
  51. static int convert_tsetnote_to_sndout_item_multichan(noteptr thisnote,sndoutmchptr sndout,
  52. double *origdur,double *origfrq,double mindur,int st_splicecnt,int *warning_set,dataptr dz);
  53. static int generate_previous_sndout(sndoutmchptr *sndout);
  54. static int get_thisdur(double *thisdur,noteptr thisnote,int thisins,
  55. double *origdur,double inv_trnsp,double mindur,dataptr dz);
  56. static int get_stereospace_compensation(double position,double *compensate);
  57. static int do_mix(sndoutmchptr sndout,double *splicebuf,dataptr dz);
  58. static int check_sequencing(sndoutmchptr sndout);
  59. static int add_samples_to_outbuf_from_inbuf(int *out_of_insamples,int * max_samp_written,
  60. sndoutmchptr sndout,double *splicebuf,int splicelen,/*int*/float *lbuf,int obuflen,dataptr dz);
  61. static void unlink_sndoutptr_at_start_of_list(sndoutmchptr sndout);
  62. static void unlink_sndoutptr(sndoutmchptr sndout);
  63. static double get_interpd_value(unsigned int here,double ibufpos,sndoutmchptr sndout);
  64. static int free_first_sndout(sndoutmchptr *sndout);
  65. //TW UPDATE 2002: to make texture from stereo sources (updated to flotsams)
  66. static int add_stereo_samples_to_outbuf_from_inbuf
  67. (int *out_of_insamples,int *max_samp_written,sndoutmchptr sndout,double *splicebuf,int splicelen,float *lbuffer,int obuflen,dataptr dz);
  68. static double get_interpd_value_stereo(unsigned int here,double ibufpos,double *chanval2,sndoutmchptr sndout);
  69. static int chanperm(int lastperm,dataptr dz);
  70. static void permute_chunks(dataptr dz);
  71. static void insert(int n,int t,dataptr dz);
  72. static void prefix(int n,dataptr dz);
  73. static void shuflup(int k,dataptr dz);
  74. /**************************** PRODUCE_TEXTURE_SOUND *****************************/
  75. int produce_texture_sound(dataptr dz)
  76. {
  77. int exit_status;
  78. /*insamptr *insound = dz->tex->insnd;*/
  79. motifptr tset;
  80. sndoutmchptr sndout;
  81. noteptr thisnote;
  82. double *origdur, *origfrq, *splicebuf;
  83. double mindur;
  84. int st_splicecnt;
  85. tset = dz->tex->timeset;
  86. thisnote = tset->firstnote;
  87. mindur = (dz->frametime + TEXTURE_SAFETY) * MS_TO_SECS;
  88. st_splicecnt = round((dz->frametime * MS_TO_SECS) * dz->infile->srate);
  89. if((exit_status = setup_splice(st_splicecnt,&splicebuf))<0)
  90. return(exit_status);
  91. if((exit_status = generate_origdur_and_frq(&origdur,&origfrq,dz))<0)
  92. return(exit_status);
  93. if((exit_status = init_soundout_set(&sndout))<0)
  94. return(exit_status);
  95. if((exit_status = replace_tset_by_soundout_set(thisnote,&sndout,origdur,origfrq,mindur,st_splicecnt,dz))<0)
  96. return(exit_status);
  97. free(origdur);
  98. free(origfrq);
  99. return do_mix(sndout,splicebuf,dz);
  100. }
  101. /************************** SETUP_SPLICE ************************/
  102. int setup_splice(int st_splicecnt,double **splicebuf)
  103. {
  104. int n, m;
  105. if((*splicebuf = (double *)malloc(st_splicecnt * sizeof(double)))==NULL) {
  106. sprintf(errstr,"INSUFFICIENT MEMORY for splice buffer.\n");
  107. return(MEMORY_ERROR);
  108. }
  109. for(m=0,n=st_splicecnt-1; n>=0; n--,m++)
  110. (*splicebuf)[m] = (double)n/(double)st_splicecnt;
  111. return(FINISHED);
  112. }
  113. /************************** GENERATE_ORIGDUR_AND_FRQ ************************/
  114. int generate_origdur_and_frq(double **origdur,double **origfrq,dataptr dz)
  115. {
  116. int n;
  117. if((*origdur = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) {
  118. sprintf(errstr,"INSUFFICIENT MEMORY to store original durations.\n");
  119. return(MEMORY_ERROR);
  120. }
  121. if((*origfrq = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) {
  122. sprintf(errstr,"INSUFFICIENT MEMORY to store original frqs.\n");
  123. return(MEMORY_ERROR);
  124. }
  125. for(n=0;n <dz->infilecnt;n++) {
  126. //TW UPDATE: Now allowing stereo sources to be used to make texture
  127. (*origdur)[n] = (double)dz->insams[n]/(double)dz->infile->channels/(double)dz->infile->srate;
  128. (*origfrq)[n] = miditohz(((dz->tex->insnd)[n])->pitch);
  129. }
  130. return(FINISHED);
  131. }
  132. /************************** INIT_SOUNDOUT_SET ************************/
  133. int init_soundout_set(sndoutmchptr *sndout)
  134. {
  135. if((*sndout = (sndoutmchptr)malloc(sizeof(struct soundoutmchan)))==NULL) {
  136. sprintf(errstr,"INSUFFICIENT MEMORY for soundoutmchan pointers.\n");
  137. return(MEMORY_ERROR);
  138. }
  139. (*sndout)->last = (sndoutmchptr)0;
  140. (*sndout)->next = (sndoutmchptr)0;
  141. return(FINISHED);
  142. }
  143. /************************** REPLACE_TSET_BY_SOUNDOUT_SET ************************/
  144. int replace_tset_by_soundout_set
  145. (noteptr thisnote,sndoutmchptr *sndout,double *origdur,double *origfrq,double mindur,int st_splicecnt,dataptr dz)
  146. {
  147. int exit_status;
  148. int warning_set = FALSE;
  149. while((thisnote->next)!=(noteptr)0) /* go to end of tset */
  150. thisnote = thisnote->next;
  151. dz->permcnt = dz->iparam[TEXTURE_OUTCHANS];
  152. while(thisnote!=(noteptr)0) {
  153. if((exit_status = convert_tsetnote_to_sndout_item_multichan
  154. (thisnote,*sndout,origdur,origfrq,mindur,st_splicecnt,&warning_set,dz))<0)
  155. return(exit_status);
  156. if((exit_status = generate_previous_sndout(sndout))<0)
  157. return(exit_status);
  158. if(thisnote->last!=NULL) {
  159. thisnote = thisnote->last; /* free tset from end backwards */
  160. free(thisnote->next);
  161. } else {
  162. free(thisnote);
  163. if((exit_status = free_first_sndout(sndout))<0)
  164. return(exit_status);
  165. thisnote = NULL;
  166. }
  167. }
  168. return(FINISHED);
  169. }
  170. /************************** CONVERT_TSETNOTE_TO_SNDOUT_ITEM ************************/
  171. //TW "STEREO" defined in globcon.h
  172. #define MAXGAIN (1.0)
  173. int convert_tsetnote_to_sndout_item_multichan
  174. (noteptr thisnote,sndoutmchptr sndout,double *origdur,double *origfrq,double mindur,int st_splicecnt,int *warning_set,dataptr dz)
  175. {
  176. int exit_status, special_case = 0;
  177. int thisins, outchanbase, lastperm = dz->iparam[TEXTURE_OUTCHANS] - 1;
  178. unsigned int insampcnt, st_osampcnt;
  179. double stereopos = 0.0, indur;
  180. double thisfrq,thisdur,trnspstep,inv_trnsp,thisamp,thispos,compensate = 1.0;
  181. double *pos = NULL;
  182. int *lmost = NULL;
  183. if(dz->vflag[4]) {
  184. lmost = dz->iparray[dz->iarray_cnt-1];
  185. pos = dz->parray[dz->array_cnt-1];
  186. }
  187. thisins = thisnote->instr;
  188. thisfrq = miditohz((double)thisnote->pitch);
  189. trnspstep = thisfrq/origfrq[thisins];
  190. inv_trnsp = 1.0/trnspstep;
  191. if((exit_status = get_thisdur(&thisdur,thisnote,thisins,origdur,inv_trnsp,mindur,dz))<0)
  192. return(exit_status);
  193. indur = thisdur * trnspstep;
  194. insampcnt = min(dz->insams[thisins]/dz->infile->channels,round(indur * (double)dz->infile->srate));
  195. st_osampcnt = round((double)insampcnt * inv_trnsp);
  196. if(st_osampcnt <= (unsigned int)st_splicecnt) {
  197. sprintf(errstr,"Error in samplecount calculations: convert_tsetnote_to_sndout_item_multichan()\n");
  198. return(PROGRAM_ERROR);
  199. }
  200. thisamp = thisnote->amp/(double)MIDITOP;
  201. thispos = thisnote->spacepos;
  202. if(dz->vflag[4]) {
  203. sndout->lchan = lmost[thisins];
  204. sndout->rchan = sndout->lchan + 2;
  205. stereopos = pos[thisins];
  206. } else if((dz->brksize[TEXTURE_SPRD] == 0) && (dz->param[TEXTURE_SPRD] == 0.0)) {
  207. special_case = 1;
  208. /* If spread param is set to 1.0 (max) and not a brkfile, uses a perm of no of loudspeakers */
  209. /* so each event is AT a different loudspeaker, and never between */
  210. if(dz->infile->channels == 2) { // In stereo case, pan between permuted chans
  211. outchanbase = chanperm(lastperm,dz);
  212. thispos = outchanbase;
  213. sndout->lchan = (int)floor(thispos);
  214. outchanbase = chanperm(lastperm,dz);
  215. thispos = outchanbase;
  216. sndout->rchan = (int)floor(thispos);
  217. } else { // In mono case, perm positions in lspkrs (no inter-lspkr positions)
  218. outchanbase = chanperm(lastperm,dz);
  219. thispos = outchanbase;
  220. sndout->lchan = (int)floor(thispos);
  221. sndout->rchan = (sndout->lchan + 1);
  222. }
  223. } else {
  224. sndout->lchan = (int)floor(thispos);
  225. sndout->rchan = (sndout->lchan + 1);
  226. }
  227. sndout->lchan %= dz->iparam[TEXTURE_OUTCHANS];
  228. sndout->rchan %= dz->iparam[TEXTURE_OUTCHANS];
  229. if(!special_case) {
  230. if(!dz->vflag[4])
  231. stereopos = thispos - (double)sndout->lchan;
  232. if((exit_status = get_stereospace_compensation(stereopos,&compensate))<0)
  233. return(exit_status);
  234. }
  235. if(thisamp > MAXGAIN) {
  236. #ifdef _DEBUG
  237. assert(thisamp <= MAXGAIN);
  238. #endif
  239. if(!(*warning_set)) {
  240. fprintf(stdout,"WARNING: one or more events exceed max level. Adjusted.\n");
  241. fflush(stdout);
  242. *warning_set = TRUE;
  243. }
  244. thisamp = MAXGAIN;
  245. }
  246. sndout->inbuf = ((dz->tex->insnd)[thisins])->buffer;
  247. sndout->ibufcnt = insampcnt;
  248. sndout->st_sstttime = round(thisnote->ntime * dz->infile->srate);
  249. sndout->st_sendtime = sndout->st_sstttime + st_osampcnt; /* Redundant variable: might need if func revised */
  250. sndout->st_splicpos = sndout->st_sendtime - st_splicecnt;
  251. sndout->ibufpos = 0.0;
  252. sndout->step = trnspstep;
  253. //TW UPDATE: in stereo-input case, only 1 gain value used, as no spatialisation takes place
  254. if(dz->infile->channels==STEREO) {
  255. sndout->lgain = thisamp;
  256. } else if(special_case) {
  257. sndout->lgain = thisamp;
  258. sndout->rgain = 0.0;
  259. } else {
  260. sndout->lgain = thisamp * (1.0 - stereopos) * compensate;
  261. sndout->rgain = thisamp * stereopos * compensate;
  262. }
  263. return(FINISHED);
  264. }
  265. /************************** GENERATE_PREVIOUS_SNDOUT ************************/
  266. int generate_previous_sndout(sndoutmchptr *sndout)
  267. {
  268. sndoutmchptr new;
  269. if((new = (sndoutmchptr)malloc(sizeof(struct soundoutmchan)))==NULL) {
  270. sprintf(errstr,"INSUFFICIENT MEMORY for new soundoutmchan pointers.\n");
  271. return(MEMORY_ERROR);
  272. }
  273. new->last = (sndoutmchptr)0;
  274. new->next = *sndout;
  275. (*sndout)->last = new;
  276. *sndout = new;
  277. return(FINISHED);
  278. }
  279. /************************** FREE_FIRST_SNDOUT ************************/
  280. int free_first_sndout(sndoutmchptr *sndout)
  281. {
  282. if((*sndout = (*sndout)->next)==NULL) {
  283. sprintf(errstr,"Problem in free_first_sndout()\n");
  284. return(PROGRAM_ERROR);
  285. }
  286. free((*sndout)->last);
  287. (*sndout)->last = NULL;
  288. return(FINISHED);
  289. }
  290. /************************** GET_THISDUR ************************/
  291. int get_thisdur
  292. (double *thisdur,noteptr thisnote,int thisins,double *origdur,double inv_trnsp,double mindur,dataptr dz)
  293. {
  294. double transposed_dur = origdur[thisins] * inv_trnsp;
  295. *thisdur = thisnote->dur;
  296. if(*thisdur>transposed_dur)
  297. *thisdur = transposed_dur;
  298. else if(dz->vflag[TEX_IGNORE_DUR])
  299. *thisdur = transposed_dur;
  300. if(*thisdur<mindur) {
  301. sprintf(errstr,
  302. "too short dur generated (%lf : mindur = %lf): get_thisdur()\n",*thisdur,mindur);
  303. return(PROGRAM_ERROR);
  304. }
  305. return(FINISHED);
  306. }
  307. /************************** GET_STEREOSPACE_COMPENSATION ************************
  308. *
  309. * 1) comp(ensation) is a factor which compensates for the apparent
  310. * loss of perceived amplitude as a sound moves out of the absolute
  311. * left or absolute right position (sound from a single loudspeaker)
  312. * by simple linear interpolation.
  313. * At first we define comp to vary LINERALY from 0.0 at L or R,
  314. * to 1.0 in centre.
  315. * 2) NONLIN makes this varation nonlinear, but smooth at the centre, and
  316. * still between 0.0 and 1.0
  317. * 3) As a signal of fixed perceived level moves from left to right (or v.v.)
  318. * we wish to boost the amplitude from each loudspeaker somewhat,
  319. * using a curve of the shape now defined.
  320. * The maximum possible amplitude is 1.0. To define how much we should
  321. * boost amplitude at any point on the L-R axis, we need to define
  322. * a ratio (MAXBOOST) with which to multiply the signal.
  323. * Multiplying comp-curve by this, defines a curve of amplitude-boosting values.
  324. * 4) 1.0 is now added to this curve, to give a multiplier of amplitude at
  325. * each point along the left-right axis.
  326. * And MAXBOOST is subtracted, so that the level
  327. * from each loudspeaker when at maximum boost cannot exceed
  328. * MAXGAIN (1.0).
  329. */
  330. #define NONLIN (0.5)
  331. #define MAXBOOST (0.25)
  332. int get_stereospace_compensation(double position,double *compensate)
  333. {
  334. double comp = 1.0 - (fabs((position * (double)2.0) - (double)1.0)); /* 9a */
  335. comp = pow(comp,NONLIN); /* 9b */
  336. comp *= MAXBOOST; /* 9c */
  337. comp += (1.0 - MAXBOOST); /* 9d */
  338. *compensate = comp;
  339. return(FINISHED);
  340. }
  341. /************************** DO_MIX ************************
  342. *
  343. * 1) Position, in multichan-samples, of start-of-splice in this-sndout-struct =
  344. * sndout->st_splicpos
  345. * Position in actual-samples of ditto =
  346. * sndout->st_splicpos * ochans
  347. * Position relative to start of current buffer =
  348. * (sndout->st_splicpos * ochans) - (obufcnt * obuflen);
  349. * Same position expressed relative to start-of-splice (so that value 0 = start_of_splice) =
  350. * -((sndout->st_splicpos * ochans) - (obufcnt * obuflen));
  351. */
  352. int do_mix(sndoutmchptr sndout,double *splicebuf,dataptr dz)
  353. {
  354. int exit_status;
  355. int out_of_insamples, ochans = dz->iparam[TEXTURE_OUTCHANS];
  356. /*unsigned long totaltime = 0;*/
  357. int max_samp_written, obuflen;
  358. unsigned int this_sampend, obufcnt = 0;
  359. int splicelen = round((dz->frametime * MS_TO_SECS) * dz->infile->srate) * ochans;
  360. sndoutmchptr startsnd = sndout, endsnd = sndout;
  361. /*int*/float *lbuf;
  362. //TW UPDATE handles stereo input files
  363. int is_stereo = 0;
  364. if(dz->infile->channels == STEREO)
  365. is_stereo = 1;
  366. //TW MOVED from texprepro
  367. dz->infile->channels = ochans; /* for output time calculations */
  368. if((exit_status = create_sized_outfile(dz->outfilename,dz))<0)
  369. return(exit_status);
  370. obuflen = dz->buflen;
  371. if(is_stereo)
  372. obuflen /= 2;
  373. obuflen *= dz->iparam[TEXTURE_OUTCHANS];
  374. if((lbuf = (float *)malloc(obuflen * sizeof(float)))==NULL) {
  375. sprintf(errstr,"INSUFFICIENT MEMORY for mixing buffers.\n");
  376. return(MEMORY_ERROR);
  377. }
  378. dz->sbufptr[0] = dz->sampbuf[0];
  379. /* <--SAFETY CHECK */
  380. if((exit_status = check_sequencing(sndout))<0)
  381. return(exit_status);
  382. /* SAFETY CHECK--> */
  383. while(startsnd != NULL) { /* until we reach end of event list */
  384. this_sampend = (obufcnt+1) * obuflen; /* get absolute samplecnt of end of current buf */
  385. /* look for NEW events starting during this outbuf */
  386. if(sndout!=NULL) {
  387. while(sndout->st_sstttime * ochans < this_sampend) {
  388. sndout->obufpos = (sndout->st_sstttime * ochans) % obuflen;/* obufptr for new event */
  389. sndout->st_splicpos = (sndout->st_splicpos * ochans)-(obufcnt * obuflen);/* NOTE1 abv*/
  390. sndout->st_splicpos = -(sndout->st_splicpos); /* NOTE 1 above */
  391. sndout = sndout->next;
  392. endsnd = sndout; /* update the endmarker of the active events list */
  393. if(endsnd == NULL) /* if all events finished,break */
  394. break;
  395. }
  396. }
  397. sndout = startsnd; /* set start to 1st event still active */
  398. memset((char *)lbuf,0,obuflen * sizeof(float)); /* empty output buffer */
  399. if(sndout == endsnd) { /* If there are NO active events during this buffer */
  400. if(endsnd != NULL) /* and we are not at end of event list */
  401. max_samp_written = obuflen; /* setup to write an empty buffer */
  402. else {
  403. sprintf(errstr,"Error in loop logic: do_mix()\n");
  404. return(PROGRAM_ERROR);
  405. }
  406. } else
  407. max_samp_written = 0;
  408. while(sndout!= endsnd) { /* look in all active buffers */
  409. out_of_insamples = FALSE;
  410. //TW UPDATE: handles stereo input
  411. if(is_stereo) {
  412. if((exit_status = add_stereo_samples_to_outbuf_from_inbuf
  413. (&out_of_insamples,&max_samp_written,sndout,splicebuf,splicelen,lbuf,obuflen,dz))<0)
  414. return(exit_status);
  415. } else {
  416. if((exit_status = add_samples_to_outbuf_from_inbuf
  417. (&out_of_insamples,&max_samp_written,sndout,splicebuf,splicelen,lbuf,obuflen,dz))<0)
  418. return(exit_status);
  419. }
  420. if(out_of_insamples) { /* if inbuf exhausted for THIS event */
  421. if(sndout->next==NULL) { /* if at end of list */
  422. if(sndout->last==NULL) { /* if this is definitively the last active event */
  423. free(sndout); /* free it */
  424. startsnd = NULL; /* and set ptr to NULL, so we dropout of outerloop */
  425. break;
  426. } else { /* BUT if some previous event still active */
  427. sndout = sndout->last; /* unlink final event from list */
  428. free(sndout->next);
  429. sndout->next = NULL;
  430. sndout = sndout->next; /* move sndout to end of list */
  431. }
  432. } else if(sndout==startsnd) { /* if this is 1st active event in list */
  433. sndout = sndout->next; /* proceed to next event */
  434. startsnd = sndout; /* move start of active list to this next event */
  435. unlink_sndoutptr_at_start_of_list(sndout->last);
  436. } else { /* else if this is NOT 1st active event in list */
  437. sndout = sndout->next; /* proceed to next event */
  438. unlink_sndoutptr(sndout->last);/* unlink the exhausted event from (active) list */
  439. }
  440. } else { /* else there is data remaining in inbuf for THIS event */
  441. sndout->obufpos = 0; /* so reset obufpos to start of next obuf */
  442. sndout->st_splicpos += obuflen;/* reset relativeposition splice-start & nextbufstart */
  443. sndout = sndout->next; /* and proceed to next event */
  444. }
  445. }
  446. if(startsnd!=NULL) /* If we're not at the end of ALL events, write a full buffer */
  447. max_samp_written = obuflen;
  448. if(max_samp_written > 0) {
  449. dz->process = TEX_MCHAN; // Forces correct display in Loom
  450. if((exit_status = write_samps(lbuf,max_samp_written,dz))<0)
  451. return(exit_status);
  452. dz->process = SIMPLE_TEX;
  453. }
  454. obufcnt++;
  455. }
  456. if(dz->param[TEX_MAXOUT] > F_MAXSAMP) {
  457. fprintf(stdout,"WARNING: OVERLOAD: suggest attenuation by < %lf\n",
  458. (((double)F_MAXSAMP/(double)dz->param[TEX_MAXOUT])) * dz->param[TEXTURE_ATTEN]);
  459. fflush(stdout);
  460. }
  461. return(FINISHED);
  462. }
  463. /************************** CHECK_SEQUENCING ************************/
  464. int check_sequencing(sndoutmchptr sndout)
  465. {
  466. unsigned int lasttime = sndout->st_sstttime;
  467. unsigned int thistime;
  468. while(sndout->next != (sndoutmchptr)0) {
  469. sndout = sndout->next;
  470. if((thistime = sndout->st_sstttime) < lasttime) {
  471. sprintf(errstr,"Sequencing anomaly in sndout list: check_sequencing()\n");
  472. return(PROGRAM_ERROR);
  473. }
  474. lasttime = thistime;
  475. }
  476. return(FINISHED);
  477. }
  478. /************************** ADD_SAMPLES_TO_OUTBUF_FROM_INBUF ************************/
  479. int add_samples_to_outbuf_from_inbuf
  480. (int *out_of_insamples,int *max_samp_written,sndoutmchptr sndout,double *splicebuf,int splicelen,float *lbuffer,int obuflen,dataptr dz)
  481. {
  482. unsigned int thisopos = sndout->obufpos;
  483. unsigned int here;
  484. double hereval = 0.0;
  485. float *lbuf = lbuffer + thisopos;
  486. float *lbufend = lbuffer + obuflen;
  487. int splicpos = sndout->st_splicpos + thisopos;
  488. float outval, thismaxoutval;
  489. int max_set = FALSE, chan;
  490. while(lbuf < lbufend) {
  491. if((here = (unsigned int) sndout->ibufpos) >= sndout->ibufcnt) { /* TRUNCATE : get current pos in inbuf */
  492. *out_of_insamples = TRUE;
  493. *max_samp_written = max(*max_samp_written,lbuf - lbuffer);
  494. /* SAFETY CHECK--> */
  495. if(splicpos < splicelen) {
  496. sprintf(errstr,"BUM endsplice: add_samples_to_outbuf_from_inbuf()\n");
  497. return(PROGRAM_ERROR);
  498. }
  499. /* <--SAFETY CHECK */
  500. max_set = TRUE;
  501. break;
  502. }
  503. hereval = get_interpd_value(here,sndout->ibufpos,sndout);
  504. /* SAFETY FOR ARITHMETIC ROUNDING ERROS CALCULATING START OF SPLICE --> */
  505. if(splicpos >= splicelen)
  506. hereval = 0.0;
  507. /* <--SAFETY */
  508. if(splicpos >= 0)
  509. hereval *= splicebuf[splicpos/dz->iparam[TEXTURE_OUTCHANS]];
  510. splicpos += dz->iparam[TEXTURE_OUTCHANS];
  511. for(chan = 0;chan < dz->iparam[TEXTURE_OUTCHANS];chan ++) {
  512. if(chan == sndout->lchan) {
  513. outval =(float)( *lbuf + (hereval * sndout->lgain ));
  514. if((thismaxoutval = (float) fabs(outval)) > dz->param[TEX_MAXOUT])
  515. dz->param[TEX_MAXOUT] = thismaxoutval;
  516. *lbuf = outval;
  517. } else if(chan == sndout->rchan) {
  518. outval = (float)(*lbuf + (hereval * sndout->rgain));
  519. if((thismaxoutval = (float) fabs(outval)) > dz->param[TEX_MAXOUT])
  520. dz->param[TEX_MAXOUT] = thismaxoutval;
  521. *lbuf = outval;
  522. }
  523. lbuf++;
  524. }
  525. sndout->ibufpos += sndout->step;
  526. }
  527. if(!max_set)
  528. *max_samp_written = obuflen;
  529. return(FINISHED);
  530. }
  531. //TW UPDATE: NEW FUNCTIONfor stereo input (updated for flotsams)
  532. /************************** ADD_STEREO_SAMPLES_TO_OUTBUF_FROM_INBUF ************************/
  533. int add_stereo_samples_to_outbuf_from_inbuf
  534. (int *out_of_insamples,int *max_samp_written,sndoutmchptr sndout,double *splicebuf,int splicelen,float *lbuffer,int obuflen,dataptr dz)
  535. {
  536. unsigned int thisopos = sndout->obufpos;
  537. unsigned int here;
  538. double chanval1, chanval2;
  539. float *lbuf = lbuffer + thisopos;
  540. float *lbufend = lbuffer + obuflen;
  541. int splicpos = sndout->st_splicpos + thisopos;
  542. float outval, thismaxoutval;
  543. int max_set = FALSE, chan;
  544. while(lbuf < lbufend) {
  545. if((here = (unsigned int)sndout->ibufpos)>=sndout->ibufcnt) { /* TRUNCATE : get current pos in inbuf */
  546. *out_of_insamples = TRUE;
  547. *max_samp_written = max(*max_samp_written,lbuf - lbuffer);
  548. if(splicpos < splicelen) {
  549. sprintf(errstr,"BUM endsplice: add_samples_to_outbuf_from_inbuf()\n");
  550. return(PROGRAM_ERROR);
  551. }
  552. max_set = TRUE;
  553. break;
  554. }
  555. chanval1 = get_interpd_value_stereo(here,sndout->ibufpos,&chanval2,sndout);
  556. /* SAFETY FOR ARITHMETIC ROUNDING ERROS CALCULATING START OF SPLICE --> */
  557. if(splicpos >= splicelen) {
  558. chanval1 = 0.0;
  559. chanval2 = 0.0;
  560. }
  561. /* <--SAFETY */
  562. if(splicpos >= 0) {
  563. chanval1 *= splicebuf[splicpos/dz->iparam[TEXTURE_OUTCHANS]];
  564. chanval2 *= splicebuf[splicpos/dz->iparam[TEXTURE_OUTCHANS]];
  565. }
  566. splicpos += dz->iparam[TEXTURE_OUTCHANS];
  567. for(chan = 0;chan < dz->iparam[TEXTURE_OUTCHANS];chan++) {
  568. if(chan == sndout->lchan) {
  569. outval = (float)(*lbuf + (chanval1 * sndout->lgain));
  570. if((thismaxoutval = (float)fabs(outval))>dz->param[TEX_MAXOUT])
  571. dz->param[TEX_MAXOUT] = thismaxoutval;
  572. *lbuf = outval;
  573. } else if(chan == sndout->rchan) {
  574. outval = (float)(*lbuf + (chanval2 * sndout->lgain)); /* only one gain val for stereo inputs: kept in lgain */
  575. if((thismaxoutval = (float)fabs(outval))>dz->param[TEX_MAXOUT])
  576. dz->param[TEX_MAXOUT] = thismaxoutval;
  577. *lbuf = outval;
  578. }
  579. lbuf++;
  580. }
  581. sndout->ibufpos += sndout->step;
  582. }
  583. if(!max_set)
  584. *max_samp_written = obuflen;
  585. return(FINISHED);
  586. }
  587. /************************** GET_INTERPD_VALUE ************************/
  588. double get_interpd_value(unsigned int here,double ibufpos,sndoutmchptr sndout)
  589. {
  590. unsigned int next = here+1; /* NB all inbufs have a wraparound (0val) point at end */
  591. double frac = ibufpos - (double)here;
  592. double hereval = (double)(sndout->inbuf[here]);
  593. double nextval = (double)(sndout->inbuf[next]);
  594. double diff = nextval - hereval;
  595. diff *= frac;
  596. return(hereval+diff);
  597. }
  598. //TW UPDATE NEW FUNCTION for stereo input
  599. /************************** GET_INTERPD_VALUE_STEREO ************************/
  600. double get_interpd_value_stereo(unsigned int here,double ibufpos,double *chanval2,sndoutmchptr sndout)
  601. {
  602. unsigned int next = here+1; /* NB all inbufs have a wraparound (0val) point at end */
  603. double frac = ibufpos - (double)here;
  604. double hereval, nextval, diff;
  605. double chanval1;
  606. unsigned int sthere = here * 2, stnext = next * 2;
  607. hereval = (double)(sndout->inbuf[sthere]);
  608. nextval = (double)(sndout->inbuf[stnext]);
  609. diff = (nextval - hereval) * frac;
  610. chanval1 = hereval+diff;
  611. sthere++;
  612. stnext++;
  613. hereval = (double)(sndout->inbuf[sthere]);
  614. nextval = (double)(sndout->inbuf[stnext]);
  615. diff = (nextval - hereval) * frac;
  616. *chanval2 = hereval+diff;
  617. return(chanval1);
  618. }
  619. /************************** UNLINK_SNDOUTPTR_AT_START_OF_LIST ************************/
  620. void unlink_sndoutptr_at_start_of_list(sndoutmchptr sndout)
  621. {
  622. sndout->next->last = (sndoutmchptr)0;
  623. free(sndout);
  624. }
  625. /************************** UNLINK_SNDOUTPTR ************************/
  626. void unlink_sndoutptr(sndoutmchptr sndout)
  627. {
  628. sndout->next->last = sndout->last;
  629. sndout->last->next = sndout->next;
  630. free(sndout);
  631. }
  632. /************************** CHANPERM ************************/
  633. int chanperm(int lastperm,dataptr dz)
  634. {
  635. int endperm;
  636. dz->permcnt++;
  637. if(dz->permcnt >= dz->iparam[TEXTURE_OUTCHANS]) {
  638. endperm = dz->iparray[6][lastperm];
  639. do {
  640. permute_chunks(dz);
  641. } while (endperm == dz->iparray[6][0]);
  642. dz->permcnt = 0;
  643. }
  644. return dz->iparray[6][dz->permcnt];
  645. }
  646. /*************************** PERMUTE_CHUNKS ***************************/
  647. void permute_chunks(dataptr dz)
  648. {
  649. int n, t;
  650. for(n=0;n<dz->iparam[TEXTURE_OUTCHANS];n++) {
  651. t = (int)(drand48() * (double)(n+1)); /* TRUNCATE */
  652. if(t==n)
  653. prefix(n,dz);
  654. else
  655. insert(n,t,dz);
  656. }
  657. }
  658. /****************************** INSERT ****************************/
  659. void insert(int n,int t,dataptr dz)
  660. {
  661. shuflup(t+1,dz);
  662. dz->iparray[6][t+1] = n;
  663. }
  664. /****************************** PREFIX ****************************/
  665. void prefix(int n,dataptr dz)
  666. {
  667. shuflup(0,dz);
  668. dz->iparray[6][0] = n;
  669. }
  670. /****************************** SHUFLUP ****************************/
  671. void shuflup(int k,dataptr dz)
  672. {
  673. int n;
  674. for(n = dz->iparam[TEXTURE_OUTCHANS] - 1; n > k; n--)
  675. dz->iparray[6][n] = dz->iparray[6][n-1];
  676. }