annotate src/libsamplerate-0.1.9/tests/snr_bw_test.c @ 83:ae30d91d2ffe

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