Mercurial > hg > sv-dependency-builds
comparison src/libsndfile-1.0.25/programs/sndfile-info.c @ 85:545efbb81310
Import initial set of sources
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Mon, 18 Mar 2013 14:12:14 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 85:545efbb81310 |
---|---|
1 /* | |
2 ** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com> | |
3 ** | |
4 ** All rights reserved. | |
5 ** | |
6 ** Redistribution and use in source and binary forms, with or without | |
7 ** modification, are permitted provided that the following conditions are | |
8 ** met: | |
9 ** | |
10 ** * Redistributions of source code must retain the above copyright | |
11 ** notice, this list of conditions and the following disclaimer. | |
12 ** * Redistributions in binary form must reproduce the above copyright | |
13 ** notice, this list of conditions and the following disclaimer in | |
14 ** the documentation and/or other materials provided with the | |
15 ** distribution. | |
16 ** * Neither the author nor the names of any contributors may be used | |
17 ** to endorse or promote products derived from this software without | |
18 ** specific prior written permission. | |
19 ** | |
20 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
21 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
22 ** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
23 ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |
24 ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
25 ** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
26 ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |
27 ** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
28 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | |
29 ** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
30 ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
31 */ | |
32 | |
33 #include <stdio.h> | |
34 #include <stdlib.h> | |
35 #include <string.h> | |
36 #include <inttypes.h> | |
37 #include <ctype.h> | |
38 #include <math.h> | |
39 | |
40 #include <sndfile.h> | |
41 | |
42 #include "common.h" | |
43 | |
44 #define BUFFER_LEN (1 << 16) | |
45 | |
46 #if (defined (WIN32) || defined (_WIN32)) | |
47 #include <windows.h> | |
48 #endif | |
49 | |
50 static void print_version (void) ; | |
51 static void usage_exit (const char *progname) ; | |
52 | |
53 static void info_dump (const char *filename) ; | |
54 static int instrument_dump (const char *filename) ; | |
55 static int broadcast_dump (const char *filename) ; | |
56 static int chanmap_dump (const char *filename) ; | |
57 static void total_dump (void) ; | |
58 | |
59 static double total_seconds = 0.0 ; | |
60 | |
61 int | |
62 main (int argc, char *argv []) | |
63 { int k ; | |
64 | |
65 print_version () ; | |
66 | |
67 if (argc < 2 || strcmp (argv [1], "--help") == 0 || strcmp (argv [1], "-h") == 0) | |
68 { usage_exit (program_name (argv [0])) ; | |
69 return 1 ; | |
70 } ; | |
71 | |
72 if (strcmp (argv [1], "-i") == 0) | |
73 { int error = 0 ; | |
74 | |
75 for (k = 2 ; k < argc ; k++) | |
76 error += instrument_dump (argv [k]) ; | |
77 return error ; | |
78 } ; | |
79 | |
80 if (strcmp (argv [1], "-b") == 0) | |
81 { int error = 0 ; | |
82 | |
83 for (k = 2 ; k < argc ; k++) | |
84 error += broadcast_dump (argv [k]) ; | |
85 return error ; | |
86 } ; | |
87 | |
88 if (strcmp (argv [1], "-c") == 0) | |
89 { int error = 0 ; | |
90 | |
91 for (k = 2 ; k < argc ; k++) | |
92 error += chanmap_dump (argv [k]) ; | |
93 return error ; | |
94 } ; | |
95 | |
96 for (k = 1 ; k < argc ; k++) | |
97 info_dump (argv [k]) ; | |
98 | |
99 if (argc > 2) | |
100 total_dump () ; | |
101 | |
102 return 0 ; | |
103 } /* main */ | |
104 | |
105 /*============================================================================== | |
106 ** Print version and usage. | |
107 */ | |
108 | |
109 static double data [BUFFER_LEN] ; | |
110 | |
111 static void | |
112 print_version (void) | |
113 { char buffer [256] ; | |
114 | |
115 sf_command (NULL, SFC_GET_LIB_VERSION, buffer, sizeof (buffer)) ; | |
116 printf ("\nVersion : %s\n\n", buffer) ; | |
117 } /* print_version */ | |
118 | |
119 | |
120 static void | |
121 usage_exit (const char *progname) | |
122 { printf ("Usage :\n %s <file> ...\n", progname) ; | |
123 printf (" Prints out information about one or more sound files.\n\n") ; | |
124 printf (" %s -i <file>\n", progname) ; | |
125 printf (" Prints out the instrument data for the given file.\n\n") ; | |
126 printf (" %s -b <file>\n", progname) ; | |
127 printf (" Prints out the broadcast WAV info for the given file.\n\n") ; | |
128 #if (defined (_WIN32) || defined (WIN32)) | |
129 printf ("This is a Unix style command line application which\n" | |
130 "should be run in a MSDOS box or Command Shell window.\n\n") ; | |
131 printf ("Sleeping for 5 seconds before exiting.\n\n") ; | |
132 fflush (stdout) ; | |
133 | |
134 /* This is the officially blessed by microsoft way but I can't get | |
135 ** it to link. | |
136 ** Sleep (15) ; | |
137 ** Instead, use this: | |
138 */ | |
139 Sleep (5 * 1000) ; | |
140 #endif | |
141 printf ("Using %s.\n\n", sf_version_string ()) ; | |
142 exit (0) ; | |
143 } /* usage_exit */ | |
144 | |
145 /*============================================================================== | |
146 ** Dumping of sndfile info. | |
147 */ | |
148 | |
149 static double data [BUFFER_LEN] ; | |
150 | |
151 static double | |
152 get_signal_max (SNDFILE *file) | |
153 { double max ; | |
154 | |
155 sf_command (file, SFC_CALC_SIGNAL_MAX, &max, sizeof (max)) ; | |
156 | |
157 return max ; | |
158 } /* get_signal_max */ | |
159 | |
160 static double | |
161 calc_decibels (SF_INFO * sfinfo, double max) | |
162 { double decibels ; | |
163 | |
164 switch (sfinfo->format & SF_FORMAT_SUBMASK) | |
165 { case SF_FORMAT_PCM_U8 : | |
166 case SF_FORMAT_PCM_S8 : | |
167 decibels = max / 0x80 ; | |
168 break ; | |
169 | |
170 case SF_FORMAT_PCM_16 : | |
171 decibels = max / 0x8000 ; | |
172 break ; | |
173 | |
174 case SF_FORMAT_PCM_24 : | |
175 decibels = max / 0x800000 ; | |
176 break ; | |
177 | |
178 case SF_FORMAT_PCM_32 : | |
179 decibels = max / 0x80000000 ; | |
180 break ; | |
181 | |
182 case SF_FORMAT_FLOAT : | |
183 case SF_FORMAT_DOUBLE : | |
184 decibels = max / 1.0 ; | |
185 break ; | |
186 | |
187 default : | |
188 decibels = max / 0x8000 ; | |
189 break ; | |
190 } ; | |
191 | |
192 return 20.0 * log10 (decibels) ; | |
193 } /* calc_decibels */ | |
194 | |
195 static const char * | |
196 format_duration_str (double seconds) | |
197 { static char str [128] ; | |
198 int hrs, min ; | |
199 double sec ; | |
200 | |
201 memset (str, 0, sizeof (str)) ; | |
202 | |
203 hrs = (int) (seconds / 3600.0) ; | |
204 min = (int) ((seconds - (hrs * 3600.0)) / 60.0) ; | |
205 sec = seconds - (hrs * 3600.0) - (min * 60.0) ; | |
206 | |
207 snprintf (str, sizeof (str) - 1, "%02d:%02d:%06.3f", hrs, min, sec) ; | |
208 | |
209 return str ; | |
210 } /* format_duration_str */ | |
211 | |
212 static const char * | |
213 generate_duration_str (SF_INFO *sfinfo) | |
214 { | |
215 double seconds ; | |
216 | |
217 if (sfinfo->samplerate < 1) | |
218 return NULL ; | |
219 | |
220 if (sfinfo->frames / sfinfo->samplerate > 0x7FFFFFFF) | |
221 return "unknown" ; | |
222 | |
223 seconds = (1.0 * sfinfo->frames) / sfinfo->samplerate ; | |
224 | |
225 /* Accumulate the total of all known file durations */ | |
226 total_seconds += seconds ; | |
227 | |
228 return format_duration_str (seconds) ; | |
229 } /* generate_duration_str */ | |
230 | |
231 static void | |
232 info_dump (const char *filename) | |
233 { static char strbuffer [BUFFER_LEN] ; | |
234 SNDFILE *file ; | |
235 SF_INFO sfinfo ; | |
236 double signal_max, decibels ; | |
237 | |
238 memset (&sfinfo, 0, sizeof (sfinfo)) ; | |
239 | |
240 if ((file = sf_open (filename, SFM_READ, &sfinfo)) == NULL) | |
241 { printf ("Error : Not able to open input file %s.\n", filename) ; | |
242 fflush (stdout) ; | |
243 memset (data, 0, sizeof (data)) ; | |
244 sf_command (file, SFC_GET_LOG_INFO, strbuffer, BUFFER_LEN) ; | |
245 puts (strbuffer) ; | |
246 puts (sf_strerror (NULL)) ; | |
247 return ; | |
248 } ; | |
249 | |
250 printf ("========================================\n") ; | |
251 sf_command (file, SFC_GET_LOG_INFO, strbuffer, BUFFER_LEN) ; | |
252 puts (strbuffer) ; | |
253 printf ("----------------------------------------\n") ; | |
254 | |
255 printf ("Sample Rate : %d\n", sfinfo.samplerate) ; | |
256 | |
257 if (sfinfo.frames == SF_COUNT_MAX) | |
258 printf ("Frames : unknown\n") ; | |
259 else | |
260 printf ("Frames : %" PRId64 "\n", sfinfo.frames) ; | |
261 | |
262 printf ("Channels : %d\n", sfinfo.channels) ; | |
263 printf ("Format : 0x%08X\n", sfinfo.format) ; | |
264 printf ("Sections : %d\n", sfinfo.sections) ; | |
265 printf ("Seekable : %s\n", (sfinfo.seekable ? "TRUE" : "FALSE")) ; | |
266 printf ("Duration : %s\n", generate_duration_str (&sfinfo)) ; | |
267 | |
268 if (sfinfo.frames < 100 * 1024 * 1024) | |
269 { /* Do not use sf_signal_max because it doesn't work for non-seekable files . */ | |
270 signal_max = get_signal_max (file) ; | |
271 decibels = calc_decibels (&sfinfo, signal_max) ; | |
272 printf ("Signal Max : %g (%4.2f dB)\n", signal_max, decibels) ; | |
273 } ; | |
274 putchar ('\n') ; | |
275 | |
276 sf_close (file) ; | |
277 | |
278 } /* info_dump */ | |
279 | |
280 /*============================================================================== | |
281 ** Dumping of SF_INSTRUMENT data. | |
282 */ | |
283 | |
284 static const char * | |
285 str_of_type (int mode) | |
286 { switch (mode) | |
287 { case SF_LOOP_NONE : return "none" ; | |
288 case SF_LOOP_FORWARD : return "fwd " ; | |
289 case SF_LOOP_BACKWARD : return "back" ; | |
290 case SF_LOOP_ALTERNATING : return "alt " ; | |
291 default : break ; | |
292 } ; | |
293 | |
294 return "????" ; | |
295 } /* str_of_mode */ | |
296 | |
297 static int | |
298 instrument_dump (const char *filename) | |
299 { SNDFILE *file ; | |
300 SF_INFO sfinfo ; | |
301 SF_INSTRUMENT inst ; | |
302 int got_inst, k ; | |
303 | |
304 memset (&sfinfo, 0, sizeof (sfinfo)) ; | |
305 | |
306 if ((file = sf_open (filename, SFM_READ, &sfinfo)) == NULL) | |
307 { printf ("Error : Not able to open input file %s.\n", filename) ; | |
308 fflush (stdout) ; | |
309 memset (data, 0, sizeof (data)) ; | |
310 puts (sf_strerror (NULL)) ; | |
311 return 1 ; | |
312 } ; | |
313 | |
314 got_inst = sf_command (file, SFC_GET_INSTRUMENT, &inst, sizeof (inst)) ; | |
315 sf_close (file) ; | |
316 | |
317 if (got_inst == SF_FALSE) | |
318 { printf ("Error : File '%s' does not contain instrument data.\n\n", filename) ; | |
319 return 1 ; | |
320 } ; | |
321 | |
322 printf ("Instrument : %s\n\n", filename) ; | |
323 printf (" Gain : %d\n", inst.gain) ; | |
324 printf (" Base note : %d\n", inst.basenote) ; | |
325 printf (" Velocity : %d - %d\n", (int) inst.velocity_lo, (int) inst.velocity_hi) ; | |
326 printf (" Key : %d - %d\n", (int) inst.key_lo, (int) inst.key_hi) ; | |
327 printf (" Loop points : %d\n", inst.loop_count) ; | |
328 | |
329 for (k = 0 ; k < inst.loop_count ; k++) | |
330 printf (" %-2d Mode : %s Start : %6d End : %6d Count : %6d\n", k, str_of_type (inst.loops [k].mode), inst.loops [k].start, inst.loops [k].end, inst.loops [k].count) ; | |
331 | |
332 putchar ('\n') ; | |
333 return 0 ; | |
334 } /* instrument_dump */ | |
335 | |
336 static int | |
337 broadcast_dump (const char *filename) | |
338 { SNDFILE *file ; | |
339 SF_INFO sfinfo ; | |
340 SF_BROADCAST_INFO_2K bext ; | |
341 double time_ref_sec ; | |
342 int got_bext ; | |
343 | |
344 memset (&sfinfo, 0, sizeof (sfinfo)) ; | |
345 | |
346 if ((file = sf_open (filename, SFM_READ, &sfinfo)) == NULL) | |
347 { printf ("Error : Not able to open input file %s.\n", filename) ; | |
348 fflush (stdout) ; | |
349 memset (data, 0, sizeof (data)) ; | |
350 puts (sf_strerror (NULL)) ; | |
351 return 1 ; | |
352 } ; | |
353 | |
354 memset (&bext, 0, sizeof (SF_BROADCAST_INFO_2K)) ; | |
355 | |
356 got_bext = sf_command (file, SFC_GET_BROADCAST_INFO, &bext, sizeof (bext)) ; | |
357 sf_close (file) ; | |
358 | |
359 if (got_bext == SF_FALSE) | |
360 { printf ("Error : File '%s' does not contain broadcast information.\n\n", filename) ; | |
361 return 1 ; | |
362 } ; | |
363 | |
364 /* | |
365 ** From : http://www.ebu.ch/en/technical/publications/userguides/bwf_user_guide.php | |
366 ** | |
367 ** Time Reference: | |
368 ** This field is a count from midnight in samples to the first sample | |
369 ** of the audio sequence. | |
370 */ | |
371 | |
372 time_ref_sec = ((pow (2.0, 32) * bext.time_reference_high) + (1.0 * bext.time_reference_low)) / sfinfo.samplerate ; | |
373 | |
374 printf ("Description : %.*s\n", (int) sizeof (bext.description), bext.description) ; | |
375 printf ("Originator : %.*s\n", (int) sizeof (bext.originator), bext.originator) ; | |
376 printf ("Origination ref : %.*s\n", (int) sizeof (bext.originator_reference), bext.originator_reference) ; | |
377 printf ("Origination date : %.*s\n", (int) sizeof (bext.origination_date), bext.origination_date) ; | |
378 printf ("Origination time : %.*s\n", (int) sizeof (bext.origination_time), bext.origination_time) ; | |
379 | |
380 if (bext.time_reference_high == 0 && bext.time_reference_low == 0) | |
381 printf ("Time ref : 0\n") ; | |
382 else | |
383 printf ("Time ref : 0x%x%08x (%.6f seconds)\n", bext.time_reference_high, bext.time_reference_low, time_ref_sec) ; | |
384 | |
385 printf ("BWF version : %d\n", bext.version) ; | |
386 printf ("UMID : %.*s\n", (int) sizeof (bext.umid), bext.umid) ; | |
387 printf ("Coding history : %.*s\n", bext.coding_history_size, bext.coding_history) ; | |
388 | |
389 return 0 ; | |
390 } /* broadcast_dump */ | |
391 | |
392 static int | |
393 chanmap_dump (const char *filename) | |
394 { SNDFILE *file ; | |
395 SF_INFO sfinfo ; | |
396 int * channel_map ; | |
397 int got_chanmap, k ; | |
398 | |
399 memset (&sfinfo, 0, sizeof (sfinfo)) ; | |
400 | |
401 if ((file = sf_open (filename, SFM_READ, &sfinfo)) == NULL) | |
402 { printf ("Error : Not able to open input file %s.\n", filename) ; | |
403 fflush (stdout) ; | |
404 memset (data, 0, sizeof (data)) ; | |
405 puts (sf_strerror (NULL)) ; | |
406 return 1 ; | |
407 } ; | |
408 | |
409 if ((channel_map = calloc (sfinfo.channels, sizeof (int))) == NULL) | |
410 { printf ("Error : malloc failed.\n\n") ; | |
411 return 1 ; | |
412 } ; | |
413 | |
414 got_chanmap = sf_command (file, SFC_GET_CHANNEL_MAP_INFO, channel_map, sfinfo.channels * sizeof (int)) ; | |
415 sf_close (file) ; | |
416 | |
417 if (got_chanmap == SF_FALSE) | |
418 { printf ("Error : File '%s' does not contain channel map information.\n\n", filename) ; | |
419 free (channel_map) ; | |
420 return 1 ; | |
421 } ; | |
422 | |
423 printf ("File : %s\n\n", filename) ; | |
424 | |
425 puts (" Chan Position") ; | |
426 for (k = 0 ; k < sfinfo.channels ; k ++) | |
427 { const char * name ; | |
428 | |
429 #define CASE_NAME(x) case x : name = #x ; break ; | |
430 switch (channel_map [k]) | |
431 { CASE_NAME (SF_CHANNEL_MAP_INVALID) ; | |
432 CASE_NAME (SF_CHANNEL_MAP_MONO) ; | |
433 CASE_NAME (SF_CHANNEL_MAP_LEFT) ; | |
434 CASE_NAME (SF_CHANNEL_MAP_RIGHT) ; | |
435 CASE_NAME (SF_CHANNEL_MAP_CENTER) ; | |
436 CASE_NAME (SF_CHANNEL_MAP_FRONT_LEFT) ; | |
437 CASE_NAME (SF_CHANNEL_MAP_FRONT_RIGHT) ; | |
438 CASE_NAME (SF_CHANNEL_MAP_FRONT_CENTER) ; | |
439 CASE_NAME (SF_CHANNEL_MAP_REAR_CENTER) ; | |
440 CASE_NAME (SF_CHANNEL_MAP_REAR_LEFT) ; | |
441 CASE_NAME (SF_CHANNEL_MAP_REAR_RIGHT) ; | |
442 CASE_NAME (SF_CHANNEL_MAP_LFE) ; | |
443 CASE_NAME (SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER) ; | |
444 CASE_NAME (SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER) ; | |
445 CASE_NAME (SF_CHANNEL_MAP_SIDE_LEFT) ; | |
446 CASE_NAME (SF_CHANNEL_MAP_SIDE_RIGHT) ; | |
447 CASE_NAME (SF_CHANNEL_MAP_TOP_CENTER) ; | |
448 CASE_NAME (SF_CHANNEL_MAP_TOP_FRONT_LEFT) ; | |
449 CASE_NAME (SF_CHANNEL_MAP_TOP_FRONT_RIGHT) ; | |
450 CASE_NAME (SF_CHANNEL_MAP_TOP_FRONT_CENTER) ; | |
451 CASE_NAME (SF_CHANNEL_MAP_TOP_REAR_LEFT) ; | |
452 CASE_NAME (SF_CHANNEL_MAP_TOP_REAR_RIGHT) ; | |
453 CASE_NAME (SF_CHANNEL_MAP_TOP_REAR_CENTER) ; | |
454 CASE_NAME (SF_CHANNEL_MAP_MAX) ; | |
455 default : name = "default" ; | |
456 break ; | |
457 } ; | |
458 | |
459 printf (" %3d %s\n", k, name) ; | |
460 } ; | |
461 | |
462 putchar ('\n') ; | |
463 free (channel_map) ; | |
464 | |
465 return 0 ; | |
466 } /* chanmap_dump */ | |
467 | |
468 static void | |
469 total_dump (void) | |
470 { printf ("========================================\n") ; | |
471 printf ("Total Duration : %s\n", format_duration_str (total_seconds)) ; | |
472 } /* total_dump */ |