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