sfprops.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  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. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <math.h>
  36. #include <ctype.h>
  37. #include <time.h>
  38. #include <sfsys.h>
  39. #include <chanmask.h>
  40. #ifdef unix
  41. int stricmp(const char *a, const char *b)
  42. {
  43. while(*a != '\0' && *b != '\0') {
  44. int ca = islower(*a) ? toupper(*a) : *a;
  45. int cb = islower(*b) ? toupper(*b) : *b;
  46. if(ca < cb)
  47. return -1;
  48. if(ca > cb)
  49. return 1;
  50. a++;
  51. b++;
  52. }
  53. if(*a == '\0' && *b == '\0')
  54. return 0;
  55. if(*a != '\0')
  56. return 1;
  57. return -1;
  58. }
  59. #endif
  60. typedef struct wave_ex_speaker {
  61. int mask;
  62. char name[28];
  63. } WAVE_EX_SPEAKER;
  64. static const WAVE_EX_SPEAKER speakers[NUM_SPEAKER_POSITIONS] = {
  65. {SPEAKER_FRONT_LEFT,"Front Left"},
  66. {SPEAKER_FRONT_RIGHT,"Front Right"},
  67. {SPEAKER_FRONT_CENTER,"Front Centre"},
  68. {SPEAKER_LOW_FREQUENCY,"Low Frequency"},
  69. {SPEAKER_BACK_LEFT,"Back Left"},
  70. {SPEAKER_BACK_RIGHT,"Back Right"},
  71. {SPEAKER_FRONT_LEFT_OF_CENTER,"Front Centre-Left"},
  72. {SPEAKER_FRONT_RIGHT_OF_CENTER,"Front Centre-Right"},
  73. {SPEAKER_BACK_CENTER,"Back Centre"},
  74. {SPEAKER_SIDE_LEFT,"Side Left"},
  75. {SPEAKER_SIDE_RIGHT,"Side Right"},
  76. {SPEAKER_TOP_CENTER,"Top Centre"},
  77. {SPEAKER_TOP_FRONT_LEFT,"Front Top Left"},
  78. {SPEAKER_TOP_FRONT_CENTER,"Front Top Centre"},
  79. {SPEAKER_TOP_FRONT_RIGHT,"Front Top Right"},
  80. {SPEAKER_TOP_BACK_LEFT,"Back Top Left"},
  81. {SPEAKER_TOP_BACK_CENTER,"Back Top Centre"},
  82. {SPEAKER_TOP_BACK_RIGHT,"Back Top Right"}
  83. };
  84. void usage(){
  85. fprintf(stderr,"CDP MCTOOLS: SFPROPS v2.2.0 (c) RWD,CDP,1999,2009,2010,2013\n"
  86. "Display soundfile details, with WAVE-EX speaker positions\n"
  87. "\n\tusage: sfprops infile\n");
  88. }
  89. int main(int argc, char **argv)
  90. {
  91. int i,ifd;
  92. unsigned int nframes,filesize; /* FEB 2010 */
  93. double srate;
  94. SFPROPS props = {0};
  95. const char *name = NULL;
  96. CHPEAK *peaks = NULL;
  97. int res,peaktime,speakermask = 0;
  98. float fmaxamp;
  99. int lmaxamp;
  100. /* CDP version number */
  101. if(argc==2 && (stricmp(argv[1],"--version")==0)){
  102. printf("2.2.0.\n");
  103. return 0;
  104. }
  105. if(argc< 2){
  106. usage();
  107. exit(1);
  108. }
  109. if(sflinit("sfprops")){
  110. fprintf(stderr,"SFPROPS: unable to initialize CDP Sound Filing System\n");
  111. exit(1);
  112. }
  113. if((ifd = sndopenEx(argv[1],0,CDP_OPEN_RDONLY)) < 0){
  114. fprintf(stderr,"SFPROPS: unable to open infile %s: %s\n",argv[1], sferrstr());
  115. exit(1);
  116. }
  117. if(!snd_headread(ifd,&props)){
  118. fprintf(stderr,"SFPROPS: unable to read infile header\n");
  119. exit(1);
  120. }
  121. srate = (double) props.srate;
  122. filesize = sndsizeEx(ifd);
  123. nframes = filesize/ props.chans; /*assume soundfile for now */
  124. name = snd_getfilename(ifd);
  125. printf("Properties of %s:\n",name);
  126. printf("File type: ");
  127. switch(props.type){
  128. case(wt_wave):
  129. printf("soundfile\nFormat : ");
  130. switch(props.format){
  131. case(WAVE):
  132. printf("Standard WAVE format\n");
  133. break;
  134. case(WAVE_EX):
  135. printf("MS WAVE-FORMAT-EXTENSIBLE\n");
  136. printf("SPEAKER CONFIGURATION:\t");
  137. switch(props.chformat){
  138. //case(MC_STD):
  139. // printf("unassigned (generic format)");
  140. // break;
  141. case(MC_MONO):
  142. printf("Mono\n");
  143. break;
  144. case(MC_STEREO):
  145. printf("Stereo\n");
  146. break;
  147. case(MC_QUAD):
  148. printf("Rectangular Quad\n");
  149. break;
  150. case(MC_LCRS):
  151. printf("Quad Surround\n");
  152. break;
  153. case(MC_BFMT):
  154. printf("Ambisonic B-Format\n");
  155. break;
  156. case(MC_DOLBY_5_1):
  157. printf("5.1 (Dolby) Surround\n");
  158. break;
  159. case(MC_SURR_6_1):
  160. printf("6.1 Surround\n");
  161. break;
  162. case(MC_SURR_7_1):
  163. printf("7.1 Surround\n");
  164. break;
  165. case(MC_CUBE):
  166. printf("Cube Surround\n");
  167. break;
  168. default:
  169. printf("Special speaker assignments\n");
  170. break;
  171. }
  172. speakermask = sndgetchanmask(ifd);
  173. if(speakermask < 0)
  174. fprintf(stderr,"Unable to read speakermask from WAVE_EX header\n");
  175. else {
  176. //try to figure out the mask
  177. int assigned = 0;
  178. int shift = 0;
  179. int this_channel = 1;
  180. printf("Speaker Mask = %d (0x%x)\n",speakermask,(unsigned int) speakermask);
  181. while(assigned < props.chans){
  182. if(speakers[shift].mask & speakermask){
  183. printf("Channel %d: %s\n",this_channel++,speakers[shift].name);
  184. assigned++;
  185. }
  186. if(++shift == NUM_SPEAKER_POSITIONS)
  187. break;
  188. }
  189. if(assigned < props.chans)
  190. printf("Remaining channels not assigned speaker locations.\n");
  191. }
  192. break;
  193. case(AIFF):
  194. printf("AIFF format\n");
  195. break;
  196. case(AIFC):
  197. printf("AIFC format\n");
  198. break;
  199. default:
  200. printf("unknown format\n");
  201. break;
  202. }
  203. printf("Sample Rate : %d\n",props.srate);
  204. printf("Channels : %d\n",props.chans);
  205. printf("Sample Frames : %d\n",nframes);
  206. printf("sample type: : ");
  207. switch(props.samptype){
  208. case(SHORT8):
  209. printf("8-bit\n");
  210. break;
  211. case(SHORT16):
  212. printf("16-bit\n");
  213. break;
  214. case(FLOAT32):
  215. printf("32bit floats\n");
  216. break;
  217. case(INT_32):
  218. printf("32bit (integer)\n");
  219. break;
  220. case(INT2424):
  221. printf("24bit (packed)\n");
  222. break;
  223. case(INT2432):
  224. printf("24bit in 32bit words\n");
  225. break;
  226. case(INT2024):
  227. printf("20bit in 24bit words\n");
  228. break;
  229. case(INT_MASKED):
  230. printf("non-standard WAVE_EX format\n");
  231. //fet more info....
  232. break;
  233. default:
  234. printf("sorry: don't recognize word format!\n");
  235. break;
  236. }
  237. printf("duration : %.4lf secs\n",(double)nframes / srate);
  238. //this is the problem: we never decided what type maxamp is, officially!
  239. if(props.samptype==FLOAT32){
  240. if(sndgetprop(ifd,"maxamp",(char *)&fmaxamp,sizeof(float)) == sizeof(float)){
  241. printf("CDP maxamp : %.4lf\n",fmaxamp);
  242. }
  243. }
  244. else{
  245. if(sndgetprop(ifd,"maxamp",(char *)&lmaxamp,sizeof(int)) == sizeof(int)){
  246. printf("CDP maxamp : %d\n",lmaxamp);
  247. }
  248. }
  249. peaks = (CHPEAK *) calloc(props.chans,sizeof(CHPEAK));
  250. if(peaks==NULL){
  251. puts("sfprops: no memory for fpeak data buffer\n");
  252. exit(1);
  253. }
  254. else{
  255. time_t thistime;
  256. res = sndreadpeaks(ifd,props.chans,peaks, (int *) &peaktime);
  257. thistime = (time_t) peaktime;
  258. if(res ==0)
  259. printf("no peak data in this infile\n");
  260. else if(res < 0){
  261. fprintf(stderr,"sfprops: WARNING: error reading infile peak data\n");
  262. }
  263. else {
  264. printf("PEAK data:\n\tcreation time: %s\n", ctime(&thistime));
  265. //for(i=0;i < props.chans; i++)
  266. // printf("CH %d: %.4lf at frame %d:\t%.4lf secs\n",
  267. // i+1,peaks[i].value,peaks[i].position,(double) (peaks[i].position) / srate);
  268. for(i=0; i < props.chans; i++){
  269. double val, dbval;
  270. val = (double) peaks[i].value;
  271. if(val > 0.0){
  272. dbval = 20.0 * log10(val);
  273. printf("CH %d: %.6f (%.2lfdB) at frame %9d:\t%.4f secs\n",i,
  274. val,dbval,peaks[i].position,(double)(peaks[i].position / (double) srate));
  275. }
  276. else{
  277. printf("CH %d: %.6f (-infdB) \t\t:\t%.4f secs\n",
  278. i,
  279. val, (double)(peaks[i].position / (double) srate));
  280. }
  281. }
  282. }
  283. }
  284. break;
  285. case(wt_analysis):
  286. printf("CDP pvoc analysis file.\n");
  287. printf("Channel Format: Amplitude,Frequency\n");
  288. printf("Orig rate: %d\n",props.origrate);
  289. printf("Analysis Window Size: %d\n",props.winlen);
  290. printf("Analysis channels: %d\n",props.chans/2);
  291. printf("Window Overlap: %d\n",props.decfac);
  292. printf("Analysis rate: %.4f\n",props.arate);
  293. printf("Frame count: %d\n",filesize / (props.chans));
  294. printf("Data size (floats): %d\n",filesize);
  295. printf("Duration (secs): %.3lf\n",
  296. ((filesize / props.chans) * props.decfac) / (double) props.origrate);
  297. break;
  298. case(wt_formant):
  299. printf("CDP formant data\n");
  300. printf("Specenvcnt: %d\n",props.specenvcnt);
  301. printf("Analysis Window Size: %d\n",props.winlen);
  302. printf("Channels: %d\n",props.chans);
  303. printf("Frame count: %d\n",filesize);
  304. printf("Orig rate: %d\n",props.origrate);
  305. printf("Window Overlap: %d\n",props.decfac);
  306. printf("Analysis rate: %.4f\n",props.arate);
  307. printf("Orig Chans: %d\n",props.origchans);
  308. printf("Duration (secs): %.3lf\n",(filesize /props.specenvcnt)/ props.arate );
  309. break;
  310. case(wt_transposition):
  311. printf("CDP transposition data\n");
  312. printf("Orig sample rate: %d\n",props.origrate);
  313. printf("Analysis Window Size: %d\n",props.winlen);
  314. printf("Channels: %d\n",props.chans);
  315. printf("Window Overlap: %d\n",props.decfac);
  316. printf("Analysis rate: %.4f\n",props.arate);
  317. printf("Orig Chans: %d\n",props.origchans);
  318. printf("Data size (floats): %d\n",filesize);
  319. printf("Duration (secs): %.3lf\n",
  320. ((filesize / props.chans) * props.decfac) / (double) props.origrate);
  321. break;
  322. case(wt_pitch):
  323. printf("CDP pitch data\n");
  324. printf("Orig sample rate: %d\n",props.origrate);
  325. printf("Analysis Window Size: %d\n",props.winlen);
  326. printf("Channels: %d\n",props.chans);
  327. printf("Window Overlap: %d\n",props.decfac);
  328. printf("Analysis rate: %.4f\n",props.arate);
  329. printf("Orig Chans: %d\n",props.origchans);
  330. printf("Data size (floats): %d\n",filesize);
  331. printf("Duration (secs): %.3lf\n",
  332. ((filesize / props.chans) * props.decfac) / (double) props.origrate);
  333. break;
  334. case(wt_binenv):
  335. printf("CDP binary envelope data\n");
  336. printf("envelope window size: %f msecs\n",props.window_size);
  337. printf("sample rate: %d\n",props.srate);
  338. printf("Channels: %d\n",props.chans);
  339. printf("Points: %d\n",filesize);
  340. printf("Duration (secs): %.3f\n",filesize * (props.window_size * 0.001));
  341. break;
  342. default:
  343. printf("internal error! unlisted soundfile type\n");
  344. break;
  345. }
  346. sndcloseEx(ifd);
  347. // sffinish();
  348. return 0;
  349. }