You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
344 lines
11 KiB
344 lines
11 KiB
/* 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.
|
|
*/
|
|
#ifndef __GSL_SIGNAL_H__
|
|
#define __GSL_SIGNAL_H__
|
|
|
|
#include <gsl/gsldefs.h>
|
|
#include <gsl/gslieee754.h>
|
|
#include <gsl/gslmath.h>
|
|
|
|
#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 <bse/bseglobals.h>
|
|
# 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 (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 (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 (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 (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 (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 (double x)
|
|
{
|
|
if (x < 0) /* make use of -atan(-x)==atan(x) */
|
|
{
|
|
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
|
|
{
|
|
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 (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 (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 (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 (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)
|
|
{
|
|
GslFloatIEEE754 fp = { 0, };
|
|
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__ */
|