]> iEval git - audio-libsamplerate.git/blob - libsamplerate/tests/snr_bw_test.c
5c69f7f5b3e345eaf8df190410c5c4e40abc8261
[audio-libsamplerate.git] / libsamplerate / tests / snr_bw_test.c
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
This page took 0.096106 seconds and 5 git commands to generate.