grain.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. /*
  2. * Copyright (c) 1983-2020 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 along 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. /*floatsm version */
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <structures.h>
  25. #include <tkglobals.h>
  26. #include <globcon.h>
  27. #include <processno.h>
  28. #include <modeno.h>
  29. #include <logic.h>
  30. #include <arrays.h>
  31. #include <grain.h>
  32. #include <cdpmain.h>
  33. #include <sfsys.h>
  34. //#ifdef unix
  35. #define round(x) lround((x))
  36. //#endif
  37. static int grains(int *ibufposition,int bufno,int *crosbuf,int *inithole,int *grainstart,int * is_first_grain,
  38. int *gapcnt,int *holecnt,int *obufpos,int *graincnt,int chans,int *grainadjusted,
  39. double samptotime,double **env,double **envstep,double *envel_val,int winsize,dataptr dz);
  40. static int read_gate(int abs_ipos,int chans,dataptr dz);
  41. static double get_grainstart_time
  42. (int ibufpos,int grainstart,int abs_ipos,int crosbuf,double samptotime,dataptr dz);
  43. static int adjust_gate(double *gate,double *ngate,int abs_ipos,int winsize,
  44. double **env,double **envstep,double *envel_val,dataptr dz);
  45. static void swap_infile_and_otherfile(dataptr dz);
  46. static int count_grains_for_assess(int *graincnt,dataptr dz);
  47. /**************************** PROCESS_GRAINS *****************************/
  48. int process_grains(dataptr dz)
  49. {
  50. int exit_status;
  51. int ibufpos = 0, obufpos = 0, graincnt = 0, gapcnt = 0, holecnt = 0, grainadjusted = 0;
  52. int bufno = 0, crosbuf = 0, inithole = TRUE;
  53. int is_first_grain = TRUE;
  54. int chans = dz->infile->channels;
  55. double samptotime = 1.0/(double)(dz->infile->srate * chans);
  56. int grainstart = 0, winsize = dz->iparam[GR_WSIZE_SAMPS];
  57. double *env = dz->parray[GR_ENVEL];
  58. double *envstep = dz->parray[GR_ENVSTEP];
  59. double envel_val;
  60. int grain_get_flag = 1;
  61. int real_process = 0;
  62. int firstpass = 1;
  63. display_virtual_time(0,dz);
  64. while(grain_get_flag == 1) {
  65. if(firstpass) {
  66. if((dz->process == GRAIN_GET) || (dz->process == GRAIN_ALIGN)) {
  67. real_process = dz->process;
  68. dz->process = GRAIN_COUNT;
  69. fprintf(stdout,"INFO: Counting the grains.\n");
  70. fflush(stdout);
  71. } else {
  72. grain_get_flag = 0;
  73. }
  74. } else {
  75. if(graincnt == 0) {
  76. sprintf(errstr,"ERROR: No grains were found.\n");
  77. return(GOAL_FAILED);
  78. }
  79. fprintf(stdout,"INFO: Getting the grains.\n");
  80. fflush(stdout);
  81. if(sndseekEx(dz->ifd[0],0,0)<0) {
  82. sprintf(errstr,"Failed to seek to start of file.");
  83. return(SYSTEM_ERROR);
  84. }
  85. dz->total_samps_read = 0;
  86. dz->samps_left = dz->insams[0];
  87. display_virtual_time(0,dz);
  88. dz->process = real_process;
  89. env = dz->parray[GR_ENVEL];
  90. envstep = dz->parray[GR_ENVSTEP];
  91. ibufpos = 0;
  92. obufpos = 0;
  93. gapcnt = 0;
  94. holecnt = 0;
  95. bufno = 0;
  96. crosbuf = 0;
  97. grainadjusted = 0;
  98. inithole = TRUE;
  99. is_first_grain = TRUE;
  100. grain_get_flag = 0;
  101. if(sndseekEx(dz->ifd[0],0,0)<0) {
  102. sprintf(errstr,"ERROR: seek failed.\n");
  103. return(SYSTEM_ERROR);
  104. }
  105. }
  106. while(dz->samps_left > 0) {
  107. if((exit_status = read_samps(dz->sampbuf[bufno],dz))<0)
  108. return(exit_status);
  109. if((exit_status = grains(&ibufpos,bufno,&crosbuf,&inithole,&grainstart,&is_first_grain,
  110. &gapcnt,&holecnt,&obufpos,&graincnt,chans,&grainadjusted,samptotime,&env,&envstep,&envel_val,winsize,dz))<0)
  111. return(exit_status);
  112. if(exit_status!=CONTINUE)
  113. break;
  114. bufno = !bufno;
  115. }
  116. //TW REVISED
  117. if((exit_status = deal_with_last_grains(ibufpos,bufno,&graincnt,grainstart,
  118. &grainadjusted, &obufpos,crosbuf,chans,samptotime,&is_first_grain,dz))<0)
  119. return(exit_status);
  120. if(dz->outfiletype==SNDFILE_OUT && dz->process != GRAIN_ALIGN && obufpos!=0
  121. && (exit_status = write_samps(dz->sampbuf[2],obufpos ,dz))<0)
  122. return(exit_status);
  123. if(grainadjusted>0) {
  124. fprintf(stdout,"WARNING: %d output grains too small: size adjusted\n",grainadjusted);
  125. fflush(stdout);
  126. }
  127. firstpass = 0;
  128. }
  129. return(FINISHED);
  130. }
  131. /**************************** GRAINS *****************************/
  132. int grains(int *ibufposition,int bufno,int *crosbuf,int *inithole,int *grainstart,int *is_first_grain,
  133. int *gapcnt,int *holecnt,int *obufpos,int *graincnt,int chans,int *grainadjusted,
  134. double samptotime,double **env,double **envstep,double *envel_val,int winsize,dataptr dz)
  135. {
  136. int exit_status;
  137. register int ibufpos, abs_ipos;
  138. int in_grain, m;
  139. double gate, ngate;
  140. double thistime;
  141. float *obuf = dz->sampbuf[2];
  142. float *b = dz->sampbuf[bufno];
  143. int has_snd_output = FALSE;
  144. int samps_read_before_thisbuf = dz->total_samps_read - dz->ssampsread;
  145. if(dz->outfiletype==SNDFILE_OUT && dz->process != GRAIN_ALIGN)
  146. has_snd_output = TRUE;
  147. for(ibufpos = 0,abs_ipos = samps_read_before_thisbuf; ibufpos < dz->ssampsread; ibufpos+=chans,abs_ipos+=chans) {
  148. if(dz->ptr[GR_GATEVALS]!=NULL && (exit_status = read_gate(abs_ipos,chans,dz))<0)
  149. return(exit_status);
  150. gate = dz->param[GR_GATE] * F_MAXSAMP;
  151. ngate = dz->param[GR_NGATE] * F_MAXSAMP;
  152. if(dz->iparam[GR_WSIZE_SAMPS] > 0) { /* envelope tracking */
  153. if((exit_status = adjust_gate(&gate,&ngate,abs_ipos,winsize,env,envstep,envel_val,dz))<0)
  154. return(exit_status);
  155. }
  156. in_grain = FALSE;
  157. for(m=0;m<chans;m++) {
  158. if(b[ibufpos+m]>gate || b[ibufpos+m]<ngate)
  159. in_grain = TRUE;
  160. }
  161. if(in_grain) {
  162. if(*inithole) {
  163. *grainstart = ibufpos;
  164. *inithole = 0;
  165. }
  166. if(*holecnt) {
  167. if(*holecnt >= dz->iparam[GR_MINHOLE]) {
  168. thistime = get_grainstart_time(ibufpos,*grainstart,abs_ipos,*crosbuf,samptotime,dz);
  169. if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
  170. return(exit_status);
  171. if((exit_status = do_the_grain(ibufpos,graincnt,bufno,*gapcnt,obufpos,*grainstart,
  172. *crosbuf,chans,grainadjusted,samptotime,is_first_grain,dz))<0)
  173. return(exit_status);
  174. if(exit_status!=CONTINUE) {
  175. *ibufposition = ibufpos;
  176. return(FINISHED); /* grsync ran out of sync-times */
  177. }
  178. *grainstart = ibufpos;
  179. *gapcnt = 0;
  180. *crosbuf = 0;
  181. }
  182. }
  183. *holecnt = 0;
  184. } else {
  185. if(*inithole) {
  186. if(has_snd_output) {
  187. for(m=0;m<chans;m++)
  188. obuf[(*obufpos)++] = b[ibufpos+m];
  189. if(*obufpos >= dz->buflen) {
  190. if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
  191. return(exit_status);
  192. *obufpos = 0;
  193. }
  194. }
  195. continue;
  196. }
  197. *holecnt += chans;
  198. }
  199. *gapcnt += chans;
  200. }
  201. *ibufposition = ibufpos;
  202. if(*crosbuf==TRUE) { /* If crosbuf STILL set */
  203. if(dz->ssampsread == dz->buflen) { /* Reached end of buffer while doing crosbuf grain */
  204. if(dz->process == GRAIN_COUNT && dz->itemcnt == GRAIN_ASSESS) {
  205. if(dz->vflag[0] == 0) {
  206. fprintf(stdout,"WARNING: Encountered grain too large for buffer: counting grains so far\n");
  207. dz->vflag[0] = 1;
  208. }
  209. } else
  210. fprintf(stdout,"WARNING: Encountered grain too large for buffer: writing file so far\n");
  211. fflush(stdout);
  212. }
  213. return(FINISHED); /* Else reached end of file while doing crosbuf grain */
  214. }
  215. if(dz->samps_left) /* UNLESS we've reached end of src */
  216. *crosbuf = TRUE; /* mark crossing into next buffer */
  217. return(CONTINUE);
  218. }
  219. /************************** COPYGRAIN ******************************/
  220. int copygrain(int start,int end,int bufno,int *obufposition,dataptr dz)
  221. {
  222. int exit_status;
  223. float *b = dz->sampbuf[bufno];
  224. float *obuf = dz->sampbuf[2];
  225. register int n, obufpos = *obufposition;
  226. for(n=start;n<end;n++) {
  227. obuf[obufpos++] = b[n];
  228. if(obufpos >= dz->buflen) {
  229. if((exit_status = write_samps(obuf,dz->buflen,dz))<0)
  230. return(exit_status);
  231. obufpos = 0;
  232. }
  233. }
  234. *obufposition = obufpos;
  235. return(FINISHED);
  236. }
  237. /************************ CROSBUF_GRAIN_TYPE3 **********************/
  238. int crosbuf_grain_type3(int grainstart,int grainend,int bufno,int *obufpos,dataptr dz)
  239. {
  240. int exit_status;
  241. if((exit_status = copygrain(grainstart,dz->buflen,!bufno,obufpos,dz))<0)
  242. return(exit_status);
  243. return copygrain(0L,grainend,bufno,obufpos,dz);
  244. }
  245. /***************************** CHECK_GRAIN_CONSISTENCY ******************************/
  246. int check_grain_consistency(dataptr dz)
  247. {
  248. int exit_status;
  249. int maxval;
  250. double dmaxval;
  251. switch(dz->process) {
  252. case(GRAIN_OMIT): /* Check grains-to-KEEP vals against OUT-OF */
  253. if(dz->brksize[GR_KEEP]) {
  254. if((exit_status = get_maxvalue_in_brktable(&dmaxval,GR_KEEP,dz))<0)
  255. return(exit_status);
  256. maxval = round(dmaxval);
  257. } else
  258. maxval = dz->iparam[GR_KEEP];
  259. if(maxval > dz->iparam[GR_OUT_OF]) {
  260. sprintf(errstr,"A value of %d grains-to-keep out of each %d is impossible.\n",maxval,(int)dz->iparam[GR_OUT_OF]);
  261. return(DATA_ERROR);
  262. }
  263. break;
  264. default:
  265. sprintf(errstr,"Unknown case in check_grain_consistency()\n");
  266. return(PROGRAM_ERROR);
  267. }
  268. return(FINISHED);
  269. }
  270. /***************************** READ_GATE ******************************/
  271. int read_gate(int abs_ipos,int chans,dataptr dz)
  272. {
  273. double sampstep;
  274. if(abs_ipos >= dz->iparam[GR_NEXTBRKSAMP]) {
  275. dz->iparam[GR_THISBRKSAMP] = dz->iparam[GR_NEXTBRKSAMP];
  276. dz->param[GR_GATE] = dz->param[GR_NEXTGATE];
  277. dz->param[GR_NGATE] = -(dz->param[GR_GATE]);
  278. dz->iparam[GR_NEXTBRKSAMP] = round(*(dz->ptr[GR_GATEVALS]++));
  279. dz->param[GR_NEXTGATE] = *(dz->ptr[GR_GATEVALS]++);
  280. if((dz->iparam[GR_TESTLIM] = dz->iparam[GR_NEXTBRKSAMP] - (GR_INTERPLIMIT * chans)) < dz->iparam[GR_THISBRKSAMP])
  281. dz->iparam[GR_TESTLIM] = dz->iparam[GR_NEXTBRKSAMP];
  282. sampstep = (double)((dz->iparam[GR_NEXTBRKSAMP] - dz->iparam[GR_THISBRKSAMP])/chans);
  283. dz->param[GR_GATESTEP] = (double)(dz->param[GR_NEXTGATE] - dz->param[GR_GATE])/sampstep;
  284. if(dz->param[GR_GATESTEP]>0.0)
  285. dz->iparam[GR_UP] = TRUE;
  286. else
  287. dz->iparam[GR_UP] = FALSE;
  288. } else {
  289. dz->param[GR_GATE] += dz->param[GR_GATESTEP];
  290. if(abs_ipos > dz->iparam[GR_TESTLIM]) { /* allowing for arithmetic rounding */
  291. if(dz->iparam[GR_UP]==TRUE) {
  292. if(dz->param[GR_GATE] > dz->param[GR_NEXTGATE])
  293. dz->param[GR_GATE] = dz->param[GR_NEXTGATE];
  294. } else {
  295. if(dz->param[GR_GATE] < dz->param[GR_NEXTGATE])
  296. dz->param[GR_GATE] = dz->param[GR_NEXTGATE];
  297. }
  298. }
  299. dz->param[GR_NGATE] = -(dz->param[GR_GATE]);
  300. }
  301. return(FINISHED);
  302. }
  303. /**************************** GET_GRAINSTART_TIME ***************************/
  304. double get_grainstart_time(int ibufpos,int grainstart,int abs_ipos,int crosbuf,double samptotime,dataptr dz)
  305. {
  306. double thistime;
  307. int abs_grainstart;
  308. int grainlen = ibufpos - grainstart;
  309. if(crosbuf)
  310. grainlen += dz->buflen;
  311. abs_grainstart = abs_ipos - grainlen;
  312. thistime = (double)abs_grainstart * samptotime;
  313. return thistime;
  314. }
  315. /******************* SWAP_TO_OTHERFILE_AND_READJUST_COUNTERS *******************/
  316. int swap_to_otherfile_and_readjust_counters(dataptr dz)
  317. {
  318. swap_infile_and_otherfile(dz); /* Now process 2nd file AS IF it were infile. */
  319. dz->infile->channels = dz->otherfile->channels;
  320. dz->infile->srate = dz->otherfile->srate;
  321. dz->infile->stype = dz->otherfile->stype;
  322. reset_filedata_counters(dz); /* initalise all counters before starting 2nd processing */
  323. if(dz->iparam[GR_WSIZE_SAMPS] > 0) { /* Free envelope storage arrays */
  324. free(dz->parray[GR_ENVEL]);
  325. free(dz->parray[GR_ENVSTEP]);
  326. }
  327. return(FINISHED);
  328. }
  329. /***************************** SWAP_INFILE_AND_OTHERFILE **************************
  330. *
  331. * SWAPPING (rather than simply replacing ifd0 by ifd1) ensures that both files
  332. * are closed properly in finish().
  333. */
  334. void swap_infile_and_otherfile(dataptr dz)
  335. {
  336. int fd;
  337. int filesize;
  338. int insamples;
  339. fd = dz->ifd[0];
  340. dz->ifd[0] = dz->ifd[1];
  341. dz->ifd[1] = fd;
  342. filesize = dz->insams[0];
  343. dz->insams[0] = dz->insams[1];
  344. dz->insams[1] = filesize;
  345. insamples = dz->insams[0];
  346. dz->insams[0] = dz->insams[1];
  347. dz->insams[1] = insamples;
  348. }
  349. /**************************** ADJUST_GATE ***************************/
  350. int adjust_gate(double *gate,double *ngate,int abs_ipos,int winsize,
  351. double **env,double **envstep,double *envel_val,dataptr dz)
  352. {
  353. int cnt;
  354. if(abs_ipos==0)
  355. *envel_val = **env;
  356. else if((cnt = abs_ipos%winsize)==0) {
  357. (*env)++;
  358. (*envstep)++;
  359. if(*env >= dz->ptr[GR_ENVEND] || *envstep >= dz->ptr[GR_ESTEPEND]) {
  360. sprintf(errstr,"Envelope array overflow: adjust_gate()\n");
  361. return(PROGRAM_ERROR);
  362. }
  363. *envel_val = **env;
  364. } else
  365. *envel_val += **envstep;
  366. *gate *= *envel_val;
  367. *ngate = -(*gate);
  368. return(FINISHED);
  369. }
  370. /*************************** ASSESS_GRAINS **************************/
  371. int assess_grains(dataptr dz)
  372. {
  373. int exit_status;
  374. int lastgraincnt = 0, graincnt = 0;
  375. int firsttime = 1;
  376. double step = 0.1;
  377. double bestgate;
  378. double hi_error = 1.0 -FLTERR;
  379. dz->process = GRAIN_COUNT;
  380. dz->itemcnt = GRAIN_ASSESS; /*n temporary storage */
  381. dz->param[GR_GATE] = GR_GATE_DEFAULT;
  382. dz->param[GR_NGATE] = -(dz->param[GR_GATE]);
  383. bestgate = dz->param[GR_GATE];
  384. fprintf(stdout,"INFO: Scanning file\n");
  385. fflush(stdout);
  386. step = 0.1;
  387. firsttime = 1;
  388. if((exit_status = count_grains_for_assess(&graincnt,dz)) < 0) {
  389. dz->process = GRAIN_ASSESS;
  390. return(exit_status);
  391. }
  392. dz->param[GR_GATE] += step;
  393. dz->param[GR_NGATE] = -(dz->param[GR_GATE]);
  394. while(fabs(step) > .00002) {
  395. lastgraincnt = graincnt;
  396. graincnt = 0;
  397. if((exit_status = count_grains_for_assess(&graincnt,dz)) < 0) {
  398. dz->process = GRAIN_ASSESS;
  399. return(exit_status);
  400. }
  401. if(graincnt >= lastgraincnt) {
  402. firsttime = 0;
  403. bestgate = dz->param[GR_GATE];
  404. dz->param[GR_GATE] += step;
  405. if(dz->param[GR_GATE] >= hi_error || dz->param[GR_GATE] < 0.0) {
  406. dz->param[GR_GATE] -= step;
  407. step *= 0.1;
  408. dz->param[GR_GATE] += step;
  409. firsttime = 1;
  410. }
  411. } else if(firsttime) {
  412. graincnt = lastgraincnt;
  413. step = -step;
  414. if((dz->param[GR_GATE] += (step * 2.0)) < 0.0) {
  415. break;
  416. }
  417. firsttime = 0;
  418. } else {
  419. dz->param[GR_GATE] -= step;
  420. bestgate = dz->param[GR_GATE];
  421. graincnt = lastgraincnt;
  422. step *= 0.1;
  423. dz->param[GR_GATE] += step;
  424. firsttime = 1;
  425. }
  426. dz->param[GR_NGATE] = -dz->param[GR_GATE];
  427. }
  428. if(lastgraincnt == 0)
  429. sprintf(errstr,"Unable to find any grains in this sound.\n");
  430. else
  431. sprintf(errstr,"Maximum grains found = %d at gate value %lf and windowlen 50ms\n",lastgraincnt,bestgate);
  432. fflush(stdout);
  433. dz->process = GRAIN_ASSESS;
  434. return(FINISHED);
  435. }
  436. /*************************** COUNT_GRAINS_FOR_ASSESS **************************/
  437. int count_grains_for_assess(int *graincnt,dataptr dz)
  438. {
  439. int exit_status;
  440. int ibufpos = 0, obufpos = 0, gapcnt = 0, holecnt = 0, grainadjusted = 0;
  441. int bufno = 0, crosbuf = 0, inithole = TRUE;
  442. int is_first_grain = TRUE;
  443. int chans = dz->infile->channels;
  444. double samptotime = 1.0/(double)(dz->infile->srate * chans);
  445. int grainstart=0, winsize = dz->iparam[GR_WSIZE_SAMPS];
  446. double *env = dz->parray[GR_ENVEL];
  447. double *envstep = dz->parray[GR_ENVSTEP];
  448. double envel_val;
  449. sndseekEx(dz->ifd[0],0,0);
  450. reset_filedata_counters(dz);
  451. display_virtual_time(0,dz);
  452. while(dz->samps_left > 0) {
  453. if((exit_status = read_samps(dz->sampbuf[bufno],dz)<0))
  454. return(exit_status);
  455. if((exit_status = grains(&ibufpos,bufno,&crosbuf,&inithole,&grainstart,&is_first_grain,
  456. &gapcnt,&holecnt,&obufpos,graincnt,chans,&grainadjusted,samptotime,&env,&envstep,&envel_val,winsize,dz))<0)
  457. return(exit_status);
  458. if(exit_status!=CONTINUE)
  459. break;
  460. bufno = !bufno;
  461. }
  462. if((exit_status = deal_with_last_grains(ibufpos,bufno,graincnt,grainstart,
  463. &grainadjusted, &obufpos,crosbuf,chans,samptotime,&is_first_grain,dz))<0)
  464. return(exit_status);
  465. return(FINISHED);
  466. }