• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1[+ AutoGen5 template h c +]
2/*
3** Copyright (C) 2002-2018 Erik de Castro Lopo <erikd@mega-nerd.com>
4**
5** This program is free software; you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation; either version 2 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program; if not, write to the Free Software
17** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18*/
19
20/*
21**	Utility functions to make writing the test suite easier.
22**
23**	The .c and .h files were generated automagically with Autogen from
24**	the files utils.def and utils.tpl.
25*/
26
27[+ CASE (suffix) +]
28[+ ==  h  +]
29
30#ifdef __cplusplus
31extern "C" {
32#endif	/* __cplusplus */
33
34#include "sfconfig.h"
35
36#include <stdint.h>
37#include <stdarg.h>
38
39#define	ARRAY_LEN(x)		((int) (sizeof (x)) / (sizeof ((x) [0])))
40#define SIGNED_SIZEOF(x)	((int64_t) (sizeof (x)))
41#define	NOT(x)				(! (x))
42#define	ABS(x)				((x) >= 0 ? (x) : - (x))
43
44#define	PIPE_INDEX(x)	((x) + 500)
45#define	PIPE_TEST_LEN	12345
46
47
48[+ FOR float_type
49+]void gen_windowed_sine_[+ (get "name") +] ([+ (get "name") +] *data, int len, double maximum) ;
50[+ ENDFOR float_type
51+]
52
53void	create_short_sndfile (const char *filename, int format, int channels) ;
54
55void	check_file_hash_or_die	(const char *filename, uint64_t target_hash, int line_num) ;
56
57void	print_test_name (const char *test, const char *filename) ;
58
59void	dump_data_to_file (const char *filename, const void *data, unsigned int datalen) ;
60
61void	write_mono_file (const char * filename, int format, int srate, float * output, int len) ;
62
63#ifdef __GNUC__
64static inline void
65exit_if_true (int test, const char *format, ...)
66#if (defined (__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO && !defined (__clang__))
67	__attribute__ ((format (gnu_printf, 2, 3))) ;
68#else
69	__attribute__ ((format (printf, 2, 3))) ;
70#endif
71#endif
72
73static inline void
74exit_if_true (int test, const char *format, ...)
75{	if (test)
76	{	va_list	argptr ;
77		va_start (argptr, format) ;
78		vprintf (format, argptr) ;
79		va_end (argptr) ;
80		exit (1) ;
81		} ;
82} /* exit_if_true */
83
84static inline int32_t
85arith_shift_left (int32_t x, int shift)
86{	return (int32_t) (((uint32_t) x) << shift) ;
87} /* arith_shift_left */
88
89/*
90**	Functions for saving two vectors of data in an ascii text file which
91**	can then be loaded into GNU octave for comparison.
92*/
93
94[+ FOR io_type
95+]int	oct_save_[+ (get "io_element") +]	(const [+ (get "io_element") +] *a, const [+ (get "io_element") +] *b, int len) ;
96[+ ENDFOR io_type
97+]
98
99void	delete_file (int format, const char *filename) ;
100
101int		truncate_file_to_zero (const char *fname) ;
102
103void	count_open_files (void) ;
104void	increment_open_file_count (void) ;
105void	check_open_file_count_or_die (int lineno) ;
106
107#ifdef SNDFILE_H
108
109static inline void
110sf_info_clear (SF_INFO * info)
111{	memset (info, 0, sizeof (SF_INFO)) ;
112} /* sf_info_clear */
113
114static inline void
115sf_info_setup (SF_INFO * info, int format, int samplerate, int channels)
116{	sf_info_clear (info) ;
117
118	info->format = format ;
119	info->samplerate = samplerate ;
120	info->channels = channels ;
121} /* sf_info_setup */
122
123
124void 	dump_log_buffer (SNDFILE *file) ;
125void 	check_log_buffer_or_die (SNDFILE *file, int line_num) ;
126int 	string_in_log_buffer (SNDFILE *file, const char *s) ;
127void	hexdump_file (const char * filename, sf_count_t offset, sf_count_t length) ;
128
129void	test_sf_format_or_die	(const SF_INFO *info, int line_num) ;
130
131SNDFILE *test_open_file_or_die
132			(const char *filename, int mode, SF_INFO *sfinfo, int allow_fd, int line_num) ;
133
134void 	test_read_write_position_or_die
135			(SNDFILE *file, int line_num, int pass, sf_count_t read_pos, sf_count_t write_pos) ;
136
137void	test_seek_or_die
138			(SNDFILE *file, sf_count_t offset, int whence, sf_count_t new_pos, int channels, int line_num) ;
139
140[+ FOR read_op +]
141[+ FOR io_type
142+]void 	test_[+ (get "op_element") +]_[+ (get "io_element") +]_or_die
143			(SNDFILE *file, int pass, [+ (get "io_element") +] *test, sf_count_t [+ (get "count_name") +], int line_num) ;
144[+ ENDFOR io_type +][+ ENDFOR read_op +]
145
146void
147test_read_raw_or_die (SNDFILE *file, int pass, void *test, sf_count_t items, int line_num) ;
148
149[+ FOR write_op +]
150[+ FOR io_type
151+]void 	test_[+ (get "op_element") +]_[+ (get "io_element") +]_or_die
152			(SNDFILE *file, int pass, const [+ (get "io_element") +] *test, sf_count_t [+ (get "count_name") +], int line_num) ;
153[+ ENDFOR io_type +][+ ENDFOR write_op +]
154
155void
156test_write_raw_or_die (SNDFILE *file, int pass, const void *test, sf_count_t items, int line_num) ;
157
158[+ FOR io_type
159+]void compare_[+ (get "io_element") +]_or_die (const [+ (get "io_element") +] *expected, const [+ (get "io_element") +] *actual, unsigned count, int line_num) ;
160[+ ENDFOR io_type +]
161
162
163void	gen_lowpass_signal_float (float *data, int len) ;
164
165sf_count_t		file_length (const char * fname) ;
166sf_count_t		file_length_fd (int fd) ;
167
168#endif
169
170#ifdef __cplusplus
171}		/* extern "C" */
172#endif	/* __cplusplus */
173
174[+  ==  c  +]
175
176#include "sfconfig.h"
177
178#include <stdio.h>
179#include <stdlib.h>
180#include <inttypes.h>
181
182#if HAVE_UNISTD_H
183#include <unistd.h>
184#endif
185
186#if (HAVE_DECL_S_IRGRP == 0)
187#include <sf_unistd.h>
188#endif
189
190#include <errno.h>
191#include <string.h>
192#include <ctype.h>
193#include <math.h>
194#include <fcntl.h>
195#include <sys/stat.h>
196
197#include <sndfile.h>
198
199#include "utils.h"
200
201#ifndef	M_PI
202#define	M_PI		3.14159265358979323846264338
203#endif
204
205#define	LOG_BUFFER_SIZE		4096
206
207/*
208**	Neat solution to the Win32/OS2 binary file flage requirement.
209**	If O_BINARY isn't already defined by the inclusion of the system
210**	headers, set it to zero.
211*/
212#ifndef O_BINARY
213#define O_BINARY 0
214#endif
215
216[+ FOR float_type +]
217void
218gen_windowed_sine_[+ (get "name") +] ([+ (get "name") +] *data, int len, double maximum)
219{	int k ;
220
221	memset (data, 0, len * sizeof ([+ (get "name") +])) ;
222
223	len = (5 * len) / 6 ;
224
225	for (k = 0 ; k < len ; k++)
226	{	data [k] = sin (2.0 * k * M_PI * 1.0 / 32.0 + 0.4) ;
227
228		/* Apply Hanning Window. */
229		data [k] *= maximum * (0.5 - 0.5 * cos (2.0 * M_PI * k / ((len) - 1))) ;
230		}
231
232	return ;
233} /* gen_windowed_sine_[+ (get "name") +] */
234[+ ENDFOR float_type +]
235
236void
237create_short_sndfile (const char *filename, int format, int channels)
238{	short data [2 * 3 * 4 * 5 * 6 * 7] = { 0, } ;
239	SNDFILE *file ;
240	SF_INFO sfinfo ;
241
242	memset (&sfinfo, 0, sizeof (sfinfo)) ;
243	sfinfo.samplerate = 44100 ;
244	sfinfo.channels = channels ;
245	sfinfo.format = format ;
246
247	if ((file = sf_open (filename, SFM_WRITE, &sfinfo)) == NULL)
248	{	printf ("Error (%s, %d) : sf_open failed : %s\n", __FILE__, __LINE__, sf_strerror (file)) ;
249		exit (1) ;
250		} ;
251
252	sf_write_short (file, data, ARRAY_LEN (data)) ;
253
254	sf_close (file) ;
255} /* create_short_sndfile */
256
257void
258check_file_hash_or_die (const char *filename, uint64_t target_hash, int line_num)
259{	static unsigned char buf [4096] ;
260	uint64_t	cksum ;
261	FILE 		*file ;
262	int			k, read_count ;
263
264	memset (buf, 0, sizeof (buf)) ;
265
266	/* The 'b' in the mode string means binary for Win32. */
267	if ((file = fopen (filename, "rb")) == NULL)
268	{	printf ("\n\nLine %d: could not open file '%s'\n\n", line_num, filename) ;
269		exit (1) ;
270		} ;
271
272	cksum = 0 ;
273
274	while ((read_count = fread (buf, 1, sizeof (buf), file)))
275		for (k = 0 ; k < read_count ; k++)
276			cksum = (cksum * 511 + buf [k]) & 0xfffffffffffff ;
277
278	fclose (file) ;
279
280	if (target_hash == 0)
281	{	printf (" 0x%" PRIx64 "\n", cksum) ;
282		return ;
283		} ;
284
285	if (cksum != target_hash)
286	{	printf ("\n\nLine %d: incorrect hash value 0x%" PRIx64 " should be 0x%" PRIx64 ".\n\n", line_num, cksum, target_hash) ;
287		exit (1) ;
288		} ;
289
290	return ;
291} /* check_file_hash_or_die */
292
293void
294print_test_name (const char *test, const char *filename)
295{	int count ;
296
297	if (test == NULL)
298	{	printf (__FILE__ ": bad test of filename parameter.\n") ;
299		exit (1) ;
300		} ;
301
302	if (filename == NULL || strlen (filename) == 0)
303	{	printf ("    %-30s : ", test) ;
304		count = 25 ;
305		}
306	else
307	{	printf ("    %-30s : %s ", test, filename) ;
308		count = 24 - strlen (filename) ;
309		} ;
310
311	while (count -- > 0)
312		putchar ('.') ;
313	putchar (' ') ;
314
315	fflush (stdout) ;
316} /* print_test_name */
317
318void
319dump_data_to_file (const char *filename, const void *data, unsigned int datalen)
320{	FILE *file ;
321
322	if ((file = fopen (filename, "wb")) == NULL)
323	{	printf ("\n\nLine %d : could not open file : %s\n\n", __LINE__, filename) ;
324		exit (1) ;
325		} ;
326
327	if (fwrite (data, 1, datalen, file) != datalen)
328	{	printf ("\n\nLine %d : fwrite failed.\n\n", __LINE__) ;
329		exit (1) ;
330		} ;
331
332	fclose (file) ;
333
334} /* dump_data_to_file */
335
336/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
337*/
338
339static char octfilename [] = "error.dat" ;
340
341[+ FOR io_type
342+]int
343oct_save_[+ (get "io_element") +]	(const [+ (get "io_element") +] *a, const [+ (get "io_element") +] *b, int len)
344{	FILE 	*file ;
345	int		k ;
346
347	if (! (file = fopen (octfilename, "w")))
348		return 1 ;
349
350	fprintf (file, "# Not created by Octave\n") ;
351
352	fprintf (file, "# name: a\n") ;
353	fprintf (file, "# type: matrix\n") ;
354	fprintf (file, "# rows: %d\n", len) ;
355	fprintf (file, "# columns: 1\n") ;
356
357	for (k = 0 ; k < len ; k++)
358		fprintf (file, [+ (get "format_str") +] "\n", a [k]) ;
359
360	fprintf (file, "# name: b\n") ;
361	fprintf (file, "# type: matrix\n") ;
362	fprintf (file, "# rows: %d\n", len) ;
363	fprintf (file, "# columns: 1\n") ;
364
365	for (k = 0 ; k < len ; k++)
366		fprintf (file, [+ (get "format_str") +] "\n", b [k]) ;
367
368	fclose (file) ;
369	return 0 ;
370} /* oct_save_[+ (get "io_element") +] */
371[+ ENDFOR io_type
372+]
373
374void
375check_log_buffer_or_die (SNDFILE *file, int line_num)
376{	static char	buffer [LOG_BUFFER_SIZE] ;
377	int			count ;
378
379	memset (buffer, 0, sizeof (buffer)) ;
380
381	/* Get the log buffer data. */
382	count = sf_command	(file, SFC_GET_LOG_INFO, buffer, LOG_BUFFER_SIZE) ;
383
384	if (LOG_BUFFER_SIZE - count < 2)
385	{	printf ("\n\nLine %d : Possible long log buffer.\n", line_num) ;
386		exit (1) ;
387		}
388
389	/* Look for "Should" */
390	if (strstr (buffer, "ould"))
391	{	printf ("\n\nLine %d : Log buffer contains `ould'. Dumping.\n", line_num) ;
392		puts (buffer) ;
393		exit (1) ;
394		} ;
395
396	/* Look for "**" */
397	if (strstr (buffer, "*"))
398	{	printf ("\n\nLine %d : Log buffer contains `*'. Dumping.\n", line_num) ;
399		puts (buffer) ;
400		exit (1) ;
401		} ;
402
403	/* Look for "Should" */
404	if (strstr (buffer, "nknown marker"))
405	{	printf ("\n\nLine %d : Log buffer contains `nknown marker'. Dumping.\n", line_num) ;
406		puts (buffer) ;
407		exit (1) ;
408		} ;
409
410	return ;
411} /* check_log_buffer_or_die */
412
413int
414string_in_log_buffer (SNDFILE *file, const char *s)
415{	static char	buffer [LOG_BUFFER_SIZE] ;
416	int			count ;
417
418	memset (buffer, 0, sizeof (buffer)) ;
419
420	/* Get the log buffer data. */
421	count = sf_command	(file, SFC_GET_LOG_INFO, buffer, LOG_BUFFER_SIZE) ;
422
423	if (LOG_BUFFER_SIZE - count < 2)
424	{	printf ("Possible long log buffer.\n") ;
425		exit (1) ;
426		}
427
428	/* Look for string */
429	return strstr (buffer, s) ? SF_TRUE : SF_FALSE ;
430} /* string_in_log_buffer */
431
432void
433hexdump_file (const char * filename, sf_count_t offset, sf_count_t length)
434{
435	FILE * file ;
436	char buffer [16] ;
437	int k, m, ch, readcount ;
438
439	if (length > 1000000)
440	{	printf ("\n\nError : length (%" PRId64 ") too long.\n\n", offset) ;
441		exit (1) ;
442		} ;
443
444	if ((file = fopen (filename, "r")) == NULL)
445	{	printf ("\n\nError : hexdump_file (%s) could not open file for read.\n\n", filename) ;
446		exit (1) ;
447		} ;
448
449	if (fseek (file, offset, SEEK_SET) != 0)
450	{	printf ("\n\nError : fseek(file, %" PRId64 ", SEEK_SET) failed : %s\n\n", offset, strerror (errno)) ;
451		exit (1) ;
452		} ;
453
454	puts ("\n\n") ;
455
456	for (k = 0 ; k < length ; k+= sizeof (buffer))
457	{	readcount = fread (buffer, 1, sizeof (buffer), file) ;
458
459		printf ("%08" PRIx64 " : ", offset + k) ;
460
461		for (m = 0 ; m < readcount ; m++)
462			printf ("%02x ", buffer [m] & 0xFF) ;
463
464		for (m = readcount ; m < SIGNED_SIZEOF (buffer) ; m++)
465			printf ("   ") ;
466
467		printf ("  ") ;
468		for (m = 0 ; m < readcount ; m++)
469		{	ch = isprint (buffer [m]) ? buffer [m] : '.' ;
470			putchar (ch) ;
471			} ;
472
473		if (readcount < SIGNED_SIZEOF (buffer))
474			break ;
475
476		putchar ('\n') ;
477		} ;
478
479	puts ("\n") ;
480
481	fclose (file) ;
482} /* hexdump_file */
483
484void
485dump_log_buffer (SNDFILE *file)
486{	static char	buffer [LOG_BUFFER_SIZE] ;
487
488	memset (buffer, 0, sizeof (buffer)) ;
489
490	/* Get the log buffer data. */
491	sf_command	(file, SFC_GET_LOG_INFO, buffer, LOG_BUFFER_SIZE) ;
492
493	if (strlen (buffer) < 1)
494		puts ("Log buffer empty.\n") ;
495	else
496		puts (buffer) ;
497
498	return ;
499} /* dump_log_buffer */
500
501void
502test_sf_format_or_die (const SF_INFO *info, int line_num)
503{	int res ;
504
505	if ((res = sf_format_check (info)) != 1)
506	{	printf ("\n\nLine %d : sf_format_check returned error (%d)\n\n", line_num, res) ;
507		exit (1) ;
508		} ;
509
510	return ;
511} /* test_sf_format_or_die */
512
513SNDFILE *
514test_open_file_or_die (const char *filename, int mode, SF_INFO *sfinfo, int allow_fd, int line_num)
515{	static int count = 0 ;
516
517	SNDFILE *file ;
518	const char *modestr, *func_name ;
519	int oflags = 0, omode = 0, err ;
520
521	/*
522	** Need to test both sf_open() and sf_open_fd().
523	** Do so alternately.
524	*/
525	switch (mode)
526	{	case SFM_READ :
527				modestr = "SFM_READ" ;
528				oflags = O_RDONLY | O_BINARY ;
529				omode = 0 ;
530				break ;
531
532		case SFM_WRITE :
533				modestr = "SFM_WRITE" ;
534				oflags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ;
535				omode = S_IRUSR | S_IWUSR | S_IRGRP ;
536				break ;
537
538		case SFM_RDWR :
539				modestr = "SFM_RDWR" ;
540				oflags = O_RDWR | O_CREAT | O_BINARY ;
541				omode = S_IRUSR | S_IWUSR | S_IRGRP ;
542				break ;
543		default :
544				printf ("\n\nLine %d: Bad mode.\n", line_num) ;
545				fflush (stdout) ;
546				exit (1) ;
547		} ;
548
549	if (OS_IS_WIN32)
550	{	/* Windows does not understand and ignores the S_IRGRP flag, but Wine
551		** gives a run time warning message, so just clear it.
552		*/
553		omode &= ~S_IRGRP ;
554		} ;
555
556	if (allow_fd && ((++count) & 1) == 1)
557	{	int fd ;
558
559		/* Only use the three argument open() function if omode != 0. */
560		fd = (omode == 0) ? open (filename, oflags) : open (filename, oflags, omode) ;
561
562		if (fd < 0)
563		{	printf ("\n\n%s : open failed : %s\n", __func__, strerror (errno)) ;
564			exit (1) ;
565			} ;
566
567		func_name = "sf_open_fd" ;
568		file = sf_open_fd (fd, mode, sfinfo, SF_TRUE) ;
569		}
570	else
571	{	func_name = "sf_open" ;
572		file = sf_open (filename, mode, sfinfo) ;
573		} ;
574
575	if (file == NULL)
576	{	printf ("\n\nLine %d: %s (%s) failed : %s\n\n", line_num, func_name, modestr, sf_strerror (NULL)) ;
577		dump_log_buffer (file) ;
578		exit (1) ;
579		} ;
580
581	err = sf_error (file) ;
582	if (err != SF_ERR_NO_ERROR)
583	{	printf ("\n\nLine %d : sf_error : %s\n\n", line_num, sf_error_number (err)) ;
584		dump_log_buffer (file) ;
585		exit (1) ;
586		} ;
587
588	return file ;
589} /* test_open_file_or_die */
590
591void
592test_read_write_position_or_die (SNDFILE *file, int line_num, int pass, sf_count_t read_pos, sf_count_t write_pos)
593{	sf_count_t pos ;
594
595	/* Check the current read position. */
596	if (read_pos >= 0 && (pos = sf_seek (file, 0, SEEK_CUR | SFM_READ)) != read_pos)
597	{	printf ("\n\nLine %d ", line_num) ;
598		if (pass > 0)
599			printf ("(pass %d): ", pass) ;
600		printf ("Read position (%" PRId64 ") should be %" PRId64 ".\n", pos, read_pos) ;
601		exit (1) ;
602		} ;
603
604	/* Check the current write position. */
605	if (write_pos >= 0 && (pos = sf_seek (file, 0, SEEK_CUR | SFM_WRITE)) != write_pos)
606	{	printf ("\n\nLine %d", line_num) ;
607		if (pass > 0)
608			printf (" (pass %d)", pass) ;
609		printf (" : Write position (%" PRId64 ") should be %" PRId64 ".\n", pos, write_pos) ;
610		exit (1) ;
611		} ;
612
613	return ;
614} /* test_read_write_position */
615
616void
617test_seek_or_die (SNDFILE *file, sf_count_t offset, int whence, sf_count_t new_pos, int channels, int line_num)
618{	sf_count_t	position ;
619	const char	*channel_name, *whence_name ;
620
621	switch (whence)
622	{	case SEEK_SET :
623				whence_name = "SEEK_SET" ;
624				break ;
625		case SEEK_CUR :
626				whence_name = "SEEK_CUR" ;
627				break ;
628		case SEEK_END :
629				whence_name = "SEEK_END" ;
630				break ;
631
632		/* SFM_READ */
633		case SEEK_SET | SFM_READ :
634				whence_name = "SFM_READ | SEEK_SET" ;
635				break ;
636		case SEEK_CUR | SFM_READ :
637				whence_name = "SFM_READ | SEEK_CUR" ;
638				break ;
639		case SEEK_END | SFM_READ :
640				whence_name = "SFM_READ | SEEK_END" ;
641				break ;
642
643		/* SFM_WRITE */
644		case SEEK_SET | SFM_WRITE :
645				whence_name = "SFM_WRITE | SEEK_SET" ;
646				break ;
647		case SEEK_CUR | SFM_WRITE :
648				whence_name = "SFM_WRITE | SEEK_CUR" ;
649				break ;
650		case SEEK_END | SFM_WRITE :
651				whence_name = "SFM_WRITE | SEEK_END" ;
652				break ;
653
654		default :
655				printf ("\n\nLine %d: bad whence parameter.\n", line_num) ;
656				exit (1) ;
657		} ;
658
659	channel_name = (channels == 1) ? "Mono" : "Stereo" ;
660
661	if ((position = sf_seek (file, offset, whence)) != new_pos)
662	{	printf ("\n\nLine %d : %s : sf_seek (file, %" PRId64 ", %s) returned %" PRId64 " (should be %" PRId64 ").\n\n",
663					line_num, channel_name, offset, whence_name, position, new_pos) ;
664		exit (1) ;
665		} ;
666
667} /* test_seek_or_die */
668
669[+ FOR read_op +]
670[+ FOR io_type +]
671void
672test_[+ (get "op_element") +]_[+ (get "io_element") +]_or_die (SNDFILE *file, int pass, [+ (get "io_element") +] *test, sf_count_t [+ (get "count_name") +], int line_num)
673{	sf_count_t count ;
674
675	if ((count = sf_[+ (get "op_element") +]_[+ (get "io_element") +] (file, test, [+ (get "count_name") +])) != [+ (get "count_name") +])
676	{	printf ("\n\nLine %d", line_num) ;
677		if (pass > 0)
678			printf (" (pass %d)", pass) ;
679		printf (" : sf_[+ (get "op_element") +]_[+ (get "io_element") +] failed with short [+ (get "op_element") +] (%" PRId64 " => %" PRId64 ").\n",
680						[+ (get "count_name") +], count) ;
681		fflush (stdout) ;
682		puts (sf_strerror (file)) ;
683		exit (1) ;
684		} ;
685
686	return ;
687} /* test_[+ (get "op_element") +]_[+ (get "io_element") +]_or_die */
688[+ ENDFOR io_type +][+ ENDFOR read_op +]
689
690void
691test_read_raw_or_die (SNDFILE *file, int pass, void *test, sf_count_t items, int line_num)
692{	sf_count_t count ;
693
694	if ((count = sf_read_raw (file, test, items)) != items)
695	{	printf ("\n\nLine %d", line_num) ;
696		if (pass > 0)
697			printf (" (pass %d)", pass) ;
698		printf (" : sf_read_raw failed with short read (%" PRId64 " => %" PRId64 ").\n", items, count) ;
699		fflush (stdout) ;
700		puts (sf_strerror (file)) ;
701		exit (1) ;
702		} ;
703
704	return ;
705} /* test_read_raw_or_die */
706
707[+ FOR write_op +]
708[+ FOR io_type +]
709void
710test_[+ (get "op_element") +]_[+ (get "io_element") +]_or_die (SNDFILE *file, int pass, const [+ (get "io_element") +] *test, sf_count_t [+ (get "count_name") +], int line_num)
711{	sf_count_t count ;
712
713	if ((count = sf_[+ (get "op_element") +]_[+ (get "io_element") +] (file, test, [+ (get "count_name") +])) != [+ (get "count_name") +])
714	{	printf ("\n\nLine %d", line_num) ;
715		if (pass > 0)
716			printf (" (pass %d)", pass) ;
717		printf (" : sf_[+ (get "op_element") +]_[+ (get "io_element") +] failed with short [+ (get "op_element") +] (%" PRId64 " => %" PRId64 ").\n",
718						[+ (get "count_name") +], count) ;
719		fflush (stdout) ;
720		puts (sf_strerror (file)) ;
721		exit (1) ;
722		} ;
723
724	return ;
725} /* test_[+ (get "op_element") +]_[+ (get "io_element") +]_or_die */
726[+ ENDFOR io_type +][+ ENDFOR write_op +]
727
728void
729test_write_raw_or_die (SNDFILE *file, int pass, const void *test, sf_count_t items, int line_num)
730{	sf_count_t count ;
731
732	if ((count = sf_write_raw (file, test, items)) != items)
733	{	printf ("\n\nLine %d", line_num) ;
734		if (pass > 0)
735			printf (" (pass %d)", pass) ;
736		printf (" : sf_write_raw failed with short write (%" PRId64 " => %" PRId64 ").\n", items, count) ;
737		fflush (stdout) ;
738		puts (sf_strerror (file)) ;
739		exit (1) ;
740		} ;
741
742	return ;
743} /* test_write_raw_or_die */
744
745
746[+ FOR io_type
747+]void
748compare_[+ (get "io_element") +]_or_die (const [+ (get "io_element") +] *expected, const [+ (get "io_element") +] *actual, unsigned count, int line_num)
749{
750	unsigned k ;
751
752	for (k = 0 ; k < count ; k++)
753		if (expected [k] != actual [k])
754		{	printf ("\n\nLine %d : Error at index %d, got " [+ (get "format_str") +] ", should be " [+ (get "format_str") +] ".\n\n", line_num, k, actual [k], expected [k]) ;
755			exit (1) ;
756			} ;
757
758	return ;
759} /* compare_[+ (get "io_element") +]_or_die */
760[+ ENDFOR io_type +]
761
762
763void
764delete_file (int format, const char *filename)
765{	char rsrc_name [512], *fname ;
766
767	unlink (filename) ;
768
769	if ((format & SF_FORMAT_TYPEMASK) != SF_FORMAT_SD2)
770		return ;
771
772	/*
773	** Now try for a resource fork stored as a separate file.
774	** Grab the un-adulterated filename again.
775	*/
776	snprintf (rsrc_name, sizeof (rsrc_name), "%s", filename) ;
777
778	if ((fname = strrchr (rsrc_name, '/')) != NULL)
779		fname ++ ;
780	else if ((fname = strrchr (rsrc_name, '\\')) != NULL)
781		fname ++ ;
782	else
783		fname = rsrc_name ;
784
785	memmove (fname + 2, fname, strlen (fname) + 1) ;
786	fname [0] = '.' ;
787	fname [1] = '_' ;
788
789	unlink (rsrc_name) ;
790} /* delete_file */
791
792int
793truncate_file_to_zero (const char * fname)
794{	FILE * file ;
795
796	if ((file = fopen (fname, "w")) == NULL)
797		return errno ;
798	fclose (file) ;
799
800	return 0 ;
801} /* truncate_file_to_zero */
802
803static int allowed_open_files = -1 ;
804
805void
806count_open_files (void)
807{
808#if OS_IS_WIN32
809	return ;
810#else
811	int k, count = 0 ;
812	struct stat statbuf ;
813
814	if (allowed_open_files > 0)
815		return ;
816
817	for (k = 0 ; k < 1024 ; k++)
818		if (fstat (k, &statbuf) == 0)
819			count ++ ;
820
821	allowed_open_files = count ;
822#endif
823} /* count_open_files */
824
825void
826increment_open_file_count (void)
827{	allowed_open_files ++ ;
828} /* increment_open_file_count */
829
830void
831check_open_file_count_or_die (int lineno)
832{
833#if OS_IS_WIN32
834	(void) lineno ;
835	return ;
836#else
837	int k, count = 0 ;
838	struct stat statbuf ;
839
840	if (allowed_open_files < 0)
841		count_open_files () ;
842
843	for (k = 0 ; k < 1024 ; k++)
844		if (fstat (k, &statbuf) == 0)
845			count ++ ;
846
847	if (count > allowed_open_files)
848	{	printf ("\nLine %d : number of open files (%d) > allowed (%d).\n\n", lineno, count, allowed_open_files) ;
849		exit (1) ;
850		} ;
851#endif
852} /* check_open_file_count_or_die */
853
854void
855write_mono_file (const char * filename, int format, int srate, float * output, int len)
856{	SNDFILE * file ;
857	SF_INFO sfinfo ;
858
859	memset (&sfinfo, 0, sizeof (sfinfo)) ;
860
861	sfinfo.samplerate = srate ;
862	sfinfo.channels = 1 ;
863	sfinfo.format = format ;
864
865	if ((file = sf_open (filename, SFM_WRITE, &sfinfo)) == NULL)
866	{	printf ("sf_open (%s) : %s\n", filename, sf_strerror (NULL)) ;
867		exit (1) ;
868		} ;
869
870	sf_write_float (file, output, len) ;
871
872	sf_close (file) ;
873} /* write_mono_file */
874
875void
876gen_lowpass_signal_float (float *data, int len)
877{	int64_t value = 0x1243456 ;
878	double sample, last_val = 0.0 ;
879	int k ;
880
881	for (k = 0 ; k < len ; k++)
882	{	/* Not a crypto quality RNG. */
883		value = (11117 * value + 211231) & 0xffffffff ;
884		value = (11117 * value + 211231) & 0xffffffff ;
885		value = (11117 * value + 211231) & 0xffffffff ;
886
887		sample = value / (0x7fffffff * 1.000001) ;
888		sample = 0.2 * sample - 0.9 * last_val ;
889
890		last_val = sample ;
891
892		data [k] = 0.5 * (sample + sin (2.0 * k * M_PI * 1.0 / 32.0)) ;
893		} ;
894
895} /* gen_lowpass_signal_float */
896
897
898/*
899**	Windows is fucked.
900**	If a file is opened R/W and data is written to it, then fstat will return
901**	the correct file length, but stat will return zero.
902*/
903
904sf_count_t
905file_length (const char * fname)
906{	struct stat data ;
907
908	if (stat (fname, &data) != 0)
909		return 0 ;
910
911	return (sf_count_t) data.st_size ;
912} /* file_length */
913
914sf_count_t
915file_length_fd (int fd)
916{	struct stat data ;
917
918	memset (&data, 0, sizeof (data)) ;
919	if (fstat (fd, &data) != 0)
920		return 0 ;
921
922	return (sf_count_t) data.st_size ;
923} /* file_length_fd */
924
925
926[+ ESAC +]
927
928