annotate src/libsamplerate-0.1.9/tests/snr_bw_test.c @ 56:af97cad61ff0

Add updated build of PortAudio for OSX
author Chris Cannam <cannam@all-day-breakfast.com>
date Tue, 03 Jan 2017 15:10:52 +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