1 // Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
3 #ifndef SPECTMORPH_MATH_HH
4 #define SPECTMORPH_MATH_HH
10 #include <bse/bseieee754.hh>
12 #include <xmmintrin.h>
19 * \brief parameter structure for the various optimized vector sine functions
24 double mix_freq; //!< the mix freq (sampling rate) of the sin (and cos) wave to be created
25 double freq; //!< the frequency of the sin (and cos) wave to be created
26 double phase; //!< the start phase of the wave
27 double mag; //!< the magnitude (amplitude) of the wave
31 ADD = 1, //!< add computed values to the values that are in the output array
32 REPLACE = 2 //!< replace values in the output array with computed values
33 } mode; //!< whether to overwrite or add output
45 template<class Iterator, int MODE>
47 internal_fast_vector_sin (const VectorSinParams& params, Iterator begin, Iterator end)
49 g_return_if_fail (params.mix_freq > 0 && params.freq > 0 && params.phase > -99 && params.mag > 0);
51 const double phase_inc = params.freq / params.mix_freq * 2 * M_PI;
52 const double inc_re = cos (phase_inc);
53 const double inc_im = sin (phase_inc);
59 sincos (params.phase, &state_im, &state_re);
60 state_re *= params.mag;
61 state_im *= params.mag;
63 for (Iterator x = begin; x != end; x++)
65 if (MODE == VectorSinParams::REPLACE)
69 if ((n++ & 255) == 255)
71 sincos (phase_inc * n + params.phase, &state_im, &state_re);
72 state_re *= params.mag;
73 state_im *= params.mag;
78 * (state_re + i * state_im) * (inc_re + i * inc_im) =
79 * state_re * inc_re - state_im * inc_im + i * (state_re * inc_im + state_im * inc_re)
81 const double re = state_re * inc_re - state_im * inc_im;
82 const double im = state_re * inc_im + state_im * inc_re;
89 template<class Iterator, int MODE>
91 internal_fast_vector_sincos (const VectorSinParams& params, Iterator sin_begin, Iterator sin_end, Iterator cos_begin)
93 g_return_if_fail (params.mix_freq > 0 && params.freq > 0 && params.phase > -99 && params.mag > 0);
95 const double phase_inc = params.freq / params.mix_freq * 2 * M_PI;
96 const double inc_re = cos (phase_inc);
97 const double inc_im = sin (phase_inc);
103 sincos (params.phase, &state_im, &state_re);
104 state_re *= params.mag;
105 state_im *= params.mag;
107 for (Iterator x = sin_begin, y = cos_begin; x != sin_end; x++, y++)
109 if (MODE == VectorSinParams::REPLACE)
119 if ((n++ & 255) == 255)
121 sincos (phase_inc * n + params.phase, &state_im, &state_re);
122 state_re *= params.mag;
123 state_im *= params.mag;
128 * (state_re + i * state_im) * (inc_re + i * inc_im) =
129 * state_re * inc_re - state_im * inc_im + i * (state_re * inc_im + state_im * inc_re)
131 const double re = state_re * inc_re - state_im * inc_im;
132 const double im = state_re * inc_im + state_im * inc_re;
139 template<class Iterator>
141 fast_vector_sin (const VectorSinParams& params, Iterator sin_begin, Iterator sin_end)
143 if (params.mode == VectorSinParams::ADD)
145 internal_fast_vector_sin<Iterator, VectorSinParams::ADD> (params, sin_begin, sin_end);
147 else if (params.mode == VectorSinParams::REPLACE)
149 internal_fast_vector_sin<Iterator, VectorSinParams::REPLACE> (params, sin_begin, sin_end);
153 g_assert_not_reached();
157 template<class Iterator>
159 fast_vector_sincos (const VectorSinParams& params, Iterator sin_begin, Iterator sin_end, Iterator cos_begin)
161 if (params.mode == VectorSinParams::ADD)
163 internal_fast_vector_sincos<Iterator, VectorSinParams::ADD> (params, sin_begin, sin_end, cos_begin);
165 else if (params.mode == VectorSinParams::REPLACE)
167 internal_fast_vector_sincos<Iterator, VectorSinParams::REPLACE> (params, sin_begin, sin_end, cos_begin);
171 g_assert_not_reached();
177 /* see: http://ds9a.nl/gcc-simd/ */
182 __m128 v; // vector of four single floats
187 template<bool NEED_COS, int MODE>
189 internal_fast_vector_sincosf (const VectorSinParams& params, float *sin_begin, float *sin_end, float *cos_begin)
192 g_return_if_fail (params.mix_freq > 0 && params.freq > 0 && params.phase > -99 && params.mag > 0);
194 const int TABLE_SIZE = 32;
196 const double phase_inc = params.freq / params.mix_freq * 2 * M_PI;
197 const double inc_re16 = cos (phase_inc * TABLE_SIZE * 4);
198 const double inc_im16 = sin (phase_inc * TABLE_SIZE * 4);
204 sincos (params.phase, &state_im, &state_re);
205 state_re *= params.mag;
206 state_im *= params.mag;
208 F4Vector incf_re[TABLE_SIZE];
209 F4Vector incf_im[TABLE_SIZE];
211 // compute tables using FPU
212 VectorSinParams table_params = params;
213 table_params.phase = 0;
214 table_params.mag = 1;
215 table_params.mode = VectorSinParams::REPLACE;
216 fast_vector_sincos (table_params, incf_im[0].f, incf_im[0].f + (TABLE_SIZE * 4), incf_re[0].f);
218 // inner loop using SSE instructions
219 int todo = sin_end - sin_begin;
220 while (todo >= 4 * TABLE_SIZE)
224 sf_re.f[0] = state_re;
225 sf_re.f[1] = state_re;
226 sf_re.f[2] = state_re;
227 sf_re.f[3] = state_re;
228 sf_im.f[0] = state_im;
229 sf_im.f[1] = state_im;
230 sf_im.f[2] = state_im;
231 sf_im.f[3] = state_im;
234 * formula for complex multiplication:
236 * (state_re + i * state_im) * (inc_re + i * inc_im) =
237 * state_re * inc_re - state_im * inc_im + i * (state_re * inc_im + state_im * inc_re)
239 F4Vector *new_im = reinterpret_cast<F4Vector *> (sin_begin + n);
240 F4Vector *new_re = reinterpret_cast<F4Vector *> (cos_begin + n);
241 for (int k = 0; k < TABLE_SIZE; k++)
243 if (MODE == VectorSinParams::ADD)
247 new_re[k].v = _mm_add_ps (new_re[k].v, _mm_sub_ps (_mm_mul_ps (sf_re.v, incf_re[k].v),
248 _mm_mul_ps (sf_im.v, incf_im[k].v)));
250 new_im[k].v = _mm_add_ps (new_im[k].v, _mm_add_ps (_mm_mul_ps (sf_re.v, incf_im[k].v),
251 _mm_mul_ps (sf_im.v, incf_re[k].v)));
257 new_re[k].v = _mm_sub_ps (_mm_mul_ps (sf_re.v, incf_re[k].v),
258 _mm_mul_ps (sf_im.v, incf_im[k].v));
260 new_im[k].v = _mm_add_ps (_mm_mul_ps (sf_re.v, incf_im[k].v),
261 _mm_mul_ps (sf_im.v, incf_re[k].v));
268 * (state_re + i * state_im) * (inc_re + i * inc_im) =
269 * state_re * inc_re - state_im * inc_im + i * (state_re * inc_im + state_im * inc_re)
271 const double re = state_re * inc_re16 - state_im * inc_im16;
272 const double im = state_re * inc_im16 + state_im * inc_re16;
276 todo -= 4 * TABLE_SIZE;
279 // compute the remaining sin/cos values using the FPU
280 VectorSinParams rest_params = params;
281 rest_params.phase += n * phase_inc;
283 fast_vector_sincos (rest_params, sin_begin + n, sin_end, cos_begin + n);
285 fast_vector_sin (rest_params, sin_begin + n, sin_end);
288 fast_vector_sincos (params, sin_begin, sin_end, cos_begin);
290 fast_vector_sin (params, sin_begin, sin_end);
295 fast_vector_sincosf (const VectorSinParams& params, float *sin_begin, float *sin_end, float *cos_begin)
297 if (params.mode == VectorSinParams::ADD)
299 internal_fast_vector_sincosf<true, VectorSinParams::ADD> (params, sin_begin, sin_end, cos_begin);
301 else if (params.mode == VectorSinParams::REPLACE)
303 internal_fast_vector_sincosf<true, VectorSinParams::REPLACE> (params, sin_begin, sin_end, cos_begin);
307 g_assert_not_reached();
312 fast_vector_sinf (const VectorSinParams& params, float *sin_begin, float *sin_end)
314 if (params.mode == VectorSinParams::ADD)
316 internal_fast_vector_sincosf<false, VectorSinParams::ADD> (params, sin_begin, sin_end, NULL);
318 else if (params.mode == VectorSinParams::REPLACE)
320 internal_fast_vector_sincosf<false, VectorSinParams::REPLACE> (params, sin_begin, sin_end, NULL);
324 g_assert_not_reached();
329 zero_float_block (size_t n_values, float *values)
331 memset (values, 0, n_values * sizeof (float));
335 int_sincos (guint8 i, double *si, double *ci)
337 extern float *int_sincos_table;
339 *si = int_sincos_table[i];
341 *ci = int_sincos_table[i];
345 int_sincosf (guint8 i, float *si, float *ci)
347 extern float *int_sincos_table;
349 *si = int_sincos_table[i];
351 *ci = int_sincos_table[i];
357 extern float *int_sincos_table;
359 int_sincos_table = (float *) malloc (sizeof (float) * 256);
360 for (int i = 0; i < 256; i++)
361 int_sincos_table[i] = sin (double (i / 256.0) * 2 * M_PI);
365 window_blackman_harris_92 (double x)
370 const double a0 = 0.35875, a1 = 0.48829, a2 = 0.14128, a3 = 0.01168;
372 return a0 + a1 * cos (M_PI * x) + a2 * cos (2.0 * M_PI * x) + a3 * cos (3.0 * M_PI * x);
375 #if defined (__i386__) && defined (__GNUC__)
377 sm_round_positive (double d)
383 sm_round_positive (float f)
389 sm_round_positive (double d)
391 return int (d + 0.5);
395 sm_round_positive (float f)
397 return int (f + 0.5);
403 static float idb2f_high[256];
404 static float idb2f_low[256];
406 static float ifreq2f_high[256];
407 static float ifreq2f_low[256];
410 #define SM_IDB_CONST_M96 uint16_t ((512 - 96) * 64)
412 uint16_t sm_factor2idb (double factor);
413 int sm_factor2delta_idb (double factor);
414 double sm_idb2factor_slow (uint16_t idb);
418 uint16_t sm_freq2ifreq (double freq);
419 double sm_ifreq2freq_slow (uint16_t ifreq);
422 sm_idb2factor (uint16_t idb)
424 return MathTables::idb2f_high[idb >> 8] * MathTables::idb2f_low[idb & 0xff];
428 sm_ifreq2freq (uint16_t ifreq)
430 return MathTables::ifreq2f_high[ifreq >> 8] * MathTables::ifreq2f_low[ifreq & 0xff];
434 } // namespace SpectMorph