/* Copyright (c) 2003 krzYszcz and others. * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ /* LATER: 'click' method */ #include "m_pd.h" #include "shared.h" #include "unstable/fragile.h" #include "sickle/sic.h" #include "sickle/arsic.h" #define POKE_MAXCHANNELS 4 /* LATER implement arsic resizing feature */ typedef struct _poke { t_arsic x_arsic; int x_maxchannels; int x_effchannel; /* effective channel (clipped reqchannel) */ int x_reqchannel; /* requested channel */ t_sample *x_indexptr; t_clock *x_clock; double x_clocklasttick; int x_clockset; } t_poke; static t_class *poke_class; static void poke_tick(t_poke *x) { arsic_redraw((t_arsic *)x); /* LATER redraw only dirty channel(s!) */ x->x_clockset = 0; x->x_clocklasttick = clock_getlogicaltime(); } static void poke_set(t_poke *x, t_symbol *s) { arsic_setarray((t_arsic *)x, s, 1); } static void poke_bang(t_poke *x) { arsic_redraw((t_arsic *)x); } /* CHECKED: index 0-based, negative values block input, overflowed are clipped. LATER revisit: incompatibly, the code below is nop for any out-of-range index (see also peek.c) */ /* CHECKED: value never clipped, 'clip' not understood */ /* CHECKED: no float-to-signal conversion. 'Float' message is ignored when dsp is on -- whether a signal is connected to the left inlet, or not (if not, current index is set to zero). Incompatible (revisit LATER) */ static void poke_float(t_poke *x, t_float f) { t_arsic *sic = (t_arsic *)x; t_word *vp; arsic_validate(sic, 0); /* LATER rethink (efficiency, and complaining) */ if (vp = sic->s_vectors[x->x_effchannel]) { int ndx = (int)*x->x_indexptr; if (ndx >= 0 && ndx < sic->s_vecsize) { double timesince; vp[ndx].w_float = f; timesince = clock_gettimesince(x->x_clocklasttick); if (timesince > 1000) poke_tick(x); else if (!x->x_clockset) { clock_delay(x->x_clock, 1000 - timesince); x->x_clockset = 1; } } } } static void poke_ft2(t_poke *x, t_floatarg f) { if ((x->x_reqchannel = (f > 1 ? (int)f - 1 : 0)) > x->x_maxchannels) x->x_effchannel = x->x_maxchannels - 1; else x->x_effchannel = x->x_reqchannel; } static t_int *poke_perform(t_int *w) { t_arsic *sic = (t_arsic *)(w[1]); int nblock = (int)(w[2]); t_float *in1 = (t_float *)(w[3]); t_float *in2 = (t_float *)(w[4]); t_poke *x = (t_poke *)sic; t_word *vp = sic->s_vectors[x->x_effchannel]; if (vp && sic->s_playable) { int vecsize = sic->s_vecsize; while (nblock--) { t_float f = *in1++; int ndx = (int)*in2++; if (ndx >= 0 && ndx < vecsize) vp[ndx].w_float = f; } } return (w + sic->s_nperfargs + 1); } static void poke_dsp(t_poke *x, t_signal **sp) { arsic_dsp((t_arsic *)x, sp, poke_perform, 0); } static void poke_free(t_poke *x) { if (x->x_clock) clock_free(x->x_clock); arsic_free((t_arsic *)x); } static void *poke_new(t_symbol *s, t_floatarg f) { int ch = (f > 0 ? (int)f : 0); t_poke *x = (t_poke *)arsic_new(poke_class, s, (ch ? POKE_MAXCHANNELS : 0), 2, 0); if (x) { t_inlet *in2; if (ch > POKE_MAXCHANNELS) ch = POKE_MAXCHANNELS; x->x_maxchannels = (ch ? POKE_MAXCHANNELS : 1); x->x_effchannel = x->x_reqchannel = (ch ? ch - 1 : 0); /* CHECKED: no float-to-signal conversion. Floats in 2nd inlet are ignored when dsp is on, but only if a signal is connected to this inlet. Incompatible (revisit LATER). */ in2 = inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal); x->x_indexptr = fragile_inlet_signalscalar(in2); inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft2")); x->x_clock = clock_new(x, (t_method)poke_tick); x->x_clocklasttick = clock_getlogicaltime(); x->x_clockset = 0; } return (x); } void poke_tilde_setup(void) { poke_class = class_new(gensym("poke~"), (t_newmethod)poke_new, (t_method)poke_free, sizeof(t_poke), 0, A_DEFSYM, A_DEFFLOAT, 0); arsic_setup(poke_class, poke_dsp, poke_float); class_addbang(poke_class, poke_bang); /* LATER rethink */ class_addfloat(poke_class, poke_float); class_addmethod(poke_class, (t_method)poke_set, gensym("set"), A_SYMBOL, 0); class_addmethod(poke_class, (t_method)poke_ft2, gensym("ft2"), A_FLOAT, 0); logpost(NULL, 4, "this is cyclone/poke~ %s, %dth %s build", CYCLONE_VERSION, CYCLONE_BUILD, CYCLONE_RELEASE); }