cannam@85
|
1 /*
|
cannam@85
|
2 ** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
|
cannam@85
|
3 **
|
cannam@85
|
4 ** This program is free software; you can redistribute it and/or modify
|
cannam@85
|
5 ** it under the terms of the GNU General Public License as published by
|
cannam@85
|
6 ** the Free Software Foundation; either version 2 of the License, or
|
cannam@85
|
7 ** (at your option) any later version.
|
cannam@85
|
8 **
|
cannam@85
|
9 ** This program is distributed in the hope that it will be useful,
|
cannam@85
|
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
cannam@85
|
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
cannam@85
|
12 ** GNU General Public License for more details.
|
cannam@85
|
13 **
|
cannam@85
|
14 ** You should have received a copy of the GNU General Public License
|
cannam@85
|
15 ** along with this program; if not, write to the Free Software
|
cannam@85
|
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
cannam@85
|
17 */
|
cannam@85
|
18
|
cannam@85
|
19 #include <stdio.h>
|
cannam@85
|
20 #include <stdlib.h>
|
cannam@85
|
21 #include <unistd.h>
|
cannam@85
|
22 #include <string.h>
|
cannam@85
|
23 #include <ctype.h>
|
cannam@85
|
24
|
cannam@85
|
25 #include "config.h"
|
cannam@85
|
26
|
cannam@85
|
27 #if (HAVE_FFTW3 && HAVE_SNDFILE && HAVE_SYS_TIMES_H)
|
cannam@85
|
28
|
cannam@85
|
29 #include <time.h>
|
cannam@85
|
30 #include <sys/times.h>
|
cannam@85
|
31
|
cannam@85
|
32 #include <sndfile.h>
|
cannam@85
|
33 #include <math.h>
|
cannam@85
|
34 #include <sys/utsname.h>
|
cannam@85
|
35
|
cannam@85
|
36 #include "util.h"
|
cannam@85
|
37
|
cannam@85
|
38 #define MAX_FREQS 4
|
cannam@85
|
39 #define BUFFER_LEN 80000
|
cannam@85
|
40
|
cannam@85
|
41 #define SAFE_STRNCAT(dest,src,len) \
|
cannam@85
|
42 { int safe_strncat_count ; \
|
cannam@85
|
43 safe_strncat_count = (len) - strlen (dest) - 1 ; \
|
cannam@85
|
44 strncat ((dest), (src), safe_strncat_count) ; \
|
cannam@85
|
45 (dest) [(len) - 1] = 0 ; \
|
cannam@85
|
46 } ;
|
cannam@85
|
47
|
cannam@85
|
48 typedef struct
|
cannam@85
|
49 { int freq_count ;
|
cannam@85
|
50 double freqs [MAX_FREQS] ;
|
cannam@85
|
51
|
cannam@85
|
52 int output_samplerate ;
|
cannam@85
|
53 int pass_band_peaks ;
|
cannam@85
|
54
|
cannam@85
|
55 double peak_value ;
|
cannam@85
|
56 } SNR_TEST ;
|
cannam@85
|
57
|
cannam@85
|
58 typedef struct
|
cannam@85
|
59 { const char *progname ;
|
cannam@85
|
60 const char *version_cmd ;
|
cannam@85
|
61 const char *version_start ;
|
cannam@85
|
62 const char *convert_cmd ;
|
cannam@85
|
63 int format ;
|
cannam@85
|
64 } RESAMPLE_PROG ;
|
cannam@85
|
65
|
cannam@85
|
66 static char *get_progname (char *) ;
|
cannam@85
|
67 static void usage_exit (const char *, const RESAMPLE_PROG *prog, int count) ;
|
cannam@85
|
68 static void measure_program (const RESAMPLE_PROG *prog, int verbose) ;
|
cannam@85
|
69 static void generate_source_wav (const char *filename, const double *freqs, int freq_count, int format) ;
|
cannam@85
|
70 static const char* get_machine_details (void) ;
|
cannam@85
|
71
|
cannam@85
|
72 static char version_string [512] ;
|
cannam@85
|
73
|
cannam@85
|
74 int
|
cannam@85
|
75 main (int argc, char *argv [])
|
cannam@85
|
76 { static RESAMPLE_PROG resample_progs [] =
|
cannam@85
|
77 { { "sndfile-resample",
|
cannam@85
|
78 "examples/sndfile-resample --version",
|
cannam@85
|
79 "libsamplerate",
|
cannam@85
|
80 "examples/sndfile-resample --max-speed -c 0 -to %d source.wav destination.wav",
|
cannam@85
|
81 SF_FORMAT_WAV | SF_FORMAT_PCM_32
|
cannam@85
|
82 },
|
cannam@85
|
83 { "sox",
|
cannam@85
|
84 "sox -h 2>&1",
|
cannam@85
|
85 "sox",
|
cannam@85
|
86 "sox source.wav -r %d destination.wav resample 0.835",
|
cannam@85
|
87 SF_FORMAT_WAV | SF_FORMAT_PCM_32
|
cannam@85
|
88 },
|
cannam@85
|
89 { "ResampAudio",
|
cannam@85
|
90 "ResampAudio --version",
|
cannam@85
|
91 "ResampAudio",
|
cannam@85
|
92 "ResampAudio -f cutoff=0.41,atten=100,ratio=128 -s %d source.wav destination.wav",
|
cannam@85
|
93 SF_FORMAT_WAV | SF_FORMAT_PCM_32
|
cannam@85
|
94 },
|
cannam@85
|
95
|
cannam@85
|
96 /*-
|
cannam@85
|
97 { /+*
|
cannam@85
|
98 ** The Shibatch converter doesn't work for all combinations of
|
cannam@85
|
99 ** source and destination sample rates. Therefore it can't be
|
cannam@85
|
100 ** included in this test.
|
cannam@85
|
101 *+/
|
cannam@85
|
102 "shibatch",
|
cannam@85
|
103 "ssrc",
|
cannam@85
|
104 "Shibatch",
|
cannam@85
|
105 "ssrc --rate %d source.wav destination.wav",
|
cannam@85
|
106 SF_FORMAT_WAV | SF_FORMAT_PCM_32
|
cannam@85
|
107 },-*/
|
cannam@85
|
108
|
cannam@85
|
109 /*-
|
cannam@85
|
110 { /+*
|
cannam@85
|
111 ** The resample program is not able to match the bandwidth and SNR
|
cannam@85
|
112 ** specs or sndfile-resample and hence will not be tested.
|
cannam@85
|
113 *+/
|
cannam@85
|
114 "resample",
|
cannam@85
|
115 "resample -version",
|
cannam@85
|
116 "resample",
|
cannam@85
|
117 "resample -to %d source.wav destination.wav",
|
cannam@85
|
118 SF_FORMAT_WAV | SF_FORMAT_FLOAT
|
cannam@85
|
119 },-*/
|
cannam@85
|
120
|
cannam@85
|
121 /*-
|
cannam@85
|
122 { "mplayer",
|
cannam@85
|
123 "mplayer -v 2>&1",
|
cannam@85
|
124 "MPlayer ",
|
cannam@85
|
125 "mplayer -ao pcm -srate %d source.wav >/dev/null 2>&1 && mv audiodump.wav destination.wav",
|
cannam@85
|
126 SF_FORMAT_WAV | SF_FORMAT_PCM_32
|
cannam@85
|
127 },-*/
|
cannam@85
|
128
|
cannam@85
|
129 } ; /* resample_progs */
|
cannam@85
|
130
|
cannam@85
|
131 char *progname ;
|
cannam@85
|
132 int prog = 0, verbose = 0 ;
|
cannam@85
|
133
|
cannam@85
|
134 progname = get_progname (argv [0]) ;
|
cannam@85
|
135
|
cannam@85
|
136 printf ("\n %s : evaluate a sample rate converter.\n", progname) ;
|
cannam@85
|
137
|
cannam@85
|
138 if (argc == 3 && strcmp ("--verbose", argv [1]) == 0)
|
cannam@85
|
139 { verbose = 1 ;
|
cannam@85
|
140 prog = atoi (argv [2]) ;
|
cannam@85
|
141 }
|
cannam@85
|
142 else if (argc == 2)
|
cannam@85
|
143 { verbose = 0 ;
|
cannam@85
|
144 prog = atoi (argv [1]) ;
|
cannam@85
|
145 }
|
cannam@85
|
146 else
|
cannam@85
|
147 usage_exit (progname, resample_progs, ARRAY_LEN (resample_progs)) ;
|
cannam@85
|
148
|
cannam@85
|
149 if (prog < 0 || prog >= ARRAY_LEN (resample_progs))
|
cannam@85
|
150 usage_exit (progname, resample_progs, ARRAY_LEN (resample_progs)) ;
|
cannam@85
|
151
|
cannam@85
|
152 measure_program (& (resample_progs [prog]), verbose) ;
|
cannam@85
|
153
|
cannam@85
|
154 puts ("") ;
|
cannam@85
|
155
|
cannam@85
|
156 return 0 ;
|
cannam@85
|
157 } /* main */
|
cannam@85
|
158
|
cannam@85
|
159 /*==============================================================================
|
cannam@85
|
160 */
|
cannam@85
|
161
|
cannam@85
|
162 static char *
|
cannam@85
|
163 get_progname (char *progname)
|
cannam@85
|
164 { char *cptr ;
|
cannam@85
|
165
|
cannam@85
|
166 if ((cptr = strrchr (progname, '/')) != NULL)
|
cannam@85
|
167 progname = cptr + 1 ;
|
cannam@85
|
168
|
cannam@85
|
169 if ((cptr = strrchr (progname, '\\')) != NULL)
|
cannam@85
|
170 progname = cptr + 1 ;
|
cannam@85
|
171
|
cannam@85
|
172 return progname ;
|
cannam@85
|
173 } /* get_progname */
|
cannam@85
|
174
|
cannam@85
|
175 static void
|
cannam@85
|
176 usage_exit (const char *progname, const RESAMPLE_PROG *prog, int count)
|
cannam@85
|
177 { int k ;
|
cannam@85
|
178
|
cannam@85
|
179 printf ("\n Usage : %s <number>\n\n", progname) ;
|
cannam@85
|
180
|
cannam@85
|
181 puts (" where <number> specifies the program to test:\n") ;
|
cannam@85
|
182
|
cannam@85
|
183 for (k = 0 ; k < count ; k++)
|
cannam@85
|
184 printf (" %d : %s\n", k, prog [k].progname) ;
|
cannam@85
|
185
|
cannam@85
|
186 puts ("\n"
|
cannam@85
|
187 " Obviously to test a given program you have to have it available on\n"
|
cannam@85
|
188 " your system. See http://www.mega-nerd.com/SRC/quality.html for\n"
|
cannam@85
|
189 " the download location of these programs.\n") ;
|
cannam@85
|
190
|
cannam@85
|
191 exit (1) ;
|
cannam@85
|
192 } /* usage_exit */
|
cannam@85
|
193
|
cannam@85
|
194 static const char*
|
cannam@85
|
195 get_machine_details (void)
|
cannam@85
|
196 { static char namestr [256] ;
|
cannam@85
|
197
|
cannam@85
|
198 struct utsname name ;
|
cannam@85
|
199
|
cannam@85
|
200 if (uname (&name) != 0)
|
cannam@85
|
201 { snprintf (namestr, sizeof (namestr), "Unknown") ;
|
cannam@85
|
202 return namestr ;
|
cannam@85
|
203 } ;
|
cannam@85
|
204
|
cannam@85
|
205 snprintf (namestr, sizeof (namestr), "%s (%s %s %s)", name.nodename,
|
cannam@85
|
206 name.machine, name.sysname, name.release) ;
|
cannam@85
|
207
|
cannam@85
|
208 return namestr ;
|
cannam@85
|
209 } /* get_machine_details */
|
cannam@85
|
210
|
cannam@85
|
211
|
cannam@85
|
212 /*==============================================================================
|
cannam@85
|
213 */
|
cannam@85
|
214
|
cannam@85
|
215 static void
|
cannam@85
|
216 get_version_string (const RESAMPLE_PROG *prog)
|
cannam@85
|
217 { FILE *file ;
|
cannam@85
|
218 char *cptr ;
|
cannam@85
|
219
|
cannam@85
|
220 /* Default. */
|
cannam@85
|
221 snprintf (version_string, sizeof (version_string), "no version") ;
|
cannam@85
|
222
|
cannam@85
|
223 if (prog->version_cmd == NULL)
|
cannam@85
|
224 return ;
|
cannam@85
|
225
|
cannam@85
|
226 if ((file = popen (prog->version_cmd, "r")) == NULL)
|
cannam@85
|
227 return ;
|
cannam@85
|
228
|
cannam@85
|
229 while ((cptr = fgets (version_string, sizeof (version_string), file)) != NULL)
|
cannam@85
|
230 {
|
cannam@85
|
231 if (strstr (cptr, prog->version_start) != NULL)
|
cannam@85
|
232 break ;
|
cannam@85
|
233
|
cannam@85
|
234 version_string [0] = 0 ;
|
cannam@85
|
235 } ;
|
cannam@85
|
236
|
cannam@85
|
237 pclose (file) ;
|
cannam@85
|
238
|
cannam@85
|
239 /* Remove trailing newline. */
|
cannam@85
|
240 if ((cptr = strchr (version_string, '\n')) != NULL)
|
cannam@85
|
241 cptr [0] = 0 ;
|
cannam@85
|
242
|
cannam@85
|
243 /* Remove leading whitespace from version string. */
|
cannam@85
|
244 cptr = version_string ;
|
cannam@85
|
245 while (cptr [0] != 0 && isspace (cptr [0]))
|
cannam@85
|
246 cptr ++ ;
|
cannam@85
|
247
|
cannam@85
|
248 if (cptr != version_string)
|
cannam@85
|
249 strncpy (version_string, cptr, sizeof (version_string)) ;
|
cannam@85
|
250
|
cannam@85
|
251 return ;
|
cannam@85
|
252 } /* get_version_string */
|
cannam@85
|
253
|
cannam@85
|
254 static void
|
cannam@85
|
255 generate_source_wav (const char *filename, const double *freqs, int freq_count, int format)
|
cannam@85
|
256 { static float buffer [BUFFER_LEN] ;
|
cannam@85
|
257
|
cannam@85
|
258 SNDFILE *sndfile ;
|
cannam@85
|
259 SF_INFO sfinfo ;
|
cannam@85
|
260
|
cannam@85
|
261 sfinfo.channels = 1 ;
|
cannam@85
|
262 sfinfo.samplerate = 44100 ;
|
cannam@85
|
263 sfinfo.format = format ;
|
cannam@85
|
264
|
cannam@85
|
265 if ((sndfile = sf_open (filename, SFM_WRITE, &sfinfo)) == NULL)
|
cannam@85
|
266 { printf ("Line %d : cound not open '%s' : %s\n", __LINE__, filename, sf_strerror (NULL)) ;
|
cannam@85
|
267 exit (1) ;
|
cannam@85
|
268 } ;
|
cannam@85
|
269
|
cannam@85
|
270 sf_command (sndfile, SFC_SET_ADD_PEAK_CHUNK, NULL, SF_FALSE) ;
|
cannam@85
|
271
|
cannam@85
|
272 gen_windowed_sines (freq_count, freqs, 0.9, buffer, ARRAY_LEN (buffer)) ;
|
cannam@85
|
273
|
cannam@85
|
274 if (sf_write_float (sndfile, buffer, ARRAY_LEN (buffer)) != ARRAY_LEN (buffer))
|
cannam@85
|
275 { printf ("Line %d : sf_write_float short write.\n", __LINE__) ;
|
cannam@85
|
276 exit (1) ;
|
cannam@85
|
277 } ;
|
cannam@85
|
278
|
cannam@85
|
279 sf_close (sndfile) ;
|
cannam@85
|
280 } /* generate_source_wav */
|
cannam@85
|
281
|
cannam@85
|
282 static double
|
cannam@85
|
283 measure_destination_wav (char *filename, int *output_samples, int expected_peaks)
|
cannam@85
|
284 { static float buffer [250000] ;
|
cannam@85
|
285
|
cannam@85
|
286 SNDFILE *sndfile ;
|
cannam@85
|
287 SF_INFO sfinfo ;
|
cannam@85
|
288 double snr ;
|
cannam@85
|
289
|
cannam@85
|
290 if ((sndfile = sf_open (filename, SFM_READ, &sfinfo)) == NULL)
|
cannam@85
|
291 { printf ("Line %d : Cound not open '%s' : %s\n", __LINE__, filename, sf_strerror (NULL)) ;
|
cannam@85
|
292 exit (1) ;
|
cannam@85
|
293 } ;
|
cannam@85
|
294
|
cannam@85
|
295 if (sfinfo.channels != 1)
|
cannam@85
|
296 { printf ("Line %d : Bad channel count (%d). Should be 1.\n", __LINE__, sfinfo.channels) ;
|
cannam@85
|
297 exit (1) ;
|
cannam@85
|
298 } ;
|
cannam@85
|
299
|
cannam@85
|
300 if (sfinfo.frames > ARRAY_LEN (buffer))
|
cannam@85
|
301 { printf ("Line %d : Too many frames (%ld) of data in file.\n", __LINE__, (long) sfinfo.frames) ;
|
cannam@85
|
302 exit (1) ;
|
cannam@85
|
303 } ;
|
cannam@85
|
304
|
cannam@85
|
305 *output_samples = (int) sfinfo.frames ;
|
cannam@85
|
306
|
cannam@85
|
307 if (sf_read_float (sndfile, buffer, sfinfo.frames) != sfinfo.frames)
|
cannam@85
|
308 { printf ("Line %d : Bad read.\n", __LINE__) ;
|
cannam@85
|
309 exit (1) ;
|
cannam@85
|
310 } ;
|
cannam@85
|
311
|
cannam@85
|
312 sf_close (sndfile) ;
|
cannam@85
|
313
|
cannam@85
|
314 snr = calculate_snr (buffer, sfinfo.frames, expected_peaks) ;
|
cannam@85
|
315
|
cannam@85
|
316 return snr ;
|
cannam@85
|
317 } /* measure_desination_wav */
|
cannam@85
|
318
|
cannam@85
|
319 static double
|
cannam@85
|
320 measure_snr (const RESAMPLE_PROG *prog, int *output_samples, int verbose)
|
cannam@85
|
321 { static SNR_TEST snr_test [] =
|
cannam@85
|
322 {
|
cannam@85
|
323 { 1, { 0.211111111111 }, 48000, 1, 1.0 },
|
cannam@85
|
324 { 1, { 0.011111111111 }, 132301, 1, 1.0 },
|
cannam@85
|
325 { 1, { 0.111111111111 }, 92301, 1, 1.0 },
|
cannam@85
|
326 { 1, { 0.011111111111 }, 26461, 1, 1.0 },
|
cannam@85
|
327 { 1, { 0.011111111111 }, 13231, 1, 1.0 },
|
cannam@85
|
328 { 1, { 0.011111111111 }, 44101, 1, 1.0 },
|
cannam@85
|
329 { 2, { 0.311111, 0.49 }, 78199, 2, 1.0 },
|
cannam@85
|
330 { 2, { 0.011111, 0.49 }, 12345, 1, 0.5 },
|
cannam@85
|
331 { 2, { 0.0123456, 0.4 }, 20143, 1, 0.5 },
|
cannam@85
|
332 { 2, { 0.0111111, 0.4 }, 26461, 1, 0.5 },
|
cannam@85
|
333 { 1, { 0.381111111111 }, 58661, 1, 1.0 }
|
cannam@85
|
334 } ; /* snr_test */
|
cannam@85
|
335 static char command [256] ;
|
cannam@85
|
336
|
cannam@85
|
337 double snr, worst_snr = 500.0 ;
|
cannam@85
|
338 int k , retval, sample_count ;
|
cannam@85
|
339
|
cannam@85
|
340 *output_samples = 0 ;
|
cannam@85
|
341
|
cannam@85
|
342 for (k = 0 ; k < ARRAY_LEN (snr_test) ; k++)
|
cannam@85
|
343 { remove ("source.wav") ;
|
cannam@85
|
344 remove ("destination.wav") ;
|
cannam@85
|
345
|
cannam@85
|
346 if (verbose)
|
cannam@85
|
347 printf (" SNR test #%d : ", k) ;
|
cannam@85
|
348 fflush (stdout) ;
|
cannam@85
|
349 generate_source_wav ("source.wav", snr_test [k].freqs, snr_test [k].freq_count, prog->format) ;
|
cannam@85
|
350
|
cannam@85
|
351 snprintf (command, sizeof (command), prog->convert_cmd, snr_test [k].output_samplerate) ;
|
cannam@85
|
352 SAFE_STRNCAT (command, " >/dev/null 2>&1", sizeof (command)) ;
|
cannam@85
|
353 if ((retval = system (command)) != 0)
|
cannam@85
|
354 printf ("system returned %d\n", retval) ;
|
cannam@85
|
355
|
cannam@85
|
356 snr = measure_destination_wav ("destination.wav", &sample_count, snr_test->pass_band_peaks) ;
|
cannam@85
|
357
|
cannam@85
|
358 *output_samples += sample_count ;
|
cannam@85
|
359
|
cannam@85
|
360 if (fabs (snr) < fabs (worst_snr))
|
cannam@85
|
361 worst_snr = fabs (snr) ;
|
cannam@85
|
362
|
cannam@85
|
363 if (verbose)
|
cannam@85
|
364 printf ("%6.2f dB\n", snr) ;
|
cannam@85
|
365 } ;
|
cannam@85
|
366
|
cannam@85
|
367 return worst_snr ;
|
cannam@85
|
368 } /* measure_snr */
|
cannam@85
|
369
|
cannam@85
|
370 /*------------------------------------------------------------------------------
|
cannam@85
|
371 */
|
cannam@85
|
372
|
cannam@85
|
373 static double
|
cannam@85
|
374 measure_destination_peak (const char *filename)
|
cannam@85
|
375 { static float data [2 * BUFFER_LEN] ;
|
cannam@85
|
376 SNDFILE *sndfile ;
|
cannam@85
|
377 SF_INFO sfinfo ;
|
cannam@85
|
378 double peak = 0.0 ;
|
cannam@85
|
379 int k = 0 ;
|
cannam@85
|
380
|
cannam@85
|
381 if ((sndfile = sf_open (filename, SFM_READ, &sfinfo)) == NULL)
|
cannam@85
|
382 { printf ("Line %d : failed to open file %s\n", __LINE__, filename) ;
|
cannam@85
|
383 exit (1) ;
|
cannam@85
|
384 } ;
|
cannam@85
|
385
|
cannam@85
|
386 if (sfinfo.channels != 1)
|
cannam@85
|
387 { printf ("Line %d : bad channel count.\n", __LINE__) ;
|
cannam@85
|
388 exit (1) ;
|
cannam@85
|
389 } ;
|
cannam@85
|
390
|
cannam@85
|
391 if (sfinfo.frames > ARRAY_LEN (data) + 4 || sfinfo.frames < ARRAY_LEN (data) - 100)
|
cannam@85
|
392 { printf ("Line %d : bad frame count (got %d, expected %d).\n", __LINE__, (int) sfinfo.frames, ARRAY_LEN (data)) ;
|
cannam@85
|
393 exit (1) ;
|
cannam@85
|
394 } ;
|
cannam@85
|
395
|
cannam@85
|
396 if (sf_read_float (sndfile, data, sfinfo.frames) != sfinfo.frames)
|
cannam@85
|
397 { printf ("Line %d : bad read.\n", __LINE__) ;
|
cannam@85
|
398 exit (1) ;
|
cannam@85
|
399 } ;
|
cannam@85
|
400
|
cannam@85
|
401 sf_close (sndfile) ;
|
cannam@85
|
402
|
cannam@85
|
403 for (k = 0 ; k < (int) sfinfo.frames ; k++)
|
cannam@85
|
404 if (fabs (data [k]) > peak)
|
cannam@85
|
405 peak = fabs (data [k]) ;
|
cannam@85
|
406
|
cannam@85
|
407 return peak ;
|
cannam@85
|
408 } /* measure_destination_peak */
|
cannam@85
|
409
|
cannam@85
|
410 static double
|
cannam@85
|
411 find_attenuation (double freq, const RESAMPLE_PROG *prog, int verbose)
|
cannam@85
|
412 { static char command [256] ;
|
cannam@85
|
413 double output_peak ;
|
cannam@85
|
414 int retval ;
|
cannam@85
|
415 char *filename ;
|
cannam@85
|
416
|
cannam@85
|
417 filename = "destination.wav" ;
|
cannam@85
|
418
|
cannam@85
|
419 generate_source_wav ("source.wav", &freq, 1, prog->format) ;
|
cannam@85
|
420
|
cannam@85
|
421 remove (filename) ;
|
cannam@85
|
422
|
cannam@85
|
423 snprintf (command, sizeof (command), prog->convert_cmd, 88189) ;
|
cannam@85
|
424 SAFE_STRNCAT (command, " >/dev/null 2>&1", sizeof (command)) ;
|
cannam@85
|
425 if ((retval = system (command)) != 0)
|
cannam@85
|
426 printf ("system returned %d\n", retval) ;
|
cannam@85
|
427
|
cannam@85
|
428 output_peak = measure_destination_peak (filename) ;
|
cannam@85
|
429
|
cannam@85
|
430 if (verbose)
|
cannam@85
|
431 printf (" freq : %f peak : %f\n", freq, output_peak) ;
|
cannam@85
|
432
|
cannam@85
|
433 return fabs (20.0 * log10 (output_peak)) ;
|
cannam@85
|
434 } /* find_attenuation */
|
cannam@85
|
435
|
cannam@85
|
436 static double
|
cannam@85
|
437 bandwidth_test (const RESAMPLE_PROG *prog, int verbose)
|
cannam@85
|
438 { double f1, f2, a1, a2 ;
|
cannam@85
|
439 double freq, atten ;
|
cannam@85
|
440
|
cannam@85
|
441 f1 = 0.35 ;
|
cannam@85
|
442 a1 = find_attenuation (f1, prog, verbose) ;
|
cannam@85
|
443
|
cannam@85
|
444 f2 = 0.49999 ;
|
cannam@85
|
445 a2 = find_attenuation (f2, prog, verbose) ;
|
cannam@85
|
446
|
cannam@85
|
447
|
cannam@85
|
448 if (fabs (a1) < 1e-2 && a2 < 3.0)
|
cannam@85
|
449 return -1.0 ;
|
cannam@85
|
450
|
cannam@85
|
451 if (a1 > 3.0 || a2 < 3.0)
|
cannam@85
|
452 { printf ("\n\nLine %d : cannot bracket 3dB point.\n\n", __LINE__) ;
|
cannam@85
|
453 exit (1) ;
|
cannam@85
|
454 } ;
|
cannam@85
|
455
|
cannam@85
|
456 while (a2 - a1 > 1.0)
|
cannam@85
|
457 { freq = f1 + 0.5 * (f2 - f1) ;
|
cannam@85
|
458 atten = find_attenuation (freq, prog, verbose) ;
|
cannam@85
|
459
|
cannam@85
|
460 if (atten < 3.0)
|
cannam@85
|
461 { f1 = freq ;
|
cannam@85
|
462 a1 = atten ;
|
cannam@85
|
463 }
|
cannam@85
|
464 else
|
cannam@85
|
465 { f2 = freq ;
|
cannam@85
|
466 a2 = atten ;
|
cannam@85
|
467 } ;
|
cannam@85
|
468 } ;
|
cannam@85
|
469
|
cannam@85
|
470 freq = f1 + (3.0 - a1) * (f2 - f1) / (a2 - a1) ;
|
cannam@85
|
471
|
cannam@85
|
472 return 200.0 * freq ;
|
cannam@85
|
473 } /* bandwidth_test */
|
cannam@85
|
474
|
cannam@85
|
475 static void
|
cannam@85
|
476 measure_program (const RESAMPLE_PROG *prog, int verbose)
|
cannam@85
|
477 { double snr, bandwidth, conversion_rate ;
|
cannam@85
|
478 int output_samples ;
|
cannam@85
|
479 struct tms time_data ;
|
cannam@85
|
480 time_t time_now ;
|
cannam@85
|
481
|
cannam@85
|
482 printf ("\n Machine : %s\n", get_machine_details ()) ;
|
cannam@85
|
483 time_now = time (NULL) ;
|
cannam@85
|
484 printf (" Date : %s", ctime (&time_now)) ;
|
cannam@85
|
485
|
cannam@85
|
486 get_version_string (prog) ;
|
cannam@85
|
487 printf (" Program : %s\n", version_string) ;
|
cannam@85
|
488 printf (" Command : %s\n\n", prog->convert_cmd) ;
|
cannam@85
|
489
|
cannam@85
|
490 snr = measure_snr (prog, &output_samples, verbose) ;
|
cannam@85
|
491
|
cannam@85
|
492 printf (" Worst case SNR : %6.2f dB\n", snr) ;
|
cannam@85
|
493
|
cannam@85
|
494 times (&time_data) ;
|
cannam@85
|
495
|
cannam@85
|
496 conversion_rate = (1.0 * output_samples * sysconf (_SC_CLK_TCK)) / time_data.tms_cutime ;
|
cannam@85
|
497
|
cannam@85
|
498 printf (" Conversion rate : %5.0f samples/sec\n", conversion_rate) ;
|
cannam@85
|
499
|
cannam@85
|
500 bandwidth = bandwidth_test (prog, verbose) ;
|
cannam@85
|
501
|
cannam@85
|
502 if (bandwidth > 0.0)
|
cannam@85
|
503 printf (" Measured bandwidth : %5.2f %%\n", bandwidth) ;
|
cannam@85
|
504 else
|
cannam@85
|
505 printf (" Could not measure bandwidth (no -3dB point found).\n") ;
|
cannam@85
|
506
|
cannam@85
|
507 return ;
|
cannam@85
|
508 } /* measure_program */
|
cannam@85
|
509
|
cannam@85
|
510 /*##############################################################################
|
cannam@85
|
511 */
|
cannam@85
|
512
|
cannam@85
|
513 #else
|
cannam@85
|
514
|
cannam@85
|
515 int
|
cannam@85
|
516 main (void)
|
cannam@85
|
517 { puts ("\n"
|
cannam@85
|
518 "****************************************************************\n"
|
cannam@85
|
519 " This program has been compiled without :\n"
|
cannam@85
|
520 " 1) FFTW (http://www.fftw.org/).\n"
|
cannam@85
|
521 " 2) libsndfile (http://www.zip.com.au/~erikd/libsndfile/).\n"
|
cannam@85
|
522 " Without these two libraries there is not much it can do.\n"
|
cannam@85
|
523 "****************************************************************\n") ;
|
cannam@85
|
524
|
cannam@85
|
525 return 0 ;
|
cannam@85
|
526 } /* main */
|
cannam@85
|
527
|
cannam@85
|
528 #endif /* (HAVE_FFTW3 && HAVE_SNDFILE) */
|
cannam@85
|
529
|