Fix pdbox makefile to actually take part in dependency generation
[kugel-rb.git] / apps / plugins / pdbox / PDa / src / g_io.c
blobdd850a9a89635ba777be2dc7844c5ab80d0665a8
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 /* graphical inlets and outlets, both for control and signals. */
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. */
16 /* hacked to run subpatches with different samplerates
18 * mfg.gfd.uil
19 * IOhannes
21 * edited lines are marked with "IOhannes"
25 #ifdef ROCKBOX
26 #include "plugin.h"
27 #include "../../pdbox.h"
28 #include "m_pd.h"
29 #include "g_canvas.h"
30 #else
31 #include "m_pd.h"
32 #include "g_canvas.h"
33 #include <string.h>
34 #endif
36 void signal_setborrowed(t_signal *sig, t_signal *sig2);
37 void signal_makereusable(t_signal *sig);
39 /* ------------------------- vinlet -------------------------- */
40 t_class *vinlet_class;
42 typedef struct _vinlet
44 t_object x_obj;
45 t_canvas *x_canvas;
46 t_inlet *x_inlet;
47 int x_bufsize;
48 t_float *x_buf; /* signal buffer; zero if not a signal */
49 t_float *x_endbuf;
50 t_float *x_fill;
51 t_float *x_read;
52 int x_hop;
53 /* if not reblocking, the next slot communicates the parent's inlet
54 signal from the prolog to the DSP routine: */
55 t_signal *x_directsignal;
57 t_resample x_updown; /* IOhannes */
58 } t_vinlet;
60 static void *vinlet_new(t_symbol *s)
62 #ifdef ROCKBOX
63 (void) s;
64 #endif
65 t_vinlet *x = (t_vinlet *)pd_new(vinlet_class);
66 x->x_canvas = canvas_getcurrent();
67 x->x_inlet = canvas_addinlet(x->x_canvas, &x->x_obj.ob_pd, 0);
68 x->x_bufsize = 0;
69 x->x_buf = 0;
70 outlet_new(&x->x_obj, 0);
71 return (x);
74 static void vinlet_bang(t_vinlet *x)
76 outlet_bang(x->x_obj.ob_outlet);
79 static void vinlet_pointer(t_vinlet *x, t_gpointer *gp)
81 outlet_pointer(x->x_obj.ob_outlet, gp);
84 static void vinlet_float(t_vinlet *x, t_float f)
86 outlet_float(x->x_obj.ob_outlet, f);
89 static void vinlet_symbol(t_vinlet *x, t_symbol *s)
91 outlet_symbol(x->x_obj.ob_outlet, s);
94 static void vinlet_list(t_vinlet *x, t_symbol *s, int argc, t_atom *argv)
96 outlet_list(x->x_obj.ob_outlet, s, argc, argv);
99 static void vinlet_anything(t_vinlet *x, t_symbol *s, int argc, t_atom *argv)
101 outlet_anything(x->x_obj.ob_outlet, s, argc, argv);
104 static void vinlet_free(t_vinlet *x)
106 canvas_rminlet(x->x_canvas, x->x_inlet);
107 resample_free(&x->x_updown);
110 t_inlet *vinlet_getit(t_pd *x)
112 if (pd_class(x) != vinlet_class) bug("vinlet_getit");
113 return (((t_vinlet *)x)->x_inlet);
116 /* ------------------------- signal inlet -------------------------- */
117 int vinlet_issignal(t_vinlet *x)
119 return (x->x_buf != 0);
122 #ifndef ROCKBOX
123 static int tot;
124 #endif
126 t_int *vinlet_perform(t_int *w)
128 t_vinlet *x = (t_vinlet *)(w[1]);
129 t_float *out = (t_float *)(w[2]);
130 int n = (int)(w[3]);
131 t_float *in = x->x_read;
132 #if 0
133 if (tot < 5) post("-in %x out %x n %d", in, out, n);
134 if (tot < 5) post("-buf %x endbuf %x", x->x_buf, x->x_endbuf);
135 if (tot < 5) post("in[0] %f in[1] %f in[2] %f", in[0], in[1], in[2]);
136 #endif
137 while (n--) *out++ = *in++;
138 if (in == x->x_endbuf) in = x->x_buf;
139 x->x_read = in;
140 return (w+4);
143 static void vinlet_dsp(t_vinlet *x, t_signal **sp)
145 t_signal *outsig;
146 /* no buffer means we're not a signal inlet */
147 if (!x->x_buf)
148 return;
149 outsig = sp[0];
150 if (x->x_directsignal)
152 signal_setborrowed(sp[0], x->x_directsignal);
154 else
156 dsp_add(vinlet_perform, 3, x, outsig->s_vec, outsig->s_n);
157 x->x_read = x->x_buf;
161 /* prolog code: loads buffer from parent patch */
162 t_int *vinlet_doprolog(t_int *w)
164 t_vinlet *x = (t_vinlet *)(w[1]);
165 t_float *in = (t_float *)(w[2]);
166 int n = (int)(w[3]);
167 t_float *out = x->x_fill;
168 if (out == x->x_endbuf)
170 t_float *f1 = x->x_buf, *f2 = x->x_buf + x->x_hop;
171 int nshift = x->x_bufsize - x->x_hop;
172 out -= x->x_hop;
173 while (nshift--) *f1++ = *f2++;
175 #if 0
176 if (tot < 5) post("in %x out %x n %x", in, out, n), tot++;
177 if (tot < 5) post("in[0] %f in[1] %f in[2] %f", in[0], in[1], in[2]);
178 #endif
180 while (n--) *out++ = *in++;
181 x->x_fill = out;
182 return (w+4);
185 int inlet_getsignalindex(t_inlet *x);
187 /* set up prolog DSP code */
188 void vinlet_dspprolog(t_vinlet *x, t_signal **parentsigs,
189 int myvecsize, int phase, int period, int frequency, int downsample, int upsample/* IOhannes */, int reblock,
190 int switched)
192 #ifdef ROCKBOX
193 t_signal *insig;
194 (void) frequency;
195 (void) switched;
196 #else
197 t_signal *insig, *outsig;
198 #endif
199 x->x_updown.downsample = downsample;
200 x->x_updown.upsample = upsample;
202 /* if the "reblock" flag is set, arrange to copy data in from the
203 parent. */
204 if (reblock)
206 int parentvecsize, bufsize, oldbufsize, prologphase;
207 int re_parentvecsize; /* resampled parentvectorsize: IOhannes */
208 /* this should never happen: */
209 if (!x->x_buf) return;
211 /* the prolog code counts from 0 to period-1; the
212 phase is backed up by one so that AFTER the prolog code
213 runs, the "x_fill" phase is in sync with the "x_read" phase. */
214 prologphase = (phase - 1) & (period - 1);
215 if (parentsigs)
217 insig = parentsigs[inlet_getsignalindex(x->x_inlet)];
218 parentvecsize = insig->s_n;
219 re_parentvecsize = parentvecsize * upsample / downsample;
221 else
223 insig = 0;
224 parentvecsize = 1;
225 re_parentvecsize = 1;
228 bufsize = re_parentvecsize;
229 if (bufsize < myvecsize) bufsize = myvecsize;
230 if (bufsize != (oldbufsize = x->x_bufsize))
232 t_float *buf = x->x_buf;
233 t_freebytes(buf, oldbufsize * sizeof(*buf));
234 buf = (t_float *)t_getbytes(bufsize * sizeof(*buf));
235 memset((char *)buf, 0, bufsize * sizeof(*buf));
236 x->x_bufsize = bufsize;
237 x->x_endbuf = buf + bufsize;
238 x->x_buf = buf;
240 if (parentsigs)
242 /* IOhannes { */
243 x->x_hop = period * re_parentvecsize;
245 x->x_fill = x->x_endbuf -
246 (x->x_hop - prologphase * re_parentvecsize);
248 if (upsample * downsample == 1)
249 dsp_add(vinlet_doprolog, 3, x, insig->s_vec, re_parentvecsize);
250 else {
251 resamplefrom_dsp(&x->x_updown, insig->s_vec, parentvecsize, re_parentvecsize, x->x_updown.method);
252 dsp_add(vinlet_doprolog, 3, x, x->x_updown.s_vec, re_parentvecsize);
255 /* } IOhannes */
256 /* if the input signal's reference count is zero, we have
257 to free it here because we didn't in ugen_doit(). */
258 if (!insig->s_refcount)
259 signal_makereusable(insig);
261 else memset((char *)(x->x_buf), 0, bufsize * sizeof(*x->x_buf));
262 x->x_directsignal = 0;
264 else
266 /* no reblocking; in this case our output signal is "borrowed"
267 and merely needs to be pointed to the real one. */
268 x->x_directsignal = parentsigs[inlet_getsignalindex(x->x_inlet)];
272 //static void *vinlet_newsig(void)
273 static void *vinlet_newsig(t_symbol *s)
275 t_vinlet *x = (t_vinlet *)pd_new(vinlet_class);
276 x->x_canvas = canvas_getcurrent();
277 x->x_inlet = canvas_addinlet(x->x_canvas, &x->x_obj.ob_pd, &s_signal);
278 x->x_endbuf = x->x_buf = (t_float *)getbytes(0);
279 x->x_bufsize = 0;
280 x->x_directsignal = 0;
281 outlet_new(&x->x_obj, &s_signal);
283 resample_init(&x->x_updown);
285 /* this should be though over:
286 * it might prove hard to provide consistency between labeled up- & downsampling methods
287 * maybe indeces would be better...
289 * up till now we provide several upsampling methods and 1 single downsampling method (no filtering !)
291 if (s == gensym("hold"))x->x_updown.method=1; /* up: sample and hold */
292 else if (s == gensym("lin"))x->x_updown.method=2; /* up: linear interpolation */
293 else x->x_updown.method=0; /* up: zero-padding */
295 return (x);
298 static void vinlet_setup(void)
300 vinlet_class = class_new(gensym("inlet"), (t_newmethod)vinlet_new,
301 (t_method)vinlet_free, sizeof(t_vinlet), CLASS_NOINLET, A_DEFSYM, 0);
302 class_addcreator((t_newmethod)vinlet_newsig, gensym("inlet~"), A_DEFSYM, 0);
303 class_addbang(vinlet_class, vinlet_bang);
304 class_addpointer(vinlet_class, vinlet_pointer);
305 class_addfloat(vinlet_class, vinlet_float);
306 class_addsymbol(vinlet_class, vinlet_symbol);
307 class_addlist(vinlet_class, vinlet_list);
308 class_addanything(vinlet_class, vinlet_anything);
309 class_addmethod(vinlet_class, (t_method)vinlet_dsp, gensym("dsp"), 0);
310 class_sethelpsymbol(vinlet_class, gensym("pd"));
313 /* ------------------------- voutlet -------------------------- */
315 t_class *voutlet_class;
317 typedef struct _voutlet
319 t_object x_obj;
320 t_canvas *x_canvas;
321 t_outlet *x_parentoutlet;
322 int x_bufsize;
323 t_sample *x_buf; /* signal buffer; zero if not a signal */
324 t_sample *x_endbuf;
325 t_sample *x_empty; /* next to read out of buffer in epilog code */
326 t_sample *x_write; /* next to write in to buffer */
327 int x_hop; /* hopsize */
328 /* vice versa from the inlet, if we don't block, this holds the
329 parent's outlet signal, valid between the prolog and the dsp setup
330 routines. */
331 t_signal *x_directsignal;
332 /* and here's a flag indicating that we aren't blocked but have to
333 do a copy (because we're switched). */
334 char x_justcopyout;
335 t_resample x_updown; /* IOhannes */
336 } t_voutlet;
338 static void *voutlet_new(t_symbol *s)
340 #ifdef ROCKBOX
341 (void) s;
342 #endif
343 t_voutlet *x = (t_voutlet *)pd_new(voutlet_class);
344 x->x_canvas = canvas_getcurrent();
345 x->x_parentoutlet = canvas_addoutlet(x->x_canvas, &x->x_obj.ob_pd, 0);
346 inlet_new(&x->x_obj, &x->x_obj.ob_pd, 0, 0);
347 x->x_bufsize = 0;
348 x->x_buf = 0;
349 return (x);
352 static void voutlet_bang(t_voutlet *x)
354 outlet_bang(x->x_parentoutlet);
357 static void voutlet_pointer(t_voutlet *x, t_gpointer *gp)
359 outlet_pointer(x->x_parentoutlet, gp);
362 static void voutlet_float(t_voutlet *x, t_float f)
364 outlet_float(x->x_parentoutlet, f);
367 static void voutlet_symbol(t_voutlet *x, t_symbol *s)
369 outlet_symbol(x->x_parentoutlet, s);
372 static void voutlet_list(t_voutlet *x, t_symbol *s, int argc, t_atom *argv)
374 outlet_list(x->x_parentoutlet, s, argc, argv);
377 static void voutlet_anything(t_voutlet *x, t_symbol *s, int argc, t_atom *argv)
379 outlet_anything(x->x_parentoutlet, s, argc, argv);
382 static void voutlet_free(t_voutlet *x)
384 canvas_rmoutlet(x->x_canvas, x->x_parentoutlet);
385 resample_free(&x->x_updown);
388 t_outlet *voutlet_getit(t_pd *x)
390 if (pd_class(x) != voutlet_class) bug("voutlet_getit");
391 return (((t_voutlet *)x)->x_parentoutlet);
394 /* ------------------------- signal outlet -------------------------- */
396 int voutlet_issignal(t_voutlet *x)
398 return (x->x_buf != 0);
401 /* LATER optimize for non-overlapped case where the "+=" isn't needed */
402 t_int *voutlet_perform(t_int *w)
404 t_voutlet *x = (t_voutlet *)(w[1]);
405 t_sample *in = (t_sample *)(w[2]);
406 int n = (int)(w[3]);
407 t_sample *out = x->x_write, *outwas = out;
408 #if 0
409 if (tot < 5) post("-in %x out %x n %d", in, out, n);
410 if (tot < 5) post("-buf %x endbuf %x", x->x_buf, x->x_endbuf);
411 #endif
412 while (n--)
414 *out++ += *in++;
415 if (out == x->x_endbuf) out = x->x_buf;
417 outwas += x->x_hop;
418 if (outwas >= x->x_endbuf) outwas = x->x_buf;
419 x->x_write = outwas;
420 return (w+4);
423 /* epilog code for blocking: write buffer to parent patch */
424 static t_int *voutlet_doepilog(t_int *w)
426 t_voutlet *x = (t_voutlet *)(w[1]);
427 t_sample *out = (t_sample *)(w[2]); /* IOhannes */
429 int n = (int)(w[3]);
430 t_sample *in = x->x_empty;
431 if (x->x_updown.downsample != x->x_updown.upsample) out = x->x_updown.s_vec; /* IOhannes */
433 #if 0
434 if (tot < 5) post("outlet in %x out %x n %x", in, out, n), tot++;
435 #endif
436 for (; n--; in++) *out++ = *in, *in = 0;
437 if (in == x->x_endbuf) in = x->x_buf;
438 x->x_empty = in;
439 return (w+4);
442 /* IOhannes { */
443 static t_int *voutlet_doepilog_resampling(t_int *w)
445 t_voutlet *x = (t_voutlet *)(w[1]);
446 // t_float *dummy = (t_float *)(w[2]);
447 int n = (int)(w[2]);
448 t_sample *in = x->x_empty;
449 t_sample *out = x->x_updown.s_vec; /* IOhannes */
451 #if 0
452 if (tot < 5) post("outlet in %x out %x n %x", in, out, n), tot++;
453 #endif
454 for (; n--; in++) *out++ = *in, *in = 0;
455 if (in == x->x_endbuf) in = x->x_buf;
456 x->x_empty = in;
457 return (w+3);
459 /* } IOhannes */
460 int outlet_getsignalindex(t_outlet *x);
462 /* prolog for outlets -- store pointer to the outlet on the
463 parent, which, if "reblock" is false, will want to refer
464 back to whatever we see on our input during the "dsp" method
465 called later. */
466 void voutlet_dspprolog(t_voutlet *x, t_signal **parentsigs,
467 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
468 int switched)
470 #ifdef ROCKBOX
471 (void) myvecsize;
472 (void) phase;
473 (void) period;
474 (void) frequency;
475 #endif
476 x->x_updown.downsample=downsample; x->x_updown.upsample=upsample; /* IOhannes */
477 x->x_justcopyout = (switched && !reblock);
478 if (reblock)
480 x->x_directsignal = 0;
482 else
484 if (!parentsigs) bug("voutlet_dspprolog");
485 x->x_directsignal =
486 parentsigs[outlet_getsignalindex(x->x_parentoutlet)];
490 static void voutlet_dsp(t_voutlet *x, t_signal **sp)
492 t_signal *insig;
493 if (!x->x_buf) return;
494 insig = sp[0];
495 if (x->x_justcopyout)
496 dsp_add_copy(insig->s_vec, x->x_directsignal->s_vec, insig->s_n);
497 else if (x->x_directsignal)
499 /* if we're just going to make the signal available on the
500 parent patch, hand it off to the parent signal. */
501 /* this is done elsewhere--> sp[0]->s_refcount++; */
502 signal_setborrowed(x->x_directsignal, sp[0]);
504 else
505 dsp_add(voutlet_perform, 3, x, insig->s_vec, insig->s_n);
508 /* set up epilog DSP code. If we're reblocking, this is the
509 time to copy the samples out to the containing object's outlets.
510 If we aren't reblocking, there's nothing to do here. */
511 void voutlet_dspepilog(t_voutlet *x, t_signal **parentsigs,
512 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
513 int switched)
515 if (!x->x_buf) return; /* this shouldn't be necesssary... */
516 x->x_updown.downsample=downsample; x->x_updown.upsample=upsample; /* IOhannes */
517 if (reblock)
519 #ifdef ROCKBOX
520 t_signal *outsig;
521 #else
522 t_signal *insig, *outsig;
523 #endif
524 int parentvecsize, bufsize, oldbufsize;
525 int re_parentvecsize; /* IOhannes */
526 int bigperiod, epilogphase, blockphase;
527 if (parentsigs)
529 outsig = parentsigs[outlet_getsignalindex(x->x_parentoutlet)];
530 parentvecsize = outsig->s_n;
531 re_parentvecsize = parentvecsize * upsample / downsample;
533 else
535 outsig = 0;
536 parentvecsize = 1;
537 re_parentvecsize = 1;
539 // bigperiod = (downsample * myvecsize)/(upsample * parentvecsize); /* IOhannes */
540 bigperiod = myvecsize/re_parentvecsize; /* IOhannes */
541 if (!bigperiod) bigperiod = 1;
542 epilogphase = phase & (bigperiod - 1);
543 blockphase = (phase + period - 1) & (bigperiod - 1) & (- period);
544 // bufsize = parentvecsize * upsample; /* IOhannes */
545 bufsize = re_parentvecsize; /* IOhannes */
546 if (bufsize < myvecsize) bufsize = myvecsize;
547 if (bufsize != (oldbufsize = x->x_bufsize))
549 t_sample *buf = x->x_buf;
550 t_freebytes(buf, oldbufsize * sizeof(*buf));
551 buf = (t_sample *)t_getbytes(bufsize * sizeof(*buf));
552 memset((char *)buf, 0, bufsize * sizeof(*buf));
553 x->x_bufsize = bufsize;
554 x->x_endbuf = buf + bufsize;
555 x->x_buf = buf;
557 /* IOhannes: { */
558 if (re_parentvecsize * period > bufsize) bug("voutlet_dspepilog");
559 x->x_write = x->x_buf + re_parentvecsize * blockphase;
560 if (x->x_write == x->x_endbuf) x->x_write = x->x_buf;
561 if (period == 1 && frequency > 1)
562 x->x_hop = re_parentvecsize / frequency;
563 else x->x_hop = period * re_parentvecsize;
564 /* } IOhannes */
565 /* post("phase %d, block %d, parent %d", phase & 63,
566 parentvecsize * blockphase, parentvecsize * epilogphase); */
567 if (parentsigs)
569 /* set epilog pointer and schedule it */
570 /* IOhannes { */
571 x->x_empty = x->x_buf + re_parentvecsize * epilogphase;
572 if (upsample * downsample == 1)
573 dsp_add(voutlet_doepilog, 3, x, outsig->s_vec, re_parentvecsize);
574 else {
575 dsp_add(voutlet_doepilog_resampling, 2, x, re_parentvecsize);
576 resampleto_dsp(&x->x_updown, outsig->s_vec, re_parentvecsize, parentvecsize, x->x_updown.method);
578 /* } IOhannes */
581 /* if we aren't blocked but we are switched, the epilog code just
582 copies zeros to the output. In this case the blocking code actually
583 jumps over the epilog if the block is running. */
584 else if (switched)
586 if (parentsigs)
588 t_signal *outsig =
589 parentsigs[outlet_getsignalindex(x->x_parentoutlet)];
590 dsp_add_zero(outsig->s_vec, outsig->s_n);
595 static void *voutlet_newsig(t_symbol *s)
597 t_voutlet *x = (t_voutlet *)pd_new(voutlet_class);
598 x->x_canvas = canvas_getcurrent();
599 x->x_parentoutlet = canvas_addoutlet(x->x_canvas,
600 &x->x_obj.ob_pd, &s_signal);
601 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
602 x->x_endbuf = x->x_buf = (t_sample *)getbytes(0);
603 x->x_bufsize = 0;
605 resample_init(&x->x_updown);
607 /* this should be though over:
608 * it might prove hard to provide consistency between labeled up- & downsampling methods
609 * maybe indeces would be better...
611 * up till now we provide several upsampling methods and 1 single downsampling method (no filtering !)
613 if (s == gensym("hold"))x->x_updown.method=1; /* up: sample and hold */
614 else if (s == gensym("lin"))x->x_updown.method=2; /* up: linear interpolation */
615 else if (s == gensym("linear"))x->x_updown.method=2; /* up: linear interpolation */
616 else x->x_updown.method=0; /* up: zero-padding; down: ignore samples inbetween */
618 return (x);
622 static void voutlet_setup(void)
624 voutlet_class = class_new(gensym("outlet"), (t_newmethod)voutlet_new,
625 (t_method)voutlet_free, sizeof(t_voutlet), CLASS_NOINLET, A_DEFSYM, 0);
626 class_addcreator((t_newmethod)voutlet_newsig, gensym("outlet~"), A_DEFSYM, 0);
627 class_addbang(voutlet_class, voutlet_bang);
628 class_addpointer(voutlet_class, voutlet_pointer);
629 class_addfloat(voutlet_class, (t_method)voutlet_float);
630 class_addsymbol(voutlet_class, voutlet_symbol);
631 class_addlist(voutlet_class, voutlet_list);
632 class_addanything(voutlet_class, voutlet_anything);
633 class_addmethod(voutlet_class, (t_method)voutlet_dsp, gensym("dsp"), 0);
634 class_sethelpsymbol(voutlet_class, gensym("pd"));
638 /* ---------------------------- overall setup ----------------------------- */
640 void g_io_setup(void)
642 vinlet_setup();
643 voutlet_setup();