paview.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  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 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. /**************************************************************************
  22. *
  23. * Convert snd data to text format suitable for Pview in Sound Loom
  24. */
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <osbind.h>
  29. #include <math.h>
  30. #include <float.h>
  31. #include <float.h>
  32. #include <sfsys.h>
  33. #include <cdplib.h>
  34. #define VIEW_WIDTH 900 /* width of sloom display */
  35. #define VIEW_HEIGHT 300 /* heigth of sloom display */
  36. #define HALF_VIEW_HEIGHT 150 /* half heigth of sloom display */
  37. #define COLOR_SPECTRUM 45 /* number of individual colours supported */
  38. #define EFFECTIVE_VIEW_WIDTH (VIEW_WIDTH - (VIEW_HEIGHT * 2))
  39. #define F_SECSIZE (256)
  40. /* Functions */
  41. static int tidy_up(int,unsigned int);
  42. static int open_in(char*);
  43. static int get_big_buf(void);
  44. static int make_textfile(int sonogram,char *filename);
  45. static int write_output(int outlen,double *outbuf,double convertor,int sonogram,FILE *fp);
  46. float *bigbuf, *sampbuf;
  47. int Mlen;
  48. float arate, frametime;
  49. int buflen; /* buffer length in samps */
  50. int ifd; /* input soundfile descriptor */
  51. int channels, expanded; /* number of channels of input */
  52. int startwin, endwin, startchan, endchan;
  53. const char* cdp_version = "7.1.0";
  54. int main(int argc,char *argv[])
  55. {
  56. unsigned int start = hz1000();
  57. char filename[200];
  58. double starttime, endtime;
  59. int sonogram;
  60. if(argc==2 && (strcmp(argv[1],"--version") == 0)) {
  61. fprintf(stdout,"%s\n",cdp_version);
  62. fflush(stdout);
  63. return 0;
  64. }
  65. /* initialise SFSYS */
  66. if( sflinit("paview") < 0 ) {
  67. fprintf(stdout,"ERROR: Cannot initialise soundfile system.\n");
  68. fflush(stdout);
  69. return tidy_up(3,start);
  70. }
  71. if(argc!=7) {
  72. fprintf(stdout,"ERROR: Wrong number of arguments.\n");
  73. fflush(stdout);
  74. return tidy_up(2,start);
  75. }
  76. if(sscanf(argv[2],"%lf",&starttime)!=1) {
  77. fprintf(stdout,"ERROR: cannot read start time.\n");
  78. fflush(stdout);
  79. return tidy_up(2,start);
  80. }
  81. if(sscanf(argv[3],"%lf",&endtime)!=1) {
  82. fprintf(stdout,"ERROR: cannot read end time.\n");
  83. fflush(stdout);
  84. return tidy_up(2,start);
  85. }
  86. if(sscanf(argv[4],"%d",&sonogram)!=1) {
  87. fprintf(stdout,"ERROR: cannot read sonogram flag.\n");
  88. fflush(stdout);
  89. return tidy_up(2,start);
  90. }
  91. if(sscanf(argv[5],"%d",&startchan)!=1) {
  92. fprintf(stdout,"ERROR: cannot read sonogram flag.\n");
  93. fflush(stdout);
  94. return tidy_up(2,start);
  95. }
  96. if(sscanf(argv[6],"%d",&endchan)!=1) {
  97. fprintf(stdout,"ERROR: cannot read sonogram flag.\n");
  98. fflush(stdout);
  99. return tidy_up(2,start);
  100. }
  101. /* open input file */
  102. if(open_in(argv[1]) < 0)
  103. return tidy_up(2,start);
  104. startwin = (int)floor(starttime/frametime);
  105. endwin = (int)ceil(endtime/frametime);
  106. strcpy(filename,argv[1]);
  107. /* get biggest buffer */
  108. if(get_big_buf() == 0)
  109. return tidy_up(1,start);
  110. /* max soundfiles */
  111. if(make_textfile(sonogram,filename)<0)
  112. return tidy_up(1,start);
  113. /* tidy up */
  114. return tidy_up(0,start);
  115. }
  116. /**************************** OPEN_IN ****************************
  117. *
  118. * opens input soundfile and gets header
  119. */
  120. int open_in(char *name) /* opens input soundfile and gets header */
  121. {
  122. if((ifd = sndopenEx(name,0,CDP_OPEN_RDONLY)) < 0) {
  123. fprintf(stdout,"ERROR: Cannot open file: %s\n\t",name);
  124. fflush(stdout);
  125. return(-1);
  126. }
  127. /* get channels */
  128. if(sndgetprop(ifd, "channels", (char*)&channels, sizeof(int)) < 0) {
  129. fprintf(stdout,"ERROR: Cannot get channel count of %s\n",name);
  130. fflush(stdout);
  131. return(-1);
  132. }
  133. /* get frametime */
  134. if(sndgetprop(ifd,"arate",(char *)&arate,sizeof(float)) < 0){
  135. fprintf(stdout,"ERROR: Failure to read analysis sample rate, in %s\n",name);
  136. fflush(stdout);
  137. return(-1);
  138. }
  139. frametime = (float)(1.0/arate);
  140. return 0;
  141. }
  142. /**************************** GET_BIG_BUF ****************************
  143. *
  144. * allocates memory for the biggest possible buffer
  145. */
  146. int get_big_buf(void)
  147. {
  148. size_t i;
  149. if((bigbuf=(float*)Malloc(((channels * 2) + F_SECSIZE) * sizeof(float))) == NULL) {
  150. fprintf(stdout,"ERROR: Failed to allocate float buffer.\n");
  151. fflush(stdout);
  152. return 0;
  153. }
  154. i = ((size_t)bigbuf+sizeof(float)-1)/sizeof(float)*sizeof(float); /* align bigbuf to word boundary */
  155. bigbuf = (float*)i;
  156. memset((char *)bigbuf,0,(channels * 2) * sizeof(float));
  157. sampbuf = bigbuf + channels;
  158. buflen = channels;
  159. /* allow for wrap-around */
  160. return 1;
  161. }
  162. /**************************** MAKE TEXTFILE *****************************/
  163. int make_textfile(int sonogram,char *filename)
  164. {
  165. FILE *fp;
  166. int samplen, zoomfact, total_windowsgot_got, samps_remain;
  167. int got, sampsgot, windowsgot, bufcnt, wingrpcnt;
  168. int channelstoshow, chanscale, ch_outlen, w_outlen, done_display, obufcnt, changrpcnt;
  169. float *rbuf;
  170. double *outbuf;
  171. double channelmax;
  172. int n, displayed_channel_cnt, channel_cnt, totchans;
  173. double convertor, zscale;
  174. expanded = 0;
  175. if(sonogram) {
  176. w_outlen = VIEW_WIDTH;
  177. ch_outlen = VIEW_HEIGHT;
  178. convertor = COLOR_SPECTRUM / 3.0; /* converts range 0 --> 3 TO range of colours */
  179. } else {
  180. w_outlen = EFFECTIVE_VIEW_WIDTH;
  181. ch_outlen = HALF_VIEW_HEIGHT;
  182. convertor = HALF_VIEW_HEIGHT / 6.0; /* converts range 0 --> 3 TO range 0 -> quarter-view-heigth */
  183. }
  184. if((outbuf = (double *)malloc(ch_outlen * sizeof(double))) == NULL) {
  185. fprintf(stdout, "ERROR: Insufficient memory to store output values.\n");
  186. fflush(stdout);
  187. return -1;
  188. }
  189. if((samplen = sndsizeEx(ifd))<0) { /* FIND SIZE OF FILE */
  190. fprintf(stdout, "ERROR: Can't read size of input file %s.\n",filename);
  191. fflush(stdout);
  192. return -1;
  193. }
  194. if((fp = fopen("cdptest00.txt","w"))==NULL) {
  195. fprintf(stdout, "ERROR: Failed to open the Sound Loom display file 'cdptest00.txt'\n");
  196. fflush(stdout);
  197. return -1;
  198. }
  199. zoomfact = max(1L,(int)ceil((double)(endwin - startwin)/w_outlen));
  200. total_windowsgot_got = 0;
  201. samps_remain = 0;
  202. rbuf = sampbuf;
  203. totchans = channels/2;
  204. if((channelstoshow = endchan - startchan) == 0) {
  205. if(endchan != totchans)
  206. endchan++;
  207. else if(startchan !=0)
  208. startchan--;
  209. channelstoshow++;
  210. }
  211. zscale = (double)channelstoshow / (double)ch_outlen;
  212. if(zscale < .5)
  213. expanded = (int)round((double)ch_outlen / (double)channelstoshow);
  214. chanscale = (int)ceil((double)channelstoshow / (double)ch_outlen); /* ratio of channels to available pixels */
  215. memset((char *)outbuf,0, ch_outlen * sizeof(double));
  216. done_display = 0;
  217. wingrpcnt = 0; /* cnt of set-of-windows to be zoomed together */
  218. while((got = fgetfbufEx(sampbuf,buflen,ifd,1)) > 0 ) {
  219. sampsgot = samps_remain; /* Take into account any wrapped around values */
  220. sampsgot += got;
  221. windowsgot = sampsgot/channels;
  222. samps_remain = sampsgot - (windowsgot * channels);
  223. bufcnt = 0; /* cnt in buffer we're reading from (which includes wrap-around) */
  224. for(n=0;n<windowsgot;n++) { /* for every window */
  225. total_windowsgot_got++; /* count the windows */
  226. if(total_windowsgot_got <= startwin) { /* if not at 1st window to display, continue */
  227. bufcnt += channels;
  228. continue;
  229. }
  230. else if(total_windowsgot_got > endwin) { /* if beyond last window to display, quit */
  231. done_display = 1;
  232. break;
  233. }
  234. obufcnt = 0; /* count in buffer of output values */
  235. changrpcnt = 0; /* count of set-of-channels to group together for display */
  236. channelmax = 0.0;
  237. for(channel_cnt=0;channel_cnt < startchan;channel_cnt++)
  238. bufcnt += 2;
  239. for(displayed_channel_cnt = 0; displayed_channel_cnt < channelstoshow; displayed_channel_cnt++) {
  240. if(rbuf[bufcnt] > channelmax) /* for each channel to display */
  241. channelmax = rbuf[bufcnt]; /* find maximum value amongst group of channels */
  242. if(++changrpcnt >= chanscale) { /* once whole group has been surveyed */
  243. if(channelmax > outbuf[obufcnt])/* transfer maxvalue to output, if it's larger than val alreasdy there */
  244. outbuf[obufcnt] = channelmax; /* (we are also possibly averaging over windows, by zoomfact) */
  245. obufcnt++; /* move to next outbuffer location */
  246. channelmax = 0.0; /* reset channelmax to min */
  247. changrpcnt = 0; /* start counting next group */
  248. }
  249. bufcnt += 2; /* move up to next amplitude value */
  250. }
  251. if(changrpcnt > 0) { /* last channels may not be a full group: if not, output their val here */
  252. if(channelmax > outbuf[obufcnt])
  253. outbuf[obufcnt] = channelmax;
  254. obufcnt++;
  255. channelmax = 0.0;
  256. changrpcnt = 0;
  257. }
  258. channel_cnt += displayed_channel_cnt;
  259. while(channel_cnt < totchans) {
  260. bufcnt += 2;
  261. channel_cnt++;
  262. }
  263. wingrpcnt++;
  264. if(wingrpcnt >= zoomfact) { /* if we have looked at enough windows (in the zoom) */
  265. if(write_output(ch_outlen,outbuf,convertor,sonogram,fp) < 0) {
  266. fclose(fp);
  267. fprintf(stdout, "ERROR: Failed to complete data write to Sound Loom display file 'cdptest00.txt'\n");
  268. fflush(stdout);
  269. return -1;
  270. }
  271. memset((char *)outbuf,0, ch_outlen * sizeof(double));
  272. wingrpcnt = 0; /* reset the obuf, and the window counter */
  273. }
  274. }
  275. if(done_display) /* if reached end of windows to display, quit */
  276. break;
  277. if(samps_remain) { /* if there are extra samples beyond end of windows */
  278. rbuf = sampbuf - samps_remain; /* wrap them around */
  279. memcpy((char *)rbuf,(char *)(rbuf + (windowsgot * channels)),samps_remain * sizeof(float));
  280. } else
  281. rbuf = sampbuf;
  282. }
  283. if(wingrpcnt > 0) { /* last windows looed at did not form a complete zoom set */
  284. if(write_output(ch_outlen,outbuf,convertor,sonogram,fp) < 0) {
  285. fclose(fp);
  286. fprintf(stdout, "ERROR: Failed to complete data write to Sound Loom display file 'cdptest00.txt'\n");
  287. fflush(stdout);
  288. return -1;
  289. }
  290. }
  291. fclose(fp);
  292. return(0);
  293. }
  294. /**************************** TIDY_UP ****************************
  295. *
  296. * Exit, freeing buffers and closing files where necessary.
  297. */
  298. int tidy_up(int where,unsigned int start)
  299. {
  300. switch(where) {
  301. case 0:
  302. Mfree(bigbuf);
  303. case 1:
  304. sndcloseEx(ifd);
  305. case 2:
  306. // sffinish();
  307. default:
  308. break;
  309. }
  310. while(!(hz1000() - start))
  311. ;
  312. return(1);
  313. }
  314. /**************************** WRITE_OUTPUT ****************************/
  315. int write_output(int outlen,double *outbuf,double convertor,int sonogram,FILE *fp)
  316. {
  317. int z, x, zob=0;
  318. int channelstoshow;
  319. char temp[2000];
  320. char temp2[64];
  321. temp[0] = '\0';
  322. if(expanded) {
  323. channelstoshow = endchan - startchan;
  324. for(z = 0;z < channelstoshow; z++) { /* output trhe results */
  325. outbuf[z] *= 999.0;
  326. outbuf[z] += 1.0; /* Range 0-1 -->> 1 to 1000 */
  327. outbuf[z] = log10(outbuf[z]); /* Range 1 to 1000 -->> 1 to 3 */
  328. outbuf[z] *= convertor;
  329. if(sonogram) {
  330. zob = (int)round(outbuf[z]);
  331. }
  332. for(x = 0; x < expanded; x++) {
  333. if(sonogram) {
  334. sprintf(temp2,"%d",zob);
  335. } else {
  336. sprintf(temp2,"%lf",outbuf[z]);
  337. }
  338. strcat(temp2," ");
  339. strcat(temp,temp2);
  340. }
  341. }
  342. } else {
  343. for(z = 0;z < outlen; z++) { /* output trhe results */
  344. outbuf[z] *= 999.0;
  345. outbuf[z] += 1.0; /* Range 0-1 -->> 1 to 1000 */
  346. outbuf[z] = log10(outbuf[z]); /* Range 1 to 1000 -->> 1 to 3 */
  347. outbuf[z] *= convertor; /* For Sonogram: Range 1 to 3 -->> 0 to 0 to max colour */
  348. /* FOr Spectrum: Range 1 to 3 -->> 0 to half of HALF_VIEW_HEIGHT */
  349. if(sonogram) {
  350. sprintf(temp2,"%d",(int)round(outbuf[z]));
  351. } else {
  352. sprintf(temp2,"%lf",outbuf[z]);
  353. }
  354. strcat(temp2," ");
  355. strcat(temp,temp2);
  356. }
  357. }
  358. if(fprintf(fp,"%s\n",temp) < 1)
  359. return -1;
  360. return 1;
  361. }