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] = 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