2
** Copyright (C) 2002-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
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.
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.
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.
29
#include <samplerate.h>
34
#define BUFFER_LEN 50000
37
#define MAX_SPEC_LEN (1<<15)
40
#define M_PI 3.14159265358979323846264338
43
#define ARRAY_LEN(x) ((int) (sizeof (x) / sizeof ((x) [0])))
52
double freqs [MAX_FREQS] ;
64
int do_bandwidth_test ;
65
SINGLE_TEST test_data [10] ;
68
static double snr_test (SINGLE_TEST *snr_test_data, int number, int converter, int verbose, double *conversion_rate) ;
69
static double find_peak (float *output, int output_len) ;
70
static double bandwidth_test (int converter, int verbose) ;
73
main (int argc, char *argv [])
74
{ CONVERTER_TEST snr_test_data [] =
76
{ SRC_ZERO_ORDER_HOLD,
79
{ { 1, { 0.01111111111 }, 3.0, 1, 29.0, 1.0 },
80
{ 1, { 0.01111111111 }, 0.6, 1, 37.0, 1.0 },
81
{ 1, { 0.01111111111 }, 0.3, 1, 37.0, 1.0 },
82
{ 1, { 0.01111111111 }, 1.0, 1, 150.0, 1.0 },
83
{ 1, { 0.01111111111 }, 1.001, 1, 38.0, 1.0 },
84
{ 2, { 0.011111, 0.324 }, 1.9999, 2, 14.0, 1.0 },
85
{ 2, { 0.012345, 0.457 }, 0.456789, 1, 32.0, 1.0 },
86
{ 1, { 0.3511111111 }, 1.33, 1, 10.0, 1.0 }
93
{ { 1, { 0.01111111111 }, 3.0, 1, 73.0, 1.0 },
94
{ 1, { 0.01111111111 }, 0.6, 1, 74.0, 1.0 },
95
{ 1, { 0.01111111111 }, 0.3, 1, 74.0, 1.0 },
96
{ 1, { 0.01111111111 }, 1.0, 1, 150.0, 1.0 },
97
{ 1, { 0.01111111111 }, 1.001, 1, 77.0, 1.0 },
98
{ 2, { 0.011111, 0.324 }, 1.9999, 2, 97.0, 0.94 },
99
{ 2, { 0.012345, 0.457 }, 0.456789, 1, 60.0, 0.96 },
100
{ 1, { 0.3511111111 }, 1.33, 1, 22.0, 0.99 }
107
{ { 1, { 0.01111111111 }, 3.0, 1, 100.0, 1.0 },
108
{ 1, { 0.01111111111 }, 0.6, 1, 100.0, 1.0 },
109
{ 1, { 0.01111111111 }, 0.3, 1, 100.0, 1.0 },
110
{ 1, { 0.01111111111 }, 1.0, 1, 150.0, 1.0 },
111
{ 1, { 0.01111111111 }, 1.001, 1, 100.0, 1.0 },
112
{ 2, { 0.011111, 0.324 }, 1.9999, 2, 97.0, 1.0 },
113
{ 2, { 0.012345, 0.457 }, 0.456789, 1, 100.0, 0.5 },
114
{ 2, { 0.011111, 0.45 }, 0.6, 1, 97.0, 0.5 },
115
{ 1, { 0.3511111111 }, 1.33, 1, 97.0, 1.0 }
119
{ SRC_SINC_MEDIUM_QUALITY,
122
{ { 1, { 0.01111111111 }, 3.0, 1, 100.0, 1.0 },
123
{ 1, { 0.01111111111 }, 0.6, 1, 100.0, 1.0 },
124
{ 1, { 0.01111111111 }, 0.3, 1, 100.0, 1.0 },
125
{ 1, { 0.01111111111 }, 1.0, 1, 149.0, 1.0 },
126
{ 1, { 0.01111111111 }, 1.001, 1, 100.0, 1.0 },
127
{ 2, { 0.011111, 0.324 }, 1.9999, 2, 97.0, 1.0 },
128
{ 2, { 0.012345, 0.457 }, 0.456789, 1, 100.0, 0.5 },
129
{ 2, { 0.011111, 0.45 }, 0.6, 1, 97.0, 0.5 },
130
{ 1, { 0.43111111111 }, 1.33, 1, 97.0, 1.0 }
134
{ SRC_SINC_BEST_QUALITY,
137
{ { 1, { 0.01111111111 }, 3.0, 1, 100.0, 1.0 },
138
{ 1, { 0.01111111111 }, 0.6, 1, 100.0, 1.0 },
139
{ 1, { 0.01111111111 }, 0.3, 1, 100.0, 1.0 },
140
{ 1, { 0.01111111111 }, 1.0, 1, 154.0, 1.0 },
141
{ 1, { 0.01111111111 }, 1.001, 1, 100.0, 1.0 },
142
{ 2, { 0.011111, 0.324 }, 1.9999, 2, 97.0, 1.0 },
143
{ 2, { 0.012345, 0.457 }, 0.456789, 1, 100.0, 0.5 },
144
{ 2, { 0.011111, 0.45 }, 0.6, 1, 97.0, 0.5 },
145
{ 1, { 0.47111111111 }, 1.33, 1, 97.0, 1.0 }
149
} ; /* snr_test_data */
151
double best_snr, snr, freq3dB, conversion_rate, worst_conv_rate ;
152
int j, k, converter, verbose = 0 ;
154
/* Force output of the Electric Fence banner message. */
155
force_efence_banner () ;
157
if (argc == 2 && strcmp (argv [1], "--verbose") == 0)
162
for (j = 0 ; j < ARRAY_LEN (snr_test_data) ; j++)
163
{ best_snr = 5000.0 ;
164
worst_conv_rate = 1e200 ;
166
converter = snr_test_data [j].converter ;
168
printf (" Converter %d : %s\n", converter, src_get_name (converter)) ;
169
printf (" %s\n", src_get_description (converter)) ;
171
for (k = 0 ; k < snr_test_data [j].tests ; k++)
172
{ snr = snr_test (&(snr_test_data [j].test_data [k]), k, converter, verbose, &conversion_rate) ;
175
if (worst_conv_rate > conversion_rate)
176
worst_conv_rate = conversion_rate ;
179
printf (" Worst case Signal-to-Noise Ratio : %.2f dB.\n", best_snr) ;
180
printf (" Worst case conversion rate : %.0f samples/sec.\n", worst_conv_rate) ;
182
if (snr_test_data [j].do_bandwidth_test == BOOLEAN_FALSE)
183
{ puts (" Bandwith test not performed on this converter.\n") ;
187
freq3dB = bandwidth_test (converter, verbose) ;
189
printf (" Measured -3dB rolloff point : %5.2f %%.\n\n", freq3dB) ;
195
/*==============================================================================
199
snr_test (SINGLE_TEST *test_data, int number, int converter, int verbose, double *conversion_rate)
200
{ static float data [BUFFER_LEN + 1] ;
201
static float output [MAX_SPEC_LEN] ;
203
SRC_STATE *src_state ;
206
clock_t start_clock, clock_time ;
208
double output_peak, snr ;
209
int k, output_len, input_len, error ;
212
{ printf ("\tSignal-to-Noise Ratio Test %d.\n"
213
"\t=====================================\n", number) ;
214
printf ("\tFrequencies : [ ") ;
215
for (k = 0 ; k < test_data->freq_count ; k++)
216
printf ("%6.4f ", test_data->freqs [k]) ;
218
printf ("]\n\tSRC Ratio : %8.4f\n", test_data->src_ratio) ;
221
{ printf ("\tSignal-to-Noise Ratio Test %d : ", number) ;
225
/* Set up the output array. */
226
if (test_data->src_ratio >= 1.0)
227
{ output_len = MAX_SPEC_LEN ;
228
input_len = (int) ceil (MAX_SPEC_LEN / test_data->src_ratio) ;
229
if (input_len > BUFFER_LEN)
230
input_len = BUFFER_LEN ;
233
{ input_len = BUFFER_LEN ;
234
output_len = (int) ceil (BUFFER_LEN * test_data->src_ratio) ;
235
output_len &= ((-1) << 4) ;
236
if (output_len > MAX_SPEC_LEN)
237
output_len = MAX_SPEC_LEN ;
238
input_len = (int) ceil (output_len / test_data->src_ratio) ;
241
memset (output, 0, sizeof (output)) ;
243
/* Generate input data array. */
244
gen_windowed_sines (data, input_len, test_data->freqs, test_data->freq_count) ;
246
/* Perform sample rate conversion. */
247
if ((src_state = src_new (converter, 1, &error)) == NULL)
248
{ printf ("\n\nLine %d : src_new() failed : %s.\n\n", __LINE__, src_strerror (error)) ;
252
src_data.end_of_input = 1 ; /* Only one buffer worth of input. */
254
src_data.data_in = data ;
255
src_data.input_frames = input_len ;
257
src_data.src_ratio = test_data->src_ratio ;
259
src_data.data_out = output ;
260
src_data.output_frames = output_len ;
262
start_clock = clock () ;
263
if ((error = src_process (src_state, &src_data)))
264
{ printf ("\n\nLine %d : %s\n\n", __LINE__, src_strerror (error)) ;
268
clock_time = clock () - start_clock ;
270
src_state = src_delete (src_state) ;
275
*conversion_rate = (1.0 * output_len * CLOCKS_PER_SEC) / clock_time ;
276
if (test_data->src_ratio < 1.0)
277
*conversion_rate /= test_data->src_ratio ;
280
{ printf ("\tOutput Rate : %.0f samples/sec\n", *conversion_rate) ;
282
printf ("\tOutput Len : %ld\n", src_data.output_frames_gen) ;
285
if (abs (src_data.output_frames_gen - output_len) > 4)
286
{ printf ("\n\nLine %d : output data length should be %d.\n\n", __LINE__, output_len) ;
290
/* Check output peak. */
291
output_peak = find_peak (output, src_data.output_frames_gen) ;
294
printf ("\tOutput Peak : %6.4f\n", output_peak) ;
296
if (fabs (output_peak - test_data->peak_value) > 0.01)
297
{ printf ("\n\nLine %d : output peak (%6.4f) should be %6.4f\n\n", __LINE__, output_peak, test_data->peak_value) ;
298
save_oct_float ("snr_test.dat", data, BUFFER_LEN, output, output_len) ;
302
/* Calculate signal-to-noise ratio. */
303
snr = calculate_snr (output, src_data.output_frames_gen) ;
306
{ /* An error occurred. */
307
save_oct_float ("snr_test.dat", data, BUFFER_LEN, output, src_data.output_frames_gen) ;
312
printf ("\tSNR Ratio : %.2f dB\n", snr) ;
314
if (snr < test_data->snr)
315
{ printf ("\n\nLine %d : SNR (%5.2f) should be > %6.2f dB\n\n", __LINE__, snr, test_data->snr) ;
320
puts ("\t-------------------------------------\n\tPass\n") ;
328
find_peak (float *data, int len)
329
{ double peak = 0.0 ;
332
for (k = 0 ; k < len ; k++)
333
if (fabs (data [k]) > peak)
334
peak = fabs (data [k]) ;
341
find_attenuation (double freq, int converter, int verbose)
342
{ static float input [BUFFER_LEN] ;
343
static float output [2 * BUFFER_LEN] ;
349
gen_windowed_sines (input, BUFFER_LEN, &freq, 1) ;
351
src_data.end_of_input = 1 ; /* Only one buffer worth of input. */
353
src_data.data_in = input ;
354
src_data.input_frames = BUFFER_LEN ;
356
src_data.src_ratio = 1.999 ;
358
src_data.data_out = output ;
359
src_data.output_frames = ARRAY_LEN (output) ;
361
if ((error = src_simple (&src_data, converter, 1)))
362
{ printf ("\n\nLine %d : %s\n\n", __LINE__, src_strerror (error)) ;
366
output_peak = find_peak (output, ARRAY_LEN (output)) ;
369
printf ("\tFreq : %6f InPeak : %6f OutPeak : %6f Atten : %6.2f dB\n",
370
freq, 1.0, output_peak, 20.0 * log10 (1.0 / output_peak)) ;
372
return 20.0 * log10 (1.0 / output_peak) ;
373
} /* find_attenuation */
376
bandwidth_test (int converter, int verbose)
377
{ double f1, f2, a1, a2 ;
381
a1 = find_attenuation (f1, converter, verbose) ;
384
a2 = find_attenuation (f2, converter, verbose) ;
386
if (a1 > 3.0 || a2 < 3.0)
387
{ printf ("\n\nLine %d : cannot bracket 3dB point.\n\n", __LINE__) ;
391
while (a2 - a1 > 1.0)
392
{ freq = f1 + 0.5 * (f2 - f1) ;
393
atten = find_attenuation (freq, converter, verbose) ;
405
freq = f1 + (3.0 - a1) * (f2 - f1) / (a2 - a1) ;
407
return 200.0 * freq ;
408
} /* bandwidth_test */
410
#else /* (HAVE_FFTW3) == 0 */
412
/* Alternative main function when librfftw is not available. */
417
"****************************************************************\n"
418
" This test cannot be run without FFTW (http://www.fftw.org/).\n"
419
" Both the real and the complex versions of the library are\n"
422
#if (defined (WIN32) || defined (_WIN32))
423
puts (" It it not known whether FFTW compiles and runs on Win32.") ;
425
puts ("****************************************************************\n") ;
433
** Do not edit or modify anything in this comment block.
434
** The arch-tag line is a file identity tag for the GNU Arch
435
** revision control system.
437
** arch-tag: c31544f5-637f-4640-953b-1f3f71de11b6