annotate src/libsamplerate-0.1.8/tests/snr_bw_test.c @ 85:545efbb81310

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