1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
/*
* Copyright (c) 1997-1999 Mark Danks.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
*/
/* Original code by Miller Puckette */
/* a non-interpolating reson filter, not very carefully coded... */
/* 11/29/94 modified to do interpolation - M. Danks */
#include "m_pd.h"
#include <stdlib.h>
#define BUFSIZE 4096
typedef struct resonctl
{
float c_freq;
float c_samprate;
float c_feedback;
int c_delayinsamps;
float c_fraction;
int c_phase;
float *c_buf;
} t_resonctl;
typedef struct sigreson
{
t_object x_obj; /* header */
t_resonctl *x_ctl; /* pointer to state */
t_resonctl x_cspace; /* garage for state when not in a chain */
} t_sigreson;
/* the DSP routine -- called for every n samples of input */
static t_int *cu_reson(t_int *w)
{
t_float *in1 = (t_float *)(w[1]);
t_float *in2 = (t_float *)(w[2]);
t_float *out = (t_float *)(w[3]);
t_resonctl *x = (t_resonctl *)(w[4]);
int n = (int)(w[5]);
long i;
int writephase = x->c_phase;
for (i = 0; i < n; i++)
{
/* note two tricks: 1. input is read before output
* is written, because the routine might be called
* in-place;
* 2 - a seed of 1E-20 is thrown in to avoid floating
* underflow which slows the calculation down.
*/
int readphase, phase, delayinsamps;
float fraction, f, g, freq, freqtemp;
float ftemp;
freq = *in2++;
freqtemp = (freq < 1 ? 1 : freq);
ftemp = x->c_samprate/freqtemp;
if (ftemp >= BUFSIZE-1)
ftemp = BUFSIZE - 1.f;
else if (ftemp < 1.0)
ftemp = 1.f;
delayinsamps = (int)ftemp;
fraction = ftemp - delayinsamps;
readphase = writephase - delayinsamps;
phase = readphase & (BUFSIZE-1);
f = x->c_buf[phase] + fraction *
(x->c_buf[(phase-1)& (BUFSIZE-1)] - x->c_buf[phase]);
g = *in1++;
*out++ = x->c_buf[(writephase++) & (BUFSIZE-1)] =
g + x->c_feedback * f + 1E-20f;
}
x->c_phase = writephase & (BUFSIZE-1);
return (w+6);
}
/* sets the reson frequency */
void sigreson_float(t_sigreson *x, t_floatarg f)
{
float ftemp;
x->x_ctl->c_freq = (f < 1 ? 1 : f);
ftemp = x->x_ctl->c_samprate/x->x_ctl->c_freq;
if (ftemp >= BUFSIZE - 1)
ftemp = BUFSIZE - 1.f;
else if (ftemp < 1.0)
ftemp = 1.f;
x->x_ctl->c_delayinsamps = (int)ftemp;
x->x_ctl->c_fraction = ftemp - x->x_ctl->c_delayinsamps;
}
/* routine which FTS calls to put you on the DSP chain or take you off. */
static void sigreson_dsp(t_sigreson *x, t_signal **sp)
{
x->x_ctl->c_samprate = sp[0]->s_sr;
sigreson_float(x, x->x_ctl->c_freq);
dsp_add(cu_reson, 5, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,
x->x_ctl, sp[0]->s_n);
}
static void sigreson_ft1(t_sigreson *x, t_floatarg f) /* sets feedback */
{
if (f > .99999) f = .99999f;
else if (f < -.99999) f = -.99999f;
x->x_ctl->c_feedback = (float)f;
}
static void sigreson_ff(t_sigreson *x) /* cleanup on free */
{
free(x->x_ctl->c_buf);
}
static t_class *sigreson_class;
void *sigreson_new(t_floatarg f, t_floatarg g)
{
t_sigreson *x = (t_sigreson *)pd_new(sigreson_class);
outlet_new(&x->x_obj, &s_signal);
/* things in "cspace" are things you'll actually use at DSP time */
x->x_cspace.c_phase = 0;
if (!(x->x_cspace.c_buf = (float *)malloc(BUFSIZE * sizeof(float))))
{
error("buffer alloc failed");
return (0);
}
x->x_cspace.c_samprate = 44100.f; /* just a plausible default */
/* control block is in the garage at startup */
x->x_ctl = &x->x_cspace;
sigreson_float(x, (t_float)f); /* setup params */
sigreson_ft1(x, g);
/* make a "float" inlet */
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
return (x);
}
void reson_tilde_setup()
{
sigreson_class = class_new(gensym("reson~"), (t_newmethod)sigreson_new,
(t_method)sigreson_ff, sizeof(t_sigreson), 0,
A_DEFFLOAT, A_DEFFLOAT, 0);
class_addfloat(sigreson_class, (t_method)sigreson_float);
class_addmethod(sigreson_class, (t_method)sigreson_ft1, gensym("ft1"), A_FLOAT, 0);
class_addmethod(sigreson_class, (t_method)nullfn, &s_signal, A_NULL);
class_addmethod(sigreson_class, (t_method)sigreson_dsp, gensym("dsp"), A_NULL);
}
|