/* 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., 59 Temple Place, Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef __GSL_SIGNAL_H__ #define __GSL_SIGNAL_H__ #include #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* smallest value of a signal sample, greater than zero */ #define GSL_SIGNAL_EPSILON (1.15e-14) /* 1.16415321826934814453125e-9 ~= 1/2^33 */ /* maximum value of a signal sample */ #define GSL_SIGNAL_KAPPA (1.5) /* catch edges in sync signals. * sync signals should be constant, do comparing against * an epsilon just hurts speed in the common case */ #define GSL_SIGNAL_RAISING_EDGE(v1,v2) ((v1) < (v2)) #define GSL_SIGNAL_FALLING_EDGE(v1,v2) ((v1) > (v2)) /* value changes in signals which represent frequencies */ #define GSL_SIGNAL_FREQ_CHANGED(v1,v2) (fabs ((v1) - (v2)) > 1e-7) /* value changes in signals which represent modulation */ #define GSL_SIGNAL_MOD_CHANGED(v1,v2) (fabs ((v1) - (v2)) > 1e-8) /* value changes in signals which represent dB ranges */ #define GSL_SIGNAL_GAIN_CHANGED(v1,v2) (fabs ((v1) - (v2)) > 1e-8) /* convert between literal frequencies and signal values */ #if defined (BSE_COMPILATION) || defined (BSE_PLUGIN_FALLBACK) #include # define GSL_SIGNAL_TO_FREQ_FACTOR (BSE_MAX_FREQUENCY_f) # define GSL_SIGNAL_FROM_FREQ_FACTOR (1.0 / BSE_MAX_FREQUENCY_f) # define GSL_SIGNAL_TO_FREQ(value) (((gfloat) (value)) * GSL_SIGNAL_TO_FREQ_FACTOR) # define GSL_SIGNAL_FROM_FREQ(freq) (((gfloat) (freq)) * GSL_SIGNAL_FROM_FREQ_FACTOR) #elif defined (GSL_USE_ARTS_THREADS) /* must be aRts */ # define GSL_SIGNAL_TO_FREQ(x) (x) # define GSL_SIGNAL_FROM_FREQ(x) (x) #endif /* --- frequency modulation --- */ typedef struct { gfloat fm_strength; /* linear: 0..1, exponential: n_octaves */ guint exponential_fm : 1; gfloat signal_freq; /* for ifreq == NULL (as GSL_SIGNAL_FROM_FREQ) */ gint fine_tune; /* -100..+100 */ } GslFrequencyModulator; void gsl_frequency_modulator (const GslFrequencyModulator *fm, guint n_values, const gfloat *ifreq, const gfloat *ifmod, gfloat *fm_buffer); /* --- function approximations --- */ /** * gsl_signal_exp2 * Deprecated in favour of gsl_approx_exp2(). */ static inline float gsl_signal_exp2 (float x) G_GNUC_CONST; /** * gsl_approx_exp2 * @ex: exponent within [-127..127] * @RETURNS: y approximating 2^x * Fast approximation of 2 raised to the power of x. * Multiplicative error stays below 8e-6 and aproaches zero * for integer values of x (i.e. x - floor (x) = 0). */ static inline double gsl_approx_exp2 (float ex) G_GNUC_CONST; /** * gsl_approx_atan1 * Fast atan(x)/(PI/2) approximation, with maximum error < 0.01 and * gsl_approx_atan1(0)==0, according to the formula: * n1 = -0.41156875521951602506487246309908; * n2 = -1.0091272542790025586079663559158; * d1 = 0.81901156857081841441890603235599; * d2 = 1.0091272542790025586079663559158; * positive_atan1(x) = 1 + (n1 * x + n2) / ((1 + d1 * x) * x + d2); */ static inline double gsl_approx_atan1 (register double x) G_GNUC_CONST; /** * gsl_approx_atan1_prescale * @boost_amount: boost amount between [0..1] * @RETURNS: prescale factor for gsl_approx_atan1() * Calculate the prescale factor for gsl_approx_atan1(x*prescale) from * a linear boost factor, where 0.5 amounts to prescale=1.0, 1.0 results * in maximum boost and 0.0 results in maximum attenuation. */ double gsl_approx_atan1_prescale (double boost_amount); /** * gsl_approx_qcircle1 * @x: x within [0..1] * @RETURNS: y for circle approximation within [0..1] * Fast approximation of the upper right quadrant of a circle. * Errors at x=0 and x=1 are zero, for the rest of the curve, the error * wasn't minimized, but distributed to best fit the curverture of a * quarter circle. The maximum error is below 0.092. */ static inline double gsl_approx_qcircle1 (register double x) G_GNUC_CONST; /** * gsl_approx_qcircle2 * @x: x within [0..1] * @RETURNS: y for circle approximation within [0..1] * Fast approximation of the upper left quadrant of a circle. * Errors at x=0 and x=1 are zero, for the rest of the curve, the error * wasn't minimized, but distributed to best fit the curverture of a * quarter circle. The maximum error is below 0.092. */ static inline double gsl_approx_qcircle2 (register double x) G_GNUC_CONST; /** * gsl_approx_qcircle3 * @x: x within [0..1] * @RETURNS: y for circle approximation within [0..1] * Fast approximation of the lower left quadrant of a circle. * Errors at x=0 and x=1 are zero, for the rest of the curve, the error * wasn't minimized, but distributed to best fit the curverture of a * quarter circle. The maximum error is below 0.092. */ static inline double gsl_approx_qcircle3 (register double x) G_GNUC_CONST; /** * gsl_approx_qcircle4 * @x: x within [0..1] * @RETURNS: y for circle approximation within [0..1] * Fast approximation of the lower right quadrant of a circle. * Errors at x=0 and x=1 are zero, for the rest of the curve, the error * wasn't minimized, but distributed to best fit the curverture of a * quarter circle. The maximum error is below 0.092. */ static inline double gsl_approx_qcircle4 (register double x) G_GNUC_CONST; /* --- windows --- */ double gsl_window_bartlett (double x); /* narrowest */ double gsl_window_blackman (double x); double gsl_window_cos (double x); double gsl_window_hamming (double x); double gsl_window_sinc (double x); double gsl_window_rect (double x); /* widest */ /* --- cents (1/100th of a semitone) --- */ #define gsl_cent_factor(index /* -100..100 */) (gsl_cent_table[index]) extern const gdouble *gsl_cent_table; /* --- implementation details --- */ static inline double G_GNUC_CONST gsl_approx_atan1 (register double x) { if (x < 0) /* make use of -atan(-x)==atan(x) */ { register double numerator, denominator = -1.0; denominator += x * 0.81901156857081841441890603235599; /* d1 */ numerator = x * 0.41156875521951602506487246309908; /* -n1 */ denominator *= x; numerator += -1.0091272542790025586079663559158; /* n2 */ denominator += 1.0091272542790025586079663559158; /* d2 */ return -1.0 - numerator / denominator; } else { register double numerator, denominator = 1.0; denominator += x * 0.81901156857081841441890603235599; /* d1 */ numerator = x * -0.41156875521951602506487246309908; /* n1 */ denominator *= x; numerator += -1.0091272542790025586079663559158; /* n2 */ denominator += 1.0091272542790025586079663559158; /* d2 */ return 1.0 + numerator / denominator; } } static inline double G_GNUC_CONST gsl_approx_qcircle1 (register double x) { double numerator = 1.20460124790369468987715633298929 * x - 1.20460124790369468987715633298929; double denominator = x - 1.20460124790369468987715633298929; /* R1(x)=(1.2046012479036946898771563 * x - 1.2046012479036946898771563) / (x - 1.2046012479036946898771563) */ return numerator / denominator; } static inline double G_GNUC_CONST gsl_approx_qcircle2 (register double x) { double numerator = 1.20460124790369468987715633298929*x; double denominator = x + 0.20460124790369468987715633298929; /* R2(x)=1.2046012479036946898771563*x/(x + 0.2046012479036946898771563) */ return numerator / denominator; } static inline double G_GNUC_CONST gsl_approx_qcircle3 (register double x) { double numerator = 0.20460124790369468987715633298929 - 0.20460124790369468987715633298929 * x; double denominator = x + 0.20460124790369468987715633298929; /* R3(x)=(0.2046012479036946898771563 - 0.2046012479036946898771563 * x) / (x + 0.2046012479036946898771563) */ return numerator / denominator; } static inline double G_GNUC_CONST gsl_approx_qcircle4 (register double x) { double numerator = -0.20460124790369468987715633298929 * x; double denominator = x - 1.20460124790369468987715633298929; /* R4(x)=-0.2046012479036946898771563 * x / (x - 1.2046012479036946898771563) */ return numerator / denominator; } static inline double G_GNUC_CONST gsl_approx_exp2 (float ex) { register GslFloatIEEE754 fp = { 0, }; register double numer, denom, x; gint i; i = gsl_ftoi (ex); fp.mpn.biased_exponent = GSL_FLOAT_BIAS + i; x = ex - i; numer = x * 1.022782938747283388104723674300322141276; denom = x - 8.72117024533378044415954808601135282456; numer += 8.786902350800703562041965087953613538091; denom *= x; numer *= x; denom += 25.25880955504064143887016455761526606757; numer += 25.2588095552441757401874424757283407864; return numer / denom * fp.v_float; } static inline float G_GNUC_CONST _gsl_signal_exp2_fraction (float x) /* 2^x, -0.5 <= x <= 0.5 */ { static const float exp2taylorC0 = 1.0000000000000000000000000000000000000000; static const float exp2taylorC1 = 0.6931471805599452862267639829951804131269; static const float exp2taylorC2 = 0.2402265069591006940719069007172947749496; static const float exp2taylorC3 = 0.0555041086648215761800706502526736585423; static const float exp2taylorC4 = 0.0096181291076284768787330037298488605302; static const float exp2taylorC5 = 0.0013333558146428443284131626356270317046; #if 0 static const float exp2taylorC6 = 0.0001540353039338160877607525334198612654; static const float exp2taylorC7 = 0.0000152527338040598393887042200089965149; static const float exp2taylorC8 = 0.0000013215486790144307390984122416166535; static const float exp2taylorC9 = 0.0000001017808600923969859895309888857262; #endif float r = 0.0; /* order 5 taylor series aproximation */ r += exp2taylorC5; r *= x; r += exp2taylorC4; r *= x; r += exp2taylorC3; r *= x; r += exp2taylorC2; r *= x; r += exp2taylorC1; r *= x; r += exp2taylorC0; return r; } static inline float G_GNUC_CONST gsl_signal_exp2 (float x) /* 2^x, -3.5 <= x <= 3.5, prec>16bit */ { if_reject (x < -0.5) { if_reject (x < -1.5) { if (x < -2.5) return 0.125 * _gsl_signal_exp2_fraction (x + 3); else /* -2.5 <= x < -1.5 */ return 0.25 * _gsl_signal_exp2_fraction (x + 2); } else /* -1.5 <= x < -0.5 */ return 0.5 * _gsl_signal_exp2_fraction (x + 1); } else if_reject (x > 0.5) { if_reject (x > 1.5) { if (x > 2.5) return 8 * _gsl_signal_exp2_fraction (x - 3); else /* 1.5 < x <= 2.5 */ return 4 * _gsl_signal_exp2_fraction (x - 2); } else /* 0.5 < x <= 1.5 */ return 2 * _gsl_signal_exp2_fraction (x - 1); } else return _gsl_signal_exp2_fraction (x); } #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __GSL_SIGNAL_H__ */