/* GSL - Generic Sound Layer * Copyright (C) 2001-2002 Tim Janik and Stefan Westerfeld * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "gslsignal.h" #include "gslcommon.h" /* --- frequency modulation --- */ void gsl_frequency_modulator (const GslFrequencyModulator *fm, guint n_values, const gfloat *ifreq, const gfloat *ifmod, gfloat *fm_buffer) { gfloat *bound, fine_tune, fm_strength; gboolean with_fine_tune; fine_tune = gsl_cent_factor (fm->fine_tune); with_fine_tune = fm->fine_tune != 0; fm_strength = fm->fm_strength; bound = fm_buffer + n_values; if (ifreq && ifmod) { if (fm->exponential_fm) { if (with_fine_tune) do { *fm_buffer++ = *ifreq++ * gsl_approx_exp2 (fm_strength * *ifmod++) * fine_tune; } while (fm_buffer < bound); else do { *fm_buffer++ = *ifreq++ * gsl_approx_exp2 (fm_strength * *ifmod++); } while (fm_buffer < bound); } else { if (with_fine_tune) do { *fm_buffer++ = *ifreq++ * (1 + fm_strength * *ifmod++) * fine_tune; } while (fm_buffer < bound); else do { *fm_buffer++ = *ifreq++ * (1 + fm_strength * *ifmod++); } while (fm_buffer < bound); } } else if (ifmod) { gfloat signal_freq = fm->signal_freq * fine_tune; if (fm->exponential_fm) do { *fm_buffer++ = signal_freq * gsl_approx_exp2 (fm_strength * *ifmod++); } while (fm_buffer < bound); else do { *fm_buffer++ = signal_freq * (1 + fm_strength * *ifmod++); } while (fm_buffer < bound); } else if (ifreq) { if (with_fine_tune) do { *fm_buffer++ = *ifreq++ * fine_tune; } while (fm_buffer < bound); else do { *fm_buffer++ = *ifreq++; } while (fm_buffer < bound); } else { gfloat signal_freq = fm->signal_freq * fine_tune; do { *fm_buffer++ = signal_freq; } while (fm_buffer < bound); } } /* --- windows --- */ double gsl_window_bartlett (double x) /* triangle */ { if (fabs (x) > 1) return 0; return 1.0 - fabs (x); } double gsl_window_blackman (double x) { if (fabs (x) > 1) return 0; return 0.42 + 0.5 * cos (GSL_PI * x) + 0.08 * cos (2.0 * GSL_PI * x); } double gsl_window_cos (double x) /* von Hann window */ { if (fabs (x) > 1) return 0; return 0.5 * cos (x * GSL_PI) + 0.5; } double gsl_window_hamming (double x) /* sharp (rectangle) cutoffs at boundaries */ { if (fabs (x) > 1) return 0; return 0.54 + 0.46 * cos (GSL_PI * x); } double gsl_window_sinc (double x) /* noramlied C. Lanczos window */ { if (fabs (x) > 1) return 0; x = x * GSL_PI; if (fabs (x) < 1e-12) return 1.0; else return sin (x) / x; } double gsl_window_rect (double x) /* a square */ { if (fabs (x) > 1) return 0; return 1.0; } /* cos_roll_off(x)= x>fh?0:x<fl?1:cos(pi/2.*((fl-x)/(fh-fl))) */ /* --- cents & init --- */ const gdouble *gsl_cent_table = NULL; #define GSL_2_RAISED_TO_1_OVER_1200_d ( /* 2^(1/1200) */ \ 1.0005777895065548488418016859213821589946746826171875) void _gsl_init_signal (void) { static gdouble cent_table_space[201]; gint i; /* cent table initialization, * allow negative indexing within [-100..+100] */ gsl_cent_table = cent_table_space + 100; for (i = -100; i <= 100; i++) cent_table_space[100 + i] = pow (GSL_2_RAISED_TO_1_OVER_1200_d, i); } /* --- gsl_approx_atan1() --- */ double gsl_approx_atan1_prescale (double boost_amount) { double max_boost_factor = 100; /* atan1(x*100) gets pretty close to 1 for x=1 */ double recip_tan_1_div_0_75 = 0.24202942695518667705824990442766; /* 1/tan(1/0.75) */ double scale; g_return_val_if_fail (boost_amount >= 0 && boost_amount <= 1.0, 1.0); /* scale boost_amount from [0..1] to -1..1 */ boost_amount = boost_amount * 2 - 1.0; /* prescale factor for atan1(x*prescale), ranges from 1/max_boost_factor..max_boost_factor */ scale = pow (max_boost_factor, tan (boost_amount / 0.75) * recip_tan_1_div_0_75); return scale; } /* --- exp2f() approximation taylor coefficients finder --- */ #if 0 #include <stdio.h> double exp2coeff (int n) { double r = 1; int i; for (i = 1; i <= n; i++) { r *= GSL_LN2; r /= i; } return r; } /* generate taylor coefficients */ int main (int argc, char *argv[]) { int i; for (i = 0; i < 20; i++) printf ("#define EXP2_TAYLOR_COEFF_%u\t(%.40f)\n", i, exp2coeff (i)); return 0; } /* test/bench program */ #define _GNU_SOURCE #include <math.h> int main (int argc, char *argv[]) { double x, dummy = 0, l = 4; if (1) /* print errors */ for (x = -3; x < 3.01; x += 0.1) { g_print ("%+f %+1.20f \t (%.20f - %.20f)\n", x, exp (x * GSL_LN2) - gsl_signal_exp2 (x), exp (x * GSL_LN2), gsl_signal_exp2 (x)); } if (0) /* bench test */ for (x = -l; x < l; x += 0.000001) { dummy += gsl_signal_exp2 (x); // dummy += exp2f (x); } g_print ("%f\r \n", dummy); return 0; } #endif /* coeff generation */