Add the identifying header
[kugel-rb.git] / apps / plugins / pdbox / PDa / src / d_delay.c
blobd04ded9e903d68290efa4f6addf354c66f7ab84d
1 /* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
5 /* send~, delread~, throw~, catch~ */
7 #include "m_pd.h"
8 extern int ugen_getsortno(void);
10 #define DEFDELVS 64 /* LATER get this from canvas at DSP time */
11 static int delread_zero = 0; /* four bytes of zero for delread~, vd~ */
13 /* ----------------------------- delwrite~ ----------------------------- */
14 static t_class *sigdelwrite_class;
16 typedef struct delwritectl
18 int c_n;
19 float *c_vec;
20 int c_phase;
21 } t_delwritectl;
23 typedef struct _sigdelwrite
25 t_object x_obj;
26 t_symbol *x_sym;
27 t_delwritectl x_cspace;
28 int x_sortno; /* DSP sort number at which this was last put on chain */
29 int x_rsortno; /* DSP sort # for first delread or write in chain */
30 int x_vecsize; /* vector size for delread~ to use */
31 float x_f;
32 } t_sigdelwrite;
34 #define XTRASAMPS 4
35 #define SAMPBLK 4
37 /* routine to check that all delwrites/delreads/vds have same vecsize */
38 static void sigdelwrite_checkvecsize(t_sigdelwrite *x, int vecsize)
41 LATER this should really check sample rate and blocking, once that is
42 supported. Probably we don't actually care about vecsize.
43 For now just suppress this check... */
44 #if 0
45 if (x->x_rsortno != ugen_getsortno())
47 x->x_vecsize = vecsize;
48 x->x_rsortno = ugen_getsortno();
50 else if (vecsize != x->x_vecsize)
51 pd_error(x, "delread/delwrite/vd vector size mismatch");
52 #endif
55 static void *sigdelwrite_new(t_symbol *s, t_floatarg msec)
57 int nsamps;
58 t_sigdelwrite *x = (t_sigdelwrite *)pd_new(sigdelwrite_class);
59 if (!*s->s_name) s = gensym("delwrite~");
60 pd_bind(&x->x_obj.ob_pd, s);
61 x->x_sym = s;
62 nsamps = msec * sys_getsr() * (float)(0.001f);
63 if (nsamps < 1) nsamps = 1;
64 nsamps += ((- nsamps) & (SAMPBLK - 1));
65 nsamps += DEFDELVS;
66 x->x_cspace.c_n = nsamps;
67 x->x_cspace.c_vec =
68 (float *)getbytes((nsamps + XTRASAMPS) * sizeof(float));
69 x->x_cspace.c_phase = XTRASAMPS;
70 x->x_sortno = 0;
71 x->x_vecsize = 0;
72 x->x_f = 0;
73 return (x);
76 static t_int *sigdelwrite_perform(t_int *w)
78 t_float *in = (t_float *)(w[1]);
79 t_delwritectl *c = (t_delwritectl *)(w[2]);
80 int n = (int)(w[3]);
81 int phase = c->c_phase, nsamps = c->c_n;
82 float *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS);
83 phase += n;
84 while (n--)
86 float f = *in++;
87 if (PD_BIGORSMALL(f))
88 f = 0;
89 *bp++ = f;
90 if (bp == ep)
92 vp[0] = ep[-4];
93 vp[1] = ep[-3];
94 vp[2] = ep[-2];
95 vp[3] = ep[-1];
96 bp = vp + XTRASAMPS;
97 phase -= nsamps;
100 c->c_phase = phase;
101 return (w+4);
104 static void sigdelwrite_dsp(t_sigdelwrite *x, t_signal **sp)
106 dsp_add(sigdelwrite_perform, 3, sp[0]->s_vec, &x->x_cspace, sp[0]->s_n);
107 x->x_sortno = ugen_getsortno();
108 sigdelwrite_checkvecsize(x, sp[0]->s_n);
111 static void sigdelwrite_free(t_sigdelwrite *x)
113 pd_unbind(&x->x_obj.ob_pd, x->x_sym);
114 freebytes(x->x_cspace.c_vec,
115 (x->x_cspace.c_n + XTRASAMPS) * sizeof(float));
118 static void sigdelwrite_setup(void)
120 sigdelwrite_class = class_new(gensym("delwrite~"),
121 (t_newmethod)sigdelwrite_new, (t_method)sigdelwrite_free,
122 sizeof(t_sigdelwrite), 0, A_DEFSYM, A_DEFFLOAT, 0);
123 CLASS_MAINSIGNALIN(sigdelwrite_class, t_sigdelwrite, x_f);
124 class_addmethod(sigdelwrite_class, (t_method)sigdelwrite_dsp,
125 gensym("dsp"), 0);
128 /* ----------------------------- delread~ ----------------------------- */
129 static t_class *sigdelread_class;
131 typedef struct _sigdelread
133 t_object x_obj;
134 t_symbol *x_sym;
135 t_float x_deltime; /* delay in msec */
136 int x_delsamps; /* delay in samples */
137 t_float x_sr; /* samples per msec */
138 t_float x_n; /* vector size */
139 int x_zerodel; /* 0 or vecsize depending on read/write order */
140 } t_sigdelread;
142 static void sigdelread_float(t_sigdelread *x, t_float f);
144 static void *sigdelread_new(t_symbol *s, t_floatarg f)
146 t_sigdelread *x = (t_sigdelread *)pd_new(sigdelread_class);
147 x->x_sym = s;
148 x->x_sr = 1;
149 x->x_n = 1;
150 x->x_zerodel = 0;
151 sigdelread_float(x, f);
152 outlet_new(&x->x_obj, &s_signal);
153 return (x);
156 static void sigdelread_float(t_sigdelread *x, t_float f)
158 int samps;
159 t_sigdelwrite *delwriter =
160 (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
161 x->x_deltime = f;
162 if (delwriter)
164 int delsize = delwriter->x_cspace.c_n;
165 x->x_delsamps = (int)(0.5 + x->x_sr * x->x_deltime)
166 + x->x_n - x->x_zerodel;
167 if (x->x_delsamps < x->x_n) x->x_delsamps = x->x_n;
168 else if (x->x_delsamps > delwriter->x_cspace.c_n - DEFDELVS)
169 x->x_delsamps = delwriter->x_cspace.c_n - DEFDELVS;
173 static t_int *sigdelread_perform(t_int *w)
175 t_float *out = (t_float *)(w[1]);
176 t_delwritectl *c = (t_delwritectl *)(w[2]);
177 int delsamps = *(int *)(w[3]);
178 int n = (int)(w[4]);
179 int phase = c->c_phase - delsamps, nsamps = c->c_n;
180 float *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS);
182 if (phase < 0) phase += nsamps;
183 bp = vp + phase;
184 while (n--)
186 *out++ = *bp++;
187 if (bp == ep) bp -= nsamps;
189 return (w+5);
192 static void sigdelread_dsp(t_sigdelread *x, t_signal **sp)
194 t_sigdelwrite *delwriter =
195 (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
196 x->x_sr = sp[0]->s_sr * 0.001;
197 x->x_n = sp[0]->s_n;
198 if (delwriter)
200 sigdelwrite_checkvecsize(delwriter, sp[0]->s_n);
201 x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ?
202 0 : delwriter->x_vecsize);
203 sigdelread_float(x, x->x_deltime);
204 dsp_add(sigdelread_perform, 4,
205 sp[0]->s_vec, &delwriter->x_cspace, &x->x_delsamps, sp[0]->s_n);
207 else if (*x->x_sym->s_name)
208 error("delread~: %s: no such delwrite~",x->x_sym->s_name);
211 static void sigdelread_setup(void)
213 sigdelread_class = class_new(gensym("delread~"),
214 (t_newmethod)sigdelread_new, 0,
215 sizeof(t_sigdelread), 0, A_DEFSYM, A_DEFFLOAT, 0);
216 class_addmethod(sigdelread_class, (t_method)sigdelread_dsp,
217 gensym("dsp"), 0);
218 class_addfloat(sigdelread_class, (t_method)sigdelread_float);
222 /* ----------------------------- vd~ ----------------------------- */
223 static t_class *sigvd_class;
225 typedef struct _sigvd
227 t_object x_obj;
228 t_symbol *x_sym;
229 t_float x_sr; /* samples per msec */
230 int x_zerodel; /* 0 or vecsize depending on read/write order */
231 float x_f;
232 } t_sigvd;
234 static void *sigvd_new(t_symbol *s)
236 t_sigvd *x = (t_sigvd *)pd_new(sigvd_class);
237 if (!*s->s_name) s = gensym("vd~");
238 x->x_sym = s;
239 x->x_sr = 1;
240 x->x_zerodel = 0;
241 outlet_new(&x->x_obj, &s_signal);
242 x->x_f = 0;
243 return (x);
246 static t_int *sigvd_perform(t_int *w)
248 t_float *in = (t_float *)(w[1]);
249 t_float *out = (t_float *)(w[2]);
250 t_delwritectl *ctl = (t_delwritectl *)(w[3]);
251 t_sigvd *x = (t_sigvd *)(w[4]);
252 int n = (int)(w[5]);
254 int nsamps = ctl->c_n;
255 float limit = nsamps - n - 1;
256 float fn = n-1;
257 float *vp = ctl->c_vec, *bp, *wp = vp + ctl->c_phase;
258 float zerodel = x->x_zerodel;
259 while (n--)
261 float delsamps = x->x_sr * *in++ - zerodel, frac;
262 int idelsamps;
263 float a, b, c, d, cminusb;
264 if (delsamps < 1.00001f) delsamps = 1.00001f;
265 if (delsamps > limit) delsamps = limit;
266 delsamps += fn;
267 fn = fn - 1.0f;
268 idelsamps = delsamps;
269 frac = delsamps - (float)idelsamps;
270 bp = wp - idelsamps;
271 if (bp < vp + 4) bp += nsamps;
272 d = bp[-3];
273 c = bp[-2];
274 b = bp[-1];
275 a = bp[0];
276 cminusb = c-b;
277 *out++ = b + frac * (
278 cminusb - 0.1666667f * (1.-frac) * (
279 (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)
283 return (w+6);
286 static void sigvd_dsp(t_sigvd *x, t_signal **sp)
288 t_sigdelwrite *delwriter =
289 (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
290 x->x_sr = sp[0]->s_sr * 0.001;
291 if (delwriter)
293 sigdelwrite_checkvecsize(delwriter, sp[0]->s_n);
294 x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ?
295 0 : delwriter->x_vecsize);
296 dsp_add(sigvd_perform, 5,
297 sp[0]->s_vec, sp[1]->s_vec,
298 &delwriter->x_cspace, x, sp[0]->s_n);
300 else error("vd~: %s: no such delwrite~",x->x_sym->s_name);
303 static void sigvd_setup(void)
305 sigvd_class = class_new(gensym("vd~"), (t_newmethod)sigvd_new, 0,
306 sizeof(t_sigvd), 0, A_DEFSYM, 0);
307 class_addmethod(sigvd_class, (t_method)sigvd_dsp, gensym("dsp"), 0);
308 CLASS_MAINSIGNALIN(sigvd_class, t_sigvd, x_f);
311 /* ----------------------- global setup routine ---------------- */
313 void d_delay_setup(void)
315 sigdelwrite_setup();
316 sigdelread_setup();
317 sigvd_setup();