• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ** Copyright (C) 2007-2018 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 <string.h>
24 #if HAVE_UNISTD_H
25 #include <unistd.h>
26 #else
27 #include "sf_unistd.h"
28 #endif
29 
30 #include <math.h>
31 #include <inttypes.h>
32 #include <sndfile.h>
33 
34 #include "utils.h"
35 
36 #define	SAMPLE_RATE			48000
37 #define	DATA_LENGTH			(SAMPLE_RATE / 8)
38 
39 typedef union
40 {	double d [DATA_LENGTH] ;
41 	float f [DATA_LENGTH] ;
42 	int i [DATA_LENGTH] ;
43 	short s [DATA_LENGTH] ;
44 } BUFFER ;
45 
46 static BUFFER data_out ;
47 static BUFFER data_in ;
48 
49 static void
ogg_opus_short_test(void)50 ogg_opus_short_test (void)
51 {	const char * filename = "ogg_opus_short.opus" ;
52 
53 	SNDFILE * file ;
54 	SF_INFO sfinfo ;
55 	short seek_data [10] ;
56 	unsigned k ;
57 
58 	print_test_name ("ogg_opus_short_test", filename) ;
59 
60 	/* Generate float data. */
61 	gen_windowed_sine_float (data_out.f, ARRAY_LEN (data_out.f), 1.0 * 0x7F00) ;
62 
63 	/* Convert to short. */
64 	for (k = 0 ; k < ARRAY_LEN (data_out.s) ; k++)
65 		data_out.s [k] = (short) lrintf (data_out.f [k]) ;
66 
67 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
68 
69 	/* Set up output file type. */
70 	sfinfo.format = SF_FORMAT_OGG | SF_FORMAT_OPUS ;
71 	sfinfo.channels = 1 ;
72 	sfinfo.samplerate = SAMPLE_RATE ;
73 
74 	/* Write the output file. */
75 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ;
76 	test_write_short_or_die (file, 0, data_out.s, ARRAY_LEN (data_out.s), __LINE__) ;
77 	sf_close (file) ;
78 
79 	/* Read the file in again. */
80 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
81 
82 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ;
83 	test_read_short_or_die (file, 0, data_in.s, ARRAY_LEN (data_in.s), __LINE__) ;
84 	sf_close (file) ;
85 
86 	puts ("ok") ;
87 
88 	/* Test seeking. */
89 	print_test_name ("ogg_opus_seek_test", filename) ;
90 
91 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ;
92 
93 	test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ;
94 	test_read_short_or_die (file, 0, seek_data, ARRAY_LEN (seek_data), __LINE__) ;
95 	compare_short_or_die (seek_data, data_in.s + 10, ARRAY_LEN (seek_data), __LINE__) ;
96 
97 	/* Test seek to end of file. */
98 	test_seek_or_die (file, 0, SEEK_END, sfinfo.frames, sfinfo.channels, __LINE__) ;
99 
100 	sf_close (file) ;
101 
102 	puts ("ok") ;
103 
104 	unlink (filename) ;
105 } /* ogg_opus_short_test */
106 
107 static void
ogg_opus_int_test(void)108 ogg_opus_int_test (void)
109 {	const char * filename = "ogg_opus_int.opus" ;
110 
111 	SNDFILE * file ;
112 	SF_INFO sfinfo ;
113 	int seek_data [10] ;
114 	unsigned k ;
115 
116 	print_test_name ("ogg_opus_int_test", filename) ;
117 
118 	/* Generate float data. */
119 	gen_windowed_sine_float (data_out.f, ARRAY_LEN (data_out.f), 1.0 * 0x7FFF0000) ;
120 
121 	/* Convert to integer. */
122 	for (k = 0 ; k < ARRAY_LEN (data_out.i) ; k++)
123 		data_out.i [k] = lrintf (data_out.f [k]) ;
124 
125 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
126 
127 	/* Set up output file type. */
128 	sfinfo.format = SF_FORMAT_OGG | SF_FORMAT_OPUS ;
129 	sfinfo.channels = 1 ;
130 	sfinfo.samplerate = SAMPLE_RATE ;
131 
132 	/* Write the output file. */
133 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ;
134 	test_write_int_or_die (file, 0, data_out.i, ARRAY_LEN (data_out.i), __LINE__) ;
135 	sf_close (file) ;
136 
137 	/* Read the file in again. */
138 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
139 
140 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ;
141 	test_read_int_or_die (file, 0, data_in.i, ARRAY_LEN (data_in.i), __LINE__) ;
142 	sf_close (file) ;
143 
144 	puts ("ok") ;
145 
146 	/* Test seeking. */
147 	print_test_name ("ogg_opus_seek_test", filename) ;
148 
149 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ;
150 
151 	test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ;
152 	test_read_int_or_die (file, 0, seek_data, ARRAY_LEN (seek_data), __LINE__) ;
153 	compare_int_or_die (seek_data, data_in.i + 10, ARRAY_LEN (seek_data), __LINE__) ;
154 
155 	sf_close (file) ;
156 
157 	puts ("ok") ;
158 
159 	unlink (filename) ;
160 } /* ogg_opus_int_test */
161 
162 static void
ogg_opus_float_test(void)163 ogg_opus_float_test (void)
164 {	const char * filename = "ogg_opus_float.opus" ;
165 
166 	SNDFILE * file ;
167 	SF_INFO sfinfo ;
168 	float seek_data [10] ;
169 
170 	print_test_name ("ogg_opus_float_test", filename) ;
171 
172 	gen_windowed_sine_float (data_out.f, ARRAY_LEN (data_out.f), 0.95) ;
173 
174 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
175 
176 	/* Set up output file type. */
177 	sfinfo.format = SF_FORMAT_OGG | SF_FORMAT_OPUS ;
178 	sfinfo.channels = 1 ;
179 	sfinfo.samplerate = SAMPLE_RATE ;
180 
181 	/* Write the output file. */
182 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ;
183 	test_write_float_or_die (file, 0, data_out.f, ARRAY_LEN (data_out.f), __LINE__) ;
184 	sf_close (file) ;
185 
186 	/* Read the file in again. */
187 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
188 
189 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ;
190 	test_read_float_or_die (file, 0, data_in.f, ARRAY_LEN (data_in.f), __LINE__) ;
191 	sf_close (file) ;
192 
193 	puts ("ok") ;
194 
195 	/* Test seeking. */
196 	print_test_name ("ogg_opus_seek_test", filename) ;
197 
198 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ;
199 
200 	test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ;
201 	test_read_float_or_die (file, 0, seek_data, ARRAY_LEN (seek_data), __LINE__) ;
202 	compare_float_or_die (seek_data, data_in.f + 10, ARRAY_LEN (seek_data), __LINE__) ;
203 
204 	sf_close (file) ;
205 
206 	puts ("ok") ;
207 
208 	unlink (filename) ;
209 } /* ogg_opus_float_test */
210 
211 static void
ogg_opus_double_test(void)212 ogg_opus_double_test (void)
213 {	const char * filename = "ogg_opus_double.opus" ;
214 
215 	SNDFILE * file ;
216 	SF_INFO sfinfo ;
217 	double seek_data [10] ;
218 
219 	print_test_name ("ogg_opus_double_test", filename) ;
220 
221 	gen_windowed_sine_double (data_out.d, ARRAY_LEN (data_out.d), 0.95) ;
222 
223 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
224 
225 	/* Set up output file type. */
226 	sfinfo.format = SF_FORMAT_OGG | SF_FORMAT_OPUS ;
227 	sfinfo.channels = 1 ;
228 	sfinfo.samplerate = SAMPLE_RATE ;
229 
230 	/* Write the output file. */
231 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ;
232 	test_write_double_or_die (file, 0, data_out.d, ARRAY_LEN (data_out.d), __LINE__) ;
233 	sf_close (file) ;
234 
235 	/* Read the file in again. */
236 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
237 
238 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ;
239 	test_read_double_or_die (file, 0, data_in.d, ARRAY_LEN (data_in.d), __LINE__) ;
240 	sf_close (file) ;
241 
242 	puts ("ok") ;
243 
244 	/* Test seeking. */
245 	print_test_name ("ogg_opus_seek_test", filename) ;
246 
247 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ;
248 
249 	test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ;
250 	test_read_double_or_die (file, 0, seek_data, ARRAY_LEN (seek_data), __LINE__) ;
251 	compare_double_or_die (seek_data, data_in.d + 10, ARRAY_LEN (seek_data), __LINE__) ;
252 
253 	sf_close (file) ;
254 
255 	puts ("ok") ;
256 
257 	unlink (filename) ;
258 } /* ogg_opus_double_test */
259 
260 
261 static void
ogg_opus_stereo_seek_test(const char * filename,int format)262 ogg_opus_stereo_seek_test (const char * filename, int format)
263 {	static float data [SAMPLE_RATE] ;
264 	static float stereo_out [SAMPLE_RATE * 2] ;
265 
266 	SNDFILE * file ;
267 	SF_INFO sfinfo ;
268 	sf_count_t pos ;
269 	unsigned k ;
270 
271 	print_test_name (__func__, filename) ;
272 
273 	gen_windowed_sine_float (data, ARRAY_LEN (data), 0.95) ;
274 	for (k = 0 ; k < ARRAY_LEN (data) ; k++)
275 	{	stereo_out [2 * k] = data [k] ;
276 		stereo_out [2 * k + 1] = data [ARRAY_LEN (data) - k - 1] ;
277 		} ;
278 
279 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
280 
281 	/* Set up output file type. */
282 	sfinfo.format = format ;
283 	sfinfo.channels = 2 ;
284 	sfinfo.samplerate = SAMPLE_RATE ;
285 
286 	/* Write the output file. */
287 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ;
288 	test_write_float_or_die (file, 0, stereo_out, ARRAY_LEN (stereo_out), __LINE__) ;
289 	sf_close (file) ;
290 
291 	/* Open file in again for reading. */
292 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
293 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ;
294 
295 	/* Read in the whole file. */
296 	test_read_float_or_die (file, 0, stereo_out, ARRAY_LEN (stereo_out), __LINE__) ;
297 
298 	/* Now hammer seeking code. */
299 	test_seek_or_die (file, 234, SEEK_SET, 234, sfinfo.channels, __LINE__) ;
300 	test_readf_float_or_die (file, 0, data, 10, __LINE__) ;
301 	compare_float_or_die (data, stereo_out + (234 * sfinfo.channels), 10, __LINE__) ;
302 
303 	test_seek_or_die (file, 442, SEEK_SET, 442, sfinfo.channels, __LINE__) ;
304 	test_readf_float_or_die (file, 0, data, 10, __LINE__) ;
305 	compare_float_or_die (data, stereo_out + (442 * sfinfo.channels), 10, __LINE__) ;
306 
307 	test_seek_or_die (file, 12, SEEK_CUR, 442 + 10 + 12, sfinfo.channels, __LINE__) ;
308 	test_readf_float_or_die (file, 0, data, 10, __LINE__) ;
309 	compare_float_or_die (data, stereo_out + ((442 + 10 + 12) * sfinfo.channels), 10, __LINE__) ;
310 
311 	test_seek_or_die (file, 12, SEEK_CUR, 442 + 20 + 24, sfinfo.channels, __LINE__) ;
312 	test_readf_float_or_die (file, 0, data, 10, __LINE__) ;
313 	compare_float_or_die (data, stereo_out + ((442 + 20 + 24) * sfinfo.channels), 10, __LINE__) ;
314 
315 	pos = 500 - sfinfo.frames ;
316 	test_seek_or_die (file, pos, SEEK_END, 500, sfinfo.channels, __LINE__) ;
317 	test_readf_float_or_die (file, 0, data, 10, __LINE__) ;
318 	compare_float_or_die (data, stereo_out + (500 * sfinfo.channels), 10, __LINE__) ;
319 
320 	pos = 10 - sfinfo.frames ;
321 	test_seek_or_die (file, pos, SEEK_END, 10, sfinfo.channels, __LINE__) ;
322 	test_readf_float_or_die (file, 0, data, 10, __LINE__) ;
323 	compare_float_or_die (data, stereo_out + (10 * sfinfo.channels), 10, __LINE__) ;
324 
325 	sf_close (file) ;
326 
327 	puts ("ok") ;
328 	unlink (filename) ;
329 } /* ogg_opus_stereo_seek_test */
330 
331 
332 static void
ogg_opus_original_samplerate_test(void)333 ogg_opus_original_samplerate_test (void)
334 {	const char * filename = "ogg_opus_original_samplerate.opus" ;
335 
336 	SNDFILE * file ;
337 	SF_INFO sfinfo ;
338 	int original_samplerate = 54321 ;
339 	sf_count_t frames ;
340 
341 	print_test_name ("ogg_opus_original_samplerate_test", filename) ;
342 
343 	gen_windowed_sine_double (data_out.d, ARRAY_LEN (data_out.d), 0.95) ;
344 
345 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
346 
347 	/* Set up output file type. */
348 	sfinfo.format = SF_FORMAT_OGG | SF_FORMAT_OPUS ;
349 	sfinfo.channels = 1 ;
350 	sfinfo.samplerate = SAMPLE_RATE ;
351 
352 	/* Write the output file. */
353 	file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ;
354 	if (sf_command (file, SFC_SET_ORIGINAL_SAMPLERATE, &original_samplerate, sizeof (original_samplerate)) != SF_TRUE)
355 	{	printf ("\nCommand SFC_SET_ORIGINAL_SAMPLERATE failed!\n") ;
356 		exit (1) ;
357 		} ;
358 	test_write_double_or_die (file, 0, data_out.d, ARRAY_LEN (data_out.d), __LINE__) ;
359 	if (sf_command (file, SFC_SET_ORIGINAL_SAMPLERATE, &original_samplerate, sizeof (original_samplerate)) != SF_FALSE)
360 	{	printf ("\nCommand SFC_SET_ORIGINAL_SAMPLERATE succeeded when it should have failed!") ;
361 		exit (1) ;
362 		} ;
363 	sf_close (file) ;
364 
365 	/* Read the file in again. */
366 	memset (&sfinfo, 0, sizeof (sfinfo)) ;
367 
368 	original_samplerate = 0 ;
369 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ;
370 	if (sf_command (file, SFC_GET_ORIGINAL_SAMPLERATE, &original_samplerate, sizeof (original_samplerate)) != SF_TRUE
371 		|| original_samplerate != 54321)
372 	{	printf ("\nCommand SFC_GET_ORIGINAL_SAMPLERATE failed!\n") ;
373 		exit (1) ;
374 		} ;
375 	test_read_double_or_die (file, 0, data_in.d, 8, __LINE__) ;
376 	if (sf_command (file, SFC_SET_ORIGINAL_SAMPLERATE, &original_samplerate, sizeof (original_samplerate)) == SF_TRUE)
377 	{	printf ("\nCommand SFC_SET_ORIGINAL_SAMPLERATE succeeded when it should have failed!\n") ;
378 		exit (1) ;
379 		} ;
380 	sf_close (file) ;
381 
382 	/* Test changing the decoder. */
383 	file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ;
384 	frames = sfinfo.frames ;
385 	original_samplerate = 16000 ;
386 	if (sf_command (file, SFC_SET_ORIGINAL_SAMPLERATE, &original_samplerate, sizeof (original_samplerate)) != SF_TRUE)
387 	{	printf ("\nCommand SFC_SET_ORIGINAL_SAMPLERATE failed!\n") ;
388 		exit (1) ;
389 		} ;
390 	if (sf_command (file, SFC_GET_CURRENT_SF_INFO, &sfinfo, sizeof (sfinfo)))
391 	{	printf ("\nCommand SFC_GET_CURRENT_SF_INFO failed!\n") ;
392 		exit (1) ;
393 		} ;
394 	if (frames / (48000 / 16000) != sfinfo.frames)
395 	{	printf ("\nIncorrect frame count! (%" PRId64 " vs %" PRId64")\n", frames / (48000 / 16000), sfinfo.frames) ;
396 		exit (1) ;
397 		} ;
398 	test_read_double_or_die (file, 0, data_out.d, sfinfo.frames, __LINE__) ;
399 
400 	sf_close (file) ;
401 
402 	puts ("ok") ;
403 
404 	unlink (filename) ;
405 } /* ogg_opus_original_samplerate_test */
406 
407 
408 int
main(void)409 main (void)
410 {
411 	if (HAVE_EXTERNAL_XIPH_LIBS)
412 	{	ogg_opus_short_test () ;
413 		ogg_opus_int_test () ;
414 		ogg_opus_float_test () ;
415 		ogg_opus_double_test () ;
416 
417 		ogg_opus_stereo_seek_test ("ogg_opus_seek.opus", SF_FORMAT_OGG | SF_FORMAT_OPUS) ;
418 		ogg_opus_original_samplerate_test () ;
419 		}
420 	else
421 		puts ("    No Ogg/Opus tests because Ogg/Opus support was not compiled in.") ;
422 
423 	return 0 ;
424 } /* main */
425