From d7b2bace5fecb16ca52c30d8b54d89c7b5389acc Mon Sep 17 00:00:00 2001 From: porres Date: Wed, 15 Jan 2025 23:45:07 -0300 Subject: [PATCH] add MC to tri~ --- Source/Audio/tri~.c | 319 ++++++++++++++++++++++++++------------------ 1 file changed, 187 insertions(+), 132 deletions(-) diff --git a/Source/Audio/tri~.c b/Source/Audio/tri~.c index 4aab6fae6..370e17c66 100644 --- a/Source/Audio/tri~.c +++ b/Source/Audio/tri~.c @@ -1,176 +1,231 @@ -// Porres 2017 +// Porres 2017-2025 #include -#include "math.h" -#include +#include +#include +#include "magic.h" -#define TWOPI (3.14159265358979323846 * 2) +#define MAXLEN 1024 + +typedef struct _tri{ + t_object x_obj; + double *x_phase; + int x_nchans; + t_int x_n; + t_int x_sig1; + t_int x_sig2; + t_int x_ch2; + t_int x_ch3; + t_int x_midi; + t_int x_soft; + t_int *x_dir; + float *x_freq_list; + t_int x_list_size; + t_symbol *x_ignore; + t_inlet *x_inlet_phase; + t_inlet *x_inlet_sync; + t_outlet *x_outlet; + double x_sr_rec; +// MAGIC: + t_glist *x_glist; // object list + t_float *x_signalscalar; // right inlet's float field + t_float x_phase_sync_float; // float from magic +}t_tri; static t_class *tri_class; -typedef struct _tri -{ - t_object x_obj; - double x_phase; - double x_last_phase_offset; - t_float x_freq; - t_inlet *x_inlet_phase; - t_inlet *x_inlet_sync; - t_outlet *x_outlet; - t_float x_sr; -// MAGIC: - t_glist *x_glist; // object list - t_float *x_signalscalar; // right inlet's float field - int x_hasfeeders; // right inlet connection flag - t_float x_phase_sync_float; // float from magic -} t_tri; +double tri_wrap_phase(double phase){ + while(phase >= 1) + phase -= 1.; + while(phase < 0) + phase += 1.; + return(phase); +} static t_int *tri_perform(t_int *w){ t_tri *x = (t_tri *)(w[1]); - int nblock = (t_int)(w[2]); - t_float *in1 = (t_float *)(w[3]); // freq - t_float *in3 = (t_float *)(w[5]); // phase - t_float *out = (t_float *)(w[6]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *in3 = (t_float *)(w[4]); + t_float *out = (t_float *)(w[5]); + t_int *dir = x->x_dir; + double *phase = x->x_phase; // Magic Start - t_float *scalar = x->x_signalscalar; - if (!else_magic_isnan(*x->x_signalscalar)){ - t_float input_phase = fmod(*scalar, 1); - if (input_phase < 0) - input_phase += 1; - x->x_phase = input_phase; - else_magic_setnan(x->x_signalscalar); + if(!x->x_sig2){ + t_float *scalar = x->x_signalscalar; + if(!else_magic_isnan(*x->x_signalscalar)){ + t_float input_phase = fmod(*scalar, 1); + if(input_phase < 0) + input_phase += 1; + for(int j = 0; j < x->x_nchans; j++) + x->x_phase[j] = input_phase; + else_magic_setnan(x->x_signalscalar); } + } // Magic End - double phase = x->x_phase; - double last_phase_offset = x->x_last_phase_offset; - double sr = x->x_sr; - double output; - while (nblock--){ - double hz = *in1++; - double phase_offset = *in3++; - double phase_step = hz / sr; // phase_step - phase_step = phase_step > 0.5 ? 0.5 : phase_step < -0.5 ? -0.5 : phase_step; // clipped to nyq - double phase_dev = phase_offset - last_phase_offset; - if (phase_dev >= 1 || phase_dev <= -1) - phase_dev = fmod(phase_dev, 1); // fmod(phase_dev) - phase = phase + phase_dev; - if (phase <= 0) - phase = phase + 1.; // wrap deviated phase - if (phase >= 1) - phase = phase - 1.; // wrap deviated phase - output = phase * 4; - if (output >= 1 && output < 3) - output = 1 - (output - 1); - else if (output >= 3 && output) - output = (output - 4); - *out++ = output; - phase = phase + phase_step; // next phase - last_phase_offset = phase_offset; // last phase offset + for(int j = 0; j < x->x_nchans; j++){ + for(int i = 0, n = x->x_n; i < n; i++){ + double hz = x->x_sig1 ? in1[j*n + i] : x->x_freq_list[j]; + if(x->x_midi){ + if(hz > 127) + hz = 127; + hz = hz <= 0 ? 0 : pow(2, (hz - 69)/12) * 440; + } + double step = hz * x->x_sr_rec; // phase step + step = step > 0.5 ? 0.5 : step < -0.5 ? -0.5 : step; + if(x->x_sig2){ + if(x->x_soft){ + if(dir[j] == 0) + dir[j] = 1; + step *= (dir[j]); + } + t_float trig = x->x_ch2 == 1 ? in2[i] : in2[j*n + i]; + if(trig > 0 && trig <= 1){ + if(x->x_soft) + dir[j] = dir[j] == 1 ? -1 : 1; + else + phase[j] = trig; + } + } + double phase_offset = x->x_ch3 == 1 ? in3[i] : in3[j*n + i]; + t_float wrap = tri_wrap_phase(phase[j] + phase_offset); + out[j*n + i] = 2 * fabs(2*(wrap+0.25 - floor(wrap+0.75))) - 1; + phase[j] = tri_wrap_phase(phase[j] + step); + } } x->x_phase = phase; - x->x_last_phase_offset = last_phase_offset; - return (w + 7); + x->x_dir = dir; + return(w+6); } -static t_int *tri_perform_sig(t_int *w) -{ - t_tri *x = (t_tri *)(w[1]); - int nblock = (t_int)(w[2]); - t_float *in1 = (t_float *)(w[3]); // freq - t_float *in2 = (t_float *)(w[4]); // sync - t_float *in3 = (t_float *)(w[5]); // phase - t_float *out = (t_float *)(w[6]); - double phase = x->x_phase; - double last_phase_offset = x->x_last_phase_offset; - double sr = x->x_sr; - double output; - while (nblock--){ - double hz = *in1++; - t_float trig = *in2++; - double phase_offset = *in3++; - double phase_step = hz / sr; // phase_step - phase_step = phase_step > 0.5 ? 0.5 : phase_step < -0.5 ? -0.5 : phase_step; // clipped to nyq - double phase_dev = phase_offset - last_phase_offset; - if (phase_dev >= 1 || phase_dev <= -1) - phase_dev = fmod(phase_dev, 1); // fmod(phase_dev) - if (trig > 0 && trig <= 1) - phase = trig; - else{ - phase = phase + phase_dev; - if (phase <= 0) - phase = phase + 1.; // wrap deviated phase - if (phase >= 1) - phase = phase - 1.; // wrap deviated phase - } - output = phase * 4; - if (output >= 1 && output < 3) - output = 1 - (output - 1); - else if (output >= 3 && output) - output = (output - 4); - *out++ = output; - phase = phase + phase_step; // next phase - last_phase_offset = phase_offset; // last phase offset +static void tri_dsp(t_tri *x, t_signal **sp){ + x->x_n = sp[0]->s_n, x->x_sr_rec = 1.0 / (double)sp[0]->s_sr; + x->x_ch2 = sp[1]->s_nchans, x->x_ch3 = sp[2]->s_nchans; + x->x_sig1 = else_magic_inlet_connection((t_object *)x, x->x_glist, 0, &s_signal); + x->x_sig2 = else_magic_inlet_connection((t_object *)x, x->x_glist, 1, &s_signal); + int chs = x->x_sig1 ? sp[0]->s_nchans : x->x_list_size; + if(x->x_nchans != chs){ + x->x_phase = (double *)resizebytes(x->x_phase, + x->x_nchans * sizeof(double), chs * sizeof(double)); + x->x_dir = (t_int *)resizebytes(x->x_dir, + x->x_nchans * sizeof(t_int), chs * sizeof(t_int)); + x->x_nchans = chs; } - x->x_phase = phase; - x->x_last_phase_offset = last_phase_offset; - return (w + 7); + signal_setmultiout(&sp[3], x->x_nchans); + if((x->x_ch2 > 1 && x->x_ch2 != x->x_nchans) + || (x->x_ch3 > 1 && x->x_ch3 != x->x_nchans)){ + dsp_add_zero(sp[3]->s_vec, x->x_nchans*x->x_n); + pd_error(x, "[tri~]: channel sizes mismatch"); + return; + } + dsp_add(tri_perform, 5, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); } -static void tri_dsp(t_tri *x, t_signal **sp){ - x->x_hasfeeders = else_magic_inlet_connection((t_object *)x, x->x_glist, 1, &s_signal); // magic feeder flag - x->x_sr = sp[0]->s_sr; - if (x->x_hasfeeders){ - dsp_add(tri_perform_sig, 6, x, sp[0]->s_n, - sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); - } - else{ - dsp_add(tri_perform, 6, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); +static void tri_midi(t_tri *x, t_floatarg f){ + x->x_midi = (int)(f != 0); +} + +static void tri_set(t_tri *x, t_symbol *s, int ac, t_atom *av){ + x->x_ignore = s; + if(ac != 2) + return; + int i = atom_getint(av); + float f = atom_getint(av+1); + if(i >= x->x_list_size) + i = x->x_list_size; + if(i <= 0) + i = 1; + i--; + x->x_freq_list[i] = f; +} + +static void tri_list(t_tri *x, t_symbol *s, int ac, t_atom * av){ + x->x_ignore = s; + if(ac == 0) + return; + if(x->x_list_size != ac){ + x->x_list_size = ac; + canvas_update_dsp(); } + for(int i = 0; i < ac; i++) + x->x_freq_list[i] = atom_getfloat(av+i); +} + +static void tri_soft(t_tri *x, t_floatarg f){ + x->x_soft = (int)(f != 0); } static void *tri_free(t_tri *x){ inlet_free(x->x_inlet_sync); inlet_free(x->x_inlet_phase); outlet_free(x->x_outlet); - return (void *)x; + freebytes(x->x_phase, x->x_nchans * sizeof(*x->x_phase)); + freebytes(x->x_dir, x->x_nchans * sizeof(*x->x_dir)); + free(x->x_freq_list); + return(void *)x; } static void *tri_new(t_symbol *s, int ac, t_atom *av){ - s = NULL; t_tri *x = (t_tri *)pd_new(tri_class); - t_float f1 = 0, f2 = 0; - if (ac && av->a_type == A_FLOAT){ - f1 = av->a_w.w_float; - ac--; av++; - if (ac && av->a_type == A_FLOAT){ - f2 = av->a_w.w_float; - ac--; av++; + x->x_ignore = s; + x->x_midi = x->x_soft = 0; + x->x_dir = (t_int *)getbytes(sizeof(*x->x_dir)); + x->x_phase = (double *)getbytes(sizeof(*x->x_phase)); + x->x_freq_list = (float*)malloc(MAXLEN * sizeof(float)); + x->x_freq_list[0] = x->x_phase[0] = 0; + x->x_list_size = 1; + while(ac && av->a_type == A_SYMBOL){ + if(atom_getsymbol(av) == gensym("-midi")){ + x->x_midi = 1; + ac--, av++; + } + else if(atom_getsymbol(av) == gensym("-soft")){ + x->x_soft = 1; + ac--, av++; + } + else if(atom_getsymbol(av) == gensym("-mc")){ + ac--, av++; + if(!ac || av->a_type != A_FLOAT) + goto errstate; + int n = 0; + while(ac && av->a_type == A_FLOAT){ + x->x_freq_list[n] = atom_getfloat(av); + ac--, av++, n++; } + x->x_list_size = n; + } + else + goto errstate; + } + if(ac && av->a_type == A_FLOAT){ + x->x_freq_list[0] = av->a_w.w_float; + ac--, av++; + if(ac && av->a_type == A_FLOAT){ + x->x_phase[0] = av->a_w.w_float; + ac--, av++; + } } - t_float init_freq = f1; - t_float init_phase = f2; - init_phase = init_phase < 0 ? 0 : init_phase >= 1 ? 0 : init_phase; // clipping phase input - if (init_phase == 0 && init_freq > 0) - x->x_phase = 1.; - else - x->x_phase = init_phase; - x->x_last_phase_offset = 0; - x->x_freq = init_freq; x->x_inlet_sync = inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal); pd_float((t_pd *)x->x_inlet_sync, 0); x->x_inlet_phase = inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal); - pd_float((t_pd *)x->x_inlet_phase, init_phase); + pd_float((t_pd *)x->x_inlet_phase, x->x_phase[0]); x->x_outlet = outlet_new(&x->x_obj, &s_signal); // Magic x->x_glist = canvas_getcurrent(); x->x_signalscalar = obj_findsignalscalar((t_object *)x, 1); - return (x); + return(x); +errstate: + post("[tri~]: improper args"); + return(NULL); } void tri_tilde_setup(void){ - tri_class = class_new(gensym("tri~"), - (t_newmethod)tri_new, (t_method)tri_free, - sizeof(t_tri), CLASS_DEFAULT, A_GIMME, 0); - CLASS_MAINSIGNALIN(tri_class, t_tri, x_freq); + tri_class = class_new(gensym("tri~"), (t_newmethod)tri_new, (t_method)tri_free, + sizeof(t_tri), CLASS_MULTICHANNEL, A_GIMME, 0); + class_addmethod(tri_class, nullfn, gensym("signal"), 0); class_addmethod(tri_class, (t_method)tri_dsp, gensym("dsp"), A_CANT, 0); + class_addlist(tri_class, tri_list); + class_addmethod(tri_class, (t_method)tri_soft, gensym("soft"), A_DEFFLOAT, 0); + class_addmethod(tri_class, (t_method)tri_midi, gensym("midi"), A_DEFFLOAT, 0); + class_addmethod(tri_class, (t_method)tri_set, gensym("set"), A_GIMME, 0); }