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