annotate src/libsndfile-1.0.25/tests/dft_cmp.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 <stdio.h>
Chris@0 20 #include <stdlib.h>
Chris@0 21 #include <math.h>
Chris@0 22
Chris@0 23 #include "dft_cmp.h"
Chris@0 24 #include "utils.h"
Chris@0 25
Chris@0 26 #ifndef M_PI
Chris@0 27 #define M_PI 3.14159265358979323846264338
Chris@0 28 #endif
Chris@0 29
Chris@0 30 #define DFT_SPEC_LENGTH (DFT_DATA_LENGTH / 2)
Chris@0 31
Chris@0 32 static void dft_magnitude (const double *data, double *spectrum) ;
Chris@0 33 static double calc_max_spectral_difference (const double *spec1, const double *spec2) ;
Chris@0 34
Chris@0 35 /*--------------------------------------------------------------------------------
Chris@0 36 ** Public functions.
Chris@0 37 */
Chris@0 38
Chris@0 39 double
Chris@0 40 dft_cmp_float (int linenum, const float *in_data, const float *test_data, int len, double target_snr, int allow_exit)
Chris@0 41 { static double orig [DFT_DATA_LENGTH] ;
Chris@0 42 static double test [DFT_DATA_LENGTH] ;
Chris@0 43 unsigned k ;
Chris@0 44
Chris@0 45 if (len != DFT_DATA_LENGTH)
Chris@0 46 { printf ("Error (line %d) : dft_cmp_float : Bad input array length.\n", linenum) ;
Chris@0 47 return 1 ;
Chris@0 48 } ;
Chris@0 49
Chris@0 50 for (k = 0 ; k < ARRAY_LEN (orig) ; k++)
Chris@0 51 { test [k] = test_data [k] ;
Chris@0 52 orig [k] = in_data [k] ;
Chris@0 53 } ;
Chris@0 54
Chris@0 55 return dft_cmp_double (linenum, orig, test, len, target_snr, allow_exit) ;
Chris@0 56 } /* dft_cmp_float */
Chris@0 57
Chris@0 58 double
Chris@0 59 dft_cmp_double (int linenum, const double *orig, const double *test, int len, double target_snr, int allow_exit)
Chris@0 60 { static double orig_spec [DFT_SPEC_LENGTH] ;
Chris@0 61 static double test_spec [DFT_SPEC_LENGTH] ;
Chris@0 62 double snr ;
Chris@0 63
Chris@0 64 if (! orig || ! test)
Chris@0 65 { printf ("Error (line %d) : dft_cmp_double : Bad input arrays.\n", linenum) ;
Chris@0 66 return 1 ;
Chris@0 67 } ;
Chris@0 68
Chris@0 69 if (len != DFT_DATA_LENGTH)
Chris@0 70 { printf ("Error (line %d) : dft_cmp_double : Bad input array length.\n", linenum) ;
Chris@0 71 return 1 ;
Chris@0 72 } ;
Chris@0 73
Chris@0 74 dft_magnitude (orig, orig_spec) ;
Chris@0 75 dft_magnitude (test, test_spec) ;
Chris@0 76
Chris@0 77 snr = calc_max_spectral_difference (orig_spec, test_spec) ;
Chris@0 78
Chris@0 79 if (snr > target_snr)
Chris@0 80 { printf ("\n\nLine %d: Actual SNR (% 4.1f) > target SNR (% 4.1f).\n\n", linenum, snr, target_snr) ;
Chris@0 81 oct_save_double (orig, test, len) ;
Chris@0 82 if (allow_exit)
Chris@0 83 exit (1) ;
Chris@0 84 } ;
Chris@0 85
Chris@0 86 if (snr < -500.0)
Chris@0 87 snr = -500.0 ;
Chris@0 88
Chris@0 89 return snr ;
Chris@0 90 } /* dft_cmp_double */
Chris@0 91
Chris@0 92 /*--------------------------------------------------------------------------------
Chris@0 93 ** Quick dirty calculation of magnitude spectrum for real valued data using
Chris@0 94 ** Discrete Fourier Transform. Since the data is real, the DFT is only
Chris@0 95 ** calculated for positive frequencies.
Chris@0 96 */
Chris@0 97
Chris@0 98 static void
Chris@0 99 dft_magnitude (const double *data, double *spectrum)
Chris@0 100 { static double cos_angle [DFT_DATA_LENGTH] = { 0.0 } ;
Chris@0 101 static double sin_angle [DFT_DATA_LENGTH] ;
Chris@0 102
Chris@0 103 double real_part, imag_part ;
Chris@0 104 int k, n ;
Chris@0 105
Chris@0 106 /* If sine and cosine tables haven't been initialised, do so. */
Chris@0 107 if (cos_angle [0] == 0.0)
Chris@0 108 for (n = 0 ; n < DFT_DATA_LENGTH ; n++)
Chris@0 109 { cos_angle [n] = cos (2.0 * M_PI * n / DFT_DATA_LENGTH) ;
Chris@0 110 sin_angle [n] = -1.0 * sin (2.0 * M_PI * n / DFT_DATA_LENGTH) ;
Chris@0 111 } ;
Chris@0 112
Chris@0 113 /* DFT proper. Since the data is real, only generate a half spectrum. */
Chris@0 114 for (k = 1 ; k < DFT_SPEC_LENGTH ; k++)
Chris@0 115 { real_part = 0.0 ;
Chris@0 116 imag_part = 0.0 ;
Chris@0 117
Chris@0 118 for (n = 0 ; n < DFT_DATA_LENGTH ; n++)
Chris@0 119 { real_part += data [n] * cos_angle [(k * n) % DFT_DATA_LENGTH] ;
Chris@0 120 imag_part += data [n] * sin_angle [(k * n) % DFT_DATA_LENGTH] ;
Chris@0 121 } ;
Chris@0 122
Chris@0 123 spectrum [k] = sqrt (real_part * real_part + imag_part * imag_part) ;
Chris@0 124 } ;
Chris@0 125
Chris@0 126 spectrum [k] = 0.0 ;
Chris@0 127
Chris@0 128 spectrum [0] = spectrum [1] = spectrum [2] = spectrum [3] = spectrum [4] = 0.0 ;
Chris@0 129
Chris@0 130 return ;
Chris@0 131 } /* dft_magnitude */
Chris@0 132
Chris@0 133 static double
Chris@0 134 calc_max_spectral_difference (const double *orig, const double *test)
Chris@0 135 { double orig_max = 0.0, max_diff = 0.0 ;
Chris@0 136 int k ;
Chris@0 137
Chris@0 138 for (k = 0 ; k < DFT_SPEC_LENGTH ; k++)
Chris@0 139 { if (orig_max < orig [k])
Chris@0 140 orig_max = orig [k] ;
Chris@0 141 if (max_diff < fabs (orig [k] - test [k]))
Chris@0 142 max_diff = fabs (orig [k] - test [k]) ;
Chris@0 143 } ;
Chris@0 144
Chris@0 145 if (max_diff < 1e-25)
Chris@0 146 return -500.0 ;
Chris@0 147
Chris@0 148 return 20.0 * log10 (max_diff / orig_max) ;
Chris@0 149 } /* calc_max_spectral_difference */