Mercurial > hg > sv-dependency-builds
comparison src/libsamplerate-0.1.9/tests/snr_bw_test.c @ 41:481f5f8c5634
Current libsamplerate source
author | Chris Cannam |
---|---|
date | Tue, 18 Oct 2016 13:24:45 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
40:1df64224f5ac | 41:481f5f8c5634 |
---|---|
1 /* | |
2 ** Copyright (c) 2002-2016, Erik de Castro Lopo <erikd@mega-nerd.com> | |
3 ** All rights reserved. | |
4 ** | |
5 ** This code is released under 2-clause BSD license. Please see the | |
6 ** file at : https://github.com/erikd/libsamplerate/blob/master/COPYING | |
7 */ | |
8 | |
9 #include "config.h" | |
10 | |
11 #include <stdio.h> | |
12 #include <stdlib.h> | |
13 #include <string.h> | |
14 #include <math.h> | |
15 #include <time.h> | |
16 | |
17 #if (HAVE_FFTW3) | |
18 | |
19 #include <fftw3.h> | |
20 | |
21 #include <samplerate.h> | |
22 | |
23 #include "util.h" | |
24 | |
25 #define BUFFER_LEN 50000 | |
26 #define MAX_FREQS 4 | |
27 #define MAX_RATIOS 6 | |
28 #define MAX_SPEC_LEN (1<<15) | |
29 | |
30 #ifndef M_PI | |
31 #define M_PI 3.14159265358979323846264338 | |
32 #endif | |
33 | |
34 enum | |
35 { BOOLEAN_FALSE = 0, | |
36 BOOLEAN_TRUE = 1 | |
37 } ; | |
38 | |
39 typedef struct | |
40 { int freq_count ; | |
41 double freqs [MAX_FREQS] ; | |
42 | |
43 double src_ratio ; | |
44 int pass_band_peaks ; | |
45 | |
46 double snr ; | |
47 double peak_value ; | |
48 } SINGLE_TEST ; | |
49 | |
50 typedef struct | |
51 { int converter ; | |
52 int tests ; | |
53 int do_bandwidth_test ; | |
54 SINGLE_TEST test_data [10] ; | |
55 } CONVERTER_TEST ; | |
56 | |
57 static double snr_test (SINGLE_TEST *snr_test_data, int number, int converter, int verbose) ; | |
58 static double find_peak (float *output, int output_len) ; | |
59 static double bandwidth_test (int converter, int verbose) ; | |
60 | |
61 int | |
62 main (int argc, char *argv []) | |
63 { CONVERTER_TEST snr_test_data [] = | |
64 { | |
65 { SRC_ZERO_ORDER_HOLD, | |
66 8, | |
67 BOOLEAN_FALSE, | |
68 { { 1, { 0.01111111111 }, 3.0, 1, 28.0, 1.0 }, | |
69 { 1, { 0.01111111111 }, 0.6, 1, 36.0, 1.0 }, | |
70 { 1, { 0.01111111111 }, 0.3, 1, 36.0, 1.0 }, | |
71 { 1, { 0.01111111111 }, 1.0, 1, 150.0, 1.0 }, | |
72 { 1, { 0.01111111111 }, 1.001, 1, 38.0, 1.0 }, | |
73 { 2, { 0.011111, 0.324 }, 1.9999, 2, 14.0, 1.0 }, | |
74 { 2, { 0.012345, 0.457 }, 0.456789, 1, 12.0, 1.0 }, | |
75 { 1, { 0.3511111111 }, 1.33, 1, 10.0, 1.0 } | |
76 } | |
77 }, | |
78 | |
79 { SRC_LINEAR, | |
80 8, | |
81 BOOLEAN_FALSE, | |
82 { { 1, { 0.01111111111 }, 3.0, 1, 73.0, 1.0 }, | |
83 { 1, { 0.01111111111 }, 0.6, 1, 73.0, 1.0 }, | |
84 { 1, { 0.01111111111 }, 0.3, 1, 73.0, 1.0 }, | |
85 { 1, { 0.01111111111 }, 1.0, 1, 150.0, 1.0 }, | |
86 { 1, { 0.01111111111 }, 1.001, 1, 77.0, 1.0 }, | |
87 { 2, { 0.011111, 0.324 }, 1.9999, 2, 15.0, 0.94 }, | |
88 { 2, { 0.012345, 0.457 }, 0.456789, 1, 25.0, 0.96 }, | |
89 { 1, { 0.3511111111 }, 1.33, 1, 22.0, 0.99 } | |
90 } | |
91 }, | |
92 | |
93 { SRC_SINC_FASTEST, | |
94 9, | |
95 BOOLEAN_TRUE, | |
96 { { 1, { 0.01111111111 }, 3.0, 1, 100.0, 1.0 }, | |
97 { 1, { 0.01111111111 }, 0.6, 1, 99.0, 1.0 }, | |
98 { 1, { 0.01111111111 }, 0.3, 1, 100.0, 1.0 }, | |
99 { 1, { 0.01111111111 }, 1.0, 1, 150.0, 1.0 }, | |
100 { 1, { 0.01111111111 }, 1.001, 1, 100.0, 1.0 }, | |
101 { 2, { 0.011111, 0.324 }, 1.9999, 2, 97.0, 1.0 }, | |
102 { 2, { 0.012345, 0.457 }, 0.456789, 1, 100.0, 0.5 }, | |
103 { 2, { 0.011111, 0.45 }, 0.6, 1, 97.0, 0.5 }, | |
104 { 1, { 0.3511111111 }, 1.33, 1, 97.0, 1.0 } | |
105 } | |
106 }, | |
107 | |
108 { SRC_SINC_MEDIUM_QUALITY, | |
109 9, | |
110 BOOLEAN_TRUE, | |
111 { { 1, { 0.01111111111 }, 3.0, 1, 145.0, 1.0 }, | |
112 { 1, { 0.01111111111 }, 0.6, 1, 132.0, 1.0 }, | |
113 { 1, { 0.01111111111 }, 0.3, 1, 138.0, 1.0 }, | |
114 { 1, { 0.01111111111 }, 1.0, 1, 157.0, 1.0 }, | |
115 { 1, { 0.01111111111 }, 1.001, 1, 148.0, 1.0 }, | |
116 { 2, { 0.011111, 0.324 }, 1.9999, 2, 127.0, 1.0 }, | |
117 { 2, { 0.012345, 0.457 }, 0.456789, 1, 123.0, 0.5 }, | |
118 { 2, { 0.011111, 0.45 }, 0.6, 1, 126.0, 0.5 }, | |
119 { 1, { 0.43111111111 }, 1.33, 1, 121.0, 1.0 } | |
120 } | |
121 }, | |
122 | |
123 { SRC_SINC_BEST_QUALITY, | |
124 9, | |
125 BOOLEAN_TRUE, | |
126 { { 1, { 0.01111111111 }, 3.0, 1, 147.0, 1.0 }, | |
127 { 1, { 0.01111111111 }, 0.6, 1, 147.0, 1.0 }, | |
128 { 1, { 0.01111111111 }, 0.3, 1, 148.0, 1.0 }, | |
129 { 1, { 0.01111111111 }, 1.0, 1, 155.0, 1.0 }, | |
130 { 1, { 0.01111111111 }, 1.001, 1, 148.0, 1.0 }, | |
131 { 2, { 0.011111, 0.324 }, 1.9999, 2, 146.0, 1.0 }, | |
132 { 2, { 0.012345, 0.457 }, 0.456789, 1, 147.0, 0.5 }, | |
133 { 2, { 0.011111, 0.45 }, 0.6, 1, 144.0, 0.5 }, | |
134 { 1, { 0.43111111111 }, 1.33, 1, 145.0, 1.0 } | |
135 } | |
136 }, | |
137 } ; /* snr_test_data */ | |
138 | |
139 double best_snr, snr, freq3dB ; | |
140 int j, k, converter, verbose = 0 ; | |
141 | |
142 if (argc == 2 && strcmp (argv [1], "--verbose") == 0) | |
143 verbose = 1 ; | |
144 | |
145 puts ("") ; | |
146 | |
147 for (j = 0 ; j < ARRAY_LEN (snr_test_data) ; j++) | |
148 { best_snr = 5000.0 ; | |
149 | |
150 converter = snr_test_data [j].converter ; | |
151 | |
152 printf (" Converter %d : %s\n", converter, src_get_name (converter)) ; | |
153 printf (" %s\n", src_get_description (converter)) ; | |
154 | |
155 for (k = 0 ; k < snr_test_data [j].tests ; k++) | |
156 { snr = snr_test (&(snr_test_data [j].test_data [k]), k, converter, verbose) ; | |
157 if (best_snr > snr) | |
158 best_snr = snr ; | |
159 } ; | |
160 | |
161 printf (" Worst case Signal-to-Noise Ratio : %.2f dB.\n", best_snr) ; | |
162 | |
163 if (snr_test_data [j].do_bandwidth_test == BOOLEAN_FALSE) | |
164 { puts (" Bandwith test not performed on this converter.\n") ; | |
165 continue ; | |
166 } | |
167 | |
168 freq3dB = bandwidth_test (converter, verbose) ; | |
169 | |
170 printf (" Measured -3dB rolloff point : %5.2f %%.\n\n", freq3dB) ; | |
171 } ; | |
172 | |
173 fftw_cleanup () ; | |
174 | |
175 return 0 ; | |
176 } /* main */ | |
177 | |
178 /*============================================================================== | |
179 */ | |
180 | |
181 static double | |
182 snr_test (SINGLE_TEST *test_data, int number, int converter, int verbose) | |
183 { static float data [BUFFER_LEN + 1] ; | |
184 static float output [MAX_SPEC_LEN] ; | |
185 | |
186 SRC_STATE *src_state ; | |
187 SRC_DATA src_data ; | |
188 | |
189 double output_peak, snr ; | |
190 int k, output_len, input_len, error ; | |
191 | |
192 if (verbose != 0) | |
193 { printf ("\tSignal-to-Noise Ratio Test %d.\n" | |
194 "\t=====================================\n", number) ; | |
195 printf ("\tFrequencies : [ ") ; | |
196 for (k = 0 ; k < test_data->freq_count ; k++) | |
197 printf ("%6.4f ", test_data->freqs [k]) ; | |
198 | |
199 printf ("]\n\tSRC Ratio : %8.4f\n", test_data->src_ratio) ; | |
200 } | |
201 else | |
202 { printf ("\tSignal-to-Noise Ratio Test %d : ", number) ; | |
203 fflush (stdout) ; | |
204 } ; | |
205 | |
206 /* Set up the output array. */ | |
207 if (test_data->src_ratio >= 1.0) | |
208 { output_len = MAX_SPEC_LEN ; | |
209 input_len = (int) ceil (MAX_SPEC_LEN / test_data->src_ratio) ; | |
210 if (input_len > BUFFER_LEN) | |
211 input_len = BUFFER_LEN ; | |
212 } | |
213 else | |
214 { input_len = BUFFER_LEN ; | |
215 output_len = (int) ceil (BUFFER_LEN * test_data->src_ratio) ; | |
216 output_len &= ((~0u) << 4) ; | |
217 if (output_len > MAX_SPEC_LEN) | |
218 output_len = MAX_SPEC_LEN ; | |
219 input_len = (int) ceil (output_len / test_data->src_ratio) ; | |
220 } ; | |
221 | |
222 memset (output, 0, sizeof (output)) ; | |
223 | |
224 /* Generate input data array. */ | |
225 gen_windowed_sines (test_data->freq_count, test_data->freqs, 1.0, data, input_len) ; | |
226 | |
227 /* Perform sample rate conversion. */ | |
228 if ((src_state = src_new (converter, 1, &error)) == NULL) | |
229 { printf ("\n\nLine %d : src_new() failed : %s.\n\n", __LINE__, src_strerror (error)) ; | |
230 exit (1) ; | |
231 } ; | |
232 | |
233 src_data.end_of_input = 1 ; /* Only one buffer worth of input. */ | |
234 | |
235 src_data.data_in = data ; | |
236 src_data.input_frames = input_len ; | |
237 | |
238 src_data.src_ratio = test_data->src_ratio ; | |
239 | |
240 src_data.data_out = output ; | |
241 src_data.output_frames = output_len ; | |
242 | |
243 if ((error = src_process (src_state, &src_data))) | |
244 { printf ("\n\nLine %d : %s\n\n", __LINE__, src_strerror (error)) ; | |
245 exit (1) ; | |
246 } ; | |
247 | |
248 src_state = src_delete (src_state) ; | |
249 | |
250 if (verbose != 0) | |
251 printf ("\tOutput Len : %ld\n", src_data.output_frames_gen) ; | |
252 | |
253 if (abs (src_data.output_frames_gen - output_len) > 4) | |
254 { printf ("\n\nLine %d : output data length should be %d.\n\n", __LINE__, output_len) ; | |
255 exit (1) ; | |
256 } ; | |
257 | |
258 /* Check output peak. */ | |
259 output_peak = find_peak (output, src_data.output_frames_gen) ; | |
260 | |
261 if (verbose != 0) | |
262 printf ("\tOutput Peak : %6.4f\n", output_peak) ; | |
263 | |
264 if (fabs (output_peak - test_data->peak_value) > 0.01) | |
265 { printf ("\n\nLine %d : output peak (%6.4f) should be %6.4f\n\n", __LINE__, output_peak, test_data->peak_value) ; | |
266 save_oct_float ("snr_test.dat", data, BUFFER_LEN, output, output_len) ; | |
267 exit (1) ; | |
268 } ; | |
269 | |
270 /* Calculate signal-to-noise ratio. */ | |
271 snr = calculate_snr (output, src_data.output_frames_gen, test_data->pass_band_peaks) ; | |
272 | |
273 if (snr < 0.0) | |
274 { /* An error occurred. */ | |
275 save_oct_float ("snr_test.dat", data, BUFFER_LEN, output, src_data.output_frames_gen) ; | |
276 exit (1) ; | |
277 } ; | |
278 | |
279 if (verbose != 0) | |
280 printf ("\tSNR Ratio : %.2f dB\n", snr) ; | |
281 | |
282 if (snr < test_data->snr) | |
283 { printf ("\n\nLine %d : SNR (%5.2f) should be > %6.2f dB\n\n", __LINE__, snr, test_data->snr) ; | |
284 exit (1) ; | |
285 } ; | |
286 | |
287 if (verbose != 0) | |
288 puts ("\t-------------------------------------\n\tPass\n") ; | |
289 else | |
290 puts ("Pass") ; | |
291 | |
292 return snr ; | |
293 } /* snr_test */ | |
294 | |
295 static double | |
296 find_peak (float *data, int len) | |
297 { double peak = 0.0 ; | |
298 int k = 0 ; | |
299 | |
300 for (k = 0 ; k < len ; k++) | |
301 if (fabs (data [k]) > peak) | |
302 peak = fabs (data [k]) ; | |
303 | |
304 return peak ; | |
305 } /* find_peak */ | |
306 | |
307 | |
308 static double | |
309 find_attenuation (double freq, int converter, int verbose) | |
310 { static float input [BUFFER_LEN] ; | |
311 static float output [2 * BUFFER_LEN] ; | |
312 | |
313 SRC_DATA src_data ; | |
314 double output_peak ; | |
315 int error ; | |
316 | |
317 gen_windowed_sines (1, &freq, 1.0, input, BUFFER_LEN) ; | |
318 | |
319 src_data.end_of_input = 1 ; /* Only one buffer worth of input. */ | |
320 | |
321 src_data.data_in = input ; | |
322 src_data.input_frames = BUFFER_LEN ; | |
323 | |
324 src_data.src_ratio = 1.999 ; | |
325 | |
326 src_data.data_out = output ; | |
327 src_data.output_frames = ARRAY_LEN (output) ; | |
328 | |
329 if ((error = src_simple (&src_data, converter, 1))) | |
330 { printf ("\n\nLine %d : %s\n\n", __LINE__, src_strerror (error)) ; | |
331 exit (1) ; | |
332 } ; | |
333 | |
334 output_peak = find_peak (output, ARRAY_LEN (output)) ; | |
335 | |
336 if (verbose) | |
337 printf ("\tFreq : %6f InPeak : %6f OutPeak : %6f Atten : %6.2f dB\n", | |
338 freq, 1.0, output_peak, 20.0 * log10 (1.0 / output_peak)) ; | |
339 | |
340 return 20.0 * log10 (1.0 / output_peak) ; | |
341 } /* find_attenuation */ | |
342 | |
343 static double | |
344 bandwidth_test (int converter, int verbose) | |
345 { double f1, f2, a1, a2 ; | |
346 double freq, atten ; | |
347 | |
348 f1 = 0.35 ; | |
349 a1 = find_attenuation (f1, converter, verbose) ; | |
350 | |
351 f2 = 0.495 ; | |
352 a2 = find_attenuation (f2, converter, verbose) ; | |
353 | |
354 if (a1 > 3.0 || a2 < 3.0) | |
355 { printf ("\n\nLine %d : cannot bracket 3dB point.\n\n", __LINE__) ; | |
356 exit (1) ; | |
357 } ; | |
358 | |
359 while (a2 - a1 > 1.0) | |
360 { freq = f1 + 0.5 * (f2 - f1) ; | |
361 atten = find_attenuation (freq, converter, verbose) ; | |
362 | |
363 if (atten < 3.0) | |
364 { f1 = freq ; | |
365 a1 = atten ; | |
366 } | |
367 else | |
368 { f2 = freq ; | |
369 a2 = atten ; | |
370 } ; | |
371 } ; | |
372 | |
373 freq = f1 + (3.0 - a1) * (f2 - f1) / (a2 - a1) ; | |
374 | |
375 return 200.0 * freq ; | |
376 } /* bandwidth_test */ | |
377 | |
378 #else /* (HAVE_FFTW3) == 0 */ | |
379 | |
380 /* Alternative main function when librfftw is not available. */ | |
381 | |
382 int | |
383 main (void) | |
384 { puts ("\n" | |
385 "****************************************************************\n" | |
386 " This test cannot be run without FFTW (http://www.fftw.org/).\n" | |
387 " Both the real and the complex versions of the library are\n" | |
388 " required.") ; | |
389 puts ("****************************************************************\n") ; | |
390 | |
391 return 0 ; | |
392 } /* main */ | |
393 | |
394 #endif | |
395 |