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~ */
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
23 typedef struct _sigdelwrite
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 */
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... */
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");
55 static void *sigdelwrite_new(t_symbol
*s
, t_floatarg msec
)
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
);
62 nsamps
= msec
* sys_getsr() * (float)(0.001f
);
63 if (nsamps
< 1) nsamps
= 1;
64 nsamps
+= ((- nsamps
) & (SAMPBLK
- 1));
66 x
->x_cspace
.c_n
= nsamps
;
68 (float *)getbytes((nsamps
+ XTRASAMPS
) * sizeof(float));
69 x
->x_cspace
.c_phase
= XTRASAMPS
;
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]);
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
);
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
,
128 /* ----------------------------- delread~ ----------------------------- */
129 static t_class
*sigdelread_class
;
131 typedef struct _sigdelread
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 */
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
);
151 sigdelread_float(x
, f
);
152 outlet_new(&x
->x_obj
, &s_signal
);
156 static void sigdelread_float(t_sigdelread
*x
, t_float f
)
159 t_sigdelwrite
*delwriter
=
160 (t_sigdelwrite
*)pd_findbyclass(x
->x_sym
, sigdelwrite_class
);
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]);
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
;
187 if (bp
== ep
) bp
-= nsamps
;
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;
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
,
218 class_addfloat(sigdelread_class
, (t_method
)sigdelread_float
);
222 /* ----------------------------- vd~ ----------------------------- */
223 static t_class
*sigvd_class
;
225 typedef struct _sigvd
229 t_float x_sr
; /* samples per msec */
230 int x_zerodel
; /* 0 or vecsize depending on read/write order */
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~");
241 outlet_new(&x
->x_obj
, &s_signal
);
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]);
254 int nsamps
= ctl
->c_n
;
255 float limit
= nsamps
- n
- 1;
257 float *vp
= ctl
->c_vec
, *bp
, *wp
= vp
+ ctl
->c_phase
;
258 float zerodel
= x
->x_zerodel
;
261 float delsamps
= x
->x_sr
* *in
++ - zerodel
, frac
;
263 float a
, b
, c
, d
, cminusb
;
264 if (delsamps
< 1.00001f
) delsamps
= 1.00001f
;
265 if (delsamps
> limit
) delsamps
= limit
;
268 idelsamps
= delsamps
;
269 frac
= delsamps
- (float)idelsamps
;
271 if (bp
< vp
+ 4) bp
+= nsamps
;
277 *out
++ = b
+ frac
* (
278 cminusb
- 0.1666667f
* (1.-frac
) * (
279 (d
- a
- 3.0f
* cminusb
) * frac
+ (d
+ 2.0f
*a
- 3.0f
*b
)
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;
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)