Skip to content

Commit

Permalink
add MC to tri~
Browse files Browse the repository at this point in the history
  • Loading branch information
porres committed Jan 16, 2025
1 parent 8b2af74 commit d7b2bac
Showing 1 changed file with 187 additions and 132 deletions.
319 changes: 187 additions & 132 deletions Source/Audio/tri~.c
Original file line number Diff line number Diff line change
@@ -1,176 +1,231 @@
// Porres 2017
// Porres 2017-2025

#include <m_pd.h>
#include "math.h"
#include <magic.h>
#include <math.h>
#include <stdlib.h>
#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);
}

0 comments on commit d7b2bac

Please sign in to comment.