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.
arts/flow/gsl/gsloscillator-aux.c

215 lines
6.5 KiB

/* GSL - Generic Sound Layer
* Copyright (C) 1999, 2000-2002 Tim Janik
*
* 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.
*/
#define OSC_FLAGS (GSL_INCLUDER_CASE | OSC_INCLUDER_FLAGS)
#define ISYNC1_OSYNC0 ((OSC_FLAGS & OSC_FLAG_ISYNC) && !(OSC_FLAGS & OSC_FLAG_OSYNC))
#define ISYNC1_OSYNC1 ((OSC_FLAGS & OSC_FLAG_ISYNC) && (OSC_FLAGS & OSC_FLAG_OSYNC))
#define ISYNC0_OSYNC1 ((OSC_FLAGS & OSC_FLAG_OSYNC) && !(OSC_FLAGS & OSC_FLAG_ISYNC))
#define WITH_OSYNC (OSC_FLAGS & OSC_FLAG_OSYNC)
#define WITH_FREQ (OSC_FLAGS & OSC_FLAG_FREQ)
#define WITH_SMOD (OSC_FLAGS & OSC_FLAG_SELF_MOD)
#define WITH_LMOD (OSC_FLAGS & OSC_FLAG_LINEAR_MOD)
#define WITH_EMOD (OSC_FLAGS & OSC_FLAG_EXP_MOD)
#define WITH_PWM_MOD (OSC_FLAGS & OSC_FLAG_PWM_MOD)
#define PULSE_OSC (OSC_FLAGS & OSC_FLAG_PULSE_OSC)
static void
GSL_INCLUDER_FUNC (GslOscData *osc,
guint n_values,
const gfloat *ifreq,
const gfloat *mod_in,
const gfloat *sync_in,
const gfloat *pwm_in,
gfloat *mono_out,
gfloat *sync_out)
{
gfloat last_sync_level = osc->last_sync_level;
gfloat last_pwm_level = osc->last_pwm_level;
gdouble last_freq_level = osc->last_freq_level;
guint32 cur_pos = osc->cur_pos;
guint32 last_pos = osc->last_pos;
guint32 sync_pos, pos_inc;
gfloat posm_strength, self_posm_strength;
gfloat *boundary = mono_out + n_values;
GslOscWave *wave = &osc->wave;
/* FIXME: should we do gsl_fpu_setround() here? */
pos_inc = gsl_dtoi (osc->last_freq_level * gsl_cent_factor (osc->config.fine_tune) * wave->freq_to_step);
sync_pos = osc->config.phase * wave->phase_to_pos;
posm_strength = pos_inc * osc->config.fm_strength;
self_posm_strength = pos_inc * osc->config.self_fm_strength;
/* do the mixing */
do
{
gfloat v;
/* handle syncs
*/
#if (ISYNC1_OSYNC0) /* input sync only */
{
gfloat sync_level = *sync_in++;
if_reject (GSL_SIGNAL_RAISING_EDGE (last_sync_level, sync_level))
cur_pos = sync_pos;
last_sync_level = sync_level;
}
#elif (ISYNC1_OSYNC1) /* input and output sync */
{
gfloat sync_level = *sync_in++;
if_reject (GSL_SIGNAL_RAISING_EDGE (last_sync_level, sync_level))
{
cur_pos = sync_pos;
*sync_out++ = 1.0;
}
else /* figure output sync position */
{
guint is_sync = (sync_pos <= cur_pos) + (last_pos < sync_pos) + (cur_pos < last_pos);
*sync_out++ = is_sync >= 2 ? 1.0 : 0.0;
}
last_sync_level = sync_level;
}
#elif (ISYNC0_OSYNC1) /* output sync only */
{
/* figure output sync position */
guint is_sync = (sync_pos <= cur_pos) + (last_pos < sync_pos) + (cur_pos < last_pos);
*sync_out++ = is_sync >= 2 ? 1.0 : 0.0;
}
#endif
/* track frequency changes
*/
#if (WITH_FREQ)
{
gdouble freq_level = *ifreq++;
freq_level = GSL_SIGNAL_TO_FREQ (freq_level);
if (GSL_SIGNAL_FREQ_CHANGED (last_freq_level, freq_level))
{
if_reject (freq_level <= wave->min_freq || freq_level > wave->max_freq)
{
gdouble fcpos, flpos;
const gfloat *orig_values = wave->values;
fcpos = cur_pos * wave->ifrac_to_float;
flpos = last_pos * wave->ifrac_to_float;
gsl_osc_table_lookup (osc->config.table, freq_level, wave);
if (orig_values != wave->values) /* catch non-changes */
{
last_pos = flpos / wave->ifrac_to_float;
cur_pos = fcpos / wave->ifrac_to_float;
sync_pos = osc->config.phase * wave->phase_to_pos;
pos_inc = gsl_dtoi (freq_level * gsl_cent_factor (osc->config.fine_tune) * wave->freq_to_step);
#if (PULSE_OSC)
osc->last_pwm_level = 0;
osc_update_pwm_offset (osc, osc->last_pwm_level);
last_pwm_level = osc->last_pwm_level;
#endif
}
}
else
pos_inc = gsl_dtoi (freq_level * gsl_cent_factor (osc->config.fine_tune) * wave->freq_to_step);
posm_strength = pos_inc * osc->config.fm_strength;
self_posm_strength = pos_inc * osc->config.self_fm_strength;
last_freq_level = freq_level;
}
}
#endif
/* track pulse witdh modulation
*/
#if (WITH_PWM_MOD)
{
gfloat pwm_level = *pwm_in++;
if (fabs (last_pwm_level - pwm_level) > 1.0 / 65536.0)
{
last_pwm_level = pwm_level;
osc_update_pwm_offset (osc, pwm_level);
}
}
#endif
/* output signal calculation
*/
#if (PULSE_OSC) /* pulse width modulation oscillator */
{
guint32 tpos, ipos;
tpos = cur_pos >> wave->n_frac_bits;
ipos = (cur_pos - osc->pwm_offset) >> wave->n_frac_bits;
v = wave->values[tpos] - wave->values[ipos];
v = (v + osc->pwm_center) * osc->pwm_max;
}
#else /* table read out and linear ipol */
{
guint32 tpos, ifrac;
gfloat ffrac, w;
tpos = cur_pos >> wave->n_frac_bits;
ifrac = cur_pos & wave->frac_bitmask;
ffrac = ifrac * wave->ifrac_to_float;
v = wave->values[tpos];
w = wave->values[tpos + 1];
v *= 1.0 - ffrac;
w *= ffrac;
v += w;
}
#endif /* v = value_out done */
*mono_out++ = v;
/* position increment
*/
#if (WITH_OSYNC)
last_pos = cur_pos;
#endif
#if (WITH_SMOD) /* self modulation */
cur_pos += self_posm_strength * v;
#endif
#if (WITH_LMOD) /* linear fm */
{
gfloat mod_level = *mod_in++;
cur_pos += pos_inc + posm_strength * mod_level;
}
#elif (WITH_EMOD) /* exponential fm */
{
gfloat mod_level = *mod_in++;
cur_pos += pos_inc * gsl_signal_exp2 (osc->config.fm_strength * mod_level);
}
#else /* no modulation */
cur_pos += pos_inc;
#endif
}
while (mono_out < boundary);
osc->last_pos = WITH_OSYNC ? last_pos : cur_pos;
osc->cur_pos = cur_pos;
osc->last_sync_level = last_sync_level;
osc->last_freq_level = last_freq_level;
osc->last_pwm_level = last_pwm_level;
}
#undef ISYNC1_OSYNC0
#undef ISYNC1_OSYNC1
#undef ISYNC0_OSYNC1
#undef WITH_OSYNC
#undef WITH_FREQ
#undef WITH_SMOD
#undef WITH_LMOD
#undef WITH_EMOD
#undef OSC_FLAGS