Hi guys, I have a max external that I need to port to pd to put it on raspberry pi. I don't have the time to do it myself. Anybody can help me? I have a little budget for it. I attach the code.vb.fourses~.c
-
[small job offer] porting max external to pd
-
Edit 1: Took a shot porting it in this little textarea. Probably doesn't compile yet...
Edit 2: Ok, this should compile now. I haven't actually tried to instantiate it yet, though. It's possible I set it up with the wrong number of xlets.
Edit 3: Seems to instantiate ok. It appears it doesn't take signal input so the CLASS_MAINSIGNALIN macro is neccessary. Just comment that part out to make it a control signal.Note-- in my port it's called
[vb_fourses~]
for the reason noted below.I have no idea if the algorithm behaves correctly, but it does output sound.
Btw-- AFAICT you should be able to compile this external for the 64-bit version of Purr Data and it should work properly. It doesn't require a special 64-bit codepath in Pd so I commented that part out.
Btw 2-- there should probably be a "best practices" rule that states you can only name your class something that is a legal C function name. Because this class doesn't follow that practice I made a mistake in the port. Further, the user will make a mistake because I had to change the class name. If I had instead made the setup function a different name than the creator I would create an additional problem that would force users to declare the lib before using it. Bad all around, and not worth whatever benefit there is to naming a class "foo.bar" instead of "foo_bar"
/* #include "ext.h" #include "ext_obex.h" #include "z_dsp.h" #include "ext_common.h" */ #include "m_pd.h" #include "math.h" /* a chaotic oscillator network based on descriptions of the 'fourses system' by ciat-lonbarde www.ciat-lonbarde.net 07.april 2013, volker b?hm */ #define NUMFOURSES 4 static void *myObj_class; typedef struct { // this is a horse... basically a ramp generator double val; double inc; double dec; double adder; double incy, incym1; // used for smoothing double decy, decym1; // used for smoothing } t_horse; typedef struct { t_object x_obj; double r_sr; t_horse fourses[NUMFOURSES+2]; // four horses make a fourse... double smoother; t_sample x_f; } t_myObj; // absolute limits static void myObj_hilim(t_myObj *x, t_floatarg input); static void myObj_lolim(t_myObj *x, t_floatarg input); // up and down freqs for all oscillators static void myObj_upfreq(t_myObj *x, t_floatarg freq1, t_floatarg freq2, t_floatarg freq3, t_floatarg freq4); static void myObj_downfreq(t_myObj *x, t_floatarg freq1, t_floatarg freq2, t_floatarg freq3, t_floatarg freq4); static void myObj_smooth(t_myObj *x, t_floatarg input); static void myObj_info(t_myObj *x); // DSP methods static void myObj_dsp(t_myObj *x, t_signal **sp); static t_int *myObj_perform(t_int *w); //void myObj_dsp64(t_myObj *x, t_object *dsp64, short *count, double samplerate, // long maxvectorsize, long flags); //void myObj_perform64(t_myObj *x, t_object *dsp64, double **ins, long numins, // double **outs, long numouts, long sampleframes, long flags, void *userparam); // static void *myObj_new( t_symbol *s, int argc, t_atom *argv); //void myObj_assist(t_myObj *x, void *b, long m, long a, char *s); void vb_fourses_tilde_setup(void) { t_class *c; myObj_class = class_new(gensym("vb_fourses~"), (t_newmethod)myObj_new, 0, sizeof(t_myObj), 0, A_GIMME, NULL); c = myObj_class; class_addmethod(c, (t_method)myObj_dsp, gensym("dsp"), A_CANT, 0); // class_addmethod(c, (t_method)myObj_dsp64, gensym("dsp64"), A_CANT, 0); class_addmethod(c, (t_method)myObj_smooth, gensym("smooth"), A_FLOAT, 0); class_addmethod(c, (t_method)myObj_hilim, gensym("hilim"), A_FLOAT, 0); class_addmethod(c, (t_method)myObj_lolim, gensym("lolim"), A_FLOAT, 0); class_addmethod(c, (t_method)myObj_upfreq, gensym("upfreq"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); class_addmethod(c, (t_method)myObj_downfreq, gensym("downfreq"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); class_addmethod(c, (t_method)myObj_info, gensym("info"), 0); //class_addmethod(c, (t_method)myObj_assist, "assist", A_CANT,0); CLASS_MAINSIGNALIN(myObj_class, t_myObj, x_f); // class_dspinit(c); // class_register(CLASS_BOX, c); post("vb_fourses~ by volker b?hm\n"); // return 0; } static void myObj_smooth(t_myObj *x, t_floatarg input) { // input = CLAMP(input, 0., 1.); if (input < 0.) input = 0; if (input > 1.) input = 1; x->smoother = 0.01 - pow(input,0.2)*0.01; } static void myObj_hilim(t_myObj *x, t_floatarg input) { x->fourses[0].val = input; // store global high limit in fourses[0] } static void myObj_lolim(t_myObj *x, t_floatarg input) { x->fourses[5].val = input; // store global low limit in fourses[5] } static void myObj_upfreq(t_myObj *x, t_floatarg freq1, t_floatarg freq2, t_floatarg freq3, t_floatarg freq4) { x->fourses[1].inc = fabs(freq1)*4*x->r_sr; x->fourses[2].inc = fabs(freq2)*4*x->r_sr; x->fourses[3].inc = fabs(freq3)*4*x->r_sr; x->fourses[4].inc = fabs(freq4)*4*x->r_sr; } static void myObj_downfreq(t_myObj *x, t_floatarg freq1, t_floatarg freq2, t_floatarg freq3, t_floatarg freq4) { x->fourses[1].dec = fabs(freq1)*-4*x->r_sr; x->fourses[2].dec = fabs(freq2)*-4*x->r_sr; x->fourses[3].dec = fabs(freq3)*-4*x->r_sr; x->fourses[4].dec = fabs(freq4)*-4*x->r_sr; } //#pragma mark 64bit dsp-loop ------------------ //void myObj_dsp64(t_myObj *x, t_object *dsp64, short *count, double samplerate, // long maxvectorsize, long flags) { // object_method(dsp64, gensym("dsp_add64"), x, myObj_perform64, 0, NULL); // // if(samplerate<=0) x->r_sr = 1.0/44100.0; // else x->r_sr = 1.0/samplerate; // // //} //static void myObj_perform64(t_myObj *x, t_object *dsp64, double **ins, long numins, // double **outs, long numouts, long sampleframes, long flags, void *userparam){ // // t_double **output = outs; // int vs = sampleframes; // t_horse *fourses = x->fourses; // double val, c, hilim, lolim; // int i, n; // // if (x->x_obj.z_disabled) // return; // // c = x->smoother; // hilim = fourses[0].val; // lolim = fourses[5].val; // // for(i=0; i<vs; i++) // { // for(n=1; n<=NUMFOURSES; n++) { // // smoother // fourses[n].incy = fourses[n].inc*c + fourses[n].incym1*(1-c); // fourses[n].incym1 = fourses[n].incy; // // fourses[n].decy = fourses[n].dec*c + fourses[n].decym1*(1-c); // fourses[n].decym1 = fourses[n].decy; // // val = fourses[n].val; // val += fourses[n].adder; // // if(val <= fourses[n+1].val || val <= lolim ) { // fourses[n].adder = fourses[n].incy; // } // else if( val >= fourses[n-1].val || val >= hilim ) { // fourses[n].adder = fourses[n].decy; // } // // output[n-1][i] = val; // // fourses[n].val = val; // } // } // // return; // //} //#pragma mark 32bit dsp-loop ------------------ static void myObj_dsp(t_myObj *x, t_signal **sp) { dsp_add(myObj_perform, 6, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[0]->s_n); if(sp[0]->s_sr<=0) x->r_sr = 1.0/44100.0; else x->r_sr = 1.0/sp[0]->s_sr; } static t_int *myObj_perform(t_int *w) { t_myObj *x = (t_myObj*)(w[1]); t_float *out1 = (float *)(w[2]); t_float *out2 = (float *)(w[3]); t_float *out3 = (float *)(w[4]); t_float *out4 = (float *)(w[5]); int vs = (int)(w[6]); // Hm... not sure about this member. I don't think we can disable individual // objects in Pd... // if (x->x_obj.z_disabled) // goto out; t_horse *fourses = x->fourses; double val, c, hilim, lolim; int i, n; c = x->smoother; hilim = fourses[0].val; lolim = fourses[5].val; for(i=0; i<vs; i++) { for(n=1; n<=NUMFOURSES; n++) { // smoother fourses[n].incy = fourses[n].inc*c + fourses[n].incym1*(1-c); fourses[n].incym1 = fourses[n].incy; fourses[n].decy = fourses[n].dec*c + fourses[n].decym1*(1-c); fourses[n].decym1 = fourses[n].decy; val = fourses[n].val; val += fourses[n].adder; if(val <= fourses[n+1].val || val <= lolim ) { fourses[n].adder = fourses[n].incy; } else if( val >= fourses[n-1].val || val >= hilim ) { fourses[n].adder = fourses[n].decy; } fourses[n].val = val; } out1[i] = fourses[1].val; out2[i] = fourses[2].val; out3[i] = fourses[3].val; out4[i] = fourses[4].val; } //out: return w+7; } static void myObj_info(t_myObj *x) { int i; // only fourses 1 to 4 are used post("----- fourses.info -------"); for(i=1; i<=NUMFOURSES; i++) { post("fourses[%ld].val = %f", i, x->fourses[i].val); post("fourses[%ld].inc = %f", i, x->fourses[i].inc); post("fourses[%ld].dec = %f", i, x->fourses[i].dec); post("fourses[%ld].adder = %f", i, x->fourses[i].adder); } post("------ end -------"); } void *myObj_new(t_symbol *s, int argc, t_atom *argv) { t_myObj *x = (t_myObj *)pd_new(myObj_class); // dsp_setup((t_pxobject*)x, 0); outlet_new((t_object *)x, &s_signal); outlet_new((t_object *)x, &s_signal); outlet_new((t_object *)x, &s_signal); outlet_new((t_object *)x, &s_signal); x->r_sr = 1.0/sys_getsr(); if(sys_getsr() <= 0) x->r_sr = 1.0/44100.f; int i; for(i=1; i<=NUMFOURSES; i++) { x->fourses[i].val = 0.; x->fourses[i].inc = 0.01; x->fourses[i].dec = -0.01; x->fourses[i].adder = x->fourses[i].inc; } x->fourses[0].val = 1.; // dummy 'horse' only used as high limit for fourses[1] x->fourses[5].val = -1.; // dummy 'horse' only used as low limit for fourses[4] x->smoother = 0.01; return x; } //void myObj_assist(t_myObj *x, void *b, long m, long a, char *s) { // if (m==1) { // switch(a) { // case 0: sprintf (s,"message inlet"); break; // } // } // else { // switch(a) { // case 0: sprintf (s,"(signal) signal out osc1"); break; // case 1: sprintf(s, "(signal) signal out osc2"); break; // case 2: sprintf(s, "(signal) signal out osc3"); break; // case 3: sprintf(s, "(signal) signal out osc4"); break; // } // // } //}
-
Btw-- If you want a binary for the RPI3 I can post one later.