SpectMorph
|
00001 /* 00002 * Copyright (C) 2010 Stefan Westerfeld 00003 * 00004 * This library is free software; you can redistribute it and/or modify it 00005 * under the terms of the GNU Lesser General Public License as published by the 00006 * Free Software Foundation; either version 3 of the License, or (at your 00007 * option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, but WITHOUT 00010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 00012 * for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public License 00015 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00016 */ 00017 00018 #ifndef SPECTMORPH_MATH_HH 00019 #define SPECTMORPH_MATH_HH 00020 00021 #include <math.h> 00022 #include <glib.h> 00023 #include <string.h> 00024 #include <stdlib.h> 00025 #include <bse/bseieee754.h> 00026 #ifdef __SSE__ 00027 #include <xmmintrin.h> 00028 #endif 00029 00030 namespace SpectMorph 00031 { 00032 00036 struct 00037 VectorSinParams 00038 { 00039 double mix_freq; 00040 double freq; 00041 double phase; 00042 double mag; 00043 00044 enum { 00045 NONE = -1, 00046 ADD = 1, 00047 REPLACE = 2 00048 } mode; 00049 00050 VectorSinParams() : 00051 mix_freq (-1), 00052 freq (-1), 00053 phase (-100), 00054 mag (-1), 00055 mode (NONE) 00056 { 00057 } 00058 }; 00059 00060 template<class Iterator, int MODE> 00061 inline void 00062 internal_fast_vector_sin (const VectorSinParams& params, Iterator begin, Iterator end) 00063 { 00064 g_return_if_fail (params.mix_freq > 0 && params.freq > 0 && params.phase > -99 && params.mag > 0); 00065 00066 const double phase_inc = params.freq / params.mix_freq * 2 * M_PI; 00067 const double inc_re = cos (phase_inc); 00068 const double inc_im = sin (phase_inc); 00069 int n = 0; 00070 00071 double state_re; 00072 double state_im; 00073 00074 sincos (params.phase, &state_im, &state_re); 00075 state_re *= params.mag; 00076 state_im *= params.mag; 00077 00078 for (Iterator x = begin; x != end; x++) 00079 { 00080 if (MODE == VectorSinParams::REPLACE) 00081 *x = state_im; 00082 else 00083 *x += state_im; 00084 if ((n++ & 255) == 255) 00085 { 00086 sincos (phase_inc * n + params.phase, &state_im, &state_re); 00087 state_re *= params.mag; 00088 state_im *= params.mag; 00089 } 00090 else 00091 { 00092 /* 00093 * (state_re + i * state_im) * (inc_re + i * inc_im) = 00094 * state_re * inc_re - state_im * inc_im + i * (state_re * inc_im + state_im * inc_re) 00095 */ 00096 const double re = state_re * inc_re - state_im * inc_im; 00097 const double im = state_re * inc_im + state_im * inc_re; 00098 state_re = re; 00099 state_im = im; 00100 } 00101 } 00102 } 00103 00104 template<class Iterator, int MODE> 00105 inline void 00106 internal_fast_vector_sincos (const VectorSinParams& params, Iterator sin_begin, Iterator sin_end, Iterator cos_begin) 00107 { 00108 g_return_if_fail (params.mix_freq > 0 && params.freq > 0 && params.phase > -99 && params.mag > 0); 00109 00110 const double phase_inc = params.freq / params.mix_freq * 2 * M_PI; 00111 const double inc_re = cos (phase_inc); 00112 const double inc_im = sin (phase_inc); 00113 int n = 0; 00114 00115 double state_re; 00116 double state_im; 00117 00118 sincos (params.phase, &state_im, &state_re); 00119 state_re *= params.mag; 00120 state_im *= params.mag; 00121 00122 for (Iterator x = sin_begin, y = cos_begin; x != sin_end; x++, y++) 00123 { 00124 if (MODE == VectorSinParams::REPLACE) 00125 { 00126 *x = state_im; 00127 *y = state_re; 00128 } 00129 else 00130 { 00131 *x += state_im; 00132 *y += state_re; 00133 } 00134 if ((n++ & 255) == 255) 00135 { 00136 sincos (phase_inc * n + params.phase, &state_im, &state_re); 00137 state_re *= params.mag; 00138 state_im *= params.mag; 00139 } 00140 else 00141 { 00142 /* 00143 * (state_re + i * state_im) * (inc_re + i * inc_im) = 00144 * state_re * inc_re - state_im * inc_im + i * (state_re * inc_im + state_im * inc_re) 00145 */ 00146 const double re = state_re * inc_re - state_im * inc_im; 00147 const double im = state_re * inc_im + state_im * inc_re; 00148 state_re = re; 00149 state_im = im; 00150 } 00151 } 00152 } 00153 00154 template<class Iterator> 00155 inline void 00156 fast_vector_sin (const VectorSinParams& params, Iterator sin_begin, Iterator sin_end) 00157 { 00158 if (params.mode == VectorSinParams::ADD) 00159 { 00160 internal_fast_vector_sin<Iterator, VectorSinParams::ADD> (params, sin_begin, sin_end); 00161 } 00162 else if (params.mode == VectorSinParams::REPLACE) 00163 { 00164 internal_fast_vector_sin<Iterator, VectorSinParams::REPLACE> (params, sin_begin, sin_end); 00165 } 00166 else 00167 { 00168 g_assert_not_reached(); 00169 } 00170 } 00171 00172 template<class Iterator> 00173 inline void 00174 fast_vector_sincos (const VectorSinParams& params, Iterator sin_begin, Iterator sin_end, Iterator cos_begin) 00175 { 00176 if (params.mode == VectorSinParams::ADD) 00177 { 00178 internal_fast_vector_sincos<Iterator, VectorSinParams::ADD> (params, sin_begin, sin_end, cos_begin); 00179 } 00180 else if (params.mode == VectorSinParams::REPLACE) 00181 { 00182 internal_fast_vector_sincos<Iterator, VectorSinParams::REPLACE> (params, sin_begin, sin_end, cos_begin); 00183 } 00184 else 00185 { 00186 g_assert_not_reached(); 00187 } 00188 } 00189 00190 00192 /* see: http://ds9a.nl/gcc-simd/ */ 00193 union F4Vector 00194 { 00195 float f[4]; 00196 #ifdef __SSE__ 00197 __m128 v; // vector of four single floats 00198 #endif 00199 }; 00201 00202 template<bool NEED_COS, int MODE> 00203 inline void 00204 internal_fast_vector_sincosf (const VectorSinParams& params, float *sin_begin, float *sin_end, float *cos_begin) 00205 { 00206 #ifdef __SSE__ 00207 g_return_if_fail (params.mix_freq > 0 && params.freq > 0 && params.phase > -99 && params.mag > 0); 00208 00209 const int TABLE_SIZE = 32; 00210 00211 const double phase_inc = params.freq / params.mix_freq * 2 * M_PI; 00212 const double inc_re16 = cos (phase_inc * TABLE_SIZE * 4); 00213 const double inc_im16 = sin (phase_inc * TABLE_SIZE * 4); 00214 int n = 0; 00215 00216 double state_re; 00217 double state_im; 00218 00219 sincos (params.phase, &state_im, &state_re); 00220 state_re *= params.mag; 00221 state_im *= params.mag; 00222 00223 F4Vector incf_re[TABLE_SIZE]; 00224 F4Vector incf_im[TABLE_SIZE]; 00225 00226 // compute tables using FPU 00227 VectorSinParams table_params = params; 00228 table_params.phase = 0; 00229 table_params.mag = 1; 00230 table_params.mode = VectorSinParams::REPLACE; 00231 fast_vector_sincos (table_params, incf_im[0].f, incf_im[0].f + (TABLE_SIZE * 4), incf_re[0].f); 00232 00233 // inner loop using SSE instructions 00234 int todo = sin_end - sin_begin; 00235 while (todo >= 4 * TABLE_SIZE) 00236 { 00237 F4Vector sf_re; 00238 F4Vector sf_im; 00239 sf_re.f[0] = state_re; 00240 sf_re.f[1] = state_re; 00241 sf_re.f[2] = state_re; 00242 sf_re.f[3] = state_re; 00243 sf_im.f[0] = state_im; 00244 sf_im.f[1] = state_im; 00245 sf_im.f[2] = state_im; 00246 sf_im.f[3] = state_im; 00247 00248 /* 00249 * formula for complex multiplication: 00250 * 00251 * (state_re + i * state_im) * (inc_re + i * inc_im) = 00252 * state_re * inc_re - state_im * inc_im + i * (state_re * inc_im + state_im * inc_re) 00253 */ 00254 F4Vector *new_im = reinterpret_cast<F4Vector *> (sin_begin + n); 00255 F4Vector *new_re = reinterpret_cast<F4Vector *> (cos_begin + n); 00256 for (int k = 0; k < TABLE_SIZE; k++) 00257 { 00258 if (MODE == VectorSinParams::ADD) 00259 { 00260 if (NEED_COS) 00261 { 00262 new_re[k].v = _mm_add_ps (new_re[k].v, _mm_sub_ps (_mm_mul_ps (sf_re.v, incf_re[k].v), 00263 _mm_mul_ps (sf_im.v, incf_im[k].v))); 00264 } 00265 new_im[k].v = _mm_add_ps (new_im[k].v, _mm_add_ps (_mm_mul_ps (sf_re.v, incf_im[k].v), 00266 _mm_mul_ps (sf_im.v, incf_re[k].v))); 00267 } 00268 else 00269 { 00270 if (NEED_COS) 00271 { 00272 new_re[k].v = _mm_sub_ps (_mm_mul_ps (sf_re.v, incf_re[k].v), 00273 _mm_mul_ps (sf_im.v, incf_im[k].v)); 00274 } 00275 new_im[k].v = _mm_add_ps (_mm_mul_ps (sf_re.v, incf_im[k].v), 00276 _mm_mul_ps (sf_im.v, incf_re[k].v)); 00277 } 00278 } 00279 00280 n += 4 * TABLE_SIZE; 00281 00282 /* 00283 * (state_re + i * state_im) * (inc_re + i * inc_im) = 00284 * state_re * inc_re - state_im * inc_im + i * (state_re * inc_im + state_im * inc_re) 00285 */ 00286 const double re = state_re * inc_re16 - state_im * inc_im16; 00287 const double im = state_re * inc_im16 + state_im * inc_re16; 00288 state_re = re; 00289 state_im = im; 00290 00291 todo -= 4 * TABLE_SIZE; 00292 } 00293 00294 // compute the remaining sin/cos values using the FPU 00295 VectorSinParams rest_params = params; 00296 rest_params.phase += n * phase_inc; 00297 if (NEED_COS) 00298 fast_vector_sincos (rest_params, sin_begin + n, sin_end, cos_begin + n); 00299 else 00300 fast_vector_sin (rest_params, sin_begin + n, sin_end); 00301 #else 00302 if (NEED_COS) 00303 fast_vector_sincos (params, sin_begin, sin_end, cos_begin); 00304 else 00305 fast_vector_sin (params, sin_begin, sin_end); 00306 #endif 00307 } 00308 00309 inline void 00310 fast_vector_sincosf (const VectorSinParams& params, float *sin_begin, float *sin_end, float *cos_begin) 00311 { 00312 if (params.mode == VectorSinParams::ADD) 00313 { 00314 internal_fast_vector_sincosf<true, VectorSinParams::ADD> (params, sin_begin, sin_end, cos_begin); 00315 } 00316 else if (params.mode == VectorSinParams::REPLACE) 00317 { 00318 internal_fast_vector_sincosf<true, VectorSinParams::REPLACE> (params, sin_begin, sin_end, cos_begin); 00319 } 00320 else 00321 { 00322 g_assert_not_reached(); 00323 } 00324 } 00325 00326 inline void 00327 fast_vector_sinf (const VectorSinParams& params, float *sin_begin, float *sin_end) 00328 { 00329 if (params.mode == VectorSinParams::ADD) 00330 { 00331 internal_fast_vector_sincosf<false, VectorSinParams::ADD> (params, sin_begin, sin_end, NULL); 00332 } 00333 else if (params.mode == VectorSinParams::REPLACE) 00334 { 00335 internal_fast_vector_sincosf<false, VectorSinParams::REPLACE> (params, sin_begin, sin_end, NULL); 00336 } 00337 else 00338 { 00339 g_assert_not_reached(); 00340 } 00341 } 00342 00343 inline void 00344 zero_float_block (size_t n_values, float *values) 00345 { 00346 memset (values, 0, n_values * sizeof (float)); 00347 } 00348 00349 inline void 00350 int_sincos (guint8 i, double *si, double *ci) 00351 { 00352 extern float *int_sincos_table; 00353 00354 *si = int_sincos_table[i]; 00355 i += 64; 00356 *ci = int_sincos_table[i]; 00357 } 00358 00359 inline void 00360 int_sincosf (guint8 i, float *si, float *ci) 00361 { 00362 extern float *int_sincos_table; 00363 00364 *si = int_sincos_table[i]; 00365 i += 64; 00366 *ci = int_sincos_table[i]; 00367 } 00368 00369 inline void 00370 int_sincos_init() 00371 { 00372 extern float *int_sincos_table; 00373 00374 int_sincos_table = (float *) malloc (sizeof (float) * 256); 00375 for (int i = 0; i < 256; i++) 00376 int_sincos_table[i] = sin (double (i / 256.0) * 2 * M_PI); 00377 } 00378 00379 inline double 00380 window_blackman_harris_92 (double x) 00381 { 00382 if (fabs (x) > 1) 00383 return 0; 00384 00385 const double a0 = 0.35875, a1 = 0.48829, a2 = 0.14128, a3 = 0.01168; 00386 00387 return a0 + a1 * cos (M_PI * x) + a2 * cos (2.0 * M_PI * x) + a3 * cos (3.0 * M_PI * x); 00388 } 00389 00390 #if defined (__i386__) && defined (__GNUC__) 00391 inline int 00392 sm_round_positive (double d) 00393 { 00394 return bse_dtoi (d); 00395 } 00396 00397 inline int 00398 sm_round_positive (float f) 00399 { 00400 return bse_ftoi (f); 00401 } 00402 #else 00403 inline int 00404 sm_round_positive (double d) 00405 { 00406 return int (d + 0.5); 00407 } 00408 00409 inline int 00410 sm_round_positive (float f) 00411 { 00412 return int (f + 0.5); 00413 } 00414 #endif 00415 00416 } // namespace SpectMorph 00417 00418 #endif