1 /*
2 ** Copyright (C) 2001-2019 Erik de Castro Lopo <erikd@mega-nerd.com>
3 **
4 ** This program is free software; you can redistribute it and/or modify
5 ** it under the terms of the GNU General Public License as published by
6 ** the Free Software Foundation; either version 2 of the License, or
7 ** (at your option) any later version.
8 **
9 ** This program is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 ** GNU General Public License for more details.
13 **
14 ** You should have received a copy of the GNU General Public License
15 ** along with this program; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18 
19 #include "sfconfig.h"
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <inttypes.h>
25 #include <string.h>
26 #include <time.h>
27 
28 #if HAVE_UNISTD_H
29 #include <unistd.h>
30 #else
31 #include "sf_unistd.h"
32 #endif
33 
34 #include <math.h>
35 
36 #include <sndfile.h>
37 
38 #include "sfendian.h"
39 #include "utils.h"
40 
41 #define	BUFFER_LEN		(1 << 10)
42 #define LOG_BUFFER_SIZE	1024
43 #define data_MARKER		MAKE_MARKER ('d', 'a', 't', 'a')
44 
45 static	void	float_norm_test			(const char *filename) ;
46 static	void	double_norm_test		(const char *filename) ;
47 static	void	format_tests			(void) ;
48 static	void	calc_peak_test			(int filetype, const char *filename, int channels) ;
49 static	void	truncate_test			(const char *filename, int filetype) ;
50 static	void	instrument_test			(const char *filename, int filetype) ;
51 static	void	cue_test				(const char *filename, int filetype) ;
52 static	void	cue_test_var			(const char *filename, int filetype, int count) ;
53 static	void	channel_map_test		(const char *filename, int filetype) ;
54 static	void	current_sf_info_test	(const char *filename) ;
55 static	void	raw_needs_endswap_test	(const char *filename, int filetype) ;
56 
57 static	void	broadcast_test			(const char *filename, int filetype) ;
58 static	void	broadcast_rdwr_test		(const char *filename, int filetype) ;
59 static	void	broadcast_coding_history_test	(const char *filename) ;
60 static	void	broadcast_coding_history_size	(const char *filename) ;
61 
62 /* Cart Chunk tests */
63 static void	cart_test				(const char *filename, int filetype) ;
64 static void	cart_rdwr_test			(const char *filename, int filetype) ;
65 
66 /* Force the start of this buffer to be double aligned. Sparc-solaris will
67 ** choke if its not.
68 */
69 
70 static	int		int_data	[BUFFER_LEN] ;
71 static	float	float_data	[BUFFER_LEN] ;
72 static	double	double_data	[BUFFER_LEN] ;
73 
74 int
main(int argc,char * argv[])75 main (int argc, char *argv [])
76 {	int		do_all = 0 ;
77 	int		test_count = 0 ;
78 
79 	if (argc != 2)
80 	{	printf ("Usage : %s <test>\n", argv [0]) ;
81 		printf ("    Where <test> is one of the following:\n") ;
82 		printf ("           ver     - test sf_command (SFC_GETLIB_VERSION)\n") ;
83 		printf ("           norm    - test floating point normalisation\n") ;
84 		printf ("           format  - test format string commands\n") ;
85 		printf ("           peak    - test peak calculation\n") ;
86 		printf ("           trunc   - test file truncation\n") ;
87 		printf ("           inst    - test set/get of SF_INSTRUMENT.\n") ;
88 		printf ("           cue     - test set/get of SF_CUES.\n") ;
89 		printf ("           chanmap - test set/get of channel map data..\n") ;
90 		printf ("           bext    - test set/get of SF_BROADCAST_INFO.\n") ;
91 		printf ("           bextch  - test set/get of SF_BROADCAST_INFO coding_history.\n") ;
92 		printf ("           cart    - test set/get of SF_CART_INFO.\n") ;
93 		printf ("           rawend  - test SFC_RAW_NEEDS_ENDSWAP.\n") ;
94 		printf ("           all     - perform all tests\n") ;
95 		exit (1) ;
96 		} ;
97 
98 	do_all = ! strcmp (argv [1], "all") ;
99 
100 	if (do_all || strcmp (argv [1], "ver") == 0)
101 	{	char buffer [128] ;
102 
103 		print_test_name ("version_test", "(none)") ;
104 		buffer [0] = 0 ;
105 		sf_command (NULL, SFC_GET_LIB_VERSION, buffer, sizeof (buffer)) ;
106 		if (strlen (buffer) < 1)
107 		{	printf ("Line %d: could not retrieve lib version.\n", __LINE__) ;
108 			exit (1) ;
109 			} ;
110 		puts ("ok") ;
111 		test_count ++ ;
112 		} ;
113 
114 	if (do_all || strcmp (argv [1], "norm") == 0)
115 	{	/*	Preliminary float/double normalisation tests. More testing
116 		**	is done in the program 'floating_point_test'.
117 		*/
118 		float_norm_test		("float.wav") ;
119 		double_norm_test	("double.wav") ;
120 		test_count ++ ;
121 		} ;
122 
123 	if (do_all || strcmp (argv [1], "peak") == 0)
124 	{	calc_peak_test (SF_ENDIAN_BIG		| SF_FORMAT_RAW, "be-peak.raw", 1) ;
125 		calc_peak_test (SF_ENDIAN_LITTLE	| SF_FORMAT_RAW, "le-peak.raw", 1) ;
126 		calc_peak_test (SF_ENDIAN_BIG		| SF_FORMAT_RAW, "be-peak.raw", 7) ;
127 		calc_peak_test (SF_ENDIAN_LITTLE	| SF_FORMAT_RAW, "le-peak.raw", 7) ;
128 		test_count ++ ;
129 		} ;
130 
131 	if (do_all || ! strcmp (argv [1], "format"))
132 	{	format_tests () ;
133 		test_count ++ ;
134 		} ;
135 
136 	if (do_all || strcmp (argv [1], "trunc") == 0)
137 	{	truncate_test ("truncate.raw", SF_FORMAT_RAW | SF_FORMAT_PCM_32) ;
138 		truncate_test ("truncate.au" , SF_FORMAT_AU | SF_FORMAT_PCM_16) ;
139 		test_count ++ ;
140 		} ;
141 
142 	if (do_all || strcmp (argv [1], "inst") == 0)
143 	{	instrument_test ("instrument.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ;
144 		/*-instrument_test ("instrument.aiff" , SF_FORMAT_AIFF | SF_FORMAT_PCM_24) ;-*/
145 		/*-instrument_test ("instrument.xi", SF_FORMAT_XI | SF_FORMAT_DPCM_16) ;-*/
146 		test_count ++ ;
147 		} ;
148 
149 	if (do_all || strcmp (argv [1], "cue") == 0)
150 	{	/* 2500 is close to the largest number of cues possible because of block sizes (enforced in aiff.c, wav.c) */
151 		int cuecounts [] = { 0, 1, 10, 100, 101, 1000, 1001, 2500 } ;
152 		unsigned int i ;
153 
154 		cue_test ("cue.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ;
155 		cue_test ("cue.aiff" , SF_FORMAT_AIFF | SF_FORMAT_PCM_24) ;
156 
157 		for (i = 0 ; i < ARRAY_LEN (cuecounts) ; i++)
158 		{	cue_test_var ("cue.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16, cuecounts [i]) ;
159 			cue_test_var ("cue.aiff", SF_FORMAT_AIFF | SF_FORMAT_PCM_24, cuecounts [i]) ;
160 			} ;
161 
162 		test_count ++ ;
163 		} ;
164 
165 	if (do_all || strcmp (argv [1], "current_sf_info") == 0)
166 	{	current_sf_info_test ("current.wav") ;
167 		test_count ++ ;
168 		} ;
169 
170 	if (do_all || strcmp (argv [1], "bext") == 0)
171 	{	broadcast_test ("broadcast.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ;
172 		broadcast_rdwr_test	("broadcast.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ;
173 
174 		broadcast_test ("broadcast.wavex", SF_FORMAT_WAVEX | SF_FORMAT_PCM_16) ;
175 		broadcast_rdwr_test	("broadcast.wavex", SF_FORMAT_WAVEX | SF_FORMAT_PCM_16) ;
176 
177 		broadcast_test ("broadcast.rf64", SF_FORMAT_RF64 | SF_FORMAT_PCM_16) ;
178 		broadcast_rdwr_test	("broadcast.rf64", SF_FORMAT_RF64 | SF_FORMAT_PCM_16) ;
179 		test_count ++ ;
180 		} ;
181 
182 	if (do_all || strcmp (argv [1], "cart") == 0)
183 	{	cart_test ("cart.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ;
184 		cart_rdwr_test ("cart.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ;
185 		cart_test ("cart.rf64", SF_FORMAT_RF64 | SF_FORMAT_PCM_16) ;
186 		cart_rdwr_test ("cart.rf64", SF_FORMAT_RF64 | SF_FORMAT_PCM_16) ;
187 		test_count ++ ;
188 		} ;
189 
190 	if (do_all || strcmp (argv [1], "bextch") == 0)
191 	{	broadcast_coding_history_test ("coding_history.wav") ;
192 		broadcast_coding_history_size ("coding_hist_size.wav") ;
193 		test_count ++ ;
194 		} ;
195 
196 	if (do_all || strcmp (argv [1], "chanmap") == 0)
197 	{	channel_map_test ("chanmap.wavex", SF_FORMAT_WAVEX | SF_FORMAT_PCM_16) ;
198 		channel_map_test ("chanmap.rf64", SF_FORMAT_RF64 | SF_FORMAT_PCM_16) ;
199 		channel_map_test ("chanmap.aifc" , SF_FORMAT_AIFF | SF_FORMAT_PCM_16) ;
200 		channel_map_test ("chanmap.caf" , SF_FORMAT_CAF | SF_FORMAT_PCM_16) ;
201 		test_count ++ ;
202 		} ;
203 
204 	if (do_all || strcmp (argv [1], "rawend") == 0)
205 	{	raw_needs_endswap_test ("raw_end.wav", SF_FORMAT_WAV) ;
206 		raw_needs_endswap_test ("raw_end.wavex", SF_FORMAT_WAVEX) ;
207 		raw_needs_endswap_test ("raw_end.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV) ;
208 		raw_needs_endswap_test ("raw_end.aiff", SF_FORMAT_AIFF) ;
209 		raw_needs_endswap_test ("raw_end.aiff_le", SF_ENDIAN_LITTLE | SF_FORMAT_AIFF) ;
210 		test_count ++ ;
211 		} ;
212 
213 	if (test_count == 0)
214 	{	printf ("Mono : ************************************\n") ;
215 		printf ("Mono : *  No '%s' test defined.\n", argv [1]) ;
216 		printf ("Mono : ************************************\n") ;
217 		return 1 ;
218 		} ;
219 
220 	return 0 ;
221 } /* main */
222 
223 /*============================================================================================
224 **	Here are the test functions.
225 */
226 
227 static void
float_norm_test(const char * filename)228 float_norm_test (const char *filename)
229 {	SNDFILE			*file ;
230 	SF_INFO			sfinfo ;
231 	unsigned int	k ;
232 
233 	print_test_name ("float_norm_test", filename) ;
234 
235 	sfinfo.samplerate	= 44100 ;
236 	sfinfo.format		= (SF_FORMAT_RAW | SF_FORMAT_PCM_16) ;
237 	sfinfo.channels		= 1 ;
238 	sfinfo.frames		= BUFFER_LEN ;
239 
240 	/* Create float_data with all values being less than 1.0. */
241 	for (k = 0 ; k < BUFFER_LEN / 2 ; k++)
242 		float_data [k] = (k + 5) / (2.0 * BUFFER_LEN) ;
243 	for (k = BUFFER_LEN / 2 ; k < BUFFER_LEN ; k++)
244 		float_data [k] = (k + 5) ;
245 
246 	if (! (file = sf_open (filename, SFM_WRITE, &sfinfo)))
247 	{	printf ("Line %d: sf_open_write failed with error : ", __LINE__) ;
248 		fflush (stdout) ;
249 		puts (sf_strerror (NULL)) ;
250 		exit (1) ;
251 		} ;
252 
253 	/* Normalisation is on by default so no need to do anything here. */
254 
255 	if ((k = sf_write_float (file, float_data, BUFFER_LEN / 2)) != BUFFER_LEN / 2)
256 	{	printf ("Line %d: sf_write_float failed with short write (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ;
257 		exit (1) ;
258 		} ;
259 
260 	/* Turn normalisation off. */
261 	sf_command (file, SFC_SET_NORM_FLOAT, NULL, SF_FALSE) ;
262 
263 	if ((k = sf_write_float (file, float_data + BUFFER_LEN / 2, BUFFER_LEN / 2)) != BUFFER_LEN / 2)
264 	{	printf ("Line %d: sf_write_float failed with short write (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ;
265 		exit (1) ;
266 		} ;
267 
268 	sf_close (file) ;
269 
270 	/* sfinfo struct should still contain correct data. */
271 	if (! (file = sf_open (filename, SFM_READ, &sfinfo)))
272 	{	printf ("Line %d: sf_open_read failed with error : ", __LINE__) ;
273 		fflush (stdout) ;
274 		puts (sf_strerror (NULL)) ;
275 		exit (1) ;
276 		} ;
277 
278 	if (sfinfo.format != (SF_FORMAT_RAW | SF_FORMAT_PCM_16))
279 	{	printf ("Line %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, (SF_FORMAT_RAW | SF_FORMAT_PCM_16), sfinfo.format) ;
280 		exit (1) ;
281 		} ;
282 
283 	if (sfinfo.frames != BUFFER_LEN)
284 	{	printf ("\n\nLine %d: Incorrect number of.frames in file. (%d => %" PRId64 ")\n", __LINE__, BUFFER_LEN, sfinfo.frames) ;
285 		exit (1) ;
286 		} ;
287 
288 	if (sfinfo.channels != 1)
289 	{	printf ("Line %d: Incorrect number of channels in file.\n", __LINE__) ;
290 		exit (1) ;
291 		} ;
292 
293 	/* Read float_data and check that it is normalised (ie default). */
294 	if ((k = sf_read_float (file, float_data, BUFFER_LEN)) != BUFFER_LEN)
295 	{	printf ("\n\nLine %d: sf_read_float failed with short read (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ;
296 		exit (1) ;
297 		} ;
298 
299 	for (k = 0 ; k < BUFFER_LEN ; k++)
300 		if (float_data [k] >= 1.0)
301 		{	printf ("\n\nLine %d: float_data [%d] == %f which is greater than 1.0\n", __LINE__, k, float_data [k]) ;
302 			exit (1) ;
303 			} ;
304 
305 	/* Seek to start of file, turn normalisation off, read float_data and check again. */
306 	sf_seek (file, 0, SEEK_SET) ;
307 	sf_command (file, SFC_SET_NORM_FLOAT, NULL, SF_FALSE) ;
308 
309 	if ((k = sf_read_float (file, float_data, BUFFER_LEN)) != BUFFER_LEN)
310 	{	printf ("\n\nLine %d: sf_read_float failed with short read (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ;
311 		exit (1) ;
312 		} ;
313 
314 	for (k = 0 ; k < BUFFER_LEN ; k++)
315 		if (float_data [k] < 1.0)
316 		{	printf ("\n\nLine %d: float_data [%d] == %f which is less than 1.0\n", __LINE__, k, float_data [k]) ;
317 			exit (1) ;
318 			} ;
319 
320 	/* Seek to start of file, turn normalisation on, read float_data and do final check. */
321 	sf_seek (file, 0, SEEK_SET) ;
322 	sf_command (file, SFC_SET_NORM_FLOAT, NULL, SF_TRUE) ;
323 
324 	if ((k = sf_read_float (file, float_data, BUFFER_LEN)) != BUFFER_LEN)
325 	{	printf ("\n\nLine %d: sf_read_float failed with short read (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ;
326 		exit (1) ;
327 		} ;
328 
329 	for (k = 0 ; k < BUFFER_LEN ; k++)
330 		if (float_data [k] > 1.0)
331 		{	printf ("\n\nLine %d: float_data [%d] == %f which is greater than 1.0\n", __LINE__, k, float_data [k]) ;
332 			exit (1) ;
333 			} ;
334 
335 
336 	sf_close (file) ;
337 
338 	unlink (filename) ;
339 
340 	printf ("ok\n") ;
341 } /* float_norm_test */
342 
343 static void
double_norm_test(const char * filename)344 double_norm_test (const char *filename)
345 {	SNDFILE			*file ;
346 	SF_INFO			sfinfo ;
347 	unsigned int	k ;
348 
349 	print_test_name ("double_norm_test", filename) ;
350 
351 	sfinfo.samplerate	= 44100 ;
352 	sfinfo.format		= (SF_FORMAT_RAW | SF_FORMAT_PCM_16) ;
353 	sfinfo.channels		= 1 ;
354 	sfinfo.frames		= BUFFER_LEN ;
355 
356 	/* Create double_data with all values being less than 1.0. */
357 	for (k = 0 ; k < BUFFER_LEN / 2 ; k++)
358 		double_data [k] = (k + 5) / (2.0 * BUFFER_LEN) ;
359 	for (k = BUFFER_LEN / 2 ; k < BUFFER_LEN ; k++)
360 		double_data [k] = (k + 5) ;
361 
362 	if (! (file = sf_open (filename, SFM_WRITE, &sfinfo)))
363 	{	printf ("Line %d: sf_open_write failed with error : ", __LINE__) ;
364 		fflush (stdout) ;
365 		puts (sf_strerror (NULL)) ;
366 		exit (1) ;
367 		} ;
368 
369 	/* Normailsation is on by default so no need to do anything here. */
370 	/*-sf_command (file, "set-norm-double", "true", 0) ;-*/
371 
372 	if ((k = sf_write_double (file, double_data, BUFFER_LEN / 2)) != BUFFER_LEN / 2)
373 	{	printf ("Line %d: sf_write_double failed with short write (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ;
374 		exit (1) ;
375 		} ;
376 
377 	/* Turn normalisation off. */
378 	sf_command (file, SFC_SET_NORM_DOUBLE, NULL, SF_FALSE) ;
379 
380 	if ((k = sf_write_double (file, double_data + BUFFER_LEN / 2, BUFFER_LEN / 2)) != BUFFER_LEN / 2)
381 	{	printf ("Line %d: sf_write_double failed with short write (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ;
382 		exit (1) ;
383 		} ;
384 
385 	sf_close (file) ;
386 
387 	if (! (file = sf_open (filename, SFM_READ, &sfinfo)))
388 	{	printf ("Line %d: sf_open_read failed with error : ", __LINE__) ;
389 		fflush (stdout) ;
390 		puts (sf_strerror (NULL)) ;
391 		exit (1) ;
392 		} ;
393 
394 	if (sfinfo.format != (SF_FORMAT_RAW | SF_FORMAT_PCM_16))
395 	{	printf ("Line %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, (SF_FORMAT_RAW | SF_FORMAT_PCM_16), sfinfo.format) ;
396 		exit (1) ;
397 		} ;
398 
399 	if (sfinfo.frames != BUFFER_LEN)
400 	{	printf ("\n\nLine %d: Incorrect number of.frames in file. (%d => %" PRId64 ")\n", __LINE__, BUFFER_LEN, sfinfo.frames) ;
401 		exit (1) ;
402 		} ;
403 
404 	if (sfinfo.channels != 1)
405 	{	printf ("Line %d: Incorrect number of channels in file.\n", __LINE__) ;
406 		exit (1) ;
407 		} ;
408 
409 	/* Read double_data and check that it is normalised (ie default). */
410 	if ((k = sf_read_double (file, double_data, BUFFER_LEN)) != BUFFER_LEN)
411 	{	printf ("\n\nLine %d: sf_read_double failed with short read (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ;
412 		exit (1) ;
413 		} ;
414 
415 	for (k = 0 ; k < BUFFER_LEN ; k++)
416 		if (double_data [k] >= 1.0)
417 		{	printf ("\n\nLine %d: double_data [%d] == %f which is greater than 1.0\n", __LINE__, k, double_data [k]) ;
418 			exit (1) ;
419 			} ;
420 
421 	/* Seek to start of file, turn normalisation off, read double_data and check again. */
422 	sf_seek (file, 0, SEEK_SET) ;
423 	sf_command (file, SFC_SET_NORM_DOUBLE, NULL, SF_FALSE) ;
424 
425 	if ((k = sf_read_double (file, double_data, BUFFER_LEN)) != BUFFER_LEN)
426 	{	printf ("\n\nLine %d: sf_read_double failed with short read (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ;
427 		exit (1) ;
428 		} ;
429 
430 	for (k = 0 ; k < BUFFER_LEN ; k++)
431 		if (double_data [k] < 1.0)
432 		{	printf ("\n\nLine %d: double_data [%d] == %f which is less than 1.0\n", __LINE__, k, double_data [k]) ;
433 			exit (1) ;
434 			} ;
435 
436 	/* Seek to start of file, turn normalisation on, read double_data and do final check. */
437 	sf_seek (file, 0, SEEK_SET) ;
438 	sf_command (file, SFC_SET_NORM_DOUBLE, NULL, SF_TRUE) ;
439 
440 	if ((k = sf_read_double (file, double_data, BUFFER_LEN)) != BUFFER_LEN)
441 	{	printf ("\n\nLine %d: sf_read_double failed with short read (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ;
442 		exit (1) ;
443 		} ;
444 
445 	for (k = 0 ; k < BUFFER_LEN ; k++)
446 		if (double_data [k] > 1.0)
447 		{	printf ("\n\nLine %d: double_data [%d] == %f which is greater than 1.0\n", __LINE__, k, double_data [k]) ;
448 			exit (1) ;
449 			} ;
450 
451 
452 	sf_close (file) ;
453 
454 	unlink (filename) ;
455 
456 	printf ("ok\n") ;
457 } /* double_norm_test */
458 
459 static	void
format_tests(void)460 format_tests	(void)
461 {	SF_FORMAT_INFO format_info ;
462 	SF_INFO		sfinfo ;
463 	const char	*last_name ;
464 	int 		k, count ;
465 
466 	print_test_name ("format_tests", "(null)") ;
467 
468 	/* Clear out SF_INFO struct and set channels > 0. */
469 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
470 	sfinfo.channels = 1 ;
471 
472 	/* First test simple formats. */
473 
474 	sf_command (NULL, SFC_GET_SIMPLE_FORMAT_COUNT, &count, sizeof (int)) ;
475 
476 	if (count < 0 || count > 30)
477 	{	printf ("Line %d: Weird count.\n", __LINE__) ;
478 		exit (1) ;
479 		} ;
480 
481 	format_info.format = 0 ;
482 	sf_command (NULL, SFC_GET_SIMPLE_FORMAT, &format_info, sizeof (format_info)) ;
483 
484 	last_name = format_info.name ;
485 	for (k = 1 ; k < count ; k ++)
486 	{	format_info.format = k ;
487 		sf_command (NULL, SFC_GET_SIMPLE_FORMAT, &format_info, sizeof (format_info)) ;
488 		if (strcmp (last_name, format_info.name) >= 0)
489 		{	printf ("\n\nLine %d: format names out of sequence `%s' < `%s'.\n", __LINE__, last_name, format_info.name) ;
490 			exit (1) ;
491 			} ;
492 		sfinfo.format = format_info.format ;
493 
494 		if (! sf_format_check (&sfinfo))
495 		{	printf ("\n\nLine %d: sf_format_check failed.\n", __LINE__) ;
496 			printf ("        Name : %s\n", format_info.name) ;
497 			printf ("        Format      : 0x%X\n", sfinfo.format) ;
498 			printf ("        Channels    : 0x%X\n", sfinfo.channels) ;
499 			printf ("        Sample Rate : 0x%X\n", sfinfo.samplerate) ;
500 			exit (1) ;
501 			} ;
502 		last_name = format_info.name ;
503 		} ;
504 	format_info.format = 666 ;
505 	sf_command (NULL, SFC_GET_SIMPLE_FORMAT, &format_info, sizeof (format_info)) ;
506 
507 	/* Now test major formats. */
508 	sf_command (NULL, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof (int)) ;
509 
510 	if (count < 0 || count > 30)
511 	{	printf ("Line %d: Weird count.\n", __LINE__) ;
512 		exit (1) ;
513 		} ;
514 
515 	format_info.format = 0 ;
516 	sf_command (NULL, SFC_GET_FORMAT_MAJOR, &format_info, sizeof (format_info)) ;
517 
518 	last_name = format_info.name ;
519 	for (k = 1 ; k < count ; k ++)
520 	{	format_info.format = k ;
521 		sf_command (NULL, SFC_GET_FORMAT_MAJOR, &format_info, sizeof (format_info)) ;
522 		if (strcmp (last_name, format_info.name) >= 0)
523 		{	printf ("\n\nLine %d: format names out of sequence (%d) `%s' < `%s'.\n", __LINE__, k, last_name, format_info.name) ;
524 			exit (1) ;
525 			} ;
526 
527 		last_name = format_info.name ;
528 		} ;
529 	format_info.format = 666 ;
530 	sf_command (NULL, SFC_GET_FORMAT_MAJOR, &format_info, sizeof (format_info)) ;
531 
532 	/* Now test subtype formats. */
533 	sf_command (NULL, SFC_GET_FORMAT_SUBTYPE_COUNT, &count, sizeof (int)) ;
534 
535 	if (count < 0 || count > 30)
536 	{	printf ("Line %d: Weird count.\n", __LINE__) ;
537 		exit (1) ;
538 		} ;
539 
540 	format_info.format = 0 ;
541 	sf_command (NULL, SFC_GET_FORMAT_SUBTYPE, &format_info, sizeof (format_info)) ;
542 
543 	last_name = format_info.name ;
544 	for (k = 1 ; k < count ; k ++)
545 	{	format_info.format = k ;
546 		sf_command (NULL, SFC_GET_FORMAT_SUBTYPE, &format_info, sizeof (format_info)) ;
547 		} ;
548 	format_info.format = 666 ;
549 	sf_command (NULL, SFC_GET_FORMAT_SUBTYPE, &format_info, sizeof (format_info)) ;
550 
551 
552 	printf ("ok\n") ;
553 } /* format_tests */
554 
555 static	void
calc_peak_test(int filetype,const char * filename,int channels)556 calc_peak_test (int filetype, const char *filename, int channels)
557 {	SNDFILE		*file ;
558 	SF_INFO		sfinfo ;
559 	char		label [128] ;
560 	int			k, format ;
561 	sf_count_t	buffer_len, frame_count ;
562 	double		peak ;
563 
564 	snprintf (label, sizeof (label), "calc_peak_test (%d channels)", channels) ;
565 	print_test_name (label, filename) ;
566 
567 	format = filetype | SF_FORMAT_PCM_16 ;
568 
569 	buffer_len = BUFFER_LEN - (BUFFER_LEN % channels) ;
570 	frame_count = buffer_len / channels ;
571 
572 	sfinfo.samplerate	= 44100 ;
573 	sfinfo.format		= format ;
574 	sfinfo.channels		= channels ;
575 	sfinfo.frames		= frame_count ;
576 
577 	/* Create double_data with max value of 0.5. */
578 	for (k = 0 ; k < buffer_len ; k++)
579 		double_data [k] = (k + 1) / (2.0 * buffer_len) ;
580 
581 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
582 
583 	test_writef_double_or_die (file, 0, double_data, frame_count, __LINE__) ;
584 
585 	sf_close (file) ;
586 
587 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
588 
589 	if (sfinfo.format != format)
590 	{	printf ("Line %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, format, sfinfo.format) ;
591 		exit (1) ;
592 		} ;
593 
594 	if (sfinfo.frames != frame_count)
595 	{	printf ("\n\nLine %d: Incorrect number of frames in file. (%" PRId64 " => %" PRId64 ")\n", __LINE__, frame_count, sfinfo.frames) ;
596 		exit (1) ;
597 		} ;
598 
599 	if (sfinfo.channels != channels)
600 	{	printf ("Line %d: Incorrect number of channels in file.\n", __LINE__) ;
601 		exit (1) ;
602 		} ;
603 
604 	sf_command (file, SFC_CALC_SIGNAL_MAX, &peak, sizeof (peak)) ;
605 	if (fabs (peak - (1 << 14)) > 1.0)
606 	{	printf ("Line %d : Peak value should be %d (is %f).\n", __LINE__, (1 << 14), peak) ;
607 		exit (1) ;
608 		} ;
609 
610 	sf_command (file, SFC_CALC_NORM_SIGNAL_MAX, &peak, sizeof (peak)) ;
611 	if (fabs (peak - 0.5) > 4e-5)
612 	{	printf ("Line %d : Peak value should be %f (is %f).\n", __LINE__, 0.5, peak) ;
613 		exit (1) ;
614 		} ;
615 
616 	sf_close (file) ;
617 
618 	format = (filetype | SF_FORMAT_FLOAT) ;
619 	sfinfo.samplerate	= 44100 ;
620 	sfinfo.format		= format ;
621 	sfinfo.channels		= channels ;
622 	sfinfo.frames		= frame_count ;
623 
624 	/* Create double_data with max value of 0.5. */
625 	for (k = 0 ; k < buffer_len ; k++)
626 		double_data [k] = (k + 1) / (2.0 * buffer_len) ;
627 
628 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
629 
630 	test_writef_double_or_die (file, 0, double_data, frame_count, __LINE__) ;
631 
632 	sf_close (file) ;
633 
634 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
635 
636 	if (sfinfo.format != format)
637 	{	printf ("Line %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, format, sfinfo.format) ;
638 		exit (1) ;
639 		} ;
640 
641 	if (sfinfo.frames != frame_count)
642 	{	printf ("\n\nLine %d: Incorrect number of.frames in file. (%" PRId64 " => %" PRId64 ")\n", __LINE__, frame_count, sfinfo.frames) ;
643 		exit (1) ;
644 		} ;
645 
646 	if (sfinfo.channels != channels)
647 	{	printf ("Line %d: Incorrect number of channels in file.\n", __LINE__) ;
648 		exit (1) ;
649 		} ;
650 
651 	sf_command (file, SFC_CALC_SIGNAL_MAX, &peak, sizeof (peak)) ;
652 	if (fabs (peak - 0.5) > 1e-5)
653 	{	printf ("Line %d : Peak value should be %f (is %f).\n", __LINE__, 0.5, peak) ;
654 		exit (1) ;
655 		} ;
656 
657 	sf_command (file, SFC_CALC_NORM_SIGNAL_MAX, &peak, sizeof (peak)) ;
658 	if (fabs (peak - 0.5) > 1e-5)
659 	{	printf ("Line %d : Peak value should be %f (is %f).\n", __LINE__, 0.5, peak) ;
660 		exit (1) ;
661 		} ;
662 
663 	sf_close (file) ;
664 
665 	unlink (filename) ;
666 
667 	printf ("ok\n") ;
668 } /* calc_peak_test */
669 
670 static void
truncate_test(const char * filename,int filetype)671 truncate_test (const char *filename, int filetype)
672 {	SNDFILE 	*file ;
673 	SF_INFO		sfinfo ;
674 	sf_count_t	len ;
675 
676 	print_test_name ("truncate_test", filename) ;
677 
678 	sfinfo.samplerate	= 11025 ;
679 	sfinfo.format		= filetype ;
680 	sfinfo.channels		= 2 ;
681 
682 	file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_TRUE, __LINE__) ;
683 
684 	test_write_int_or_die (file, 0, int_data, BUFFER_LEN, __LINE__) ;
685 
686 	len = 100 ;
687 	if (sf_command (file, SFC_FILE_TRUNCATE, &len, sizeof (len)))
688 	{	printf ("Line %d: sf_command (SFC_FILE_TRUNCATE) returned error.\n", __LINE__) ;
689 		exit (1) ;
690 		} ;
691 
692 	test_seek_or_die (file, 0, SEEK_CUR, len, 2, __LINE__) ;
693 	test_seek_or_die (file, 0, SEEK_END, len, 2, __LINE__) ;
694 
695 	sf_close (file) ;
696 
697 	unlink (filename) ;
698 	puts ("ok") ;
699 } /* truncate_test */
700 
701 /*------------------------------------------------------------------------------
702 */
703 
704 static void
instrumet_rw_test(const char * filename)705 instrumet_rw_test (const char *filename)
706 {	SNDFILE *sndfile ;
707 	SF_INFO sfinfo ;
708 	SF_INSTRUMENT inst ;
709 	memset (&sfinfo, 0, sizeof (SF_INFO)) ;
710 
711 	sndfile = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_FALSE, __LINE__) ;
712 
713 	if (sf_command (sndfile, SFC_GET_INSTRUMENT, &inst, sizeof (inst)) == SF_TRUE)
714 	{	inst.basenote = 22 ;
715 
716 		if (sf_command (sndfile, SFC_SET_INSTRUMENT, &inst, sizeof (inst)) == SF_TRUE)
717 			printf ("Sucess: [%s] updated\n", filename) ;
718 		else
719 			printf ("Error: SFC_SET_INSTRUMENT on [%s] [%s]\n", filename, sf_strerror (sndfile)) ;
720 		}
721 	else
722 		printf ("Error: SFC_GET_INSTRUMENT on [%s] [%s]\n", filename, sf_strerror (sndfile)) ;
723 
724 
725 	if (sf_command (sndfile, SFC_UPDATE_HEADER_NOW, NULL, 0) != 0)
726 		printf ("Error: SFC_UPDATE_HEADER_NOW on [%s] [%s]\n", filename, sf_strerror (sndfile)) ;
727 
728 	sf_write_sync (sndfile) ;
729 	sf_close (sndfile) ;
730 
731 	return ;
732 } /* instrumet_rw_test */
733 
734 static void
instrument_test(const char * filename,int filetype)735 instrument_test (const char *filename, int filetype)
736 {	static SF_INSTRUMENT write_inst =
737 	{	2,		/* gain */
738 		3, 		/* detune */
739 		4, 		/* basenote */
740 		5, 6,	/* key low and high */
741 		7, 8,	/* velocity low and high */
742 		2,		/* loop_count */
743 		{	{	801, 2, 3, 0 },
744 			{	801, 3, 4, 0 },
745 		}
746 	} ;
747 	SF_INSTRUMENT read_inst ;
748 	SNDFILE	*file ;
749 	SF_INFO	sfinfo ;
750 
751 	print_test_name ("instrument_test", filename) ;
752 
753 	sfinfo.samplerate	= 11025 ;
754 	sfinfo.format		= filetype ;
755 	sfinfo.channels		= 1 ;
756 
757 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
758 	if (sf_command (file, SFC_SET_INSTRUMENT, &write_inst, sizeof (write_inst)) == SF_FALSE)
759 	{	printf ("\n\nLine %d : sf_command (SFC_SET_INSTRUMENT) failed.\n\n", __LINE__) ;
760 		exit (1) ;
761 		} ;
762 	test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ;
763 	sf_close (file) ;
764 
765 	memset (&read_inst, 0, sizeof (read_inst)) ;
766 
767 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
768 	if (sf_command (file, SFC_GET_INSTRUMENT, &read_inst, sizeof (read_inst)) == SF_FALSE)
769 	{	printf ("\n\nLine %d : sf_command (SFC_GET_INSTRUMENT) failed.\n\n", __LINE__) ;
770 		exit (1) ;
771 		return ;
772 		} ;
773 	check_log_buffer_or_die (file, __LINE__) ;
774 	sf_close (file) ;
775 
776 	if ((filetype & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV)
777 	{	/*
778 		**	For all the fields that WAV doesn't support, modify the
779 		**	write_inst struct to hold the default value that the WAV
780 		**	module should hold.
781 		*/
782 		write_inst.key_lo = write_inst.velocity_lo = 0 ;
783 		write_inst.key_hi = write_inst.velocity_hi = 127 ;
784 		write_inst.gain = 1 ;
785 		} ;
786 
787 	if ((filetype & SF_FORMAT_TYPEMASK) == SF_FORMAT_XI)
788 	{	/*
789 		**	For all the fields that XI doesn't support, modify the
790 		**	write_inst struct to hold the default value that the XI
791 		**	module should hold.
792 		*/
793 		write_inst.basenote = 0 ;
794 		write_inst.detune = 0 ;
795 		write_inst.key_lo = write_inst.velocity_lo = 0 ;
796 		write_inst.key_hi = write_inst.velocity_hi = 127 ;
797 		write_inst.gain = 1 ;
798 		} ;
799 
800 	if (memcmp (&write_inst, &read_inst, sizeof (write_inst)) != 0)
801 	{	printf ("\n\nLine %d : instrument comparison failed.\n\n", __LINE__) ;
802 		printf ("W  Base Note : %u\n"
803 			"   Detune    : %u\n"
804 			"   Low  Note : %u\tHigh Note : %u\n"
805 			"   Low  Vel. : %u\tHigh Vel. : %u\n"
806 			"   Gain      : %d\tCount     : %d\n"
807 			"   mode      : %d\n"
808 			"   start     : %d\tend       : %d\tcount  :%d\n"
809 			"   mode      : %d\n"
810 			"   start     : %d\tend       : %d\tcount  :%d\n\n",
811 			write_inst.basenote,
812 			write_inst.detune,
813 			write_inst.key_lo, write_inst.key_hi,
814 			write_inst.velocity_lo, write_inst.velocity_hi,
815 			write_inst.gain, write_inst.loop_count,
816 			write_inst.loops [0].mode, write_inst.loops [0].start,
817 			write_inst.loops [0].end, write_inst.loops [0].count,
818 			write_inst.loops [1].mode, write_inst.loops [1].start,
819 			write_inst.loops [1].end, write_inst.loops [1].count) ;
820 		printf ("R  Base Note : %u\n"
821 			"   Detune    : %u\n"
822 			"   Low  Note : %u\tHigh Note : %u\n"
823 			"   Low  Vel. : %u\tHigh Vel. : %u\n"
824 			"   Gain      : %d\tCount     : %d\n"
825 			"   mode      : %d\n"
826 			"   start     : %d\tend       : %d\tcount  :%d\n"
827 			"   mode      : %d\n"
828 			"   start     : %d\tend       : %d\tcount  :%d\n\n",
829 			read_inst.basenote,
830 			read_inst.detune,
831 			read_inst.key_lo, read_inst.key_hi,
832 			read_inst.velocity_lo, read_inst.velocity_hi,
833 			read_inst.gain,	read_inst.loop_count,
834 			read_inst.loops [0].mode, read_inst.loops [0].start,
835 			read_inst.loops [0].end, read_inst.loops [0].count,
836 			read_inst.loops [1].mode, read_inst.loops [1].start,
837 			read_inst.loops [1].end, read_inst.loops [1].count) ;
838 
839 		if ((filetype & SF_FORMAT_TYPEMASK) != SF_FORMAT_XI)
840 			exit (1) ;
841 		} ;
842 
843 	if (0) instrumet_rw_test (filename) ;
844 
845 	unlink (filename) ;
846 	puts ("ok") ;
847 } /* instrument_test */
848 
849 static void
print_cue(SF_CUES * cue,int i)850 print_cue (SF_CUES *cue, int i)
851 {
852 	printf ("   indx[%d]       : %d\n"
853 		"   position      : %u\n"
854 		"   fcc_chunk     : %x\n"
855 		"   chunk_start   : %d\n"
856 		"   block_start   : %d\n"
857 		"   sample_offset : %u\n"
858 		"   name          : %s\n",
859 		i,
860 		cue->cue_points [i].indx,
861 		cue->cue_points [i].position,
862 		cue->cue_points [i].fcc_chunk,
863 		cue->cue_points [i].chunk_start,
864 		cue->cue_points [i].block_start,
865 		cue->cue_points [i].sample_offset,
866 		cue->cue_points [i].name) ;
867 }
868 
869 static int
cue_compare(SF_CUES * write_cue,SF_CUES * read_cue,size_t cue_size,int line)870 cue_compare (SF_CUES *write_cue, SF_CUES *read_cue, size_t cue_size, int line)
871 {
872 	if (memcmp (write_cue, read_cue, cue_size) != 0)
873 	{
874 		printf ("\n\nLine %d : cue comparison failed.\n\n", line) ;
875 		printf ("W  Cue count     : %d\n", write_cue->cue_count) ;
876 		if (write_cue->cue_count > 0)
877 			print_cue (write_cue, 0) ;
878 		if (write_cue->cue_count > 2)	/* print last if at least 2 */
879 			print_cue (write_cue, write_cue->cue_count - 1) ;
880 
881 		printf ("R  Cue count     : %d\n", read_cue->cue_count) ;
882 		if (read_cue->cue_count > 0)
883 			print_cue (read_cue, 0) ;
884 		if (read_cue->cue_count > 2)	/* print last if at least 2 */
885 			print_cue (read_cue, read_cue->cue_count - 1) ;
886 
887 		return SF_FALSE ;
888 		} ;
889 
890 	return SF_TRUE ;
891 } /* cue_compare */
892 
893 static void
cue_rw_test(const char * filename)894 cue_rw_test (const char *filename)
895 {	SNDFILE *sndfile ;
896 	SF_INFO sfinfo ;
897 	SF_CUES cues ;
898 	memset (&sfinfo, 0, sizeof (SF_INFO)) ;
899 
900 	sndfile = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_FALSE, __LINE__) ;
901 
902 	exit_if_true (
903 		sf_command (sndfile, SFC_GET_CUE_COUNT, &cues.cue_count, sizeof (cues.cue_count)) != SF_TRUE,
904 		"\nLine %d: SFC_GET_CUE_COUNT command failed.\n\n", __LINE__
905 		) ;
906 
907 	exit_if_true (
908 		cues.cue_count != 3,
909 		"\nLine %d: Expected cue_count (%u) to be 3.\n\n", __LINE__, cues.cue_count
910 		) ;
911 
912 	if (sf_command (sndfile, SFC_GET_CUE, &cues, sizeof (cues)) == SF_TRUE)
913 	{	cues.cue_points [1].sample_offset = 3 ;
914 
915 		if (sf_command (sndfile, SFC_SET_CUE, &cues, sizeof (cues)) == SF_TRUE)
916 			printf ("Sucess: [%s] updated\n", filename) ;
917 		else
918 			printf ("Error: SFC_SET_CUE on [%s] [%s]\n", filename, sf_strerror (sndfile)) ;
919 		}
920 	else
921 		printf ("Error: SFC_GET_CUE on [%s] [%s]\n", filename, sf_strerror (sndfile)) ;
922 
923 
924 	if (sf_command (sndfile, SFC_UPDATE_HEADER_NOW, NULL, 0) != 0)
925 		printf ("Error: SFC_UPDATE_HEADER_NOW on [%s] [%s]\n", filename, sf_strerror (sndfile)) ;
926 
927 	sf_write_sync (sndfile) ;
928 	sf_close (sndfile) ;
929 
930 	return ;
931 } /* cue_rw_test */
932 
933 static void
cue_test(const char * filename,int filetype)934 cue_test (const char *filename, int filetype)
935 {	SF_CUES write_cue ;
936 	SF_CUES read_cue ;
937 	SNDFILE	*file ;
938 	SF_INFO	sfinfo ;
939 
940 	if (filetype == (SF_FORMAT_WAV | SF_FORMAT_PCM_16))
941 	{	write_cue = (SF_CUES)
942 		{	2,		/* cue_count */
943 			{	{	1, 0, data_MARKER, 0, 0, 1, "" },
944 				{	2, 0, data_MARKER, 0, 0, 2, "" },
945 			}
946 		} ;
947 	}
948 	else
949 	{	write_cue = (SF_CUES)
950 		{	2,		/* cue_count */
951 			{	{	1, 0, data_MARKER, 0, 0, 1, "Cue1" },
952 				{	2, 0, data_MARKER, 0, 0, 2, "Cue2" },
953 			}
954 		} ;
955 	}
956 
957 	print_test_name ("cue_test", filename) ;
958 
959 	sfinfo.samplerate	= 11025 ;
960 	sfinfo.format		= filetype ;
961 	sfinfo.channels		= 1 ;
962 
963 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
964 	if (sf_command (file, SFC_SET_CUE, &write_cue, sizeof (write_cue)) == SF_FALSE)
965 	{	printf ("\n\nLine %d : sf_command (SFC_SET_CUE) failed.\n\n", __LINE__) ;
966 		exit (1) ;
967 		} ;
968 	test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ;
969 	sf_close (file) ;
970 
971 	memset (&read_cue, 0, sizeof (read_cue)) ;
972 
973 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
974 	if (sf_command (file, SFC_GET_CUE, &read_cue, sizeof (read_cue)) == SF_FALSE)
975 	{	printf ("\n\nLine %d : sf_command (SFC_GET_CUE) failed.\n\n", __LINE__) ;
976 		exit (1) ;
977 		return ;
978 		} ;
979 	check_log_buffer_or_die (file, __LINE__) ;
980 	sf_close (file) ;
981 
982 	if (cue_compare (&write_cue, &read_cue, sizeof (write_cue), __LINE__) == SF_FALSE)
983 			exit (1) ;
984 
985 	if (0) cue_rw_test (filename) ;
986 
987 	unlink (filename) ;
988 	puts ("ok") ;
989 } /* cue_test */
990 
991 /* calculate size of SF_CUES struct given number of cues */
992 #define SF_CUES_SIZE(count)	(sizeof (uint32_t) + sizeof (SF_CUE_POINT) * (count))
993 
994 static void
cue_test_var(const char * filename,int filetype,int count)995 cue_test_var (const char *filename, int filetype, int count)
996 {	size_t cues_size = SF_CUES_SIZE (count) ;
997 	SF_CUES *write_cue = calloc (1, cues_size) ;
998 	SF_CUES *read_cue = calloc (1, cues_size) ;
999 	SNDFILE	*file ;
1000 	SF_INFO	sfinfo ;
1001 	char name [40] ;
1002 	int i ;
1003 
1004 	snprintf (name, sizeof (name), "cue_test_var %d", count) ;
1005 	print_test_name (name, filename) ;
1006 
1007 	if (write_cue == NULL || read_cue == NULL)
1008 	{	printf ("ok (can't alloc)\n") ;
1009 		return ;
1010 		} ;
1011 
1012 	write_cue->cue_count = count ;
1013 	for (i = 0 ; i < count ; i++)
1014 	{	write_cue->cue_points [i] = (SF_CUE_POINT) { i, 0, data_MARKER, 0, 0, i, "" } ;
1015 		if (filetype == (SF_FORMAT_AIFF | SF_FORMAT_PCM_24))
1016 			snprintf (write_cue->cue_points [i].name, sizeof (write_cue->cue_points [i].name), "Cue%03d", i) ;
1017 		} ;
1018 
1019 	sfinfo.samplerate	= 11025 ;
1020 	sfinfo.format		= filetype ;
1021 	sfinfo.channels		= 1 ;
1022 
1023 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
1024 	if (sf_command (file, SFC_SET_CUE, write_cue, cues_size) == SF_FALSE)
1025 	{	printf ("\n\nLine %d : sf_command (SFC_SET_CUE) failed with %d cues, datasize %zu --> error: %s\n\n", __LINE__, count, cues_size, sf_strerror (file)) ;
1026 		exit (1) ;
1027 		} ;
1028 	test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ;
1029 	sf_close (file) ;
1030 
1031 	memset (read_cue, 0, cues_size) ;
1032 
1033 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
1034 
1035 	if (sf_command (file, SFC_GET_CUE, read_cue, cues_size) == SF_FALSE)
1036 	{	printf ("\n\nLine %d : sf_command (SFC_GET_CUE) failed with %d cues, datasize %zu --> error: %s\n\n", __LINE__, count, cues_size, sf_strerror (file)) ;
1037 		exit (1) ;
1038 		} ;
1039 	check_log_buffer_or_die (file, __LINE__) ;
1040 	sf_close (file) ;
1041 
1042 	if (cue_compare (write_cue, read_cue, cues_size, __LINE__) == SF_FALSE)
1043 	{	printf ("\n\nLine %d : cue_compare failed.\n\n", __LINE__) ;
1044 		exit (1) ;
1045 		} ;
1046 
1047 	free (write_cue) ;
1048 	free (read_cue) ;
1049 	unlink (filename) ;
1050 	puts ("ok") ;
1051 } /* cue_test_var */
1052 
1053 static	void
current_sf_info_test(const char * filename)1054 current_sf_info_test	(const char *filename)
1055 {	SNDFILE *outfile, *infile ;
1056 	SF_INFO outinfo, ininfo ;
1057 
1058 	print_test_name ("current_sf_info_test", filename) ;
1059 
1060 	outinfo.samplerate	= 44100 ;
1061 	outinfo.format		= (SF_FORMAT_WAV | SF_FORMAT_PCM_16) ;
1062 	outinfo.channels	= 1 ;
1063 	outinfo.frames		= 0 ;
1064 
1065 	outfile = test_open_file_or_die (filename, SFM_WRITE, &outinfo, SF_TRUE, __LINE__) ;
1066 	sf_command (outfile, SFC_SET_UPDATE_HEADER_AUTO, NULL, 0) ;
1067 
1068 	exit_if_true (outinfo.frames != 0,
1069 		"\n\nLine %d : Initial sfinfo.frames is not zero.\n\n", __LINE__
1070 		) ;
1071 
1072 	test_write_double_or_die (outfile, 0, double_data, BUFFER_LEN, __LINE__) ;
1073 	sf_command (outfile, SFC_GET_CURRENT_SF_INFO, &outinfo, sizeof (outinfo)) ;
1074 
1075 	exit_if_true (outinfo.frames != BUFFER_LEN,
1076 		"\n\nLine %d : Initial sfinfo.frames (%" PRId64 ") should be %d.\n\n", __LINE__,
1077 		outinfo.frames, BUFFER_LEN
1078 		) ;
1079 
1080 	/* Read file making sure no channel map exists. */
1081 	memset (&ininfo, 0, sizeof (ininfo)) ;
1082 	infile = test_open_file_or_die (filename, SFM_READ, &ininfo, SF_TRUE, __LINE__) ;
1083 
1084 	test_write_double_or_die (outfile, 0, double_data, BUFFER_LEN, __LINE__) ;
1085 
1086 	sf_command (infile, SFC_GET_CURRENT_SF_INFO, &ininfo, sizeof (ininfo)) ;
1087 
1088 	exit_if_true (ininfo.frames != BUFFER_LEN,
1089 		"\n\nLine %d : Initial sfinfo.frames (%" PRId64 ") should be %d.\n\n", __LINE__,
1090 		ininfo.frames, BUFFER_LEN
1091 		) ;
1092 
1093 	sf_close (outfile) ;
1094 	sf_close (infile) ;
1095 
1096 	unlink (filename) ;
1097 	puts ("ok") ;
1098 } /* current_sf_info_test */
1099 
1100 static void
broadcast_test(const char * filename,int filetype)1101 broadcast_test (const char *filename, int filetype)
1102 {	static SF_BROADCAST_INFO bc_write, bc_read ;
1103 	SNDFILE	*file ;
1104 	SF_INFO	sfinfo ;
1105 	int errors = 0 ;
1106 
1107 	print_test_name ("broadcast_test", filename) ;
1108 
1109 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
1110 	sfinfo.samplerate	= 11025 ;
1111 	sfinfo.format		= filetype ;
1112 	sfinfo.channels		= 1 ;
1113 
1114 	memset (&bc_write, 0, sizeof (bc_write)) ;
1115 
1116 	snprintf (bc_write.description, sizeof (bc_write.description), "Test description") ;
1117 	snprintf (bc_write.originator, sizeof (bc_write.originator), "Test originator") ;
1118 	snprintf (bc_write.originator_reference, sizeof (bc_write.originator_reference), "%08x-%08x", (unsigned int) time (NULL), (unsigned int) (~ time (NULL))) ;
1119 	snprintf (bc_write.origination_date, sizeof (bc_write.origination_date), "%d/%02d/%02d", 2006, 3, 30) ;
1120 	snprintf (bc_write.origination_time, sizeof (bc_write.origination_time), "%02d:%02d:%02d", 20, 27, 0) ;
1121 	snprintf (bc_write.umid, sizeof (bc_write.umid), "Some umid") ;
1122 	bc_write.coding_history_size = 0 ;
1123 
1124 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
1125 	if (sf_command (file, SFC_SET_BROADCAST_INFO, &bc_write, sizeof (bc_write)) == SF_FALSE)
1126 	{	printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) failed.\n\n", __LINE__) ;
1127 		exit (1) ;
1128 		} ;
1129 	test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ;
1130 	sf_close (file) ;
1131 
1132 	memset (&bc_read, 0, sizeof (bc_read)) ;
1133 
1134 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
1135 	if (sf_command (file, SFC_GET_BROADCAST_INFO, &bc_read, sizeof (bc_read)) == SF_FALSE)
1136 	{	printf ("\n\nLine %d : sf_command (SFC_GET_BROADCAST_INFO) failed.\n\n", __LINE__) ;
1137 		exit (1) ;
1138 		return ;
1139 		} ;
1140 	check_log_buffer_or_die (file, __LINE__) ;
1141 	sf_close (file) ;
1142 
1143 	if (bc_read.version != 2)
1144 	{	printf ("\n\nLine %d : Read bad version number %d.\n\n", __LINE__, bc_read.version) ;
1145 		exit (1) ;
1146 		return ;
1147 		} ;
1148 
1149 	bc_read.version = bc_write.version = 0 ;
1150 
1151 	if (memcmp (bc_write.description, bc_read.description, sizeof (bc_write.description)) != 0)
1152 	{	printf ("\n\nLine %d : description mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, bc_write.description, bc_read.description) ;
1153 		errors ++ ;
1154 		} ;
1155 
1156 	if (memcmp (bc_write.originator, bc_read.originator, sizeof (bc_write.originator)) != 0)
1157 	{	printf ("\n\nLine %d : originator mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, bc_write.originator, bc_read.originator) ;
1158 		errors ++ ;
1159 		} ;
1160 
1161 	if (memcmp (bc_write.originator_reference, bc_read.originator_reference, sizeof (bc_write.originator_reference)) != 0)
1162 	{	printf ("\n\nLine %d : originator_reference mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, bc_write.originator_reference, bc_read.originator_reference) ;
1163 		errors ++ ;
1164 		} ;
1165 
1166 	if (memcmp (bc_write.origination_date, bc_read.origination_date, sizeof (bc_write.origination_date)) != 0)
1167 	{	printf ("\n\nLine %d : origination_date mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, bc_write.origination_date, bc_read.origination_date) ;
1168 		errors ++ ;
1169 		} ;
1170 
1171 	if (memcmp (bc_write.origination_time, bc_read.origination_time, sizeof (bc_write.origination_time)) != 0)
1172 	{	printf ("\n\nLine %d : origination_time mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, bc_write.origination_time, bc_read.origination_time) ;
1173 		errors ++ ;
1174 		} ;
1175 
1176 	if (memcmp (bc_write.umid, bc_read.umid, sizeof (bc_write.umid)) != 0)
1177 	{	printf ("\n\nLine %d : umid mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, bc_write.umid, bc_read.umid) ;
1178 		errors ++ ;
1179 		} ;
1180 
1181 	if (errors)
1182 		exit (1) ;
1183 
1184 	unlink (filename) ;
1185 	puts ("ok") ;
1186 } /* broadcast_test */
1187 
1188 static	void
broadcast_rdwr_test(const char * filename,int filetype)1189 broadcast_rdwr_test (const char *filename, int filetype)
1190 {	SF_BROADCAST_INFO binfo ;
1191 	SNDFILE *file ;
1192 	SF_INFO sfinfo ;
1193 	sf_count_t frames ;
1194 
1195 	print_test_name (__func__, filename) ;
1196 
1197 	create_short_sndfile (filename, filetype, 2) ;
1198 
1199 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
1200 	memset (&binfo, 0, sizeof (binfo)) ;
1201 
1202 	snprintf (binfo.description, sizeof (binfo.description), "Test description") ;
1203 	snprintf (binfo.originator, sizeof (binfo.originator), "Test originator") ;
1204 	snprintf (binfo.originator_reference, sizeof (binfo.originator_reference), "%08x-%08x", (unsigned int) time (NULL), (unsigned int) (~ time (NULL))) ;
1205 	snprintf (binfo.origination_date, sizeof (binfo.origination_date), "%d/%02d/%02d", 2006, 3, 30) ;
1206 	snprintf (binfo.origination_time, sizeof (binfo.origination_time), "%02d:%02d:%02d", 20, 27, 0) ;
1207 	snprintf (binfo.umid, sizeof (binfo.umid), "Some umid") ;
1208 	binfo.coding_history_size = 0 ;
1209 
1210 	file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_TRUE, __LINE__) ;
1211 	frames = sfinfo.frames ;
1212 	if (sf_command (file, SFC_SET_BROADCAST_INFO, &binfo, sizeof (binfo)) != SF_FALSE)
1213 	{	printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) should have failed but didn't.\n\n", __LINE__) ;
1214 		exit (1) ;
1215 		} ;
1216 	sf_close (file) ;
1217 
1218 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
1219 	sf_close (file) ;
1220 	exit_if_true (frames != sfinfo.frames, "\n\nLine %d : Frame count %" PRId64 " should be %" PRId64 ".\n", __LINE__, sfinfo.frames, frames) ;
1221 
1222 	unlink (filename) ;
1223 	puts ("ok") ;
1224 } /* broadcast_rdwr_test */
1225 
1226 static void
check_coding_history_newlines(const char * filename)1227 check_coding_history_newlines (const char *filename)
1228 {	static SF_BROADCAST_INFO bc_write, bc_read ;
1229 	SNDFILE	*file ;
1230 	SF_INFO	sfinfo ;
1231 	unsigned k ;
1232 
1233 	sfinfo.samplerate	= 22050 ;
1234 	sfinfo.format		= SF_FORMAT_WAV | SF_FORMAT_PCM_16 ;
1235 	sfinfo.channels		= 1 ;
1236 
1237 	memset (&bc_write, 0, sizeof (bc_write)) ;
1238 
1239 	snprintf (bc_write.description, sizeof (bc_write.description), "Test description") ;
1240 	snprintf (bc_write.originator, sizeof (bc_write.originator), "Test originator") ;
1241 	snprintf (bc_write.originator_reference, sizeof (bc_write.originator_reference), "%08x-%08x", (unsigned int) time (NULL), (unsigned int) (~ time (NULL))) ;
1242 	snprintf (bc_write.origination_date, sizeof (bc_write.origination_date), "%d/%02d/%02d", 2006, 3, 30) ;
1243 	snprintf (bc_write.origination_time, sizeof (bc_write.origination_time), "%02d:%02d:%02d", 20, 27, 0) ;
1244 	snprintf (bc_write.umid, sizeof (bc_write.umid), "Some umid") ;
1245 	bc_write.coding_history_size = snprintf (bc_write.coding_history, sizeof (bc_write.coding_history), "This has\nUnix\nand\rMac OS9\rline endings.\nLast line") ; ;
1246 
1247 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
1248 	if (sf_command (file, SFC_SET_BROADCAST_INFO, &bc_write, sizeof (bc_write)) == SF_FALSE)
1249 	{	printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) failed.\n\n", __LINE__) ;
1250 		exit (1) ;
1251 		} ;
1252 
1253 	test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ;
1254 	sf_close (file) ;
1255 
1256 	memset (&bc_read, 0, sizeof (bc_read)) ;
1257 
1258 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
1259 	if (sf_command (file, SFC_GET_BROADCAST_INFO, &bc_read, sizeof (bc_read)) == SF_FALSE)
1260 	{	printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) failed.\n\n", __LINE__) ;
1261 		exit (1) ;
1262 		} ;
1263 	check_log_buffer_or_die (file, __LINE__) ;
1264 	sf_close (file) ;
1265 
1266 	if (bc_read.coding_history_size == 0)
1267 	{	printf ("\n\nLine %d : missing coding history.\n\n", __LINE__) ;
1268 		exit (1) ;
1269 		} ;
1270 
1271 	if (strstr (bc_read.coding_history, "Last line") == NULL)
1272 	{	printf ("\n\nLine %d : coding history truncated.\n\n", __LINE__) ;
1273 		exit (1) ;
1274 		} ;
1275 
1276 	for (k = 1 ; k < bc_read.coding_history_size ; k++)
1277 	{	if (bc_read.coding_history [k] == '\n' && bc_read.coding_history [k - 1] != '\r')
1278 		{	printf ("\n\nLine %d : '\\n' without '\\r' before.\n\n", __LINE__) ;
1279 			exit (1) ;
1280 			} ;
1281 
1282 		if (bc_read.coding_history [k] == '\r' && bc_read.coding_history [k + 1] != '\n')
1283 		{	printf ("\n\nLine %d : '\\r' without '\\n' after.\n\n", __LINE__) ;
1284 			exit (1) ;
1285 			} ;
1286 
1287 		if (bc_read.coding_history [k] == 0 && k < bc_read.coding_history_size - 1)
1288 		{	printf ("\n\nLine %d : '\\0' within coding history at index %d of %d.\n\n", __LINE__, k, bc_read.coding_history_size) ;
1289 			exit (1) ;
1290 			} ;
1291 		} ;
1292 
1293 	return ;
1294 } /* check_coding_history_newlines */
1295 
1296 static void
broadcast_coding_history_test(const char * filename)1297 broadcast_coding_history_test (const char *filename)
1298 {	static SF_BROADCAST_INFO bc_write, bc_read ;
1299 	SNDFILE	*file ;
1300 	SF_INFO	sfinfo ;
1301 	const char *default_history = "A=PCM,F=22050,W=16,M=mono" ;
1302 	const char *supplied_history =
1303 					"A=PCM,F=44100,W=24,M=mono,T=other\r\n"
1304 					"A=PCM,F=22050,W=16,M=mono,T=yet_another\r\n" ;
1305 
1306 	print_test_name ("broadcast_coding_history_test", filename) ;
1307 
1308 	sfinfo.samplerate	= 22050 ;
1309 	sfinfo.format		= SF_FORMAT_WAV | SF_FORMAT_PCM_16 ;
1310 	sfinfo.channels		= 1 ;
1311 
1312 	memset (&bc_write, 0, sizeof (bc_write)) ;
1313 
1314 	snprintf (bc_write.description, sizeof (bc_write.description), "Test description") ;
1315 	snprintf (bc_write.originator, sizeof (bc_write.originator), "Test originator") ;
1316 	snprintf (bc_write.originator_reference, sizeof (bc_write.originator_reference), "%08x-%08x", (unsigned int) time (NULL), (unsigned int) (~ time (NULL))) ;
1317 	snprintf (bc_write.origination_date, sizeof (bc_write.origination_date), "%d/%02d/%02d", 2006, 3, 30) ;
1318 	snprintf (bc_write.origination_time, sizeof (bc_write.origination_time), "%02d:%02d:%02d", 20, 27, 0) ;
1319 	snprintf (bc_write.umid, sizeof (bc_write.umid), "Some umid") ;
1320 	/* Coding history will be filled in by the library. */
1321 	bc_write.coding_history_size = 0 ;
1322 
1323 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
1324 	if (sf_command (file, SFC_SET_BROADCAST_INFO, &bc_write, sizeof (bc_write)) == SF_FALSE)
1325 	{	printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) failed.\n\n", __LINE__) ;
1326 		exit (1) ;
1327 		} ;
1328 
1329 	test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ;
1330 	sf_close (file) ;
1331 
1332 	memset (&bc_read, 0, sizeof (bc_read)) ;
1333 
1334 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
1335 	if (sf_command (file, SFC_GET_BROADCAST_INFO, &bc_read, sizeof (bc_read)) == SF_FALSE)
1336 	{	printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) failed.\n\n", __LINE__) ;
1337 		exit (1) ;
1338 		} ;
1339 	check_log_buffer_or_die (file, __LINE__) ;
1340 	sf_close (file) ;
1341 
1342 	if (bc_read.coding_history_size == 0)
1343 	{	printf ("\n\nLine %d : missing coding history.\n\n", __LINE__) ;
1344 		exit (1) ;
1345 		} ;
1346 
1347 	if (bc_read.coding_history_size < strlen (default_history) || memcmp (bc_read.coding_history, default_history, strlen (default_history)) != 0)
1348 	{	printf ("\n\n"
1349 				"Line %d : unexpected coding history '%.*s',\n"
1350 				"            should be '%s'\n\n", __LINE__, bc_read.coding_history_size, bc_read.coding_history, default_history) ;
1351 		exit (1) ;
1352 		} ;
1353 
1354 	bc_write.coding_history_size = strlen (supplied_history) ;
1355 	bc_write.coding_history_size = snprintf (bc_write.coding_history, sizeof (bc_write.coding_history), "%s", supplied_history) ;
1356 
1357 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
1358 	if (sf_command (file, SFC_SET_BROADCAST_INFO, &bc_write, sizeof (bc_write)) == SF_FALSE)
1359 	{	printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) failed.\n\n", __LINE__) ;
1360 		exit (1) ;
1361 		} ;
1362 
1363 	test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ;
1364 	sf_close (file) ;
1365 
1366 	memset (&bc_read, 0, sizeof (bc_read)) ;
1367 
1368 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
1369 	if (sf_command (file, SFC_GET_BROADCAST_INFO, &bc_read, sizeof (bc_read)) == SF_FALSE)
1370 	{	printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) failed.\n\n", __LINE__) ;
1371 		exit (1) ;
1372 		} ;
1373 
1374 	check_log_buffer_or_die (file, __LINE__) ;
1375 	sf_close (file) ;
1376 
1377 	if (strstr (bc_read.coding_history, supplied_history) != bc_read.coding_history)
1378 	{	printf ("\n\nLine %d : unexpected coding history :\n"
1379 				"----------------------------------------------------\n%s"
1380 				"----------------------------------------------------\n"
1381 				"should be this :\n"
1382 				"----------------------------------------------------\n%s"
1383 				"----------------------------------------------------\n"
1384 				"with one more line at the end.\n\n",
1385 				__LINE__, bc_read.coding_history, supplied_history) ;
1386 		exit (1) ;
1387 		} ;
1388 
1389 	check_coding_history_newlines (filename) ;
1390 
1391 	unlink (filename) ;
1392 	puts ("ok") ;
1393 } /* broadcast_coding_history_test */
1394 
1395 /*==============================================================================
1396 */
1397 
1398 static void
broadcast_coding_history_size(const char * filename)1399 broadcast_coding_history_size (const char *filename)
1400 {	/* SF_BROADCAST_INFO struct with coding_history field of 1024 bytes. */
1401 	static SF_BROADCAST_INFO_VAR (1024) bc_write ;
1402 	static SF_BROADCAST_INFO_VAR (1024) bc_read ;
1403 	SNDFILE	*file ;
1404 	SF_INFO	sfinfo ;
1405 	int k ;
1406 
1407 	print_test_name (__func__, filename) ;
1408 
1409 	sfinfo.samplerate	= 22050 ;
1410 	sfinfo.format		= SF_FORMAT_WAV | SF_FORMAT_PCM_16 ;
1411 	sfinfo.channels		= 1 ;
1412 
1413 	memset (&bc_write, 0, sizeof (bc_write)) ;
1414 
1415 	snprintf (bc_write.description, sizeof (bc_write.description), "Test description") ;
1416 	snprintf (bc_write.originator, sizeof (bc_write.originator), "Test originator") ;
1417 	snprintf (bc_write.originator_reference, sizeof (bc_write.originator_reference), "%08x-%08x", (unsigned int) time (NULL), (unsigned int) (~ time (NULL))) ;
1418 	snprintf (bc_write.origination_date, sizeof (bc_write.origination_date), "%d/%02d/%02d", 2006, 3, 30) ;
1419 	snprintf (bc_write.origination_time, sizeof (bc_write.origination_time), "%02d:%02d:%02d", 20, 27, 0) ;
1420 	snprintf (bc_write.umid, sizeof (bc_write.umid), "Some umid") ;
1421 	bc_write.coding_history_size = 0 ;
1422 
1423 	for (k = 0 ; bc_write.coding_history_size < 512 ; k++)
1424 	{	snprintf (bc_write.coding_history + bc_write.coding_history_size,
1425 			sizeof (bc_write.coding_history) - bc_write.coding_history_size, "line %4d\n", k) ;
1426 		bc_write.coding_history_size = strlen (bc_write.coding_history) ;
1427 		} ;
1428 
1429 	exit_if_true (bc_write.coding_history_size < 512,
1430 			"\n\nLine %d : bc_write.coding_history_size (%d) should be > 512.\n\n", __LINE__, bc_write.coding_history_size) ;
1431 
1432 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
1433 	if (sf_command (file, SFC_SET_BROADCAST_INFO, &bc_write, sizeof (bc_write)) == SF_FALSE)
1434 	{	printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) failed.\n\n", __LINE__) ;
1435 		exit (1) ;
1436 		} ;
1437 
1438 	test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ;
1439 	sf_close (file) ;
1440 
1441 	memset (&bc_read, 0, sizeof (bc_read)) ;
1442 
1443 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
1444 	if (sf_command (file, SFC_GET_BROADCAST_INFO, &bc_read, sizeof (bc_read)) == SF_FALSE)
1445 	{	printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) failed.\n\n", __LINE__) ;
1446 		exit (1) ;
1447 		} ;
1448 	check_log_buffer_or_die (file, __LINE__) ;
1449 	sf_close (file) ;
1450 
1451 	exit_if_true (bc_read.coding_history_size < 512,
1452 			"\n\nLine %d : unexpected coding history size %d (should be > 512).\n\n", __LINE__, bc_read.coding_history_size) ;
1453 
1454 	exit_if_true (strstr (bc_read.coding_history, "libsndfile") == NULL,
1455 			"\n\nLine %d : coding history incomplete (should contain 'libsndfile').\n\n", __LINE__) ;
1456 
1457 	unlink (filename) ;
1458 	puts ("ok") ;
1459 } /* broadcast_coding_history_size */
1460 
1461 /*==============================================================================
1462 */
1463 static void
cart_test(const char * filename,int filetype)1464 cart_test (const char *filename, int filetype)
1465 {	static SF_CART_INFO ca_write, ca_read ;
1466 	SNDFILE	*file ;
1467 	SF_INFO	sfinfo ;
1468 	int errors = 0 ;
1469 
1470 	print_test_name ("cart_test", filename) ;
1471 
1472 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
1473 	sfinfo.samplerate	= 11025 ;
1474 	sfinfo.format		= filetype ;
1475 	sfinfo.channels		= 1 ;
1476 	memset (&ca_write, 0, sizeof (ca_write)) ;
1477 
1478 	// example test data
1479 	snprintf (ca_write.artist, sizeof (ca_write.artist), "Test artist") ;
1480 	snprintf (ca_write.version, sizeof (ca_write.version), "Test version") ;
1481 	snprintf (ca_write.cut_id, sizeof (ca_write.cut_id), "Test cut ID") ;
1482 	snprintf (ca_write.client_id, sizeof (ca_write.client_id), "Test client ID") ;
1483 	snprintf (ca_write.category, sizeof (ca_write.category), "Test category") ;
1484 	snprintf (ca_write.classification, sizeof (ca_write.classification), "Test classification") ;
1485 	snprintf (ca_write.out_cue, sizeof (ca_write.out_cue), "Test out cue") ;
1486 	snprintf (ca_write.start_date, sizeof (ca_write.start_date), "%d/%02d/%02d", 2006, 3, 30) ;
1487 	snprintf (ca_write.start_time, sizeof (ca_write.start_time), "%02d:%02d:%02d", 20, 27, 0) ;
1488 	snprintf (ca_write.end_date, sizeof (ca_write.end_date), "%d/%02d/%02d", 2006, 3, 30) ;
1489 	snprintf (ca_write.end_time, sizeof (ca_write.end_time), "%02d:%02d:%02d", 20, 27, 0) ;
1490 	snprintf (ca_write.producer_app_id, sizeof (ca_write.producer_app_id), "Test producer app id") ;
1491 	snprintf (ca_write.producer_app_version, sizeof (ca_write.producer_app_version), "Test producer app version") ;
1492 	snprintf (ca_write.user_def, sizeof (ca_write.user_def), "test user def test test") ;
1493 	ca_write.level_reference = 42 ;
1494 	snprintf (ca_write.url, sizeof (ca_write.url), "http://www.test.com/test_url") ;
1495 	snprintf (ca_write.tag_text, sizeof (ca_write.tag_text), "tag text test! \r\n") ; // must be terminated \r\n to be valid
1496 	ca_write.tag_text_size = strlen (ca_write.tag_text) ;
1497 
1498 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
1499 	if (sf_command (file, SFC_SET_CART_INFO, &ca_write, sizeof (ca_write)) == SF_FALSE)
1500 		exit (1) ;
1501 
1502 	test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ;
1503 	sf_close (file) ;
1504 
1505 	memset (&ca_read, 0, sizeof (ca_read)) ;
1506 
1507 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
1508 	if (sf_command (file, SFC_GET_CART_INFO, &ca_read, sizeof (ca_read)) == SF_FALSE)
1509 	{	printf ("\n\nLine %d : sf_command (SFC_GET_CART_INFO) failed.\n\n", __LINE__) ;
1510 		exit (1) ;
1511 		return ;
1512 		} ;
1513 	check_log_buffer_or_die (file, __LINE__) ;
1514 	sf_close (file) ;
1515 
1516 
1517 	if (memcmp (ca_write.artist, ca_read.artist, sizeof (ca_write.artist)) != 0)
1518 	{	printf ("\n\nLine %d : artist mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, ca_write.artist, ca_read.artist) ;
1519 		errors ++ ;
1520 		} ;
1521 
1522 	if (memcmp (ca_write.version, ca_read.version, sizeof (ca_write.version)) != 0)
1523 	{	printf ("\n\nLine %d : version mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, ca_write.version, ca_read.version) ;
1524 		errors ++ ;
1525 		} ;
1526 
1527 	if (memcmp (ca_write.title, ca_read.title, sizeof (ca_write.title)) != 0)
1528 	{	printf ("\n\nLine %d : title mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, ca_write.title, ca_read.title) ;
1529 		errors ++ ;
1530 		} ;
1531 
1532 	if (memcmp (ca_write.cut_id, ca_read.cut_id, sizeof (ca_write.cut_id)) != 0)
1533 	{	printf ("\n\nLine %d : cut_id mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, ca_write.cut_id, ca_read.cut_id) ;
1534 		errors ++ ;
1535 		} ;
1536 
1537 	if (memcmp (ca_write.client_id, ca_read.client_id, sizeof (ca_write.client_id)) != 0)
1538 	{	printf ("\n\nLine %d : client_id mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, ca_write.client_id, ca_read.client_id) ;
1539 		errors ++ ;
1540 		} ;
1541 
1542 	if (memcmp (ca_write.category, ca_read.category, sizeof (ca_write.category)) != 0)
1543 	{	printf ("\n\nLine %d : category mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, ca_write.category, ca_read.category) ;
1544 		errors ++ ;
1545 		} ;
1546 
1547 	if (memcmp (ca_write.out_cue, ca_read.out_cue, sizeof (ca_write.out_cue)) != 0)
1548 	{	printf ("\n\nLine %d : out_cue mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, ca_write.out_cue, ca_read.out_cue) ;
1549 		errors ++ ;
1550 		} ;
1551 
1552 	if (memcmp (ca_write.start_date, ca_read.start_date, sizeof (ca_write.start_date)) != 0)
1553 	{	printf ("\n\nLine %d : start_date mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, ca_write.start_date, ca_read.start_date) ;
1554 		errors ++ ;
1555 		} ;
1556 
1557 
1558 	if (memcmp (ca_write.start_time, ca_read.start_time, sizeof (ca_write.start_time)) != 0)
1559 	{	printf ("\n\nLine %d : start_time mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, ca_write.start_time, ca_read.start_time) ;
1560 		errors ++ ;
1561 		} ;
1562 
1563 
1564 	if (memcmp (ca_write.end_date, ca_read.end_date, sizeof (ca_write.end_date)) != 0)
1565 	{	printf ("\n\nLine %d : end_date mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, ca_write.end_date, ca_read.end_date) ;
1566 		errors ++ ;
1567 		} ;
1568 
1569 
1570 	if (memcmp (ca_write.end_time, ca_read.end_time, sizeof (ca_write.end_time)) != 0)
1571 	{	printf ("\n\nLine %d : end_time mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, ca_write.end_time, ca_read.end_time) ;
1572 		errors ++ ;
1573 		} ;
1574 
1575 
1576 	if (memcmp (ca_write.producer_app_id, ca_read.producer_app_id, sizeof (ca_write.producer_app_id)) != 0)
1577 	{	printf ("\n\nLine %d : producer_app_id mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, ca_write.producer_app_id, ca_read.producer_app_id) ;
1578 		errors ++ ;
1579 		} ;
1580 
1581 
1582 	if (memcmp (ca_write.producer_app_version, ca_read.producer_app_version, sizeof (ca_write.producer_app_version)) != 0)
1583 	{	printf ("\n\nLine %d : producer_app_version mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, ca_write.producer_app_version, ca_read.producer_app_version) ;
1584 		errors ++ ;
1585 		} ;
1586 
1587 
1588 	if (memcmp (ca_write.user_def, ca_read.user_def, sizeof (ca_write.user_def)) != 0)
1589 	{	printf ("\n\nLine %d : user_def mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, ca_write.user_def, ca_read.user_def) ;
1590 		errors ++ ;
1591 		} ;
1592 
1593 
1594 	if (ca_write.level_reference != ca_read.level_reference)
1595 	{	printf ("\n\nLine %d : level_reference mismatch :\n\twrite : '%d'\n\tread  : '%d'\n\n", __LINE__, ca_write.level_reference, ca_read.level_reference) ;
1596 		errors ++ ;
1597 		} ;
1598 
1599 	// TODO: make this more helpful
1600 	if (memcmp (ca_write.post_timers, ca_read.post_timers, sizeof (ca_write.post_timers)) != 0)
1601 	{	printf ("\n\nLine %d : post_timers mismatch :\n'\n\n", __LINE__) ;
1602 		errors ++ ;
1603 		} ;
1604 
1605 	if (memcmp (ca_write.url, ca_read.url, sizeof (ca_write.url)) != 0)
1606 	{	printf ("\n\nLine %d : url mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, ca_write.url, ca_read.url) ;
1607 		errors ++ ;
1608 		} ;
1609 
1610 
1611 	if (memcmp (ca_write.tag_text, ca_read.tag_text, (size_t) (ca_read.tag_text_size)) != 0)
1612 	{	printf ("\n\nLine %d : tag_text mismatch :\n\twrite : '%s'\n\tread  : '%s'\n\n", __LINE__, ca_write.tag_text, ca_read.tag_text) ;
1613 		errors ++ ;
1614 		} ;
1615 
1616 
1617 	if (errors)
1618 		exit (1) ;
1619 
1620 	unlink (filename) ;
1621 	puts ("ok") ;
1622 } /* cart_test */
1623 
1624 static	void
cart_rdwr_test(const char * filename,int filetype)1625 cart_rdwr_test (const char *filename, int filetype)
1626 {	SF_CART_INFO cinfo ;
1627 	SNDFILE *file ;
1628 	SF_INFO sfinfo ;
1629 	sf_count_t frames ;
1630 
1631 	print_test_name (__func__, filename) ;
1632 
1633 	create_short_sndfile (filename, filetype, 2) ;
1634 
1635 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
1636 	memset (&cinfo, 0, sizeof (cinfo)) ;
1637 
1638 	snprintf (cinfo.artist, sizeof (cinfo.artist), "Test artist") ;
1639 	snprintf (cinfo.version, sizeof (cinfo.version), "Test version") ;
1640 	snprintf (cinfo.cut_id, sizeof (cinfo.cut_id), "Test cut ID") ;
1641 	snprintf (cinfo.client_id, sizeof (cinfo.client_id), "Test client ID") ;
1642 	snprintf (cinfo.category, sizeof (cinfo.category), "Test category") ;
1643 	snprintf (cinfo.classification, sizeof (cinfo.classification), "Test classification") ;
1644 	snprintf (cinfo.out_cue, sizeof (cinfo.out_cue), "Test out cue") ;
1645 	snprintf (cinfo.start_date, sizeof (cinfo.start_date), "%d/%02d/%02d", 2006, 3, 30) ;
1646 	snprintf (cinfo.start_time, sizeof (cinfo.start_time), "%02d:%02d:%02d", 20, 27, 0) ;
1647 	snprintf (cinfo.end_date, sizeof (cinfo.end_date), "%d/%02d/%02d", 2006, 3, 30) ;
1648 	snprintf (cinfo.end_time, sizeof (cinfo.end_time), "%02d:%02d:%02d", 20, 27, 0) ;
1649 	snprintf (cinfo.producer_app_id, sizeof (cinfo.producer_app_id), "Test producer app id") ;
1650 	snprintf (cinfo.producer_app_version, sizeof (cinfo.producer_app_version), "Test producer app version") ;
1651 	snprintf (cinfo.user_def, sizeof (cinfo.user_def), "test user def test test") ;
1652 	cinfo.level_reference = 42 ;
1653 	snprintf (cinfo.url, sizeof (cinfo.url), "http://www.test.com/test_url") ;
1654 	snprintf (cinfo.tag_text, sizeof (cinfo.tag_text), "tag text test!\r\n") ;
1655 	cinfo.tag_text_size = strlen (cinfo.tag_text) ;
1656 
1657 	file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_TRUE, __LINE__) ;
1658 	frames = sfinfo.frames ;
1659 	if (sf_command (file, SFC_SET_CART_INFO, &cinfo, sizeof (cinfo)) != SF_FALSE)
1660 	{	printf ("\n\nLine %d : sf_command (SFC_SET_CART_INFO) should have failed but didn't.\n\n", __LINE__) ;
1661 		exit (1) ;
1662 		} ;
1663 	sf_close (file) ;
1664 
1665 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
1666 	sf_close (file) ;
1667 	exit_if_true (frames != sfinfo.frames, "\n\nLine %d : Frame count %" PRId64 " should be %" PRId64 ".\n", __LINE__, sfinfo.frames, frames) ;
1668 
1669 	unlink (filename) ;
1670 	puts ("ok") ;
1671 } /* cart_rdwr_test */
1672 
1673 /*==============================================================================
1674 */
1675 
1676 static	void
channel_map_test(const char * filename,int filetype)1677 channel_map_test (const char *filename, int filetype)
1678 {	SNDFILE	*file ;
1679 	SF_INFO	sfinfo ;
1680 	int channel_map_read [4], channel_map_write [4] =
1681 	{	SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_LFE,
1682 		SF_CHANNEL_MAP_REAR_CENTER
1683 		} ;
1684 
1685 	print_test_name ("channel_map_test", filename) ;
1686 
1687 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
1688 	sfinfo.samplerate	= 11025 ;
1689 	sfinfo.format		= filetype ;
1690 	sfinfo.channels		= ARRAY_LEN (channel_map_read) ;
1691 
1692 	switch (filetype & SF_FORMAT_TYPEMASK)
1693 	{	/* WAVEX and RF64 have a default channel map, even if you don't specify one. */
1694 		case SF_FORMAT_WAVEX :
1695 		case SF_FORMAT_RF64 :
1696 			/* Write file without channel map. */
1697 			file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
1698 			test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ;
1699 			sf_close (file) ;
1700 
1701 			/* Read file making default channel map exists. */
1702 			file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
1703 			exit_if_true (
1704 				sf_command (file, SFC_GET_CHANNEL_MAP_INFO, channel_map_read, sizeof (channel_map_read)) == SF_FALSE,
1705 				"\n\nLine %d : sf_command (SFC_GET_CHANNEL_MAP_INFO) should not have failed.\n\n", __LINE__
1706 				) ;
1707 			check_log_buffer_or_die (file, __LINE__) ;
1708 			sf_close (file) ;
1709 			break ;
1710 
1711 		default :
1712 			break ;
1713 		} ;
1714 
1715 	/* Write file with a channel map. */
1716 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
1717 	exit_if_true (
1718 		sf_command (file, SFC_SET_CHANNEL_MAP_INFO, channel_map_write, sizeof (channel_map_write)) == SF_FALSE,
1719 		"\n\nLine %d : sf_command (SFC_SET_CHANNEL_MAP_INFO) failed.\n\n", __LINE__
1720 		) ;
1721 	test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ;
1722 	sf_close (file) ;
1723 
1724 	/* Read file making sure no channel map exists. */
1725 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
1726 	exit_if_true (
1727 		sf_command (file, SFC_GET_CHANNEL_MAP_INFO, channel_map_read, sizeof (channel_map_read)) != SF_TRUE,
1728 		"\n\nLine %d : sf_command (SFC_GET_CHANNEL_MAP_INFO) failed.\n\n", __LINE__
1729 		) ;
1730 	check_log_buffer_or_die (file, __LINE__) ;
1731 	sf_close (file) ;
1732 
1733 	exit_if_true (
1734 		memcmp (channel_map_read, channel_map_write, sizeof (channel_map_read)) != 0,
1735 		"\n\nLine %d : Channel map read does not match channel map written.\n\n", __LINE__
1736 		) ;
1737 
1738 	unlink (filename) ;
1739 	puts ("ok") ;
1740 } /* channel_map_test */
1741 
1742 static	void
raw_needs_endswap_test(const char * filename,int filetype)1743 raw_needs_endswap_test (const char *filename, int filetype)
1744 {	static int subtypes [] =
1745 	{	SF_FORMAT_FLOAT, SF_FORMAT_DOUBLE,
1746 		SF_FORMAT_PCM_16, SF_FORMAT_PCM_24, SF_FORMAT_PCM_32
1747 		} ;
1748 	SNDFILE	*file ;
1749 	SF_INFO	sfinfo ;
1750 	unsigned k ;
1751 	int needs_endswap ;
1752 
1753 	print_test_name (__func__, filename) ;
1754 
1755 	for (k = 0 ; k < ARRAY_LEN (subtypes) ; k++)
1756 	{
1757 		if (filetype == (SF_ENDIAN_LITTLE | SF_FORMAT_AIFF))
1758 			switch (subtypes [k])
1759 			{	/* Little endian AIFF does not AFAIK support fl32 and fl64. */
1760 				case SF_FORMAT_FLOAT :
1761 				case SF_FORMAT_DOUBLE :
1762 					continue ;
1763 				default :
1764 					break ;
1765 				} ;
1766 
1767 		memset (&sfinfo, 0, sizeof (sfinfo)) ;
1768 		sfinfo.samplerate	= 11025 ;
1769 		sfinfo.format		= filetype | subtypes [k] ;
1770 		sfinfo.channels		= 1 ;
1771 
1772 		file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
1773 		test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ;
1774 		sf_close (file) ;
1775 
1776 		memset (&sfinfo, 0, sizeof (sfinfo)) ;
1777 		file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ;
1778 
1779 		needs_endswap = sf_command (file, SFC_RAW_DATA_NEEDS_ENDSWAP, NULL, 0) ;
1780 
1781 		switch (filetype)
1782 		{	case SF_FORMAT_WAV :
1783 			case SF_FORMAT_WAVEX :
1784 			case SF_FORMAT_AIFF | SF_ENDIAN_LITTLE :
1785 				exit_if_true (needs_endswap != CPU_IS_BIG_ENDIAN,
1786 					"\n\nLine %d : SFC_RAW_DATA_NEEDS_ENDSWAP failed for (%d | %d).\n\n", __LINE__, filetype, k) ;
1787 				break ;
1788 
1789 			case SF_FORMAT_AIFF :
1790 			case SF_FORMAT_WAV | SF_ENDIAN_BIG :
1791 				exit_if_true (needs_endswap != CPU_IS_LITTLE_ENDIAN,
1792 					"\n\nLine %d : SFC_RAW_DATA_NEEDS_ENDSWAP failed for (%d | %d).\n\n", __LINE__, filetype, k) ;
1793 				break ;
1794 
1795 			default :
1796 				printf ("\n\nLine %d : bad format value %d.\n\n", __LINE__, filetype) ;
1797 				exit (1) ;
1798 				break ;
1799 			} ;
1800 
1801 		sf_close (file) ;
1802 		} ;
1803 
1804 	unlink (filename) ;
1805 	puts ("ok") ;
1806 } /* raw_needs_endswap_test */
1807