summaryrefslogtreecommitdiffstats
path: root/flow/gsl/gsloscillator-aux.c
diff options
context:
space:
mode:
Diffstat (limited to 'flow/gsl/gsloscillator-aux.c')
-rw-r--r--flow/gsl/gsloscillator-aux.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/flow/gsl/gsloscillator-aux.c b/flow/gsl/gsloscillator-aux.c
new file mode 100644
index 0000000..d755bc5
--- /dev/null
+++ b/flow/gsl/gsloscillator-aux.c
@@ -0,0 +1,214 @@
+/* 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, 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