diff options
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/g_io.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/src/g_io.c | 1224 |
1 files changed, 1224 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/src/g_io.c b/apps/plugins/pdbox/PDa/src/g_io.c new file mode 100644 index 0000000000..39788d2adb --- /dev/null +++ b/apps/plugins/pdbox/PDa/src/g_io.c | |||
@@ -0,0 +1,1224 @@ | |||
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. */ | ||
4 | |||
5 | /* graphical inlets and outlets, both for control and signals. */ | ||
6 | |||
7 | /* This code is highly inefficient; messages actually have to be forwarded | ||
8 | by inlets and outlets. The outlet is in even worse shape than the inlet; | ||
9 | in order to avoid having a "signal" method in the class, the oulet actually | ||
10 | sprouts an inlet, which forwards the message to the "outlet" object, which | ||
11 | sends it on to the outlet proper. Another way to do it would be to have | ||
12 | separate classes for "signal" and "control" outlets, but this would complicate | ||
13 | life elsewhere. */ | ||
14 | |||
15 | |||
16 | /* hacked to run subpatches with different samplerates | ||
17 | * | ||
18 | * mfg.gfd.uil | ||
19 | * IOhannes | ||
20 | * | ||
21 | * edited lines are marked with "IOhannes" | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include "m_pd.h" | ||
26 | #include "g_canvas.h" | ||
27 | #include <string.h> | ||
28 | void signal_setborrowed(t_signal *sig, t_signal *sig2); | ||
29 | void signal_makereusable(t_signal *sig); | ||
30 | |||
31 | /* ------------------------- vinlet -------------------------- */ | ||
32 | t_class *vinlet_class; | ||
33 | |||
34 | typedef struct _vinlet | ||
35 | { | ||
36 | t_object x_obj; | ||
37 | t_canvas *x_canvas; | ||
38 | t_inlet *x_inlet; | ||
39 | int x_bufsize; | ||
40 | t_float *x_buf; /* signal buffer; zero if not a signal */ | ||
41 | t_float *x_endbuf; | ||
42 | t_float *x_fill; | ||
43 | t_float *x_read; | ||
44 | int x_hop; | ||
45 | /* if not reblocking, the next slot communicates the parent's inlet | ||
46 | signal from the prolog to the DSP routine: */ | ||
47 | t_signal *x_directsignal; | ||
48 | |||
49 | t_resample x_updown; /* IOhannes */ | ||
50 | } t_vinlet; | ||
51 | |||
52 | static void *vinlet_new(t_symbol *s) | ||
53 | { | ||
54 | t_vinlet *x = (t_vinlet *)pd_new(vinlet_class); | ||
55 | x->x_canvas = canvas_getcurrent(); | ||
56 | x->x_inlet = canvas_addinlet(x->x_canvas, &x->x_obj.ob_pd, 0); | ||
57 | x->x_bufsize = 0; | ||
58 | x->x_buf = 0; | ||
59 | outlet_new(&x->x_obj, 0); | ||
60 | return (x); | ||
61 | } | ||
62 | |||
63 | static void vinlet_bang(t_vinlet *x) | ||
64 | { | ||
65 | outlet_bang(x->x_obj.ob_outlet); | ||
66 | } | ||
67 | |||
68 | static void vinlet_pointer(t_vinlet *x, t_gpointer *gp) | ||
69 | { | ||
70 | outlet_pointer(x->x_obj.ob_outlet, gp); | ||
71 | } | ||
72 | |||
73 | static void vinlet_float(t_vinlet *x, t_float f) | ||
74 | { | ||
75 | outlet_float(x->x_obj.ob_outlet, f); | ||
76 | } | ||
77 | |||
78 | static void vinlet_symbol(t_vinlet *x, t_symbol *s) | ||
79 | { | ||
80 | outlet_symbol(x->x_obj.ob_outlet, s); | ||
81 | } | ||
82 | |||
83 | static void vinlet_list(t_vinlet *x, t_symbol *s, int argc, t_atom *argv) | ||
84 | { | ||
85 | outlet_list(x->x_obj.ob_outlet, s, argc, argv); | ||
86 | } | ||
87 | |||
88 | static void vinlet_anything(t_vinlet *x, t_symbol *s, int argc, t_atom *argv) | ||
89 | { | ||
90 | outlet_anything(x->x_obj.ob_outlet, s, argc, argv); | ||
91 | } | ||
92 | |||
93 | static void vinlet_free(t_vinlet *x) | ||
94 | { | ||
95 | canvas_rminlet(x->x_canvas, x->x_inlet); | ||
96 | resample_free(&x->x_updown); | ||
97 | } | ||
98 | |||
99 | t_inlet *vinlet_getit(t_pd *x) | ||
100 | { | ||
101 | if (pd_class(x) != vinlet_class) bug("vinlet_getit"); | ||
102 | return (((t_vinlet *)x)->x_inlet); | ||
103 | } | ||
104 | |||
105 | /* ------------------------- signal inlet -------------------------- */ | ||
106 | int vinlet_issignal(t_vinlet *x) | ||
107 | { | ||
108 | return (x->x_buf != 0); | ||
109 | } | ||
110 | |||
111 | static int tot; | ||
112 | |||
113 | t_int *vinlet_perform(t_int *w) | ||
114 | { | ||
115 | t_vinlet *x = (t_vinlet *)(w[1]); | ||
116 | t_float *out = (t_float *)(w[2]); | ||
117 | int n = (int)(w[3]); | ||
118 | t_float *in = x->x_read; | ||
119 | #if 0 | ||
120 | if (tot < 5) post("-in %x out %x n %d", in, out, n); | ||
121 | if (tot < 5) post("-buf %x endbuf %x", x->x_buf, x->x_endbuf); | ||
122 | if (tot < 5) post("in[0] %f in[1] %f in[2] %f", in[0], in[1], in[2]); | ||
123 | #endif | ||
124 | while (n--) *out++ = *in++; | ||
125 | if (in == x->x_endbuf) in = x->x_buf; | ||
126 | x->x_read = in; | ||
127 | return (w+4); | ||
128 | } | ||
129 | |||
130 | static void vinlet_dsp(t_vinlet *x, t_signal **sp) | ||
131 | { | ||
132 | t_signal *outsig; | ||
133 | /* no buffer means we're not a signal inlet */ | ||
134 | if (!x->x_buf) | ||
135 | return; | ||
136 | outsig = sp[0]; | ||
137 | if (x->x_directsignal) | ||
138 | { | ||
139 | signal_setborrowed(sp[0], x->x_directsignal); | ||
140 | } | ||
141 | else | ||
142 | { | ||
143 | dsp_add(vinlet_perform, 3, x, outsig->s_vec, outsig->s_n); | ||
144 | x->x_read = x->x_buf; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | /* prolog code: loads buffer from parent patch */ | ||
149 | t_int *vinlet_doprolog(t_int *w) | ||
150 | { | ||
151 | t_vinlet *x = (t_vinlet *)(w[1]); | ||
152 | t_float *in = (t_float *)(w[2]); | ||
153 | int n = (int)(w[3]); | ||
154 | t_float *out = x->x_fill; | ||
155 | if (out == x->x_endbuf) | ||
156 | { | ||
157 | t_float *f1 = x->x_buf, *f2 = x->x_buf + x->x_hop; | ||
158 | int nshift = x->x_bufsize - x->x_hop; | ||
159 | out -= x->x_hop; | ||
160 | while (nshift--) *f1++ = *f2++; | ||
161 | } | ||
162 | #if 0 | ||
163 | if (tot < 5) post("in %x out %x n %x", in, out, n), tot++; | ||
164 | if (tot < 5) post("in[0] %f in[1] %f in[2] %f", in[0], in[1], in[2]); | ||
165 | #endif | ||
166 | |||
167 | while (n--) *out++ = *in++; | ||
168 | x->x_fill = out; | ||
169 | return (w+4); | ||
170 | } | ||
171 | |||
172 | int inlet_getsignalindex(t_inlet *x); | ||
173 | |||
174 | /* set up prolog DSP code */ | ||
175 | void vinlet_dspprolog(t_vinlet *x, t_signal **parentsigs, | ||
176 | int myvecsize, int phase, int period, int frequency, int downsample, int upsample/* IOhannes */, int reblock, | ||
177 | int switched) | ||
178 | { | ||
179 | t_signal *insig, *outsig; | ||
180 | x->x_updown.downsample = downsample; | ||
181 | x->x_updown.upsample = upsample; | ||
182 | |||
183 | /* if the "reblock" flag is set, arrange to copy data in from the | ||
184 | parent. */ | ||
185 | if (reblock) | ||
186 | { | ||
187 | int parentvecsize, bufsize, oldbufsize, prologphase; | ||
188 | int re_parentvecsize; /* resampled parentvectorsize: IOhannes */ | ||
189 | /* this should never happen: */ | ||
190 | if (!x->x_buf) return; | ||
191 | |||
192 | /* the prolog code counts from 0 to period-1; the | ||
193 | phase is backed up by one so that AFTER the prolog code | ||
194 | runs, the "x_fill" phase is in sync with the "x_read" phase. */ | ||
195 | prologphase = (phase - 1) & (period - 1); | ||
196 | if (parentsigs) | ||
197 | { | ||
198 | insig = parentsigs[inlet_getsignalindex(x->x_inlet)]; | ||
199 | parentvecsize = insig->s_n; | ||
200 | re_parentvecsize = parentvecsize * upsample / downsample; | ||
201 | } | ||
202 | else | ||
203 | { | ||
204 | insig = 0; | ||
205 | parentvecsize = 1; | ||
206 | re_parentvecsize = 1; | ||
207 | } | ||
208 | |||
209 | bufsize = re_parentvecsize; | ||
210 | if (bufsize < myvecsize) bufsize = myvecsize; | ||
211 | if (bufsize != (oldbufsize = x->x_bufsize)) | ||
212 | { | ||
213 | t_float *buf = x->x_buf; | ||
214 | t_freebytes(buf, oldbufsize * sizeof(*buf)); | ||
215 | buf = (t_float *)t_getbytes(bufsize * sizeof(*buf)); | ||
216 | memset((char *)buf, 0, bufsize * sizeof(*buf)); | ||
217 | x->x_bufsize = bufsize; | ||
218 | x->x_endbuf = buf + bufsize; | ||
219 | x->x_buf = buf; | ||
220 | } | ||
221 | if (parentsigs) | ||
222 | { | ||
223 | /* IOhannes { */ | ||
224 | x->x_hop = period * re_parentvecsize; | ||
225 | |||
226 | x->x_fill = x->x_endbuf - | ||
227 | (x->x_hop - prologphase * re_parentvecsize); | ||
228 | |||
229 | if (upsample * downsample == 1) | ||
230 | dsp_add(vinlet_doprolog, 3, x, insig->s_vec, re_parentvecsize); | ||
231 | else { | ||
232 | resamplefrom_dsp(&x->x_updown, insig->s_vec, parentvecsize, re_parentvecsize, x->x_updown.method); | ||
233 | dsp_add(vinlet_doprolog, 3, x, x->x_updown.s_vec, re_parentvecsize); | ||
234 | } | ||
235 | |||
236 | /* } IOhannes */ | ||
237 | /* if the input signal's reference count is zero, we have | ||
238 | to free it here because we didn't in ugen_doit(). */ | ||
239 | if (!insig->s_refcount) | ||
240 | signal_makereusable(insig); | ||
241 | } | ||
242 | else memset((char *)(x->x_buf), 0, bufsize * sizeof(*x->x_buf)); | ||
243 | x->x_directsignal = 0; | ||
244 | } | ||
245 | else | ||
246 | { | ||
247 | /* no reblocking; in this case our output signal is "borrowed" | ||
248 | and merely needs to be pointed to the real one. */ | ||
249 | x->x_directsignal = parentsigs[inlet_getsignalindex(x->x_inlet)]; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | //static void *vinlet_newsig(void) | ||
254 | static void *vinlet_newsig(t_symbol *s) | ||
255 | { | ||
256 | t_vinlet *x = (t_vinlet *)pd_new(vinlet_class); | ||
257 | x->x_canvas = canvas_getcurrent(); | ||
258 | x->x_inlet = canvas_addinlet(x->x_canvas, &x->x_obj.ob_pd, &s_signal); | ||
259 | x->x_endbuf = x->x_buf = (t_float *)getbytes(0); | ||
260 | x->x_bufsize = 0; | ||
261 | x->x_directsignal = 0; | ||
262 | outlet_new(&x->x_obj, &s_signal); | ||
263 | |||
264 | resample_init(&x->x_updown); | ||
265 | |||
266 | /* this should be though over: | ||
267 | * it might prove hard to provide consistency between labeled up- & downsampling methods | ||
268 | * maybe indeces would be better... | ||
269 | * | ||
270 | * up till now we provide several upsampling methods and 1 single downsampling method (no filtering !) | ||
271 | */ | ||
272 | if (s == gensym("hold"))x->x_updown.method=1; /* up: sample and hold */ | ||
273 | else if (s == gensym("lin"))x->x_updown.method=2; /* up: linear interpolation */ | ||
274 | else x->x_updown.method=0; /* up: zero-padding */ | ||
275 | |||
276 | return (x); | ||
277 | } | ||
278 | |||
279 | static void vinlet_setup(void) | ||
280 | { | ||
281 | vinlet_class = class_new(gensym("inlet"), (t_newmethod)vinlet_new, | ||
282 | (t_method)vinlet_free, sizeof(t_vinlet), CLASS_NOINLET, A_DEFSYM, 0); | ||
283 | class_addcreator((t_newmethod)vinlet_newsig, gensym("inlet~"), A_DEFSYM, 0); | ||
284 | class_addbang(vinlet_class, vinlet_bang); | ||
285 | class_addpointer(vinlet_class, vinlet_pointer); | ||
286 | class_addfloat(vinlet_class, vinlet_float); | ||
287 | class_addsymbol(vinlet_class, vinlet_symbol); | ||
288 | class_addlist(vinlet_class, vinlet_list); | ||
289 | class_addanything(vinlet_class, vinlet_anything); | ||
290 | class_addmethod(vinlet_class, (t_method)vinlet_dsp, gensym("dsp"), 0); | ||
291 | class_sethelpsymbol(vinlet_class, gensym("pd")); | ||
292 | } | ||
293 | |||
294 | /* ------------------------- voutlet -------------------------- */ | ||
295 | |||
296 | t_class *voutlet_class; | ||
297 | |||
298 | typedef struct _voutlet | ||
299 | { | ||
300 | t_object x_obj; | ||
301 | t_canvas *x_canvas; | ||
302 | t_outlet *x_parentoutlet; | ||
303 | int x_bufsize; | ||
304 | t_sample *x_buf; /* signal buffer; zero if not a signal */ | ||
305 | t_sample *x_endbuf; | ||
306 | t_sample *x_empty; /* next to read out of buffer in epilog code */ | ||
307 | t_sample *x_write; /* next to write in to buffer */ | ||
308 | int x_hop; /* hopsize */ | ||
309 | /* vice versa from the inlet, if we don't block, this holds the | ||
310 | parent's outlet signal, valid between the prolog and the dsp setup | ||
311 | routines. */ | ||
312 | t_signal *x_directsignal; | ||
313 | /* and here's a flag indicating that we aren't blocked but have to | ||
314 | do a copy (because we're switched). */ | ||
315 | char x_justcopyout; | ||
316 | t_resample x_updown; /* IOhannes */ | ||
317 | } t_voutlet; | ||
318 | |||
319 | static void *voutlet_new(t_symbol *s) | ||
320 | { | ||
321 | t_voutlet *x = (t_voutlet *)pd_new(voutlet_class); | ||
322 | x->x_canvas = canvas_getcurrent(); | ||
323 | x->x_parentoutlet = canvas_addoutlet(x->x_canvas, &x->x_obj.ob_pd, 0); | ||
324 | inlet_new(&x->x_obj, &x->x_obj.ob_pd, 0, 0); | ||
325 | x->x_bufsize = 0; | ||
326 | x->x_buf = 0; | ||
327 | return (x); | ||
328 | } | ||
329 | |||
330 | static void voutlet_bang(t_voutlet *x) | ||
331 | { | ||
332 | outlet_bang(x->x_parentoutlet); | ||
333 | } | ||
334 | |||
335 | static void voutlet_pointer(t_voutlet *x, t_gpointer *gp) | ||
336 | { | ||
337 | outlet_pointer(x->x_parentoutlet, gp); | ||
338 | } | ||
339 | |||
340 | static void voutlet_float(t_voutlet *x, t_float f) | ||
341 | { | ||
342 | outlet_float(x->x_parentoutlet, f); | ||
343 | } | ||
344 | |||
345 | static void voutlet_symbol(t_voutlet *x, t_symbol *s) | ||
346 | { | ||
347 | outlet_symbol(x->x_parentoutlet, s); | ||
348 | } | ||
349 | |||
350 | static void voutlet_list(t_voutlet *x, t_symbol *s, int argc, t_atom *argv) | ||
351 | { | ||
352 | outlet_list(x->x_parentoutlet, s, argc, argv); | ||
353 | } | ||
354 | |||
355 | static void voutlet_anything(t_voutlet *x, t_symbol *s, int argc, t_atom *argv) | ||
356 | { | ||
357 | outlet_anything(x->x_parentoutlet, s, argc, argv); | ||
358 | } | ||
359 | |||
360 | static void voutlet_free(t_voutlet *x) | ||
361 | { | ||
362 | canvas_rmoutlet(x->x_canvas, x->x_parentoutlet); | ||
363 | resample_free(&x->x_updown); | ||
364 | } | ||
365 | |||
366 | t_outlet *voutlet_getit(t_pd *x) | ||
367 | { | ||
368 | if (pd_class(x) != voutlet_class) bug("voutlet_getit"); | ||
369 | return (((t_voutlet *)x)->x_parentoutlet); | ||
370 | } | ||
371 | |||
372 | /* ------------------------- signal outlet -------------------------- */ | ||
373 | |||
374 | int voutlet_issignal(t_voutlet *x) | ||
375 | { | ||
376 | return (x->x_buf != 0); | ||
377 | } | ||
378 | |||
379 | /* LATER optimize for non-overlapped case where the "+=" isn't needed */ | ||
380 | t_int *voutlet_perform(t_int *w) | ||
381 | { | ||
382 | t_voutlet *x = (t_voutlet *)(w[1]); | ||
383 | t_sample *in = (t_sample *)(w[2]); | ||
384 | int n = (int)(w[3]); | ||
385 | t_sample *out = x->x_write, *outwas = out; | ||
386 | #if 0 | ||
387 | if (tot < 5) post("-in %x out %x n %d", in, out, n); | ||
388 | if (tot < 5) post("-buf %x endbuf %x", x->x_buf, x->x_endbuf); | ||
389 | #endif | ||
390 | while (n--) | ||
391 | { | ||
392 | *out++ += *in++; | ||
393 | if (out == x->x_endbuf) out = x->x_buf; | ||
394 | } | ||
395 | outwas += x->x_hop; | ||
396 | if (outwas >= x->x_endbuf) outwas = x->x_buf; | ||
397 | x->x_write = outwas; | ||
398 | return (w+4); | ||
399 | } | ||
400 | |||
401 | /* epilog code for blocking: write buffer to parent patch */ | ||
402 | static t_int *voutlet_doepilog(t_int *w) | ||
403 | { | ||
404 | t_voutlet *x = (t_voutlet *)(w[1]); | ||
405 | t_sample *out = (t_sample *)(w[2]); /* IOhannes */ | ||
406 | |||
407 | int n = (int)(w[3]); | ||
408 | t_sample *in = x->x_empty; | ||
409 | if (x->x_updown.downsample != x->x_updown.upsample) out = x->x_updown.s_vec; /* IOhannes */ | ||
410 | |||
411 | #if 0 | ||
412 | if (tot < 5) post("outlet in %x out %x n %x", in, out, n), tot++; | ||
413 | #endif | ||
414 | for (; n--; in++) *out++ = *in, *in = 0; | ||
415 | if (in == x->x_endbuf) in = x->x_buf; | ||
416 | x->x_empty = in; | ||
417 | return (w+4); | ||
418 | } | ||
419 | |||
420 | /* IOhannes { */ | ||
421 | static t_int *voutlet_doepilog_resampling(t_int *w) | ||
422 | { | ||
423 | t_voutlet *x = (t_voutlet *)(w[1]); | ||
424 | // t_float *dummy = (t_float *)(w[2]); | ||
425 | int n = (int)(w[2]); | ||
426 | t_sample *in = x->x_empty; | ||
427 | t_sample *out = x->x_updown.s_vec; /* IOhannes */ | ||
428 | |||
429 | #if 0 | ||
430 | if (tot < 5) post("outlet in %x out %x n %x", in, out, n), tot++; | ||
431 | #endif | ||
432 | for (; n--; in++) *out++ = *in, *in = 0; | ||
433 | if (in == x->x_endbuf) in = x->x_buf; | ||
434 | x->x_empty = in; | ||
435 | return (w+3); | ||
436 | } | ||
437 | /* } IOhannes */ | ||
438 | int outlet_getsignalindex(t_outlet *x); | ||
439 | |||
440 | /* prolog for outlets -- store pointer to the outlet on the | ||
441 | parent, which, if "reblock" is false, will want to refer | ||
442 | back to whatever we see on our input during the "dsp" method | ||
443 | called later. */ | ||
444 | void voutlet_dspprolog(t_voutlet *x, t_signal **parentsigs, | ||
445 | int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock, | ||
446 | int switched) | ||
447 | { | ||
448 | x->x_updown.downsample=downsample; x->x_updown.upsample=upsample; /* IOhannes */ | ||
449 | x->x_justcopyout = (switched && !reblock); | ||
450 | if (reblock) | ||
451 | { | ||
452 | x->x_directsignal = 0; | ||
453 | } | ||
454 | else | ||
455 | { | ||
456 | if (!parentsigs) bug("voutlet_dspprolog"); | ||
457 | x->x_directsignal = | ||
458 | parentsigs[outlet_getsignalindex(x->x_parentoutlet)]; | ||
459 | } | ||
460 | } | ||
461 | |||
462 | static void voutlet_dsp(t_voutlet *x, t_signal **sp) | ||
463 | { | ||
464 | t_signal *insig; | ||
465 | if (!x->x_buf) return; | ||
466 | insig = sp[0]; | ||
467 | if (x->x_justcopyout) | ||
468 | dsp_add_copy(insig->s_vec, x->x_directsignal->s_vec, insig->s_n); | ||
469 | else if (x->x_directsignal) | ||
470 | { | ||
471 | /* if we're just going to make the signal available on the | ||
472 | parent patch, hand it off to the parent signal. */ | ||
473 | /* this is done elsewhere--> sp[0]->s_refcount++; */ | ||
474 | signal_setborrowed(x->x_directsignal, sp[0]); | ||
475 | } | ||
476 | else | ||
477 | dsp_add(voutlet_perform, 3, x, insig->s_vec, insig->s_n); | ||
478 | } | ||
479 | |||
480 | /* set up epilog DSP code. If we're reblocking, this is the | ||
481 | time to copy the samples out to the containing object's outlets. | ||
482 | If we aren't reblocking, there's nothing to do here. */ | ||
483 | void voutlet_dspepilog(t_voutlet *x, t_signal **parentsigs, | ||
484 | int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock, | ||
485 | int switched) | ||
486 | { | ||
487 | if (!x->x_buf) return; /* this shouldn't be necesssary... */ | ||
488 | x->x_updown.downsample=downsample; x->x_updown.upsample=upsample; /* IOhannes */ | ||
489 | if (reblock) | ||
490 | { | ||
491 | t_signal *insig, *outsig; | ||
492 | int parentvecsize, bufsize, oldbufsize; | ||
493 | int re_parentvecsize; /* IOhannes */ | ||
494 | int bigperiod, epilogphase, blockphase; | ||
495 | if (parentsigs) | ||
496 | { | ||
497 | outsig = parentsigs[outlet_getsignalindex(x->x_parentoutlet)]; | ||
498 | parentvecsize = outsig->s_n; | ||
499 | re_parentvecsize = parentvecsize * upsample / downsample; | ||
500 | } | ||
501 | else | ||
502 | { | ||
503 | outsig = 0; | ||
504 | parentvecsize = 1; | ||
505 | re_parentvecsize = 1; | ||
506 | } | ||
507 | // bigperiod = (downsample * myvecsize)/(upsample * parentvecsize); /* IOhannes */ | ||
508 | bigperiod = myvecsize/re_parentvecsize; /* IOhannes */ | ||
509 | if (!bigperiod) bigperiod = 1; | ||
510 | epilogphase = phase & (bigperiod - 1); | ||
511 | blockphase = (phase + period - 1) & (bigperiod - 1) & (- period); | ||
512 | // bufsize = parentvecsize * upsample; /* IOhannes */ | ||
513 | bufsize = re_parentvecsize; /* IOhannes */ | ||
514 | if (bufsize < myvecsize) bufsize = myvecsize; | ||
515 | if (bufsize != (oldbufsize = x->x_bufsize)) | ||
516 | { | ||
517 | t_sample *buf = x->x_buf; | ||
518 | t_freebytes(buf, oldbufsize * sizeof(*buf)); | ||
519 | buf = (t_sample *)t_getbytes(bufsize * sizeof(*buf)); | ||
520 | memset((char *)buf, 0, bufsize * sizeof(*buf)); | ||
521 | x->x_bufsize = bufsize; | ||
522 | x->x_endbuf = buf + bufsize; | ||
523 | x->x_buf = buf; | ||
524 | } | ||
525 | /* IOhannes: { */ | ||
526 | if (re_parentvecsize * period > bufsize) bug("voutlet_dspepilog"); | ||
527 | x->x_write = x->x_buf + re_parentvecsize * blockphase; | ||
528 | if (x->x_write == x->x_endbuf) x->x_write = x->x_buf; | ||
529 | if (period == 1 && frequency > 1) | ||
530 | x->x_hop = re_parentvecsize / frequency; | ||
531 | else x->x_hop = period * re_parentvecsize; | ||
532 | /* } IOhannes */ | ||
533 | /* post("phase %d, block %d, parent %d", phase & 63, | ||
534 | parentvecsize * blockphase, parentvecsize * epilogphase); */ | ||
535 | if (parentsigs) | ||
536 | { | ||
537 | /* set epilog pointer and schedule it */ | ||
538 | /* IOhannes { */ | ||
539 | x->x_empty = x->x_buf + re_parentvecsize * epilogphase; | ||
540 | if (upsample * downsample == 1) | ||
541 | dsp_add(voutlet_doepilog, 3, x, outsig->s_vec, re_parentvecsize); | ||
542 | else { | ||
543 | dsp_add(voutlet_doepilog_resampling, 2, x, re_parentvecsize); | ||
544 | resampleto_dsp(&x->x_updown, outsig->s_vec, re_parentvecsize, parentvecsize, x->x_updown.method); | ||
545 | } | ||
546 | /* } IOhannes */ | ||
547 | } | ||
548 | } | ||
549 | /* if we aren't blocked but we are switched, the epilog code just | ||
550 | copies zeros to the output. In this case the blocking code actually | ||
551 | jumps over the epilog if the block is running. */ | ||
552 | else if (switched) | ||
553 | { | ||
554 | if (parentsigs) | ||
555 | { | ||
556 | t_signal *outsig = | ||
557 | parentsigs[outlet_getsignalindex(x->x_parentoutlet)]; | ||
558 | dsp_add_zero(outsig->s_vec, outsig->s_n); | ||
559 | } | ||
560 | } | ||
561 | } | ||
562 | |||
563 | static void *voutlet_newsig(t_symbol *s) | ||
564 | { | ||
565 | t_voutlet *x = (t_voutlet *)pd_new(voutlet_class); | ||
566 | x->x_canvas = canvas_getcurrent(); | ||
567 | x->x_parentoutlet = canvas_addoutlet(x->x_canvas, | ||
568 | &x->x_obj.ob_pd, &s_signal); | ||
569 | inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); | ||
570 | x->x_endbuf = x->x_buf = (t_sample *)getbytes(0); | ||
571 | x->x_bufsize = 0; | ||
572 | |||
573 | resample_init(&x->x_updown); | ||
574 | |||
575 | /* this should be though over: | ||
576 | * it might prove hard to provide consistency between labeled up- & downsampling methods | ||
577 | * maybe indeces would be better... | ||
578 | * | ||
579 | * up till now we provide several upsampling methods and 1 single downsampling method (no filtering !) | ||
580 | */ | ||
581 | if (s == gensym("hold"))x->x_updown.method=1; /* up: sample and hold */ | ||
582 | else if (s == gensym("lin"))x->x_updown.method=2; /* up: linear interpolation */ | ||
583 | else if (s == gensym("linear"))x->x_updown.method=2; /* up: linear interpolation */ | ||
584 | else x->x_updown.method=0; /* up: zero-padding; down: ignore samples inbetween */ | ||
585 | |||
586 | return (x); | ||
587 | } | ||
588 | |||
589 | |||
590 | static void voutlet_setup(void) | ||
591 | { | ||
592 | voutlet_class = class_new(gensym("outlet"), (t_newmethod)voutlet_new, | ||
593 | (t_method)voutlet_free, sizeof(t_voutlet), CLASS_NOINLET, A_DEFSYM, 0); | ||
594 | class_addcreator((t_newmethod)voutlet_newsig, gensym("outlet~"), A_DEFSYM, 0); | ||
595 | class_addbang(voutlet_class, voutlet_bang); | ||
596 | class_addpointer(voutlet_class, voutlet_pointer); | ||
597 | class_addfloat(voutlet_class, (t_method)voutlet_float); | ||
598 | class_addsymbol(voutlet_class, voutlet_symbol); | ||
599 | class_addlist(voutlet_class, voutlet_list); | ||
600 | class_addanything(voutlet_class, voutlet_anything); | ||
601 | class_addmethod(voutlet_class, (t_method)voutlet_dsp, gensym("dsp"), 0); | ||
602 | class_sethelpsymbol(voutlet_class, gensym("pd")); | ||
603 | } | ||
604 | |||
605 | |||
606 | /* ---------------------------- overall setup ----------------------------- */ | ||
607 | |||
608 | void g_io_setup(void) | ||
609 | { | ||
610 | vinlet_setup(); | ||
611 | voutlet_setup(); | ||
612 | } | ||
613 | /* Copyright (c) 1997-1999 Miller Puckette. | ||
614 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
615 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | ||
616 | |||
617 | /* graphical inlets and outlets, both for control and signals. */ | ||
618 | |||
619 | /* This code is highly inefficient; messages actually have to be forwarded | ||
620 | by inlets and outlets. The outlet is in even worse shape than the inlet; | ||
621 | in order to avoid having a "signal" method in the class, the oulet actually | ||
622 | sprouts an inlet, which forwards the message to the "outlet" object, which | ||
623 | sends it on to the outlet proper. Another way to do it would be to have | ||
624 | separate classes for "signal" and "control" outlets, but this would complicate | ||
625 | life elsewhere. */ | ||
626 | |||
627 | |||
628 | /* hacked to run subpatches with different samplerates | ||
629 | * | ||
630 | * mfg.gfd.uil | ||
631 | * IOhannes | ||
632 | * | ||
633 | * edited lines are marked with "IOhannes" | ||
634 | * | ||
635 | */ | ||
636 | |||
637 | #include "m_pd.h" | ||
638 | #include "g_canvas.h" | ||
639 | #include <string.h> | ||
640 | void signal_setborrowed(t_signal *sig, t_signal *sig2); | ||
641 | void signal_makereusable(t_signal *sig); | ||
642 | |||
643 | /* ------------------------- vinlet -------------------------- */ | ||
644 | t_class *vinlet_class; | ||
645 | |||
646 | typedef struct _vinlet | ||
647 | { | ||
648 | t_object x_obj; | ||
649 | t_canvas *x_canvas; | ||
650 | t_inlet *x_inlet; | ||
651 | int x_bufsize; | ||
652 | t_float *x_buf; /* signal buffer; zero if not a signal */ | ||
653 | t_float *x_endbuf; | ||
654 | t_float *x_fill; | ||
655 | t_float *x_read; | ||
656 | int x_hop; | ||
657 | /* if not reblocking, the next slot communicates the parent's inlet | ||
658 | signal from the prolog to the DSP routine: */ | ||
659 | t_signal *x_directsignal; | ||
660 | |||
661 | t_resample x_updown; /* IOhannes */ | ||
662 | } t_vinlet; | ||
663 | |||
664 | static void *vinlet_new(t_symbol *s) | ||
665 | { | ||
666 | t_vinlet *x = (t_vinlet *)pd_new(vinlet_class); | ||
667 | x->x_canvas = canvas_getcurrent(); | ||
668 | x->x_inlet = canvas_addinlet(x->x_canvas, &x->x_obj.ob_pd, 0); | ||
669 | x->x_bufsize = 0; | ||
670 | x->x_buf = 0; | ||
671 | outlet_new(&x->x_obj, 0); | ||
672 | return (x); | ||
673 | } | ||
674 | |||
675 | static void vinlet_bang(t_vinlet *x) | ||
676 | { | ||
677 | outlet_bang(x->x_obj.ob_outlet); | ||
678 | } | ||
679 | |||
680 | static void vinlet_pointer(t_vinlet *x, t_gpointer *gp) | ||
681 | { | ||
682 | outlet_pointer(x->x_obj.ob_outlet, gp); | ||
683 | } | ||
684 | |||
685 | static void vinlet_float(t_vinlet *x, t_float f) | ||
686 | { | ||
687 | outlet_float(x->x_obj.ob_outlet, f); | ||
688 | } | ||
689 | |||
690 | static void vinlet_symbol(t_vinlet *x, t_symbol *s) | ||
691 | { | ||
692 | outlet_symbol(x->x_obj.ob_outlet, s); | ||
693 | } | ||
694 | |||
695 | static void vinlet_list(t_vinlet *x, t_symbol *s, int argc, t_atom *argv) | ||
696 | { | ||
697 | outlet_list(x->x_obj.ob_outlet, s, argc, argv); | ||
698 | } | ||
699 | |||
700 | static void vinlet_anything(t_vinlet *x, t_symbol *s, int argc, t_atom *argv) | ||
701 | { | ||
702 | outlet_anything(x->x_obj.ob_outlet, s, argc, argv); | ||
703 | } | ||
704 | |||
705 | static void vinlet_free(t_vinlet *x) | ||
706 | { | ||
707 | canvas_rminlet(x->x_canvas, x->x_inlet); | ||
708 | resample_free(&x->x_updown); | ||
709 | } | ||
710 | |||
711 | t_inlet *vinlet_getit(t_pd *x) | ||
712 | { | ||
713 | if (pd_class(x) != vinlet_class) bug("vinlet_getit"); | ||
714 | return (((t_vinlet *)x)->x_inlet); | ||
715 | } | ||
716 | |||
717 | /* ------------------------- signal inlet -------------------------- */ | ||
718 | int vinlet_issignal(t_vinlet *x) | ||
719 | { | ||
720 | return (x->x_buf != 0); | ||
721 | } | ||
722 | |||
723 | static int tot; | ||
724 | |||
725 | t_int *vinlet_perform(t_int *w) | ||
726 | { | ||
727 | t_vinlet *x = (t_vinlet *)(w[1]); | ||
728 | t_float *out = (t_float *)(w[2]); | ||
729 | int n = (int)(w[3]); | ||
730 | t_float *in = x->x_read; | ||
731 | #if 0 | ||
732 | if (tot < 5) post("-in %x out %x n %d", in, out, n); | ||
733 | if (tot < 5) post("-buf %x endbuf %x", x->x_buf, x->x_endbuf); | ||
734 | if (tot < 5) post("in[0] %f in[1] %f in[2] %f", in[0], in[1], in[2]); | ||
735 | #endif | ||
736 | while (n--) *out++ = *in++; | ||
737 | if (in == x->x_endbuf) in = x->x_buf; | ||
738 | x->x_read = in; | ||
739 | return (w+4); | ||
740 | } | ||
741 | |||
742 | static void vinlet_dsp(t_vinlet *x, t_signal **sp) | ||
743 | { | ||
744 | t_signal *outsig; | ||
745 | /* no buffer means we're not a signal inlet */ | ||
746 | if (!x->x_buf) | ||
747 | return; | ||
748 | outsig = sp[0]; | ||
749 | if (x->x_directsignal) | ||
750 | { | ||
751 | signal_setborrowed(sp[0], x->x_directsignal); | ||
752 | } | ||
753 | else | ||
754 | { | ||
755 | dsp_add(vinlet_perform, 3, x, outsig->s_vec, outsig->s_n); | ||
756 | x->x_read = x->x_buf; | ||
757 | } | ||
758 | } | ||
759 | |||
760 | /* prolog code: loads buffer from parent patch */ | ||
761 | t_int *vinlet_doprolog(t_int *w) | ||
762 | { | ||
763 | t_vinlet *x = (t_vinlet *)(w[1]); | ||
764 | t_float *in = (t_float *)(w[2]); | ||
765 | int n = (int)(w[3]); | ||
766 | t_float *out = x->x_fill; | ||
767 | if (out == x->x_endbuf) | ||
768 | { | ||
769 | t_float *f1 = x->x_buf, *f2 = x->x_buf + x->x_hop; | ||
770 | int nshift = x->x_bufsize - x->x_hop; | ||
771 | out -= x->x_hop; | ||
772 | while (nshift--) *f1++ = *f2++; | ||
773 | } | ||
774 | #if 0 | ||
775 | if (tot < 5) post("in %x out %x n %x", in, out, n), tot++; | ||
776 | if (tot < 5) post("in[0] %f in[1] %f in[2] %f", in[0], in[1], in[2]); | ||
777 | #endif | ||
778 | |||
779 | while (n--) *out++ = *in++; | ||
780 | x->x_fill = out; | ||
781 | return (w+4); | ||
782 | } | ||
783 | |||
784 | int inlet_getsignalindex(t_inlet *x); | ||
785 | |||
786 | /* set up prolog DSP code */ | ||
787 | void vinlet_dspprolog(t_vinlet *x, t_signal **parentsigs, | ||
788 | int myvecsize, int phase, int period, int frequency, int downsample, int upsample/* IOhannes */, int reblock, | ||
789 | int switched) | ||
790 | { | ||
791 | t_signal *insig, *outsig; | ||
792 | x->x_updown.downsample = downsample; | ||
793 | x->x_updown.upsample = upsample; | ||
794 | |||
795 | /* if the "reblock" flag is set, arrange to copy data in from the | ||
796 | parent. */ | ||
797 | if (reblock) | ||
798 | { | ||
799 | int parentvecsize, bufsize, oldbufsize, prologphase; | ||
800 | int re_parentvecsize; /* resampled parentvectorsize: IOhannes */ | ||
801 | /* this should never happen: */ | ||
802 | if (!x->x_buf) return; | ||
803 | |||
804 | /* the prolog code counts from 0 to period-1; the | ||
805 | phase is backed up by one so that AFTER the prolog code | ||
806 | runs, the "x_fill" phase is in sync with the "x_read" phase. */ | ||
807 | prologphase = (phase - 1) & (period - 1); | ||
808 | if (parentsigs) | ||
809 | { | ||
810 | insig = parentsigs[inlet_getsignalindex(x->x_inlet)]; | ||
811 | parentvecsize = insig->s_n; | ||
812 | re_parentvecsize = parentvecsize * upsample / downsample; | ||
813 | } | ||
814 | else | ||
815 | { | ||
816 | insig = 0; | ||
817 | parentvecsize = 1; | ||
818 | re_parentvecsize = 1; | ||
819 | } | ||
820 | |||
821 | bufsize = re_parentvecsize; | ||
822 | if (bufsize < myvecsize) bufsize = myvecsize; | ||
823 | if (bufsize != (oldbufsize = x->x_bufsize)) | ||
824 | { | ||
825 | t_float *buf = x->x_buf; | ||
826 | t_freebytes(buf, oldbufsize * sizeof(*buf)); | ||
827 | buf = (t_float *)t_getbytes(bufsize * sizeof(*buf)); | ||
828 | memset((char *)buf, 0, bufsize * sizeof(*buf)); | ||
829 | x->x_bufsize = bufsize; | ||
830 | x->x_endbuf = buf + bufsize; | ||
831 | x->x_buf = buf; | ||
832 | } | ||
833 | if (parentsigs) | ||
834 | { | ||
835 | /* IOhannes { */ | ||
836 | x->x_hop = period * re_parentvecsize; | ||
837 | |||
838 | x->x_fill = x->x_endbuf - | ||
839 | (x->x_hop - prologphase * re_parentvecsize); | ||
840 | |||
841 | if (upsample * downsample == 1) | ||
842 | dsp_add(vinlet_doprolog, 3, x, insig->s_vec, re_parentvecsize); | ||
843 | else { | ||
844 | resamplefrom_dsp(&x->x_updown, insig->s_vec, parentvecsize, re_parentvecsize, x->x_updown.method); | ||
845 | dsp_add(vinlet_doprolog, 3, x, x->x_updown.s_vec, re_parentvecsize); | ||
846 | } | ||
847 | |||
848 | /* } IOhannes */ | ||
849 | /* if the input signal's reference count is zero, we have | ||
850 | to free it here because we didn't in ugen_doit(). */ | ||
851 | if (!insig->s_refcount) | ||
852 | signal_makereusable(insig); | ||
853 | } | ||
854 | else memset((char *)(x->x_buf), 0, bufsize * sizeof(*x->x_buf)); | ||
855 | x->x_directsignal = 0; | ||
856 | } | ||
857 | else | ||
858 | { | ||
859 | /* no reblocking; in this case our output signal is "borrowed" | ||
860 | and merely needs to be pointed to the real one. */ | ||
861 | x->x_directsignal = parentsigs[inlet_getsignalindex(x->x_inlet)]; | ||
862 | } | ||
863 | } | ||
864 | |||
865 | //static void *vinlet_newsig(void) | ||
866 | static void *vinlet_newsig(t_symbol *s) | ||
867 | { | ||
868 | t_vinlet *x = (t_vinlet *)pd_new(vinlet_class); | ||
869 | x->x_canvas = canvas_getcurrent(); | ||
870 | x->x_inlet = canvas_addinlet(x->x_canvas, &x->x_obj.ob_pd, &s_signal); | ||
871 | x->x_endbuf = x->x_buf = (t_float *)getbytes(0); | ||
872 | x->x_bufsize = 0; | ||
873 | x->x_directsignal = 0; | ||
874 | outlet_new(&x->x_obj, &s_signal); | ||
875 | |||
876 | resample_init(&x->x_updown); | ||
877 | |||
878 | /* this should be though over: | ||
879 | * it might prove hard to provide consistency between labeled up- & downsampling methods | ||
880 | * maybe indeces would be better... | ||
881 | * | ||
882 | * up till now we provide several upsampling methods and 1 single downsampling method (no filtering !) | ||
883 | */ | ||
884 | if (s == gensym("hold"))x->x_updown.method=1; /* up: sample and hold */ | ||
885 | else if (s == gensym("lin"))x->x_updown.method=2; /* up: linear interpolation */ | ||
886 | else x->x_updown.method=0; /* up: zero-padding */ | ||
887 | |||
888 | return (x); | ||
889 | } | ||
890 | |||
891 | static void vinlet_setup(void) | ||
892 | { | ||
893 | vinlet_class = class_new(gensym("inlet"), (t_newmethod)vinlet_new, | ||
894 | (t_method)vinlet_free, sizeof(t_vinlet), CLASS_NOINLET, A_DEFSYM, 0); | ||
895 | class_addcreator((t_newmethod)vinlet_newsig, gensym("inlet~"), A_DEFSYM, 0); | ||
896 | class_addbang(vinlet_class, vinlet_bang); | ||
897 | class_addpointer(vinlet_class, vinlet_pointer); | ||
898 | class_addfloat(vinlet_class, vinlet_float); | ||
899 | class_addsymbol(vinlet_class, vinlet_symbol); | ||
900 | class_addlist(vinlet_class, vinlet_list); | ||
901 | class_addanything(vinlet_class, vinlet_anything); | ||
902 | class_addmethod(vinlet_class, (t_method)vinlet_dsp, gensym("dsp"), 0); | ||
903 | class_sethelpsymbol(vinlet_class, gensym("pd")); | ||
904 | } | ||
905 | |||
906 | /* ------------------------- voutlet -------------------------- */ | ||
907 | |||
908 | t_class *voutlet_class; | ||
909 | |||
910 | typedef struct _voutlet | ||
911 | { | ||
912 | t_object x_obj; | ||
913 | t_canvas *x_canvas; | ||
914 | t_outlet *x_parentoutlet; | ||
915 | int x_bufsize; | ||
916 | t_sample *x_buf; /* signal buffer; zero if not a signal */ | ||
917 | t_sample *x_endbuf; | ||
918 | t_sample *x_empty; /* next to read out of buffer in epilog code */ | ||
919 | t_sample *x_write; /* next to write in to buffer */ | ||
920 | int x_hop; /* hopsize */ | ||
921 | /* vice versa from the inlet, if we don't block, this holds the | ||
922 | parent's outlet signal, valid between the prolog and the dsp setup | ||
923 | routines. */ | ||
924 | t_signal *x_directsignal; | ||
925 | /* and here's a flag indicating that we aren't blocked but have to | ||
926 | do a copy (because we're switched). */ | ||
927 | char x_justcopyout; | ||
928 | t_resample x_updown; /* IOhannes */ | ||
929 | } t_voutlet; | ||
930 | |||
931 | static void *voutlet_new(t_symbol *s) | ||
932 | { | ||
933 | t_voutlet *x = (t_voutlet *)pd_new(voutlet_class); | ||
934 | x->x_canvas = canvas_getcurrent(); | ||
935 | x->x_parentoutlet = canvas_addoutlet(x->x_canvas, &x->x_obj.ob_pd, 0); | ||
936 | inlet_new(&x->x_obj, &x->x_obj.ob_pd, 0, 0); | ||
937 | x->x_bufsize = 0; | ||
938 | x->x_buf = 0; | ||
939 | return (x); | ||
940 | } | ||
941 | |||
942 | static void voutlet_bang(t_voutlet *x) | ||
943 | { | ||
944 | outlet_bang(x->x_parentoutlet); | ||
945 | } | ||
946 | |||
947 | static void voutlet_pointer(t_voutlet *x, t_gpointer *gp) | ||
948 | { | ||
949 | outlet_pointer(x->x_parentoutlet, gp); | ||
950 | } | ||
951 | |||
952 | static void voutlet_float(t_voutlet *x, t_float f) | ||
953 | { | ||
954 | outlet_float(x->x_parentoutlet, f); | ||
955 | } | ||
956 | |||
957 | static void voutlet_symbol(t_voutlet *x, t_symbol *s) | ||
958 | { | ||
959 | outlet_symbol(x->x_parentoutlet, s); | ||
960 | } | ||
961 | |||
962 | static void voutlet_list(t_voutlet *x, t_symbol *s, int argc, t_atom *argv) | ||
963 | { | ||
964 | outlet_list(x->x_parentoutlet, s, argc, argv); | ||
965 | } | ||
966 | |||
967 | static void voutlet_anything(t_voutlet *x, t_symbol *s, int argc, t_atom *argv) | ||
968 | { | ||
969 | outlet_anything(x->x_parentoutlet, s, argc, argv); | ||
970 | } | ||
971 | |||
972 | static void voutlet_free(t_voutlet *x) | ||
973 | { | ||
974 | canvas_rmoutlet(x->x_canvas, x->x_parentoutlet); | ||
975 | resample_free(&x->x_updown); | ||
976 | } | ||
977 | |||
978 | t_outlet *voutlet_getit(t_pd *x) | ||
979 | { | ||
980 | if (pd_class(x) != voutlet_class) bug("voutlet_getit"); | ||
981 | return (((t_voutlet *)x)->x_parentoutlet); | ||
982 | } | ||
983 | |||
984 | /* ------------------------- signal outlet -------------------------- */ | ||
985 | |||
986 | int voutlet_issignal(t_voutlet *x) | ||
987 | { | ||
988 | return (x->x_buf != 0); | ||
989 | } | ||
990 | |||
991 | /* LATER optimize for non-overlapped case where the "+=" isn't needed */ | ||
992 | t_int *voutlet_perform(t_int *w) | ||
993 | { | ||
994 | t_voutlet *x = (t_voutlet *)(w[1]); | ||
995 | t_sample *in = (t_sample *)(w[2]); | ||
996 | int n = (int)(w[3]); | ||
997 | t_sample *out = x->x_write, *outwas = out; | ||
998 | #if 0 | ||
999 | if (tot < 5) post("-in %x out %x n %d", in, out, n); | ||
1000 | if (tot < 5) post("-buf %x endbuf %x", x->x_buf, x->x_endbuf); | ||
1001 | #endif | ||
1002 | while (n--) | ||
1003 | { | ||
1004 | *out++ += *in++; | ||
1005 | if (out == x->x_endbuf) out = x->x_buf; | ||
1006 | } | ||
1007 | outwas += x->x_hop; | ||
1008 | if (outwas >= x->x_endbuf) outwas = x->x_buf; | ||
1009 | x->x_write = outwas; | ||
1010 | return (w+4); | ||
1011 | } | ||
1012 | |||
1013 | /* epilog code for blocking: write buffer to parent patch */ | ||
1014 | static t_int *voutlet_doepilog(t_int *w) | ||
1015 | { | ||
1016 | t_voutlet *x = (t_voutlet *)(w[1]); | ||
1017 | t_sample *out = (t_sample *)(w[2]); /* IOhannes */ | ||
1018 | |||
1019 | int n = (int)(w[3]); | ||
1020 | t_sample *in = x->x_empty; | ||
1021 | if (x->x_updown.downsample != x->x_updown.upsample) out = x->x_updown.s_vec; /* IOhannes */ | ||
1022 | |||
1023 | #if 0 | ||
1024 | if (tot < 5) post("outlet in %x out %x n %x", in, out, n), tot++; | ||
1025 | #endif | ||
1026 | for (; n--; in++) *out++ = *in, *in = 0; | ||
1027 | if (in == x->x_endbuf) in = x->x_buf; | ||
1028 | x->x_empty = in; | ||
1029 | return (w+4); | ||
1030 | } | ||
1031 | |||
1032 | /* IOhannes { */ | ||
1033 | static t_int *voutlet_doepilog_resampling(t_int *w) | ||
1034 | { | ||
1035 | t_voutlet *x = (t_voutlet *)(w[1]); | ||
1036 | // t_float *dummy = (t_float *)(w[2]); | ||
1037 | int n = (int)(w[2]); | ||
1038 | t_sample *in = x->x_empty; | ||
1039 | t_sample *out = x->x_updown.s_vec; /* IOhannes */ | ||
1040 | |||
1041 | #if 0 | ||
1042 | if (tot < 5) post("outlet in %x out %x n %x", in, out, n), tot++; | ||
1043 | #endif | ||
1044 | for (; n--; in++) *out++ = *in, *in = 0; | ||
1045 | if (in == x->x_endbuf) in = x->x_buf; | ||
1046 | x->x_empty = in; | ||
1047 | return (w+3); | ||
1048 | } | ||
1049 | /* } IOhannes */ | ||
1050 | int outlet_getsignalindex(t_outlet *x); | ||
1051 | |||
1052 | /* prolog for outlets -- store pointer to the outlet on the | ||
1053 | parent, which, if "reblock" is false, will want to refer | ||
1054 | back to whatever we see on our input during the "dsp" method | ||
1055 | called later. */ | ||
1056 | void voutlet_dspprolog(t_voutlet *x, t_signal **parentsigs, | ||
1057 | int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock, | ||
1058 | int switched) | ||
1059 | { | ||
1060 | x->x_updown.downsample=downsample; x->x_updown.upsample=upsample; /* IOhannes */ | ||
1061 | x->x_justcopyout = (switched && !reblock); | ||
1062 | if (reblock) | ||
1063 | { | ||
1064 | x->x_directsignal = 0; | ||
1065 | } | ||
1066 | else | ||
1067 | { | ||
1068 | if (!parentsigs) bug("voutlet_dspprolog"); | ||
1069 | x->x_directsignal = | ||
1070 | parentsigs[outlet_getsignalindex(x->x_parentoutlet)]; | ||
1071 | } | ||
1072 | } | ||
1073 | |||
1074 | static void voutlet_dsp(t_voutlet *x, t_signal **sp) | ||
1075 | { | ||
1076 | t_signal *insig; | ||
1077 | if (!x->x_buf) return; | ||
1078 | insig = sp[0]; | ||
1079 | if (x->x_justcopyout) | ||
1080 | dsp_add_copy(insig->s_vec, x->x_directsignal->s_vec, insig->s_n); | ||
1081 | else if (x->x_directsignal) | ||
1082 | { | ||
1083 | /* if we're just going to make the signal available on the | ||
1084 | parent patch, hand it off to the parent signal. */ | ||
1085 | /* this is done elsewhere--> sp[0]->s_refcount++; */ | ||
1086 | signal_setborrowed(x->x_directsignal, sp[0]); | ||
1087 | } | ||
1088 | else | ||
1089 | dsp_add(voutlet_perform, 3, x, insig->s_vec, insig->s_n); | ||
1090 | } | ||
1091 | |||
1092 | /* set up epilog DSP code. If we're reblocking, this is the | ||
1093 | time to copy the samples out to the containing object's outlets. | ||
1094 | If we aren't reblocking, there's nothing to do here. */ | ||
1095 | void voutlet_dspepilog(t_voutlet *x, t_signal **parentsigs, | ||
1096 | int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock, | ||
1097 | int switched) | ||
1098 | { | ||
1099 | if (!x->x_buf) return; /* this shouldn't be necesssary... */ | ||
1100 | x->x_updown.downsample=downsample; x->x_updown.upsample=upsample; /* IOhannes */ | ||
1101 | if (reblock) | ||
1102 | { | ||
1103 | t_signal *insig, *outsig; | ||
1104 | int parentvecsize, bufsize, oldbufsize; | ||
1105 | int re_parentvecsize; /* IOhannes */ | ||
1106 | int bigperiod, epilogphase, blockphase; | ||
1107 | if (parentsigs) | ||
1108 | { | ||
1109 | outsig = parentsigs[outlet_getsignalindex(x->x_parentoutlet)]; | ||
1110 | parentvecsize = outsig->s_n; | ||
1111 | re_parentvecsize = parentvecsize * upsample / downsample; | ||
1112 | } | ||
1113 | else | ||
1114 | { | ||
1115 | outsig = 0; | ||
1116 | parentvecsize = 1; | ||
1117 | re_parentvecsize = 1; | ||
1118 | } | ||
1119 | // bigperiod = (downsample * myvecsize)/(upsample * parentvecsize); /* IOhannes */ | ||
1120 | bigperiod = myvecsize/re_parentvecsize; /* IOhannes */ | ||
1121 | if (!bigperiod) bigperiod = 1; | ||
1122 | epilogphase = phase & (bigperiod - 1); | ||
1123 | blockphase = (phase + period - 1) & (bigperiod - 1) & (- period); | ||
1124 | // bufsize = parentvecsize * upsample; /* IOhannes */ | ||
1125 | bufsize = re_parentvecsize; /* IOhannes */ | ||
1126 | if (bufsize < myvecsize) bufsize = myvecsize; | ||
1127 | if (bufsize != (oldbufsize = x->x_bufsize)) | ||
1128 | { | ||
1129 | t_sample *buf = x->x_buf; | ||
1130 | t_freebytes(buf, oldbufsize * sizeof(*buf)); | ||
1131 | buf = (t_sample *)t_getbytes(bufsize * sizeof(*buf)); | ||
1132 | memset((char *)buf, 0, bufsize * sizeof(*buf)); | ||
1133 | x->x_bufsize = bufsize; | ||
1134 | x->x_endbuf = buf + bufsize; | ||
1135 | x->x_buf = buf; | ||
1136 | } | ||
1137 | /* IOhannes: { */ | ||
1138 | if (re_parentvecsize * period > bufsize) bug("voutlet_dspepilog"); | ||
1139 | x->x_write = x->x_buf + re_parentvecsize * blockphase; | ||
1140 | if (x->x_write == x->x_endbuf) x->x_write = x->x_buf; | ||
1141 | if (period == 1 && frequency > 1) | ||
1142 | x->x_hop = re_parentvecsize / frequency; | ||
1143 | else x->x_hop = period * re_parentvecsize; | ||
1144 | /* } IOhannes */ | ||
1145 | /* post("phase %d, block %d, parent %d", phase & 63, | ||
1146 | parentvecsize * blockphase, parentvecsize * epilogphase); */ | ||
1147 | if (parentsigs) | ||
1148 | { | ||
1149 | /* set epilog pointer and schedule it */ | ||
1150 | /* IOhannes { */ | ||
1151 | x->x_empty = x->x_buf + re_parentvecsize * epilogphase; | ||
1152 | if (upsample * downsample == 1) | ||
1153 | dsp_add(voutlet_doepilog, 3, x, outsig->s_vec, re_parentvecsize); | ||
1154 | else { | ||
1155 | dsp_add(voutlet_doepilog_resampling, 2, x, re_parentvecsize); | ||
1156 | resampleto_dsp(&x->x_updown, outsig->s_vec, re_parentvecsize, parentvecsize, x->x_updown.method); | ||
1157 | } | ||
1158 | /* } IOhannes */ | ||
1159 | } | ||
1160 | } | ||
1161 | /* if we aren't blocked but we are switched, the epilog code just | ||
1162 | copies zeros to the output. In this case the blocking code actually | ||
1163 | jumps over the epilog if the block is running. */ | ||
1164 | else if (switched) | ||
1165 | { | ||
1166 | if (parentsigs) | ||
1167 | { | ||
1168 | t_signal *outsig = | ||
1169 | parentsigs[outlet_getsignalindex(x->x_parentoutlet)]; | ||
1170 | dsp_add_zero(outsig->s_vec, outsig->s_n); | ||
1171 | } | ||
1172 | } | ||
1173 | } | ||
1174 | |||
1175 | static void *voutlet_newsig(t_symbol *s) | ||
1176 | { | ||
1177 | t_voutlet *x = (t_voutlet *)pd_new(voutlet_class); | ||
1178 | x->x_canvas = canvas_getcurrent(); | ||
1179 | x->x_parentoutlet = canvas_addoutlet(x->x_canvas, | ||
1180 | &x->x_obj.ob_pd, &s_signal); | ||
1181 | inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); | ||
1182 | x->x_endbuf = x->x_buf = (t_sample *)getbytes(0); | ||
1183 | x->x_bufsize = 0; | ||
1184 | |||
1185 | resample_init(&x->x_updown); | ||
1186 | |||
1187 | /* this should be though over: | ||
1188 | * it might prove hard to provide consistency between labeled up- & downsampling methods | ||
1189 | * maybe indeces would be better... | ||
1190 | * | ||
1191 | * up till now we provide several upsampling methods and 1 single downsampling method (no filtering !) | ||
1192 | */ | ||
1193 | if (s == gensym("hold"))x->x_updown.method=1; /* up: sample and hold */ | ||
1194 | else if (s == gensym("lin"))x->x_updown.method=2; /* up: linear interpolation */ | ||
1195 | else if (s == gensym("linear"))x->x_updown.method=2; /* up: linear interpolation */ | ||
1196 | else x->x_updown.method=0; /* up: zero-padding; down: ignore samples inbetween */ | ||
1197 | |||
1198 | return (x); | ||
1199 | } | ||
1200 | |||
1201 | |||
1202 | static void voutlet_setup(void) | ||
1203 | { | ||
1204 | voutlet_class = class_new(gensym("outlet"), (t_newmethod)voutlet_new, | ||
1205 | (t_method)voutlet_free, sizeof(t_voutlet), CLASS_NOINLET, A_DEFSYM, 0); | ||
1206 | class_addcreator((t_newmethod)voutlet_newsig, gensym("outlet~"), A_DEFSYM, 0); | ||
1207 | class_addbang(voutlet_class, voutlet_bang); | ||
1208 | class_addpointer(voutlet_class, voutlet_pointer); | ||
1209 | class_addfloat(voutlet_class, (t_method)voutlet_float); | ||
1210 | class_addsymbol(voutlet_class, voutlet_symbol); | ||
1211 | class_addlist(voutlet_class, voutlet_list); | ||
1212 | class_addanything(voutlet_class, voutlet_anything); | ||
1213 | class_addmethod(voutlet_class, (t_method)voutlet_dsp, gensym("dsp"), 0); | ||
1214 | class_sethelpsymbol(voutlet_class, gensym("pd")); | ||
1215 | } | ||
1216 | |||
1217 | |||
1218 | /* ---------------------------- overall setup ----------------------------- */ | ||
1219 | |||
1220 | void g_io_setup(void) | ||
1221 | { | ||
1222 | vinlet_setup(); | ||
1223 | voutlet_setup(); | ||
1224 | } | ||