annotate src/libsamplerate-0.1.9/tests/snr_bw_test.c @ 157:570d27da3fb5

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