forked from len0rd/rockbox
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21070 a1c6a512-1295-4272-9138-f99709370657
535 lines
14 KiB
C
535 lines
14 KiB
C
/* Copyright (c) 1997-1999 Miller Puckette.
|
|
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
|
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
|
|
|
|
/* sinusoidal oscillator and table lookup; see also tabosc4~ in d_array.c.
|
|
*/
|
|
|
|
#include "m_pd.h"
|
|
#include "math.h"
|
|
|
|
#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */
|
|
|
|
/* machine-dependent definitions. These ifdefs really
|
|
should have been by CPU type and not by operating system! */
|
|
#ifdef IRIX
|
|
/* big-endian. Most significant byte is at low address in memory */
|
|
#define HIOFFSET 0 /* word offset to find MSB */
|
|
#define LOWOFFSET 1 /* word offset to find LSB */
|
|
#define int32 long /* a data type that has 32 bits */
|
|
#else
|
|
#ifdef MSW
|
|
/* little-endian; most significant byte is at highest address */
|
|
#define HIOFFSET 1
|
|
#define LOWOFFSET 0
|
|
#define int32 long
|
|
#else
|
|
#ifdef __FreeBSD__
|
|
#include <machine/endian.h>
|
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
|
#define HIOFFSET 1
|
|
#define LOWOFFSET 0
|
|
#else
|
|
#define HIOFFSET 0 /* word offset to find MSB */
|
|
#define LOWOFFSET 1 /* word offset to find LSB */
|
|
#endif /* BYTE_ORDER */
|
|
#include <sys/types.h>
|
|
#define int32 int32_t
|
|
#endif
|
|
#ifdef __linux__
|
|
|
|
#include <endian.h>
|
|
|
|
#if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN)
|
|
#error No byte order defined
|
|
#endif
|
|
|
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
|
#define HIOFFSET 1
|
|
#define LOWOFFSET 0
|
|
#else
|
|
#define HIOFFSET 0 /* word offset to find MSB */
|
|
#define LOWOFFSET 1 /* word offset to find LSB */
|
|
#endif /* __BYTE_ORDER */
|
|
|
|
#include <sys/types.h>
|
|
#define int32 int32_t
|
|
|
|
#else
|
|
#ifdef MACOSX
|
|
#define HIOFFSET 0 /* word offset to find MSB */
|
|
#define LOWOFFSET 1 /* word offset to find LSB */
|
|
#define int32 int /* a data type that has 32 bits */
|
|
|
|
#endif /* MACOSX */
|
|
#endif /* __linux__ */
|
|
#endif /* MSW */
|
|
#endif /* SGI */
|
|
|
|
union tabfudge
|
|
{
|
|
double tf_d;
|
|
int32 tf_i[2];
|
|
};
|
|
|
|
|
|
/* -------------------------- phasor~ ------------------------------ */
|
|
static t_class *phasor_class, *scalarphasor_class;
|
|
|
|
#if 1 /* in the style of R. Hoeldrich (ICMC 1995 Banff) */
|
|
|
|
typedef struct _phasor
|
|
{
|
|
t_object x_obj;
|
|
double x_phase;
|
|
float x_conv;
|
|
float x_f; /* scalar frequency */
|
|
} t_phasor;
|
|
|
|
static void *phasor_new(t_floatarg f)
|
|
{
|
|
t_phasor *x = (t_phasor *)pd_new(phasor_class);
|
|
x->x_f = f;
|
|
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
|
|
x->x_phase = 0;
|
|
x->x_conv = 0;
|
|
outlet_new(&x->x_obj, gensym("signal"));
|
|
return (x);
|
|
}
|
|
|
|
static t_int *phasor_perform(t_int *w)
|
|
{
|
|
t_phasor *x = (t_phasor *)(w[1]);
|
|
t_float *in = (t_float *)(w[2]);
|
|
t_float *out = (t_float *)(w[3]);
|
|
int n = (int)(w[4]);
|
|
double dphase = x->x_phase + UNITBIT32;
|
|
union tabfudge tf;
|
|
int normhipart;
|
|
float conv = x->x_conv;
|
|
|
|
tf.tf_d = UNITBIT32;
|
|
normhipart = tf.tf_i[HIOFFSET];
|
|
tf.tf_d = dphase;
|
|
|
|
while (n--)
|
|
{
|
|
tf.tf_i[HIOFFSET] = normhipart;
|
|
dphase += *in++ * conv;
|
|
*out++ = tf.tf_d - UNITBIT32;
|
|
tf.tf_d = dphase;
|
|
}
|
|
tf.tf_i[HIOFFSET] = normhipart;
|
|
x->x_phase = tf.tf_d - UNITBIT32;
|
|
return (w+5);
|
|
}
|
|
|
|
static void phasor_dsp(t_phasor *x, t_signal **sp)
|
|
{
|
|
x->x_conv = 1./sp[0]->s_sr;
|
|
dsp_add(phasor_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
|
|
}
|
|
|
|
static void phasor_ft1(t_phasor *x, t_float f)
|
|
{
|
|
x->x_phase = f;
|
|
}
|
|
|
|
static void phasor_setup(void)
|
|
{
|
|
phasor_class = class_new(gensym("phasor~"), (t_newmethod)phasor_new, 0,
|
|
sizeof(t_phasor), 0, A_DEFFLOAT, 0);
|
|
CLASS_MAINSIGNALIN(phasor_class, t_phasor, x_f);
|
|
class_addmethod(phasor_class, (t_method)phasor_dsp, gensym("dsp"), 0);
|
|
class_addmethod(phasor_class, (t_method)phasor_ft1,
|
|
gensym("ft1"), A_FLOAT, 0);
|
|
}
|
|
|
|
#endif /* Hoeldrich version */
|
|
|
|
/* ------------------------ cos~ ----------------------------- */
|
|
|
|
float *cos_table;
|
|
|
|
static t_class *cos_class;
|
|
|
|
typedef struct _cos
|
|
{
|
|
t_object x_obj;
|
|
float x_f;
|
|
} t_cos;
|
|
|
|
static void *cos_new(void)
|
|
{
|
|
t_cos *x = (t_cos *)pd_new(cos_class);
|
|
outlet_new(&x->x_obj, gensym("signal"));
|
|
x->x_f = 0;
|
|
return (x);
|
|
}
|
|
|
|
static t_int *cos_perform(t_int *w)
|
|
{
|
|
t_float *in = (t_float *)(w[1]);
|
|
t_float *out = (t_float *)(w[2]);
|
|
int n = (int)(w[3]);
|
|
float *tab = cos_table, *addr, f1, f2, frac;
|
|
double dphase;
|
|
int normhipart;
|
|
union tabfudge tf;
|
|
|
|
tf.tf_d = UNITBIT32;
|
|
normhipart = tf.tf_i[HIOFFSET];
|
|
|
|
#if 0 /* this is the readable version of the code. */
|
|
while (n--)
|
|
{
|
|
dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
|
|
tf.tf_d = dphase;
|
|
addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
|
|
tf.tf_i[HIOFFSET] = normhipart;
|
|
frac = tf.tf_d - UNITBIT32;
|
|
f1 = addr[0];
|
|
f2 = addr[1];
|
|
*out++ = f1 + frac * (f2 - f1);
|
|
}
|
|
#endif
|
|
#if 1 /* this is the same, unwrapped by hand. */
|
|
dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
|
|
tf.tf_d = dphase;
|
|
addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
|
|
tf.tf_i[HIOFFSET] = normhipart;
|
|
while (--n)
|
|
{
|
|
dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
|
|
frac = tf.tf_d - UNITBIT32;
|
|
tf.tf_d = dphase;
|
|
f1 = addr[0];
|
|
f2 = addr[1];
|
|
addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
|
|
*out++ = f1 + frac * (f2 - f1);
|
|
tf.tf_i[HIOFFSET] = normhipart;
|
|
}
|
|
frac = tf.tf_d - UNITBIT32;
|
|
f1 = addr[0];
|
|
f2 = addr[1];
|
|
*out++ = f1 + frac * (f2 - f1);
|
|
#endif
|
|
return (w+4);
|
|
}
|
|
|
|
static void cos_dsp(t_cos *x, t_signal **sp)
|
|
{
|
|
dsp_add(cos_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
|
|
}
|
|
|
|
static void cos_maketable(void)
|
|
{
|
|
int i;
|
|
float *fp, phase, phsinc = (2. * 3.14159) / COSTABSIZE;
|
|
union tabfudge tf;
|
|
|
|
if (cos_table) return;
|
|
cos_table = (float *)getbytes(sizeof(float) * (COSTABSIZE+1));
|
|
for (i = COSTABSIZE + 1, fp = cos_table, phase = 0; i--;
|
|
fp++, phase += phsinc)
|
|
*fp = cos(phase);
|
|
|
|
/* here we check at startup whether the byte alignment
|
|
is as we declared it. If not, the code has to be
|
|
recompiled the other way. */
|
|
tf.tf_d = UNITBIT32 + 0.5;
|
|
if ((unsigned)tf.tf_i[LOWOFFSET] != 0x80000000)
|
|
bug("cos~: unexpected machine alignment");
|
|
}
|
|
|
|
static void cos_setup(void)
|
|
{
|
|
cos_class = class_new(gensym("cos~"), (t_newmethod)cos_new, 0,
|
|
sizeof(t_cos), 0, A_DEFFLOAT, 0);
|
|
CLASS_MAINSIGNALIN(cos_class, t_cos, x_f);
|
|
class_addmethod(cos_class, (t_method)cos_dsp, gensym("dsp"), 0);
|
|
cos_maketable();
|
|
}
|
|
|
|
/* ------------------------ osc~ ----------------------------- */
|
|
|
|
static t_class *osc_class, *scalarosc_class;
|
|
|
|
typedef struct _osc
|
|
{
|
|
t_object x_obj;
|
|
double x_phase;
|
|
float x_conv;
|
|
float x_f; /* frequency if scalar */
|
|
} t_osc;
|
|
|
|
static void *osc_new(t_floatarg f)
|
|
{
|
|
t_osc *x = (t_osc *)pd_new(osc_class);
|
|
x->x_f = f;
|
|
outlet_new(&x->x_obj, gensym("signal"));
|
|
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
|
|
x->x_phase = 0;
|
|
x->x_conv = 0;
|
|
return (x);
|
|
}
|
|
|
|
static t_int *osc_perform(t_int *w)
|
|
{
|
|
t_osc *x = (t_osc *)(w[1]);
|
|
t_float *in = (t_float *)(w[2]);
|
|
t_float *out = (t_float *)(w[3]);
|
|
int n = (int)(w[4]);
|
|
float *tab = cos_table, *addr, f1, f2, frac;
|
|
double dphase = x->x_phase + UNITBIT32;
|
|
int normhipart;
|
|
union tabfudge tf;
|
|
float conv = x->x_conv;
|
|
|
|
tf.tf_d = UNITBIT32;
|
|
normhipart = tf.tf_i[HIOFFSET];
|
|
#if 0
|
|
while (n--)
|
|
{
|
|
tf.tf_d = dphase;
|
|
dphase += *in++ * conv;
|
|
addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
|
|
tf.tf_i[HIOFFSET] = normhipart;
|
|
frac = tf.tf_d - UNITBIT32;
|
|
f1 = addr[0];
|
|
f2 = addr[1];
|
|
*out++ = f1 + frac * (f2 - f1);
|
|
}
|
|
#endif
|
|
#if 1
|
|
tf.tf_d = dphase;
|
|
dphase += *in++ * conv;
|
|
addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
|
|
tf.tf_i[HIOFFSET] = normhipart;
|
|
frac = tf.tf_d - UNITBIT32;
|
|
while (--n)
|
|
{
|
|
tf.tf_d = dphase;
|
|
f1 = addr[0];
|
|
dphase += *in++ * conv;
|
|
f2 = addr[1];
|
|
addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
|
|
tf.tf_i[HIOFFSET] = normhipart;
|
|
*out++ = f1 + frac * (f2 - f1);
|
|
frac = tf.tf_d - UNITBIT32;
|
|
}
|
|
f1 = addr[0];
|
|
f2 = addr[1];
|
|
*out++ = f1 + frac * (f2 - f1);
|
|
#endif
|
|
|
|
tf.tf_d = UNITBIT32 * COSTABSIZE;
|
|
normhipart = tf.tf_i[HIOFFSET];
|
|
tf.tf_d = dphase + (UNITBIT32 * COSTABSIZE - UNITBIT32);
|
|
tf.tf_i[HIOFFSET] = normhipart;
|
|
x->x_phase = tf.tf_d - UNITBIT32 * COSTABSIZE;
|
|
return (w+5);
|
|
}
|
|
|
|
static void osc_dsp(t_osc *x, t_signal **sp)
|
|
{
|
|
x->x_conv = COSTABSIZE/sp[0]->s_sr;
|
|
dsp_add(osc_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
|
|
}
|
|
|
|
static void osc_ft1(t_osc *x, t_float f)
|
|
{
|
|
x->x_phase = COSTABSIZE * f;
|
|
}
|
|
|
|
static void osc_setup(void)
|
|
{
|
|
osc_class = class_new(gensym("osc~"), (t_newmethod)osc_new, 0,
|
|
sizeof(t_osc), 0, A_DEFFLOAT, 0);
|
|
CLASS_MAINSIGNALIN(osc_class, t_osc, x_f);
|
|
class_addmethod(osc_class, (t_method)osc_dsp, gensym("dsp"), 0);
|
|
class_addmethod(osc_class, (t_method)osc_ft1, gensym("ft1"), A_FLOAT, 0);
|
|
|
|
cos_maketable();
|
|
}
|
|
|
|
/* ---------------- vcf~ - 2-pole bandpass filter. ----------------- */
|
|
|
|
typedef struct vcfctl
|
|
{
|
|
float c_re;
|
|
float c_im;
|
|
float c_q;
|
|
float c_isr;
|
|
} t_vcfctl;
|
|
|
|
typedef struct sigvcf
|
|
{
|
|
t_object x_obj;
|
|
t_vcfctl x_cspace;
|
|
t_vcfctl *x_ctl;
|
|
float x_f;
|
|
} t_sigvcf;
|
|
|
|
t_class *sigvcf_class;
|
|
|
|
static void *sigvcf_new(t_floatarg q)
|
|
{
|
|
t_sigvcf *x = (t_sigvcf *)pd_new(sigvcf_class);
|
|
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
|
|
inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
|
|
outlet_new(&x->x_obj, gensym("signal"));
|
|
outlet_new(&x->x_obj, gensym("signal"));
|
|
x->x_ctl = &x->x_cspace;
|
|
x->x_cspace.c_re = 0;
|
|
x->x_cspace.c_im = 0;
|
|
x->x_cspace.c_q = q;
|
|
x->x_cspace.c_isr = 0;
|
|
x->x_f = 0;
|
|
return (x);
|
|
}
|
|
|
|
static void sigvcf_ft1(t_sigvcf *x, t_floatarg f)
|
|
{
|
|
x->x_ctl->c_q = (f > 0 ? f : 0.f);
|
|
}
|
|
|
|
static t_int *sigvcf_perform(t_int *w)
|
|
{
|
|
float *in1 = (float *)(w[1]);
|
|
float *in2 = (float *)(w[2]);
|
|
float *out1 = (float *)(w[3]);
|
|
float *out2 = (float *)(w[4]);
|
|
t_vcfctl *c = (t_vcfctl *)(w[5]);
|
|
int n = (t_int)(w[6]);
|
|
int i;
|
|
float re = c->c_re, re2;
|
|
float im = c->c_im;
|
|
float q = c->c_q;
|
|
float qinv = (q > 0? 1.0f/q : 0);
|
|
float ampcorrect = 2.0f - 2.0f / (q + 2.0f);
|
|
float isr = c->c_isr;
|
|
float coefr, coefi;
|
|
float *tab = cos_table, *addr, f1, f2, frac;
|
|
double dphase;
|
|
int normhipart, tabindex;
|
|
union tabfudge tf;
|
|
|
|
tf.tf_d = UNITBIT32;
|
|
normhipart = tf.tf_i[HIOFFSET];
|
|
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
float cf, cfindx, r, oneminusr;
|
|
cf = *in2++ * isr;
|
|
if (cf < 0) cf = 0;
|
|
cfindx = cf * (float)(COSTABSIZE/6.28318f);
|
|
r = (qinv > 0 ? 1 - cf * qinv : 0);
|
|
if (r < 0) r = 0;
|
|
oneminusr = 1.0f - r;
|
|
dphase = ((double)(cfindx)) + UNITBIT32;
|
|
tf.tf_d = dphase;
|
|
tabindex = tf.tf_i[HIOFFSET] & (COSTABSIZE-1);
|
|
addr = tab + tabindex;
|
|
tf.tf_i[HIOFFSET] = normhipart;
|
|
frac = tf.tf_d - UNITBIT32;
|
|
f1 = addr[0];
|
|
f2 = addr[1];
|
|
coefr = r * (f1 + frac * (f2 - f1));
|
|
|
|
addr = tab + ((tabindex - (COSTABSIZE/4)) & (COSTABSIZE-1));
|
|
f1 = addr[0];
|
|
f2 = addr[1];
|
|
coefi = r * (f1 + frac * (f2 - f1));
|
|
|
|
f1 = *in1++;
|
|
re2 = re;
|
|
*out1++ = re = ampcorrect * oneminusr * f1
|
|
+ coefr * re2 - coefi * im;
|
|
*out2++ = im = coefi * re2 + coefr * im;
|
|
}
|
|
if (PD_BIGORSMALL(re))
|
|
re = 0;
|
|
if (PD_BIGORSMALL(im))
|
|
im = 0;
|
|
c->c_re = re;
|
|
c->c_im = im;
|
|
return (w+7);
|
|
}
|
|
|
|
static void sigvcf_dsp(t_sigvcf *x, t_signal **sp)
|
|
{
|
|
x->x_ctl->c_isr = 6.28318f/sp[0]->s_sr;
|
|
dsp_add(sigvcf_perform, 6,
|
|
sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec,
|
|
x->x_ctl, sp[0]->s_n);
|
|
|
|
}
|
|
|
|
void sigvcf_setup(void)
|
|
{
|
|
sigvcf_class = class_new(gensym("vcf~"), (t_newmethod)sigvcf_new, 0,
|
|
sizeof(t_sigvcf), 0, A_DEFFLOAT, 0);
|
|
CLASS_MAINSIGNALIN(sigvcf_class, t_sigvcf, x_f);
|
|
class_addmethod(sigvcf_class, (t_method)sigvcf_dsp, gensym("dsp"), 0);
|
|
class_addmethod(sigvcf_class, (t_method)sigvcf_ft1,
|
|
gensym("ft1"), A_FLOAT, 0);
|
|
}
|
|
|
|
/* -------------------------- noise~ ------------------------------ */
|
|
static t_class *noise_class;
|
|
|
|
typedef struct _noise
|
|
{
|
|
t_object x_obj;
|
|
int x_val;
|
|
} t_noise;
|
|
|
|
static void *noise_new(void)
|
|
{
|
|
t_noise *x = (t_noise *)pd_new(noise_class);
|
|
static int init = 307;
|
|
x->x_val = (init *= 1319);
|
|
outlet_new(&x->x_obj, gensym("signal"));
|
|
return (x);
|
|
}
|
|
|
|
static t_int *noise_perform(t_int *w)
|
|
{
|
|
t_float *out = (t_float *)(w[1]);
|
|
int *vp = (int *)(w[2]);
|
|
int n = (int)(w[3]);
|
|
int val = *vp;
|
|
while (n--)
|
|
{
|
|
*out++ = ((float)((val & 0x7fffffff) - 0x40000000)) *
|
|
(float)(1.0 / 0x40000000);
|
|
val = val * 435898247 + 382842987;
|
|
}
|
|
*vp = val;
|
|
return (w+4);
|
|
}
|
|
|
|
static void noise_dsp(t_noise *x, t_signal **sp)
|
|
{
|
|
dsp_add(noise_perform, 3, sp[0]->s_vec, &x->x_val, sp[0]->s_n);
|
|
}
|
|
|
|
static void noise_setup(void)
|
|
{
|
|
noise_class = class_new(gensym("noise~"), (t_newmethod)noise_new, 0,
|
|
sizeof(t_noise), 0, 0);
|
|
class_addmethod(noise_class, (t_method)noise_dsp, gensym("dsp"), 0);
|
|
}
|
|
|
|
|
|
/* ----------------------- global setup routine ---------------- */
|
|
void d_osc_setup(void)
|
|
{
|
|
phasor_setup();
|
|
cos_setup();
|
|
osc_setup();
|
|
sigvcf_setup();
|
|
noise_setup();
|
|
}
|
|
|