sfprops.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. /*
  2. * Copyright (c) 1983-2013 Richard Dobson and Composers Desktop Project Ltd
  3. * http://people.bath.ac.uk/masrwd
  4. * http://www.composersdesktop.com
  5. * This file is part of the CDP System.
  6. * The CDP System is free software; you can redistribute it
  7. * and/or modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  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.
  14. * See the 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 02111-1307 USA
  18. *
  19. */
  20. /* sfprops.c: display primary soundfile properties
  21. * uses sfsysEx.lib: recognizes WAVE-EX formats
  22. * part of the CDP MCTOOLS suite
  23. */
  24. //RWD.6.99 use new funcs to report 24bit formats, etc
  25. //last update: 22.6.99 enumerate PEAK chans from 1, link with latest sfsysEx
  26. /* Nov28 2001: rebuild with sfsysEx recognizing stupid QuickTime AIFC floats with 16bit size! */
  27. /*Dec 2005 support .amb extension */
  28. /*April 2006: build with updated sfsys to read PEAK chunk after data chunk (Thanks to Sony!)*/
  29. /* OCT 2009 TODO: sort out 64bit platform issues (peaktime etc) */
  30. /* FEB 2010: decl filesize etc as unsigned to read huge file sizes! */
  31. /* Nov 2013 added MC_SURR_6_1 */
  32. /* March 2023: add flags for plain numeric output, as helper for TV scripts */
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <math.h>
  37. #include <ctype.h>
  38. #include <time.h>
  39. #include <sfsys.h>
  40. #include <chanmask.h>
  41. #ifdef unix
  42. int stricmp(const char *a, const char *b)
  43. {
  44. while(*a != '\0' && *b != '\0') {
  45. int ca = islower(*a) ? toupper(*a) : *a;
  46. int cb = islower(*b) ? toupper(*b) : *b;
  47. if(ca < cb)
  48. return -1;
  49. if(ca > cb)
  50. return 1;
  51. a++;
  52. b++;
  53. }
  54. if(*a == '\0' && *b == '\0')
  55. return 0;
  56. if(*a != '\0')
  57. return 1;
  58. return -1;
  59. }
  60. #endif
  61. typedef struct wave_ex_speaker {
  62. int mask;
  63. char name[28];
  64. } WAVE_EX_SPEAKER;
  65. static const WAVE_EX_SPEAKER speakers[NUM_SPEAKER_POSITIONS] = {
  66. {SPEAKER_FRONT_LEFT,"Front Left"},
  67. {SPEAKER_FRONT_RIGHT,"Front Right"},
  68. {SPEAKER_FRONT_CENTER,"Front Centre"},
  69. {SPEAKER_LOW_FREQUENCY,"Low Frequency"},
  70. {SPEAKER_BACK_LEFT,"Back Left"},
  71. {SPEAKER_BACK_RIGHT,"Back Right"},
  72. {SPEAKER_FRONT_LEFT_OF_CENTER,"Front Centre-Left"},
  73. {SPEAKER_FRONT_RIGHT_OF_CENTER,"Front Centre-Right"},
  74. {SPEAKER_BACK_CENTER,"Back Centre"},
  75. {SPEAKER_SIDE_LEFT,"Side Left"},
  76. {SPEAKER_SIDE_RIGHT,"Side Right"},
  77. {SPEAKER_TOP_CENTER,"Top Centre"},
  78. {SPEAKER_TOP_FRONT_LEFT,"Front Top Left"},
  79. {SPEAKER_TOP_FRONT_CENTER,"Front Top Centre"},
  80. {SPEAKER_TOP_FRONT_RIGHT,"Front Top Right"},
  81. {SPEAKER_TOP_BACK_LEFT,"Back Top Left"},
  82. {SPEAKER_TOP_BACK_CENTER,"Back Top Centre"},
  83. {SPEAKER_TOP_BACK_RIGHT,"Back Top Right"}
  84. };
  85. void usage(){
  86. fprintf(stderr,"CDP MCTOOLS: SFPROPS v2.2.1 (c) RWD,CDP,1999,2009,2010,2013,2023\n"
  87. "Display soundfile details, with WAVE-EX speaker positions\n"
  88. "\n\tusage: sfprops [-c | -d | -r] infile\n");
  89. fprintf(stderr,"\tflag options for single data report\n");
  90. fprintf(stderr,"\t-c: print number of channels in file\n");
  91. fprintf(stderr,"\t-d: print duration (secs) of file\n");
  92. fprintf(stderr,"\t-r: print sample rate of file\n");
  93. }
  94. int main(int argc, char **argv)
  95. {
  96. int i,ifd;
  97. unsigned int nframes,filesize; /* FEB 2010 */
  98. double srate;
  99. SFPROPS props = {0};
  100. const char *name = NULL;
  101. CHPEAK *peaks = NULL;
  102. int res,peaktime,speakermask = 0;
  103. float fmaxamp;
  104. int lmaxamp;
  105. unsigned int do_singleflag = 0;
  106. unsigned int wantsr = 0, wantdur = 0,wantchans = 0;
  107. if(argc< 2){
  108. usage();
  109. exit(1);
  110. }
  111. /* CDP version number */
  112. if(argc==2 && (stricmp(argv[1],"--version")==0)){
  113. printf("2.2.1.\n");
  114. return 0;
  115. }
  116. //RWD new, for TV scripting
  117. if(argc>2 && argv[1][0] == '-'){
  118. unsigned char uiflag = 0;
  119. if(argv[1][1] == '\0'){
  120. fprintf(stderr,"no flag option specified\n");
  121. return 0;
  122. }
  123. else {
  124. do_singleflag = 1;
  125. uiflag = argv[1][1];
  126. switch(uiflag){
  127. case 'c':
  128. wantchans = 1;
  129. break;
  130. case 'r':
  131. wantsr = 1;
  132. break;
  133. case 'd':
  134. wantdur = 1;
  135. break;
  136. default:
  137. fprintf(stderr,"unrecognised flag %s\n",argv[1]);
  138. return 0;
  139. break;
  140. }
  141. }
  142. argv++;
  143. argc--;
  144. }
  145. if(sflinit("sfprops")){
  146. if(do_singleflag)
  147. printf("0\n");
  148. else
  149. fprintf(stderr,"SFPROPS: unable to initialize CDP Sound Filing System\n");
  150. exit(1);
  151. }
  152. if((ifd = sndopenEx(argv[1],0,CDP_OPEN_RDONLY)) < 0){
  153. if(do_singleflag)
  154. printf("0\n");
  155. else
  156. fprintf(stderr,"SFPROPS: unable to open infile %s: %s\n",argv[1], sferrstr());
  157. exit(1);
  158. }
  159. if(!snd_headread(ifd,&props)){
  160. if(do_singleflag)
  161. printf("0\n");
  162. else
  163. fprintf(stderr,"SFPROPS: unable to read infile header\n");
  164. exit(1);
  165. }
  166. srate = (double) props.srate;
  167. if(do_singleflag && wantsr){
  168. printf("%u\n",props.srate);
  169. sndcloseEx(ifd);
  170. return 0;
  171. }
  172. filesize = sndsizeEx(ifd);
  173. nframes = filesize/ props.chans; /*assume soundfile for now */
  174. if(do_singleflag && wantdur){
  175. float dur = nframes / srate;
  176. printf("%f\n",dur);
  177. sndcloseEx(ifd);
  178. return 0;
  179. }
  180. if(do_singleflag && wantchans){
  181. printf("%u\n",props.chans);
  182. sndcloseEx(ifd);
  183. return 0;
  184. }
  185. name = snd_getfilename(ifd);
  186. printf("Properties of %s:\n",name);
  187. printf("File type: ");
  188. switch(props.type){
  189. case(wt_wave):
  190. printf("soundfile\nFormat : ");
  191. switch(props.format){
  192. case(WAVE):
  193. printf("Standard WAVE format\n");
  194. break;
  195. case(WAVE_EX):
  196. printf("MS WAVE-FORMAT-EXTENSIBLE\n");
  197. printf("SPEAKER CONFIGURATION:\t");
  198. switch(props.chformat){
  199. //case(MC_STD):
  200. // printf("unassigned (generic format)");
  201. // break;
  202. case(MC_MONO):
  203. printf("Mono\n");
  204. break;
  205. case(MC_STEREO):
  206. printf("Stereo\n");
  207. break;
  208. case(MC_QUAD):
  209. printf("Rectangular Quad\n");
  210. break;
  211. case(MC_LCRS):
  212. printf("Quad Surround\n");
  213. break;
  214. case(MC_BFMT):
  215. printf("Ambisonic B-Format\n");
  216. break;
  217. case(MC_DOLBY_5_1):
  218. printf("5.1 (Dolby) Surround\n");
  219. break;
  220. case(MC_SURR_6_1):
  221. printf("6.1 Surround\n");
  222. break;
  223. case(MC_SURR_7_1):
  224. printf("7.1 Surround\n");
  225. break;
  226. case(MC_CUBE):
  227. printf("Cube Surround\n");
  228. break;
  229. default:
  230. printf("Special speaker assignments\n");
  231. break;
  232. }
  233. speakermask = sndgetchanmask(ifd);
  234. if(speakermask < 0)
  235. fprintf(stderr,"Unable to read speakermask from WAVE_EX header\n");
  236. else {
  237. //try to figure out the mask
  238. int assigned = 0;
  239. int shift = 0;
  240. int this_channel = 1;
  241. printf("Speaker Mask = %d (0x%x)\n",speakermask,(unsigned int) speakermask);
  242. while(assigned < props.chans){
  243. if(speakers[shift].mask & speakermask){
  244. printf("Channel %d: %s\n",this_channel++,speakers[shift].name);
  245. assigned++;
  246. }
  247. if(++shift == NUM_SPEAKER_POSITIONS)
  248. break;
  249. }
  250. if(assigned < props.chans)
  251. printf("Remaining channels not assigned speaker locations.\n");
  252. }
  253. break;
  254. case(AIFF):
  255. printf("AIFF format\n");
  256. break;
  257. case(AIFC):
  258. printf("AIFC format\n");
  259. break;
  260. default:
  261. printf("unknown format\n");
  262. break;
  263. }
  264. printf("Sample Rate : %d\n",props.srate);
  265. printf("Channels : %d\n",props.chans);
  266. printf("Sample Frames : %d\n",nframes);
  267. printf("sample type: : ");
  268. switch(props.samptype){
  269. case(SHORT8):
  270. printf("8-bit\n");
  271. break;
  272. case(SHORT16):
  273. printf("16-bit\n");
  274. break;
  275. case(FLOAT32):
  276. printf("32bit floats\n");
  277. break;
  278. case(INT_32):
  279. printf("32bit (integer)\n");
  280. break;
  281. case(INT2424):
  282. printf("24bit (packed)\n");
  283. break;
  284. case(INT2432):
  285. printf("24bit in 32bit words\n");
  286. break;
  287. case(INT2024):
  288. printf("20bit in 24bit words\n");
  289. break;
  290. case(INT_MASKED):
  291. printf("non-standard WAVE_EX format\n");
  292. //fet more info....
  293. break;
  294. default:
  295. printf("sorry: don't recognize word format!\n");
  296. break;
  297. }
  298. printf("duration : %.4lf secs\n",(double)nframes / srate);
  299. //this is the problem: we never decided what type maxamp is, officially!
  300. if(props.samptype==FLOAT32){
  301. if(sndgetprop(ifd,"maxamp",(char *)&fmaxamp,sizeof(float)) == sizeof(float)){
  302. printf("CDP maxamp : %.4lf\n",fmaxamp);
  303. }
  304. }
  305. else{
  306. if(sndgetprop(ifd,"maxamp",(char *)&lmaxamp,sizeof(int)) == sizeof(int)){
  307. printf("CDP maxamp : %d\n",lmaxamp);
  308. }
  309. }
  310. peaks = (CHPEAK *) calloc(props.chans,sizeof(CHPEAK));
  311. if(peaks==NULL){
  312. puts("sfprops: no memory for fpeak data buffer\n");
  313. exit(1);
  314. }
  315. else{
  316. time_t thistime;
  317. res = sndreadpeaks(ifd,props.chans,peaks, (int *) &peaktime);
  318. thistime = (time_t) peaktime;
  319. if(res ==0)
  320. printf("no peak data in this infile\n");
  321. else if(res < 0){
  322. fprintf(stderr,"sfprops: WARNING: error reading infile peak data\n");
  323. }
  324. else {
  325. printf("PEAK data:\n\tcreation time: %s\n", ctime(&thistime));
  326. //for(i=0;i < props.chans; i++)
  327. // printf("CH %d: %.4lf at frame %d:\t%.4lf secs\n",
  328. // i+1,peaks[i].value,peaks[i].position,(double) (peaks[i].position) / srate);
  329. for(i=0; i < props.chans; i++){
  330. double val, dbval;
  331. val = (double) peaks[i].value;
  332. if(val > 0.0){
  333. dbval = 20.0 * log10(val);
  334. printf("CH %d: %.6f (%.2lfdB) at frame %9d:\t%.4f secs\n",i,
  335. val,dbval,peaks[i].position,(double)(peaks[i].position / (double) srate));
  336. }
  337. else{
  338. printf("CH %d: %.6f (-infdB) \t\t:\t%.4f secs\n",
  339. i,
  340. val, (double)(peaks[i].position / (double) srate));
  341. }
  342. }
  343. }
  344. }
  345. break;
  346. case(wt_analysis):
  347. printf("CDP pvoc analysis file.\n");
  348. printf("Channel Format: Amplitude,Frequency\n");
  349. printf("Orig rate: %d\n",props.origrate);
  350. printf("Analysis Window Size: %d\n",props.winlen);
  351. printf("Analysis channels: %d\n",props.chans/2);
  352. printf("Window Overlap: %d\n",props.decfac);
  353. printf("Analysis rate: %.4f\n",props.arate);
  354. printf("Frame count: %d\n",filesize / (props.chans));
  355. printf("Data size (floats): %d\n",filesize);
  356. printf("Duration (secs): %.3lf\n",
  357. ((filesize / props.chans) * props.decfac) / (double) props.origrate);
  358. break;
  359. case(wt_formant):
  360. printf("CDP formant data\n");
  361. printf("Specenvcnt: %d\n",props.specenvcnt);
  362. printf("Analysis Window Size: %d\n",props.winlen);
  363. printf("Channels: %d\n",props.chans);
  364. printf("Frame count: %d\n",filesize);
  365. printf("Orig rate: %d\n",props.origrate);
  366. printf("Window Overlap: %d\n",props.decfac);
  367. printf("Analysis rate: %.4f\n",props.arate);
  368. printf("Orig Chans: %d\n",props.origchans);
  369. printf("Duration (secs): %.3lf\n",(filesize /props.specenvcnt)/ props.arate );
  370. break;
  371. case(wt_transposition):
  372. printf("CDP transposition data\n");
  373. printf("Orig sample rate: %d\n",props.origrate);
  374. printf("Analysis Window Size: %d\n",props.winlen);
  375. printf("Channels: %d\n",props.chans);
  376. printf("Window Overlap: %d\n",props.decfac);
  377. printf("Analysis rate: %.4f\n",props.arate);
  378. printf("Orig Chans: %d\n",props.origchans);
  379. printf("Data size (floats): %d\n",filesize);
  380. printf("Duration (secs): %.3lf\n",
  381. ((filesize / props.chans) * props.decfac) / (double) props.origrate);
  382. break;
  383. case(wt_pitch):
  384. printf("CDP pitch data\n");
  385. printf("Orig sample rate: %d\n",props.origrate);
  386. printf("Analysis Window Size: %d\n",props.winlen);
  387. printf("Channels: %d\n",props.chans);
  388. printf("Window Overlap: %d\n",props.decfac);
  389. printf("Analysis rate: %.4f\n",props.arate);
  390. printf("Orig Chans: %d\n",props.origchans);
  391. printf("Data size (floats): %d\n",filesize);
  392. printf("Duration (secs): %.3lf\n",
  393. ((filesize / props.chans) * props.decfac) / (double) props.origrate);
  394. break;
  395. case(wt_binenv):
  396. printf("CDP binary envelope data\n");
  397. printf("envelope window size: %f msecs\n",props.window_size);
  398. printf("sample rate: %d\n",props.srate);
  399. printf("Channels: %d\n",props.chans);
  400. printf("Points: %d\n",filesize);
  401. printf("Duration (secs): %.3f\n",filesize * (props.window_size * 0.001));
  402. break;
  403. default:
  404. printf("internal error! unlisted soundfile type\n");
  405. break;
  406. }
  407. sndcloseEx(ifd);
  408. // sffinish();
  409. return 0;
  410. }