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