aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans-Christoph Steiner <eighthave@users.sourceforge.net>2006-02-09 16:18:39 +0000
committerHans-Christoph Steiner <eighthave@users.sourceforge.net>2006-02-09 16:18:39 +0000
commitb418fb91e7bb45d7b5f1eb8b19703441ae94eb13 (patch)
tree3f4a32d0b99d4ea0ac602bec59f0d2accba46719
got everything building and working, including building single-object/single-file objects with a shared dylib. Now got to get it integrated into the build systemsvn2git-root
svn path=/trunk/externals/fftease/; revision=4574
-rw-r--r--README5
-rw-r--r--bthresher~.c625
-rw-r--r--burrow~.c545
-rw-r--r--cavoc27~.c675
-rw-r--r--cavoc~.c529
-rw-r--r--centerring~.c599
-rw-r--r--codepend~.c607
-rw-r--r--crossx~.c449
-rw-r--r--dentist~.c693
-rw-r--r--disarrain~.c810
-rw-r--r--disarray~.c526
-rw-r--r--drown~.c424
-rw-r--r--ether~.c514
-rw-r--r--help/burrow~-help.pd90
-rw-r--r--help/cross~-help.pd88
-rw-r--r--help/dentist~-help.pd65
-rw-r--r--help/disarray~-help.pd67
-rw-r--r--help/drown~-help.pd61
-rw-r--r--help/ether~-help.pd84
-rw-r--r--help/morphine~-help.pd77
-rw-r--r--help/residency~-help.pd33
-rw-r--r--help/scrape~-help.pd72
-rw-r--r--help/shapee~-help.pd62
-rw-r--r--help/swinger~-help.pd62
-rw-r--r--help/taint~-help.pd83
-rw-r--r--help/thresher~-help.pd46
-rw-r--r--help/vacancy~-help.pd97
-rw-r--r--help/xsyn~-help.pd61
-rw-r--r--leaker~.c467
-rw-r--r--lib/MSPd.h36
-rw-r--r--lib/PenroseOscil.c40
-rw-r--r--lib/PenroseOscil.h8
-rw-r--r--lib/PenroseRand.c13
-rw-r--r--lib/PenroseRand.h3
-rw-r--r--lib/bloscbank.c1
-rw-r--r--lib/convert.c1
-rw-r--r--lib/fft.c1
-rw-r--r--lib/fft4.c1
-rw-r--r--lib/fftease.h50
-rw-r--r--lib/fftease_setup.c9
-rw-r--r--lib/fold.c1
-rw-r--r--lib/leanconvert.c1
-rw-r--r--lib/leanunconvert.c1
-rw-r--r--lib/limit_fftsize.c17
-rw-r--r--lib/makewindows.c1
-rw-r--r--lib/overlapadd.c1
-rw-r--r--lib/power_of_two.c17
-rw-r--r--lib/qsortE.c1
-rw-r--r--lib/unconvert.c34
-rw-r--r--mindwarp~.c643
-rw-r--r--morphine~.c588
-rw-r--r--multyq~.c729
-rw-r--r--presidency~.c760
-rw-r--r--pvcompand~.c510
-rw-r--r--pvgrain~.c536
-rw-r--r--pvharm~.c581
-rw-r--r--pvoc~.c564
-rw-r--r--pvtuner~.c1232
-rw-r--r--pvwarp~.c1
-rw-r--r--reanimator~.c698
-rw-r--r--resent~.c766
-rw-r--r--residency_buffer~.c565
-rw-r--r--residency~.c592
-rw-r--r--scrape~.c494
-rw-r--r--shapee~.c506
-rw-r--r--swinger~.c408
-rw-r--r--taint~.c596
-rw-r--r--thresher~.c444
-rw-r--r--vacancy~.c582
-rw-r--r--xsyn~.c381
70 files changed, 20929 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..20aeafc
--- /dev/null
+++ b/README
@@ -0,0 +1,5 @@
+This is source code for FFTease 2.5. It is up to you to link it into
+your favorite compiler system. You are welcome to study, modify or do
+anything else with it.
+
+FFTease is copyright 2000-2005 Eric Lyon and Christopher Penrose. \ No newline at end of file
diff --git a/bthresher~.c b/bthresher~.c
new file mode 100644
index 0000000..050ca2a
--- /dev/null
+++ b/bthresher~.c
@@ -0,0 +1,625 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *bthresher_class;
+#endif
+
+#if PD
+static t_class *bthresher_class;
+#endif
+
+#define OBJECT_NAME "bthresher~"
+
+typedef struct _bthresher
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int in_count;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ float *buffer;
+ float *channel;
+ float *output;
+ /* bthresher vars */
+ float *move_threshold;
+ float *composite_frame ;
+ int *frames_left;
+ int max_hold_frames;
+ float max_hold_time;
+ int first_frame;
+ float *damping_factor ;
+ float thresh_scalar;
+ float damp_scalar;
+ short thresh_connected;
+ short damping_connected;
+ void *list_outlet;
+ void *misc_outlet;
+ t_atom *list_data;
+
+ // for convert
+ float *c_lastphase_in;
+ float *c_lastphase_out;
+ float c_fundamental;
+ float c_factor_in;
+ float c_factor_out;
+ // for fast fft
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ short mute;
+ short bypass;
+ float init_thresh;
+ float init_damping;
+ int overlap;
+ int winfac;
+ float tadv;
+ short inf_hold;
+} t_bthresher;
+
+
+void *bthresher_new(t_symbol *s, int argc, t_atom *argv);
+t_int *offset_perform(t_int *w);
+t_int *bthresher_perform(t_int *w);
+void bthresher_dsp(t_bthresher *x, t_signal **sp, short *count);
+void bthresher_assist(t_bthresher *x, void *b, long m, long a, char *s);
+void bthresher_float(t_bthresher *x, double f);
+void bthresher_mute(t_bthresher *x, t_floatarg f);
+void bthresher_bypass(t_bthresher *x, t_floatarg f);
+void bthresher_overlap(t_bthresher *x, t_floatarg f);
+void bthresher_winfac(t_bthresher *x, t_floatarg f);
+void bthresher_fftinfo(t_bthresher *x);
+void bthresher_free(t_bthresher *x);
+void bthresher_bin(t_bthresher *x, t_floatarg bin_num, t_floatarg threshold, t_floatarg damper);
+void bthresher_rdamper(t_bthresher *x, t_floatarg min, t_floatarg max );
+void bthresher_rthreshold(t_bthresher *x, t_floatarg min, t_floatarg max);
+void bthresher_dump(t_bthresher *x );
+void bthresher_list (t_bthresher *x, t_symbol *msg, short argc, t_atom *argv);
+void bthresher_init(t_bthresher *x, short initialized);
+float bthresher_boundrand(float min, float max);
+void bthresher_allthresh(t_bthresher *x, t_floatarg f);
+void bthresher_alldamp(t_bthresher *x, t_floatarg f);
+void bthresher_inf_hold(t_bthresher *x, t_floatarg f);
+void bthresher_max_hold(t_bthresher *x, t_floatarg f);
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&bthresher_class, (method)bthresher_new, (method)bthresher_free,
+ (short)sizeof(t_bthresher), 0, A_GIMME, 0);
+ addmess((method)bthresher_dsp, "dsp", A_CANT, 0);
+ addmess((method)bthresher_assist,"assist",A_CANT,0);
+ addmess((method)bthresher_mute,"mute",A_FLOAT,0);
+ addmess((method)bthresher_bypass,"bypass",A_FLOAT,0);
+ addmess((method)bthresher_overlap,"overlap",A_FLOAT,0);
+ addmess((method)bthresher_winfac,"winfac",A_FLOAT,0);
+ addmess((method)bthresher_fftinfo,"fftinfo",0);
+ addmess ((method)bthresher_bin, "bin", A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ addmess ((method)bthresher_rdamper, "rdamper", A_DEFFLOAT, A_DEFFLOAT, 0);
+ addmess ((method)bthresher_rthreshold, "rthreshold", A_DEFFLOAT, A_DEFFLOAT, 0);
+ addmess((method)bthresher_dump,"dump",0);
+ addmess((method)bthresher_list,"list",A_GIMME,0);
+ addmess((method)bthresher_alldamp,"alldamp",A_FLOAT,0);
+ addmess((method)bthresher_allthresh,"allthresh",A_FLOAT,0);
+ addmess((method)bthresher_inf_hold,"inf_hold",A_FLOAT,0);
+ addmess((method)bthresher_max_hold,"max_hold",A_FLOAT,0);
+ addfloat((method)bthresher_float);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+#if PD
+void bthresher_tilde_setup(void){
+ bthresher_class = class_new(gensym("bthresher~"), (t_newmethod)bthresher_new,
+ (t_method)bthresher_free ,sizeof(t_bthresher), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(bthresher_class, t_bthresher, x_f);
+ class_addmethod(bthresher_class,(t_method)bthresher_dsp,gensym("dsp"),0);
+ class_addmethod(bthresher_class,(t_method)bthresher_mute,gensym("mute"),A_FLOAT,0);
+ class_addmethod(bthresher_class,(t_method)bthresher_bypass,gensym("bypass"),A_FLOAT,0);
+ class_addmethod(bthresher_class,(t_method)bthresher_overlap,gensym("overlap"),A_FLOAT,0);
+ class_addmethod(bthresher_class,(t_method)bthresher_winfac,gensym("winfac"),A_FLOAT,0);
+ class_addmethod(bthresher_class,(t_method)bthresher_fftinfo,gensym("fftinfo"),0);
+ class_addmethod(bthresher_class,(t_method)bthresher_rdamper,gensym("rdamper"),A_FLOAT,A_FLOAT,0);
+ class_addmethod(bthresher_class,(t_method)bthresher_rthreshold,gensym("rthreshold"),A_FLOAT,A_FLOAT,0);
+ class_addmethod(bthresher_class,(t_method)bthresher_dump,gensym("dump"),0);
+ class_addmethod(bthresher_class,(t_method)bthresher_list,gensym("list"),A_GIMME,0);
+ class_addmethod(bthresher_class,(t_method)bthresher_alldamp,gensym("alldamp"),A_FLOAT,0);
+ class_addmethod(bthresher_class,(t_method)bthresher_allthresh,gensym("allthresh"),A_FLOAT,0);
+ class_addmethod(bthresher_class,(t_method)bthresher_inf_hold,gensym("inf_hold"),A_FLOAT,0);
+ class_addmethod(bthresher_class,(t_method)bthresher_max_hold,gensym("max_hold"),A_FLOAT,0);
+ class_addmethod(bthresher_class,(t_method)bthresher_bin,gensym("bin"),A_FLOAT,A_FLOAT,A_FLOAT,0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+void bthresher_fftinfo( t_bthresher *x )
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+void bthresher_free( t_bthresher *x ){
+#if MSP
+ dsp_free( (t_pxobject *) x);
+#endif
+
+
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->buffer,0);
+ freebytes(x->channel,0);
+ freebytes(x->input,0);
+ freebytes(x->output,0);
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ /* full phase vocoder */
+ freebytes(x->c_lastphase_in,0);
+ freebytes(x->c_lastphase_out,0);
+ /* external-specific memory */
+ freebytes(x->composite_frame,0);
+ freebytes(x->frames_left,0);
+ freebytes(x->move_threshold,0);
+ freebytes(x->damping_factor,0);
+ freebytes(x->list_data,0);
+}
+
+void bthresher_max_hold(t_bthresher *x, t_floatarg f)
+{
+ if(f<=0)
+ return;
+ x->max_hold_time = f * .001;
+ x->max_hold_frames = x->max_hold_time / x->tadv;
+}
+
+void bthresher_inf_hold(t_bthresher *x, t_floatarg f)
+{
+ x->inf_hold = (int)f;
+}
+
+void bthresher_allthresh(t_bthresher *x, t_floatarg f)
+{
+int i;
+//post("thresh %f",f);
+ for(i=0;i<x->N2+1;i++)
+ x->move_threshold[i] = f;
+}
+
+void bthresher_alldamp(t_bthresher *x, t_floatarg f)
+{
+int i;
+//post("damp %f",f);
+ for(i=0;i<x->N2+1;i++)
+ x->damping_factor[i] = f;
+}
+
+void bthresher_overlap(t_bthresher *x, t_floatarg f)
+{
+int i = (int) f;
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->overlap = i;
+ bthresher_init(x,1);
+}
+
+void bthresher_winfac(t_bthresher *x, t_floatarg f)
+{
+int i = (int)f;
+
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = i;
+ bthresher_init(x,2);
+}
+
+void bthresher_mute(t_bthresher *x, t_floatarg f){
+ x->mute = f;
+}
+void bthresher_bypass(t_bthresher *x, t_floatarg f){
+ x->bypass = f;
+}
+
+void bthresher_assist (t_bthresher *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0:sprintf(dst,"(signal) Input");break;
+ case 1:sprintf(dst,"(signal/float) Threshold Scalar");break;
+ case 2:sprintf(dst,"(signal/float) Damping Factor Scalar");break;
+ }
+ } else if (msg==2) {
+ switch (arg) {
+ case 0:sprintf(dst,"(signal) Output");break;
+ case 1:sprintf(dst,"(list) Current State");break;
+ }
+ }
+}
+
+void bthresher_list (t_bthresher *x, t_symbol *msg, short argc, t_atom *argv) {
+ int i, bin, idiv;
+ float fdiv;
+ float *damping_factor = x->damping_factor;
+ float *move_threshold = x->move_threshold;
+
+ // post("reading %d elements", argc);
+ idiv = fdiv = (float) argc / 3.0 ;
+ if( fdiv - idiv > 0.0 ) {
+ post("list must be in triplets");
+ return;
+ }
+/* for( i = 0; i < x->N2+1; i++) {
+ move_threshold[i] = 0.0 ;
+ }*/
+
+ for( i = 0; i < argc; i += 3 ) {
+ bin = atom_getintarg(i,argc,argv);
+ damping_factor[bin] = atom_getfloatarg(i+1,argc,argv);
+ move_threshold[bin] = atom_getfloatarg(i+2,argc,argv);
+/* bin = argv[i].a_w.w_long ;
+ damping_factor[bin] = argv[i + 1].a_w.w_float;
+ move_threshold[bin] = argv[i + 2].a_w.w_float;*/
+ }
+}
+
+void bthresher_dump (t_bthresher *x) {
+
+ t_atom *list_data = x->list_data;
+ float *damping_factor = x->damping_factor;
+ float *move_threshold = x->move_threshold;
+
+ int i,j, count;
+#if MSP
+ for( i = 0, j = 0; i < x->N2 * 3 ; i += 3, j++ ) {
+ SETLONG(list_data+i,j);
+ SETFLOAT(list_data+(i+1),damping_factor[j]);
+ SETFLOAT(list_data+(i+2),move_threshold[j]);
+ }
+#endif
+
+#if PD
+ for( i = 0, j = 0; i < x->N2 * 3 ; i += 3, j++ ) {
+ SETFLOAT(list_data+i,(float)j);
+ SETFLOAT(list_data+(i+1),damping_factor[j]);
+ SETFLOAT(list_data+(i+2),move_threshold[j]);
+ }
+#endif
+
+ count = x->N2 * 3;
+ outlet_list(x->list_outlet,0,count,list_data);
+
+ return;
+}
+
+void *bthresher_new(t_symbol *s, int argc, t_atom *argv)
+{
+#if MSP
+ t_bthresher *x = (t_bthresher *)newobject(bthresher_class);
+ x->list_outlet = listout((t_pxobject *)x);
+ dsp_setup((t_pxobject *)x,3);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+
+#if PD
+ t_bthresher *x = (t_bthresher *)pd_new(bthresher_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->list_outlet = outlet_new(&x->x_obj,gensym("list"));
+#endif
+
+
+ x->D = sys_getblksize();
+ x->R = sys_getsr();
+
+ x->init_thresh = atom_getfloatarg(0,argc,argv);
+ x->init_damping = atom_getfloatarg(1,argc,argv);
+ x->overlap = atom_getintarg(2,argc,argv);
+ x->winfac = atom_getintarg(3,argc,argv);
+
+ bthresher_init(x,0);
+
+
+
+ return (x);
+}
+
+void bthresher_init(t_bthresher *x, short initialized)
+{
+int i;
+
+ if(!x->D)
+ x->D = 256;
+ if(!x->R)
+ x->R = 44100;
+ if(!power_of_two(x->overlap))
+ x->overlap = 4;
+ if(!power_of_two(x->winfac))
+ x->winfac = 1;
+
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+
+limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+
+ x->mult = 1. / (float) x->N;
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->in_count = -(x->Nw);
+ x->c_fundamental = (float) x->R/((x->N2)<<1 );
+ x->c_factor_in = (float) x->R/((float)x->D * TWOPI);
+ x->c_factor_out = TWOPI * (float) x->D / (float) x->R;
+
+ if(!initialized){
+ x->first_frame = 1;
+ x->max_hold_time = 60.0 ;
+ x->thresh_connected = 0;
+ x->damping_connected = 0;
+ x->thresh_scalar = 1;
+ x->damp_scalar = 1;
+ x->mute = 0;
+ x->bypass = 0;
+ x->inf_hold = 0;
+ x->Wanal = (float *) getbytes((MAX_Nw) * sizeof(float));
+ x->Wsyn = (float *) getbytes((MAX_Nw) * sizeof(float));
+ x->Hwin = (float *) getbytes((MAX_Nw) * sizeof(float));
+ x->input = (float *) getbytes((MAX_Nw) * sizeof(float));
+ x->buffer = (float *) getbytes((MAX_N) * sizeof(float));
+ x->channel = (float *) getbytes(((MAX_N+2)) * sizeof(float));
+ x->output = (float *) getbytes((MAX_Nw) * sizeof(float));
+ x->bitshuffle = (int *) getbytes((MAX_N * 2) * sizeof(int));
+ x->trigland = (float *) getbytes((MAX_N * 2) * sizeof(float));
+
+ x->c_lastphase_in = (float *) getbytes((MAX_N2+1)* sizeof(float));
+ x->c_lastphase_out = (float *) getbytes((MAX_N2+1)* sizeof(float));
+
+ x->composite_frame = (float *) getbytes( (MAX_N+2)* sizeof(float));
+ x->frames_left = (int *) getbytes((MAX_N+2)* sizeof(int));
+
+ // TRIPLETS OF bin# damp_factor threshold
+ x->list_data = (t_atom *) getbytes((MAX_N2 + 1) * 3 * sizeof(t_atom));
+
+ x->move_threshold = (float *) getbytes((MAX_N2+1)* sizeof(float));
+ x->damping_factor = (float *) getbytes((MAX_N2+1)* sizeof(float));
+
+
+ }
+ if(initialized == 0 || initialized == 1){
+ for(i = 0; i < x->N2+1; i++) {
+ x->move_threshold[i] = x->init_thresh;
+ x->damping_factor[i] = x->init_damping;
+ }
+ }
+
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ memset((char *)x->buffer,0,x->N * sizeof(float));
+ memset((char *)x->c_lastphase_in,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->c_lastphase_out,0,(x->N2+1) * sizeof(float));
+
+
+ x->tadv = (float) x->D / (float) x->R;
+ x->max_hold_frames = x->max_hold_time / x->tadv;
+ init_rdft(x->N, x->bitshuffle, x->trigland);
+ makehanning(x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 0);
+}
+
+void bthresher_rdamper(t_bthresher *x, t_floatarg min, t_floatarg max)
+{
+ int i;
+
+ for( i = 0; i < x->N2; i++ ) {
+ x->damping_factor[i] = bthresher_boundrand(min, max);
+ }
+}
+
+void bthresher_rthreshold( t_bthresher *x, t_floatarg min, t_floatarg max )
+{
+ int i;
+ for( i = 0; i < x->N2; i++ ) {
+ x->move_threshold[i] = bthresher_boundrand(min, max);
+ }
+}
+
+
+void bthresher_bin(t_bthresher *x, t_floatarg bin_num, t_floatarg damper, t_floatarg threshold)
+{
+int bn = (int) bin_num;
+ if( bn >= 0 && bn < x->N2 ){
+// post("setting %d to %f %f",bn,threshold,damper);
+ x->move_threshold[bn] = threshold;
+ x->damping_factor[bn] = damper;
+ } else {
+ post("bthresher~: %d is out of range", bn);
+ }
+}
+
+
+t_int *bthresher_perform(t_int *w)
+{
+
+ float sample, outsamp ;
+ int i, j, on;
+ t_bthresher *x = (t_bthresher *) (w[1]);
+ float *in = (t_float *)(w[2]);
+ float *inthresh = (t_float *)(w[3]);
+ float *damping = (t_float *)(w[4]);
+ float *out = (t_float *)(w[5]);
+ t_int n = w[6];
+
+
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland;
+ float mult = x->mult;
+
+ int in_count = x->in_count;
+ int R = x->R;
+ int N = x->N;
+ int N2 = x->N2;
+ int D = x->D;
+ int Nw = x->Nw;
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *damping_factor = x->damping_factor;
+ float *move_threshold = x->move_threshold;
+ float *input = x->input;
+ float *output = x->output;
+ float *buffer = x->buffer;
+ float *channel = x->channel;
+ float *composite_frame = x->composite_frame;
+ int max_hold_frames = x->max_hold_frames;
+ int *frames_left = x->frames_left;
+ float thresh_scalar = x->thresh_scalar;
+ float damp_scalar = x->damp_scalar;
+ short inf_hold = x->inf_hold;
+
+ if( x->mute ) {
+ for( j = 0; j < D; j++) {
+ *out++ = 0.0 ;
+ }
+ } else if ( x->bypass ) {
+ for( j = 0; j < D; j++) {
+ *out++ = *in++ * 0.5;
+ }
+ } else {
+#if MSP
+ if( x->thresh_connected ) {
+ thresh_scalar = *inthresh++;
+ }
+ if( x->damping_connected ) {
+ damp_scalar = *damping++;
+ }
+#endif
+
+#if PD
+ thresh_scalar = *inthresh++;
+ damp_scalar = *damping++;
+#endif
+
+ in_count += D;
+
+
+ for ( j = 0 ; j < Nw - D ; j++ )
+ input[j] = input[j+D];
+
+ for ( j = Nw-D; j < Nw; j++ ) {
+ input[j] = *in++;
+ }
+
+ fold( input, Wanal, Nw, buffer, N, in_count );
+ rdft( N, 1, buffer, bitshuffle, trigland );
+ convert( buffer, channel, N2, x->c_lastphase_in, x->c_fundamental, x->c_factor_in );
+
+ if( x->first_frame ){
+ for ( i = 0; i < N+2; i++ ){
+ composite_frame[i] = channel[i];
+ x->frames_left[i] = max_hold_frames;
+ }
+ x->first_frame = 0;
+ } else {
+ if( thresh_scalar < .999 || thresh_scalar > 1.001 || damp_scalar < .999 || damp_scalar > 1.001 ) {
+ for(i = 0, j = 0; i < N+2; i += 2, j++ ){
+ if( fabs( composite_frame[i] - channel[i] ) > move_threshold[j] * thresh_scalar|| frames_left[j] <= 0 ){
+ composite_frame[i] = channel[i];
+ composite_frame[i+1] = channel[i+1];
+ frames_left[j] = max_hold_frames;
+ } else {
+ if(!inf_hold){
+ --(frames_left[j]);
+ }
+ composite_frame[i] *= damping_factor[j] * damp_scalar;
+ }
+ }
+
+ } else {
+ for( i = 0, j = 0; i < N+2; i += 2, j++ ){
+ if( fabs( composite_frame[i] - channel[i] ) > move_threshold[j] || frames_left[j] <= 0 ){
+ composite_frame[i] = channel[i];
+ composite_frame[i+1] = channel[i+1];
+ frames_left[j] = max_hold_frames;
+ } else {
+ if(!inf_hold){
+ --(frames_left[j]);
+ }
+ composite_frame[i] *= damping_factor[j];
+ }
+ }
+ }
+ }
+
+ unconvert(x->composite_frame, buffer, N2, x->c_lastphase_out, x->c_fundamental, x->c_factor_out);
+ rdft(N, -1, buffer, bitshuffle, trigland);
+
+ overlapadd(buffer, N, Wsyn, output, Nw, in_count);
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+ }
+ x->in_count = in_count % Nw;
+ x->thresh_scalar = thresh_scalar;
+ x->damp_scalar = damp_scalar;
+
+ return (w+7);
+}
+
+#if MSP
+void bthresher_float(t_bthresher *x, double f) // Look at floats at inlets
+{
+ int inlet = x->x_obj.z_in;
+ int i;
+ if (inlet == 1)
+ {
+ x->thresh_scalar = f;
+ } else if (inlet == 2) {
+ x->damp_scalar = f;
+ }
+}
+#endif
+
+void bthresher_dsp(t_bthresher *x, t_signal **sp, short *count)
+{
+#if MSP
+ x->thresh_connected = count[1];
+ x->damping_connected = count[2];
+#endif
+ if(sp[0]->s_n != x->D || x->R != sp[0]->s_sr){
+ x->D = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ bthresher_init(x,1);
+ }
+ dsp_add(bthresher_perform, 6, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec,
+ sp[0]->s_n);
+}
+
+float bthresher_boundrand( float min, float max) {
+ float frand;
+ frand = (float) (rand() % 32768)/ 32768.0;
+ return (min + frand * (max-min) );
+}
+
diff --git a/burrow~.c b/burrow~.c
new file mode 100644
index 0000000..cf5be2d
--- /dev/null
+++ b/burrow~.c
@@ -0,0 +1,545 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+ void *burrow_class;
+#endif
+#if PD
+ static t_class *burrow_class;
+#endif
+
+#define OBJECT_NAME "burrow~"
+
+/* after adding fixes, window factors > 1 are defective. Is there
+a remaining bug, or is this a problem for FFT-only processors? */
+
+/* A few changes:
+
+Threshold and Multiplier now have their own
+inlets, which accept (signal/float). The input
+is now linear, rather than in dB. Reasons for this:
+
+1) Linear input is the Max/MSP convention
+2) It is easy to convert from linear to dB in Max
+3) (My favorite) This cuts down on programmer overhead.
+
+ */
+
+typedef struct _burrow
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ int invert;
+ int *bitshuffle;
+
+ float threshold;
+ float multiplier;
+ float mult;
+ float *Wanal;
+ float *Wsyn;
+ float *inputOne;
+ float *inputTwo;
+ float *Hwin;
+ float *bufferOne;
+ float *bufferTwo;
+ float *channelOne;
+ float *channelTwo;
+ float *output;
+ float *trigland;
+
+ short connected[8];
+ short mute;
+ int overlap;//overlap factor
+ int winfac;//window factor
+ int vs;//vector size
+} t_burrow;
+
+
+/* msp function prototypes */
+
+void *burrow_new(t_symbol *s, int argc, t_atom *argv);
+t_int *offset_perform(t_int *w);
+t_int *burrow_perform(t_int *w);
+void burrow_dsp(t_burrow *x, t_signal **sp, short *count);
+void burrow_assist(t_burrow *x, void *b, long m, long a, char *s);
+void burrow_float(t_burrow *x, t_floatarg myFloat);
+void burrow_init(t_burrow *x, short initialized);
+void burrow_free(t_burrow *x);
+void burrow_invert(t_burrow *x, t_floatarg toggle);
+void burrow_mute(t_burrow *x, t_floatarg toggle);
+void burrow_fftinfo(t_burrow *x);
+void burrow_tilde_setup(void);
+void burrow_overlap(t_burrow *x, t_floatarg o);
+void burrow_winfac(t_burrow *x, t_floatarg f);
+
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&burrow_class,(method) burrow_new,
+(method)burrow_free, (short) sizeof(t_burrow),0, A_GIMME, 0);
+ addmess((method)burrow_dsp, "dsp", A_CANT, 0);
+ addmess((method)burrow_assist,"assist",A_CANT,0);
+ addmess((method)burrow_invert,"invert", A_FLOAT, 0);
+ addmess((method)burrow_overlap,"overlap", A_FLOAT, 0);
+ addmess((method)burrow_mute,"mute", A_FLOAT, 0);
+ addmess((method)burrow_winfac,"winfac",A_FLOAT,0);
+ addmess((method)burrow_fftinfo,"fftinfo", 0);
+ addfloat((method)burrow_float);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+
+/* float input handling routines (MSP only) */
+
+void burrow_float(t_burrow *x, t_floatarg myFloat)
+{
+int inlet = ((t_pxobject*)x)->z_in;
+ if ( inlet == 2 ) // added two outlets so position is moved over
+ x->threshold = myFloat;
+
+ if ( inlet == 3 )
+ x->multiplier = myFloat;
+}
+#endif
+#if PD
+void burrow_tilde_setup(void)
+{
+ burrow_class = class_new(gensym("burrow~"), (t_newmethod)burrow_new,
+ (t_method)burrow_free ,sizeof(t_burrow), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(burrow_class, t_burrow, x_f);
+ class_addmethod(burrow_class, (t_method)burrow_dsp, gensym("dsp"), 0);
+ class_addmethod(burrow_class, (t_method)burrow_assist, gensym("assist"), 0);
+ class_addmethod(burrow_class, (t_method)burrow_invert, gensym("invert"), A_FLOAT,0);
+ class_addmethod(burrow_class, (t_method)burrow_overlap, gensym("overlap"), A_FLOAT,0);
+ class_addmethod(burrow_class, (t_method)burrow_mute, gensym("mute"), A_FLOAT,0);
+ class_addmethod(burrow_class, (t_method)burrow_fftinfo, gensym("fftinfo"), A_CANT,0);
+ class_addmethod(burrow_class,(t_method)burrow_winfac,gensym("winfac"),A_FLOAT,0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+void burrow_free(t_burrow *x)
+{
+#if MSP
+ dsp_free((t_pxobject *) x);
+#endif
+ free(x->trigland);
+ free(x->bitshuffle);
+ free(x->Wanal);
+ free(x->Wsyn);
+ free(x->Hwin);
+ free(x->inputOne);
+ free(x->inputTwo);
+ free(x->bufferOne);
+ free(x->bufferTwo);
+ free(x->channelOne);
+ free(x->channelTwo);
+ free(x->output);
+
+}
+
+
+void burrow_invert(t_burrow *x, t_floatarg toggle)
+{
+ x->invert = toggle;
+}
+
+void burrow_mute(t_burrow *x, t_floatarg toggle)
+{
+ x->mute = toggle;
+}
+
+void burrow_overlap(t_burrow *x, t_floatarg o)
+{
+ if(!power_of_two(o)){
+ error("%f is not a power of two",o);
+ return;
+ }
+ x->overlap = o;
+ burrow_init(x,1);
+}
+
+void burrow_winfac(t_burrow *x, t_floatarg f)
+{
+ if(!power_of_two(f)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = (int)f;
+ burrow_init(x,1);
+}
+
+void burrow_fftinfo( t_burrow *x )
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+
+
+/* diagnostic messages for Max */
+
+void burrow_assist (t_burrow *x, void *b, long msg, long arg, char *dst)
+{
+
+ if (msg == 1) {
+
+ switch (arg) {
+ case 0: sprintf(dst,"(signal) Source Sound"); break;
+ case 1: sprintf(dst,"(signal) Burrow Filtering Sound"); break;
+ case 2: sprintf(dst,"(signal/float) Filter Threshold"); break;
+ case 3: sprintf(dst,"(signal/float) Filter Multiplier"); break;
+ }
+ }
+
+ else {
+ if (msg == 2)
+ sprintf(dst,"(signal) Output");
+ }
+}
+
+void burrow_init(t_burrow *x, short initialized)
+{
+int i;
+ x->D = x->vs;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+ if(!initialized){
+ x->mute = 0;
+ x->invert = 0;
+ x->inputOne = (float *) calloc(MAX_Nw, sizeof(float));
+ x->inputTwo = (float *) calloc(MAX_Nw, sizeof(float));
+ x->bufferOne = (float *) calloc(MAX_N, sizeof(float));
+ x->bufferTwo = (float *) calloc(MAX_N, sizeof(float));
+ x->channelOne = (float *) calloc((MAX_N+2), sizeof(float));
+ x->channelTwo = (float *) calloc((MAX_N+2), sizeof(float));
+ x->Wanal = (float *) calloc(MAX_Nw, sizeof(float));
+ x->Wsyn = (float *) calloc(MAX_Nw, sizeof(float));
+ x->Hwin = (float *) calloc(MAX_Nw, sizeof(float));
+ x->output = (float *) calloc(MAX_Nw, sizeof(float));
+ x->bitshuffle = (int *) calloc(MAX_N * 2, sizeof(int));
+ x->trigland = (float *) calloc(MAX_N * 2, sizeof(float));
+ }
+ memset((char *)x->inputOne,0,x->Nw * sizeof(float));
+ memset((char *)x->inputTwo,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ memset((char *)x->bufferOne,0,x->N * sizeof(float));
+ memset((char *)x->bufferTwo,0,x->N * sizeof(float));
+
+ makehanning( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 0);
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+}
+
+void *burrow_new(t_symbol *s, int argc, t_atom *argv)
+{
+#if MSP
+ t_burrow *x = (t_burrow *) newobject(burrow_class);
+ dsp_setup((t_pxobject *)x,4);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+#if PD
+ t_burrow *x = (t_burrow *)pd_new(burrow_class);
+ /* add three additional signal inlets */
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+/* optional arguments: threshold, multiplier, overlap, winfac */
+
+ x->threshold = atom_getfloatarg(0,argc,argv);
+ x->multiplier = atom_getfloatarg(1,argc,argv);
+ x->overlap = atom_getfloatarg(2,argc,argv);
+ x->winfac = atom_getfloatarg(3,argc,argv);
+
+ if(!power_of_two(x->overlap)){
+ x->overlap = 4;
+ }
+ if(!power_of_two(x->winfac)){
+ x->winfac = 1;
+ }
+ if(x->threshold > 1.0 || x->threshold < 0.0){
+ x->threshold = 0;
+ }
+ if(x->multiplier > 1.0 || x->multiplier < 0.0){
+ x->multiplier = .01;
+ }
+
+ x->vs = sys_getblksize();
+ x->R = sys_getsr();
+
+ burrow_init(x,0);
+ return(x);
+
+}
+
+
+t_int *burrow_perform(t_int *w)
+{
+/* get our inlets and outlets */
+
+ t_burrow *x = (t_burrow *) (w[1]);
+ t_float *inOne = (t_float *)(w[2]);
+ t_float *inTwo = (t_float *)(w[3]);
+ t_float *flt_threshold = (t_float *)(w[4]);
+ t_float *flt_multiplier = (t_float *)(w[5]);
+ t_float *out = (t_float *)(w[6]);
+ t_int n = w[7];
+
+ short *connected = x->connected;
+
+ int
+ i,j,
+ inCount,
+ R,
+ N,
+ N2,
+ D,
+ Nw,
+ invert = 0,
+ even, odd,
+ *bitshuffle;
+
+ float maxamp,
+ threshold = 1.,
+ multiplier = 1.,
+ mult,
+ a1, b1,
+ a2, b2,
+ *inputOne,
+ *inputTwo,
+ *bufferOne,
+ *bufferTwo,
+ *output,
+ *Wanal,
+ *Wsyn,
+ *channelOne,
+ *channelTwo,
+ *trigland;
+
+/* dereference structure */
+
+ inputOne = x->inputOne;
+ inputTwo = x->inputTwo;
+ bufferOne = x->bufferOne;
+ bufferTwo = x->bufferTwo;
+ inCount = x->inCount;
+
+ R = x->R;
+ N = x->N;
+ N2 = x->N2;
+ D = x->D;
+ Nw = x->Nw;
+ Wanal = x->Wanal;
+ Wsyn = x->Wsyn;
+ output = x->output;
+
+ channelOne = x->channelOne;
+ channelTwo = x->channelTwo;
+ bitshuffle = x->bitshuffle;
+ trigland = x->trigland;
+ multiplier = x->multiplier;
+ threshold = x->threshold;
+ mult = x->mult;
+ invert = x->invert;
+
+ if(connected[2]){
+ threshold = *flt_threshold;
+ } else {
+ threshold = x->threshold;
+ }
+
+ if(connected[3]){
+ multiplier = *flt_multiplier;
+ } else {
+ multiplier = x->multiplier;
+ }
+
+/* save some CPUs if muted */
+ if(x->mute){
+ while(n--)
+ *out++ = 0.0;
+ return (w+8);
+ }
+
+/* fill our retaining buffers */
+
+ inCount += D;
+
+ for ( j = 0 ; j < Nw - D ; j++ ) {
+ inputOne[j] = inputOne[j+D];
+ inputTwo[j] = inputTwo[j+D];
+ }
+
+ for ( j = Nw-D; j < Nw; j++ ) {
+ inputOne[j] = *inOne++;
+ inputTwo[j] = *inTwo++;
+ }
+
+/* apply hamming window and fold our window buffer into the fft buffer */
+
+ fold( inputOne, Wanal, Nw, bufferOne, N, inCount );
+ fold( inputTwo, Wanal, Nw, bufferTwo, N, inCount );
+
+
+/* do an fft */
+
+ rdft( N, 1, bufferOne, bitshuffle, trigland );
+ rdft( N, 1, bufferTwo, bitshuffle, trigland );
+
+/* use redundant coding for speed, even though moving the invert variable
+ comparison outside of the for loop will give us only a minimal performance
+ increase (hypot and atan2 are the most intensive portions of this code).
+ consider adding a table lookup for atan2 instead.
+*/
+
+
+if (invert) {
+
+/* convert to polar coordinates from complex values */
+
+ for ( i = 0; i <= N2; i++ ) {
+
+ odd = ( even = i<<1 ) + 1;
+
+ a1 = ( i == N2 ? *(bufferOne+1) : *(bufferOne+even) );
+ b1 = ( i == 0 || i == N2 ? 0. : *(bufferOne+odd) );
+
+ a2 = ( i == N2 ? *(bufferTwo+1) : *(bufferTwo+even) );
+ b2 = ( i == 0 || i == N2 ? 0. : *(bufferTwo+odd) );
+
+ *(channelOne+even) = hypot( a1, b1 );
+ *(channelOne+odd) = -atan2( b1, a1 );
+
+ *(channelTwo+even) = hypot( a2, b2 );
+
+ /* use simple threshold from second signal to trigger filtering */
+
+ if ( *(channelTwo+even) < threshold )
+ *(channelOne+even) *= multiplier;
+
+/* *(channelTwo+odd) = -atan2( b2, a2 ); */
+
+ }
+}
+
+else {
+
+/* convert to polar coordinates from complex values */
+
+ for ( i = 0; i <= N2; i++ ) {
+
+ odd = ( even = i<<1 ) + 1;
+
+ a1 = ( i == N2 ? *(bufferOne+1) : *(bufferOne+even) );
+ b1 = ( i == 0 || i == N2 ? 0. : *(bufferOne+odd) );
+
+ a2 = ( i == N2 ? *(bufferTwo+1) : *(bufferTwo+even) );
+ b2 = ( i == 0 || i == N2 ? 0. : *(bufferTwo+odd) );
+
+ *(channelOne+even) = hypot( a1, b1 );
+ *(channelOne+odd) = -atan2( b1, a1 );
+
+ *(channelTwo+even) = hypot( a2, b2 );
+
+ /* use simple threshold from second signal to trigger filtering */
+
+ if ( *(channelTwo+even) > threshold )
+ *(channelOne+even) *= multiplier;
+
+/* *(channelTwo+odd) = -atan2( b2, a2 ); */
+
+ }
+}
+
+/* convert back to complex form, read for the inverse fft */
+
+ for ( i = 0; i <= N2; i++ ) {
+
+ odd = ( even = i<<1 ) + 1;
+
+ *(bufferOne+even) = *(channelOne+even) * cos( *(channelOne+odd) );
+
+ if ( i != N2 )
+ *(bufferOne+odd) = -(*(channelOne+even)) * sin( *(channelOne+odd) );
+ }
+
+
+/* do an inverse fft */
+
+ rdft( N, -1, bufferOne, bitshuffle, trigland );
+
+/* dewindow our result */
+
+ overlapadd( bufferOne, N, Wsyn, output, Nw, inCount);
+
+/* set our output and adjust our retaining output buffer */
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+
+/* restore state variables */
+
+ x->inCount = inCount % Nw;
+ return (w+8);
+}
+
+void burrow_dsp(t_burrow *x, t_signal **sp, short *count)
+{
+ long i;
+ #if MSP
+ for( i = 0; i < 4; i++ ){
+ x->connected[i] = count[i];
+ }
+ #endif
+ /* signal is always connected in Pd */
+ #if PD
+ for( i = 0; i < 4; i++ ){
+ x->connected[i] = 1;
+ }
+ #endif
+ /* reinitialize if vector size or sampling rate has been changed */
+ if(x->vs != sp[0]->s_n || x->R != sp[0]->s_sr){
+ x->vs = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ burrow_init(x,1);
+ }
+ dsp_add(burrow_perform, 7, x,
+ sp[0]->s_vec,
+ sp[1]->s_vec,
+ sp[2]->s_vec,
+ sp[3]->s_vec,
+ sp[4]->s_vec,
+ sp[0]->s_n);
+}
+
diff --git a/cavoc27~.c b/cavoc27~.c
new file mode 100644
index 0000000..8fbca59
--- /dev/null
+++ b/cavoc27~.c
@@ -0,0 +1,675 @@
+#include "MSPd.h"
+
+#include "fftease.h"
+
+#if MSP
+void *cavoc27_class;
+#endif
+
+#if PD
+static t_class *cavoc27_class;
+#endif
+
+#define OBJECT_NAME "cavoc27~"
+
+/* NOTE THIS IS A MORE COMPLEX CA WITH 3 DIFFERENT STATES */
+
+typedef struct _cavoc27
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ float *buffer;
+ float *channel;
+ float *ichannel; //for interpolation
+ float *tmpchannel; // for spectrum capture
+ float *output;
+ float frame_duration;
+ int max_bin;
+
+ // for CAVOC2
+
+ float fundamental;
+ float *last_frame;
+ short left;
+ short right;
+ short center;
+ short *rule;
+ float density;
+ float start_breakpoint;
+ int hold_frames;
+ int frames_left;
+ int set_count;
+ short interpolate_flag;
+ short capture_flag;
+ short capture_lock;
+ // FFT
+ // for convert
+
+ float *c_lastphase_in;
+ float *c_lastphase_out;
+ float c_fundamental;
+ float c_factor_in;
+ float c_factor_out;
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ //
+ void *list_outlet;
+ t_atom *list_data;
+ short mute;
+ int winfac;//window factor
+ int overlap;//overlap factor
+ int vs;//vector size
+ float hold_time;//hold time in seconds
+} t_cavoc27;
+
+void *cavoc27_new(t_symbol *s, int argc, t_atom *argv);
+t_int *offset_perform(t_int *w);
+t_int *cavoc27_perform(t_int *w);
+void cavoc27_dsp(t_cavoc27 *x, t_signal **sp, short *count);
+void cavoc27_assist(t_cavoc27 *x, void *b, long m, long a, char *s);
+void cavoc27_free( t_cavoc27 *x);
+int cavoc27_apply_rule( short left, short right, short center, short *rule);
+float cavoc27_randf(float min, float max);
+void cavoc27_rule (t_cavoc27 *x, t_symbol *msg, short argc, t_atom *argv);
+void cavoc27_density (t_cavoc27 *x, t_floatarg density);
+void cavoc27_hold_time (t_cavoc27 *x, t_floatarg hold_time);
+void cavoc27_interpolate (t_cavoc27 *x, t_floatarg interpolate);
+void cavoc27_capture_spectrum (t_cavoc27 *x, t_floatarg flag );
+void cavoc27_capture_lock (t_cavoc27 *x, t_floatarg toggle );
+void cavoc27_retune (t_cavoc27 *x, t_floatarg min, t_floatarg max);
+void cavoc27_mute (t_cavoc27 *x, t_floatarg toggle);
+void cavoc27_init(t_cavoc27 *x,short initialized);
+void cavoc27_rand_set_spectrum(t_cavoc27 *x);
+void cavoc27_rand_set_rule(t_cavoc27 *x);
+void cavoc27_fftinfo(t_cavoc27 *x);
+void cavoc27_overlap(t_cavoc27 *x, t_floatarg f);
+void cavoc27_winfac(t_cavoc27 *x, t_floatarg f);
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&cavoc27_class, (method)cavoc27_new, (method)cavoc27_free,
+ (short)sizeof(t_cavoc27), 0, A_GIMME, 0);
+ addmess((method)cavoc27_dsp, "dsp", A_CANT, 0);
+ addmess((method)cavoc27_assist,"assist",A_CANT,0);
+ addmess((method)cavoc27_rule,"rule",A_GIMME,0);
+ addmess((method)cavoc27_density,"density",A_FLOAT,0);
+ addmess((method)cavoc27_hold_time,"hold_time",A_FLOAT,0);
+ addmess((method)cavoc27_interpolate,"interpolate",A_FLOAT,0);
+ addmess((method)cavoc27_overlap,"overlap",A_FLOAT,0);
+ addmess((method)cavoc27_winfac,"winfac",A_FLOAT,0);
+ addmess((method)cavoc27_fftinfo,"fftinfo",0);
+ addmess((method)cavoc27_retune,"retune",A_FLOAT,A_FLOAT,0);
+ addmess((method)cavoc27_capture_spectrum,"capture_spectrum",A_FLOAT,0);
+ addmess((method)cavoc27_mute,"mute",A_FLOAT,0);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+#if PD
+/* Pd Initialization */
+void cavoc27_tilde_setup(void)
+{
+ cavoc27_class = class_new(gensym("cavoc27~"), (t_newmethod)cavoc27_new,
+ (t_method)cavoc27_free ,sizeof(t_cavoc27), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(cavoc27_class, t_cavoc27, x_f);
+ class_addmethod(cavoc27_class, (t_method)cavoc27_dsp, gensym("dsp"), 0);
+ class_addmethod(cavoc27_class, (t_method)cavoc27_mute, gensym("mute"), A_FLOAT,0);
+ class_addmethod(cavoc27_class, (t_method)cavoc27_rule, gensym("rule"), A_GIMME,0);
+ class_addmethod(cavoc27_class, (t_method)cavoc27_density, gensym("density"), A_DEFFLOAT,0);
+ class_addmethod(cavoc27_class, (t_method)cavoc27_hold_time, gensym("hold_time"), A_DEFFLOAT,0);
+ class_addmethod(cavoc27_class, (t_method)cavoc27_interpolate, gensym("interpolate"), A_DEFFLOAT, 0);
+ class_addmethod(cavoc27_class, (t_method)cavoc27_capture_spectrum, gensym("capture_spectrum"), A_FLOAT, 0);
+ class_addmethod(cavoc27_class, (t_method)cavoc27_retune, gensym("retune"), A_DEFFLOAT,A_DEFFLOAT,0);
+ class_addmethod(cavoc27_class, (t_method)cavoc27_overlap, gensym("overlap"), A_FLOAT, 0);
+ class_addmethod(cavoc27_class, (t_method)cavoc27_winfac, gensym("winfac"), A_FLOAT, 0);
+ class_addmethod(cavoc27_class, (t_method)cavoc27_fftinfo, gensym("fftinfo"), 0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+void cavoc27_rand_set_rule(t_cavoc27 *x)
+{
+int i;
+float rval;
+ for( i = 0; i < 27; i++ ){
+ rval = cavoc27_randf(0.0,1.0);
+ if( rval < .333 )
+ x->rule[i] = 0;
+ else if(rval < .666 )
+ x->rule[i] = 1;
+ else x->rule[i] = 2;
+ }
+}
+
+void cavoc27_retune(t_cavoc27 *x, t_floatarg min, t_floatarg max)
+{
+ int i;
+
+ if( max <= 0 || min <= 0 || min > max ){
+ error("bad values for min and max multipliers");
+ return;
+ }
+ if( min < .1 )
+ min = 0.1;
+ if( max > 2.0 )
+ max = 2.0;
+ for( i = 0; i < x->N2 + 1; i++ ){
+ x->channel[ i * 2 + 1 ] = x->c_fundamental * (float) (i / 2) * cavoc27_randf(min, max);
+ }
+
+}
+
+void cavoc27_density(t_cavoc27 *x, t_floatarg density)
+{
+ int i;
+ if( density < 0.0001 ){
+ density = .0001;
+ } else if( density > .9999 ){
+ density = 1.0;
+ }
+ x->density = density;
+ x->start_breakpoint = 1.0 - x->density;
+ for( i = 0; i < x->N2 + 1; i++ ){
+ if( cavoc27_randf(0.0, 1.0) > x->start_breakpoint ){
+ if( cavoc27_randf(0.0,1.0) > 0.5 ){
+ x->channel[ i * 2 ] = 1;
+ }
+ else {
+ x->channel[ i * 2 ] = 2;
+ }
+ ++(x->set_count);
+ } else {
+ x->channel[ i * 2 ] = 0;
+ }
+ }
+ for( i = 0; i < x->N+2; i++ ){
+ x->last_frame[i] = x->channel[i];
+ }
+}
+
+void cavoc27_mute (t_cavoc27 *x, t_floatarg toggle)
+{
+ x->mute = (short)toggle;
+}
+
+void cavoc27_hold_time(t_cavoc27 *x, t_floatarg hold_time)
+{
+
+ if(hold_time <= 0){
+ post("illegal hold time %f",hold_time);
+ return;
+ }
+ x->hold_time = hold_time;
+ if(! x->frame_duration){
+ error("%s: zero frame duration",OBJECT_NAME);
+ x->frame_duration = .15;
+ }
+ x->hold_frames = (int) ( (hold_time/1000.0) / x->frame_duration);
+ if( x->hold_frames < 1 )
+ x->hold_frames = 1;
+ // x->frames_left = x->hold_frames;
+
+}
+
+void cavoc27_interpolate(t_cavoc27 *x, t_floatarg flag)
+{
+ x->interpolate_flag = (short) flag;
+}
+
+void cavoc27_capture_spectrum(t_cavoc27 *x, t_floatarg flag )
+{
+// now identical to capture_lock
+ x->capture_lock = (short)flag;
+}
+
+void cavoc27_capture_lock(t_cavoc27 *x, t_floatarg flag )
+{
+ x->capture_lock = (short)flag;
+}
+
+void cavoc27_rule (t_cavoc27 *x, t_symbol *msg, short argc, t_atom *argv)
+{
+ int i;
+ short *rule = x->rule;
+ if( argc != 27 ){
+ error("the rule must be size 18");
+ return;
+ }
+
+ for( i = 0; i < 27; i++ ){
+ rule[i] = (short) atom_getfloatarg( i, argc, argv);
+ }
+}
+
+void cavoc27_free( t_cavoc27 *x ){
+#if MSP
+ dsp_free( (t_pxobject *) x);
+#endif
+ free(x->trigland);
+ free(x->bitshuffle);
+ free(x->Wanal);
+ free(x->Wsyn);
+ free(x->input);
+ free(x->Hwin);
+ free(x->buffer);
+ free(x->channel);
+ free(x->ichannel);
+ free(x->tmpchannel);
+ free(x->last_frame);
+ free(x->output);
+ free(x->c_lastphase_out);
+ free(x->rule);
+}
+
+void cavoc27_assist (t_cavoc27 *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0:
+ sprintf(dst,"unused(signal)");
+ break;
+ }
+ } else if (msg==2) {
+ switch (arg) {
+ case 0:
+ sprintf(dst,"output(signal)"); break;
+ }
+ }
+}
+
+void *cavoc27_new(t_symbol *s, int argc, t_atom *argv)
+{
+#if MSP
+ t_cavoc27 *x = (t_cavoc27 *)newobject(cavoc27_class);
+ dsp_setup((t_pxobject *)x,1);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+#if PD
+ int i;
+ t_cavoc27 *x = (t_cavoc27 *)pd_new(cavoc27_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+ x->overlap = 0;
+ x->winfac=0;
+ x->hold_time=0;
+ x->density = 0;
+
+ x->density = atom_getfloatarg(0,argc,argv);
+ x->hold_time = atom_getfloatarg(1,argc,argv) * .001;// convert to seconds
+ x->overlap = atom_getfloatarg(2,argc,argv);
+ x->winfac = atom_getfloatarg(3,argc,argv);
+
+ if(x->density <= 0)
+ x->density = .0001;
+ if(x->density >= 1)
+ x->density = .9999;
+ x->start_breakpoint = 1.0 - x->density;
+ if(!x->hold_time)
+ x->hold_time = 0.15;
+
+ x->vs = sys_getblksize();
+ x->R = sys_getsr();
+
+ cavoc27_init(x,0);
+ return (x);
+}
+
+void cavoc27_overlap(t_cavoc27 *x, t_floatarg f)
+{
+int i = (int) f;
+ if(!power_of_two(i)){
+ post("%f is not a power of two",f);
+ return;
+ }
+ x->overlap = i;
+ cavoc27_init(x,1);
+}
+
+void cavoc27_winfac(t_cavoc27 *x, t_floatarg f)
+{
+int i = (int)f;
+
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = i;
+ cavoc27_init(x,2);
+}
+
+void cavoc27_fftinfo(t_cavoc27 *x)
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+
+void cavoc27_init(t_cavoc27 *x,short initialized)
+{
+int i;
+
+ if(!power_of_two(x->overlap))
+ x->overlap = 4;
+ if(!power_of_two(x->winfac))
+ x->winfac = 1;
+//post("init with o %d and wf %d",x->overlap,x->winfac);
+ x->D = x->vs;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+
+
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+ x->c_fundamental = (float) x->R/( (x->N2)<<1 );
+ x->c_factor_out = TWOPI * (float) x->D / (float) x->R;
+ x->c_factor_in = (float) x->R/((float)x->D * TWOPI);
+ x->frame_duration = (float)x->D/(float) x->R;
+ x->hold_frames = (int) (x->hold_time/x->frame_duration);
+ x->frames_left = x->hold_frames;
+// x->frames_left = 0;
+ x->set_count = 0;
+
+ if(!initialized){
+ srand(time(0));
+ x->interpolate_flag = 0;
+ x->capture_lock = 0;
+
+ x->mute = 0;
+ x->Wanal = (float *) calloc(MAX_Nw, sizeof(float));
+ x->Wsyn = (float *) calloc(MAX_Nw, sizeof(float));
+ x->input = (float *) calloc(MAX_Nw, sizeof(float));
+ x->Hwin = (float *) calloc(MAX_Nw, sizeof(float));
+ x->buffer = (float *) calloc(MAX_N, sizeof(float));
+ x->channel = (float *) calloc(MAX_N+2, sizeof(float));
+ x->ichannel = (float *) calloc(MAX_N+2, sizeof(float));
+ x->tmpchannel = (float *) calloc(MAX_N+2, sizeof(float));
+ x->rule = (short *) calloc(27, sizeof(short));
+ x->last_frame = (float *) calloc(MAX_N+2, sizeof(float));
+ x->output = (float *) calloc(MAX_Nw, sizeof(float));
+ x->bitshuffle = (int *) calloc(MAX_N * 2, sizeof(int));
+ x->trigland = (float *) calloc(MAX_N * 2, sizeof(float));
+ x->c_lastphase_in = (float *) calloc(MAX_N2+1, sizeof(float));
+ x->c_lastphase_out = (float *) calloc(MAX_N2+1, sizeof(float));
+
+
+ }
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ memset((char *)x->buffer,0,x->N * sizeof(float));
+ memset((char *)x->c_lastphase_in,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->c_lastphase_out,0,(x->N2+1) * sizeof(float));
+
+
+ cavoc27_rand_set_rule(x);
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makehanning( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 0);
+ cavoc27_rand_set_spectrum(x);
+ for( i = 0; i < x->N+2; i++ ){
+ x->last_frame[i] = x->channel[i];
+ }
+}
+
+void cavoc27_rand_set_spectrum(t_cavoc27 *x)
+{
+int i;
+float rval;
+
+ //set spectrum
+ for( i = 0; i < x->N2 + 1; i++ ){
+ if( cavoc27_randf(0.0, 1.0) > x->start_breakpoint){
+ rval = cavoc27_randf(0.0, 1.0);
+ if( rval < 0.5 ){
+ x->channel[ i * 2 ] = 1;
+ }
+ else {
+ x->channel[ i * 2 ] = 2;
+ }
+ ++(x->set_count);
+ } else {
+ x->channel[ i * 2 ] = 0;
+ }
+ x->channel[ i * 2 + 1 ] = x->c_fundamental * (float) (i / 2) * cavoc27_randf(.9,1.1);
+ }
+}
+
+t_int *cavoc27_perform(t_int *w)
+{
+ int i,j;
+ float m1,m2;
+ ////////////
+ t_cavoc27 *x = (t_cavoc27 *) (w[1]);
+
+ float *in = (t_float *)(w[2]);
+ float *out = (t_float *)(w[3]);
+ t_int n = w[4];
+
+ int frames_left = x->frames_left;
+ float *input = x->input;
+ float *buffer = x->buffer;
+ int inCount = x->inCount;
+ int R = x->R;
+ int N = x->N;
+ int N2 = x->N2;
+ int D = x->D;
+ int Nw = x->Nw;
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *output = x->output;
+ float *channel = x->channel;
+ float *tmpchannel = x->tmpchannel;
+ float *ichannel = x->ichannel;
+ float mult = x->mult ;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland ;
+ int hold_frames = x->hold_frames;
+ short *rule = x->rule;
+ short left = x->left;
+ short right = x->right;
+ short center = x->center;
+ float *last_frame = x->last_frame;
+ float *c_lastphase_out = x->c_lastphase_out;
+ float *c_lastphase_in = x->c_lastphase_in;
+ float c_fundamental = x->c_fundamental;
+ float c_factor_out = x->c_factor_out;
+ float c_factor_in = x->c_factor_in;
+ short interpolate_flag = x->interpolate_flag;
+
+
+ if( x->mute ){
+ while( n-- ){
+ *out++ = 0.0;
+ }
+ return (w+5);
+ }
+
+ x->inCount += D;
+
+ if( x->capture_flag || x->capture_lock ) {
+
+
+ for ( j = 0 ; j < (Nw - D) ; j++ ){
+ input[j] = input[j+D];
+ }
+ for ( j = (Nw-D), i = 0 ; j < Nw; j++, i++ ) {
+ input[j] = *in++;
+ }
+
+ fold( input, Wanal, Nw, buffer, N, x->inCount );
+ rdft( N, 1, buffer, bitshuffle, trigland );
+ convert( buffer, tmpchannel, N2, c_lastphase_in, c_fundamental, c_factor_in );
+
+ // ONLY COPY PHASES
+ for( i = 1; i < N+2; i += 2 ){
+ channel[i] = tmpchannel[i];
+ // last_frame[i] = channel[i] = tmpchannel[i];
+ }
+
+ if( x->capture_flag ){
+ --(x->capture_flag);
+ }
+ // on final frame - swap in channel (just phases though )
+
+
+ }
+ if( --frames_left <= 0){
+ /* save composite frame for next time (only amps) */
+/* for( i = 0; i < N+1; i++ ){
+ last_frame[i] = channel[i];
+ }*/
+
+ for( i = 0; i < N+1; i += 2 ){
+ last_frame[i] = channel[i];
+ }
+
+ frames_left = hold_frames;
+ for( i = 2; i < N; i+=2 ){
+ left = last_frame[ i - 2 ];
+ center = last_frame[i] ;
+ right = last_frame[i+2];
+ channel[i] = cavoc27_apply_rule(left, right, center, rule );
+ }
+ /* boundary cases */
+ center = last_frame[0];
+ right = last_frame[2];
+ left = last_frame[N];
+ channel[0] = cavoc27_apply_rule(left, right, center, rule );
+
+ center = last_frame[N];
+ right = last_frame[0];
+ left = last_frame[N - 2];
+ channel[N] = cavoc27_apply_rule(left, right, center, rule );
+ }
+ if( interpolate_flag ){
+ m1 = (float) frames_left / (float) hold_frames ;
+ m2 = 1.0 - m1;
+ for( i = 0; i <N+2; i += 2 ){
+ ichannel[i] = m1 * last_frame[i] + m2 * channel[i];
+ ichannel[i+1] = channel[i+1];
+ }
+
+ unconvert( ichannel, buffer, N2, c_lastphase_out, c_fundamental, c_factor_out );
+ } else {
+ unconvert( channel, buffer, N2, c_lastphase_out, c_fundamental, c_factor_out );
+ }
+ rdft( N, -1, buffer, bitshuffle, trigland );
+ overlapadd( buffer, N, Wsyn, output, Nw, inCount);
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+ /* restore state variables */
+ x->inCount = inCount;
+ x->frames_left = frames_left;
+ return (w+5);
+}
+
+int cavoc27_apply_rule( short left, short right, short center, short *rule){
+
+ if( left == 0 && center == 0 && right == 0 )
+ return rule[0];
+ if( left == 1 && center == 0 && right == 1 )
+ return rule[1];
+ if( left == 1 && center == 0 && right == 0 )
+ return rule[2];
+ if( left == 0 && center == 0 && right == 1 )
+ return rule[3];
+ if( left == 2 && center == 0 && right == 2 )
+ return rule[4];
+ if( left == 2 && center == 0 && right == 0 )
+ return rule[5];
+ if( left == 0 && center == 0 && right == 2 )
+ return rule[6];
+ if( left == 2 && center == 0 && right == 1 )
+ return rule[7];
+ if( left == 1 && center == 0 && right == 2 )
+ return rule[8];
+
+ if( left == 0 && center == 1 && right == 0 )
+ return rule[9];
+ if( left == 1 && center == 1 && right == 1 )
+ return rule[10];
+ if( left == 1 && center == 1 && right == 0 )
+ return rule[11];
+ if( left == 0 && center == 1 && right == 1 )
+ return rule[12];
+ if( left == 2 && center == 1 && right == 2 )
+ return rule[13];
+ if( left == 2 && center == 1 && right == 0 )
+ return rule[14];
+ if( left == 0 && center == 1 && right == 2 )
+ return rule[15];
+ if( left == 2 && center == 1 && right == 1 )
+ return rule[16];
+ if( left == 1 && center == 1 && right == 2 )
+ return rule[17];
+
+ if( left == 0 && center == 2 && right == 0 )
+ return rule[18];
+ if( left == 1 && center == 2 && right == 1 )
+ return rule[19];
+ if( left == 1 && center == 2 && right == 0 )
+ return rule[20];
+ if( left == 0 && center == 2 && right == 1 )
+ return rule[21];
+ if( left == 2 && center == 2 && right == 2 )
+ return rule[22];
+ if( left == 2 && center == 2 && right == 0 )
+ return rule[23];
+ if( left == 0 && center == 2 && right == 2 )
+ return rule[24];
+ if( left == 2 && center == 2 && right == 1 )
+ return rule[25];
+ if( left == 1 && center == 2 && right == 2 )
+ return rule[26];
+ return 0; //should never happen
+}
+
+float cavoc27_randf(float min, float max)
+{
+ float randv, retval;
+
+ randv = (float) (rand() % 32768) / 32768.0 ;
+ return (retval = min + (max-min) * randv) ;
+}
+void cavoc27_dsp(t_cavoc27 *x, t_signal **sp, short *count)
+{
+ if(x->vs != sp[0]->s_n || x->R != sp[0]->s_sr) {
+ x->vs = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ cavoc27_init(x,1);
+ }
+ dsp_add(cavoc27_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
diff --git a/cavoc~.c b/cavoc~.c
new file mode 100644
index 0000000..7bfcedc
--- /dev/null
+++ b/cavoc~.c
@@ -0,0 +1,529 @@
+#include "MSPd.h"
+
+#include "fftease.h"
+
+#if MSP
+void *cavoc_class;
+#endif
+
+#if PD
+static t_class *cavoc_class;
+#endif
+
+#define OBJECT_NAME "cavoc~"
+
+typedef struct _cavoc
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int in_count;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ float *buffer;
+ float *channel;
+ float *output;
+
+ float frame_duration;
+ int max_bin;
+
+ float fundamental;
+ float *last_frame;
+ short left;
+ short right;
+ short center;
+ short *rule;
+ float density;
+ float start_breakpoint;
+ int hold_frames;
+ int frames_left;
+ int set_count;
+ // FFT
+ float *c_lastphase_out;
+ float c_fundamental;
+ float c_factor_out;
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ //
+ void *list_outlet;
+ t_atom *list_data;
+ short mute;
+ int overlap;
+ int winfac;
+ short external_trigger;
+ float hold_time;
+} t_cavoc;
+
+void *cavoc_new(t_symbol *msg, short argc, t_atom *argv);
+t_int *offset_perform(t_int *w);
+t_int *cavoc_perform(t_int *w);
+void cavoc_dsp(t_cavoc *x, t_signal **sp, short *count);
+void cavoc_assist(t_cavoc *x, void *b, long m, long a, char *s);
+void cavoc_free( t_cavoc *x );
+int cavoc_apply_rule( short left, short right, short center, short *rule);
+float cavoc_randf(float min, float max);
+void cavoc_rule (t_cavoc *x, t_symbol *msg, short argc, t_atom *argv);
+void cavoc_density (t_cavoc *x, t_floatarg density);
+void cavoc_hold_time (t_cavoc *x, t_floatarg hold_time);
+void cavoc_retune (t_cavoc *x, t_floatarg min, t_floatarg max);
+void cavoc_mute (t_cavoc *x, t_floatarg toggle);
+void cavoc_external_trigger(t_cavoc *x, t_floatarg toggle);
+void cavoc_init(t_cavoc *x,short initialized);
+void cavoc_overlap(t_cavoc *x, t_floatarg f);
+void cavoc_winfac(t_cavoc *x, t_floatarg f);
+void cavoc_fftinfo(t_cavoc *x);
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&cavoc_class, (method)cavoc_new, (method)cavoc_free,
+ (short)sizeof(t_cavoc), 0, A_GIMME, 0);
+ addmess((method)cavoc_dsp, "dsp", A_CANT, 0);
+ addmess((method)cavoc_assist,"assist",A_CANT,0);
+ addmess((method)cavoc_rule,"rule",A_GIMME,0);
+ addmess((method)cavoc_density,"density",A_FLOAT,0);
+ addmess((method)cavoc_hold_time,"hold_time",A_FLOAT,0);
+ addmess((method)cavoc_mute,"mute",A_FLOAT,0);
+ addmess((method)cavoc_external_trigger,"external_trigger",A_FLOAT,0);
+ addmess((method)cavoc_retune,"retune",A_FLOAT,A_FLOAT,0);
+ addmess((method)cavoc_overlap,"overlap",A_FLOAT,0);
+ addmess((method)cavoc_winfac,"winfac",A_FLOAT,0);
+ addmess((method)cavoc_fftinfo,"fftinfo",0);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+#if PD
+void cavoc_tilde_setup(void){
+ cavoc_class = class_new(gensym("cavoc~"), (t_newmethod)cavoc_new,
+ (t_method)cavoc_free ,sizeof(t_cavoc), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(cavoc_class, t_cavoc, x_f);
+ class_addmethod(cavoc_class,(t_method)cavoc_dsp,gensym("dsp"),0);
+ class_addmethod(cavoc_class,(t_method)cavoc_mute,gensym("mute"),A_FLOAT,0);
+ class_addmethod(cavoc_class,(t_method)cavoc_overlap,gensym("overlap"),A_FLOAT,0);
+ class_addmethod(cavoc_class,(t_method)cavoc_winfac,gensym("winfac"),A_FLOAT,0);
+ class_addmethod(cavoc_class,(t_method)cavoc_rule,gensym("rule"),A_GIMME,0);
+ class_addmethod(cavoc_class,(t_method)cavoc_density,gensym("density"),A_FLOAT,0);
+ class_addmethod(cavoc_class,(t_method)cavoc_hold_time,gensym("hold_time"),A_FLOAT,0);
+ class_addmethod(cavoc_class,(t_method)cavoc_external_trigger,gensym("external_trigger"),A_FLOAT,0);
+ class_addmethod(cavoc_class,(t_method)cavoc_retune,gensym("retune"),A_FLOAT,A_FLOAT,0);
+ class_addmethod(cavoc_class,(t_method)cavoc_winfac,gensym("winfac"),A_FLOAT,0);
+ class_addmethod(cavoc_class,(t_method)cavoc_overlap,gensym("overlap"),A_FLOAT,0);
+ class_addmethod(cavoc_class,(t_method)cavoc_fftinfo,gensym("fftinfo"),0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+void cavoc_fftinfo( t_cavoc *x )
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+void cavoc_overlap(t_cavoc *x, t_floatarg f)
+{
+ if(!power_of_two(f)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->overlap = (int)f;
+ cavoc_init(x,1);
+}
+
+void cavoc_winfac(t_cavoc *x, t_floatarg f)
+{
+ if(!power_of_two(f)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = (int)f;
+ cavoc_init(x,1);
+}
+
+void cavoc_external_trigger(t_cavoc *x, t_floatarg toggle)
+{
+ x->external_trigger = toggle;
+}
+
+void cavoc_mute (t_cavoc *x, t_floatarg toggle)
+{
+ x->mute = toggle;
+}
+
+void cavoc_retune(t_cavoc *x, t_floatarg min, t_floatarg max)
+{
+ int i;
+
+ if( max <= 0 || min <= 0 || min > max ){
+ error("bad values for min and max multipliers");
+ return;
+ }
+ if( min < .1 )
+ min = 0.1;
+ if( max > 2.0 )
+ max = 2.0;
+ for( i = 0; i < x->N2 + 1; i++ ){
+ x->channel[ i * 2 + 1 ] = x->c_fundamental * (float) (i / 2) * cavoc_randf(min, max);
+ }
+
+}
+
+void cavoc_density(t_cavoc *x, t_floatarg density)
+{
+ int i;
+ if( density < 0.0001 ){
+ density = .0001;
+ } else if( density > .9999 ){
+ density = 1.0;
+ }
+ x->density = density;
+ x->start_breakpoint = 1.0 - x->density;
+ for( i = 0; i < x->N2 + 1; i++ ){
+ if( cavoc_randf(0.0, 1.0) > x->start_breakpoint ){
+ x->channel[ i * 2 ] = 1;
+ ++(x->set_count);
+ } else {
+ x->channel[ i * 2 ] = 0;
+ }
+ }
+ for( i = 0; i < x->N+2; i++ ){
+ x->last_frame[i] = x->channel[i];
+ }
+}
+
+void cavoc_hold_time(t_cavoc *x, t_floatarg f)
+{
+
+ if(f <= 0){
+ error("negative or zero hold time.");
+ return;
+ }
+ x->hold_time = f;
+ x->hold_frames = (int) ((x->hold_time/1000.0) / x->frame_duration);
+ if( x->hold_frames < 1 )
+ x->hold_frames = 1;
+ x->frames_left = x->hold_frames;
+
+}
+
+void cavoc_rule (t_cavoc *x, t_symbol *msg, short argc, t_atom *argv)
+{
+ int i;
+ short *rule = x->rule;
+ if( argc != 8 ){
+ error("the rule must be size 8");
+ return;
+ }
+
+ for( i = 0; i < 8; i++ ){
+ rule[i] = (short) atom_getfloatarg(i, argc, argv);
+// post("%d",rule[i]);
+ }
+}
+
+void cavoc_free( t_cavoc *x ){
+#if MSP
+ dsp_free((t_pxobject *) x);
+#endif
+ free(x->trigland);
+ free(x->bitshuffle);
+ free(x->Wanal);
+ free(x->Wsyn);
+ free(x->input);
+ free(x->Hwin);
+ free(x->buffer);
+ free(x->channel);
+ free(x->last_frame);
+ free(x->output);
+ free(x->c_lastphase_out);
+ free(x->rule);
+}
+
+void cavoc_assist (t_cavoc *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0: sprintf(dst,"(signal) Trigger");break;
+ }
+ } else if (msg==2) {
+ switch (arg) {
+ case 0:sprintf(dst,"(signal) Output"); break;
+ }
+ }
+}
+
+void *cavoc_new(t_symbol *msg, short argc, t_atom *argv)
+{
+#if MSP
+ t_cavoc *x = (t_cavoc *)newobject(cavoc_class);
+ dsp_setup((t_pxobject *)x,1);
+ outlet_new((t_pxobject *)x, "signal");
+ #endif
+
+#if PD
+ t_cavoc *x = (t_cavoc *)pd_new(cavoc_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+ x->D = sys_getblksize();
+ x->R = sys_getsr();
+
+ x->density = atom_getfloatarg(0,argc,argv);
+ x->hold_time = atom_getintarg(1,argc,argv);
+ x->overlap = atom_getintarg(2,argc,argv);
+ x->winfac = atom_getintarg(3,argc,argv);
+
+
+ cavoc_init(x,0);
+ return (x);
+}
+
+void cavoc_init(t_cavoc *x,short initialized)
+{
+int i;
+
+ if(!x->D)
+ x->D = 256;
+ if(!x->R)
+ x->R = 44100;
+ if(!power_of_two(x->overlap))
+ x->overlap = 4;
+ if(!power_of_two(x->winfac))
+ x->winfac = 1;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->mult = 1. / (float) x->N;
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->in_count = -(x->Nw);
+ x->c_fundamental = (float) x->R/(float)((x->N2)<<1);
+ x->frame_duration = (float)x->D/(float) x->R;
+ if(x->hold_time <= 100) /* in milliseconds */
+ x->hold_time = 100;
+
+
+ cavoc_hold_time(x, x->hold_time);
+
+ if(!initialized){
+
+ srand(time(0));
+ x->mute = 0;
+ x->set_count = 0;
+ x->external_trigger = 0;
+ if( x->density < 0.0 ){
+ x->density = 0;
+ } else if( x->density > 1.0 ){
+ x->density = 1.0;
+ }
+ x->start_breakpoint = 1.0 - x->density;
+
+ x->Wanal = (float *) calloc( MAX_Nw, sizeof(float) );
+ x->Wsyn = (float *) calloc( MAX_Nw, sizeof(float) );
+ x->input = (float *) calloc( MAX_Nw, sizeof(float) );
+ x->Hwin = (float *) calloc( MAX_Nw, sizeof(float) );
+ x->buffer = (float *) calloc( MAX_N, sizeof(float) );
+ x->channel = (float *) calloc( MAX_N+2, sizeof(float) );
+ x->last_frame = (float *) calloc(MAX_N+2, sizeof(float));
+ x->output = (float *) calloc( MAX_Nw, sizeof(float) );
+ x->bitshuffle = (int *) calloc( MAX_N * 2, sizeof( int ) );
+ x->trigland = (float *) calloc( MAX_N * 2, sizeof( float ) );
+ x->c_lastphase_out = (float *) calloc( MAX_N2+1, sizeof(float) );
+
+ x->c_factor_out = TWOPI * (float) x->D / (float) x->R;
+ x->rule = (short *) calloc(8, sizeof(short));
+
+ x->rule[2] = x->rule[3] = x->rule[5] = x->rule[6] = 1;
+ x->rule[0] = x->rule[1] = x->rule[4] = x->rule[7] = 0;
+
+ }
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ memset((char *)x->buffer,0,x->N * sizeof(float));
+ memset((char *)x->c_lastphase_out,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->last_frame,0,(x->N+2) * sizeof(float));
+
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makehanning( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 0);
+
+ for(i = 0; i < x->N2 + 1; i++){
+ if(cavoc_randf(0.0, 1.0) > x->start_breakpoint){
+ x->channel[ i * 2 ] = 1;
+ ++(x->set_count);
+ } else {
+ x->channel[i * 2] = 0;
+ }
+ x->channel[i * 2 + 1] = x->c_fundamental * (float) (i / 2) * cavoc_randf(.9,1.1);
+ }
+
+// post("turned on %d of a possible %d bins", x->set_count, x->N2+1 );
+
+ for( i = 0; i < x->N+2; i++ ){
+ x->last_frame[i] = x->channel[i];
+ }
+// post("cavoc~ FFT size: %d",x->N);
+}
+
+t_int *cavoc_perform(t_int *w)
+{
+ int i,j;
+ float oldfrac,newfrac;
+ t_cavoc *x = (t_cavoc *)(w[1]);
+ float *trigger_vec = (t_float *)(w[2]);
+ float *out = (t_float *)(w[3]);
+ t_int n = w[4];
+
+ int frames_left = x->frames_left;
+ float *input = x->input;
+ float *buffer = x->buffer;
+ int in_count = x->in_count;
+ int R = x->R;
+ int N = x->N;
+ int N2 = x->N2;
+ int D = x->D;
+ int Nw = x->Nw;
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *output = x->output;
+ float *channel = x->channel;
+ float mult = x->mult ;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland ;
+ int hold_frames = x->hold_frames;
+ short *rule = x->rule;
+ short left = x->left;
+ short right = x->right;
+ short center = x->center;
+ float *last_frame = x->last_frame;
+ float *c_lastphase_out = x->c_lastphase_out;
+ float c_fundamental = x->c_fundamental;
+ float c_factor_out = x->c_factor_out;
+ short external_trigger = x->external_trigger;
+ short new_event = 0;
+
+ in_count += D;
+
+ if( x->mute ){
+ while( n-- ){
+ *out++ = 0.0;
+ }
+ return (w+5);
+ }
+ if(external_trigger){// only accurate to within a vector because of FFT
+ for(i=0;i<n;i++){
+ if(trigger_vec[i]){
+ new_event = 1;
+ break;
+ }
+ }
+ } else if(!--frames_left){
+ frames_left = hold_frames;
+ new_event = 1;
+ }
+
+ if(new_event){
+ for( i = 2; i < N; i+=2 ){
+ left = last_frame[ i - 2];
+ center = last_frame[i] ;
+ right = last_frame[i+2];
+ channel[i] = cavoc_apply_rule(left, right, center, rule );
+ }
+ /* boundary cases */
+ center = last_frame[0];
+ right = last_frame[2];
+ left = last_frame[N];
+ channel[0] = cavoc_apply_rule(left, right, center, rule );
+
+ center = last_frame[N];
+ right = last_frame[0];
+ left = last_frame[N - 2];
+ channel[N] = cavoc_apply_rule(left, right, center, rule );
+
+
+ /* save composite frame for next time */
+ for( i = 0; i < N+1; i++ ){
+ last_frame[i] = channel[i];
+ }
+ }
+ unconvert( channel, buffer, N2, c_lastphase_out, c_fundamental, c_factor_out );
+ rdft( N, -1, buffer, bitshuffle, trigland );
+ overlapadd( buffer, N, Wsyn, output, Nw, in_count);
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+ /* restore state variables */
+ x->in_count = in_count % Nw;
+ x->frames_left = frames_left;
+ return (w+5);
+}
+
+int cavoc_apply_rule(short left, short right, short center, short *rule){
+
+ if( ! center ){
+ if( ! left && ! right){
+ return rule[0];
+ } else if ( ! left && right ){
+ return rule[1];
+ } else if ( left && ! right ) {
+ return rule[2];
+ } else if (left && right) {
+ return rule[3];
+ }
+ } else {
+ if( ! left && ! right){
+ return rule[4];
+ } else if ( ! left && right ){
+ return rule[5];
+ } else if ( left && ! right ) {
+ return rule[6];
+ } else if (left && right) {
+ return rule[7];
+ }
+ }
+ return 0;// never happens
+}
+
+float cavoc_randf(float min, float max)
+{
+ float randv;
+
+ randv = (float) (rand() % 32768) / 32768.0 ;
+
+ return (min + ((max-min) * randv)) ;
+}
+void cavoc_dsp(t_cavoc *x, t_signal **sp, short *count)
+{
+ if(sp[0]->s_n != x->D || x->R != sp[0]->s_sr){
+ x->D = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ cavoc_init(x,1);
+ }
+
+ dsp_add(cavoc_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
diff --git a/centerring~.c b/centerring~.c
new file mode 100644
index 0000000..31e9483
--- /dev/null
+++ b/centerring~.c
@@ -0,0 +1,599 @@
+#include "MSPd.h"
+#include "fftease.h"
+#include "PenroseOscil.h"
+#include "PenroseRand.h"
+
+#define OBJECT_NAME "centerring~"
+#define MAX_WARP 16.0
+
+#if MSP
+ void *centerring_class;
+#endif
+#if PD
+ static t_class *centerring_class;
+#endif
+
+#define OBJECT_NAME "centerring~"
+
+typedef struct _centerring
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ int bufferLength;
+ int recalc;
+ int seed;
+ int *bitshuffle;
+
+ float baseFreq;
+ float constFreq;
+ float bandFreq;
+ float frameR;
+ float *ringPhases;
+ float *ringIncrements;
+ float *sineBuffer;
+ float *Wanal;
+ float *Wsyn;
+ float *inputOne;
+ float *Hwin;
+ float *bufferOne;
+ float *channelOne;
+ float *newChannel;
+ float *newAmplitudes;
+ float *output;
+ float mult;
+ float *trigland;
+
+ short connected[8];
+ short mute;
+ int overlap;//overlap factor
+ int winfac;//window factor
+ int vs;//vector size
+} t_centerring;
+
+
+/* msp function prototypes */
+
+void *centerring_new(t_symbol *s, int argc, t_atom *argv);
+t_int *centerring_perform(t_int *w);
+void centerring_dsp(t_centerring *x, t_signal **sp, short *count);
+void centerring_float(t_centerring *x, double myFloat);
+void centerring_assist(t_centerring *x, void *b, long m, long a, char *s);
+void centerring_dest(t_centerring *x, double f);
+void centerring_messages(t_centerring *x, t_symbol *s, short argc, t_atom *argv);
+void centerring_adjust( t_centerring *x );
+void centerring_zerophases( t_centerring *x );
+void centerring_randphases( t_centerring *x );
+void centerring_free(t_centerring *x);
+void centerring_init(t_centerring *x, short initialized);
+void centerring_mute(t_centerring *x, t_floatarg toggle);
+void centerring_overlap(t_centerring *x, t_floatarg o);
+void centerring_fftinfo( t_centerring *x );
+void centerring_winfac(t_centerring *x, t_floatarg f);
+
+
+/* float input handling routine for shape width (MSP only) */
+#if MSP
+void centerring_float( t_centerring *x, t_floatarg df )
+{
+float myFloat = (float) df;
+int inlet = x->x_obj.z_in;
+
+ if ( inlet == 1 ) {
+ x->baseFreq = myFloat;
+ x->recalc = 1;
+ }
+ if ( inlet == 2 ) {
+ x->bandFreq = myFloat;
+ x->recalc = 1;
+ }
+ if ( inlet == 3 ) {
+ x->constFreq = myFloat;
+ x->recalc = 1;
+ }
+}
+
+
+void main(void)
+{
+ setup( (struct messlist **) &centerring_class, (method) centerring_new,
+ (method) centerring_free, (short) sizeof(t_centerring), 0,A_GIMME, 0);
+
+ addmess((method)centerring_dsp, "dsp", A_CANT, 0);
+ addmess((method)centerring_assist,"assist",A_CANT,0);
+ addmess((method)centerring_messages,"seed", A_GIMME, 0);
+ addmess((method)centerring_messages,"zerophases", A_GIMME, 0);
+ addmess((method)centerring_messages,"randphases", A_GIMME, 0);
+ addmess((method)centerring_mute,"mute", A_FLOAT, 0);
+ addmess((method)centerring_overlap,"overlap", A_FLOAT, 0);
+ addmess((method)centerring_winfac,"winfac", A_FLOAT, 0);
+ addmess((method)centerring_fftinfo,"fftinfo", 0);
+ addfloat((method)centerring_float);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+#if PD
+void centerring_tilde_setup(void)
+{
+ centerring_class = class_new(gensym("centerring~"), (t_newmethod)centerring_new,
+ (t_method)centerring_free ,sizeof(t_centerring), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(centerring_class, t_centerring, x_f);
+ class_addmethod(centerring_class, (t_method)centerring_dsp, gensym("dsp"), 0);
+ class_addmethod(centerring_class, (t_method)centerring_assist, gensym("assist"), 0);
+ class_addmethod(centerring_class, (t_method)centerring_messages, gensym("seed"), A_GIMME,0);
+ class_addmethod(centerring_class, (t_method)centerring_messages, gensym("zerophases"), A_GIMME,0);
+ class_addmethod(centerring_class, (t_method)centerring_messages, gensym("randphases"), A_GIMME,0);
+ class_addmethod(centerring_class, (t_method)centerring_overlap, gensym("overlap"), A_FLOAT,0);
+ class_addmethod(centerring_class, (t_method)centerring_winfac, gensym("winfac"), A_FLOAT,0);
+ class_addmethod(centerring_class, (t_method)centerring_mute, gensym("mute"), A_FLOAT,0);
+ class_addmethod(centerring_class, (t_method)centerring_fftinfo, gensym("fftinfo"),0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+void centerring_messages(t_centerring *x, t_symbol *s, short argc, t_atom *argv)
+{
+
+ if (s == gensym("seed"))
+ x->seed = (int) atom_getfloatarg(0,argc,argv);
+
+ if (s == gensym("zerophases"))
+ centerring_zerophases( x );
+
+ if (s == gensym("randphases"))
+ centerring_randphases( x );
+}
+
+
+
+/* diagnostic messages for Max */
+
+void centerring_assist (t_centerring *x, void *b, long msg, long arg, char *dst)
+{
+
+ if (msg == 1) {
+
+ switch (arg) {
+
+ case 0: sprintf(dst,"(signal) Input");
+ break;
+
+ case 1: sprintf(dst,"(signal/float) Base Modulation Frequency");
+ break;
+
+ case 2: sprintf(dst,"(signal/float) Frequency Deviation Bandwidth");
+ break;
+
+ case 3: sprintf(dst,"(signal/float) Frequency Deviation Constant");
+ break;
+ }
+ }
+
+ else {
+
+ if (msg == 2)
+ sprintf(dst,"(signal) Output");
+
+ }
+}
+
+
+void *centerring_new(t_symbol *s, int argc, t_atom *argv)
+{
+#if MSP
+ t_centerring *x = (t_centerring *) newobject(centerring_class);
+ dsp_setup((t_pxobject *)x, 4);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+#if PD
+ t_centerring *x = (t_centerring *)pd_new(centerring_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+
+ /* optional arguments: baseFreq, bandFreq, constFreq, seed, overlap, winfac */
+ x->overlap = x->winfac = 0;
+ x->baseFreq = atom_getfloatarg(0,argc,argv);
+ x->bandFreq = atom_getfloatarg(1,argc,argv);
+ x->constFreq = atom_getfloatarg(2,argc,argv);
+ x->seed = atom_getfloatarg(3,argc,argv);
+ x->overlap = atom_getfloatarg(4,argc,argv);
+ x->winfac = atom_getfloatarg(5,argc,argv);
+
+ if(!power_of_two(x->overlap)){
+ x->overlap = 4;
+ }
+ if(!power_of_two(x->winfac)){
+ x->winfac = 1;
+ }
+
+if(x->baseFreq <= 0.0)
+ x->baseFreq = 1.;
+if(x->bandFreq <= 0.0)
+ x->bandFreq = .2;
+if(x->constFreq <= 0)
+ x->constFreq = 1.;
+
+ x->vs = sys_getblksize();
+ x->R = sys_getsr();
+
+ centerring_init(x,0);
+ return(x);
+}
+
+void centerring_init(t_centerring *x, short initialized)
+{
+ int i;
+
+ x->D = x->vs;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+ x->frameR = (float) x->R / (float) x->D;
+
+ if(!initialized){
+ x->mute = 0;
+ x->bufferLength = 131072;
+ x->recalc = 0;
+ x->Wanal = (float *) calloc(MAX_Nw, sizeof(float));
+ x->Wsyn = (float *) calloc(MAX_Nw, sizeof(float));
+ x->Hwin = (float *) calloc(MAX_Nw, sizeof(float));
+ x->inputOne = (float *) calloc(MAX_Nw, sizeof(float));
+ x->bufferOne = (float *) calloc(MAX_N, sizeof(float));
+ x->channelOne = (float *) calloc((MAX_N+2), sizeof(float));
+ x->newChannel = (float *) calloc(MAX_N+2, sizeof(float));
+ x->newAmplitudes = (float *) calloc(((MAX_N2 + 1) * 16), sizeof(float) );
+ x->ringPhases = (float *) calloc((MAX_N2 + 1), sizeof(float));
+ x->ringIncrements = (float *) calloc((MAX_N2 + 1), sizeof(float));
+ x->sineBuffer = (float *) calloc((x->bufferLength + 1), sizeof(float));
+ x->output = (float *) calloc(MAX_Nw, sizeof(float));
+ x->bitshuffle = (int *) calloc(MAX_N * 2, sizeof(int));
+ x->trigland = (float *) calloc(MAX_N * 2, sizeof(float));
+ }
+ memset((char *)x->inputOne,0,x->Nw);
+ memset((char *)x->output,0,x->Nw);
+ memset((char *)x->bufferOne,0,x->N);
+ memset((char *)x->channelOne,0,x->N+2);
+ memset((char *)x->newChannel,0,x->N+2);
+ memset((char *)x->ringPhases,0,(x->N2+1));
+ memset((char *)x->ringIncrements,0,(x->N2+1));
+ memset((char *)x->newAmplitudes,0,(x->N2+1));
+
+ init_rdft(x->N, x->bitshuffle, x->trigland);
+ makehanning( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 0);
+ makeSineBuffer(x->sineBuffer, x->bufferLength);
+ centerring_adjust(x);
+ centerring_zerophases(x);
+}
+
+void centerring_free(t_centerring *x)
+{
+#if MSP
+ dsp_free((t_pxobject *) x);
+#endif
+ free(x->trigland);
+ free(x->bitshuffle);
+ free(x->Wanal);
+ free(x->Wsyn);
+ free(x->Hwin);
+ free(x->inputOne);
+ free(x->bufferOne);
+ free(x->channelOne);
+ free(x->output);
+ free(x->newChannel);
+ free(x->newAmplitudes);
+ free(x->ringPhases);
+ free(x->ringIncrements);
+ free(x->sineBuffer);
+}
+
+void centerring_adjust( t_centerring *x ) {
+
+ int i;
+
+ float *ringIncrements = x->ringIncrements,
+ *ringPhases = x->ringPhases;
+
+/* initialize oscillator increments and phases */
+
+ for (i=0; i < x->N2; i++) {
+
+ *(ringIncrements+i) = frequencyToIncrement( x->frameR,
+ x->baseFreq *
+ ( (rrand(&(x->seed)) * x->bandFreq) + x->constFreq ),
+ x->bufferLength );
+ }
+}
+
+
+void centerring_zerophases( t_centerring *x ) {
+
+ int i;
+
+ for (i=0; i < x->N2; i++)
+ *((x->ringPhases)+i) = 0.;
+}
+
+
+void centerring_randphases( t_centerring *x ) {
+
+ int i;
+
+ for (i=0; i < x->N2; i++)
+ *((x->ringPhases)+i) = prand(&(x->seed)) * (float) (x->bufferLength);
+
+}
+
+
+
+t_int *centerring_perform(t_int *w)
+{
+
+ int
+ i,j,
+ bindex,
+ inCount,
+ R,
+ N,
+ N2,
+ D,
+ Nw,
+ newLength,
+ bufferLength,
+ even, odd,
+ *bitshuffle;
+
+ float mult,
+ bandFreq,
+ constFreq,
+ baseFreq,
+ a1, b1,
+ interpIncr,
+ interpPhase,
+ *inputOne,
+ *inputTwo,
+ *bufferOne,
+ *bufferTwo,
+ *output,
+ *Wanal,
+ *Wsyn,
+ *ringPhases,
+ *ringIncrements,
+ *sineBuffer,
+ *channelOne,
+ *newChannel,
+ *newAmplitudes,
+ *trigland;
+
+
+ t_centerring *x = (t_centerring *) (w[1]);
+ t_float *inOne = (t_float *) (w[2]);
+ t_float *vec_baseFreq = (t_float *) (w[3]);
+ t_float *vec_bandFreq = (t_float *) (w[4]);
+ t_float *vec_constFreq = (t_float *) (w[5]);
+ t_float *out = (t_float *)(w[6]);
+ t_int n = (int) (w[7]);
+ short *connected = x->connected;
+
+ if(connected[1]){
+ x->recalc = 1;
+ x->baseFreq = *vec_baseFreq;
+ }
+ if(connected[2]){
+ x->recalc = 1;
+ x->bandFreq = *vec_bandFreq;
+ }
+ if(connected[3]){
+ x->recalc = 1;
+ x->constFreq = *vec_constFreq;
+ }
+
+ if(x->mute){
+ while(n--)
+ *out++ = 0.0;
+ return (w+8);
+ }
+
+/* dereference structure */
+
+ inputOne = x->inputOne;
+ bufferOne = x->bufferOne;
+ inCount = x->inCount;
+ R = x->R;
+ N = x->N;
+ N2 = x->N2;
+ D = x->D;
+ Nw = x->Nw;
+ Wanal = x->Wanal;
+ Wsyn = x->Wsyn;
+ output = x->output;
+ channelOne = x->channelOne;
+ newChannel = x->newChannel;
+ newAmplitudes = x->newAmplitudes;
+ bitshuffle = x->bitshuffle;
+ trigland = x->trigland;
+ mult = x->mult;
+
+ bufferLength = x->bufferLength;
+
+ ringPhases = x->ringPhases;
+ ringIncrements = x->ringIncrements;
+ sineBuffer = x->sineBuffer;
+
+ /* recalculate our oscillator values if object inputs have been updated */
+
+ if (x->recalc)
+ centerring_adjust( x );
+
+ x->recalc = 0;
+
+/* fill our retaining buffers */
+
+ inCount += D;
+
+ for ( j = 0 ; j < Nw - D ; j++ )
+ inputOne[j] = inputOne[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ inputOne[j] = *inOne++;
+
+/* apply hamming window and fold our window buffer into the fft buffer */
+
+ fold( inputOne, Wanal, Nw, bufferOne, N, inCount );
+
+/* do an fft */
+
+ rdft( N, 1, bufferOne, bitshuffle, trigland );
+
+/* convert to polar coordinates from complex values */
+
+ for ( i = 0; i <= N2; i++ ) {
+ odd = ( even = i<<1 ) + 1;
+
+ a1 = ( i == N2 ? *(bufferOne+1) : *(bufferOne+even) );
+ b1 = ( i == 0 || i == N2 ? 0. : *(bufferOne+odd) );
+
+/* replace signal one's phases with those of signal two */
+
+ *(channelOne+even) = hypot( a1, b1 );
+ *(channelOne+odd) = -atan2( b1, a1 );
+ }
+
+
+/* perform ring modulation on successive fft frames */
+
+ for (i=0; i < N2; i++) {
+ even = i<<1;
+
+ *(channelOne+even) *= bufferOscil( ringPhases+i,
+ *(ringIncrements+i), sineBuffer, bufferLength );
+ }
+
+/* convert from polar to cartesian */
+
+ for ( i = 0; i <= N2; i++ ) {
+
+ odd = ( even = i<<1 ) + 1;
+
+ *(bufferOne+even) = *(channelOne+even) * cos( *(channelOne+odd) );
+
+ if ( i != N2 )
+ *(bufferOne+odd) = (*(channelOne+even)) * -sin( *(channelOne+odd) );
+ }
+
+
+/* do an inverse fft */
+
+ rdft( N, -1, bufferOne, bitshuffle, trigland );
+
+/* dewindow our result */
+
+ overlapadd( bufferOne, N, Wsyn, output, Nw, inCount);
+
+/* set our output and adjust our retaining output buffer */
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+
+/* restore state variables */
+
+ x->inCount = inCount % Nw;
+ return (w+8);
+}
+
+
+
+void centerring_mute(t_centerring *x, t_floatarg toggle)
+{
+ x->mute = (short)toggle;
+}
+
+void centerring_overlap(t_centerring *x, t_floatarg o)
+{
+ if(!power_of_two((int)o)){
+ error("%f is not a power of two",o);
+ return;
+ }
+ x->overlap = (int)o;
+ centerring_init(x,1);
+}
+
+void centerring_winfac(t_centerring *x, t_floatarg f)
+{
+ if(!power_of_two((int)f)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = (int)f;
+ centerring_init(x,1);
+}
+
+void centerring_fftinfo( t_centerring *x )
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+
+void centerring_dsp(t_centerring *x, t_signal **sp, short *count)
+{
+ int i;
+
+ #if MSP
+ for( i = 0; i < 4; i++ ){
+ x->connected[i] = count[i];
+ }
+ #endif
+
+ #if PD
+ for( i = 0; i < 4; i++ ){
+ x->connected[i] = 1;
+ }
+ #endif
+
+ if(x->vs != sp[0]->s_n || x->R != sp[0]->s_sr){
+ x->vs = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ centerring_init(x,1);
+ }
+
+ dsp_add(centerring_perform, 7, x,
+ sp[0]->s_vec,
+ sp[1]->s_vec,
+ sp[2]->s_vec,
+ sp[3]->s_vec,
+ sp[4]->s_vec,
+ sp[0]->s_n);
+}
+
diff --git a/codepend~.c b/codepend~.c
new file mode 100644
index 0000000..cdc29ff
--- /dev/null
+++ b/codepend~.c
@@ -0,0 +1,607 @@
+#include "MSPd.h"
+
+#include "fftease.h"
+
+#if MSP
+void *codepend_class;
+#endif
+#if PD
+static t_class *codepend_class;
+#endif
+
+#define OBJECT_NAME "codepend~"
+
+
+/*
+ Adding -32dB pad for invert option. Also added latency mechanism in
+ switching from normal to "invert" to avoid glitches from extreme
+ amplitude disparities.
+
+ Made all inlets of type signal (with float options).
+
+ Threshold input is now linear, not dB (with Max doing the conversion
+ if desired).
+
+ -EL 10/1/2005
+
+*/
+
+typedef struct _codepend
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ int invert;
+ int *bitshuffle;
+
+ float threshold;
+ float exponent;
+ float *Wanal;
+ float *Wsyn;
+ float *inputOne;
+ float *inputTwo;
+ float *Hwin;
+ float *bufferOne;
+ float *bufferTwo;
+ float *channelOne;
+ float *channelTwo;
+ float *output;
+ float mult;
+ float *trigland;
+
+ short connected[8];
+ short mute;
+ int overlap;//overlap factor
+ int winfac;//window factor
+ int vs;//vector size
+ int invert_countdown; // delay onset of invert effect to avoid loud glitches
+ int invert_nextstate;// next state for invert
+ float invert_pad;
+} t_codepend;
+
+
+/* msp function prototypes */
+
+void *codepend_new(t_symbol *s, int argc, t_atom *argv);
+t_int *offset_perform(t_int *w);
+t_int *codepend_perform(t_int *w);
+void codepend_dsp(t_codepend *x, t_signal **sp, short *count);
+void codepend_assist(t_codepend *x, void *b, long m, long a, char *s);
+void codepend_dest(t_codepend *x, double f);
+void codepend_invert(t_codepend *x, t_floatarg toggle);
+void codepend_free(t_codepend *x);
+void codepend_mute(t_codepend *x, t_floatarg toggle);
+void codepend_fftinfo(t_codepend *x);
+void codepend_tilde_setup(void);
+void codepend_winfac(t_codepend *x, t_floatarg o);
+void codepend_overlap(t_codepend *x, t_floatarg o);
+void codepend_init(t_codepend *x, short initialized);
+void codepend_pad(t_codepend *x, t_floatarg pad);
+
+
+#if MSP
+void main(void)
+{
+ setup( (struct messlist **) &codepend_class, (void *) codepend_new,
+ (method)dsp_free, (short) sizeof(t_codepend),
+ 0, A_GIMME, 0);
+
+ addmess((method)codepend_dsp, "dsp", A_CANT, 0);
+ addmess((method)codepend_assist,"assist",A_CANT,0);
+ addmess((method)codepend_invert,"invert", A_FLOAT, 0);
+
+ addmess((method)codepend_mute,"mute", A_FLOAT, 0);
+ addmess((method)codepend_pad,"pad", A_FLOAT, 0);
+ addmess((method)codepend_overlap,"overlap", A_FLOAT, 0);
+ addmess((method)codepend_winfac,"winfac", A_FLOAT, 0);
+ addmess((method)codepend_fftinfo,"fftinfo", 0);
+ addfloat((method) codepend_dest);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+
+/* float input handling routine (MSP only)*/
+void codepend_dest(t_codepend *x, double df)
+{
+float f = (float) df;
+int inlet = x->x_obj.z_in;
+
+ if ( inlet == 2 ) {
+ x->exponent = f;
+ }
+
+ if ( inlet == 3 ){
+ /* x->threshold = (float) (pow( 10., (f * .05))); */
+ x->threshold = f;
+ }
+}
+#endif
+
+#if PD
+void codepend_tilde_setup(void)
+{
+ codepend_class = class_new(gensym("codepend~"), (t_newmethod)codepend_new,
+ (t_method)codepend_free ,sizeof(t_codepend), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(codepend_class, t_codepend, x_f);
+ class_addmethod(codepend_class, (t_method)codepend_dsp, gensym("dsp"), 0);
+ class_addmethod(codepend_class, (t_method)codepend_assist, gensym("assist"), 0);
+ class_addmethod(codepend_class, (t_method)codepend_invert, gensym("invert"), A_FLOAT,0);
+
+ class_addmethod(codepend_class, (t_method)codepend_mute, gensym("mute"), A_FLOAT,0);
+ class_addmethod(codepend_class, (t_method)codepend_pad, gensym("pad"), A_FLOAT,0);
+ class_addmethod(codepend_class, (t_method)codepend_overlap, gensym("overlap"), A_FLOAT,0);
+ class_addmethod(codepend_class, (t_method)codepend_winfac, gensym("winfac"), A_FLOAT,0);
+ class_addmethod(codepend_class, (t_method)codepend_fftinfo, gensym("fftinfo"), A_CANT,0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+
+void codepend_mute(t_codepend *x, t_floatarg toggle)
+{
+ x->mute = (short)toggle;
+// post("mute set to %f, %d",toggle,x->mute);
+}
+
+void codepend_overlap(t_codepend *x, t_floatarg o)
+{
+ if(!power_of_two((int)o)){
+ error("%f is not a power of two",o);
+ return;
+ }
+ x->overlap = (int)o;
+ codepend_init(x,1);
+}
+
+void codepend_winfac(t_codepend *x, t_floatarg f)
+{
+ if(!power_of_two((int)f)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = (int)f;
+ codepend_init(x,1);
+}
+
+void codepend_fftinfo( t_codepend *x )
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+void codepend_free(t_codepend *x)
+{
+#if MSP
+ dsp_free((t_pxobject *) x);
+#endif
+ free(x->trigland);
+ free(x->bitshuffle);
+ free(x->Wanal);
+ free(x->Wsyn);
+ free(x->Hwin);
+ free(x->inputOne);
+ free(x->inputTwo);
+ free(x->bufferOne);
+ free(x->bufferTwo);
+ free(x->channelOne);
+ free(x->channelTwo);
+ free(x->output);
+}
+
+void codepend_pad(t_codepend *x, t_floatarg pad)
+{
+ x->invert_pad = pad;
+ codepend_invert(x,x->invert);//resubmit to invert
+}
+
+void codepend_invert(t_codepend *x, t_floatarg toggle)
+{
+
+ x->invert_nextstate = (short)toggle;
+ x->invert_countdown = x->overlap; // delay effect for "overlap" vectors
+
+ if(x->invert_nextstate){ // lower gain immediately; delay going to invert
+ x->mult = (1. / (float) x->N) * x->invert_pad;
+ } else {
+ x->invert = 0; //immediately turn off invert; delay raising gain
+ }
+
+}
+
+void codepend_assist (t_codepend *x, void *b, long msg, long arg, char *dst)
+{
+
+ if (msg == 1) {
+
+ switch (arg) {
+ case 0: sprintf(dst,"(signal) Input One");break;
+ case 1: sprintf(dst,"(signal) Input Two"); break;
+ case 2: sprintf(dst,"(signal/float) Scaling Exponent"); break;
+ case 3: sprintf(dst,"(signal/float) Inverse Threshold"); break;
+ }
+ }
+
+ else {
+
+ if (msg == 2)
+ sprintf(dst,"(signal) Output");
+
+ }
+}
+
+
+void *codepend_new(t_symbol *s, int argc, t_atom *argv)
+{
+
+#if MSP
+ t_codepend *x = (t_codepend *) newobject(codepend_class);
+ dsp_setup((t_pxobject *)x,4);
+ outlet_new((t_pxobject *)x, "signal");
+ // x->x_obj.z_misc |= Z_NO_INPLACE; // probably not needed
+#endif
+#if PD
+ t_codepend *x = (t_codepend *)pd_new(codepend_class);
+ /* add three additional signal inlets */
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+
+ /* optional arguments: scaling exponent, threshold (now linear), overlap, winfac */
+ x->exponent = atom_getfloatarg(0,argc,argv);
+ x->threshold = atom_getfloatarg(1,argc,argv);
+ x->overlap = atom_getfloatarg(2,argc,argv);
+ x->winfac = atom_getfloatarg(3,argc,argv);
+
+ /*
+ x->threshold = (float) pow(10.0,(x->threshold * .05));
+ */
+ /* sanity check */
+ if(x->exponent < 0.25)
+ x->exponent = 0.25;
+
+ if(!power_of_two(x->overlap)){
+ x->overlap = 4;
+ }
+ if(!power_of_two(x->winfac)){
+ x->winfac = 1;
+ }
+
+ x->vs = sys_getblksize();
+ x->R = sys_getsr();
+
+ codepend_init(x,0);
+
+ return (x);
+}
+
+void codepend_init(t_codepend *x, short initialized)
+{
+ int i;
+ x->D = x->vs;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+ if(!initialized){
+ x->invert_pad = 0.025; // -32 dB
+ x->invert_countdown = 0;
+ x->mute = 0;
+ x->invert = 0;
+ x->Wanal = (float *) calloc(MAX_Nw, sizeof(float));
+ x->Wsyn = (float *) calloc(MAX_Nw, sizeof(float));
+ x->Hwin = (float *) calloc(MAX_Nw, sizeof(float));
+ x->inputOne = (float *) calloc(MAX_Nw, sizeof(float));
+ x->inputTwo = (float *) calloc(MAX_Nw, sizeof(float));
+ x->bufferOne = (float *) calloc(MAX_N, sizeof(float));
+ x->bufferTwo = (float *) calloc(MAX_N, sizeof(float));
+ x->channelOne = (float *) calloc(MAX_N+2, sizeof(float));
+ x->channelTwo = (float *) calloc(MAX_N+2, sizeof(float));
+ x->output = (float *) calloc(MAX_Nw, sizeof(float));
+ x->bitshuffle = (int *) calloc(MAX_N * 2, sizeof(int));
+ x->trigland = (float *) calloc(MAX_N * 2, sizeof(float));
+ }
+ memset((char *)x->inputOne,0,x->Nw);
+ memset((char *)x->inputTwo,0,x->Nw);
+ memset((char *)x->output,0,x->Nw);
+ memset((char *)x->bufferOne,0,x->N);
+ memset((char *)x->bufferTwo,0,x->N);
+ memset((char *)x->channelOne,0,(x->N+2));
+ memset((char *)x->channelTwo,0,(x->N+2));
+
+ if(x->invert){
+ x->mult *= x->invert_pad;
+ }
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makehanning( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 1);
+
+}
+
+
+t_int *codepend_perform(t_int *w)
+{
+
+ int
+ i,j,
+ inCount,
+ R,
+ N,
+ N2,
+ D,
+ Nw,
+ invert = 0,
+ even, odd,
+ *bitshuffle;
+
+ float maxamp,
+ threshold = 1.,
+ mult,
+ exponent,
+ a1, b1,
+ a2, b2,
+ *inputOne,
+ *inputTwo,
+ *bufferOne,
+ *bufferTwo,
+ *output,
+ *Wanal,
+ *Wsyn,
+ *channelOne,
+ *channelTwo,
+ *trigland;
+
+
+
+ /* get our inlets and outlets */
+
+ t_codepend *x = (t_codepend *) (w[1]);
+ t_float *inOne = (t_float *)(w[2]);
+ t_float *inTwo = (t_float *)(w[3]);
+ t_float *vec_exponent = (t_float *)(w[4]);
+ t_float *vec_threshold = (t_float *)(w[5]);
+ t_float *out = (t_float *)(w[6]);
+ t_int n = w[7];
+
+ short *connected = x->connected;
+ /* dereference structure */
+ if(connected[2])
+ x->exponent = *vec_exponent;
+ if(connected[3]){
+ x->threshold = *vec_threshold;
+ /*
+ x->threshold = (float) (pow( 10., (x->threshold * .05)));
+ */
+ }
+
+ if(x->mute){
+ while(n--)
+ *out++ = 0.0;
+ return w+8;
+ }
+ // do countdown
+ if(x->invert_countdown > 0){
+
+ if(x->invert) { // we
+ } else {
+ }
+ --(x->invert_countdown);
+ if(! x->invert_countdown){ // countdown just ended
+ if(x->invert_nextstate){ // moving to invert (gain is already down)
+ x->invert = x->invert_nextstate;
+ } else { // invert is already off - now reset gain
+ x->mult = 1. / (float) x->N;
+ }
+ }
+ }
+
+ inputOne = x->inputOne;
+ inputTwo = x->inputTwo;
+ bufferOne = x->bufferOne;
+ bufferTwo = x->bufferTwo;
+ inCount = x->inCount;
+ R = x->R;
+ N = x->N;
+ N2 = x->N2;
+ D = x->D;
+ Nw = x->Nw;
+ Wanal = x->Wanal;
+ Wsyn = x->Wsyn;
+ output = x->output;
+ channelOne = x->channelOne;
+ channelTwo = x->channelTwo;
+ bitshuffle = x->bitshuffle;
+ trigland = x->trigland;
+ mult = x->mult;
+ invert = x->invert;
+ exponent = x->exponent;
+
+ if ( x->threshold != 0. )
+ threshold = x->threshold;
+
+ /* fill our retaining buffers */
+
+ inCount += D;
+
+ for ( j = 0 ; j < Nw - D ; j++ ) {
+ inputOne[j] = inputOne[j+D];
+ inputTwo[j] = inputTwo[j+D];
+ }
+
+ for ( j = Nw - D; j < Nw; j++ ) {
+ inputOne[j] = *inOne++;
+ inputTwo[j] = *inTwo++;
+ }
+
+ /* apply hamming window and fold our window buffer into the fft buffer */
+
+ fold( inputOne, Wanal, Nw, bufferOne, N, inCount );
+ fold( inputTwo, Wanal, Nw, bufferTwo, N, inCount );
+
+ /* do an fft */
+
+ rdft( N, 1, bufferOne, bitshuffle, trigland );
+ rdft( N, 1, bufferTwo, bitshuffle, trigland );
+
+ /* convert to polar coordinates from complex values */
+
+ if (invert) {
+
+ for ( i = 0; i <= N2; i++ ) {
+
+ float mag_1, mag_2;
+
+ odd = ( even = i<<1 ) + 1;
+
+ a1 = ( i == N2 ? *(bufferOne+1) : *(bufferOne+even) );
+ b1 = ( i == 0 || i == N2 ? 0. : *(bufferOne+odd) );
+
+ a2 = ( i == N2 ? *(bufferTwo+1) : *(bufferTwo+even) );
+ b2 = ( i == 0 || i == N2 ? 0. : *(bufferTwo+odd) );
+
+ /* complex division */
+
+ mag_1 = hypot( a1, b1 );
+ mag_2 = hypot( a2, b2 );
+
+ if ( mag_2 > threshold )
+ *(channelOne+even) = mag_1 / mag_2;
+
+ else
+ *(channelOne+even) = mag_1 / threshold;
+
+ if ( mag_1 != 0. && mag_2 != 0. )
+ *(channelOne+odd) = atan2( b2, a2 ) - atan2( b1, a1 );
+
+ else
+ *(channelOne+odd) = 0.;
+
+ /* raise resulting magnitude to a desired power */
+
+ *(channelOne+even) = pow( *(channelOne+even), exponent );
+ }
+ }
+
+
+ else {
+
+ for ( i = 0; i <= N2; i++ ) {
+
+ float f_real, f_imag;
+
+ odd = ( even = i<<1 ) + 1;
+
+ a1 = ( i == N2 ? *(bufferOne+1) : *(bufferOne+even) );
+ b1 = ( i == 0 || i == N2 ? 0. : *(bufferOne+odd) );
+
+ a2 = ( i == N2 ? *(bufferTwo+1) : *(bufferTwo+even) );
+ b2 = ( i == 0 || i == N2 ? 0. : *(bufferTwo+odd) );
+
+ /* complex multiply */
+
+ f_real = (a1 * a2) - (b1 * b2);
+ f_imag = (a1 * b2) + (b1 * a2);
+
+ *(channelOne+even) = hypot( f_real, f_imag );
+ *(channelOne+odd) = -atan2( f_imag, f_real );
+
+ /* raise resulting magnitude to a desired power */
+
+ *(channelOne+even) = pow( *(channelOne+even), exponent );
+ }
+ }
+
+ /* convert back to complex form, read for the inverse fft */
+
+ for ( i = 0; i <= N2; i++ ) {
+
+ odd = ( even = i<<1 ) + 1;
+
+ *(bufferOne+even) = *(channelOne+even) * cos( *(channelOne+odd) );
+
+ if ( i != N2 )
+ *(bufferOne+odd) = -(*(channelOne+even)) * sin( *(channelOne+odd) );
+ }
+
+
+ /* do an inverse fft */
+
+ rdft( N, -1, bufferOne, bitshuffle, trigland );
+
+
+ /* dewindow our result */
+
+ overlapadd( bufferOne, N, Wsyn, output, Nw, inCount);
+
+ /* set our output and adjust our retaining output buffer */
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+
+ /* restore state variables */
+
+
+ x->inCount = inCount % Nw;
+ return (w+8);
+}
+
+
+void codepend_dsp(t_codepend *x, t_signal **sp, short *count)
+{
+long i;
+
+#if MSP
+ for( i = 0; i < 4; i++ ){
+ x->connected[i] = count[i];
+ }
+#endif
+ /* signal is always connected in Pd */
+#if PD
+ for( i = 0; i < 4; i++ ){
+ x->connected[i] = 1;
+ }
+#endif
+
+ /* reinitialize if vector size or sampling rate has been changed */
+ if(x->vs != sp[0]->s_n || x->R != sp[0]->s_sr){
+ x->vs = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ codepend_init(x,1);
+ }
+
+ dsp_add(codepend_perform, 7, x,
+ sp[0]->s_vec,
+ sp[1]->s_vec,
+ sp[2]->s_vec,
+ sp[3]->s_vec,
+ sp[4]->s_vec,
+ sp[0]->s_n);
+}
+
diff --git a/crossx~.c b/crossx~.c
new file mode 100644
index 0000000..70739f0
--- /dev/null
+++ b/crossx~.c
@@ -0,0 +1,449 @@
+#include "MSPd.h"
+
+#include "fftease.h"
+
+#if MSP
+void *crossx_class;
+#endif
+
+#if PD
+static t_class *crossx_class;
+#endif
+
+#define OBJECT_NAME "crossx~"
+
+typedef struct _crossx
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ float *input1;
+ float *buffer1;
+ float *channel1;
+
+ float *input2;
+ float *buffer2;
+ float *channel2;
+ float *last_channel;
+ //
+ int inCount;
+ float *Hwin;
+ float *Wanal;
+ float *Wsyn;
+ float *output;
+ /* crossx vars */
+
+ float *c_lastphase_in1;
+ float *c_lastphase_in2;
+ float *c_lastphase_out;
+ float c_fundamental;
+ float c_factor_in;
+ float c_factor_out;
+
+ float threshie;
+ short thresh_connected;
+ // for fast fft
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ int overlap;//overlap factor
+ int winfac;//window factor
+ int vs;//vector size
+ short mute;//flag
+ short autonorm;// for self gain regulation
+} t_crossx;
+
+void *crossx_new(t_symbol *s, int argc, t_atom *argv);
+t_int *offset_perform(t_int *w);
+t_int *crossx_perform(t_int *w);
+void crossx_dsp(t_crossx *x, t_signal **sp, short *count);
+void crossx_assist(t_crossx *x, void *b, long m, long a, char *s);
+void crossx_float(t_crossx *x, double f);
+void *crossx_new(t_symbol *s, int argc, t_atom *argv);
+void crossx_init(t_crossx *x, short initialized);
+void crossx_overlap(t_crossx *x, t_floatarg o);
+void crossx_winfac(t_crossx *x, t_floatarg o);
+void crossx_fftinfo(t_crossx *x);
+void crossx_mute(t_crossx *x, t_floatarg toggle);
+void crossx_autonorm(t_crossx *x, t_floatarg toggle);
+void crossx_free(t_crossx *x);
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&crossx_class, (method)crossx_new, (method)dsp_free,
+ (short)sizeof(t_crossx), 0L, A_GIMME, 0);
+ addmess((method)crossx_dsp, "dsp", A_CANT, 0);
+ addmess((method)crossx_assist,"assist",A_CANT,0);
+ addmess((method)crossx_mute,"mute",A_DEFFLOAT,0);
+ addmess((method)crossx_overlap, "overlap", A_DEFFLOAT, 0);
+ addmess((method)crossx_winfac, "winfac", A_DEFFLOAT, 0);
+ addmess((method)crossx_fftinfo, "fftinfo", 0);
+ addmess((method)crossx_autonorm, "autonorm", A_DEFFLOAT, 0);
+ addfloat((method)crossx_float);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+#if PD
+void crossx_tilde_setup(void)
+{
+ crossx_class = class_new(gensym("crossx~"), (t_newmethod)crossx_new,
+ (t_method)crossx_free ,sizeof(t_crossx), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(crossx_class, t_crossx, x_f);
+ class_addmethod(crossx_class, (t_method)crossx_dsp, gensym("dsp"), 0);
+ class_addmethod(crossx_class, (t_method)crossx_assist, gensym("assist"), 0);
+ class_addmethod(crossx_class, (t_method)crossx_mute, gensym("mute"), A_DEFFLOAT,0);
+ class_addmethod(crossx_class, (t_method)crossx_overlap, gensym("overlap"), A_DEFFLOAT,0);
+ class_addmethod(crossx_class, (t_method)crossx_winfac, gensym("winfac"), A_DEFFLOAT,0);
+ class_addmethod(crossx_class, (t_method)crossx_fftinfo, gensym("fftinfo"), 0);
+ class_addmethod(crossx_class, (t_method)crossx_autonorm, gensym("autonorm"), A_DEFFLOAT,0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+post("padded memory");
+}
+#endif
+
+
+void crossx_autonorm(t_crossx *x, t_floatarg toggle)
+{
+ x->autonorm = (short) toggle;
+}
+void crossx_assist (t_crossx *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0:
+ sprintf(dst,"(signal) Driver Sound");
+ break;
+ case 1:
+ sprintf(dst,"(signal) Filter Sound");
+ break;
+ case 2:
+ sprintf(dst,"(float/signal) Cross Synthesis Threshold");
+ break;
+
+ }
+ } else if (msg==2) {
+ sprintf(dst,"(signal) Output");
+ }
+}
+
+void crossx_overlap(t_crossx *x, t_floatarg o)
+{
+ if(!power_of_two((int)o)){
+ error("%f is not a power of two",o);
+ return;
+ }
+ x->overlap = (int)o;
+ crossx_init(x,1);
+}
+
+void crossx_winfac(t_crossx *x, t_floatarg f)
+{
+ if(!power_of_two((int)f)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = (int)f;
+ crossx_init(x,1);
+}
+
+void crossx_fftinfo( t_crossx *x )
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+
+void crossx_mute(t_crossx *x, t_floatarg toggle)
+{
+ x->mute = (short)toggle;
+}
+
+void crossx_free(t_crossx *x)
+{
+#if MSP
+ dsp_free((t_pxobject *) x);
+#endif
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->input1,0);
+ freebytes(x->input2,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->buffer1,0);
+ freebytes(x->buffer2,0);
+ freebytes(x->channel1,0);
+ freebytes(x->channel2,0);
+ freebytes(x->output,0);
+ /* these last are extra - kill if we clean up - upstairs
+ free(x->c_lastphase_in1);
+ free(x->c_lastphase_in2);
+ free(x->c_lastphase_out);
+ free(x->last_channel);*/
+}
+
+#if MSP
+void crossx_float(t_crossx *x, double f) // Look at floats at inlets
+{
+int inlet = x->x_obj.z_in;
+
+ if (inlet == 2)
+ {
+ x->threshie = f;
+ }
+}
+#endif
+
+void *crossx_new(t_symbol *s, int argc, t_atom *argv)
+{
+#if MSP
+ t_crossx *x = (t_crossx *)newobject(crossx_class);
+ dsp_setup((t_pxobject *)x,3);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+#if PD
+ t_crossx *x = (t_crossx *)pd_new(crossx_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+
+ x->overlap = atom_getfloatarg(0,argc,argv);
+ x->winfac = atom_getfloatarg(1,argc,argv);
+ if(x->overlap <= 0)
+ x->overlap = 4;
+
+ x->winfac = 1;
+
+ x->R = sys_getsr();
+ x->vs = sys_getblksize();
+
+ crossx_init(x,0);
+ return (x);
+}
+
+void crossx_init(t_crossx *x, short initialized)
+{
+ int i;
+
+ x->D = x->vs;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+
+ x->c_fundamental = (float) x->R/( (x->N2)<<1 );
+ x->c_factor_in = (float) x->R/((float)x->D * TWOPI);
+ x->c_factor_out = TWOPI * (float) x->D / (float) x->R;
+ if(!initialized){
+ x->threshie = .001 ;
+ x->autonorm = 0;
+ x->mute = 0;
+ x->Wanal = (float *) getbytes((MAX_Nw) * sizeof(float));
+ x->Wsyn = (float *) getbytes((MAX_Nw) * sizeof(float));
+ x->Hwin = (float *) getbytes((MAX_Nw) * sizeof(float));
+ x->output = (float *) getbytes((MAX_Nw) * sizeof(float));
+ x->bitshuffle = (int *) getbytes((MAX_N * 2)* sizeof(int));
+ x->trigland = (float *) getbytes((MAX_N * 2)* sizeof(float));
+
+ x->input1 = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->buffer1 = (float *) getbytes(MAX_N * sizeof(float));
+ x->channel1 = (float *) getbytes((MAX_N+2) * sizeof(float));
+ x->input2 = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->buffer2 = (float *) getbytes(MAX_N * sizeof(float));
+ x->channel2 = (float *) getbytes((MAX_N+2) * sizeof(float));
+ x->last_channel = (float *) getbytes((MAX_N+2) * sizeof(float));
+ x->c_lastphase_in1 = (float *) getbytes((MAX_N2+1) * sizeof(float));
+ x->c_lastphase_in2 = (float *) getbytes((MAX_N2+1) * sizeof(float));
+ x->c_lastphase_out = (float *) getbytes((MAX_N2+1) * sizeof(float));
+ }
+ memset((char *)x->input1,0,x->Nw * sizeof(float));
+ memset((char *)x->input2,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ memset((char *)x->buffer1,0,x->N * sizeof(float));
+ memset((char *)x->buffer2,0,x->N * sizeof(float));
+ memset((char *)x->channel1,0,(x->N+2) * sizeof(float));
+ memset((char *)x->channel2,0,(x->N+2) * sizeof(float));
+ memset((char *)x->c_lastphase_in1,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->c_lastphase_in2,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->c_lastphase_out,0,(x->N2+1) * sizeof(float));
+
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makehanning( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 0);
+}
+
+t_int *crossx_perform(t_int *w)
+{
+ int i, j;
+
+ float a1, a2, b1, b2;
+ int even, odd;
+ int amp, freq;
+ float gainer, threshie;
+ float ingain = 0;
+ float outgain, rescale;
+ float mymult;
+
+ t_crossx *x = (t_crossx *) (w[1]);
+ 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 n = w[6];
+
+ /* dereference struncture */
+ float *input1 = x->input1;
+ float *input2 = x->input2;
+ float *buffer1 = x->buffer1;
+ float *buffer2 = x->buffer2;
+ int inCount = x->inCount;
+ int R = x->R;
+ int N = x->N;
+ int N2 = x->N2;
+ int D = x->D;
+ int Nw = x->Nw;
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *output = x->output;
+ float *channel1 = x->channel1;
+ float *channel2 = x->channel2;
+ float *last_channel = x->last_channel;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland;
+ float mult = x->mult;
+ float *c_lastphase_in1 = x->c_lastphase_in1;
+ float *c_lastphase_in2 = x->c_lastphase_in2;
+float *c_lastphase_out = x->c_lastphase_out;
+float c_fundamental = x->c_fundamental;
+ float c_factor_in = x->c_factor_in;
+ float c_factor_out = x->c_factor_out;
+ short autonorm = x->autonorm;
+
+ if(x->mute){
+ while(n--){
+ *out++ = 0;
+ }
+ return w+7;
+ }
+
+ if( x->thresh_connected ){
+ threshie = *in3++;
+ } else {
+ threshie = x->threshie;
+ }
+
+ inCount += D;
+
+ for ( j = 0 ; j < Nw - D ; j++ ){
+ input1[j] = input1[j+D];
+ input2[j] = input2[j+D];
+ }
+ for ( j = Nw - D; j < Nw; j++ ) {
+ input1[j] = *in1++;
+ input2[j] = *in2++;
+ }
+
+ fold( input1, Wanal, Nw, buffer1, N, inCount );
+ fold( input2, Wanal, Nw, buffer2, N, inCount );
+ rdft( N, 1, buffer1, bitshuffle, trigland );
+ rdft( N, 1, buffer2, bitshuffle, trigland );
+
+/* changing algorithm for window flexibility */
+ if(autonorm){
+ ingain = 0;
+ for(i = 0; i < N; i+=2){
+ ingain += hypot(buffer1[i], buffer1[i+1]);
+ }
+ }
+
+ for ( i = 0; i <= N2; i++ ) {
+ odd = ( even = i<<1 ) + 1;
+
+ a1 = ( i == N2 ? *(buffer1+1) : *(buffer1+even) );
+ b1 = ( i == 0 || i == N2 ? 0. : *(buffer1+odd) );
+ a2 = ( i == N2 ? *(buffer2+1) : *(buffer2+even) );
+ b2 = ( i == 0 || i == N2 ? 0. : *(buffer2+odd) );
+ gainer = hypot(a2, b2);
+ if( gainer > threshie )
+ *(channel1+even) = hypot( a1, b1 ) * gainer;
+ *(channel1+odd) = -atan2( b1, a1 );
+ *(buffer1+even) = *(channel1+even) * cos( *(channel1+odd) );
+ if ( i != N2 )
+ *(buffer1+odd) = -(*(channel1+even)) * sin( *(channel1+odd) );
+
+ }
+ if(autonorm){
+ outgain = 0;
+ for(i = 0; i < N; i+=2){
+ outgain += hypot(buffer1[i], buffer1[i+1]);
+ }
+ if(ingain <= .0000001){
+ // post("gain emergency!");
+ rescale = 1.0;
+ } else {
+ rescale = ingain / outgain;
+ }
+ // post("ingain %f outgain %f rescale %f",ingain, outgain, rescale);
+ mymult = mult * rescale;
+ } else {
+ mymult = mult;
+ }
+
+ rdft( N, -1, buffer1, bitshuffle, trigland );
+ overlapadd( buffer1, N, Wsyn, output, Nw, inCount);
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mymult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+
+
+ /* restore state variables */
+ x->inCount = inCount % Nw;
+ return (w+7);
+}
+
+void crossx_dsp(t_crossx *x, t_signal **sp, short *count)
+{
+#if MSP
+ x->thresh_connected = count[2];
+#endif
+#if PD
+ x->thresh_connected = 1;
+#endif
+
+ if(x->vs != sp[0]->s_n || x->R != sp[0]->s_sr ){
+ x->vs = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ crossx_init(x,1);
+ }
+
+ dsp_add(crossx_perform, 6, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,
+ sp[3]->s_vec, sp[0]->s_n);
+}
+
diff --git a/dentist~.c b/dentist~.c
new file mode 100644
index 0000000..e9cb8fe
--- /dev/null
+++ b/dentist~.c
@@ -0,0 +1,693 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *dentist_class;
+#endif
+
+#if PD
+static t_class *dentist_class;
+#endif
+
+#define OBJECT_NAME "dentist~"
+
+typedef struct _dentist
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ float *buffer;
+ float *channel;
+ float *output;
+ //
+ short *bin_selection;
+ short *last_bin_selection;
+ int *active_bins;
+ int tooth_count;
+ int ramp_frames;
+ int frames_left;
+ float frame_duration;
+ int max_bin;
+ //
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ int overlap;
+ int winfac;
+ float topfreq;
+ float funda;
+ //
+ void *list_outlet;
+ short direct_update;
+ short mute;
+ t_atom *list_data;
+ short interpolate_singles;
+ float sync;
+} t_dentist;
+
+void *dentist_new(t_symbol *msg, short argc, t_atom *argv);
+t_int *offset_perform(t_int *w);
+t_int *dentist_perform(t_int *w);
+void dentist_dsp(t_dentist *x, t_signal **sp, short *count);
+void dentist_assist(t_dentist *x, void *b, long m, long a, char *s);
+void set_switch_bins (t_dentist *x, int i);
+void reset_shuffle(t_dentist *x);
+void dentist_showstate(t_dentist *x);
+void dentist_direct_update(t_dentist *x, t_floatarg toggle);
+void dentist_mute(t_dentist *x, t_floatarg toggle);
+void dentist_setstate(t_dentist *x, t_symbol *msg, short argc, t_atom *argv);
+void dentist_ramptime(t_dentist *x, t_floatarg ramp_ms);
+int rand_index(int max);
+void dentist_init(t_dentist *x, short initialized);
+void dentist_bins_pd (t_dentist *x, t_floatarg i);
+void dentist_topfreq(t_dentist *x, t_floatarg f);
+void dentist_free(t_dentist *x);
+void dentist_toothcount(t_dentist *x, t_floatarg newcount);
+void dentist_scramble(t_dentist *x);
+void dentist_activate_bins(t_dentist *x, t_floatarg f);
+void dentist_interpolate_singles(t_dentist *x, t_floatarg f);
+void dentist_overlap(t_dentist *x, t_floatarg o);
+void dentist_winfac(t_dentist *x, t_floatarg o);
+void dentist_fftinfo(t_dentist *x);
+void dentist_mute(t_dentist *x, t_floatarg toggle);
+
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&dentist_class, (method)dentist_new, (method)dsp_free,
+ (short)sizeof(t_dentist), 0, A_GIMME, 0);
+ addmess((method)dentist_dsp, "dsp", A_CANT, 0);
+ addint((method)set_switch_bins);
+// addbang((method)reset_shuffle);
+ addmess((method)dentist_showstate,"showstate",0);
+// addmess((method)dentist_direct_update,"direct_update",A_FLOAT, 0);
+ addmess((method)dentist_mute,"mute",A_FLOAT, 0);
+ addmess((method)dentist_setstate, "setstate", A_GIMME, 0);
+ addmess((method)dentist_ramptime, "ramptime", A_FLOAT, 0);
+ addmess((method)dentist_topfreq, "topfreq", A_FLOAT, 0);
+ addmess((method)dentist_toothcount, "toothcount", A_FLOAT, 0);
+// addmess((method)dentist_activate_bins, "activate_bins", A_FLOAT, 0);
+ addmess((method)dentist_interpolate_singles, "interpolate_singles", A_FLOAT, 0);
+ addmess((method)dentist_scramble, "scramble", 0);
+ addmess((method)dentist_assist,"assist",A_CANT,0);
+ addmess((method)dentist_overlap, "overlap", A_DEFFLOAT, 0);
+ addmess((method)dentist_winfac, "winfac", A_DEFFLOAT, 0);
+ addmess((method)dentist_fftinfo, "fftinfo", 0);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+#if PD
+void dentist_tilde_setup(void)
+{
+ dentist_class = class_new(gensym("dentist~"), (t_newmethod)dentist_new,
+ (t_method)dentist_free ,sizeof(t_dentist), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(dentist_class, t_dentist, x_f);
+ class_addmethod(dentist_class,(t_method)dentist_dsp,gensym("dsp"),0);
+ class_addmethod(dentist_class,(t_method)dentist_mute,gensym("mute"),A_FLOAT,0);
+ class_addmethod(dentist_class,(t_method)dentist_showstate,gensym("showstate"),0);
+// class_addmethod(dentist_class,(t_method)dentist_direct_update,gensym("direct_update"),A_FLOAT,0);
+ class_addmethod(dentist_class,(t_method)dentist_setstate,gensym("setstate"),A_GIMME,0);
+ class_addmethod(dentist_class,(t_method)dentist_ramptime,gensym("ramptime"),A_FLOAT,0);
+// class_addmethod(dentist_class,(t_method)dentist_bins_pd,gensym("dentist_bins"),A_FLOAT,0);
+ class_addmethod(dentist_class,(t_method)dentist_topfreq,gensym("topfreq"),A_FLOAT,0);
+ class_addmethod(dentist_class,(t_method)dentist_toothcount,gensym("toothcount"),A_FLOAT,0);
+ class_addmethod(dentist_class,(t_method)dentist_interpolate_singles,gensym("interpolate_singles"),A_FLOAT, 0);
+ class_addmethod(dentist_class,(t_method)dentist_scramble,gensym("scramble"),0);
+// class_addmethod(dentist_class,(t_method)dentist_activate_bins,gensym("activate_bins"),A_FLOAT,0);
+ class_addmethod(dentist_class, (t_method)dentist_overlap, gensym("overlap"), A_DEFFLOAT,0);
+ class_addmethod(dentist_class, (t_method)dentist_winfac, gensym("winfac"), A_DEFFLOAT,0);
+ class_addmethod(dentist_class, (t_method)dentist_fftinfo, gensym("fftinfo"), 0);
+
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+void dentist_interpolate_singles(t_dentist *x, t_floatarg f)
+{
+ x->interpolate_singles = (short)f;
+// post("singles interp: %d",x->interpolate_singles);
+}
+
+void dentist_free(t_dentist *x)
+{
+/* Pd might be having difficulty freeing its memory */
+#if MSP
+ dsp_free((t_pxobject *)x);
+#endif
+ free(x->Wanal);
+ free(x->Wsyn);
+ free(x->input);
+ free(x->Hwin);
+ free(x->buffer);
+ free(x->channel);
+ free(x->output);
+ free(x->bitshuffle);
+ free(x->trigland);
+ free(x->bin_selection);
+ free(x->active_bins);
+ free(x->last_bin_selection);
+ free(x->list_data);
+
+//post("avoiding freeing memory here");
+}
+
+void dentist_overlap(t_dentist *x, t_floatarg f)
+{
+int o = (int)f;
+ if(!power_of_two(o)){
+ error("%d is not a power of two",o);
+ return;
+ }
+ x->overlap = o;
+ dentist_init(x,1);
+}
+
+void dentist_winfac(t_dentist *x, t_floatarg f)
+{
+int w = (int)f;
+ if(!power_of_two(w)){
+ error("%d is not a power of two",w);
+ return;
+ }
+ x->winfac = w;
+ dentist_init(x,2);
+}
+
+void dentist_fftinfo( t_dentist *x )
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+
+void dentist_direct_update( t_dentist *x, t_floatarg toggle)
+{
+ x->direct_update = (short)toggle;
+}
+
+void dentist_mute( t_dentist *x, t_floatarg toggle )
+{
+ x->mute = (short)toggle;
+}
+
+void dentist_assist (t_dentist *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0:
+ sprintf(dst,"(signal) Input ");
+ break;
+ }
+ } else if (msg==2) {
+ switch (arg) {
+ case 0: sprintf(dst,"(signal) Output"); break;
+ case 1: sprintf(dst,"(signal) Interpolation Sync"); break;
+ case 2: sprintf(dst,"(list) Current Selected Bins"); break;
+ }
+ }
+}
+
+void *dentist_new(t_symbol *msg, short argc, t_atom *argv)
+{
+#if MSP
+ t_dentist *x = (t_dentist *)newobject(dentist_class);
+ x->list_outlet = listout((t_pxobject *)x);
+ dsp_setup((t_pxobject *)x,1);
+ outlet_new((t_pxobject *)x, "signal");
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+
+#if PD
+ t_dentist *x = (t_dentist *)pd_new(dentist_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->list_outlet = outlet_new(&x->x_obj,gensym("list"));
+#endif
+
+ // INITIALIZATIONS
+
+ x->D = sys_getblksize();
+ x->R = sys_getsr();
+ x->topfreq = atom_getfloatarg(0,argc,argv);
+ x->overlap = atom_getfloatarg(1,argc,argv);
+ x->winfac = atom_getfloatarg(2,argc,argv);
+ if(!power_of_two(x->overlap))
+ x->overlap = 4;
+ if(!power_of_two(x->winfac))
+ x->winfac = 1;
+
+ dentist_init(x,0);
+ return (x);
+}
+
+void dentist_topfreq(t_dentist *x, t_floatarg f)
+{
+float funda = x->funda;
+float curfreq;
+
+ if(f < 50 || f > x->R/2.0)
+ return;
+
+ x->topfreq = f;
+ x->max_bin = 1;
+ curfreq = 0;
+ while(curfreq < x->topfreq) {
+ ++(x->max_bin);
+ curfreq += funda ;
+ }
+}
+
+void dentist_init(t_dentist *x, short initialized)
+{
+
+ float curfreq;
+ int i;
+
+ x->N = x->overlap * x->D;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+
+ if(!initialized){
+ x->sync = 0;
+ x->mute = 0;
+ x->direct_update = 0;
+ if(x->topfreq < 100)
+ x->topfreq = 100.0;
+ x->Wanal = (float *) calloc(MAX_Nw, sizeof(float));
+ x->Wsyn = (float *) calloc(MAX_Nw, sizeof(float));
+ x->input = (float *) calloc(MAX_Nw, sizeof(float));
+ x->Hwin = (float *) calloc(MAX_Nw, sizeof(float));
+ x->buffer = (float *) calloc(MAX_N, sizeof(float));
+ x->channel = (float *) calloc(MAX_N+2, sizeof(float));
+ x->output = (float *) calloc(MAX_Nw, sizeof(float));
+ x->bitshuffle = (int *) calloc(MAX_N * 2, sizeof(int));
+ x->trigland = (float *) calloc(MAX_N * 2, sizeof(float));
+ x->bin_selection = (short *) calloc( MAX_N2, sizeof(short));
+ x->active_bins = (int *) calloc( MAX_N2, sizeof(int));
+ x->last_bin_selection = (short *) calloc( MAX_N2, sizeof(short)) ;
+ x->list_data = (t_atom *) calloc( MAX_N + 2, sizeof(t_atom));
+ x->tooth_count = 0;
+ x->interpolate_singles = 1;
+ x->ramp_frames = 0;
+ dentist_scramble(x);
+ }
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ memset((char *)x->buffer,0,x->N * sizeof(float));
+ memset((char *)x->channel,0,(x->N+2) * sizeof(float));
+
+
+ x->mult = 1. / (float) x->N;
+ x->frame_duration = (float) x->D / (float) x->R;
+ x->frames_left = 0;
+ x->funda = (float) x->R / (float) x->N;
+ x->max_bin = 1;
+/* curfreq = 0;
+
+ while(curfreq < x->topfreq) {
+ ++(x->max_bin);
+ curfreq += x->funda;
+ }*/
+ if(!x->funda){
+ error("%s: zero sampling rate!",OBJECT_NAME);
+ return;
+ }
+ x->max_bin = (int) (x->topfreq / x->funda);
+ if(x->max_bin < 1)
+ x->max_bin = 1;
+
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makehanning( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 0);
+
+ for( i = 0; i < x->N2; i++) {
+ x->last_bin_selection[i] = x->bin_selection[i];
+ }
+}
+
+t_int *dentist_perform(t_int *w)
+{
+ int i,j;
+ float oldfrac,newfrac;
+ int tooth_count;
+
+ t_dentist *x = (t_dentist *) (w[1]);
+
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ t_float *sync_vec = (t_float *)(w[4]);
+ t_int n = w[5];
+
+ int frames_left = x->frames_left;
+ int ramp_frames = x->ramp_frames;
+ short *bin_selection = x->bin_selection;
+ short *last_bin_selection = x->last_bin_selection;
+ /* dereference struncture */
+ float *input = x->input;
+ float *buffer = x->buffer;
+ int inCount = x->inCount;
+ int R = x->R;
+ int N = x->N;
+ int N2 = x->N2;
+ int D = x->D;
+ int Nw = x->Nw;
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *output = x->output;
+ float *channel = x->channel;
+ float mult = x->mult ;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland ;
+ float sync = x->sync;
+
+
+ if( x->mute ){
+ while( n-- ){
+ *out++ = 0.0;
+ *sync_vec++ = sync;
+ }
+ return (w+6);
+ }
+
+ inCount += D;
+
+ for ( j = 0 ; j < Nw - D ; j++ ){
+ input[j] = input[j+D];
+ }
+ for ( j = Nw - D; j < Nw; j++ ) {
+ input[j] = *in++;
+ }
+
+ fold( input, Wanal, Nw, buffer, N, inCount );
+ rdft( N, 1, buffer, bitshuffle, trigland );
+ leanconvert( buffer, channel, N2 );
+
+ if(frames_left > 0 && ramp_frames > 0) {
+ // INTERPOLATE ACCORDING TO POSITION IN RAMP
+ oldfrac = (float) frames_left / (float) ramp_frames ;
+ sync = newfrac = 1.0 - oldfrac;
+ for( i = 0; i < N2 ; i++){
+ if( (! bin_selection[i]) && (! last_bin_selection[i]) ){
+ channel[i * 2] = 0;
+ } else if (bin_selection[i] && last_bin_selection[i]) {
+ // channel[i * 2] *= 1; NO ACTION
+ } else if (bin_selection[i]) {
+ channel[i * 2] *= newfrac;
+ } else if (last_bin_selection[i]) {
+ channel[i * 2] *= oldfrac;
+ }
+ }
+ --frames_left;
+ if( ! frames_left ){
+ // Copy current to last
+ for( i = 0; i < N2; i++) {
+ last_bin_selection[i] = bin_selection[i];
+ }
+ }
+ } else {
+ for( i = 0; i < N2 ; i++){
+ if( ! bin_selection[ i ] ){
+ channel[ i * 2 ] = 0;
+ }
+ }
+ oldfrac = 0.0;
+ sync = 1.0;
+ }
+ leanunconvert( channel, buffer, N2 );
+ rdft( N, -1, buffer, bitshuffle, trigland );
+ overlapadd( buffer, N, Wsyn, output, Nw, inCount);
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+ /* restore state variables */
+ for(i=0; i < n; i++){
+ sync_vec[i] = sync;
+ }
+ x->inCount = inCount % Nw;
+ x->frames_left = frames_left;
+ x->sync = sync;
+ return (w+6);
+}
+
+
+void set_switch_bins (t_dentist *x, int i)
+{
+ if( i < 0 ){
+ i = 0;
+ }
+ if( i > x->N2 ) {
+ i = x->N2;
+ }
+ x->tooth_count = i;
+ if( x->direct_update ){
+ reset_shuffle(x);
+ }
+ return;
+}
+//identical function for Pd
+void dentist_bins_pd (t_dentist *x, t_floatarg i)
+{
+ if( i < 0 ){
+ i = 0;
+ }
+ if( i > x->N2 ) {
+ i = x->N2;
+ }
+ x->tooth_count = (int)i;
+ if(x->direct_update){
+ reset_shuffle(x);
+ }
+ return;
+}
+
+// experimental, not to be used
+void dentist_activate_bins(t_dentist *x, t_floatarg f)
+{
+ if(f < 0 || f > x->max_bin){
+#if PD
+ post("* %d bin out of range",(int)f);
+#endif
+ return;
+ }
+ x->tooth_count = (int)f;
+}
+
+void dentist_scramble(t_dentist *x)
+{
+short *last_bin_selection = x->last_bin_selection;
+short *bin_selection = x->bin_selection;
+int *active_bins = x->active_bins;
+int N2 = x->N2;
+int i,tmp,b1,b2;
+int maxswap = x->max_bin;
+int tooth_count = x->tooth_count;
+
+ /* for(i = 0; i < x->N2; i++){
+ last_bin_selection[i] = bin_selection[i];
+ }*/
+ for(i=0; i<N2; i++){
+ bin_selection[i] = 0;
+ active_bins[i] = i;
+ }
+ while(maxswap > 0){
+ b1 = maxswap;
+ b2 = rand_index(maxswap);
+ tmp = active_bins[b1];
+ active_bins[b1] = active_bins[b2];
+ active_bins[b2] = tmp;
+ --maxswap;
+ }
+ for( i = 0; i < x->tooth_count; i++ ) {
+ x->bin_selection[active_bins[i]] = 1;
+ }
+ x->frames_left = x->ramp_frames;
+ if(! x->ramp_frames) {
+ for(i = 0; i < N2; i++){
+ last_bin_selection[i] = bin_selection[i];
+ }
+ }
+}
+
+
+void dentist_toothcount(t_dentist *x, t_floatarg newcount)
+{
+int i;
+int nc = (int) newcount;
+int max = x->max_bin;
+int tooth_count = x->tooth_count;
+int newbin;
+int oldbin;
+
+if(nc < 0 || nc > x->N2){
+#if PD
+ post("* %d out of range",nc);
+#endif
+#if MSP
+ error("%d out of range",nc);
+#endif
+ return;
+}
+ /* for(i = 0; i < x->N2; i++){
+ x->last_bin_selection[i] = x->bin_selection[i];
+ }*/
+ if(nc < x->tooth_count){
+ for(i = nc; i < tooth_count; i++){
+ x->bin_selection[x->active_bins[i]] = 0;
+ }
+ } else {
+ for(i = tooth_count; i < nc; i++){
+ x->bin_selection[x->active_bins[i]] = 1;
+ }
+ }
+ // if immediate reset
+ if(x->interpolate_singles){
+// post("setting frames left");
+ x->frames_left = x->ramp_frames;
+ }
+ if(! x->ramp_frames) {
+ for(i = 0; i < x->N2; i++){
+ x->last_bin_selection[i] = x->bin_selection[i];
+ }
+ }
+ x->tooth_count = nc;
+}
+
+
+void reset_shuffle (t_dentist *x)
+{
+ int i;
+ int temp, p1, p2;
+ int max;
+
+ max = x->max_bin;
+ for(i = 0; i < x->N2; i++){
+ x->last_bin_selection[i] = x->bin_selection[i];
+ x->bin_selection[i] = 0;
+ }
+ for(i = 0; i < x->max_bin; i++) {
+ x->active_bins[i] = rand_index(max);
+ x->bin_selection[x->active_bins[i]] = 1;
+ }
+ x->frames_left = x->ramp_frames;
+ if(! x->ramp_frames) { // Ramp Off - Immediately set last to current
+ for( i = 0; i < x->N2; i++ ){
+ x->last_bin_selection[ i ] = x->bin_selection[ i ];
+ }
+ }
+}
+
+int rand_index(int max) {
+ return (rand() % max);
+}
+
+void dentist_setstate (t_dentist *x, t_symbol *msg, short argc, t_atom *argv) {
+ short i;
+ int selex;
+
+ short *last_bin_selection = x->last_bin_selection;
+ short *bin_selection = x->bin_selection;
+ int *active_bins = x->active_bins;
+ x->tooth_count = argc;
+
+ for(i = 0; i < x->N2; i++){
+ last_bin_selection[i] = bin_selection[i]; // needed here
+ bin_selection[i] = 0;
+ }
+
+ for (i=0; i < argc; i++) {
+ selex = atom_getfloatarg(i,argc,argv);
+ if (selex < x->N2 && selex >= 0 ) {
+ active_bins[i] = selex;
+ bin_selection[selex] = 1;
+ } else {
+ post ("%d out of range bin",selex);
+ }
+ }
+
+
+ x->frames_left = x->ramp_frames;
+ if(! x->ramp_frames) { // Ramp Off - Immediately set last to current
+ for(i = 0; i < x->N2; i++){
+ last_bin_selection[i] = bin_selection[i];
+ }
+ }
+
+ return;
+}
+void dentist_ramptime (t_dentist *x, t_floatarg ramp_ms) {
+
+ if(ramp_ms <= 0){
+ x->ramp_frames = 0;
+ return;
+ }
+
+ x->frames_left = x->ramp_frames = (int)(ramp_ms * .001 / x->frame_duration);
+ return;
+}
+// REPORT CURRENT SHUFFLE STATUS
+void dentist_showstate (t_dentist *x) {
+
+ t_atom *list_data = x->list_data;
+
+ short i, count;
+ float data;
+
+ count = 0;
+ for(i = 0; i < x->tooth_count; i++ ) {
+ data = x->active_bins[i];
+#if MSP
+ SETLONG(list_data+count,x->active_bins[i]);
+ #endif
+ #if PD
+ SETFLOAT(list_data+count,data);
+ #endif
+ ++count;
+ }
+ outlet_list(x->list_outlet,0,x->tooth_count,list_data);
+
+ return;
+}
+void dentist_dsp(t_dentist *x, t_signal **sp, short *count)
+{
+ long i;
+ if(x->R != sp[0]->s_sr || x->D != sp[0]->s_n){
+ x->R = sp[0]->s_sr;
+ x->D = sp[0]->s_n;
+ dentist_init(x,1);
+ }
+ dsp_add(dentist_perform, 5, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
diff --git a/disarrain~.c b/disarrain~.c
new file mode 100644
index 0000000..d0a7ff7
--- /dev/null
+++ b/disarrain~.c
@@ -0,0 +1,810 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *disarrain_class;
+#endif
+
+#if PD
+static t_class *disarrain_class;
+#endif
+
+#define OBJECT_NAME "disarrain~"
+
+
+typedef struct _disarrain
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ float *buffer;
+ float *channel;
+ float *last_channel;
+ float *composite_channel;
+ float *output;
+ int overlap;
+ int winfac;
+ //
+
+ int *shuffle_mapping;
+ int *last_shuffle_mapping;
+ int *shuffle_tmp; // work space for making a new distribution
+ int shuffle_count;// number of bins to swap
+ int last_shuffle_count;// ditto from last shuffle mapping
+ int max_bin;
+ //
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ //
+ void *list_outlet;
+ t_atom *list_data;
+ short mute;
+ short bypass;
+ float frame_duration; // duration in seconds of a single frame
+ float interpolation_duration; // duration in seconds of interpolation
+ int interpolation_frames; // number of frames to interpolate
+ int frame_countdown; // keep track of position in interpolation
+ int overlap_factor;// determines window size, etc.
+ float top_frequency;// for remapping spectrum
+ int perform_method;// 0 for lean, 1 for full conversion
+ // for convert
+// float *c_lastphase_in;
+// float *c_lastphase_out;
+ float c_fundamental;
+ float c_factor_in;
+ float c_factor_out;
+ // check switching algorithm
+ short lock;// lock for switching mapping arrays, but not used now
+ short force_fade; // new fadetime set regardless of situation
+ short force_switch;// binds new distribution to change of bin count
+} t_disarrain;
+
+void *disarrain_new(t_symbol *msg, short argc, t_atom *argv);
+
+t_int *disarrain_perform_lean(t_int *w);
+t_int *disarrain_perform_full(t_int *w);
+void disarrain_dsp(t_disarrain *x, t_signal **sp, short *count);
+void disarrain_assist(t_disarrain *x, void *b, long m, long a, char *s);
+void disarrain_switch_count (t_disarrain *x, t_floatarg i);
+void disarrain_topfreq (t_disarrain *x, t_floatarg freq);
+void disarrain_fadetime (t_disarrain *x, t_floatarg f);
+void reset_shuffle( t_disarrain *x );
+void disarrain_showstate( t_disarrain *x );
+void disarrain_list (t_disarrain *x, t_symbol *msg, short argc, t_atom *argv);
+void disarrain_setstate (t_disarrain *x, t_symbol *msg, short argc, t_atom *argv);
+void disarrain_isetstate (t_disarrain *x, t_symbol *msg, short argc, t_atom *argv);
+int rand_index(int max);
+void disarrain_mute(t_disarrain *x, t_floatarg toggle);
+void disarrain_bypass(t_disarrain *x, t_floatarg toggle);
+void copy_shuffle_array(t_disarrain *x);
+void interpolate_frames_to_channel(t_disarrain *x);
+void disarrain_killfade(t_disarrain *x);
+void disarrain_forcefade(t_disarrain *x, t_floatarg toggle);
+void disarrain_init(t_disarrain *x, short initialized);
+void disarrain_free(t_disarrain *x);
+void disarrain_overlap(t_disarrain *x, t_floatarg o);
+void disarrain_winfac(t_disarrain *x, t_floatarg o);
+void disarrain_fftinfo(t_disarrain *x);
+void disarrain_force_switch(t_disarrain *x, t_floatarg toggle);
+
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&disarrain_class, (method)disarrain_new, (method)disarrain_free,
+ (short)sizeof(t_disarrain), 0, A_GIMME, 0);
+ addmess((method)disarrain_dsp, "dsp", A_CANT, 0);
+ addint((method)disarrain_switch_count);
+ addbang((method)reset_shuffle);
+ addmess((method)disarrain_showstate,"showstate",0);
+ addmess ((method)disarrain_list, "list", A_GIMME, 0);
+ addmess ((method)disarrain_setstate, "setstate", A_GIMME, 0);
+ addmess ((method)disarrain_isetstate, "isetstate", A_GIMME, 0);
+ addmess((method)disarrain_assist,"assist",A_CANT,0);
+ addmess ((method)disarrain_mute, "mute", A_FLOAT, 0);
+ addmess ((method)disarrain_topfreq, "topfreq", A_FLOAT, 0);
+ addmess ((method)disarrain_fadetime, "fadetime", A_FLOAT, 0);
+ addmess ((method)disarrain_bypass, "bypass", A_FLOAT, 0);
+ addmess ((method)disarrain_forcefade, "forcefade", A_FLOAT, 0);
+ addmess ((method)disarrain_force_switch, "force_switch", A_FLOAT, 0);
+ addmess ((method)disarrain_switch_count, "switch_count", A_FLOAT, 0);
+ addmess ((method)disarrain_killfade, "killfade", 0);
+ addmess ((method)reset_shuffle, "reset_shuffle", 0);
+
+ addmess((method)disarrain_overlap, "overlap", A_DEFFLOAT, 0);
+ addmess((method)disarrain_winfac, "winfac", A_DEFFLOAT, 0);
+ addmess((method)disarrain_fftinfo, "fftinfo", 0);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+#if PD
+void disarrain_tilde_setup(void)
+{
+ disarrain_class = class_new(gensym("disarrain~"), (t_newmethod)disarrain_new,
+ (t_method)disarrain_free ,sizeof(t_disarrain), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(disarrain_class, t_disarrain, x_f);
+ class_addmethod(disarrain_class, (t_method)disarrain_dsp, gensym("dsp"), 0);
+ class_addmethod(disarrain_class, (t_method)disarrain_showstate, gensym("showstate"), 0);
+ class_addmethod(disarrain_class, (t_method)disarrain_list, gensym("list"), A_GIMME, 0);
+ class_addmethod(disarrain_class, (t_method)disarrain_setstate, gensym("setstate"), A_GIMME, 0);
+ class_addmethod(disarrain_class, (t_method)disarrain_isetstate, gensym("isetstate"), A_GIMME, 0);
+
+ class_addmethod(disarrain_class, (t_method)disarrain_mute, gensym("mute"), A_FLOAT, 0);
+ class_addmethod(disarrain_class, (t_method)disarrain_topfreq, gensym("topfreq"), A_FLOAT, 0);
+ class_addmethod(disarrain_class, (t_method)disarrain_fadetime, gensym("fadetime"), A_FLOAT, 0);
+ class_addmethod(disarrain_class, (t_method)disarrain_bypass, gensym("bypass"), A_FLOAT, 0);
+ class_addmethod(disarrain_class, (t_method)disarrain_forcefade, gensym("forcefade"), A_FLOAT, 0);
+class_addmethod(disarrain_class, (t_method)disarrain_force_switch, gensym("force_switch"), A_FLOAT, 0);
+
+
+// class_addmethod(disarrain_class, (t_method)disarrain_killfade, gensym("reset"), A_FLOAT, 0);
+ class_addmethod(disarrain_class, (t_method)reset_shuffle, gensym("bang"), 0);
+ class_addmethod(disarrain_class, (t_method)reset_shuffle, gensym("reset_shuffle"), 0);
+ class_addmethod(disarrain_class, (t_method)disarrain_switch_count, gensym("switch_count"), A_FLOAT, 0);
+
+ class_addmethod(disarrain_class, (t_method)disarrain_overlap, gensym("overlap"), A_DEFFLOAT,0);
+ class_addmethod(disarrain_class, (t_method)disarrain_winfac, gensym("winfac"), A_DEFFLOAT,0);
+ class_addmethod(disarrain_class, (t_method)disarrain_fftinfo, gensym("fftinfo"), 0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+void disarrain_free(t_disarrain *x)
+{
+#if MSP
+ dsp_free((t_pxobject *) x);
+#endif
+ freebytes(x->Wanal, x->Nw * sizeof(float));
+ freebytes(x->Wsyn, x->Nw * sizeof(float));
+ freebytes(x->input, x->Nw * sizeof(float));
+ freebytes(x->Hwin, x->Nw * sizeof(float));
+ freebytes(x->buffer, x->N * sizeof(float));
+ freebytes(x->channel, (x->N+2) * sizeof(float));
+ freebytes(x->last_channel, (x->N+2) * sizeof(float));
+ freebytes(x->composite_channel, x->N+2 * sizeof(float));
+ freebytes(x->output, x->Nw * sizeof(float));
+ freebytes(x->bitshuffle, (x->N * 2) * sizeof(int));
+ freebytes(x->trigland, x->N * 2 * sizeof(float));
+ freebytes(x->shuffle_mapping, x->N2 * sizeof(int)) ;
+ freebytes(x->last_shuffle_mapping, x->N2 * sizeof(int)) ;
+ freebytes(x->shuffle_tmp, x->N2 * sizeof(int)) ;
+ freebytes(x->list_data,(x->N+2) * sizeof(t_atom)) ;
+// freebytes(x->c_lastphase_in, (x->N2+1)*sizeof(float));
+// freebytes(x->c_lastphase_out,(x->N2+1)* sizeof(float));
+}
+
+
+
+void disarrain_init(t_disarrain *x, short initialized)
+{
+ int i;
+ float curfreq;
+
+ if(!power_of_two(x->winfac)){
+ x->winfac = 1;
+ }
+ if(!power_of_two(x->overlap)){
+ x->overlap = 4;
+ }
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->c_fundamental = (float) x->R/(float)( (x->N2)<<1 );
+ x->c_factor_in = (float) x->R/((float)x->D * TWOPI);
+ x->c_factor_out = TWOPI * (float) x->D / (float) x->R;
+
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+
+ x->lock = 1; // not good enough
+
+ if(initialized == 0){
+ x->Wanal = (float *) calloc(MAX_Nw , sizeof(float));
+ x->Wsyn = (float *) calloc(MAX_Nw , sizeof(float));
+ x->input = (float *) calloc(MAX_Nw , sizeof(float));
+ x->Hwin = (float *) calloc(MAX_Nw , sizeof(float));
+ x->buffer = (float *) calloc(MAX_N , sizeof(float));
+ x->channel = (float *) calloc(MAX_N+2 , sizeof(float));
+ x->last_channel = (float *) calloc(MAX_N+2 , sizeof(float));
+ x->composite_channel = (float *) calloc(MAX_N+2 , sizeof(float));
+ x->output = (float *) calloc(MAX_Nw , sizeof(float));
+ x->bitshuffle = (int *) calloc((MAX_N * 2) , sizeof(int));
+ x->trigland = (float *) calloc(MAX_N * 2 , sizeof(float));
+ x->shuffle_mapping = (int *) calloc( MAX_N2 , sizeof(int) ) ;
+ x->last_shuffle_mapping = (int *) calloc( MAX_N2 , sizeof(int) ) ;
+ x->shuffle_tmp = (int *) calloc( MAX_N2 , sizeof(int) ) ;
+ x->list_data = (t_atom *) calloc((MAX_N+2) , sizeof(t_atom) ) ;
+ x->mute = 0;
+ x->bypass = 0;
+ x->force_fade = 0;
+ x->interpolation_duration = 0.1; //seconds
+ }
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ memset((char *)x->buffer,0,x->N * sizeof(float));
+ memset((char *)x->channel,0,(x->N+2) * sizeof(float));
+ memset((char *)x->last_channel,0,(x->N+2) * sizeof(float));
+
+
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makewindows( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D);
+
+
+ if(initialized != 2){
+ if( x->top_frequency < x->c_fundamental || x->top_frequency > 20000) {
+ x->top_frequency = 1000.0 ;
+ }
+ x->max_bin = 1;
+ curfreq = 0;
+ while( curfreq < x->top_frequency ) {
+ ++(x->max_bin);
+ curfreq += x->c_fundamental ;
+ }
+ for( i = 0; i < x->N2; i++ ) {
+ x->shuffle_mapping[i] = x->last_shuffle_mapping[i] = i*2;
+ }
+ reset_shuffle(x); // set shuffle lookup
+ copy_shuffle_array(x);// copy it to the last lookup (for interpolation)
+ x->frame_duration = (float) x->D / (float) x->R;
+ x->interpolation_frames = x->interpolation_duration / x->frame_duration;
+ x->frame_countdown = 0;
+ x->shuffle_count = 0;
+ x->last_shuffle_count = 0;
+ }
+ x->lock = 0;
+ }
+
+
+void disarrain_force_switch(t_disarrain *x, t_floatarg f)
+{
+ x->force_switch = (short)f;
+}
+
+void disarrain_fadetime (t_disarrain *x, t_floatarg f)
+{
+ int frames;
+ float duration;
+
+ // forcefade allows forcing new fadetime at any time
+ if(! x->force_fade) {
+#if MSP
+ if(!sys_getdspstate()){
+ return; // DSP is inactive
+ }
+#endif
+ if(x->frame_countdown) {
+ error("disarrain: fade in progress, fadetime reset blocked");
+ return;
+ }
+ }
+
+ duration = f * .001;
+ frames = duration / x->frame_duration;
+ if( frames <= 1){
+ error("%s: too short fade",OBJECT_NAME);
+ return;
+ }
+ x->interpolation_duration = f * .001;
+ x->interpolation_frames = frames;
+
+}
+
+void disarrain_killfade(t_disarrain *x)
+{
+ x->frame_countdown = 0;
+
+}
+
+void disarrain_topfreq (t_disarrain *x, t_floatarg freq)
+{
+ float funda = (float) x->R / (2. * (float) x->N) ;
+ float curfreq;
+
+ if( freq < funda || freq > 20000) {
+ freq = 1000.0 ;
+ }
+ x->max_bin = 1;
+ curfreq = 0;
+ while( curfreq < freq ) {
+ ++(x->max_bin);
+ curfreq += funda ;
+ }
+}
+
+void disarrain_assist (t_disarrain *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0: sprintf(dst,"(signal) Input"); break;
+ }
+ } else if (msg==2) {
+ switch (arg) {
+ case 0: sprintf(dst,"(signal) Output"); break;
+ case 1: sprintf(dst,"(signal) Interpolation Sync"); break;
+ case 2: sprintf(dst,"(list) Current State"); break;
+ }
+ }
+}
+
+void *disarrain_new(t_symbol *msg, short argc, t_atom *argv)
+{
+
+#if MSP
+ t_disarrain *x = (t_disarrain *)newobject(disarrain_class);
+ x->list_outlet = listout((t_pxobject *)x);
+ dsp_setup((t_pxobject *)x,1);
+ outlet_new((t_pxobject *)x, "signal");
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+
+#if PD
+ t_disarrain *x = (t_disarrain *)pd_new(disarrain_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->list_outlet = outlet_new(&x->x_obj,gensym("list"));
+#endif
+
+ srand(time(0));
+
+ x->D = sys_getblksize();
+ x->R = sys_getsr();
+ x->top_frequency = atom_getfloatarg(0,argc,argv);
+ x->overlap_factor = atom_getintarg(1,argc,argv);
+ x->winfac = atom_getintarg(2,argc,argv);
+
+ disarrain_init(x,0);
+ return (x);
+}
+
+void disarrain_forcefade(t_disarrain *x, t_floatarg toggle)
+{
+ x->force_fade = (short)toggle;
+}
+
+void disarrain_mute(t_disarrain *x, t_floatarg toggle)
+{
+ x->mute = (short)toggle;
+}
+
+void disarrain_bypass(t_disarrain *x, t_floatarg toggle)
+{
+ x->bypass = (short)toggle;
+}
+
+void disarrain_overlap(t_disarrain *x, t_floatarg df)
+{
+int o = (int)df;
+ if(!power_of_two(o)){
+ error("%d is not a power of two",o);
+ return;
+ }
+ x->overlap = (int)o;
+ disarrain_init(x,1);
+}
+
+void disarrain_winfac(t_disarrain *x, t_floatarg f)
+{
+int wf = (int)f;
+ if(!power_of_two(wf)){
+ error("%f is not a power of two",wf);
+ return;
+ }
+ x->winfac = wf;
+ disarrain_init(x,2); /* calling lighter reinit routine */
+}
+
+void disarrain_fftinfo( t_disarrain *x )
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+
+// lean convert perform method
+t_int *disarrain_perform_lean(t_int *w)
+{
+ t_disarrain *x = (t_disarrain *) (w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ t_float *vec_sync = (t_float *)(w[4]);
+ int n = w[5];
+ int R = x->R;
+ int Nw = x->Nw;
+ int N = x->N ;
+ int N2 = x-> N2;
+ int Nw2 = x->Nw2;
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *Hwin = x->Hwin;
+
+ float *input = x->input;
+ float *output = x->output;
+ float *buffer = x->buffer;
+ float *channel = x->channel;
+ float *last_channel = x->last_channel;
+ int i,j;
+ int inCount = x->inCount;
+
+ int D = x->D;
+ float tmp;
+ float ival = 0.0;
+ int *shuffle_mapping = x->shuffle_mapping;
+ int shuffle_count = x->shuffle_count;
+ int *last_shuffle_mapping = x->last_shuffle_mapping;
+ int last_shuffle_count = x->last_shuffle_count;
+ float mult = x->mult ;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland ;
+ int frame_countdown = x->frame_countdown; // will read from variable
+ int interpolation_frames = x->interpolation_frames;
+ if( x->mute || x->lock ){
+ while( n-- ){
+ *out++ = 0.0;
+ }
+ return (w+6);
+ }
+ if( x->bypass ){
+ while( n-- ){
+ *out++ = *in++ * 0.5; // gain compensation
+ }
+ return (w+6);
+ }
+
+ inCount += D;
+
+ for ( j = 0 ; j < Nw - D ; j++ ){
+ input[j] = input[j+D];
+ }
+ for ( j = Nw - D; j < Nw; j++ ) {
+ input[j] = *in++;
+ }
+
+ fold(input, Wanal, Nw, buffer, N, inCount);
+ rdft(N, 1, buffer, bitshuffle, trigland);
+
+ leanconvert(buffer, channel, N2);
+
+ // first time for interpolation, just do last frame
+
+ if(frame_countdown == interpolation_frames){
+
+ for( i = 0, j = 0; i < last_shuffle_count ; i++, j+=2){
+ tmp = channel[j];
+ channel[j] = channel[last_shuffle_mapping[i]];
+ channel[last_shuffle_mapping[i]] = tmp;
+ }
+ --frame_countdown;
+ }
+ else if( frame_countdown > 0 ){
+ ival = (float)frame_countdown/(float)interpolation_frames;
+ // copy current frame to lastframe
+ for(j = 0; j < N; j+=2){
+ last_channel[j] = channel[j];
+ }
+ // make last frame swap
+ for(i = 0, j = 0; i < last_shuffle_count ; i++, j+=2){
+ tmp = last_channel[j];
+ last_channel[j] = last_channel[last_shuffle_mapping[i]];
+ last_channel[last_shuffle_mapping[i]] = tmp;
+
+ }
+ // make current frame swap
+ for( i = 0, j = 0; i < shuffle_count ; i++, j+=2){
+ tmp = channel[j];
+ channel[j] = channel[shuffle_mapping[i]];
+ channel[shuffle_mapping[i]] = tmp;
+
+ }
+ // now interpolate between the two
+
+ for(j = 0; j < N; j+=2){
+ channel[j] = channel[j] + ival * (last_channel[j] - channel[j]);
+ }
+
+ --frame_countdown;
+ if(frame_countdown <= 0){
+ copy_shuffle_array(x);
+ }
+ } else {
+ // otherwise straight swapping
+ for( i = 0, j = 0; i < shuffle_count ; i++, j+=2){
+ tmp = channel[j];
+ channel[j] = channel[ shuffle_mapping[i]];
+ channel[shuffle_mapping[i]] = tmp;
+ }
+ }
+ leanunconvert( channel, buffer, N2 );
+
+ rdft( N, -1, buffer, bitshuffle, trigland );
+ overlapadd( buffer, N, Wsyn, output, Nw, inCount);
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+/* send out sync signal */
+ for(j = 0; j < n; j++){
+ vec_sync[j] = ival;
+ }
+ /* restore state variables */
+ x->inCount = inCount % Nw;
+ x->frame_countdown = frame_countdown;
+ return (w+6);
+}
+
+
+void interpolate_frames_to_channel(t_disarrain *x)
+{
+ float ival;
+ float tmp;
+ int i,j;
+ int frame_countdown = x->frame_countdown;
+ int interpolation_frames = x->interpolation_frames;
+ float *channel = x->channel;
+ float *last_channel = x->last_channel;
+ int *shuffle_mapping = x->shuffle_mapping;
+ int shuffle_count = x->shuffle_count;
+ int *last_shuffle_mapping = x->shuffle_mapping;
+ int last_shuffle_count = x->shuffle_count;
+ int local_max_bins;
+ int N = x->N;
+
+ ival = (float)frame_countdown/(float)interpolation_frames;
+
+// post("interpolation:%f",ival);
+ local_max_bins = (shuffle_count > last_shuffle_count)? shuffle_count : last_shuffle_count;
+ // copy channel (only amplitudes)
+ for(j = 0; j < N; j+=2){
+ last_channel[j] = channel[j];
+ }
+ // make last frame
+ for( i = 0, j = 0; i < last_shuffle_count ; i++, j+=2){
+ tmp = last_channel[j];
+ last_channel[j] = last_channel[last_shuffle_mapping[i]];
+ last_channel[last_shuffle_mapping[i]] = tmp;
+ }
+ // make current frame
+ for( i = 0, j = 0; i < shuffle_count ; i++, j+=2){
+ tmp = channel[j];
+ channel[j] = channel[shuffle_mapping[i]];
+ channel[shuffle_mapping[i]] = tmp;
+ }
+ // now interpolate between the two
+
+ for(j = 0; j < N; j+=2){
+ // channel[j] = channel[j] + ival * (last_channel[j] - channel[j]);
+
+ // or better?
+ channel[j] += ival * (last_channel[j] - channel[j]);
+ }
+}
+
+
+void disarrain_switch_count (t_disarrain *x, t_floatarg f)
+{
+int i = f;
+/*
+#if MSP
+ if(! sys_getdspstate()){
+ return; // DSP is inactive
+ }
+#endif
+*/
+ if( x->frame_countdown && !x->force_fade){
+ error("%s: fade in progress, no action taken",OBJECT_NAME);
+ return;
+ }
+ if( i < 0 ){
+ i = 0;
+ }
+ if( i > x->N2 ) {
+ i = x->N2;
+ }
+ copy_shuffle_array(x);
+ x->last_shuffle_count = x->shuffle_count;
+ x->shuffle_count = i;
+ x->frame_countdown = x->interpolation_frames; // force interpolation
+}
+
+
+void reset_shuffle (t_disarrain *x)
+{
+ int i;
+ int temp, p1, p2;
+ int max = x->max_bin;
+ int N2 = x->N2;
+
+ int *shuffle_tmp = x->shuffle_tmp;
+ int *shuffle_mapping = x->shuffle_mapping;
+
+
+ copy_shuffle_array(x);
+
+ for( i = 0; i < N2; i++ ) {
+ shuffle_tmp[i] = i;
+ }
+ // improve this algorithm
+
+ for( i = 0; i < max; i++ ) {
+ p1 = shuffle_tmp[ rand_index( max ) ];
+ p2 = shuffle_tmp[ rand_index( max ) ];
+ temp = shuffle_tmp[p1];
+ shuffle_tmp[ p1 ] = shuffle_tmp[ p2 ];
+ shuffle_tmp[ p2 ] = temp;
+ }
+
+
+
+ // now map to amplitude channels
+ for( i = 0; i < N2; i++ ) {
+ shuffle_tmp[i] *= 2;
+ }
+
+ // force interpolation
+ x->frame_countdown = x->interpolation_frames;
+
+ x->lock = 1;
+ for( i = 0; i < N2; i++ ) {
+ shuffle_mapping[i] = shuffle_tmp[i];
+ }
+
+ x->lock = 0;
+}
+
+void copy_shuffle_array(t_disarrain *x)
+{
+ int i;
+ int N2 = x->N2;
+ int *shuffle_mapping = x->shuffle_mapping;
+ int *last_shuffle_mapping = x->last_shuffle_mapping;
+
+
+ for(i = 0; i<N2; i++){
+ last_shuffle_mapping[i] = shuffle_mapping[i];
+ }
+ x->last_shuffle_count = x->shuffle_count;
+
+}
+
+int rand_index(int max) {
+
+ return (rand() % max);
+}
+
+void disarrain_dsp(t_disarrain *x, t_signal **sp, short *count)
+{
+ long i;
+
+ if(x->D != sp[0]->s_n ||x->D != sp[0]->s_n ) {
+ x->R = sp[0]->s_sr;
+ x->D = sp[0]->s_n;
+ disarrain_init(x,1);
+ }
+
+ dsp_add(disarrain_perform_lean, 5, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+
+}
+
+// ENTER STORED SHUFFLE
+void disarrain_list (t_disarrain *x, t_symbol *msg, short argc, t_atom *argv) {
+ short i;
+ int ival;
+// post("list message called");
+ x->shuffle_count = argc;
+// post("list: count now %d",x->shuffle_count );
+ for (i=0; i < argc; i++) {
+ #if MSP
+ ival = argv[i].a_w.w_long;
+ #endif
+
+ #if PD
+ ival = atom_getfloatarg(i,argc,argv);
+ #endif
+ if (ival < x->N2) {
+ x->shuffle_mapping[i] = ival;
+// post("set %d to %d",i, x->shuffle_mapping[ i ]);
+ } else {
+// post ("%d out of range",ival);
+ }
+
+ }
+// post("last val is %d", x->shuffle_mapping[argc - 1]);
+ return;
+}
+
+
+void disarrain_isetstate (t_disarrain *x, t_symbol *msg, short argc, t_atom *argv) {
+ short i;
+ int ival;
+
+// x->last_shuffle_count = x->shuffle_count;
+
+ copy_shuffle_array(x);
+ x->shuffle_count = argc;
+
+
+// x->lock = 1;
+
+ for (i=0; i < argc; i++) {
+ ival = 2 * atom_getfloatarg(i,argc,argv);
+
+ if ( ival < x->N2 && ival >= 0) {
+ x->shuffle_mapping[ i ] = ival;
+ }else {
+ error("%s: %d is out of range",OBJECT_NAME, ival);
+ }
+ }
+
+// x->lock = 0;
+ x->frame_countdown = x->interpolation_frames;
+
+ return;
+}
+
+void disarrain_setstate (t_disarrain *x, t_symbol *msg, short argc, t_atom *argv) {
+ short i;
+ int ival;
+
+ x->shuffle_count = argc;
+ for (i=0; i < argc; i++) {
+ ival = 2 *atom_getfloatarg(i,argc,argv);
+
+ if ( ival < x->N2 && ival >= 0) {
+ x->shuffle_mapping[ i ] = ival;
+ } else {
+ error("%s: %d is out of range",OBJECT_NAME, ival);
+ }
+ }
+ return;
+}
+
+// REPORT CURRENT SHUFFLE STATUS
+void disarrain_showstate (t_disarrain *x ) {
+
+ t_atom *list_data = x->list_data;
+
+ short i;
+#if MSP
+ for( i = 0; i < x->shuffle_count; i++ ) {
+ SETLONG(list_data+i,x->shuffle_mapping[i]/2);
+ }
+#endif
+
+#if PD
+ for( i = 0; i < x->shuffle_count; i++ ) {
+ SETFLOAT(list_data+i,(float)x->shuffle_mapping[i]/2);
+ }
+#endif
+ outlet_list(x->list_outlet,0,x->shuffle_count,list_data);
+
+ return;
+}
+
diff --git a/disarray~.c b/disarray~.c
new file mode 100644
index 0000000..c115857
--- /dev/null
+++ b/disarray~.c
@@ -0,0 +1,526 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#define MEMPAD (1024)
+
+#if MSP
+void *disarray_class;
+#endif
+
+#if PD
+static t_class *disarray_class;
+#endif
+
+#define OBJECT_NAME "disarray~"
+
+
+typedef struct _disarray
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ float *buffer;
+ float *channel;
+ float *output;
+ //
+ int *shuffle_in;
+ int *shuffle_out;
+ int shuffle_count;
+ int max_bin;
+ //
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ //
+ float top_frequency;
+ int overlap;
+ int winfac;
+ float c_fundamental;
+
+ //
+ void *list_outlet;
+ t_atom *list_data;
+ short mute;
+ short bypass;
+ short lock;
+} t_disarray;
+
+void *disarray_new(t_symbol *msg, short argc, t_atom *argv);
+t_int *offset_perform(t_int *w);
+t_int *disarray_perform(t_int *w);
+void disarray_dsp(t_disarray *x, t_signal **sp, short *count);
+void disarray_assist(t_disarray *x, void *b, long m, long a, char *s);
+void switch_count (t_disarray *x, t_floatarg i);
+void iswitch_count (t_disarray *x, t_int i);
+void disarray_topfreq (t_disarray *x, t_floatarg freq);
+void reset_shuffle( t_disarray *x );
+void disarray_showstate( t_disarray *x );
+void disarray_list (t_disarray *x, t_symbol *msg, short argc, t_atom *argv);
+void disarray_setstate (t_disarray *x, t_symbol *msg, short argc, t_atom *argv);
+int rand_index( int max);
+void disarray_mute(t_disarray *x, t_floatarg toggle);
+void disarray_bypass(t_disarray *x, t_floatarg toggle);
+void disarray_tilde_setup(void);
+void disarray_free(t_disarray *x);
+
+void disarray_overlap(t_disarray *x, t_floatarg o);
+void disarray_winfac(t_disarray *x, t_floatarg o);
+void disarray_fftinfo(t_disarray *x);
+void disarray_init(t_disarray *x, short initialized);
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&disarray_class, (method)disarray_new,
+ (method)disarray_free, (short)sizeof(t_disarray), 0, A_GIMME, 0);
+ addmess((method)disarray_dsp, "dsp", A_CANT, 0);
+ addint((method)iswitch_count);
+ addbang((method)reset_shuffle);
+ addmess((method)disarray_showstate,"showstate",0);
+ addmess ((method)disarray_list, "list", A_GIMME, 0);
+ addmess ((method)disarray_setstate, "setstate", A_GIMME, 0);
+ addmess((method)disarray_assist,"assist",A_CANT,0);
+ addmess ((method)disarray_mute, "mute", A_FLOAT, 0);
+ addmess ((method)disarray_topfreq, "topfreq", A_FLOAT, 0);
+ addmess ((method)disarray_bypass, "bypass", A_LONG, 0);
+ addmess((method)disarray_overlap, "overlap", A_DEFFLOAT, 0);
+ addmess((method)disarray_winfac, "winfac", A_DEFFLOAT, 0);
+ addmess((method)switch_count, "switch_count", A_DEFFLOAT, 0);
+ addmess((method)disarray_fftinfo, "fftinfo", 0);
+
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+#if PD
+void disarray_tilde_setup(void)
+{
+ disarray_class = class_new(gensym("disarray~"), (t_newmethod)disarray_new,
+ (t_method)disarray_free ,sizeof(t_disarray), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(disarray_class, t_disarray, x_f);
+ class_addmethod(disarray_class, (t_method)disarray_dsp, gensym("dsp"), 0);
+ class_addmethod(disarray_class, (t_method)disarray_showstate, gensym("showstate"), 0);
+ class_addmethod(disarray_class, (t_method)disarray_list, gensym("list"), A_GIMME, 0);
+ class_addmethod(disarray_class, (t_method)disarray_mute, gensym("mute"), A_FLOAT, 0);
+ class_addmethod(disarray_class, (t_method)disarray_topfreq, gensym("topfreq"), A_FLOAT, 0);
+ class_addmethod(disarray_class, (t_method)switch_count, gensym("switch_count"), A_FLOAT, 0);
+ class_addmethod(disarray_class, (t_method)reset_shuffle, gensym("bang"), 0);
+ class_addmethod(disarray_class, (t_method)disarray_overlap, gensym("overlap"), A_DEFFLOAT,0);
+ class_addmethod(disarray_class, (t_method)disarray_winfac, gensym("winfac"), A_DEFFLOAT,0);
+ class_addmethod(disarray_class, (t_method)disarray_fftinfo, gensym("fftinfo"), 0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+void disarray_free(t_disarray *x)
+{
+#if MSP
+ dsp_free((t_pxobject *) x);
+#endif
+ free(x->Wanal);
+ free(x->Wsyn);
+ free(x->input);
+ free(x->Hwin);
+ free(x->buffer);
+ free(x->channel);
+ free(x->output);
+ free(x->bitshuffle);
+ free(x->trigland);
+ free(x->list_data) ;
+}
+
+
+void disarray_overlap(t_disarray *x, t_floatarg o)
+{
+ if(!power_of_two(o)){
+ error("%f is not a power of two",o);
+ return;
+ }
+ x->overlap = (int)o;
+ disarray_init(x,1);
+}
+
+void disarray_winfac(t_disarray *x, t_floatarg f)
+{
+ if(!power_of_two(f)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = (int)f;
+ disarray_init(x,2); /* calling lighter reinit routine */
+}
+
+void disarray_fftinfo( t_disarray *x )
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+void disarray_topfreq (t_disarray *x, t_floatarg freq)
+{
+ float funda = (float) x->R / (2. * (float) x->N) ;
+ float curfreq;
+
+
+ if( freq < funda || freq > 20000) {
+ freq = 1000.0 ;
+ }
+ x->max_bin = 1;
+ curfreq = 0;
+ while( curfreq < freq ) {
+ ++(x->max_bin);
+ curfreq += funda ;
+ }
+
+}
+
+void disarray_assist (t_disarray *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0: sprintf(dst,"(signal) Input "); break;
+ }
+ } else if (msg==2) {
+ switch (arg) {
+ case 0: sprintf(dst,"(signal) Output "); break;
+ case 1: sprintf(dst,"(list) Current State "); break;
+ }
+ }
+}
+
+void *disarray_new(t_symbol *msg, short argc, t_atom *argv)
+{
+#if MSP
+ t_disarray *x = (t_disarray *)newobject(disarray_class);
+ x->list_outlet = listout((t_pxobject *)x);
+ dsp_setup((t_pxobject *)x,1);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+
+#if PD
+ t_disarray *x = (t_disarray *)pd_new(disarray_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->list_outlet = outlet_new(&x->x_obj,gensym("list"));
+#endif
+
+// INITIALIZATIONS
+
+
+ srand( time( 0 ) );
+
+ x->D = sys_getblksize();
+ x->R = sys_getsr();
+ x->top_frequency = atom_getfloatarg(0,argc,argv);
+ x->overlap = atom_getintarg(1,argc,argv);
+ x->winfac = atom_getintarg(2,argc,argv);
+
+ if(!power_of_two(x->overlap))
+ x->overlap = 4;
+ if(!power_of_two(x->winfac))
+ x->winfac = 1;
+ disarray_init(x,0);
+ return (x);
+}
+
+
+void disarray_init(t_disarray *x, short initialized)
+{
+ int i;
+ float curfreq;
+
+
+ if(!power_of_two(x->winfac)){
+ x->winfac = 1;
+ }
+ if(!power_of_two(x->overlap)){
+ x->overlap = 4;
+ }
+
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+
+ x->c_fundamental = (float) x->R/(float)( (x->N2)<<1 );
+ x->mult = 1. / (float) x->N;
+
+ x->lock = 1;
+
+ if(initialized == 0){
+ x->Wanal = (float *) calloc( (MAX_Nw) , sizeof(float));
+ x->Wsyn = (float *) calloc( (MAX_Nw), sizeof(float));
+ x->input = (float *) calloc( (MAX_Nw), sizeof(float));
+ x->Hwin = (float *) calloc( (MAX_Nw), sizeof(float));
+ x->output = (float *) calloc( (MAX_Nw) , sizeof(float));
+ x->buffer = (float *) calloc( (MAX_N), sizeof(float));
+ x->channel = (float *) calloc( ((MAX_N+2)) , sizeof(float));
+ x->bitshuffle = (int *) calloc( ((MAX_N * 2)) , sizeof(int));
+ x->trigland = (float *) calloc( ((MAX_N * 2)) , sizeof(float));
+ x->shuffle_in = (int *) calloc( (MAX_N2), sizeof(int) ) ;
+ x->shuffle_out = (int *) calloc( (MAX_N2), sizeof(int) ) ;
+ x->list_data = (t_atom *) calloc( ((MAX_N+2)) , sizeof(t_atom) ) ;
+ x->mute = 0;
+ x->bypass = 0;
+ x->shuffle_count = 0;
+
+ } else {
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ memset((char *)x->buffer,0,x->N * sizeof(float));
+ memset((char *)x->channel,0,(x->N+2) * sizeof(float));
+ }
+
+
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makewindows( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D);
+
+
+ if(initialized != 2){
+ if( x->top_frequency < x->c_fundamental || x->top_frequency > 20000) {
+ x->top_frequency = 1000.0 ;
+ }
+ x->max_bin = 1;
+ curfreq = 0;
+ while( curfreq < x->top_frequency ) {
+ ++(x->max_bin);
+ curfreq += x->c_fundamental ;
+ }
+
+ reset_shuffle(x); // set shuffle lookup
+ x->shuffle_count = 0;
+ }
+ x->lock = 0;
+}
+
+
+void disarray_mute(t_disarray *x, t_floatarg toggle)
+{
+ x->mute = (short)toggle;
+// post("muted: %d", x->mute);
+}
+
+void disarray_bypass(t_disarray *x, t_floatarg toggle)
+{
+ x->bypass = (short)toggle;
+}
+
+
+t_int *disarray_perform(t_int *w)
+{
+ t_disarray *x = (t_disarray *) (w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = w[4];
+
+ int R = x->R;
+ int Nw = x->Nw;
+ int N = x->N ;
+ int N2 = x-> N2;
+ int Nw2 = x->Nw2;
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *Hwin = x->Hwin;
+
+ float *input = x->input;
+ float *output = x->output;
+ float *buffer = x->buffer;
+ float *channel = x->channel;
+ int i,j;
+ int inCount = x->inCount;
+
+ int D = x->D;
+ float tmp;
+
+ int shuffle_count = x->shuffle_count;
+
+ float mult = x->mult ;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland ;
+ int *shuffle_in = x->shuffle_in;
+ int *shuffle_out = x->shuffle_out;
+
+ if( x->mute || x->lock ){
+ while( n-- ){
+ *out++ = 0.0;
+ }
+ return (w+5);
+ }
+
+ if( x->bypass ){
+ while( n-- ){
+ *out++ = *in++ * 0.5; // gain compensation
+ }
+ return (w+5);
+ }
+
+ inCount += D;
+
+ for ( j = 0 ; j < Nw - D ; j++ ){
+ input[j] = input[j+D];
+ }
+ for ( j = Nw - D; j < Nw; j++ ) {
+ input[j] = *in++;
+ }
+
+ fold(input, Wanal, Nw, buffer, N, inCount);
+ rdft(N, 1, buffer, bitshuffle, trigland);
+
+ leanconvert(buffer, channel, N2);
+
+ for( i = 0; i < shuffle_count ; i++){
+ tmp = channel[ shuffle_in[ i ] * 2 ];
+ channel[ shuffle_in[ i ] * 2] = channel[ shuffle_out[ i ] * 2];
+ channel[ shuffle_out[ i ] * 2] = tmp;
+ }
+
+ leanunconvert( channel, buffer, N2 );
+
+ rdft( N, -1, buffer, bitshuffle, trigland );
+ overlapadd( buffer, N, Wsyn, output, Nw, inCount);
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+ /* restore state variables */
+ x->inCount = inCount % Nw;
+
+ return (w+5);
+}
+
+void iswitch_count(t_disarray *x, t_int i)
+{
+ switch_count(x,(t_floatarg)i);
+}
+
+void switch_count (t_disarray *x, t_floatarg i)
+{
+ if( i < 0 ){
+ i = 0;
+ }
+ if( i > x->N2 ) {
+ i = x->N2;
+ }
+ x->shuffle_count = i;
+}
+
+void reset_shuffle (t_disarray *x)
+{
+int i;
+int temp, p1, p2;
+int max;
+
+//post("max bin %d",x->max_bin);
+max = x->max_bin;
+ for( i = 0; i < x->N2; i++ ) {
+ x->shuffle_out[i] = x->shuffle_in[i] = i ;
+ }
+
+ for( i = 0; i < 10000; i++ ) {
+ p1 = x->shuffle_out[ rand_index( max ) ];
+ p2 = x->shuffle_out[ rand_index( max ) ];
+ temp = x->shuffle_out[ p1 ];
+ x->shuffle_out[ p1 ] = x->shuffle_out[ p2 ];
+ x->shuffle_out[ p2 ] = temp;
+ }
+
+}
+
+int rand_index( int max) {
+ return ( rand() % max );
+}
+
+void disarray_dsp(t_disarray *x, t_signal **sp, short *count)
+{
+
+ if(x->D != sp[0]->s_n ||x->D != sp[0]->s_n ) {
+ x->R = sp[0]->s_sr;
+ x->D = sp[0]->s_n;
+ disarray_init(x,1);
+ }
+ dsp_add(disarray_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+// ENTER STORED SHUFFLE
+void disarray_list (t_disarray *x, t_symbol *msg, short argc, t_atom *argv) {
+ short i;
+ int ival;
+ x->shuffle_count = argc;
+ for (i=0; i < argc; i++) {
+
+ ival = (int)atom_getfloatarg(i,argc,argv);
+
+
+ if ( ival < x->N2 ) {
+ x->shuffle_out[ i ] = ival;
+ } else {
+ post ("%d out of range",ival);
+ }
+ }
+ return;
+}
+
+void disarray_setstate (t_disarray *x, t_symbol *msg, short argc, t_atom *argv) {
+ short i;
+ int ival;
+
+ x->shuffle_count = argc;
+ for (i=0; i < argc; i++) {
+ ival = atom_getfloatarg(i,argc,argv);
+
+ if ( ival < x->N2 && ival >= 0) {
+ x->shuffle_out[ i ] = ival;
+ } else {
+ error("%s: %d is out of range",OBJECT_NAME, ival);
+ }
+ }
+ return;
+}
+
+// REPORT CURRENT SHUFFLE STATUS
+void disarray_showstate (t_disarray *x ) {
+
+ t_atom *list_data = x->list_data;
+
+ short i;
+#if MSP
+ for( i = 0; i < x->shuffle_count; i++ ) {
+ SETLONG(list_data+i,x->shuffle_out[i]);
+ }
+#endif
+
+#if PD
+ for( i = 0; i < x->shuffle_count; i++ ) {
+ SETFLOAT(list_data+i,(float)x->shuffle_out[i]);
+ }
+#endif
+ outlet_list(x->list_outlet,0,x->shuffle_count,list_data);
+
+ return;
+}
diff --git a/drown~.c b/drown~.c
new file mode 100644
index 0000000..b7fe734
--- /dev/null
+++ b/drown~.c
@@ -0,0 +1,424 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *drown_class;
+#endif
+
+#if PD
+static t_class *drown_class;
+#endif
+
+#define OBJECT_NAME "drown~"
+
+typedef struct _drown
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ float *buffer;
+ float *channel;
+ float *output;
+ float drownmult;
+ // float threshgen;
+ short mute;
+ float threshold;
+ // faster FFT
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+
+ short connected[8];
+ int overlap;//overlap factor
+ int winfac;//window factor
+ int vs;//vector size
+
+ short peakflag;// means threshold is relative to peak amp
+ //
+} t_drown;
+
+void *drown_new(t_symbol *s, int argc, t_atom *argv);
+void drown_mute(t_drown *x, t_floatarg toggle);
+void drown_rel2peak(t_drown *x, t_floatarg toggle);
+//t_int *offset_perform(t_int *w);
+t_int *drown_perform(t_int *w);
+void drown_dsp(t_drown *x, t_signal **sp, short *count);
+void drown_assist(t_drown *x, void *b, long m, long a, char *s);
+void nudist( float *S, float *C, float threshold, float fmult, int N2 );
+void drown_float(t_drown *x, double f);
+void drown_overlap(t_drown *x, t_floatarg o);
+void drown_free(t_drown *x);
+void drown_init(t_drown *x, short initialized);
+void drown_overlap(t_drown *x, t_floatarg f);
+void drown_winfac(t_drown *x, t_floatarg f);
+void drown_fftinfo(t_drown *x);
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&drown_class, (method)drown_new, (method)drown_free,
+ (short)sizeof(t_drown), 0, A_GIMME, 0);
+ addmess((method)drown_dsp, "dsp", A_CANT, 0);
+ addmess((method)drown_assist,"assist",A_CANT,0);
+ addmess((method)drown_mute,"mute",A_FLOAT,0);
+ addmess((method)drown_rel2peak,"rel2peak",A_FLOAT,0);
+ addmess((method)drown_overlap,"overlap",A_FLOAT,0);
+ addmess((method)drown_winfac,"winfac",A_FLOAT,0);
+ addmess((method)drown_fftinfo,"fftinfo",0);
+ addfloat((method)drown_float);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+#if MSP
+void drown_float(t_drown *x, double f) // Look at floats at inlets
+{
+
+ int inlet = x->x_obj.z_in;
+// post("drown: incoming float: %f",f);
+// post("inlet %d",inlet);
+ if (inlet == 1)
+ {
+ x->threshold = f;
+ }
+ if (inlet == 2)
+ {
+ x->drownmult = f;
+ }
+}
+#endif
+#if PD
+void drown_tilde_setup(void)
+{
+ drown_class = class_new(gensym("drown~"), (t_newmethod)drown_new,
+ (t_method)drown_free ,sizeof(t_drown), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(drown_class, t_drown, x_f);
+ class_addmethod(drown_class, (t_method)drown_dsp, gensym("dsp"), 0);
+ class_addmethod(drown_class, (t_method)drown_assist, gensym("assist"), 0);
+ class_addmethod(drown_class, (t_method)drown_mute, gensym("mute"), A_FLOAT,0);
+ class_addmethod(drown_class, (t_method)drown_overlap, gensym("overlap"), A_FLOAT,0);
+ class_addmethod(drown_class, (t_method)drown_rel2peak, gensym("rel2peak"), A_FLOAT,0);
+ class_addmethod(drown_class, (t_method)drown_overlap, gensym("overlap"), A_FLOAT,0);
+ class_addmethod(drown_class, (t_method)drown_winfac, gensym("winfac"), A_FLOAT,0);
+ class_addmethod(drown_class, (t_method)drown_fftinfo, gensym("fftinfo"), 0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+
+
+void drown_overlap(t_drown *x, t_floatarg f)
+{
+int i = (int) f;
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->overlap = i;
+ drown_init(x,1);
+}
+
+void drown_winfac(t_drown *x, t_floatarg f)
+{
+int i = (int)f;
+
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = i;
+ drown_init(x,2);
+}
+
+void drown_fftinfo(t_drown *x)
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+void drown_rel2peak(t_drown *x, t_floatarg toggle)
+{
+ x->peakflag = (short)toggle;
+}
+
+void drown_mute(t_drown *x, t_floatarg toggle)
+{
+ x->mute = (short)toggle;
+}
+
+void drown_assist (t_drown *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0: sprintf(dst,"(signal) Input"); break;
+ case 1: sprintf(dst,"(signal/float) Threshold Generator"); break;
+ case 2: sprintf(dst,"(signal/float) Multiplier for Weak Bins"); break;
+ }
+ } else if (msg==2) {
+ sprintf(dst,"(signal) Output");
+ }
+}
+
+void *drown_new(t_symbol *s, int argc, t_atom *argv)
+{
+#if MSP
+ t_drown *x = (t_drown *)newobject(drown_class);
+ dsp_setup((t_pxobject *)x,3);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+#if PD
+ t_drown *x = (t_drown *)pd_new(drown_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+ x->threshold = atom_getfloatarg(0,argc,argv);
+ x->drownmult = atom_getfloatarg(1,argc,argv);
+ x->overlap = atom_getfloatarg(2,argc,argv);
+ x->winfac = atom_getfloatarg(3,argc,argv);
+
+ if(x->threshold <= 0)
+ x->threshold = .0001;
+ if(x->drownmult <= 0)
+ x->drownmult = 0.1;
+ if(!power_of_two(x->overlap))
+ x->overlap = 4;
+ if(!power_of_two(x->winfac))
+ x->winfac = 1;
+
+ x->vs = sys_getblksize();
+ x->R = sys_getsr();
+
+ drown_init(x,0);
+ return (x);
+}
+
+void drown_init(t_drown *x, short initialized)
+{
+ int i;
+ int mem;
+
+ x->D = x->vs;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+
+ if(!initialized){
+ x->mute = 0;
+ x->peakflag = 0;
+ mem = (MAX_Nw) * sizeof(float);
+ x->input = (float *) getbytes(mem);
+ x->output = (float *) getbytes(mem);
+ x->Wanal = (float *) getbytes(mem);
+ x->Wsyn = (float *) getbytes(mem);
+ x->Hwin = (float *) getbytes(mem);
+ mem = (MAX_N) * sizeof(float);
+ x->buffer = (float *) getbytes(mem);
+ mem = (MAX_N+2) * sizeof(float);
+ x->channel = (float *) getbytes(mem);
+ mem = (MAX_N) * sizeof(int);
+ x->bitshuffle = (int *) getbytes(mem);
+ mem = (MAX_N) * sizeof(float);
+ x->trigland = (float *) getbytes(mem);
+ }
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+
+ makehanning( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 0);
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+}
+
+void drown_free(t_drown *x)
+{
+#if MSP
+ dsp_free((t_pxobject *) x);
+#endif
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->input,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->buffer,0);
+ freebytes(x->channel,0);
+ freebytes(x->output,0);
+}
+
+t_int *drown_perform(t_int *w)
+{
+ int i,j;
+ float frame_peak = 0.0;
+ float local_thresh;
+
+ t_drown *x = (t_drown *) (w[1]);
+ t_float *in = (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 n = w[6];
+
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *input = x->input;
+ float *Hwin = x->Hwin;
+ float *buffer = x->buffer;
+ float *channel = x->channel;
+ float *output = x->output;
+
+ int D = x->D;
+ int I = D;
+ int R = x->R;
+ int Nw = x->Nw;
+ int N = x->N ;
+ int N2 = x-> N2;
+ int Nw2 = x->Nw2;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland;
+ float mult = x->mult;
+ int inCount = x->inCount ;
+ int on = inCount;
+ float threshold = x->threshold;
+ float drownmult = x->drownmult;
+ short *connected = x->connected;
+ // get multiplier from sig inlet
+
+ /* dereference struncture */
+
+
+ if( x->mute ){
+ while( n-- ){
+ *out++ = 0.0;
+ }
+ return (w+7);
+ }
+
+ if( connected[1] )
+ threshold = *in2++ ;
+
+ if( connected[2] )
+ drownmult = *in3++ ;
+
+ inCount += D;
+
+
+ for ( j = 0 ; j < Nw - D ; j++ ){
+ input[j] = input[j+D];
+ }
+ for ( j = Nw - D; j < Nw; j++ ) {
+ input[j] = *in++;
+ }
+
+ fold( input, Wanal, Nw, buffer, N, inCount );
+
+ rdft(N, 1, buffer, bitshuffle, trigland);
+
+ if( x->peakflag ){
+ leanconvert( buffer, channel, N2);
+ for(i = 0; i <N; i+= 2){
+ if(frame_peak < channel[i])
+ frame_peak = channel[i];
+ }
+ local_thresh = frame_peak * threshold;
+ for(i = 0; i <N; i+= 2){
+ if(channel[i] < local_thresh)
+ channel[i] *= drownmult;
+ }
+ leanunconvert( channel, buffer, N2);
+ } else {
+ nudist( buffer, channel, threshold, drownmult, N2 );
+ }
+ rdft( N, -1, buffer, bitshuffle, trigland );
+
+ overlapadd( buffer, N, Wsyn, output, Nw, inCount);
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+
+
+ /* restore state variables */
+ x->inCount = inCount % Nw;
+ return (w+7);
+}
+
+void nudist( float *S, float *C, float threshold, float fmult, int N2 )
+
+{
+ int real, imag, amp, phase;
+ float a, b;
+ int i;
+ float maxamp = 1.;
+ for ( i = 0; i <= N2; i++ ) {
+ imag = phase = ( real = amp = i<<1 ) + 1;
+ a = ( i == N2 ? S[1] : S[real] );
+ b = ( i == 0 || i == N2 ? 0. : S[imag] );
+ C[amp] = hypot( a, b );
+
+ if ( (C[amp]) < threshold ){
+ C[amp] *= fmult;
+ }
+ C[phase] = -atan2( b, a );
+ }
+
+ for ( i = 0; i <= N2; i++ ) {
+ imag = phase = ( real = amp = i<<1 ) + 1;
+ S[real] = *(C+amp) * cos( *(C+phase) );
+ if ( i != N2 )
+ S[imag] = -*(C+amp) * sin( *(C+phase) );
+ }
+}
+
+void drown_dsp(t_drown *x, t_signal **sp, short *count)
+{
+ long i;
+#if MSP
+ for( i = 0; i < 4; i++ ){
+ x->connected[i] = count[i];
+ }
+#endif
+#if PD
+ for( i = 0; i < 4; i++ ){
+ x->connected[i] = 1;
+ }
+#endif
+
+ if(x->vs != sp[0]->s_n || x->R != sp[0]->s_sr){
+ x->vs = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ drown_init(x,1);
+ }
+ dsp_add(drown_perform, 6, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,
+ sp[3]->s_vec, sp[0]->s_n);
+}
+
diff --git a/ether~.c b/ether~.c
new file mode 100644
index 0000000..4293676
--- /dev/null
+++ b/ether~.c
@@ -0,0 +1,514 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *ether_class;
+#endif
+#if PD
+static t_class *ether_class;
+#endif
+
+#define OBJECT_NAME "ether~"
+
+
+/* Added a new inlet for the composite index */
+
+typedef struct _ether
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ int invert;
+ int *bitshuffle;
+
+ float threshMult;
+ float *Wanal;
+ float *Wsyn;
+ float *inputOne;
+ float *inputTwo;
+ float *Hwin;
+ float *bufferOne;
+ float *bufferTwo;
+ float *channelOne;
+ float *channelTwo;
+ float *output;
+ float mult;
+ float *trigland;
+ short connected[8];
+ short mute;
+ int overlap;//overlap factor
+ int winfac;//window factor
+ int vs;//vector size
+
+} t_ether;
+
+
+void *ether_new(t_symbol *s, int argc, t_atom *argv);
+t_int *ether_perform(t_int *w);
+void ether_dsp(t_ether *x, t_signal **sp, short *count);
+void ether_assist(t_ether *x, void *b, long m, long a, char *s);
+void ether_dest(t_ether *x, double f);
+void ether_invert(t_ether *x, t_floatarg toggle);
+void ether_init(t_ether *x, short initialized);
+void ether_free(t_ether *x);
+void ether_mute(t_ether *x, t_floatarg toggle);
+void ether_fftinfo(t_ether *x);
+void ether_winfac(t_ether *x, t_floatarg f);
+void ether_overlap(t_ether *x, t_floatarg o);
+void ether_tilde_setup(void);
+
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&ether_class, (method) ether_new, (method)ether_free, (short) sizeof(t_ether),
+ 0, A_GIMME, 0);
+
+ addmess((method)ether_dsp, "dsp", A_CANT, 0);
+ addmess((method)ether_assist,"assist",A_CANT,0);
+ addfloat((method)ether_dest);
+ addmess((method)ether_invert,"invert", A_FLOAT, 0);
+ addmess((method)ether_mute,"mute", A_FLOAT, 0);
+ addmess((method)ether_overlap,"overlap", A_FLOAT, 0);
+ addmess((method)ether_winfac,"winfac", A_FLOAT, 0);
+ addmess((method)ether_fftinfo,"fftinfo", 0);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+
+}
+
+void ether_dest(t_ether *x, double f)
+{
+ x->threshMult = (float) f;
+}
+#endif
+
+#if PD
+void ether_tilde_setup(void)
+{
+ ether_class = class_new(gensym("ether~"), (t_newmethod)ether_new,
+ (t_method)ether_free ,sizeof(t_ether), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(ether_class, t_ether, x_f);
+ class_addmethod(ether_class, (t_method)ether_dsp, gensym("dsp"), 0);
+ class_addmethod(ether_class, (t_method)ether_assist, gensym("assist"), 0);
+ class_addmethod(ether_class, (t_method)ether_invert, gensym("invert"), A_FLOAT,0);
+ class_addmethod(ether_class, (t_method)ether_overlap, gensym("overlap"), A_FLOAT,0);
+ class_addmethod(ether_class, (t_method)ether_mute, gensym("mute"), A_FLOAT,0);
+ class_addmethod(ether_class, (t_method)ether_winfac, gensym("winfac"), A_FLOAT,0);
+ class_addmethod(ether_class, (t_method)ether_fftinfo, gensym("fftinfo"), A_CANT,0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+
+
+/* diagnostic messages for Max */
+
+
+void ether_assist (t_ether *x, void *b, long msg, long arg, char *dst)
+{
+
+ if (msg == 1) {
+
+ switch (arg) {
+
+ case 0: sprintf(dst,"(signal) Input One");break;
+ case 1: sprintf(dst,"(signal) Input Two"); break;
+ case 2: sprintf(dst,"(signal) Composite Index"); break;
+ }
+ }
+
+ else {
+
+ if (msg == 2)
+ sprintf(dst,"(signal) Output");
+
+ }
+}
+
+void ether_free(t_ether *x)
+{
+#if MSP
+ dsp_free((t_pxobject *) x);
+#endif
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->inputOne,0);
+ freebytes(x->inputTwo,0);
+ freebytes(x->bufferOne,0);
+ freebytes(x->bufferTwo,0);
+ freebytes(x->channelOne,0);
+ freebytes(x->channelTwo,0);
+ freebytes(x->output,0);
+}
+
+void ether_overlap(t_ether *x, t_floatarg df)
+{
+int o = (int)df;
+ if(!power_of_two(o)){
+ error("%d is not a power of two",o);
+ return;
+ }
+ x->overlap = o;
+ ether_init(x,1);
+}
+
+void ether_winfac(t_ether *x, t_floatarg f)
+{
+int wf = (int)f;
+ if(!power_of_two(wf)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = wf;
+ ether_init(x,1);
+}
+
+void ether_fftinfo( t_ether *x )
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+
+void *ether_new(t_symbol *s, int argc, t_atom *argv)
+{
+
+#if MSP
+ t_ether *x = (t_ether *) newobject(ether_class);
+ dsp_setup((t_pxobject *)x,3);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+#if PD
+ t_ether *x = (t_ether *)pd_new(ether_class);
+ /* add two additional signal inlets */
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+/* optional arguments: overlap winfac */
+
+ x->overlap = atom_getfloatarg(0,argc,argv);
+ x->winfac = atom_getfloatarg(1,argc,argv);
+ if(!power_of_two(x->overlap)){
+ x->overlap = 4;
+ }
+ if(!power_of_two(x->winfac)){
+ x->winfac = 1;
+ }
+ x->vs = sys_getblksize();
+ x->R = sys_getsr();
+ ether_init(x,0);
+
+ return (x);
+}
+
+void ether_init(t_ether *x, short initialized)
+{
+ int i;
+
+ x->D = x->vs;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+ if(!initialized){
+ x->mute = 0;
+ x->invert = 0;
+ x->threshMult = 0.;
+ x->Wanal = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Wsyn = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Hwin = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->inputOne = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->inputTwo = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->bufferOne = (float *) getbytes(MAX_N * sizeof(float));
+ x->bufferTwo = (float *) getbytes(MAX_N * sizeof(float));
+ x->channelOne = (float *) getbytes(MAX_N+2 * sizeof(float));
+ x->channelTwo = (float *) getbytes(MAX_N+2 * sizeof(float));
+ x->output = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->bitshuffle = (int *) getbytes(MAX_N * 2 * sizeof(int));
+ x->trigland = (float *) getbytes(MAX_N * 2 * sizeof(float));
+ }
+ memset((char *)x->inputOne,0,x->Nw * sizeof(float));
+ memset((char *)x->inputTwo,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makehanning( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 1);
+
+}
+
+
+t_int *ether_perform(t_int *w)
+{
+
+ int i,j,
+ inCount,
+ R,
+ N,
+ N2,
+ D,
+ Nw,
+ invert = 1,
+ even, odd,
+ *bitshuffle;
+
+ float maxamp,
+ threshMult = 1.,
+ mult,
+ a1, b1,
+ a2, b2,
+ *inputOne,
+ *inputTwo,
+ *bufferOne,
+ *bufferTwo,
+ *output,
+ *Wanal,
+ *Wsyn,
+ *channelOne,
+ *channelTwo,
+ *trigland;
+
+
+/* get our inlets and outlets */
+
+ t_ether *x = (t_ether *) (w[1]);
+ t_float *inOne = (t_float *)(w[2]);
+ t_float *inTwo = (t_float *)(w[3]);
+ t_float *vec_threshMult = (t_float *)(w[4]);
+ t_float *out = (t_float *)(w[5]);
+ t_int n = w[6];
+
+ short *connected = x->connected;
+
+/* dereference structure */
+
+ inputOne = x->inputOne;
+ inputTwo = x->inputTwo;
+ bufferOne = x->bufferOne;
+ bufferTwo = x->bufferTwo;
+ inCount = x->inCount;
+ R = x->R;
+ N = x->N;
+ N2 = x->N2;
+ D = x->D;
+ Nw = x->Nw;
+ Wanal = x->Wanal;
+ Wsyn = x->Wsyn;
+ output = x->output;
+ channelOne = x->channelOne;
+ channelTwo = x->channelTwo;
+ bitshuffle = x->bitshuffle;
+ trigland = x->trigland;
+ mult = x->mult;
+ invert = x->invert;
+
+ if(connected[2]){
+ threshMult = *vec_threshMult;
+ }
+ else if ( x->threshMult != 0. ){
+ threshMult = x->threshMult;
+ }
+ else {
+ threshMult = 1.0;
+ }
+
+ if(x->mute){
+ while(n--)
+ *out++ = 0.0;
+ return w+7;
+ }
+
+/* fill our retaining buffers */
+
+ inCount += D;
+
+ for ( j = 0 ; j < Nw - D ; j++ ) {
+ inputOne[j] = inputOne[j+D];
+ inputTwo[j] = inputTwo[j+D];
+ }
+
+ for ( j = Nw - D; j < Nw; j++ ) {
+ inputOne[j] = *inOne++;
+ inputTwo[j] = *inTwo++;
+ }
+
+/* apply hamming window and fold our window buffer into the fft buffer */
+
+ fold( inputOne, Wanal, Nw, bufferOne, N, inCount );
+ fold( inputTwo, Wanal, Nw, bufferTwo, N, inCount );
+
+
+/* do an fft */
+
+ rdft( N, 1, bufferOne, bitshuffle, trigland );
+ rdft( N, 1, bufferTwo, bitshuffle, trigland );
+
+/* use slow fft */
+
+
+/* use redundant coding for speed, even though moving the invert variable
+ comparison outside of the for loop will give us only a minimal performance
+ increase (hypot and atan2 are the most intensive portions of this code).
+ consider adding a table lookup for atan2 instead.
+*/
+
+ if (invert) {
+
+/* convert to polar coordinates from complex values */
+
+ for ( i = 0; i <= N2; i++ ) {
+ odd = ( even = i<<1 ) + 1;
+
+ a1 = ( i == N2 ? *(bufferOne+1) : *(bufferOne+even) );
+ b1 = ( i == 0 || i == N2 ? 0. : *(bufferOne+odd) );
+
+ a2 = ( i == N2 ? *(bufferTwo+1) : *(bufferTwo+even) );
+ b2 = ( i == 0 || i == N2 ? 0. : *(bufferTwo+odd) );
+
+ *(channelOne+even) = hypot( a1, b1 );
+ *(channelOne+odd) = -atan2( b1, a1 );
+
+ *(channelTwo+even) = hypot( a2, b2 );
+ *(channelTwo+odd) = -atan2( b2, a2 );
+
+/* use simple threshold for inverse compositing */
+
+ if ( *(channelOne+even) > *(channelTwo+even) * threshMult )
+ *(channelOne+even) = *(channelTwo+even);
+
+ if ( *(channelOne+odd) == 0. )
+ *(channelOne+odd) = *(channelTwo+odd);
+ }
+ }
+
+ else {
+
+/* convert to polar coordinates from complex values */
+
+ for ( i = 0; i <= N2; i++ ) {
+
+ odd = ( even = i<<1 ) + 1;
+
+ a1 = ( i == N2 ? *(bufferOne+1) : *(bufferOne+even) );
+ b1 = ( i == 0 || i == N2 ? 0. : *(bufferOne+odd) );
+
+ a2 = ( i == N2 ? *(bufferTwo+1) : *(bufferTwo+even) );
+ b2 = ( i == 0 || i == N2 ? 0. : *(bufferTwo+odd) );
+
+ *(channelOne+even) = hypot( a1, b1 );
+ *(channelOne+odd) = -atan2( b1, a1 );
+
+ *(channelTwo+even) = hypot( a2, b2 );
+ *(channelTwo+odd) = -atan2( b2, a2 );
+
+/* use simple threshold for compositing */
+
+ if ( *(channelOne+even) < *(channelTwo+even) * threshMult )
+ *(channelOne+even) = *(channelTwo+even);
+
+ if ( *(channelOne+odd) == 0. )
+ *(channelOne+odd) = *(channelTwo+odd);
+ }
+ }
+
+/* convert back to complex form, read for the inverse fft */
+
+ for ( i = 0; i <= N2; i++ ) {
+
+ odd = ( even = i<<1 ) + 1;
+
+ *(bufferOne+even) = *(channelOne+even) * cos( *(channelOne+odd) );
+
+ if ( i != N2 )
+ *(bufferOne+odd) = -(*(channelOne+even)) * sin( *(channelOne+odd) );
+ }
+
+
+/* do an inverse fft */
+
+ rdft( N, -1, bufferOne, bitshuffle, trigland );
+
+
+/* dewindow our result */
+
+ overlapadd( bufferOne, N, Wsyn, output, Nw, inCount);
+
+/* set our output and adjust our retaining output buffer */
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+
+/* restore state variables */
+
+ x->inCount = inCount % Nw;
+ return (w+7);
+}
+
+void ether_mute(t_ether *x, t_floatarg toggle)
+{
+ x->mute = (short)toggle;
+}
+
+void ether_invert(t_ether *x, t_floatarg toggle)
+{
+ x->invert = (int)toggle;
+}
+
+void ether_dsp(t_ether *x, t_signal **sp, short *count)
+{
+ long i;
+#if MSP
+ for( i = 0; i < 3; i++ ){
+ x->connected[i] = count[i];
+ }
+#endif
+ /* signal is always connected in Pd */
+#if PD
+ for( i = 0; i < 3; i++ ){
+ x->connected[i] = 1;
+ }
+#endif
+ /* reinitialize if vector size or sampling rate has been changed */
+ if(x->vs != sp[0]->s_n || x->R != sp[0]->s_sr){
+ x->vs = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ ether_init(x,1);
+ }
+ dsp_add(ether_perform, 6, x,
+ sp[0]->s_vec,
+ sp[1]->s_vec,
+ sp[2]->s_vec,
+ sp[3]->s_vec,
+ sp[0]->s_n);
+}
+
diff --git a/help/burrow~-help.pd b/help/burrow~-help.pd
new file mode 100644
index 0000000..5e50cb7
--- /dev/null
+++ b/help/burrow~-help.pd
@@ -0,0 +1,90 @@
+#N canvas 143 237 600 366 12;
+#X msg 17 161 getattributes;
+#X obj 391 278 print A;
+#X obj 161 210 burrow~ -30 -18 0;
+#X obj 17 78 tgl 20 1 empty empty enable_dsp 0 -6 0 10 -225271 -1 -1
+1 1;
+#X msg 17 103 enable \$1;
+#X obj 211 78 tgl 20 0 empty empty inverse_filtering 0 -6 0 10 -225271
+-1 -1 0 1;
+#X msg 211 102 invert \$1;
+#X obj 373 78 nbx 5 18 -100 0 0 1 empty empty filtering_threshold(dB)
+0 -6 0 10 -225271 -1 -1 -30 256;
+#X msg 373 100 thresh \$1;
+#X obj 374 145 nbx 5 18 -100 0 0 1 empty empty filter_multiplier(dB)
+0 -6 0 10 -225271 -1 -1 -18 256;
+#X msg 374 167 mult \$1;
+#X obj 161 275 *~;
+#X obj 202 280 hsl 128 15 0.001 10 1 1 empty empty volume -2 -6 0 10
+-261681 -1 -1 10000 1;
+#X obj 150 312 dac~;
+#X text 390 297 print attributes;
+#X text 15 143 list attributes;
+#X obj 16 8 cnv 15 550 40 empty empty burrow~ 10 22 0 24 -260818 -1
+0;
+#X text 188 8 FFTease (C)Lyon \, Penrose (for Max/MSP);
+#X text 188 28 Pd port;
+#X text 222 231 threshold \, multiplier \, invert;
+#X obj 138 80 bng 25 250 50 0 empty empty start 0 -6 0 8 -261689 -1
+-1;
+#N canvas 35 47 456 306 schubert 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/schubert.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 233 172 pd schubert;
+#N canvas 35 47 460 310 nixon 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/nixon.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 161 172 pd nixon;
+#X msg 17 259 getthresh;
+#X msg 17 284 getmult;
+#X msg 17 234 getinvert;
+#X text 15 213 get attributes;
+#X connect 0 0 2 0;
+#X connect 2 0 11 0;
+#X connect 2 1 1 0;
+#X connect 3 0 4 0;
+#X connect 4 0 2 0;
+#X connect 5 0 6 0;
+#X connect 6 0 2 0;
+#X connect 7 0 8 0;
+#X connect 8 0 2 0;
+#X connect 9 0 10 0;
+#X connect 10 0 2 0;
+#X connect 11 0 13 0;
+#X connect 11 0 13 1;
+#X connect 12 0 11 1;
+#X connect 20 0 21 0;
+#X connect 20 0 22 0;
+#X connect 21 0 2 1;
+#X connect 22 0 2 0;
+#X connect 23 0 2 0;
+#X connect 24 0 2 0;
+#X connect 25 0 2 0;
diff --git a/help/cross~-help.pd b/help/cross~-help.pd
new file mode 100644
index 0000000..6d5523a
--- /dev/null
+++ b/help/cross~-help.pd
@@ -0,0 +1,88 @@
+#N canvas 275 53 604 370 12;
+#X obj 17 78 tgl 20 1 empty empty enable_dsp 0 -6 0 10 -225271 -1 -1
+1 1;
+#X msg 17 103 enable \$1;
+#X obj 312 84 nbx 5 18 -100 0 0 1 empty empty threshold(dB) 0 -6 0
+10 -225271 -1 -1 -86 256;
+#X obj 161 275 *~;
+#X obj 202 280 hsl 128 15 0.001 10 1 1 empty empty volume -2 -6 0 10
+-261681 -1 -1 11800 1;
+#X obj 150 312 dac~;
+#X obj 16 8 cnv 15 550 40 empty empty cross~ 10 22 0 24 -260818 -1
+0;
+#X text 188 8 FFTease (C)Lyon \, Penrose (for Max/MSP);
+#X text 188 28 Pd port;
+#X obj 161 210 cross~;
+#X obj 312 161 sig~;
+#X obj 311 113 + 100;
+#X obj 312 136 dbtorms;
+#X obj 161 80 bng 25 250 50 0 empty empty start 0 -6 0 8 -261689 -1
+-1;
+#N canvas 35 47 456 306 schubert 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/schubert.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 162 175 pd schubert;
+#N canvas 35 47 460 310 nixon 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/nixon.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 183 142 pd nixon;
+#X msg 17 161 getattributes;
+#X text 15 143 list attributes;
+#X text 15 215 get attributes;
+#X obj 445 85 tgl 25 1 empty empty memorize 0 -6 0 10 -225271 -1 -1
+1 1;
+#X text 371 182 partials below the threshold;
+#X text 370 200 are taken from the previous;
+#X text 370 216 frame;
+#X obj 391 278 print A;
+#X text 390 297 print attributes;
+#X msg 17 234 getmemorize;
+#X text 373 165 memorize defaults to 1;
+#X msg 445 117 memorize \$1;
+#X connect 0 0 1 0;
+#X connect 1 0 9 0;
+#X connect 2 0 11 0;
+#X connect 3 0 5 0;
+#X connect 3 0 5 1;
+#X connect 4 0 3 1;
+#X connect 9 0 3 0;
+#X connect 9 1 23 0;
+#X connect 10 0 9 2;
+#X connect 11 0 12 0;
+#X connect 12 0 10 0;
+#X connect 13 0 14 0;
+#X connect 13 0 15 0;
+#X connect 14 0 9 0;
+#X connect 15 0 9 1;
+#X connect 16 0 9 0;
+#X connect 19 0 27 0;
+#X connect 25 0 9 0;
+#X connect 27 0 9 0;
diff --git a/help/dentist~-help.pd b/help/dentist~-help.pd
new file mode 100644
index 0000000..3ca8841
--- /dev/null
+++ b/help/dentist~-help.pd
@@ -0,0 +1,65 @@
+#N canvas 45 260 600 366 12;
+#X obj 17 78 tgl 20 1 empty empty enable_dsp 0 -6 0 10 -225271 -1 -1
+1 1;
+#X msg 17 103 enable \$1;
+#X obj 417 91 nbx 5 18 0 20000 0 0 empty empty knee_frq 0 -6 0 10 -225271
+-1 -1 0 256;
+#X obj 211 272 *~;
+#X obj 252 277 hsl 128 15 0.001 10 1 1 empty empty volume -2 -6 0 10
+-261681 -1 -1 10200 1;
+#X obj 200 309 dac~;
+#X obj 16 8 cnv 15 550 40 empty empty dentist~ 10 22 0 24 -260818 -1
+0;
+#X text 198 8 FFTease (C)Lyon \, Penrose (for Max/MSP);
+#X text 198 28 Pd port;
+#X msg 14 181 getattributes;
+#X obj 432 255 print A;
+#X obj 337 90 bng 25 250 50 0 empty empty reshuffle 0 -6 0 8 -225271
+-1 -1;
+#X msg 417 123 knee \$1;
+#X obj 495 91 nbx 5 18 0 1000 0 0 empty empty teeth 0 -6 0 10 -225271
+-1 -1 0 256;
+#X msg 495 123 teeth \$1;
+#X text 348 209 knee frq. \, teeth;
+#X obj 211 208 dentist~ 1000 10;
+#X text 14 164 list attributes;
+#X obj 212 92 bng 25 250 50 0 empty empty start 0 -6 0 8 -261689 -1
+-1;
+#N canvas 35 47 456 306 schubert 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/schubert.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 212 156 pd schubert;
+#X text 15 222 get attributes;
+#X msg 15 239 getknee;
+#X msg 15 267 getteeth;
+#X connect 0 0 1 0;
+#X connect 1 0 16 0;
+#X connect 2 0 12 0;
+#X connect 3 0 5 0;
+#X connect 3 0 5 1;
+#X connect 4 0 3 1;
+#X connect 9 0 16 0;
+#X connect 11 0 16 0;
+#X connect 12 0 16 0;
+#X connect 13 0 14 0;
+#X connect 14 0 16 0;
+#X connect 16 0 3 0;
+#X connect 16 1 10 0;
+#X connect 18 0 19 0;
+#X connect 19 0 16 0;
+#X connect 21 0 16 0;
+#X connect 22 0 16 0;
diff --git a/help/disarray~-help.pd b/help/disarray~-help.pd
new file mode 100644
index 0000000..d3238a2
--- /dev/null
+++ b/help/disarray~-help.pd
@@ -0,0 +1,67 @@
+#N canvas 68 275 606 372 12;
+#X obj 17 78 tgl 20 1 empty empty enable_dsp 0 -6 0 10 -225271 -1 -1
+1 1;
+#X msg 17 103 enable \$1;
+#X obj 369 88 nbx 5 18 0 20000 0 1 empty empty knee_frq 0 -6 0 10 -225271
+-1 -1 1300 256;
+#X obj 211 272 *~;
+#X obj 252 277 hsl 128 15 0.001 10 1 1 empty empty volume -2 -6 0 10
+-261681 -1 -1 9600 1;
+#X obj 200 309 dac~;
+#X obj 16 8 cnv 15 550 40 empty empty disarray~ 10 22 0 24 -260818
+-1 0;
+#X text 206 7 FFTease (C)Lyon \, Penrose (for Max/MSP);
+#X text 206 27 Pd port;
+#X msg 14 181 getattributes;
+#X obj 427 281 print A;
+#X text 14 164 list attributes;
+#X obj 211 217 disarray~ 1300 0 20;
+#X obj 281 89 bng 25 250 50 0 empty empty reshuffle 0 -6 0 10 -225271
+-1 -1;
+#X obj 454 88 nbx 5 18 0 1000 0 1 empty empty shuffle_count 0 -6 0
+10 -225271 -1 -1 20 256;
+#X text 424 300 attributes;
+#X text 15 219 get attributes;
+#X obj 207 89 bng 25 250 50 0 empty empty start 0 -6 0 8 -261689 -1
+-1;
+#N canvas 35 47 456 306 schubert 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/schubert.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 212 154 pd schubert;
+#X msg 369 120 knee \$1;
+#X msg 454 120 partials \$1;
+#X msg 15 238 getknee;
+#X msg 16 263 getpartials;
+#X text 292 199 knee frq \, quality \, partials;
+#X text 367 218 (these are the defaults);
+#X connect 0 0 1 0;
+#X connect 1 0 12 0;
+#X connect 2 0 19 0;
+#X connect 3 0 5 0;
+#X connect 3 0 5 1;
+#X connect 4 0 3 1;
+#X connect 9 0 12 0;
+#X connect 12 0 3 0;
+#X connect 12 1 10 0;
+#X connect 13 0 12 0;
+#X connect 14 0 20 0;
+#X connect 17 0 18 0;
+#X connect 18 0 12 0;
+#X connect 19 0 12 0;
+#X connect 20 0 12 0;
+#X connect 21 0 12 0;
+#X connect 22 0 12 0;
diff --git a/help/drown~-help.pd b/help/drown~-help.pd
new file mode 100644
index 0000000..1a35b97
--- /dev/null
+++ b/help/drown~-help.pd
@@ -0,0 +1,61 @@
+#N canvas 140 138 612 378 12;
+#X obj 17 90 tgl 20 1 empty empty enable_dsp 0 -6 0 10 -225271 -1 -1
+1 1;
+#X msg 17 115 enable \$1;
+#X obj 166 272 *~;
+#X obj 207 277 hsl 128 15 0.001 1000 1 1 empty empty volume -2 -6 0
+10 -261681 -1 -1 9700 1;
+#X obj 155 309 dac~;
+#X obj 16 8 cnv 15 550 40 empty empty drown~ 10 22 0 24 -260818 -1
+0;
+#X text 206 7 FFTease (C)Lyon \, Penrose (for Max/MSP);
+#X text 206 27 Pd port;
+#X obj 294 97 nbx 5 18 -100 0 0 1 empty empty threshold 0 -6 0 10 -225271
+-1 -1 -75 256;
+#X obj 166 88 bng 25 250 50 0 empty empty start 0 -6 0 8 -261689 -1
+-1;
+#N canvas 35 47 456 306 schubert 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/schubert.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 166 126 pd schubert;
+#X obj 166 217 drown~;
+#X obj 384 174 sig~ 1;
+#X obj 385 99 nbx 5 18 -100 10 0 1 empty empty multiplication_factor
+0 -6 0 10 -225271 -1 -1 -18 256;
+#X obj 292 175 sig~ 1;
+#X obj 294 125 + 100;
+#X obj 385 125 + 100;
+#X obj 385 148 dbtorms;
+#X obj 293 149 dbtorms;
+#X obj 405 324 denude~;
+#X text 403 345 alternative naming;
+#X connect 0 0 1 0;
+#X connect 1 0 11 0;
+#X connect 2 0 4 0;
+#X connect 2 0 4 1;
+#X connect 3 0 2 1;
+#X connect 8 0 15 0;
+#X connect 9 0 10 0;
+#X connect 10 0 11 0;
+#X connect 11 0 2 0;
+#X connect 12 0 11 2;
+#X connect 13 0 16 0;
+#X connect 14 0 11 1;
+#X connect 15 0 18 0;
+#X connect 16 0 17 0;
+#X connect 17 0 12 0;
+#X connect 18 0 14 0;
diff --git a/help/ether~-help.pd b/help/ether~-help.pd
new file mode 100644
index 0000000..5eed4e0
--- /dev/null
+++ b/help/ether~-help.pd
@@ -0,0 +1,84 @@
+#N canvas 140 138 602 368 12;
+#X obj 17 78 tgl 20 1 empty empty enable_dsp 0 -6 0 10 -225271 -1 -1
+1 1;
+#X msg 17 103 enable \$1;
+#X obj 211 272 *~;
+#X obj 252 277 hsl 128 15 0.001 10 1 1 empty empty volume -2 -6 0 10
+-261681 -1 -1 8600 1;
+#X obj 200 309 dac~;
+#X obj 16 8 cnv 15 550 40 empty empty ether~ 10 22 0 24 -260818 -1
+0;
+#X text 206 7 FFTease (C)Lyon \, Penrose (for Max/MSP);
+#X text 206 27 Pd port;
+#X msg 14 181 getattributes;
+#X obj 427 281 print A;
+#X text 14 164 list attributes;
+#X obj 499 84 nbx 5 18 0 1000 0 0 empty empty index 0 -6 0 10 -225271
+-1 -1 22 256;
+#X text 424 300 attributes;
+#X msg 387 117 invert \$1;
+#X obj 387 83 tgl 25 0 empty empty invert 0 -6 0 8 -225271 -1 -1 0
+1;
+#X msg 499 116 index \$1;
+#X obj 211 217 ether~ 1;
+#X text 287 212 quality \, invert \, index;
+#X obj 211 88 bng 25 250 50 0 empty empty start 0 -6 0 8 -261689 -1
+-1;
+#N canvas 35 47 456 306 schubert 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/schubert.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 271 172 pd schubert;
+#N canvas 35 47 460 310 nixon 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/nixon.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 212 148 pd nixon;
+#X text 15 213 get attributes;
+#X msg 15 230 getinvert;
+#X msg 16 259 getindex;
+#X text 287 228 (defaults are 0 \, 0 \, 0);
+#X connect 0 0 1 0;
+#X connect 1 0 16 0;
+#X connect 2 0 4 0;
+#X connect 2 0 4 1;
+#X connect 3 0 2 1;
+#X connect 8 0 16 0;
+#X connect 11 0 15 0;
+#X connect 13 0 16 0;
+#X connect 14 0 13 0;
+#X connect 15 0 16 0;
+#X connect 16 0 2 0;
+#X connect 16 1 9 0;
+#X connect 18 0 19 0;
+#X connect 18 0 20 0;
+#X connect 19 0 16 1;
+#X connect 20 0 16 0;
+#X connect 22 0 16 0;
+#X connect 23 0 16 0;
diff --git a/help/morphine~-help.pd b/help/morphine~-help.pd
new file mode 100644
index 0000000..6124b23
--- /dev/null
+++ b/help/morphine~-help.pd
@@ -0,0 +1,77 @@
+#N canvas 140 138 606 372 12;
+#X obj 17 78 tgl 20 1 empty empty enable_dsp 0 -6 0 10 -225271 -1 -1
+1 1;
+#X msg 17 103 enable \$1;
+#X obj 211 272 *~;
+#X obj 252 277 hsl 128 15 0.001 10 1 1 empty empty volume -2 -6 0 10
+-261681 -1 -1 10000 1;
+#X obj 200 309 dac~;
+#X obj 16 8 cnv 15 550 40 empty empty morphine~ 10 22 0 24 -260818
+-1 0;
+#X text 206 7 FFTease (C)Lyon \, Penrose (for Max/MSP);
+#X text 206 27 Pd port;
+#X msg 14 181 getattributes;
+#X obj 427 281 print A;
+#X text 14 164 list attributes;
+#X obj 414 86 nbx 5 18 0.001 1 1 1 empty empty index 0 -6 0 10 -225271
+-1 -1 0.001 256;
+#X text 424 300 attributes;
+#X msg 414 110 index \$1;
+#X obj 211 88 bng 25 250 50 0 empty empty start 0 -6 0 8 -261689 -1
+-1;
+#N canvas 35 47 456 306 schubert 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/schubert.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 210 184 pd schubert;
+#N canvas 35 47 460 310 nixon 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/nixon.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 307 186 pd nixon;
+#X text 15 215 get attributes;
+#X msg 16 234 getindex;
+#X text 477 87 (0...1);
+#X obj 211 217 morphine~ 0.05;
+#X text 336 219 index (defaults to 0);
+#X connect 0 0 1 0;
+#X connect 1 0 20 0;
+#X connect 2 0 4 0;
+#X connect 2 0 4 1;
+#X connect 3 0 2 1;
+#X connect 8 0 20 0;
+#X connect 11 0 13 0;
+#X connect 13 0 20 0;
+#X connect 14 0 15 0;
+#X connect 14 0 16 0;
+#X connect 15 0 20 0;
+#X connect 16 0 20 1;
+#X connect 18 0 20 0;
+#X connect 20 0 2 0;
+#X connect 20 1 9 0;
diff --git a/help/residency~-help.pd b/help/residency~-help.pd
new file mode 100644
index 0000000..f80a2b5
--- /dev/null
+++ b/help/residency~-help.pd
@@ -0,0 +1,33 @@
+#N canvas 37 209 558 409 10;
+#X floatatom 264 146 5 0 0 0 - - -;
+#X obj 207 190 residency~ 5000 1;
+#X floatatom 321 145 5 0 0 0 - - -;
+#X obj 198 278 dac~;
+#X obj 207 243 *~;
+#X obj 83 133 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X msg 83 156 playthrough \$1;
+#X obj 206 60 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 342 12 adc~;
+#X obj 414 69 prvu~;
+#X obj 415 94 vu 15 120 empty empty -1 -8 0 8 -66577 -1 1 0;
+#X obj 242 101 *~;
+#X obj 261 81 hsl 128 15 0.01 1 1 0 empty empty gain 12 8 1 12 -225271
+-1 -1 0 1;
+#X obj 226 224 hsl 128 15 0.01 1 1 0 empty empty gain 12 8 1 12 -225271
+-1 -1 0 1;
+#X connect 0 0 1 1;
+#X connect 1 0 4 0;
+#X connect 2 0 1 2;
+#X connect 4 0 3 0;
+#X connect 4 0 3 1;
+#X connect 5 0 6 0;
+#X connect 6 0 1 0;
+#X connect 7 0 1 0;
+#X connect 8 0 9 0;
+#X connect 8 0 11 0;
+#X connect 9 0 10 0;
+#X connect 11 0 1 0;
+#X connect 12 0 11 1;
+#X connect 13 0 4 1;
diff --git a/help/scrape~-help.pd b/help/scrape~-help.pd
new file mode 100644
index 0000000..72f2440
--- /dev/null
+++ b/help/scrape~-help.pd
@@ -0,0 +1,72 @@
+#N canvas 140 138 606 372 12;
+#X obj 17 78 tgl 20 1 empty empty enable_dsp 0 -6 0 10 -225271 -1 -1
+1 1;
+#X msg 17 103 enable \$1;
+#X obj 211 272 *~;
+#X obj 252 277 hsl 128 15 0.001 10 1 1 empty empty volume -2 -6 0 10
+-261681 -1 -1 9800 1;
+#X obj 200 309 dac~;
+#X obj 16 8 cnv 15 550 40 empty empty scrape~ 10 22 0 24 -260818 -1
+0;
+#X text 206 7 FFTease (C)Lyon \, Penrose (for Max/MSP);
+#X text 206 27 Pd port;
+#X msg 14 181 getattributes;
+#X obj 427 281 print A;
+#X text 14 164 list attributes;
+#X obj 423 90 nbx 5 18 10 20000 1 1 empty empty knee 0 -6 0 10 -225271
+-1 -1 1000 256;
+#X text 424 300 attributes;
+#X obj 211 88 bng 25 250 50 0 empty empty start 0 -6 0 8 -261689 -1
+-1;
+#N canvas 35 47 456 306 schubert 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/schubert.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 210 184 pd schubert;
+#X text 15 215 get attributes;
+#X obj 319 89 nbx 5 18 -100 0 0 1 empty empty multiplier 0 -6 0 10
+-225271 -1 -1 -60 256;
+#X obj 318 183 sig~ 1;
+#X obj 318 116 + 100;
+#X obj 318 143 dbtorms;
+#X msg 16 234 getknee;
+#X msg 16 257 getcutoff;
+#X msg 423 114 knee \$1;
+#X obj 505 90 nbx 5 18 10 20000 1 1 empty empty cutoff 0 -6 0 10 -225271
+-1 -1 2000 256;
+#X msg 505 114 cutoff \$1;
+#X obj 211 217 scrape~ 1000 2000;
+#X text 361 219 knee \, cutoff;
+#X connect 0 0 1 0;
+#X connect 1 0 25 0;
+#X connect 2 0 4 0;
+#X connect 2 0 4 1;
+#X connect 3 0 2 1;
+#X connect 8 0 25 0;
+#X connect 11 0 22 0;
+#X connect 13 0 14 0;
+#X connect 14 0 25 0;
+#X connect 16 0 18 0;
+#X connect 17 0 25 1;
+#X connect 18 0 19 0;
+#X connect 19 0 17 0;
+#X connect 20 0 25 0;
+#X connect 21 0 25 0;
+#X connect 22 0 25 0;
+#X connect 23 0 24 0;
+#X connect 24 0 25 0;
+#X connect 25 0 2 0;
+#X connect 25 1 9 0;
diff --git a/help/shapee~-help.pd b/help/shapee~-help.pd
new file mode 100644
index 0000000..c0a06de
--- /dev/null
+++ b/help/shapee~-help.pd
@@ -0,0 +1,62 @@
+#N canvas 140 138 612 378 12;
+#X obj 17 78 tgl 20 1 empty empty enable_dsp 0 -6 0 10 -225271 -1 -1
+1 1;
+#X msg 17 103 enable \$1;
+#X obj 211 272 *~;
+#X obj 252 277 hsl 128 15 0.001 10 1 1 empty empty volume -2 -6 0 10
+-261681 -1 -1 10700 1;
+#X obj 200 309 dac~;
+#X obj 16 8 cnv 15 550 40 empty empty shapee~ 10 22 0 24 -260818 -1
+0;
+#X text 206 7 FFTease (C)Lyon \, Penrose (for Max/MSP);
+#X text 206 27 Pd port;
+#X obj 211 88 bng 25 250 50 0 empty empty start 0 -6 0 8 -261689 -1
+-1;
+#N canvas 35 47 458 308 schubert 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/schubert.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 210 184 pd schubert;
+#N canvas 35 47 460 310 nixon 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/nixon.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 307 184 pd nixon;
+#X text 298 219 quality (defaults to 0);
+#X obj 211 217 shapee~ 1;
+#X connect 0 0 1 0;
+#X connect 1 0 12 0;
+#X connect 2 0 4 0;
+#X connect 2 0 4 1;
+#X connect 3 0 2 1;
+#X connect 8 0 9 0;
+#X connect 8 0 10 0;
+#X connect 9 0 12 0;
+#X connect 10 0 12 1;
+#X connect 12 0 2 0;
diff --git a/help/swinger~-help.pd b/help/swinger~-help.pd
new file mode 100644
index 0000000..af12c5e
--- /dev/null
+++ b/help/swinger~-help.pd
@@ -0,0 +1,62 @@
+#N canvas 275 53 610 376 12;
+#X obj 17 78 tgl 20 1 empty empty enable_dsp 0 -6 0 10 -225271 -1 -1
+1 1;
+#X msg 17 103 enable \$1;
+#X obj 198 275 *~;
+#X obj 239 280 hsl 128 15 0.001 10 1 1 empty empty volume -2 -6 0 10
+-261681 -1 -1 10300 1;
+#X obj 187 312 dac~;
+#X obj 16 8 cnv 15 550 40 empty empty swinger~ 10 22 0 24 -260818 -1
+0;
+#X text 188 8 FFTease (C)Lyon \, Penrose (for Max/MSP);
+#X text 188 28 Pd port;
+#X obj 198 80 bng 25 250 50 0 empty empty start 0 -6 0 8 -261689 -1
+-1;
+#N canvas 35 47 456 306 schubert 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/schubert.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 199 175 pd schubert;
+#N canvas 35 47 460 310 nixon 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/nixon.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 274 144 pd nixon;
+#X obj 198 210 swinger~ 1;
+#X text 284 210 quality (defaults to 0);
+#X connect 0 0 1 0;
+#X connect 1 0 11 0;
+#X connect 2 0 4 0;
+#X connect 2 0 4 1;
+#X connect 3 0 2 1;
+#X connect 8 0 9 0;
+#X connect 8 0 10 0;
+#X connect 9 0 11 0;
+#X connect 10 0 11 1;
+#X connect 11 0 2 0;
diff --git a/help/taint~-help.pd b/help/taint~-help.pd
new file mode 100644
index 0000000..fa2b627
--- /dev/null
+++ b/help/taint~-help.pd
@@ -0,0 +1,83 @@
+#N canvas 140 138 614 380 12;
+#X obj 17 78 tgl 20 1 empty empty enable_dsp 0 -6 0 10 -225271 -1 -1
+1 1;
+#X msg 17 103 enable \$1;
+#X obj 211 272 *~;
+#X obj 252 277 hsl 128 15 0.001 10 1 1 empty empty volume -2 -6 0 10
+-261681 -1 -1 10000 1;
+#X obj 200 309 dac~;
+#X obj 16 8 cnv 15 550 40 empty empty taint~ 10 22 0 24 -260818 -1
+0;
+#X text 206 7 FFTease (C)Lyon \, Penrose (for Max/MSP);
+#X text 206 27 Pd port;
+#X msg 14 181 getattributes;
+#X obj 427 281 print A;
+#X text 14 164 list attributes;
+#X obj 480 89 nbx 5 18 -100 0 0 1 empty empty thresh 0 -6 0 10 -225271
+-1 -1 -60 256;
+#X text 424 300 attributes;
+#X obj 211 88 bng 25 250 50 0 empty empty start 0 -6 0 8 -261689 -1
+-1;
+#N canvas 35 47 456 306 schubert 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/schubert.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 210 184 pd schubert;
+#N canvas 35 47 460 310 nixon 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/nixon.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 302 185 pd nixon;
+#X text 15 215 get attributes;
+#X obj 211 217 taint~ -60 0;
+#X msg 481 125 thresh \$1;
+#X obj 391 89 tgl 25 1 empty empty invert 0 -6 0 10 -225271 -1 -1 0
+1;
+#X msg 391 125 invert \$1;
+#X msg 16 258 getthresh;
+#X msg 16 234 getinvert;
+#X text 319 217 threshold \, invert (default -10 \, 0);
+#X connect 0 0 1 0;
+#X connect 1 0 17 0;
+#X connect 2 0 4 0;
+#X connect 2 0 4 1;
+#X connect 3 0 2 1;
+#X connect 8 0 17 0;
+#X connect 11 0 18 0;
+#X connect 13 0 14 0;
+#X connect 13 0 15 0;
+#X connect 14 0 17 0;
+#X connect 15 0 17 1;
+#X connect 17 0 2 0;
+#X connect 17 1 9 0;
+#X connect 18 0 17 0;
+#X connect 19 0 20 0;
+#X connect 20 0 17 0;
+#X connect 21 0 17 0;
+#X connect 22 0 17 0;
diff --git a/help/thresher~-help.pd b/help/thresher~-help.pd
new file mode 100644
index 0000000..fbfde9f
--- /dev/null
+++ b/help/thresher~-help.pd
@@ -0,0 +1,46 @@
+#N canvas 140 138 585 330 12;
+#X obj 17 86 tgl 20 1 empty empty enable_dsp 0 -6 0 10 -225271 -1 -1
+1 1;
+#X msg 17 111 enable \$1;
+#X obj 219 248 *~;
+#X obj 260 253 hsl 128 15 0.001 10 1 1 empty empty volume -2 -6 0 10
+-261681 -1 -1 10300 1;
+#X obj 208 285 dac~;
+#X obj 16 8 cnv 15 550 40 empty empty thresher~ 10 22 0 24 -260818
+-1 0;
+#X text 206 7 FFTease (C)Lyon \, Penrose (for Max/MSP);
+#X text 206 27 Pd port;
+#X obj 327 217 print A;
+#X text 391 216 attributes;
+#X obj 219 92 bng 25 250 50 0 empty empty start 0 -6 0 8 -261689 -1
+-1;
+#N canvas 35 47 460 310 nixon 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/nixon.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 219 144 pd nixon;
+#X obj 218 187 thresher~;
+#X obj 18 250 nacho~;
+#X text 17 274 alternative name;
+#X connect 0 0 1 0;
+#X connect 1 0 12 0;
+#X connect 2 0 4 0;
+#X connect 2 0 4 1;
+#X connect 3 0 2 1;
+#X connect 10 0 11 0;
+#X connect 11 0 12 0;
+#X connect 12 0 2 0;
+#X connect 12 1 8 0;
diff --git a/help/vacancy~-help.pd b/help/vacancy~-help.pd
new file mode 100644
index 0000000..b6e01f6
--- /dev/null
+++ b/help/vacancy~-help.pd
@@ -0,0 +1,97 @@
+#N canvas 140 138 622 388 12;
+#X obj 17 78 tgl 20 1 empty empty enable_dsp 0 -6 0 10 -225271 -1 -1
+1 1;
+#X msg 17 103 enable \$1;
+#X obj 179 284 *~;
+#X obj 220 289 hsl 128 15 0.001 10 1 1 empty empty volume -2 -6 0 10
+-261681 -1 -1 11000 1;
+#X obj 168 321 dac~;
+#X obj 16 8 cnv 15 550 40 empty empty vacancy~ 10 22 0 24 -260818 -1
+0;
+#X text 206 7 FFTease (C)Lyon \, Penrose (for Max/MSP);
+#X text 206 27 Pd port;
+#X msg 14 181 getattributes;
+#X obj 427 293 print A;
+#X text 14 164 list attributes;
+#X obj 276 91 nbx 5 18 -100 0 0 1 empty empty threshold 0 -6 0 10 -225271
+-1 -1 -31 256;
+#X text 424 312 attributes;
+#X obj 179 88 bng 25 250 50 0 empty empty start 0 -6 0 8 -261689 -1
+-1;
+#N canvas 35 47 456 306 schubert 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/schubert.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 180 174 pd schubert;
+#N canvas 35 47 460 310 nixon 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/nixon.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 316 175 pd nixon;
+#X text 15 215 get attributes;
+#X msg 275 129 thresh \$1;
+#X obj 363 91 tgl 25 1 empty empty invert 0 -6 0 10 -225271 -1 -1 0
+1;
+#X msg 363 127 invert \$1;
+#X msg 16 235 getthresh;
+#X msg 16 259 getinvert;
+#X obj 179 203 vacancy~ -30 0 1 0;
+#X obj 451 91 tgl 25 1 empty empty use_rms 0 -6 0 10 -225271 -1 -1
+1 1;
+#X obj 520 91 tgl 25 1 empty empty swap_phase 0 -6 0 10 -225271 -1
+-1 0 1;
+#X msg 451 127 rms \$1;
+#X msg 520 127 swap \$1;
+#X text 256 226 threshold \, invert \, rms \, swap;
+#X msg 16 283 getrms;
+#X msg 17 308 getswap;
+#X connect 0 0 1 0;
+#X connect 1 0 22 0;
+#X connect 2 0 4 0;
+#X connect 2 0 4 1;
+#X connect 3 0 2 1;
+#X connect 8 0 22 0;
+#X connect 11 0 17 0;
+#X connect 13 0 14 0;
+#X connect 13 0 15 0;
+#X connect 14 0 22 0;
+#X connect 15 0 22 1;
+#X connect 17 0 22 0;
+#X connect 18 0 19 0;
+#X connect 19 0 22 0;
+#X connect 20 0 22 0;
+#X connect 21 0 22 0;
+#X connect 22 0 2 0;
+#X connect 22 1 9 0;
+#X connect 23 0 25 0;
+#X connect 24 0 26 0;
+#X connect 25 0 22 0;
+#X connect 26 0 22 0;
+#X connect 28 0 22 0;
+#X connect 29 0 22 0;
diff --git a/help/xsyn~-help.pd b/help/xsyn~-help.pd
new file mode 100644
index 0000000..2416afb
--- /dev/null
+++ b/help/xsyn~-help.pd
@@ -0,0 +1,61 @@
+#N canvas 140 138 589 373 12;
+#X obj 17 78 tgl 20 1 empty empty enable_dsp 0 -6 0 10 -225271 -1 -1
+1 1;
+#X msg 17 103 enable \$1;
+#X obj 214 284 *~;
+#X obj 255 289 hsl 128 15 0.001 10 1 1 empty empty volume -2 -6 0 10
+-261681 -1 -1 10500 1;
+#X obj 203 321 dac~;
+#X obj 16 8 cnv 15 550 40 empty empty xsyn~ 10 22 0 24 -260818 -1 0
+;
+#X text 206 7 FFTease (C)Lyon \, Penrose (for Max/MSP);
+#X text 206 27 Pd port;
+#X obj 214 88 bng 25 250 50 0 empty empty start 0 -6 0 8 -261689 -1
+-1;
+#N canvas 35 47 456 306 schubert 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/schubert.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 215 174 pd schubert;
+#N canvas 35 47 460 310 nixon 0;
+#X obj 51 234 outlet~;
+#X obj 51 188 readsf~ 1;
+#X obj 51 19 inlet;
+#X msg 27 80 1;
+#X obj 52 115 t f b;
+#X obj 51 44 route bang 1 0;
+#X msg 86 149 open ../media/nixon.aiff;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 5 2 1 0;
+#X connect 6 0 1 0;
+#X restore 249 150 pd nixon;
+#X obj 214 203 xsyn~;
+#X connect 0 0 1 0;
+#X connect 1 0 11 0;
+#X connect 2 0 4 0;
+#X connect 2 0 4 1;
+#X connect 3 0 2 1;
+#X connect 8 0 9 0;
+#X connect 8 0 10 0;
+#X connect 9 0 11 0;
+#X connect 10 0 11 1;
+#X connect 11 0 2 0;
diff --git a/leaker~.c b/leaker~.c
new file mode 100644
index 0000000..ccdb6a0
--- /dev/null
+++ b/leaker~.c
@@ -0,0 +1,467 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *leaker_class;
+#endif
+
+#if PD
+static t_class *leaker_class;
+#endif
+
+#define OBJECT_NAME "leaker~"
+
+
+typedef struct _leaker
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ float *input1;
+ float *buffer1;
+ float *channel1;
+
+
+ float *input2;
+ float *buffer2;
+ float *channel2;
+
+ int *sieve ;
+ //
+ int inCount;
+ float *Hwin;
+ float *Wanal;
+ float *Wsyn;
+ float *output;
+ /* leaker vars */
+
+ float *c_lastphase_in1;
+ float *c_lastphase_in2;
+ float *c_lastphase_out;
+ float c_fundamental;
+ float c_factor_in;
+ float c_factor_out;
+
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ short mute;
+ short bypass;
+ short fade_connected;
+ float fade_value;
+ int overlap;
+ int winfac;
+} t_leaker;
+
+static void leaker_free(t_leaker *x);
+void *leaker_new(t_symbol *msg, short argc, t_atom *argv);
+//t_int *offset_perform(t_int *w);
+t_int *leaker_perform(t_int *w);
+void leaker_dsp(t_leaker *x, t_signal **sp, short *count);
+void leaker_assist(t_leaker *x, void *b, long m, long a, char *s);
+void leaker_upsieve(t_leaker *x) ;
+void leaker_downsieve(t_leaker *x) ;
+void leaker_randsieve(t_leaker *x) ;
+void leaker_bypass(t_leaker *x, t_floatarg state);
+void leaker_mute(t_leaker *x, t_floatarg state);
+void leaker_float(t_leaker *x, double f);
+void leaker_init(t_leaker *x, short initialized);
+void leaker_overlap(t_leaker *x, t_floatarg f);
+void leaker_winfac(t_leaker *x, t_floatarg f);
+void leaker_fftinfo(t_leaker *x);
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&leaker_class, (method)leaker_new, (method)leaker_free,
+ (short)sizeof(t_leaker), 0, A_GIMME, 0);
+ addmess((method)leaker_dsp, "dsp", A_CANT, 0);
+ addmess((method)leaker_assist,"assist",A_CANT,0);
+ addmess((method)leaker_upsieve, "upsieve", 0);
+ addmess((method)leaker_downsieve, "downsieve", 0);
+ addmess((method)leaker_randsieve, "randsieve", 0);
+ addmess((method)leaker_bypass,"bypass",A_DEFFLOAT,0);
+ addmess((method)leaker_mute,"mute",A_DEFFLOAT,0);
+ addmess((method)leaker_overlap,"overlap",A_DEFFLOAT,0);
+ addmess((method)leaker_winfac,"winfac",A_DEFFLOAT,0);
+ addmess((method)leaker_fftinfo,"fftinfo",0);
+ addfloat((method)leaker_float);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+#if PD
+void leaker_tilde_setup(void)
+{
+ leaker_class = class_new(gensym("leaker~"), (t_newmethod)leaker_new,
+ (t_method)leaker_free ,sizeof(t_leaker), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(leaker_class, t_leaker, x_f);
+ class_addmethod(leaker_class, (t_method)leaker_dsp, gensym("dsp"), 0);
+ class_addmethod(leaker_class, (t_method)leaker_mute, gensym("mute"), A_DEFFLOAT,0);
+ class_addmethod(leaker_class, (t_method)leaker_bypass, gensym("bypass"), A_DEFFLOAT,0);
+ class_addmethod(leaker_class, (t_method)leaker_mute, gensym("mute"), A_DEFFLOAT,0);
+ class_addmethod(leaker_class, (t_method)leaker_overlap, gensym("overlap"), A_DEFFLOAT,0);
+ class_addmethod(leaker_class, (t_method)leaker_winfac, gensym("winfac"), A_DEFFLOAT,0);
+ class_addmethod(leaker_class, (t_method)leaker_fftinfo, gensym("fftinfo"),0);
+ class_addmethod(leaker_class, (t_method)leaker_upsieve, gensym("upsieve"), 0);
+ class_addmethod(leaker_class, (t_method)leaker_downsieve, gensym("downsieve"),0);
+ class_addmethod(leaker_class, (t_method)leaker_randsieve, gensym("randsieve"),0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+void leaker_overlap(t_leaker *x, t_floatarg f)
+{
+int i = (int) f;
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->overlap = i;
+ leaker_init(x,1);
+}
+
+void leaker_winfac(t_leaker *x, t_floatarg f)
+{
+int i = (int)f;
+
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = i;
+ leaker_init(x,2);
+}
+
+void leaker_fftinfo(t_leaker *x)
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+
+void leaker_free( t_leaker *x ){
+#if MSP
+ dsp_free((t_pxobject *)x);
+#endif
+ freebytes(x->c_lastphase_in1,0);
+ freebytes(x->c_lastphase_in2,0);
+ freebytes(x->c_lastphase_out,0);
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->input1,0);
+ freebytes(x->input2,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->buffer1,0);
+ freebytes(x->buffer2,0);
+ freebytes(x->channel1,0);
+ freebytes(x->channel2,0);
+ freebytes(x->output,0);
+ freebytes(x->sieve,0);
+}
+
+void leaker_upsieve(t_leaker *x) {
+ int i;
+ for( i = 0; i < x->N2; i++ ){
+ x->sieve[i] = i + 1;
+ }
+}
+
+void leaker_downsieve(t_leaker *x) {
+ int i;
+ for( i = 0; i < x->N2; i++ ){
+ x->sieve[i] = x->N2 - i;
+ }
+}
+
+void leaker_randsieve(t_leaker *x) {
+ int i,j;
+ int NSwitch = 100000 ;
+ int temp ;
+ int pos1, pos2;
+
+ // use better algorithm
+
+ for( i = 0; i < x->N2; i++ ){
+ x->sieve[i] = i + 1;
+ }
+ for( i = 0; i < NSwitch; i++ ){
+ pos1 = rand() % x->N2;
+ pos2 = rand() % x->N2;
+ temp = x->sieve[pos2];
+ x->sieve[pos2] = x->sieve[pos1];
+ x->sieve[pos1] = temp ;
+ }
+}
+
+void leaker_bypass(t_leaker *x, t_floatarg state)
+{
+ x->bypass = (short)state;
+}
+void leaker_mute(t_leaker *x, t_floatarg state)
+{
+ x->mute = (short)state;
+}
+
+
+void leaker_assist (t_leaker *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0: sprintf(dst,"(signal) Input 1");break;
+ case 1: sprintf(dst,"(signal) Input 2");break;
+ case 2: sprintf(dst,"(signal/float) Crossfade Position (0.0 - 1.0)");break;
+ }
+ } else if (msg==2) {
+ sprintf(dst,"(signal) Output ");
+ }
+}
+
+void *leaker_new(t_symbol *msg, short argc, t_atom *argv)
+{
+#if MSP
+ t_leaker *x = (t_leaker *)newobject(leaker_class);
+ dsp_setup((t_pxobject *)x,3);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+
+#if PD
+ t_leaker *x = (t_leaker *)pd_new(leaker_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+ x->D = sys_getblksize();
+ x->R = sys_getsr();
+ if(!x->D)
+ x->D = 256;
+ if(!x->R)
+ x->R = 44100;
+
+ x->overlap = atom_getfloatarg(0,argc,argv);
+ x->winfac = atom_getfloatarg(1,argc,argv);
+ if(!x->overlap)
+ x->overlap = 4;
+ if(!x->winfac)
+ x->winfac = 1;
+
+ leaker_init(x,0);
+ return (x);
+}
+
+void leaker_init(t_leaker *x, short initialized)
+{
+ int i;
+ if(!power_of_two(x->overlap))
+ x->overlap = 4;
+ if(!power_of_two(x->winfac))
+ x->winfac = 2;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+ x->c_fundamental = (float) x->R/( (x->N2)<<1 );
+ x->c_factor_in = (float) x->R/((float)x->D * TWOPI);
+ x->c_factor_out = TWOPI * (float) x->D / (float) x->R;
+
+ if(!initialized) {
+ x->mute = 0;
+ x->bypass = 0;
+ x->fade_connected = 0;
+ x->fade_value = 0;
+
+ x->input1 = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->buffer1 = (float *) getbytes(MAX_N * sizeof(float));
+ x->channel1 = (float *) getbytes((MAX_N+2) * sizeof(float));
+ x->input2 = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->buffer2 = (float *) getbytes(MAX_N * sizeof(float));
+ x->channel2 = (float *) getbytes((MAX_N+2) * sizeof(float));
+ x->Wanal = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->Wsyn = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->Hwin = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->output = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->bitshuffle = (int *) getbytes (MAX_N * 2 * sizeof( int ));
+ x->trigland = (float *) getbytes(MAX_N * 2 * sizeof( float ));
+ x->sieve = (int *) getbytes((MAX_N2 + 1) * sizeof(int));
+ x->c_lastphase_in1 = (float *) getbytes((MAX_N2+1) * sizeof(float));
+ x->c_lastphase_in2 = (float *) getbytes((MAX_N2+1) * sizeof(float));
+ x->c_lastphase_out = (float *) getbytes((MAX_N2+1) * sizeof(float));
+
+ }
+
+ memset((char *)x->input1,0,x->Nw);
+ memset((char *)x->input2,0,x->Nw);
+ memset((char *)x->output,0,x->Nw);
+ memset((char *)x->c_lastphase_in1,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->c_lastphase_in2,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->c_lastphase_out,0,(x->N2+1) * sizeof(float));
+
+ init_rdft(x->N, x->bitshuffle, x->trigland);
+ makehanning(x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 0);
+ if(initialized != 2){
+ for(i = 0; i < x->N2; i++){
+ x->sieve[i] = i;
+ }
+ }
+}
+
+t_int *leaker_perform(t_int *w)
+{
+ int i,j,odd,even;
+ float a1,a2,b1,b2;
+
+ t_leaker *x = (t_leaker *) (w[1]);
+ 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 n = w[6];
+
+ float fade_value = x->fade_value;
+ float *input1 = x->input1;
+ float *input2 = x->input2;
+ int inCount = x->inCount;
+ int R = x->R;
+ int N = x->N;
+ int N2 = x->N2;
+ int D = x->D;
+ int Nw = x->Nw;
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *output = x->output;
+ float *buffer1 = x->buffer1;
+ float *buffer2 = x->buffer2;
+ float *channel1 = x->channel1;
+ float *channel2 = x->channel2;
+ int *sieve = x->sieve;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland;
+ float mult = x->mult;
+
+ /* dereference struncture */
+ if( x->mute) {
+ while(n--){
+ *out++ = 0.;
+ }
+ return (w+7);
+ }
+ if( x->bypass ) {
+ while(n--){
+ *out++ = *in1++;
+ }
+ return (w+7);
+ }
+
+#if MSP
+ if(x->fade_connected)
+ fade_value = *in3++ * (float) N2;
+#endif
+
+#if PD
+ fade_value = *in3++ * (float) N2;
+#endif
+
+ inCount += D;
+
+ for ( j = 0 ; j < Nw - D ; j++ ){
+ input1[j] = input1[j+D];
+ input2[j] = input2[j+D];
+ }
+ for ( j = Nw - D; j < Nw; j++ ) {
+ input1[j] = *in1++;
+ input2[j] = *in2++;
+ }
+
+ fold(input1, Wanal, Nw, buffer1, N, inCount);
+ fold(input2, Wanal, Nw, buffer2, N, inCount);
+ rdft(N, 1, buffer1, bitshuffle, trigland);
+ rdft(N, 1, buffer2, bitshuffle, trigland);
+
+
+ for ( i = 0; i <= N2; i++ ) {
+ odd = ( even = i<<1 ) + 1;
+ if( fade_value <= 0 || fade_value < sieve[i] ){
+ a1 = ( i == N2 ? *(buffer1+1) : *(buffer1+even) );
+ b1 = ( i == 0 || i == N2 ? 0. : *(buffer1+odd) );
+
+ *(channel1+even) = hypot( a1, b1 ) ;
+ *(channel1+odd) = -atan2( b1, a1 );
+ *(buffer1+even) = *(channel1+even) * cos(*(channel1+odd));
+ if ( i != N2 ){
+ *(buffer1+odd) = -(*(channel1+even)) * sin(*(channel1+odd));
+ }
+ } else {
+ a2 = ( i == N2 ? *(buffer2+1) : *(buffer2+even) );
+ b2 = ( i == 0 || i == N2 ? 0. : *(buffer2+odd) );
+ *(channel1+even) = hypot( a2, b2 ) ;
+ *(channel1+odd) = -atan2( b2, a2 );
+ *(buffer1+even) = *(channel1+even) * cos(*(channel1+odd) );
+ if ( i != N2 ){
+ *(buffer1+odd) = -(*(channel1+even)) * sin( *(channel1+odd) );
+ }
+ }
+ }
+
+ rdft( N, -1, buffer1, bitshuffle, trigland );
+ overlapadd( buffer1, N, Wsyn, output, Nw, inCount);
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+ x->inCount = inCount % Nw;
+
+ return (w+7);
+}
+
+void leaker_dsp(t_leaker *x, t_signal **sp, short *count)
+{
+ long i;
+#if MSP
+ x->fade_connected = count[2];
+#endif
+ if(x->R != sp[0]->s_sr || x->D != sp[0]->s_n){
+ x->R = sp[0]->s_sr;
+ x->D = sp[0]->s_n;
+ leaker_init(x,1);
+ }
+
+ dsp_add(leaker_perform, 6, x,
+ sp[0]->s_vec,sp[1]->s_vec,sp[2]->s_vec,sp[3]->s_vec,sp[0]->s_n);
+}
+#if MSP
+void leaker_float(t_leaker *x, double f)
+{
+ int inlet = x->x_obj.z_in;
+ if( inlet == 2 && f >= 0 && f <= 1){
+ x->fade_value = f * (float) x->N2;
+ }
+}
+#endif
+
diff --git a/lib/MSPd.h b/lib/MSPd.h
new file mode 100644
index 0000000..a47ce2b
--- /dev/null
+++ b/lib/MSPd.h
@@ -0,0 +1,36 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+
+
+#ifndef PIOVERTWO
+#define PIOVERTWO 1.5707963268
+#define TWOPI 6.2831853072
+#endif
+
+#if MSP
+#include "ext.h"
+#include "z_dsp.h"
+#include "buffer.h"
+#include "ext_obex.h"
+#define t_floatarg double
+#define resizebytes t_resizebytes
+#define getbytes t_getbytes
+#define freebytes t_freebytes
+
+#endif
+
+#if PD
+#include "m_pd.h"
+#define t_floatarg float
+#endif
+
+/* because Max and Pd have different ideas of what A_FLOAT is, use t_floatarg
+to force consistency. Otherwise functions that look good will fail on some
+hardware. Also note that Pd messages cannot accept arguments of type A_LONG. */
+
+
+
+
+
diff --git a/lib/PenroseOscil.c b/lib/PenroseOscil.c
new file mode 100644
index 0000000..78cd7b6
--- /dev/null
+++ b/lib/PenroseOscil.c
@@ -0,0 +1,40 @@
+#include <math.h>
+#include "PenroseOscil.h"
+
+
+float frequencyToIncrement( float samplingRate, float frequency, int bufferLength ) {
+
+ return (frequency / samplingRate) * (float) bufferLength;
+}
+
+void makeSineBuffer( float *buffer, int bufferLength ) {
+
+ int i;
+
+ float myTwoPi = 8. * atan(1.);
+
+ for ( i=0; i <= bufferLength; i++ )
+ *(buffer+i) = sin( myTwoPi * ((float) i / (float) bufferLength) );
+
+ return;
+}
+
+
+float bufferOscil( float *phase, float increment, float *buffer,
+ int bufferLength )
+{
+
+ float sample;
+
+ while ( *phase > bufferLength )
+ *phase -= bufferLength;
+
+ while ( *phase < 0. )
+ *phase += bufferLength;
+
+ sample = *( buffer + (int) (*phase) );
+
+ *phase += increment;
+
+ return sample;
+}
diff --git a/lib/PenroseOscil.h b/lib/PenroseOscil.h
new file mode 100644
index 0000000..a47414d
--- /dev/null
+++ b/lib/PenroseOscil.h
@@ -0,0 +1,8 @@
+
+float frequencyToIncrement( float samplingRate, float frequency,
+ int bufferLength );
+
+void makeSineBuffer( float *buffer, int bufferLength );
+
+float bufferOscil( float *phase, float increment, float *buffer,
+ int bufferLength );
diff --git a/lib/PenroseRand.c b/lib/PenroseRand.c
new file mode 100644
index 0000000..98f396e
--- /dev/null
+++ b/lib/PenroseRand.c
@@ -0,0 +1,13 @@
+#include "PenroseRand.h"
+
+float rrand(int *seed)
+{
+ int i = ((*seed = *seed * 1103515245 + 12345)>>16) & 077777;
+ return((float)i/16384. - 1.);
+}
+
+float prand(int *seed)
+{
+ int i = ((*seed = *seed * 1103515245 + 12345)>>16) & 077777;
+ return((float)i/32768.);
+}
diff --git a/lib/PenroseRand.h b/lib/PenroseRand.h
new file mode 100644
index 0000000..fb06588
--- /dev/null
+++ b/lib/PenroseRand.h
@@ -0,0 +1,3 @@
+
+float rrand(int *seed);
+float prand(int *seed);
diff --git a/lib/bloscbank.c b/lib/bloscbank.c
new file mode 100644
index 0000000..c35ab0d
--- /dev/null
+++ b/lib/bloscbank.c
@@ -0,0 +1 @@
+ #include "fftease.h" void bloscbank( float *S, float *O, int D, float iD, float *lf, float *la, float *index, float *tab, int len, float synt, int lo, int hi ) { int amp,freq,chan, i; float a,ainc,f,finc,address; for ( chan = lo; chan < hi; chan++ ) { freq = ( amp = ( chan << 1 ) ) + 1; if ( S[amp] > synt ){ finc = ( S[freq] - ( f = lf[chan] ) )* iD; ainc = ( S[amp] - ( a = la[chan] ) )* iD; address = index[chan]; for ( i = 0; i < D ; i++ ) { O[i] += a*tab[ (int) address ]; address += f; while ( address >= len ) address -= len; while ( address < 0 ) address += len; a += ainc; f += finc; } lf[chan] = S[freq]; la[chan] = S[amp]; index[chan] = address; } } } \ No newline at end of file
diff --git a/lib/convert.c b/lib/convert.c
new file mode 100644
index 0000000..0131774
--- /dev/null
+++ b/lib/convert.c
@@ -0,0 +1 @@
+#include "fftease.h" /* S is a spectrum in rfft format, i.e., it contains N real values arranged as real followed by imaginary values, except for first two values, which are real parts of 0 and Nyquist frequencies; convert first changes these into N/2+1 PAIRS of magnitude and phase values to be stored in output array C; the phases are then unwrapped and successive phase differences are used to compute estimates of the instantaneous frequencies for each phase vocoder analysis channel; decimation rate D and sampling rate R are used to render these frequency values directly in Hz. */ void convert(float *S, float *C, int N2, float *lastphase, float fundamental, float factor ) { float phase, phasediff; int real, imag, amp, freq; float a, b; int i; /* float myTWOPI, myPI; */ /* double sin(), cos(), atan(), hypot();*/ /* myTWOPI = 8.*atan(1.); myPI = 4.*atan(1.); */ for ( i = 0; i <= N2; i++ ) { imag = freq = ( real = amp = i<<1 ) + 1; a = ( i == N2 ? S[1] : S[real] ); b = ( i == 0 || i == N2 ? 0. : S[imag] ); C[amp] = hypot( a, b ); if ( C[amp] == 0. ) phasediff = 0.; else { phasediff = ( phase = -atan2( b, a ) ) - lastphase[i]; lastphase[i] = phase; while ( phasediff > PI ) phasediff -= TWOPI; while ( phasediff < -PI ) phasediff += TWOPI; } C[freq] = phasediff*factor + i*fundamental; } } \ No newline at end of file
diff --git a/lib/fft.c b/lib/fft.c
new file mode 100644
index 0000000..d6bb1bc
--- /dev/null
+++ b/lib/fft.c
@@ -0,0 +1 @@
+#include "fftease.h" /* If forward is true, rfft replaces 2*N real data points in x with N complex values representing the positive frequency half of their Fourier spectrum, with x[1] replaced with the real part of the Nyquist frequency value. If forward is false, rfft expects x to contain a positive frequency spectrum arranged as before, and replaces it with 2*N real values. N MUST be a power of 2. */ void rfft( float *x, int N, int forward ) { float c1,c2, h1r,h1i, h2r,h2i, wr,wi, wpr,wpi, temp, theta; float xr,xi; int i, i1,i2,i3,i4, N2p1; static int first = 1; /*float PI, TWOPI;*/ void cfft(); if ( first ) { first = 0; } theta = PI/N; wr = 1.; wi = 0.; c1 = 0.5; if ( forward ) { c2 = -0.5; cfft( x, N, forward ); xr = x[0]; xi = x[1]; } else { c2 = 0.5; theta = -theta; xr = x[1]; xi = 0.; x[1] = 0.; } wpr = -2.*pow( sin( 0.5*theta ), 2. ); wpi = sin( theta ); N2p1 = (N<<1) + 1; for ( i = 0; i <= N>>1; i++ ) { i1 = i<<1; i2 = i1 + 1; i3 = N2p1 - i2; i4 = i3 + 1; if ( i == 0 ) { h1r = c1*(x[i1] + xr ); h1i = c1*(x[i2] - xi ); h2r = -c2*(x[i2] + xi ); h2i = c2*(x[i1] - xr ); x[i1] = h1r + wr*h2r - wi*h2i; x[i2] = h1i + wr*h2i + wi*h2r; xr = h1r - wr*h2r + wi*h2i; xi = -h1i + wr*h2i + wi*h2r; } else { h1r = c1*(x[i1] + x[i3] ); h1i = c1*(x[i2] - x[i4] ); h2r = -c2*(x[i2] + x[i4] ); h2i = c2*(x[i1] - x[i3] ); x[i1] = h1r + wr*h2r - wi*h2i; x[i2] = h1i + wr*h2i + wi*h2r; x[i3] = h1r - wr*h2r + wi*h2i; x[i4] = -h1i + wr*h2i + wi*h2r; } wr = (temp = wr)*wpr - wi*wpi + wr; wi = wi*wpr + temp*wpi + wi; } if ( forward ) x[1] = xr; else cfft( x, N, forward ); } /* cfft replaces float array x containing NC complex values (2*NC float values alternating real, imagininary, etc.) by its Fourier transform if forward is true, or by its inverse Fourier transform if forward is false, using a recursive Fast Fourier transform method due to Danielson and Lanczos. NC MUST be a power of 2. */ void cfft( float *x, int NC, int forward ) { float wr,wi, wpr,wpi, theta, scale; int mmax, ND, m, i,j, delta; void bitreverse(); ND = NC<<1; bitreverse( x, ND ); for ( mmax = 2; mmax < ND; mmax = delta ) { delta = mmax<<1; theta = TWOPI/( forward? mmax : -mmax ); wpr = -2.*pow( sin( 0.5*theta ), 2. ); wpi = sin( theta ); wr = 1.; wi = 0.; for ( m = 0; m < mmax; m += 2 ) { register float rtemp, itemp; for ( i = m; i < ND; i += delta ) { j = i + mmax; rtemp = wr*x[j] - wi*x[j+1]; itemp = wr*x[j+1] + wi*x[j]; x[j] = x[i] - rtemp; x[j+1] = x[i+1] - itemp; x[i] += rtemp; x[i+1] += itemp; } wr = (rtemp = wr)*wpr - wi*wpi + wr; wi = wi*wpr + rtemp*wpi + wi; } } /* scale output */ scale = forward ? 1./ND : 2.; { register float *xi=x, *xe=x+ND; while ( xi < xe ) *xi++ *= scale; } } /* bitreverse places float array x containing N/2 complex values into bit-reversed order */ void bitreverse( float *x, int N ) { float rtemp,itemp; int i,j, m; for ( i = j = 0; i < N; i += 2, j += m ) { if ( j > i ) { rtemp = x[j]; itemp = x[j+1]; /* complex exchange */ x[j] = x[i]; x[j+1] = x[i+1]; x[i] = rtemp; x[i+1] = itemp; } for ( m = N>>1; m >= 2 && j >= m; m >>= 1 ) j -= m; } } \ No newline at end of file
diff --git a/lib/fft4.c b/lib/fft4.c
new file mode 100644
index 0000000..fb22118
--- /dev/null
+++ b/lib/fft4.c
@@ -0,0 +1 @@
+#include <math.h> #include "fftease.h" void init_rdft(int n, int *ip, float *w) { int nw, nc; void makewt(int nw, int *ip, float *w); void makect(int nc, int *ip, float *c); nw = n >> 2; makewt(nw, ip, w); nc = n >> 2; makect(nc, ip, w + nw); return; } void rdft(int n, int isgn, float *a, int *ip, float *w) { int j, nw, nc; float xi; void bitrv2(int n, int *ip, float *a), cftsub(int n, float *a, float *w), rftsub(int n, float *a, int nc, float *c); nw = ip[0]; nc = ip[1]; if (isgn < 0) { a[1] = 0.5 * (a[1] - a[0]); a[0] += a[1]; for (j = 3; j <= n - 1; j += 2) { a[j] = -a[j]; } if (n > 4) { rftsub(n, a, nc, w + nw); bitrv2(n, ip + 2, a); } cftsub(n, a, w); for (j = 1; j <= n - 1; j += 2) { a[j] = -a[j]; } } else { if (n > 4) { bitrv2(n, ip + 2, a); } cftsub(n, a, w); if (n > 4) { rftsub(n, a, nc, w + nw); } xi = a[0] - a[1]; a[0] += a[1]; a[1] = xi; } } void bitrv2(int n, int *ip, float *a) { int j, j1, k, k1, l, m, m2; float xr, xi; ip[0] = 0; l = n; m = 1; while ((m << 2) < l) { l >>= 1; for (j = 0; j <= m - 1; j++) { ip[m + j] = ip[j] + l; } m <<= 1; } if ((m << 2) > l) { for (k = 1; k <= m - 1; k++) { for (j = 0; j <= k - 1; j++) { j1 = (j << 1) + ip[k]; k1 = (k << 1) + ip[j]; xr = a[j1]; xi = a[j1 + 1]; a[j1] = a[k1]; a[j1 + 1] = a[k1 + 1]; a[k1] = xr; a[k1 + 1] = xi; } } } else { m2 = m << 1; for (k = 1; k <= m - 1; k++) { for (j = 0; j <= k - 1; j++) { j1 = (j << 1) + ip[k]; k1 = (k << 1) + ip[j]; xr = a[j1]; xi = a[j1 + 1]; a[j1] = a[k1]; a[j1 + 1] = a[k1 + 1]; a[k1] = xr; a[k1 + 1] = xi; j1 += m2; k1 += m2; xr = a[j1]; xi = a[j1 + 1]; a[j1] = a[k1]; a[j1 + 1] = a[k1 + 1]; a[k1] = xr; a[k1 + 1] = xi; } } } } void cftsub(int n, float *a, float *w) { int j, j1, j2, j3, k, k1, ks, l, m; float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; l = 2; while ((l << 1) < n) { m = l << 2; for (j = 0; j <= l - 2; j += 2) { j1 = j + l; j2 = j1 + l; j3 = j2 + l; x0r = a[j] + a[j1]; x0i = a[j + 1] + a[j1 + 1]; x1r = a[j] - a[j1]; x1i = a[j + 1] - a[j1 + 1]; x2r = a[j2] + a[j3]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2] - a[j3]; x3i = a[j2 + 1] - a[j3 + 1]; a[j] = x0r + x2r; a[j + 1] = x0i + x2i; a[j2] = x0r - x2r; a[j2 + 1] = x0i - x2i; a[j1] = x1r - x3i; a[j1 + 1] = x1i + x3r; a[j3] = x1r + x3i; a[j3 + 1] = x1i - x3r; } if (m < n) { wk1r = w[2]; for (j = m; j <= l + m - 2; j += 2) { j1 = j + l; j2 = j1 + l; j3 = j2 + l; x0r = a[j] + a[j1]; x0i = a[j + 1] + a[j1 + 1]; x1r = a[j] - a[j1]; x1i = a[j + 1] - a[j1 + 1]; x2r = a[j2] + a[j3]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2] - a[j3]; x3i = a[j2 + 1] - a[j3 + 1]; a[j] = x0r + x2r; a[j + 1] = x0i + x2i; a[j2] = x2i - x0i; a[j2 + 1] = x0r - x2r; x0r = x1r - x3i; x0i = x1i + x3r; a[j1] = wk1r * (x0r - x0i); a[j1 + 1] = wk1r * (x0r + x0i); x0r = x3i + x1r; x0i = x3r - x1i; a[j3] = wk1r * (x0i - x0r); a[j3 + 1] = wk1r * (x0i + x0r); } k1 = 1; ks = -1; for (k = (m << 1); k <= n - m; k += m) { k1++; ks = -ks; wk1r = w[k1 << 1]; wk1i = w[(k1 << 1) + 1]; wk2r = ks * w[k1]; wk2i = w[k1 + ks]; wk3r = wk1r - 2 * wk2i * wk1i; wk3i = 2 * wk2i * wk1r - wk1i; for (j = k; j <= l + k - 2; j += 2) { j1 = j + l; j2 = j1 + l; j3 = j2 + l; x0r = a[j] + a[j1]; x0i = a[j + 1] + a[j1 + 1]; x1r = a[j] - a[j1]; x1i = a[j + 1] - a[j1 + 1]; x2r = a[j2] + a[j3]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2] - a[j3]; x3i = a[j2 + 1] - a[j3 + 1]; a[j] = x0r + x2r; a[j + 1] = x0i + x2i; x0r -= x2r; x0i -= x2i; a[j2] = wk2r * x0r - wk2i * x0i; a[j2 + 1] = wk2r * x0i + wk2i * x0r; x0r = x1r - x3i; x0i = x1i + x3r; a[j1] = wk1r * x0r - wk1i * x0i; a[j1 + 1] = wk1r * x0i + wk1i * x0r; x0r = x1r + x3i; x0i = x1i - x3r; a[j3] = wk3r * x0r - wk3i * x0i; a[j3 + 1] = wk3r * x0i + wk3i * x0r; } } } l = m; } if (l < n) { for (j = 0; j <= l - 2; j += 2) { j1 = j + l; x0r = a[j] - a[j1]; x0i = a[j + 1] - a[j1 + 1]; a[j] += a[j1]; a[j + 1] += a[j1 + 1]; a[j1] = x0r; a[j1 + 1] = x0i; } } } void rftsub(int n, float *a, int nc, float *c) { int j, k, kk, ks; float wkr, wki, xr, xi, yr, yi; ks = (nc << 2) / n; kk = 0; for (k = (n >> 1) - 2; k >= 2; k -= 2) { j = n - k; kk += ks; wkr = 0.5 - c[kk]; wki = c[nc - kk]; xr = a[k] - a[j]; xi = a[k + 1] + a[j + 1]; yr = wkr * xr - wki * xi; yi = wkr * xi + wki * xr; a[k] -= yr; a[k + 1] -= yi; a[j] += yr; a[j + 1] -= yi; } } void makewt(int nw, int *ip, float *w) { void bitrv2(int n, int *ip, float *a); int nwh, j; float delta, x, y; ip[0] = nw; ip[1] = 1; if (nw > 2) { nwh = nw >> 1; delta = atan(1.0) / nwh; w[0] = 1; w[1] = 0; w[nwh] = cos(delta * nwh); w[nwh + 1] = w[nwh]; for (j = 2; j <= nwh - 2; j += 2) { x = cos(delta * j); y = sin(delta * j); w[j] = x; w[j + 1] = y; w[nw - j] = y; w[nw - j + 1] = x; } bitrv2(nw, ip + 2, w); } } void makect(int nc, int *ip, float *c) { int nch, j; float delta; ip[1] = nc; if (nc > 1) { nch = nc >> 1; delta = atan(1.0) / nch; c[0] = 0.5; c[nch] = 0.5 * cos(delta * nch); for (j = 1; j <= nch - 1; j++) { c[j] = 0.5 * cos(delta * j); c[nc - j] = 0.5 * sin(delta * j); } } } \ No newline at end of file
diff --git a/lib/fftease.h b/lib/fftease.h
new file mode 100644
index 0000000..30b39e9
--- /dev/null
+++ b/lib/fftease.h
@@ -0,0 +1,50 @@
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+#define FORWARD 1
+#define INVERSE 0
+
+#ifndef PI
+#define PI 3.141592653589793115997963468544185161590576171875
+#endif
+
+#ifndef TWOPI
+#define TWOPI 6.28318530717958623199592693708837032318115234375
+#endif
+
+#define FFTEASE_ANNOUNCEMENT "- a member of FFTease 2.5\nby Eric Lyon and Christopher Penrose"
+
+#define MAX_N (16384)
+#define MAX_Nw (MAX_N * 4)
+#define MAX_N2 (MAX_N/2)
+
+void rfft( float *x, int N, int forward );
+void cfft( float *x, int NC, int forward );
+void convert(float *S, float *C, int N2, float *lastphase, float fundamental, float factor );
+void unconvert( float *C, float *S, int N2, float *lastphase, float fundamental, float factor );
+void leanconvert( float *S, float *C, int N2 );
+void leanunconvert( float *C, float *S, int N2 );
+void makewindows( float *H, float *A, float *S, int Nw, int N, int I );
+void makehamming( float *H, float *A, float *S, int Nw, int N, int I,int odd );
+void makehanning( float *H, float *A, float *S, int Nw, int N, int I,int odd );
+void fold( float *I, float *W, int Nw, float *O, int N, int n );
+void overlapadd( float *I, int N, float *W, float *O, int Nw, int n );
+void bitreverse( float *x, int N );
+void bloscbank( float *S, float *O, int D, float iD, float *lf, float *la, float *bindex, float *tab,
+ int len, float synt, int lo, int hi );
+/* fast fft calls */
+void makect(int nc, int *ip, float *c);
+void makewt(int nw, int *ip, float *w);
+void rftsub(int n, float *a, int nc, float *c);
+void cftsub(int n, float *a, float *w);
+void bitrv2(int n, int *ip, float *a);
+void rdft(int n, int isgn, float *a, int *ip, float *w);
+void init_rdft(int n, int *ip, float *w);
+/* rands */
+float randf( float min, float max );
+int randi( int min, int max );
+int power_of_two(int test);
+
+void limit_fftsize(int *N, int *Nw, char *OBJECT_NAME);
+
diff --git a/lib/fftease_setup.c b/lib/fftease_setup.c
new file mode 100644
index 0000000..521fde8
--- /dev/null
+++ b/lib/fftease_setup.c
@@ -0,0 +1,9 @@
+
+#include "m_pd.h"
+#include <stdio.h>
+
+void fftease_setup(void)
+{
+// post("Loaded FFTease Library");
+ printf("Loaded FFTease Library(2)");
+}
diff --git a/lib/fold.c b/lib/fold.c
new file mode 100644
index 0000000..0523d28
--- /dev/null
+++ b/lib/fold.c
@@ -0,0 +1 @@
+#include "fftease.h" /* * multiply current input I by window W (both of length Nw); * using modulus arithmetic, fold and rotate windowed input * into output array O of (FFT) length N according to current * input time n */ void fold( float *I, float *W, int Nw, float *O, int N, int n ) { int i; for ( i = 0; i < N; i++ ) O[i] = 0.; while ( n < 0 ) n += N; n %= N; for ( i = 0; i < Nw; i++ ) { O[n] += I[i]*W[i]; if ( ++n == N ) n = 0; } } \ No newline at end of file
diff --git a/lib/leanconvert.c b/lib/leanconvert.c
new file mode 100644
index 0000000..617c665
--- /dev/null
+++ b/lib/leanconvert.c
@@ -0,0 +1 @@
+#include "fftease.h" void leanconvert( float *S, float *C, int N2 ) { int real, imag, amp, phase; float a, b; int i; double hypot(), atan2(); for ( i = 0; i <= N2; i++ ) { imag = phase = ( real = amp = i<<1 ) + 1; a = ( i == N2 ? S[1] : S[real] ); b = ( i == 0 || i == N2 ? 0. : S[imag] ); C[amp] = hypot( a, b ); C[phase] = -atan2( b, a ); } } \ No newline at end of file
diff --git a/lib/leanunconvert.c b/lib/leanunconvert.c
new file mode 100644
index 0000000..4880729
--- /dev/null
+++ b/lib/leanunconvert.c
@@ -0,0 +1 @@
+#include "fftease.h" /* unconvert essentially undoes what convert does, i.e., it turns N2+1 PAIRS of amplitude and frequency values in C into N2 PAIR of complex spectrum data (in rfft format) in output array S; sampling rate R and interpolation factor I are used to recompute phase values from frequencies */ void leanunconvert( float *C, float *S, int N2 ) { double cos(), sin(); int real, imag, amp, phase; register int i; for ( i = 0; i <= N2; i++ ) { imag = phase = ( real = amp = i<<1 ) + 1; S[real] = *(C+amp) * cos( *(C+phase) ); if ( i != N2 ) S[imag] = -*(C+amp) * sin( *(C+phase) ); } } \ No newline at end of file
diff --git a/lib/limit_fftsize.c b/lib/limit_fftsize.c
new file mode 100644
index 0000000..4ad4612
--- /dev/null
+++ b/lib/limit_fftsize.c
@@ -0,0 +1,17 @@
+#include "fftease.h"
+
+//extern void post(const char *fmt, ...);
+
+void limit_fftsize(int *N, int *Nw, char *OBJECT_NAME)
+{
+ if(*N > MAX_N){
+// post("%s: N set to maximum FFT size of %d",OBJECT_NAME,MAX_N);
+ printf("%s: N set to maximum FFT size of %d",OBJECT_NAME,MAX_N);
+ *N = MAX_N;
+ }
+ if(*Nw > MAX_Nw){
+// post("%s: Nw set to maximum window size of %d",OBJECT_NAME,MAX_Nw);
+ printf("%s: Nw set to maximum window size of %d",OBJECT_NAME,MAX_Nw);
+ *Nw = MAX_Nw;
+ }
+}
diff --git a/lib/makewindows.c b/lib/makewindows.c
new file mode 100644
index 0000000..81a80f0
--- /dev/null
+++ b/lib/makewindows.c
@@ -0,0 +1 @@
+#include "fftease.h" void makewindows( float *H, float *A, float *S, int Nw, int N, int I ) { int i ; float sum ; for ( i = 0 ; i < Nw ; i++ ) H[i] = A[i] = S[i] = 0.54 - 0.46*cos( TWOPI*i/(Nw - 1) ) ; if ( Nw > N ) { float x ; x = -(Nw - 1)/2. ; for ( i = 0 ; i < Nw ; i++, x += 1. ) if ( x != 0. ) { A[i] *= N*sin( PI*x/N )/(PI*x) ; if ( I ) S[i] *= I*sin( PI*x/I )/(PI*x) ; } } for ( sum = i = 0 ; i < Nw ; i++ ) sum += A[i] ; for ( i = 0 ; i < Nw ; i++ ) { float afac = 2./sum ; float sfac = Nw > N ? 1./afac : afac ; A[i] *= afac ; S[i] *= sfac ; } if ( Nw <= N && I ) { for ( sum = i = 0 ; i < Nw ; i += I ) sum += S[i]*S[i] ; for ( sum = 1./sum, i = 0 ; i < Nw ; i++ ) S[i] *= sum ; } } void makehamming( float *H, float *A, float *S, int Nw, int N, int I, int odd ) { int i; float sum ; if (odd) { for ( i = 0 ; i < Nw ; i++ ) H[i] = A[i] = S[i] = sqrt(0.54 - 0.46*cos( TWOPI*i/(Nw - 1) )); } else { for ( i = 0 ; i < Nw ; i++ ) H[i] = A[i] = S[i] = 0.54 - 0.46*cos( TWOPI*i/(Nw - 1) ); } if ( Nw > N ) { float x ; x = -(Nw - 1)/2. ; for ( i = 0 ; i < Nw ; i++, x += 1. ) if ( x != 0. ) { A[i] *= N*sin( PI*x/N )/(PI*x) ; if ( I ) S[i] *= I*sin( PI*x/I )/(PI*x) ; } } for ( sum = i = 0 ; i < Nw ; i++ ) sum += A[i] ; for ( i = 0 ; i < Nw ; i++ ) { float afac = 2./sum ; float sfac = Nw > N ? 1./afac : afac ; A[i] *= afac ; S[i] *= sfac ; } if ( Nw <= N && I ) { for ( sum = i = 0 ; i < Nw ; i += I ) sum += S[i]*S[i] ; for ( sum = 1./sum, i = 0 ; i < Nw ; i++ ) S[i] *= sum ; } } void makehanning( float *H, float *A, float *S, int Nw, int N, int I, int odd ) { int i; float sum ; if (odd) { for ( i = 0 ; i < Nw ; i++ ) H[i] = A[i] = S[i] = sqrt(0.5 * (1. + cos(PI + TWOPI * i / (Nw - 1)))); } else { for ( i = 0 ; i < Nw ; i++ ) H[i] = A[i] = S[i] = 0.5 * (1. + cos(PI + TWOPI * i / (Nw - 1))); } if ( Nw > N ) { float x ; x = -(Nw - 1)/2. ; for ( i = 0 ; i < Nw ; i++, x += 1. ) if ( x != 0. ) { A[i] *= N*sin( PI*x/N )/(PI*x) ; if ( I ) S[i] *= I*sin( PI*x/I )/(PI*x) ; } } for ( sum = i = 0 ; i < Nw ; i++ ) sum += A[i] ; for ( i = 0 ; i < Nw ; i++ ) { float afac = 2./sum ; float sfac = Nw > N ? 1./afac : afac ; A[i] *= afac ; S[i] *= sfac ; } if ( Nw <= N && I ) { for ( sum = i = 0 ; i < Nw ; i += I ) sum += S[i]*S[i] ; for ( sum = 1./sum, i = 0 ; i < Nw ; i++ ) S[i] *= sum ; } } \ No newline at end of file
diff --git a/lib/overlapadd.c b/lib/overlapadd.c
new file mode 100644
index 0000000..beab0e0
--- /dev/null
+++ b/lib/overlapadd.c
@@ -0,0 +1 @@
+/* * input I is a folded spectrum of length N; output O and * synthesis window W are of length Nw--overlap-add windowed, * unrotated, unfolded input data into output O */ #include "fftease.h" void overlapadd( float *I, int N, float *W, float *O, int Nw, int n ) { int i ; while ( n < 0 ) n += N ; n %= N ; for ( i = 0 ; i < Nw ; i++ ) { O[i] += I[n]*W[i] ; if ( ++n == N ) n = 0 ; } } \ No newline at end of file
diff --git a/lib/power_of_two.c b/lib/power_of_two.c
new file mode 100644
index 0000000..038c6a3
--- /dev/null
+++ b/lib/power_of_two.c
@@ -0,0 +1,17 @@
+
+int power_of_two(int test)
+{
+ int limit = 8192;
+ int compare = 1;
+ // post("testing what we thing is an int:%d",test);
+ do {
+ if(test == compare){
+ // post("good power of 2 found!");
+ return 1;
+ }
+ compare *= 2;
+ } while (compare <= limit);
+
+ return 0;
+}
+
diff --git a/lib/qsortE.c b/lib/qsortE.c
new file mode 100644
index 0000000..0fa7e50
--- /dev/null
+++ b/lib/qsortE.c
@@ -0,0 +1 @@
+/* Plug-compatible replacement for UNIX qsort. Copyright (C) 1989 Free Software Foundation, Inc. Written by Douglas C. Schmidt (schmidt@ics.uci.edu) This file is part of GNU CC. GNU QSORT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU QSORT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU QSORT; see the file COPYING. If not, write to the Free the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Synched up with: FSF 19.28. */ #ifdef sparc #include <alloca.h> #endif #include <stdlib.h> /* Invoke the comparison function, returns either 0, < 0, or > 0. */ #define CMP(A,B) ((*cmp)((A),(B))) /* Byte-wise swap two items of size SIZE. */ #define SWAP(A,B,SIZE) do {int sz = (SIZE); char *a = (A); char *b = (B); \ do { char _temp = *a;*a++ = *b;*b++ = _temp;} while (--sz);} while (0) /* Copy SIZE bytes from item B to item A. */ #define COPY(A,B,SIZE) {int sz = (SIZE); do { *(A)++ = *(B)++; } while (--sz); } /* This should be replaced by a standard ANSI macro. */ #define BYTES_PER_WORD 8 /* The next 4 #defines implement a very fast in-line stack abstraction. */ #define STACK_SIZE (BYTES_PER_WORD * sizeof (long)) #define PUSH(LOW,HIGH) do {top->lo = LOW;top++->hi = HIGH;} while (0) #define POP(LOW,HIGH) do {LOW = (--top)->lo;HIGH = top->hi;} while (0) #define STACK_NOT_EMPTY (stack < top) /* Discontinue quicksort algorithm when partition gets below this size. This particular magic number was chosen to work best on a Sun 4/260. */ #define MAX_THRESH 4 /* requisite prototype */ int qsortE (char *base_ptr, int total_elems, int size, int (*cmp)()); /* Stack node declarations used to store unfulfilled partition obligations. */ typedef struct { char *lo; char *hi; } stack_node; /* Order size using quicksort. This implementation incorporates four optimizations discussed in Sedgewick: 1. Non-recursive, using an explicit stack of pointer that store the next array partition to sort. To save time, this maximum amount of space required to store an array of MAX_INT is allocated on the stack. Assuming a 32-bit integer, this needs only 32 * sizeof (stack_node) == 136 bits. Pretty cheap, actually. 2. Choose the pivot element using a median-of-three decision tree. This reduces the probability of selecting a bad pivot value and eliminates certain extraneous comparisons. 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving insertion sort to order the MAX_THRESH items within each partition. This is a big win, since insertion sort is faster for small, mostly sorted array segments. 4. The larger of the two sub-partitions is always pushed onto the stack first, with the algorithm then concentrating on the smaller partition. This *guarantees* no more than log (n) stack size is needed (actually O(1) in this case)! */ int qsortE (char *base_ptr, int total_elems, int size, int (*cmp)()) { /* Allocating SIZE bytes for a pivot buffer facilitates a better algorithm below since we can do comparisons directly on the pivot. */ char *pivot_buffer = (char *) malloc(size); int max_thresh = MAX_THRESH * size; if (total_elems > MAX_THRESH) { char *lo = base_ptr; char *hi = lo + size * (total_elems - 1); stack_node stack[STACK_SIZE]; /* Largest size needed for 32-bit int!!! */ stack_node *top = stack + 1; while (STACK_NOT_EMPTY) { char *left_ptr; char *right_ptr; { char *pivot = pivot_buffer; { /* Select median value from among LO, MID, and HI. Rearrange LO and HI so the three values are sorted. This lowers the probability of picking a pathological pivot value and skips a comparison for both the LEFT_PTR and RIGHT_PTR. */ char *mid = lo + size * ((hi - lo) / size >> 1); if (CMP (mid, lo) < 0) SWAP (mid, lo, size); if (CMP (hi, mid) < 0) SWAP (mid, hi, size); else goto jump_over; if (CMP (mid, lo) < 0) SWAP (mid, lo, size); jump_over: COPY (pivot, mid, size); pivot = pivot_buffer; } left_ptr = lo + size; right_ptr = hi - size; /* Here's the famous ``collapse the walls'' section of quicksort. Gotta like those tight inner loops! They are the main reason that this algorithm runs much faster than others. */ do { while (CMP (left_ptr, pivot) < 0) left_ptr += size; while (CMP (pivot, right_ptr) < 0) right_ptr -= size; if (left_ptr < right_ptr) { SWAP (left_ptr, right_ptr, size); left_ptr += size; right_ptr -= size; } else if (left_ptr == right_ptr) { left_ptr += size; right_ptr -= size; break; } } while (left_ptr <= right_ptr); } /* Set up pointers for next iteration. First determine whether left and right partitions are below the threshold size. If so, ignore one or both. Otherwise, push the larger partition's bounds on the stack and continue sorting the smaller one. */ if ((right_ptr - lo) <= max_thresh) { if ((hi - left_ptr) <= max_thresh) /* Ignore both small partitions. */ POP (lo, hi); else /* Ignore small left partition. */ lo = left_ptr; } else if ((hi - left_ptr) <= max_thresh) /* Ignore small right partition. */ hi = right_ptr; else if ((right_ptr - lo) > (hi - left_ptr)) /* Push larger left partition indices. */ { PUSH (lo, right_ptr); lo = left_ptr; } else /* Push larger right partition indices. */ { PUSH (left_ptr, hi); hi = right_ptr; } } } /* Once the BASE_PTR array is partially sorted by quicksort the rest is completely sorted using insertion sort, since this is efficient for partitions below MAX_THRESH size. BASE_PTR points to the beginning of the array to sort, and END_PTR points at the very last element in the array (*not* one beyond it!). */ #define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) { char *end_ptr = base_ptr + size * (total_elems - 1); char *run_ptr; char *tmp_ptr = base_ptr; char *thresh = MIN (end_ptr, base_ptr + max_thresh); /* Find smallest element in first threshold and place it at the array's beginning. This is the smallest array element, and the operation speeds up insertion sort's inner loop. */ for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size) if (CMP (run_ptr, tmp_ptr) < 0) tmp_ptr = run_ptr; if (tmp_ptr != base_ptr) SWAP (tmp_ptr, base_ptr, size); /* Insertion sort, running from left-hand-side up to `right-hand-side.' Pretty much straight out of the original GNU qsort routine. */ for (run_ptr = base_ptr + size; (tmp_ptr = run_ptr += size) <= end_ptr; ) { while (CMP (run_ptr, tmp_ptr -= size) < 0) ; if ((tmp_ptr += size) != run_ptr) { char *trav; for (trav = run_ptr + size; --trav >= run_ptr;) { char c = *trav; char *hi, *lo; for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo) *hi = *lo; *hi = c; } } } } return 1; } \ No newline at end of file
diff --git a/lib/unconvert.c b/lib/unconvert.c
new file mode 100644
index 0000000..85392dd
--- /dev/null
+++ b/lib/unconvert.c
@@ -0,0 +1,34 @@
+#include "fftease.h"
+
+
+
+void unconvert( float *C, float *S, int N2, float *lastphase, float fundamental, float factor )
+
+{
+ int i,
+ real,
+ imag,
+ amp,
+ freq;
+ float mag,
+ phase;
+double sin(), cos();
+
+ for ( i = 0; i <= N2; i++ ) {
+
+ imag = freq = ( real = amp = i<<1 ) + 1;
+
+ if ( i == N2 )
+ real = 1;
+
+ mag = C[amp];
+ lastphase[i] += C[freq] - i*fundamental;
+ phase = lastphase[i]*factor;
+ S[real] = mag*cos( phase );
+
+ if ( i != N2 )
+ S[imag] = -mag*sin( phase );
+
+ }
+
+}
diff --git a/mindwarp~.c b/mindwarp~.c
new file mode 100644
index 0000000..d49769e
--- /dev/null
+++ b/mindwarp~.c
@@ -0,0 +1,643 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *mindwarp_class;
+#endif
+#if PD
+static t_class *mindwarp_class;
+#endif
+
+#define OBJECT_NAME "mindwarp~"
+
+
+#define MAX_WARP 16.0
+
+/* 12.11.05 fixed divide-by-zero bug */
+
+typedef struct _mindwarp
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ int warpConnected;
+ int widthConnected;
+ int *bitshuffle;
+
+ float warpFactor;
+ float shapeWidth;
+ float *Wanal;
+ float *Wsyn;
+ float *inputOne;
+ float *Hwin;
+ float *bufferOne;
+ float *channelOne;
+ float *newChannel;
+ float *newAmplitudes;
+ float *output;
+ float mult;
+ float *trigland;
+ short connected[8];
+ short mute;
+ int overlap;//overlap factor
+ int winfac;//window factor
+ int vs;//vector size
+} t_mindwarp;
+
+
+/* msp function prototypes */
+
+void *mindwarp_new(t_symbol *s, int argc, t_atom *argv);
+
+t_int *mindwarp_perform(t_int *w);
+void mindwarp_dsp(t_mindwarp *x, t_signal **sp, short *count);
+void mindwarp_float(t_mindwarp *x, double myFloat);
+void mindwarp_assist(t_mindwarp *x, void *b, long m, long a, char *s);
+void mindwarp_dest(t_mindwarp *x, double f);
+void mindwarp_init(t_mindwarp *x, short initialized);
+void mindwarp_free(t_mindwarp *x);
+void mindwarp_mute(t_mindwarp *x, t_floatarg toggle);
+void mindwarp_fftinfo(t_mindwarp *x);
+void mindwarp_overlap(t_mindwarp *x, t_floatarg o);
+void mindwarp_winfac(t_mindwarp *x, t_floatarg o);
+void mindwarp_tilde_setup(void);
+
+#if MSP
+
+void mindwarp_float( t_mindwarp *x, double df )
+{
+float myFloat = (float)df;
+
+int inlet = x->x_obj.z_in;
+
+//post("float input to mindwarp: %f",myFloat);
+
+ if ( inlet == 1 ) {
+
+ x->warpFactor = myFloat;
+
+ if ( x->warpFactor > MAX_WARP )
+ x->warpFactor = MAX_WARP;
+
+ if ( x->warpFactor < (1. / MAX_WARP) )
+ x->warpFactor = (1. / MAX_WARP);
+ }
+
+ if ( inlet == 2 ) {
+
+ if ( myFloat >= 1. && myFloat <= (double) x->N )
+ x->shapeWidth = myFloat;
+ }
+
+}
+
+void main(void)
+{
+ setup( (struct messlist **) &mindwarp_class, (method) mindwarp_new,
+ (method) mindwarp_free, (short) sizeof(t_mindwarp), 0, A_GIMME, 0);
+
+ addmess((method)mindwarp_dsp, "dsp", A_CANT, 0);
+ addmess((method)mindwarp_assist,"assist",A_CANT,0);
+ addmess((method)mindwarp_mute,"mute", A_FLOAT, 0);
+ addmess((method)mindwarp_overlap,"overlap", A_FLOAT, 0);
+ addmess((method)mindwarp_winfac,"winfac", A_FLOAT, 0);
+ addmess((method)mindwarp_fftinfo,"fftinfo", 0);
+ addfloat((method)mindwarp_float);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+#if PD
+void mindwarp_tilde_setup(void)
+{
+ mindwarp_class = class_new(gensym("mindwarp~"), (t_newmethod)mindwarp_new,
+ (t_method)mindwarp_free ,sizeof(t_mindwarp), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(mindwarp_class, t_mindwarp, x_f);
+ class_addmethod(mindwarp_class, (t_method)mindwarp_dsp, gensym("dsp"), 0);
+ class_addmethod(mindwarp_class, (t_method)mindwarp_assist, gensym("assist"), 0);
+ class_addmethod(mindwarp_class, (t_method)mindwarp_overlap, gensym("overlap"), A_FLOAT,0);
+ class_addmethod(mindwarp_class, (t_method)mindwarp_winfac, gensym("winfac"), A_FLOAT,0);
+
+ class_addmethod(mindwarp_class, (t_method)mindwarp_mute, gensym("mute"), A_FLOAT,0);
+ class_addmethod(mindwarp_class, (t_method)mindwarp_fftinfo, gensym("fftinfo"), A_CANT,0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+
+
+/* diagnostic messages for Max */
+
+void mindwarp_assist (t_mindwarp *x, void *b, long msg, long arg, char *dst)
+{
+
+ if (msg == 1) {
+
+ switch (arg) {
+
+ case 0: sprintf(dst,"(signal) Formant Input");
+ break;
+
+ case 1: sprintf(dst,"(signal/float) Warp Factor");
+ break;
+
+ case 2: sprintf(dst,"(signal/float) Shape Width");
+ break;
+ }
+ }
+
+ else {
+
+ if (msg == 2)
+ sprintf(dst,"(signal) Mindwarp Output");
+
+ }
+}
+
+
+void *mindwarp_new(t_symbol *s, int argc, t_atom *argv)
+{
+#if MSP
+ t_mindwarp *x = (t_mindwarp *) newobject(mindwarp_class);
+ dsp_setup((t_pxobject *)x, 3);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+
+#if PD
+ t_mindwarp *x = (t_mindwarp *)pd_new(mindwarp_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+
+/* args: warpfactor, shape width, overlap, window factor */
+
+
+ x->warpFactor = atom_getfloatarg(0,argc,argv);
+ x->shapeWidth = atom_getfloatarg(1,argc,argv);
+ x->overlap = atom_getfloatarg(2,argc,argv);
+ x->winfac = atom_getfloatarg(3,argc,argv);
+
+ if(!power_of_two(x->overlap)){
+ x->overlap = 4;
+ }
+ if(!power_of_two(x->winfac)){
+ x->winfac = 1;
+ }
+
+ if(x->warpFactor <= 0 || x->warpFactor > 100.0)
+ x->warpFactor = 1.0;
+ if(x->shapeWidth <= 0 || x->shapeWidth > 64)
+ x->shapeWidth = 3.0;
+
+ x->vs = sys_getblksize();
+ x->R = sys_getsr();
+ mindwarp_init(x,0);
+
+ return (x);
+
+}
+
+void mindwarp_init(t_mindwarp *x, short initialized)
+{
+
+
+ x->D = x->vs;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+
+
+ if(!initialized){
+ x->mute = 0;
+ x->Wanal = (float *) getbytes (MAX_Nw * sizeof(float));
+ x->Wsyn = (float *) getbytes (MAX_Nw * sizeof(float));
+ x->Hwin = (float *) getbytes (MAX_Nw * sizeof(float));
+ x->inputOne = (float *) getbytes (MAX_Nw * sizeof(float));
+ x->bufferOne = (float *) getbytes (MAX_N * sizeof(float));
+ x->channelOne = (float *) getbytes (MAX_N+2 * sizeof(float));
+ x->newAmplitudes = (float *) getbytes (((MAX_N2 + 1) * 16) * sizeof(float));
+ x->newChannel = (float *) getbytes ((MAX_N + 1) * sizeof(float));
+ x->output = (float *) getbytes (MAX_Nw * sizeof(float));
+ x->bitshuffle = (int *) getbytes (MAX_N * 2 * sizeof(int));
+ x->trigland = (float *) getbytes (MAX_N * 2 * sizeof(float));
+ }
+ memset((char *)x->inputOne,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+
+
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makehanning( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 1);
+
+}
+
+void mindwarp_free(t_mindwarp *x)
+{
+#if MSP
+ dsp_free((t_pxobject *) x);
+#endif
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->inputOne,0);
+ freebytes(x->bufferOne,0);
+ freebytes(x->channelOne,0);
+ freebytes(x->newAmplitudes,0);
+ freebytes(x->newChannel,0);
+ freebytes(x->output,0);
+}
+
+
+
+t_int *mindwarp_perform(t_int *w)
+{
+
+ int
+ i,j,
+ bindex,
+ inCount,
+ R,
+ N,
+ N2,
+ D,
+ Nw,
+ invert = 1,
+ shapeWidth,
+ remainingWidth,
+ newLength,
+ even, odd,
+ *bitshuffle;
+
+ float maxamp,
+ threshMult = 1.,
+ warpFactor,
+ mult,
+ cutoff,
+ filterMult,
+ a1, b1,
+ interpIncr,
+ interpPhase,
+ *inputOne,
+ *inputTwo,
+ *bufferOne,
+ *bufferTwo,
+ *output,
+ *Wanal,
+ *Wsyn,
+ *channelOne,
+ *newChannel,
+ *newAmplitudes,
+ *trigland;
+
+/* get our inlets and outlets */
+
+ t_mindwarp *x = (t_mindwarp *) (w[1]);
+ t_float *inOne = (t_float *) (w[2]);
+ t_float *vec_warpFactor = (t_float *) (w[3]);
+ t_float *vec_shapeWidth = (t_float *) (w[4]);
+ t_float *out = (t_float *)(w[5]);
+ t_int n = w[6];
+
+ short *connected = x->connected;
+
+ if(x->mute){
+ while(n--)
+ *out++ = 0.0;
+ return w+7;
+ }
+
+ warpFactor = connected[1] ? *vec_warpFactor : x->warpFactor;
+ shapeWidth = connected[2] ? (int) (*vec_shapeWidth) : (int) x->shapeWidth;
+
+ if(warpFactor <= 0.0){
+ warpFactor = 0.1;
+ error("zero warp factor reported");
+ }
+
+
+
+/* dereference structure */
+
+ inputOne = x->inputOne;
+ bufferOne = x->bufferOne;
+ inCount = x->inCount;
+ R = x->R;
+ N = x->N;
+ N2 = x->N2;
+ D = x->D;
+ Nw = x->Nw;
+ Wanal = x->Wanal;
+ Wsyn = x->Wsyn;
+ output = x->output;
+ channelOne = x->channelOne;
+ newChannel = x->newChannel;
+ newAmplitudes = x->newAmplitudes;
+ bitshuffle = x->bitshuffle;
+ trigland = x->trigland;
+ mult = x->mult;
+
+ cutoff = (float) N2 * .9;
+ filterMult = .00001;
+
+
+
+
+
+/* fill our retaining buffers */
+
+ inCount += D;
+
+ for ( j = 0 ; j < Nw - D ; j++ )
+ inputOne[j] = inputOne[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ inputOne[j] = *inOne++;
+
+/* apply hamming window and fold our window buffer into the fft buffer */
+
+ fold( inputOne, Wanal, Nw, bufferOne, N, inCount );
+
+
+/* do an fft */
+
+ rdft( N, 1, bufferOne, bitshuffle, trigland );
+
+/* convert to polar coordinates from complex values */
+
+ for ( i = 0; i <= N2; i++ ) {
+ odd = ( even = i<<1 ) + 1;
+
+ a1 = ( i == N2 ? *(bufferOne+1) : *(bufferOne+even) );
+ b1 = ( i == 0 || i == N2 ? 0. : *(bufferOne+odd) );
+
+/* replace signal one's phases with those of signal two */
+
+ *(channelOne+even) = hypot( a1, b1 );
+ *(channelOne+odd) = -atan2( b1, a1 );
+ }
+
+
+
+ /* set the number of expected new amplitudes */
+ if(warpFactor <= 0){
+ error("bad warp, resetting");
+ warpFactor = 1.0;
+ }
+
+ newLength = (int) ((float) N2 / warpFactor);
+
+ if(newLength <= 0){
+ error("bad length: resetting");
+ newLength = 1.0;
+ }
+
+ interpIncr = (float) N2 / (float) newLength;
+
+ interpPhase = 0.;
+
+
+ /* do simple linear interpolation on magnitudes */
+
+ for ( bindex=0; bindex < newLength; bindex++ ) {
+
+ int localbindex = ((int) interpPhase) << 1;
+
+ float lower = *(channelOne + localbindex),
+ upper = *(channelOne + localbindex + 2),
+ diff = interpPhase - ( (float) ( (int) interpPhase ) );
+
+ *(newAmplitudes+bindex) = lower + ( ( upper - lower ) * diff );
+
+ interpPhase += interpIncr;
+ }
+
+
+
+/* replace magnitudes with warped values */
+
+ if (warpFactor > 1.) {
+
+ int until = (int) ( cutoff / warpFactor );
+
+ for ( bindex=0; bindex < until; bindex++ ) {
+ register int amp = bindex<<1;
+
+ *(newChannel+amp) = *(newAmplitudes+bindex);
+ }
+
+
+ /* filter remaining spectrum as spectral envelope has shrunk */
+
+ for ( bindex=until; bindex < N2; bindex++ ) {
+ register int amp = bindex<<1;
+
+ *(newChannel+amp) *= filterMult;
+ }
+ }
+
+
+//OK
+
+ /* spectral envelope has enlarged, no post filtering is necessary */
+
+ else {
+
+ for ( bindex=0; bindex <= N2; bindex++ ) {
+ register int amp = bindex<<1;
+
+ *(newChannel+amp) = *(newAmplitudes+bindex);
+ }
+ }
+
+
+
+/* constrain our shapeWidth value */
+
+ if ( shapeWidth > N2 )
+ shapeWidth = N2;
+
+ if ( shapeWidth < 1 )
+ shapeWidth = 1;
+
+/* lets just shape the entire signal by the shape width */
+
+
+ for ( i=0; i < N; i += shapeWidth << 1 ) {
+
+ float amplSum = 0.,
+ freqSum = 0.,
+ factor = 1.0;
+
+ for ( j = 0; j < shapeWidth << 1; j += 2 ) {
+
+ amplSum += *(newChannel+i+j);
+ freqSum += *(channelOne+i+j);
+ }
+
+ if (amplSum < 0.000000001)
+ factor = 0.000000001;
+
+ /* this can happen, crashing external; now fixed.*/
+
+ if( freqSum <= 0 ){
+// error("bad freq sum, resetting");
+ freqSum = 1.0;
+ }
+ else
+ factor = amplSum / freqSum;
+
+ for ( j = 0; j < shapeWidth << 1; j += 2 )
+ *(channelOne+i+j) *= factor;
+ }
+
+/* copy remaining magnitudes (fixed shadowed variable warning by renaming bindex)*/
+
+ if ( (remainingWidth = N2 % shapeWidth) ) {
+
+ int lbindex = (N2 - remainingWidth) << 1;
+
+
+ float amplSum = 0.,
+ freqSum = 0.,
+ factor;
+
+ for ( j = 0; j < remainingWidth << 1; j += 2 ) {
+
+ amplSum += *(newChannel+lbindex+j);
+ freqSum += *(channelOne+lbindex+j);
+ }
+
+ if (amplSum < 0.000000001)
+ factor = 0.000000001;
+
+ else
+ factor = amplSum / freqSum;
+
+ for ( j = 0; j < remainingWidth << 1; j += 2 )
+ *(channelOne+bindex+j) *= factor;
+ }
+
+
+/* convert from polar to cartesian */
+
+ for ( i = 0; i <= N2; i++ ) {
+
+ odd = ( even = i<<1 ) + 1;
+
+ *(bufferOne+even) = *(channelOne+even) * cos( *(channelOne+odd) );
+
+ if ( i != N2 )
+ *(bufferOne+odd) = (*(channelOne+even)) * -sin( *(channelOne+odd) );
+ }
+
+
+/* do an inverse fft */
+
+ rdft( N, -1, bufferOne, bitshuffle, trigland );
+
+/* dewindow our result */
+
+ overlapadd( bufferOne, N, Wsyn, output, Nw, inCount);
+
+/* set our output and adjust our retaining output buffer */
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+
+/* restore state variables */
+
+ x->inCount = inCount % Nw;
+ return (w+7);
+}
+
+void mindwarp_mute(t_mindwarp *x, t_floatarg toggle)
+{
+ x->mute = (short)toggle;
+}
+
+void mindwarp_overlap(t_mindwarp *x, t_floatarg o)
+{
+ if(!power_of_two((int)o)){
+ error("%f is not a power of two",o);
+ return;
+ }
+ x->overlap = (int)o;
+ mindwarp_init(x,1);
+}
+
+void mindwarp_winfac(t_mindwarp *x, t_floatarg f)
+{
+ if(!power_of_two((int)f)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = (int)f;
+ mindwarp_init(x,1);
+}
+
+void mindwarp_fftinfo( t_mindwarp *x )
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+void mindwarp_dsp(t_mindwarp *x, t_signal **sp, short *count)
+{
+long i;
+#if MSP
+ for( i = 0; i < 3; i++ ){
+ x->connected[i] = count[i];
+ }
+#endif
+ /* signal is always connected in Pd */
+#if PD
+ for( i = 0; i < 3; i++ ){
+ x->connected[i] = 1;
+ }
+#endif
+
+ /* reinitialize if vector size or sampling rate has been changed */
+ if(x->vs != sp[0]->s_n || x->R != sp[0]->s_sr){
+ x->vs = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ mindwarp_init(x,1);
+ }
+
+ dsp_add(mindwarp_perform, 6, x,
+ sp[0]->s_vec,
+ sp[1]->s_vec,
+ sp[2]->s_vec,
+ sp[3]->s_vec,
+ sp[0]->s_n);
+}
+
diff --git a/morphine~.c b/morphine~.c
new file mode 100644
index 0000000..c57c4a5
--- /dev/null
+++ b/morphine~.c
@@ -0,0 +1,588 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *morphine_class;
+#endif
+#if PD
+static t_class *morphine_class;
+#endif
+
+#define OBJECT_NAME "morphine~"
+
+/*
+
+Added additional inlet for morphine index
+
+-EL
+
+*/
+
+typedef struct _pickme {
+
+ int bin;
+ float value;
+
+} pickme;
+
+
+typedef struct _morphine
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ int *bitshuffle;
+ float morphIndex;
+ float exponScale;
+ float *Wanal;
+ float *Wsyn;
+ float *inputOne;
+ float *inputTwo;
+ float *Hwin;
+ float *bufferOne;
+ float *bufferTwo;
+ float *channelOne;
+ float *channelTwo;
+ float *output;
+ float mult;
+ float *trigland;
+ pickme *picks;
+ pickme *mirror;
+
+ short connected[8];
+ short mute;
+ int overlap;//overlap factor
+ int winfac;//window factor
+ int vs;//vector size
+
+} t_morphine;
+
+
+/* msp function prototypes */
+
+void *morphine_new(t_symbol *s, int argc, t_atom *argv);
+//t_int *offset_perform(t_int *w);
+t_int *morphine_perform(t_int *w);
+void morphine_dsp(t_morphine *x, t_signal **sp, short *count);
+void morphine_assist(t_morphine *x, void *b, long m, long a, char *s);
+void morphine_dest(t_morphine *x, double f);
+
+int sortIncreasing( const void *a, const void *b );
+//int qsortE (char *base_ptr, int total_elems, int size, int (*cmp)());
+// avoid warning with legal function pointer prototype
+int qsortE (char *base_ptr, int total_elems, int size, int (*cmp)(const void *a, const void *b));
+void morphine_transition(t_morphine *x, t_floatarg f);
+void morphine_free(t_morphine *x);
+void morphine_mute(t_morphine *x, t_floatarg toggle);
+void morphine_fftinfo(t_morphine *x);
+void morphine_tilde_setup(void);
+void morphine_overlap(t_morphine *x, t_floatarg o);
+void morphine_winfac(t_morphine *x, t_floatarg o);
+void morphine_init(t_morphine *x, short initialized);
+
+int sortIncreasing( const void *a, const void *b )
+{
+
+ if ( ((pickme *) a)->value > ((pickme *) b)->value )
+ return 1;
+
+ if ( ((pickme *) a)->value < ((pickme *) b)->value )
+ return -1;
+
+ return 0;
+}
+
+#if MSP
+void main(void)
+{
+ setup( (struct messlist **) &morphine_class, (void *) morphine_new, (method)morphine_free,
+ (short) sizeof(t_morphine), 0, A_GIMME, 0);
+
+ addmess((method)morphine_dsp, "dsp", A_CANT, 0);
+ addmess((method)morphine_assist,"assist",A_CANT,0);
+
+ addmess((method)morphine_transition,"transition", A_FLOAT, 0);
+ addmess((method)morphine_overlap,"overlap", A_FLOAT, 0);
+ addmess((method)morphine_mute,"mute", A_FLOAT, 0);
+ addmess((method)morphine_fftinfo,"fftinfo", 0);
+ addmess((method)morphine_winfac,"winfac",A_FLOAT, 0);
+ addfloat((method)morphine_dest);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+ dsp_initclass();
+}
+
+void morphine_dest(t_morphine *x, double f)
+{
+int inlet = x->x_obj.z_in;
+
+ if(inlet == 2)
+ x->morphIndex = f;
+// post("index now %f", x->morphIndex);
+}
+#endif
+
+#if PD
+void morphine_tilde_setup(void)
+{
+ morphine_class = class_new(gensym("morphine~"), (t_newmethod)morphine_new,
+ (t_method)morphine_free ,sizeof(t_morphine), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(morphine_class, t_morphine, x_f);
+ class_addmethod(morphine_class, (t_method)morphine_dsp, gensym("dsp"), 0);
+ class_addmethod(morphine_class, (t_method)morphine_assist, gensym("assist"), 0);
+ class_addmethod(morphine_class, (t_method)morphine_overlap, gensym("overlap"), A_FLOAT,0);
+ class_addmethod(morphine_class, (t_method)morphine_winfac, gensym("winfac"), A_FLOAT,0);
+ class_addmethod(morphine_class, (t_method)morphine_mute, gensym("mute"), A_FLOAT,0);
+ class_addmethod(morphine_class, (t_method)morphine_transition, gensym("transition"), A_FLOAT,0);
+ class_addmethod(morphine_class, (t_method)morphine_fftinfo, gensym("fftinfo"), A_CANT,0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+/* diagnostic messages for Max */
+
+void morphine_assist (t_morphine *x, void *b, long msg, long arg, char *dst)
+{
+
+ if (msg == 1) {
+
+ switch (arg) {
+
+ case 0: sprintf(dst,"(signal) Input One"); break;
+ case 1: sprintf(dst,"(signal) Input Two"); break;
+ case 2: sprintf(dst,"(signal/float) Morph Index"); break;
+ }
+ }
+
+ else {
+
+ if (msg == 2)
+ sprintf(dst,"(signal) output");
+
+ }
+}
+
+void morphine_transition(t_morphine *x, t_floatarg f)
+{
+ x->exponScale = (float)f;
+}
+
+
+void *morphine_new(t_symbol *s, int argc, t_atom *argv)
+{
+
+#if MSP
+ t_morphine *x = (t_morphine *) newobject(morphine_class);
+ dsp_setup((t_pxobject *)x,3);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+
+#if PD
+ t_morphine *x = (t_morphine *)pd_new(morphine_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+/* optional arguments: exponent scale, overlap, window factor */
+
+ x->exponScale = atom_getfloatarg(0,argc,argv);
+ x->overlap = atom_getfloatarg(1,argc,argv);
+ x->winfac = atom_getfloatarg(2,argc,argv);
+
+ if(!power_of_two(x->overlap)){
+ x->overlap = 4;
+ }
+ if(!power_of_two(x->winfac)){
+ x->winfac = 1;
+ }
+
+ x->vs = sys_getblksize();
+ x->R = sys_getsr();
+
+ morphine_init(x,0);
+
+ return (x);
+}
+
+void morphine_init(t_morphine *x, short initialized)
+{
+ int i;
+int BIGGIE = 32768;
+
+ x->D = x->vs;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+ if(!initialized){
+ x->morphIndex = 0.;
+ x->mute = 0;
+ x->Wanal = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Wsyn = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Hwin = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->inputOne = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->inputTwo = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->bufferOne = (float *) getbytes(MAX_N * sizeof(float));
+ x->bufferTwo = (float *) getbytes(MAX_N * sizeof(float));
+ x->channelOne = (float *) getbytes(MAX_N+2 * sizeof(float));
+ x->channelTwo = (float *) getbytes(MAX_N+2 * sizeof(float));
+ x->output = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->bitshuffle = (int *) getbytes(MAX_N * 2 * sizeof(int));
+ x->trigland = (float *) getbytes(MAX_N * 2 * sizeof(float));
+ x->picks = (pickme *) getbytes(((MAX_N2)+1) * sizeof(pickme));
+ x->mirror = (pickme *) getbytes(((MAX_N2)+1) * sizeof(pickme));
+
+ }
+ memset((char *)x->inputOne,0,x->Nw * sizeof(float));
+ memset((char *)x->inputTwo,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makehanning( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 0);
+
+}
+
+t_int *morphine_perform(t_int *w)
+{
+
+ int
+ i,j,
+ inCount,
+ R,
+ N,
+ N2,
+ D,
+ Nw,
+ lookupIndex,
+ even, odd,
+ *bitshuffle;
+
+ float maxamp,
+ threshMult = 1.,
+ mult,
+ morphIndex,
+ exponScale,
+ a1, b1,
+ a2, b2,
+ *inputOne,
+ *inputTwo,
+ *bufferOne,
+ *bufferTwo,
+ *output,
+ *Wanal,
+ *Wsyn,
+ *channelOne,
+ *channelTwo,
+ *trigland;
+
+ pickme *picks,
+ *mirror;
+
+/* get our inlets and outlets */
+
+ t_morphine *x = (t_morphine *) (w[1]);
+ t_float *inOne = (t_float *)(w[2]);
+ t_float *inTwo = (t_float *)(w[3]);
+ t_float *vec_morphIndex = (t_float *)(w[4]);
+ t_float *out = (t_float *)(w[5]);
+ t_int n = w[6];
+
+ short *connected = x->connected;
+
+ if(x->mute){
+ while(n--)
+ *out++ = 0.0;
+ return w+7;
+ }
+
+/* dereference structure */
+
+ inputOne = x->inputOne;
+ inputTwo = x->inputTwo;
+ bufferOne = x->bufferOne;
+ bufferTwo = x->bufferTwo;
+ inCount = x->inCount;
+ R = x->R;
+ N = x->N;
+ N2 = x->N2;
+ D = x->D;
+ Nw = x->Nw;
+ Wanal = x->Wanal;
+ Wsyn = x->Wsyn;
+ output = x->output;
+ channelOne = x->channelOne;
+ channelTwo = x->channelTwo;
+ bitshuffle = x->bitshuffle;
+ trigland = x->trigland;
+ mult = x->mult;
+ picks = x->picks;
+ mirror = x->mirror;
+ morphIndex = x->morphIndex;
+ exponScale = x->exponScale;
+
+ morphIndex = connected[2] ? *vec_morphIndex : x->morphIndex;
+// post("connected %d index %f stored index %f",connected[2],morphIndex, x->morphIndex);
+ if ( morphIndex < 0 )
+ morphIndex = 0.;
+ else {
+ if ( morphIndex > 1. )
+ morphIndex = 1.;
+ }
+
+
+/* fill our retaining buffers */
+
+ inCount += D;
+
+ for ( j = 0 ; j < Nw - D ; j++ ) {
+ inputOne[j] = inputOne[j+D];
+ inputTwo[j] = inputTwo[j+D];
+ }
+
+ for ( j = Nw - D; j < Nw; j++ ) {
+ inputOne[j] = *inOne++;
+ inputTwo[j] = *inTwo++;
+ }
+
+
+/* apply hamming window and fold our window buffer into the fft buffer */
+
+ fold( inputOne, Wanal, Nw, bufferOne, N, inCount );
+ fold( inputTwo, Wanal, Nw, bufferTwo, N, inCount );
+
+/* do an fft */
+
+ rdft( N, 1, bufferOne, bitshuffle, trigland );
+ rdft( N, 1, bufferTwo, bitshuffle, trigland );
+
+/* convert to polar coordinates from complex values */
+
+ for ( i = 0; i <= N2; i++ ) {
+ odd = ( even = i<<1 ) + 1;
+
+ a1 = ( i == N2 ? *(bufferOne+1) : *(bufferOne+even) );
+ b1 = ( i == 0 || i == N2 ? 0. : *(bufferOne+odd) );
+
+ a2 = ( i == N2 ? *(bufferTwo+1) : *(bufferTwo+even) );
+ b2 = ( i == 0 || i == N2 ? 0. : *(bufferTwo+odd) );
+
+ *(channelOne+even) = hypot( a1, b1 );
+ *(channelOne+odd) = -atan2( b1, a1 );
+
+ *(channelTwo+even) = hypot( a2, b2 );
+ *(channelTwo+odd) = -atan2( b2, a2 );
+
+
+/* find amplitude differences between home and visitors */
+
+ (picks+i)->value = fabs( *(channelOne+even) -
+ *(channelTwo+even) );
+ (picks+i)->bin = i;
+ }
+
+/* sort our differences in ascending order */
+
+
+ qsortE( (char *) picks, (int) N2+1, (int) sizeof(pickme),
+ sortIncreasing );
+
+ /* now we create an effective mirror of the sorted distribution.
+ we will assure that the initial transition will be made from
+ small spectral differences (when the sort behavior is increasing)
+ and the ending transition will also be made from small spectral
+ differences */
+
+ for ( i=0; i <= N2; i += 2 ) {
+ (mirror+(i/2))->bin = (picks+i)->bin;
+ (mirror+(i/2))->value = (picks+i)->value;
+ }
+
+ for ( i=1; i <= N2; i += 2 ) {
+ (mirror+(N2-(i/2)))->bin = (picks+i)->bin;
+ (mirror+(N2-(i/2)))->value = (picks+i)->value;
+ }
+
+
+/* calculate our morphIndex from an exponential function based on exponScale */
+
+ if (exponScale == 0.)
+ lookupIndex = (int) (( (float) N2 ) * morphIndex);
+
+ else {
+
+ if ( morphIndex < .5 ) {
+
+ lookupIndex = (int) ( ((float) N2) * ((
+ (1. - exp( exponScale * morphIndex * 2. )) /
+ (1. - exp( exponScale )) ) * .5) );
+ }
+
+ else {
+
+ lookupIndex = (int) ( ((float) N2) * ( .5 +
+ (( (1. - exp( -exponScale * (morphIndex - .5) * 2. )) /
+ (1. - exp( -exponScale )) ) * .5) ) );
+ }
+
+ }
+
+
+// post("%d", lookupIndex);
+
+/* choose the bins that are least different first */
+
+ for ( i=0; i <= lookupIndex; i++ ) {
+
+ even = ((mirror+i)->bin)<<1,
+ odd = (((mirror+i)->bin)<<1) + 1;
+
+ *(channelOne+even) = *(channelTwo+even);
+ *(channelOne+odd) = *(channelTwo+odd);
+ }
+
+/* convert back to complex form, read for the inverse fft */
+
+ for ( i = 0; i <= N2; i++ ) {
+
+ odd = ( even = i<<1 ) + 1;
+
+ *(bufferOne+even) = *(channelOne+even) * cos( *(channelOne+odd) );
+
+ if ( i != N2 )
+ *(bufferOne+odd) = -(*(channelOne+even)) * sin( *(channelOne+odd) );
+ }
+
+/* do an inverse fft */
+
+ rdft( N, -1, bufferOne, bitshuffle, trigland );
+
+
+/* dewindow our result */
+
+ overlapadd( bufferOne, N, Wsyn, output, Nw, inCount);
+
+
+/* set our output and adjust our retaining output buffer */
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+/* restore state variables */
+
+ x->inCount = inCount % Nw;
+
+ return (w+7);
+}
+void morphine_free(t_morphine *x)
+{
+#if MSP
+ dsp_free((t_pxobject *) x);
+#endif
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->inputOne,0);
+ freebytes(x->inputTwo,0);
+ freebytes(x->bufferOne,0);
+ freebytes(x->bufferTwo,0);
+ freebytes(x->channelOne,0);
+ freebytes(x->channelTwo,0);
+ freebytes(x->picks,0);
+ freebytes(x->mirror,0);
+ freebytes(x->output,0);
+}
+
+void morphine_fftinfo( t_morphine *x )
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+
+void morphine_overlap(t_morphine *x, t_floatarg df)
+{
+int o = (int)df;
+
+ if(!power_of_two(o)){
+ error("%d is not a power of two",o);
+ return;
+ }
+ x->overlap = (int)o;
+ morphine_init(x,1);
+}
+
+void morphine_winfac(t_morphine *x, t_floatarg df)
+{
+int wf = (int) df;
+ if(!power_of_two(wf)){
+ error("%d is not a power of two",wf);
+ return;
+ }
+ x->winfac = wf;
+ morphine_init(x,1);
+}
+
+void morphine_mute(t_morphine *x, t_floatarg toggle)
+{
+ x->mute = (short)toggle;
+}
+
+void morphine_dsp(t_morphine *x, t_signal **sp, short *count)
+{
+long i;
+
+#if MSP
+ for( i = 0; i < 3; i++ ){
+ x->connected[i] = count[i];
+ }
+#endif
+ /* signal is always connected in Pd */
+#if PD
+ for( i = 0; i < 3; i++ ){
+ x->connected[i] = 1;
+ }
+#endif
+
+ /* reinitialize if vector size or sampling rate has been changed */
+ if(x->vs != sp[0]->s_n || x->R != sp[0]->s_sr){
+ x->vs = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ morphine_init(x,1);
+ }
+
+ dsp_add(morphine_perform, 6, x,
+ sp[0]->s_vec,
+ sp[1]->s_vec,
+ sp[2]->s_vec,
+ sp[3]->s_vec,
+ sp[0]->s_n);
+}
+
+
+
diff --git a/multyq~.c b/multyq~.c
new file mode 100644
index 0000000..fee3228
--- /dev/null
+++ b/multyq~.c
@@ -0,0 +1,729 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *multyq_class;
+#endif
+
+#if PD
+static t_class *multyq_class;
+#endif
+
+#define OBJECT_NAME "multyq~"
+
+typedef struct _multyq
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ float *buffer;
+ float *channel;
+ float *output;
+ //
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+
+ // for multyQ
+ float cf1;
+ float gainfac1;
+ float bw1;
+ float cf2;
+ float gainfac2;
+ float bw2;
+ float cf3;
+ float gainfac3;
+ float bw3;
+ float cf4;
+ float gainfac4;
+ float bw4;
+
+ float *rcos;
+ float *filt;
+ float *freqs;
+ int rcoslen;
+ //
+ short in2_connected;
+ short in3_connected;
+ short in4_connected;
+ short in5_connected;
+ short in6_connected;
+ short in7_connected;
+ short in8_connected;
+ short in9_connected;
+ short in10_connected;
+ short in11_connected;
+ short in12_connected;
+ short in13_connected;
+ short please_update;
+ short always_update;
+ short mute;
+ short bypass;
+ int overlap;
+ int winfac;
+} t_multyq;
+
+void *multyq_new(t_symbol *s, int argc, t_atom *argv);
+t_int *offset_perform(t_int *w);
+t_int *multyq_perform(t_int *w);
+void multyq_dsp(t_multyq *x, t_signal **sp, short *count);
+void multyq_assist(t_multyq *x, void *b, long m, long a, char *s);
+void multyq_bypass(t_multyq *x, t_floatarg state);
+void multyq_mute(t_multyq *x, t_floatarg state);
+void update_filter_function(t_multyq *x);
+void multyq_float(t_multyq *x, double f);
+void filtyQ( float *S, float *C, float *filtfunc, int N2 );
+void multyq_init(t_multyq *x, short initialized);
+void multyq_free(t_multyq *x);
+void multyq_fftinfo(t_multyq *x);
+void multyq_overlap(t_multyq *x, t_floatarg f);
+void multyq_winfac(t_multyq *x, t_floatarg f);
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&multyq_class, (method)multyq_new, (method)multyq_free,
+ (short)sizeof(t_multyq), 0, A_GIMME, 0);
+ addmess((method)multyq_dsp, "dsp", A_CANT, 0);
+ addmess((method)multyq_assist,"assist",A_CANT,0);
+ addmess((method)multyq_bypass,"bypass",A_DEFFLOAT,0);
+ addmess((method)multyq_mute,"mute",A_DEFFLOAT,0);
+ addmess((method)multyq_overlap,"overlap",A_DEFFLOAT,0);
+ addmess((method)multyq_winfac,"winfac",A_DEFFLOAT,0);
+ addmess((method)multyq_fftinfo,"fftinfo",0);
+ addfloat((method)multyq_float);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+#if PD
+void multyq_tilde_setup(void)
+{
+ multyq_class = class_new(gensym("multyq~"), (t_newmethod)multyq_new,
+ (t_method)multyq_free ,sizeof(t_multyq), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(multyq_class, t_multyq, x_f);
+ class_addmethod(multyq_class,(t_method)multyq_dsp,gensym("dsp"),0);
+ class_addmethod(multyq_class,(t_method)multyq_mute,gensym("mute"),A_FLOAT,0);
+ class_addmethod(multyq_class,(t_method)multyq_bypass,gensym("bypass"),A_FLOAT,0);
+ class_addmethod(multyq_class,(t_method)multyq_overlap,gensym("overlap"),A_FLOAT,0);
+ class_addmethod(multyq_class,(t_method)multyq_winfac,gensym("winfac"),A_FLOAT,0);
+ class_addmethod(multyq_class,(t_method)multyq_fftinfo,gensym("fftinfo"),0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+
+void multyq_free(t_multyq *x)
+{
+#if MSP
+ dsp_free((t_pxobject *)x);
+#endif
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->input,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->buffer,0);
+ freebytes(x->channel,0);
+ freebytes(x->output,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->trigland,0);
+ freebytes(x->rcos,0);
+ freebytes(x->freqs,0);
+ freebytes(x->filt,0);
+}
+
+void multyq_overlap(t_multyq *x, t_floatarg f)
+{
+int i = (int) f;
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->overlap = i;
+ multyq_init(x,1);
+}
+
+void multyq_winfac(t_multyq *x, t_floatarg f)
+{
+int i = (int)f;
+
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = i;
+ multyq_init(x,2);
+}
+
+void multyq_fftinfo(t_multyq *x)
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+void *multyq_new(t_symbol *s, int argc, t_atom *argv)
+{
+int i;
+#if MSP
+ t_multyq *x = (t_multyq *)newobject(multyq_class);
+ dsp_setup((t_pxobject *)x,13);
+ outlet_new((t_pxobject *)x, "signal");
+ x->x_obj.z_misc |= Z_NO_INPLACE;
+#endif
+
+#if PD
+ t_multyq *x = (t_multyq *)pd_new(multyq_class);
+ for(i=0; i<12; i++){
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+ }
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+ x->overlap = atom_getfloatarg(0,argc,argv);
+ x->winfac = atom_getfloatarg(1,argc,argv);
+ if(!power_of_two(x->overlap))
+ x->overlap = 4;
+ if(!power_of_two(x->winfac))
+ x->winfac = 2;
+
+ x->D = sys_getblksize();
+ x->R = sys_getsr();
+ if(!x->R)
+ x->R = 44100;
+ if(!x->D)
+ x->D = 256;
+
+
+ multyq_init(x,0);
+
+ return (x);
+}
+
+void multyq_init(t_multyq *x, short initialized)
+{
+ int i;
+ float funda, base;
+
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->mult = 1. / (float) x->N;
+ x->inCount = -(x->Nw);
+
+ if(!initialized){
+ x->please_update = 0;
+ x->always_update = 0;
+ x->rcoslen = 8192 ;
+ x->Wanal = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Wsyn = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Hwin = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->input = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->output = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->buffer = (float *) getbytes( MAX_N * sizeof(float) );
+ x->channel = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->bitshuffle = (int *) getbytes( MAX_N * 2 * sizeof( int ) );
+ x->trigland = (float *) getbytes( MAX_N * 2 * sizeof( float ) );
+ x->rcos = (float *) getbytes( x->rcoslen * sizeof( float ) );
+ x->freqs = (float *) getbytes( MAX_N2 * sizeof( float ) );
+ x->filt = (float *) getbytes( (MAX_N2 + 1) * sizeof( float ) );
+
+ x->cf1 = 200.;
+ x->gainfac1 = 0.0;
+ x->bw1 = .15;
+
+ x->cf2 = 700.;
+ x->gainfac2 = 0.0;
+ x->bw2 = .1;
+
+ x->cf3 = 3000.;
+ x->gainfac3 = 0.0;
+ x->bw3 = .15;
+
+ x->cf4 = 12000.;
+ x->gainfac4 = 0.0;
+ x->bw4 = .15;
+
+ x->mute = 0;
+ x->bypass = 0;
+ for (i = 0; i < x->rcoslen; i++){
+ x->rcos[i] = .5 - .5 * cos(((float)i/(float)x->rcoslen) * TWOPI);
+ }
+
+ }
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makehanning(x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 0);
+ funda = base = (float)x->R /(float)x->N ;
+ for(i = 0; i < x->N2; i++){
+ x->freqs[i] = base;
+ base += funda;
+ }
+ update_filter_function(x);
+
+}
+
+t_int *multyq_perform(t_int *w)
+{
+
+ int i, j;
+ t_multyq *x = (t_multyq *) (w[1]);
+ short please_update = x->please_update;
+ float *inbuf = (t_float *)(w[2]);
+ float *in2 = (t_float *)(w[3]);
+ float *in3 = (t_float *)(w[4]);
+ float *in4 = (t_float *)(w[5]);
+ float *in5 = (t_float *)(w[6]);
+ float *in6 = (t_float *)(w[7]);
+ float *in7 = (t_float *)(w[8]);
+ float *in8 = (t_float *)(w[9]);
+ float *in9 = (t_float *)(w[10]);
+ float *in10 = (t_float *)(w[11]);
+ float *in11 = (t_float *)(w[12]);
+ float *in12 = (t_float *)(w[13]);
+ float *in13 = (t_float *)(w[14]);
+ float *outbuf = (t_float *)(w[15]);
+ t_int n = w[16];
+ int inCount = x->inCount;
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *input = x->input;
+ float *Hwin = x->Hwin;
+ float *buffer = x->buffer;
+ float *channel = x->channel;
+ float *output = x->output;
+ int D = x->D;
+ int I = D;
+ int R = x->R;
+ int Nw = x->Nw;
+ int N = x->N ;
+ int N2 = x-> N2;
+ int Nw2 = x->Nw2;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland;
+ float *filt = x->filt;
+ float mult = x->mult;
+ int in = x->inCount ;
+ int on = in;
+
+ if(x->mute) {
+ while (n--){
+ *outbuf++ = 0.;
+ }
+ return (w+17);
+ }
+ if(x->bypass) {
+ while (n--){
+ *outbuf++ = *inbuf++;
+ }
+ return (w+17);
+ }
+#if MSP
+ if( x->in2_connected ){
+ x->cf1 = *in2++ ;
+ }
+ if( x->in3_connected ){
+ x->bw1 = *in3++ ;
+ }
+ if( x->in4_connected ){
+ x->gainfac1 = *in4++ ;
+ }
+ if( x->in5_connected ){
+ x->cf2 = *in5++ ;
+ }
+ if( x->in6_connected ){
+ x->bw2 = *in6++ ;
+ }
+ if( x->in7_connected ){
+ x->gainfac2 = *in7++ ;
+ }
+ if( x->in8_connected ){
+ x->cf3 = *in8++ ;
+ }
+ if( x->in9_connected ){
+ x->bw3 = *in9++ ;
+ }
+ if( x->in10_connected ){
+ x->gainfac3 = *in10++ ;
+ }
+ if( x->in11_connected ){
+ x->cf4 = *in11++ ;
+ }
+ if( x->in12_connected ){
+ x->bw4 = *in12++ ;
+ }
+ if( x->in13_connected ){
+ x->gainfac4 = *in13++;
+ }
+#endif
+
+#if PD
+ x->cf1 = *in2++;
+ x->bw1 = *in3++;
+ x->gainfac1 = *in4++;
+ x->cf2 = *in5++;
+ x->bw2 = *in6++;
+ x->gainfac2 = *in7++;
+ x->cf3 = *in8++;
+ x->bw3 = *in9++;
+ x->gainfac3 = *in10++;
+ x->cf4 = *in11++;
+ x->bw4 = *in12++;
+ x->gainfac4 = *in13++;
+#endif
+
+ if(x->always_update) {
+ update_filter_function(x);
+ }
+ else if(please_update) {
+ update_filter_function(x);
+ please_update = 0;
+ }
+
+ in += D;
+ on += I;
+
+ for ( j = 0 ; j < (Nw - D) ; j++ ){
+ input[j] = input[j+D];
+ }
+ for ( j = (Nw-D), i = 0 ; j < Nw; j++, i++ ) {
+ input[j] = *inbuf++;
+ }
+
+ fold(input, Wanal, Nw, buffer, N, in);
+ rdft(N, 1, buffer, bitshuffle, trigland);
+
+ filtyQ(buffer, channel,filt, N2);
+
+ rdft(N, -1, buffer, bitshuffle, trigland);
+ overlapadd( buffer, N, Wsyn, output, Nw, inCount);
+
+
+ for (j = 0; j < D; j++){
+ *outbuf++ = output[j] * mult;
+ }
+ for (j = 0; j < Nw - D; j++){
+ output[j] = output[j+D];
+ }
+
+ for (j = Nw - D; j < Nw; j++){
+ output[j] = 0.;
+ }
+
+ x->inCount = in;
+ x->please_update = please_update;
+
+ return (w+17);
+}
+
+void multyq_bypass(t_multyq *x, t_floatarg state)
+{
+ x->bypass = (short)state;
+}
+
+void multyq_mute(t_multyq *x, t_floatarg state)
+{
+ x->mute = (short)state;
+}
+
+void multyq_dsp(t_multyq *x, t_signal **sp, short *count)
+{
+ int i;
+
+ if(x->R != sp[0]->s_sr||x->D != sp[0]->s_n){
+ x->R = sp[0]->s_sr;
+ x->D = sp[0]->s_n;
+ multyq_init(x,1);
+ }
+
+#if MSP
+ x->in2_connected = count[1];
+ x->in3_connected = count[2];
+ x->in4_connected = count[3];
+ x->in5_connected = count[4];
+ x->in6_connected = count[5];
+ x->in7_connected = count[6];
+ x->in8_connected = count[7];
+ x->in9_connected = count[8];
+ x->in10_connected = count[9];
+ x->in11_connected = count[10];
+ x->in12_connected = count[11];
+ x->in13_connected = count[12];
+ x->always_update = 0;
+ for(i = 1; i < 13; i++) {
+ x->always_update += count[i];
+ }
+#endif
+
+#if PD
+ x->always_update = 1;
+#endif
+
+ dsp_add(multyq_perform, 16, x,
+ sp[0]->s_vec,sp[1]->s_vec,sp[2]->s_vec,sp[3]->s_vec,sp[4]->s_vec,
+ sp[5]->s_vec,sp[6]->s_vec,sp[7]->s_vec,sp[8]->s_vec,sp[9]->s_vec,
+ sp[10]->s_vec,sp[11]->s_vec,sp[12]->s_vec,sp[13]->s_vec,sp[0]->s_n);
+}
+
+
+void update_filter_function(t_multyq *x)
+{
+ float funda, curfreq, m1, m2;
+ float lo, hi ;
+ float ploc, gainer;
+ int i;
+ float nyquist = (float)x->R / 2.0;
+ float *filt = x->filt;
+ float *rcos = x->rcos;
+ float *freqs = x->freqs;
+ int rcoslen = x->rcoslen;
+
+ // sanity
+ if( x->cf1 < 0 ){
+ x->cf1 = 0;
+ }
+ else if( x->cf1 > nyquist){
+ x->cf1 = nyquist ;
+ }
+ if( x->bw1 <= .05 ){
+ x->bw1 = .05;
+ }
+ else if( x->bw1 > 1. ){
+ x->bw1 = 1.;
+ }
+ if( x->gainfac1 < -1. ){
+ x->gainfac1 = -1;
+ }
+ if( x->cf2 < 0 ){
+ x->cf2 = 0;
+ }
+ else if( x->cf2> nyquist){
+ x->cf2 = nyquist ;
+ }
+ if( x->bw2 <= .05 ){
+ x->bw2 = .05;
+ }
+ else if( x->bw2 > 1. ){
+ x->bw2 = 1.;
+ }
+ if( x->gainfac2 < -1. ){
+ x->gainfac2 = -1;
+ }
+ if( x->cf3 < 0 ){
+ x->cf3 = 0;
+ }
+ else if( x->cf3 > nyquist){
+ x->cf3 = nyquist ;
+ }
+ if( x->bw3 <= .05 ){
+ x->bw3 = .05;
+ }
+ else if( x->bw3 > 1. ){
+ x->bw3 = 1.;
+ }
+ if( x->gainfac3 < -1. ){
+ x->gainfac3 = -1;
+ }
+ if( x->cf4 < 0 ){
+ x->cf4 = 0;
+ }
+ else if( x->cf4 > nyquist){
+ x->cf4 = nyquist ;
+ }
+ if( x->bw4 <= .05 ){
+ x->bw4 = .05;
+ }
+ else if( x->bw4 > 1. ){
+ x->bw4 = 1.;
+ }
+ if( x->gainfac4 < -1. ){
+ x->gainfac4 = -1;
+ }
+ for( i = 0; i < x->N2; i++ ) {
+ x->filt[i] = 1.0 ;
+ }
+ // filt 1
+ lo = x->cf1 * (1.0 - x->bw1 );
+ hi = x->cf1 * (1.0 + x->bw1 );
+ for( i = 0; i < x->N2; i++ ) {
+ if(freqs[i] >= lo && freqs[i] <= hi){
+ ploc = (freqs[i] - lo) / (hi - lo);
+ gainer = 1 + x->gainfac1 * rcos[ (int) (ploc * rcoslen) ] ;
+ if( gainer < 0 ){
+ gainer = 0;
+ }
+ filt[i] *= gainer ;
+
+ }
+ }
+ // filt 2
+ lo = x->cf2 * (1.0 - x->bw2 );
+ hi = x->cf2 * (1.0 + x->bw2 );
+ for( i = 0; i < x->N2; i++ ) {
+ if( freqs[i] >= lo && freqs[i] <= hi){
+ ploc = (freqs[i] - lo) / (hi - lo);
+ gainer = 1 + x->gainfac2 * rcos[ (int) (ploc * rcoslen) ] ;
+ if( gainer < 0 ){
+ gainer = 0;
+ }
+ filt[i] *= gainer ;
+
+ }
+ }
+ // filt 3
+ lo = x->cf3 * (1.0 - x->bw3 );
+ hi = x->cf3 * (1.0 + x->bw3 );
+ for( i = 0; i < x->N2; i++ ) {
+ if(freqs[i] >= lo && freqs[i] <= hi){
+ ploc = (freqs[i] - lo) / (hi - lo);
+ gainer = 1 + x->gainfac3 * rcos[ (int) (ploc * rcoslen) ] ;
+ if( gainer < 0 ){
+ gainer = 0;
+ }
+ filt[i] *= gainer ;
+
+ }
+ }
+ // filt 4
+ lo = x->cf4 * (1.0 - x->bw4 );
+ hi = x->cf4 * (1.0 + x->bw4 );
+ for( i = 0; i < x->N2; i++ ) {
+ if(freqs[i] >= lo && freqs[i] <= hi){
+ ploc = (freqs[i] - lo) / (hi - lo);
+ gainer = 1 + x->gainfac4 * rcos[ (int) (ploc * rcoslen) ] ;
+ if( gainer < 0 ){
+ gainer = 0;
+ }
+ filt[i] *= gainer ;
+
+ }
+ }
+
+}
+#if MSP
+void multyq_float(t_multyq *x, double f) // Look at floats at inlets
+{
+int inlet = x->x_obj.z_in;
+
+ if (inlet == 1)
+ {
+ x->cf1 = f;
+ }
+ else if (inlet == 2)
+ {
+ x->bw1 = f;
+ }
+ else if (inlet == 3)
+ {
+ x->gainfac1 = f;
+ }
+ else if (inlet == 4)
+ {
+ x->cf2 = f;
+ }
+ else if (inlet == 5)
+ {
+ x->bw2 = f;
+ }
+ else if (inlet == 6)
+ {
+ x->gainfac2 = f;
+ }
+ else if (inlet == 7)
+ {
+ x->cf3 = f;
+ }
+ else if (inlet == 8)
+ {
+ x->bw3 = f;
+ }
+ else if (inlet == 9)
+ {
+ x->gainfac3 = f;
+ }
+ else if (inlet == 10)
+ {
+ x->cf4 = f;
+ }
+ else if (inlet == 11)
+ {
+ x->bw4 = f;
+ }
+ else if (inlet == 12)
+ {
+ x->gainfac4 = f;
+ }
+ x->please_update = 1;
+}
+#endif
+
+void multyq_assist (t_multyq *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0: sprintf(dst,"(signal) Input"); break;
+ case 1: sprintf(dst,"(signal/float) Cf1");break;
+ case 2: sprintf(dst,"(signal/float) Bw1"); break;
+ case 3: sprintf(dst,"(signal/float) Gain1"); break;
+ case 4: sprintf(dst,"(signal/float) Cf2"); break;
+ case 5: sprintf(dst,"(signal/float) Bw2"); break;
+ case 6: sprintf(dst,"(signal/float) Gain2"); break;
+ case 7: sprintf(dst,"(signal/float) Cf3"); break;
+ case 8: sprintf(dst,"(signal/float) Bw3"); break;
+ case 9: sprintf(dst,"(signal/float) Gain3"); break;
+ case 10: sprintf(dst,"(signal/float) Cf4"); break;
+ case 11: sprintf(dst,"(signal/float) Bw4"); break;
+ case 12: sprintf(dst,"(signal/float) Gain4"); break;
+ }
+ } else if (msg==2) {
+ sprintf(dst,"(signal) Output");
+ }
+}
+
+
+void filtyQ( float *S, float *C, float *filtfunc, int N2 )
+{
+ int real, imag, amp, phase;
+ float a, b;
+ int i;
+ float maxamp = 1.;
+
+ for ( i = 0; i <= N2; i++ ) {
+ imag = phase = ( real = amp = i<<1 ) + 1;
+ a = ( i == N2 ? S[1] : S[real] );
+ b = ( i == 0 || i == N2 ? 0. : S[imag] );
+ C[amp] = hypot( a, b );
+ C[amp] *= filtfunc[ i ];
+ C[phase] = -atan2( b, a );
+ }
+
+ for ( i = 0; i <= N2; i++ ) {
+ imag = phase = ( real = amp = i<<1 ) + 1;
+ S[real] = *(C+amp) * cos( *(C+phase) );
+ if ( i != N2 )
+ S[imag] = -*(C+amp) * sin( *(C+phase) );
+ }
+}
diff --git a/presidency~.c b/presidency~.c
new file mode 100644
index 0000000..3e78243
--- /dev/null
+++ b/presidency~.c
@@ -0,0 +1,760 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *presidency_class;
+#endif
+
+#if PD
+static t_class *presidency_class;
+#endif
+
+#define OBJECT_NAME "presidency~"
+
+typedef struct _presidency
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ float *buffer;
+ float *channel;
+ float *output;
+ float **loveboat;
+ float current_frame;
+ float *local_frame; // needs mem allocation in init
+ int framecount;
+ float lo_freq;
+ float hi_freq;
+ float topfreq;
+ float curfreq;
+ float P;
+ int lo_bin;
+ int hi_bin;
+ float i_vector_size;
+ float vector_size;
+ float synthesis_threshold;
+ float pitch_increment;
+ // oscillator
+ float *table;
+ float *bindex;
+ float *lastamp;// stores last amplitudes for each bin
+ float *lastfreq;// stores last frequencies
+ float table_si;
+ int table_length;
+ //
+ float frame_increment ;
+ float fpos;
+ float last_fpos;
+ float tadv;
+ // for convert
+ float *c_lastphase_in;
+ float *c_lastphase_out;
+ float c_fundamental;
+ float c_factor_in;
+ float c_factor_out;
+ // faster fft
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ int read_me;
+ int frames_read;
+ // int MAXFRAMES;
+ short mute;
+ short virgin;
+ short playthrough;
+ short in2_connected;
+ short in3_connected;
+ short in4_connected;
+ int overlap;
+ int winfac;
+ int hopsize;
+ float duration;
+ short lock;
+ short verbose;
+ short override;
+ float sync;
+} t_presidency;
+
+void *presidency_new(t_symbol *s, int argc, t_atom *argv);
+t_int *presidency_perform(t_int *w);
+void presidency_dsp(t_presidency *x, t_signal **sp, short *count);
+void presidency_assist(t_presidency *x, void *b, long m, long a, char *s);
+void presidency_bangname(t_presidency *x) ;
+
+void presidency_playthrough( t_presidency *x, t_floatarg tog) ;
+void presidency_float(t_presidency *x, double f) ;
+void presidency_int(t_presidency *x, long i);
+void presidency_mute(t_presidency *x, t_floatarg tog);
+void presidency_free(t_presidency *x);
+void presidency_init(t_presidency *x, short initialized);
+void presidency_size(t_presidency *x, t_floatarg newsize);
+void presidency_winfac(t_presidency *x, t_floatarg factor);
+void presidency_overlap(t_presidency *x, t_floatarg o);
+void presidency_fftinfo(t_presidency *x) ;
+void presidency_verbose(t_presidency *x, t_floatarg t);
+void presidency_acquire_sample(t_presidency *x);
+void presidency_low_freq(t_presidency *x, t_floatarg f);
+void presidency_high_freq(t_presidency *x, t_floatarg f);
+void presidency_calc_bins_from_freqs(t_presidency *x);
+void presidency_abs_thresh(t_presidency *x, t_floatarg t);
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&presidency_class, (method)presidency_new, (method)presidency_free,
+ (short)sizeof(t_presidency), 0, A_GIMME,0);
+ addmess((method)presidency_dsp, "dsp", A_CANT, 0);
+ addmess((method)presidency_assist,"assist",A_CANT,0);
+ addfloat((method)presidency_float);
+ addint((method)presidency_int);
+ addbang((method)presidency_bangname);
+ addmess((method)presidency_mute, "mute", A_FLOAT, 0);
+ addmess((method)presidency_fftinfo, "fftinfo", 0);
+ addmess((method)presidency_playthrough, "playthrough", A_DEFFLOAT, 0);
+ addmess((method)presidency_size, "size", A_DEFFLOAT, 0);
+ addmess((method)presidency_overlap, "overlap", A_DEFFLOAT, 0);
+ addmess((method)presidency_winfac, "winfac", A_DEFFLOAT, 0);
+ addmess((method)presidency_verbose, "verbose", A_DEFFLOAT, 0);
+ addmess((method)presidency_low_freq, "low_freq", A_DEFFLOAT, 0);
+ addmess((method)presidency_high_freq, "high_freq", A_DEFFLOAT, 0);
+ addmess((method)presidency_acquire_sample, "acquire_sample", 0);
+ addmess((method)presidency_abs_thresh, "abs_thresh", A_FLOAT, 0);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+#if PD
+void presidency_tilde_setup(void)
+{
+ presidency_class = class_new(gensym("presidency~"), (t_newmethod)presidency_new,
+ (t_method)presidency_free ,sizeof(t_presidency), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(presidency_class, t_presidency, x_f);
+ class_addmethod(presidency_class,(t_method)presidency_dsp,gensym("dsp"),0);
+ class_addmethod(presidency_class,(t_method)presidency_mute,gensym("mute"),A_FLOAT,0);
+ class_addmethod(presidency_class,(t_method)presidency_fftinfo,gensym("fftinfo"),0);
+ class_addmethod(presidency_class,(t_method)presidency_playthrough,gensym("playthrough"),A_FLOAT,0);
+ class_addmethod(presidency_class,(t_method)presidency_size,gensym("size"),A_FLOAT,0);
+ class_addmethod(presidency_class,(t_method)presidency_overlap,gensym("overlap"),A_FLOAT,0);
+ class_addmethod(presidency_class,(t_method)presidency_winfac,gensym("winfac"),A_FLOAT,0);
+ class_addmethod(presidency_class,(t_method)presidency_verbose,gensym("verbose"),A_FLOAT,0);
+ class_addmethod(presidency_class,(t_method)presidency_acquire_sample,gensym("acquire_sample"),0);
+ class_addmethod(presidency_class,(t_method)presidency_low_freq,gensym("low_freq"),A_FLOAT,0);
+ class_addmethod(presidency_class,(t_method)presidency_high_freq,gensym("high_freq"),A_FLOAT,0);
+ class_addmethod(presidency_class,(t_method)presidency_abs_thresh,gensym("abs_thresh"),A_FLOAT,0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+void presidency_abs_thresh(t_presidency *x, t_floatarg f)
+{
+ if(f < 0){
+ error("illegal value for threshold");
+ return;
+ }
+ x->synthesis_threshold = f;
+}
+
+void presidency_low_freq(t_presidency *x, t_floatarg f)
+{
+ if(f > x->hi_freq || f < 0){
+ error("illegal value for low freq");
+ return;
+ }
+ x->lo_freq = f;
+ presidency_calc_bins_from_freqs(x);
+}
+
+void presidency_high_freq(t_presidency *x, t_floatarg f)
+{
+ if(f < x->lo_freq || f > x->R/2.0){
+ error("illegal value for high freq");
+ return;
+ }
+ x->hi_freq = f;
+ presidency_calc_bins_from_freqs(x);
+}
+
+void presidency_calc_bins_from_freqs(t_presidency *x)
+{
+ x->hi_bin = 1;
+ x->curfreq = 0;
+
+ if( x->c_fundamental <= 0){
+ error("we're not yet fully initialized. Try turning on DACs first");
+ return;
+ }
+
+ while( x->curfreq < x->hi_freq ) {
+ ++(x->hi_bin);
+ x->curfreq += x->c_fundamental ;
+ }
+
+ x->lo_bin = 0;
+ x->curfreq = 0;
+ while( x->curfreq < x->lo_freq ) {
+ ++(x->lo_bin);
+ x->curfreq += x->c_fundamental ;
+ }
+
+ if( x->hi_bin > x->N2)
+ x->hi_bin = x->N2 ;
+ if(x->lo_bin > x->hi_bin)
+ x->lo_bin = x->hi_bin;
+// post("hibin: %d lobin %d",x->hi_bin, x->lo_bin);
+}
+
+
+void presidency_overlap(t_presidency *x, t_floatarg f)
+{
+int i = (int) f;
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->overlap = i;
+ presidency_init(x,1);
+}
+
+void presidency_winfac(t_presidency *x, t_floatarg f)
+{
+int i = (int)f;
+
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = i;
+ presidency_init(x,2);
+}
+
+void presidency_fftinfo(t_presidency *x)
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, winfac %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+void presidency_verbose(t_presidency *x, t_floatarg t)
+{
+ x->verbose = t;
+}
+
+void presidency_size(t_presidency *x, t_floatarg newsize)
+{
+//protect with DACs off?
+
+ if(newsize > 0.0){//could be horrendous size, but that's the user's problem
+ x->duration = newsize/1000.0;
+ presidency_init(x,1);
+ }
+}
+
+void presidency_playthrough (t_presidency *x, t_floatarg tog)
+{
+ x->playthrough = tog;
+}
+
+void presidency_free(t_presidency *x){
+ int i ;
+#if MSP
+ dsp_free((t_pxobject *)x);
+#endif
+ for(i = 0; i < x->framecount; i++){
+ freebytes(x->loveboat[i],0) ;
+ }
+ freebytes(x->loveboat,0);
+ freebytes(x->c_lastphase_in,0);
+ freebytes(x->c_lastphase_out,0);
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->input,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->buffer,0);
+ freebytes(x->channel,0);
+ freebytes(x->output,0);
+ freebytes(x->local_frame,0);
+}
+
+
+
+void presidency_init(t_presidency *x, short initialized)
+{
+ int i;
+ long oldsize,newsize;
+ int oldN = x->N;
+ int oldN2 = x->N2;
+ int oldNw = x->Nw;
+ int last_framecount = x->framecount;
+ x->lock = 1;
+ x->virgin = 1;
+
+ if(!power_of_two(x->winfac))
+ x->winfac = 1;
+ if(!power_of_two(x->overlap))
+ x->overlap = 4;
+ if(!x->R)
+ x->R = 44100;
+ if(!x->D){
+ x->D = 256;
+ x->vector_size = x->D;
+ }
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N, &x->Nw, OBJECT_NAME);
+
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+// post("mult %f N %d",x->mult,x->N);
+ x->current_frame = 0;
+ x->fpos = x->last_fpos = 0;
+ x->tadv = (float)x->D/(float)x->R;
+ x->c_fundamental = (float)x->R/((x->N2)<<1);
+ x->c_factor_in = (float) x->R/((float)x->D * TWOPI);
+ x->c_factor_out = TWOPI * (float)x->D / (float)x->R;
+ x->table_length = 8192;
+ x->table_si = (float) x->table_length / (float) x->R;
+ x->pitch_increment = 1.0 * x->table_si;
+
+ if( x->duration <= 0 ){
+ x->duration = 1.0;
+ }
+
+ x->framecount = x->duration / x->tadv ;
+ x->hopsize = (float)x->N / x->overlap;
+ x->read_me = 0;
+
+ if(!initialized){
+ x->mute = 0;
+ x->in2_connected = 0;
+ x->in3_connected = 0;
+ x->sync = 0;
+ x->playthrough = 0;
+ x->frame_increment = 1.0;
+ x->verbose = 0;
+ x->table = (float *) getbytes(x->table_length * sizeof(float));
+ x->Wanal = (float *) getbytes(MAX_Nw*sizeof(float));
+ x->Wsyn = (float *) getbytes(MAX_Nw*sizeof(float));
+ x->input = (float *) getbytes(MAX_Nw*sizeof(float));
+ x->Hwin = (float *) getbytes(MAX_Nw*sizeof(float));
+ x->bindex = (float *) getbytes( (MAX_N+1) * sizeof(float) );
+ x->buffer = (float *) getbytes(MAX_N*sizeof(float));
+ x->channel = (float *) getbytes((MAX_N+2)*sizeof(float));
+ x->output = (float *) getbytes(MAX_Nw*sizeof(float));
+ x->bitshuffle = (int *) getbytes((MAX_N*2)*sizeof(int));
+ x->trigland = (float *) getbytes((MAX_N*2)*sizeof(float));
+ x->c_lastphase_in = (float *) getbytes((MAX_N2+1)*sizeof(float));
+ x->c_lastphase_out = (float *) getbytes((MAX_N2+1)*sizeof(float));
+ x->lastamp = (float *) getbytes((MAX_N+1) * sizeof(float));
+ x->lastfreq = (float *) getbytes((MAX_N+1) * sizeof(float));
+ x->local_frame = (float *) getbytes((MAX_N+2)*sizeof(float));
+ x->loveboat = (float **) getbytes(x->framecount*sizeof(float *));
+
+
+ /* here we stay with old reallocation approach and pray */
+ for(i=0;i<x->framecount;i++){
+ x->loveboat[i] = (float *) getbytes(((x->N)+2)*sizeof(float));
+ if(x->loveboat[i] == NULL){
+ error("memory error");
+ return;
+ }
+ memset((char *)x->loveboat[i],0,(x->N+2)*sizeof(float));
+ }
+ } else if(initialized == 1) {
+ //free and allocate
+ oldsize = (oldN+2)*sizeof(float);
+ for(i = 0; i < last_framecount; i++){
+ freebytes(x->loveboat[i],oldsize) ;
+ }
+ oldsize = last_framecount*sizeof(float *);
+ freebytes(x->loveboat,oldsize);
+ x->loveboat = (float **) getbytes(x->framecount*sizeof(float *));
+ for(i=0;i<x->framecount;i++){
+ x->loveboat[i] = (float *) getbytes((x->N+2)*sizeof(float));
+ if(x->loveboat[i] == NULL){
+ error("memory error");
+ return;
+ }
+ memset((char *)x->loveboat[i],0,(x->N+2)*sizeof(float));
+ }
+ }
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ memset((char *)x->c_lastphase_in,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->lastamp,0,(x->N+1)*sizeof(float));
+ memset((char *)x->lastfreq,0,(x->N+1)*sizeof(float));
+ memset((char *)x->bindex,0,(x->N+1)*sizeof(float));
+ memset((char *)x->buffer,0,x->N * sizeof(float));
+ if(!x->vector_size){
+ post("zero vector size - something is really screwed up here!");
+ return;
+ }
+ for ( i = 0; i < x->table_length; i++ ) {
+ x->table[i] = (float) x->N * cos((float)i * TWOPI / (float)x->table_length);
+ }
+ x->c_fundamental = (float) x->R/(float)x->N ;
+ x->c_factor_in = (float) x->R/((float)x->vector_size * TWOPI);
+
+ if( x->hi_freq < x->c_fundamental ) {
+ x->hi_freq = x->topfreq ;
+ }
+ x->hi_bin = 1;
+ x->curfreq = 0;
+ while( x->curfreq < x->hi_freq ) {
+ ++(x->hi_bin);
+ x->curfreq += x->c_fundamental ;
+ }
+
+ x->lo_bin = 0;
+ x->curfreq = 0;
+ while( x->curfreq < x->lo_freq ) {
+ ++(x->lo_bin);
+ x->curfreq += x->c_fundamental ;
+ }
+
+ if( x->hi_bin > x->N2)
+ x->hi_bin = x->N2 ;
+ if(x->lo_bin > x->hi_bin)
+ x->lo_bin = x->hi_bin;
+
+ x->i_vector_size = 1.0/x->vector_size;
+ x->pitch_increment = x->P*x->table_length/x->R;
+
+ makewindows( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D);
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+
+
+ x->lock = 0;
+}
+
+void *presidency_new(t_symbol *s, int argc, t_atom *argv)
+{
+#if MSP
+ t_presidency *x = (t_presidency *)newobject(presidency_class);
+ dsp_setup((t_pxobject *)x,4);
+ outlet_new((t_pxobject *)x, "signal");
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+
+#if PD
+ t_presidency *x = (t_presidency *)pd_new(presidency_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+ x->duration = atom_getfloatarg(0,argc,argv)/1000.0;
+ x->lo_freq = atom_getfloatarg(1,argc,argv);
+ x->hi_freq = atom_getfloatarg(2,argc,argv);
+ x->overlap = atom_getfloatarg(3,argc,argv);
+ x->winfac = atom_getfloatarg(4,argc,argv);
+
+ x->D = sys_getblksize();
+ x->R = sys_getsr();
+ x->vector_size = x->D;
+
+ x->topfreq = 3000.; // default top freq
+ if(!x->lo_freq){
+ x->lo_freq = 0;
+ }
+ if(!x->hi_freq)
+ x->hi_freq = 4000.0;
+
+ presidency_init(x,0);
+
+ return (x);
+}
+
+t_int *presidency_perform(t_int *w)
+{
+ int i, j;
+ float sample;
+
+ //////////////////////////////////////////////
+ t_presidency *x = (t_presidency *) (w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *speed = (t_float *)(w[3]);
+ t_float *position = (t_float *)(w[4]);
+ t_float *pinc = (t_float *)(w[5]);
+ t_float *out = (t_float *)(w[6]);
+ t_float *sync_vec = (t_float *)(w[7]);
+ t_int n = w[8];
+
+ int inCount = x->inCount;
+ int R = x->R;
+ int N = x->N;
+ int N2 = x->N2;
+ int D = x->D;
+ int vector_size = x->D;
+ int Nw = x->Nw;
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *input = x->input;
+ float *output = x->output;
+ float *buffer = x->buffer;
+ float *channel = x->channel;
+ float *local_frame = x->local_frame;
+ float fframe = x->current_frame ;
+ float last_fpos = x->last_fpos ;
+ int framecount = x->framecount;
+ float fincr = x->frame_increment;
+ float fpos = x->fpos;
+ float pitch_increment = x->pitch_increment;
+ float mult = x->mult;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland ;
+ float *c_lastphase_in = x->c_lastphase_in;
+ float *c_lastphase_out = x->c_lastphase_out;
+ float c_fundamental = x->c_fundamental;
+ float c_factor_in = x->c_factor_in;
+ float c_factor_out = x->c_factor_out;
+ float table_si = x->table_si;
+ int lo_bin = x->lo_bin;
+ int hi_bin = x->hi_bin;
+ float i_vector_size = x->i_vector_size;
+ float synthesis_threshold = x->synthesis_threshold;
+ float *lastfreq = x->lastfreq;
+ float *lastamp = x->lastamp;
+ float *bindex = x->bindex;
+ float *table = x->table;
+ int table_length = x->table_length;
+ float sync = x->sync;
+
+
+ if(x->lock || x->mute){
+ while(n--){
+ *out++ = 0.0;
+ *sync_vec++ = sync;
+ }
+ return (w+9);
+ }
+
+#if MSP
+ if (x->in2_connected) {
+ fincr = *speed;
+ }
+ if (x->in3_connected) {
+ fpos = *position;
+ }
+ if (x->in4_connected) {
+ pitch_increment = *pinc * table_si;
+ }
+#endif
+
+#if PD
+ fincr = *speed;
+ fpos = *position;
+ pitch_increment = *pinc * table_si;
+#endif
+
+ inCount += D;
+
+ if(x->read_me) {
+ for ( j = 0 ; j < Nw - D ; j++ ){
+ input[j] = input[j+D];
+ }
+ for (j = Nw - D; j < Nw; j++) {
+ input[j] = *in++;
+ }
+
+ if( x->playthrough ){
+ for ( j = N-D; j < N; j++ ) {
+ *out++ = input[j] * 0.5;
+ }
+ }
+ else {
+ for ( j = 0; j < D; j++ ){
+ *out++ = 0.0;
+ }
+ }
+
+ fold(input, Wanal, Nw, buffer, N, inCount);
+ rdft(N, 1, buffer, bitshuffle, trigland);
+ sync = (float) x->frames_read / (float) framecount;
+ if(x->frames_read >= framecount){
+ sync = 1.0;
+ x->read_me = 0;
+ if(x->verbose){
+ post("presidency: data acquisition completed");
+ }
+ } else {
+ convert(buffer, x->loveboat[(x->frames_read)++], N2, c_lastphase_in, c_fundamental, c_factor_in);
+ }
+ x->virgin = 0;
+ for ( j = 0; j < D; j++ ){
+ *sync_vec++ = sync;
+ }
+
+ }
+ else if(x->playthrough && x->virgin){
+ while(n--){
+ sample = *in++ * 0.5;
+ *out++ = sample;
+ *sync_vec++ = sync;
+ }
+ }
+ /* synthesis section */
+ else {
+ if(fpos < 0)
+ fpos = 0;
+ if(fpos > 1)
+ fpos = 1;
+ if(fpos != last_fpos){
+ fframe = fpos * (float) framecount;
+ last_fpos = fpos;
+ }
+
+
+ fframe += fincr;
+ while(fframe >= framecount) {
+ fframe -= framecount;
+ }
+ while( fframe < 0. ) {
+ fframe += framecount ;
+ }
+ // copy stored frame to local for possible modifications
+ for(i = 0; i < N; i++){
+ local_frame[i] = x->loveboat[(int) fframe ][i];
+ }
+
+ for( i = lo_bin * 2 + 1; i < hi_bin * 2 + 1; i += 2 ){
+ local_frame[i] *= pitch_increment;
+ }
+
+ bloscbank(local_frame, output, D, i_vector_size, lastfreq, lastamp,
+ bindex, table, table_length, synthesis_threshold, lo_bin, hi_bin);
+
+ for ( j = 0; j < D; j++ ){
+ *out++ = output[j] * mult;
+ *sync_vec++ = sync;
+ }
+ for ( j = 0; j < Nw - D; j++ ){
+ output[j] = output[j+D];
+ }
+
+ for ( j = Nw - D; j < Nw; j++ ){
+ output[j] = 0.;
+ }
+ }
+
+ /* restore state variables */
+
+ x->inCount = inCount % Nw;
+ x->current_frame = fframe;
+ x->frame_increment = fincr;
+ x->fpos = fpos;
+ x->last_fpos = last_fpos;
+ x->pitch_increment = pitch_increment;
+ x->sync = sync;
+ return (w+9);
+}
+
+#if MSP
+void presidency_int(t_presidency *x, long i)
+{
+ presidency_float(x,(float)i);
+}
+
+void presidency_float(t_presidency *x, double f) // Look at floats at inlets
+{
+ int inlet = ((t_pxobject*)x)->z_in;
+
+ if (inlet == 1) {
+ x->frame_increment = f;
+ }
+ else if (inlet == 2){
+ if (f < 0 ){
+ f = 0;
+ } else if(f > 1) {
+ f = 1.;
+ }
+ x->fpos = f;
+ }
+ else if( inlet == 3 ){
+ x->pitch_increment = f * x->table_si;
+ }
+}
+#endif
+
+void presidency_acquire_sample(t_presidency *x)
+{
+ x->read_me = 1;
+ x->frames_read = 0;
+ if(x->verbose)
+ post("%: beginning spectral data acquisition",OBJECT_NAME);
+}
+
+void presidency_bangname (t_presidency *x)
+{
+ x->read_me = 1;
+ x->frames_read = 0;
+ if(x->verbose)
+ post("%s: beginning spectral data acquisition",OBJECT_NAME);
+}
+
+void presidency_mute(t_presidency *x, t_floatarg tog)
+{
+ x->mute = (short)tog;
+}
+
+void presidency_dsp(t_presidency *x, t_signal **sp, short *count)
+{
+#if MSP
+ x->in2_connected = count[1];
+ x->in3_connected = count[2];
+ x->in4_connected = count[3];
+#endif
+
+ if(x->R != sp[0]->s_sr || x->D != sp[0]->s_n){
+ x->R = sp[0]->s_sr;
+ x->D = sp[0]->s_n;
+ x->vector_size = x->D;
+ if(x->verbose)
+ post("new vsize: %d, new SR:%d",x->D,x->R);
+ presidency_init(x,1);
+ }
+
+ dsp_add(presidency_perform, 8, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,
+ sp[3]->s_vec, sp[4]->s_vec, sp[5]->s_vec, sp[0]->s_n);
+}
+
+void presidency_assist(t_presidency *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0: sprintf(dst,"(signal) Input"); break;
+ case 1: sprintf(dst,"(signal/float) Frame Increment"); break;
+ case 2: sprintf(dst,"(signal/float) Frame Position [0-1]"); break;
+ case 3: sprintf(dst,"(signal/float) Transposition Factor"); break;
+ }
+ } else if (msg==2) {
+ switch (arg) {
+ case 0: sprintf(dst,"(signal) Output"); break;
+ case 1: sprintf(dst,"(signal/float) Record Sync"); break;
+ }
+ }
+}
diff --git a/pvcompand~.c b/pvcompand~.c
new file mode 100644
index 0000000..92035f3
--- /dev/null
+++ b/pvcompand~.c
@@ -0,0 +1,510 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *pvcompand_class;
+#endif
+
+#if PD
+static t_class *pvcompand_class;
+#endif
+
+#define OBJECT_NAME "pvcompand~"
+
+#define MAX_N (16384)
+#define MAX_Nw (MAX_N * 4)
+
+typedef struct _pvcompand
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ float *buffer;
+ float *channel;
+ float *output;
+ //
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ //
+ float *curthresh ;
+ float *atten;
+ float *thresh ;
+ int count;
+ float thresh_interval;
+ float max_atten;
+ float atten_interval ;
+ float tstep;
+ float gstep;
+ float last_max_atten;
+ short norml;
+ short mute;
+ short bypass;
+ short connected[2];
+ int overlap;
+ int winfac;
+} t_pvcompand;
+
+void *pvcompand_new(t_symbol *s, int argc, t_atom *argv);
+t_int *offset_perform(t_int *w);
+t_int *pvcompand_perform(t_int *w);
+void pvcompand_dsp(t_pvcompand *x, t_signal **sp, short *count);
+void pvcompand_assist(t_pvcompand *x, void *b, long m, long a, char *s);
+void update_thresholds(t_pvcompand *x);
+void pvcompand_normalize(t_pvcompand *x, t_floatarg val);
+void pvcompand_float(t_pvcompand *x, double f);
+void pvcompand_free(t_pvcompand *x);
+float pvcompand_ampdb(float db);
+void pvcompand_init(t_pvcompand *x,short initialized);
+void pvcompand_fftinfo(t_pvcompand *x);
+void pvcompand_overlap(t_pvcompand *x, t_floatarg f);
+void pvcompand_winfac(t_pvcompand *x, t_floatarg f);
+void pvcompand_bypass(t_pvcompand *x, t_floatarg f);
+void pvcompand_mute(t_pvcompand *x, t_floatarg f);
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&pvcompand_class, (method)pvcompand_new,
+ (method)pvcompand_free, (short)sizeof(t_pvcompand), 0, A_GIMME, 0);
+ addmess((method)pvcompand_dsp, "dsp", A_CANT, 0);
+ addmess((method)pvcompand_normalize, "normalize", A_LONG, 0);
+ addmess((method)pvcompand_winfac,"winfac", A_FLOAT, 0);
+ addmess((method)pvcompand_overlap,"overlap", A_FLOAT, 0);
+ addmess((method)pvcompand_fftinfo,"fftinfo", 0);
+ addmess((method)pvcompand_bypass,"bypass", A_FLOAT, 0);
+ addmess((method)pvcompand_mute,"mute", A_FLOAT, 0);
+ addmess((method)pvcompand_assist,"assist",A_CANT,0);
+ addfloat((method)pvcompand_float);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+#if PD
+void pvcompand_tilde_setup(void)
+{
+ pvcompand_class = class_new(gensym("pvcompand~"), (t_newmethod)pvcompand_new,
+ (t_method)pvcompand_free ,sizeof(t_pvcompand), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(pvcompand_class, t_pvcompand, x_f);
+ class_addmethod(pvcompand_class,(t_method)pvcompand_dsp,gensym("dsp"),0);
+ class_addmethod(pvcompand_class,(t_method)pvcompand_mute,gensym("mute"),A_FLOAT,0);
+ class_addmethod(pvcompand_class,(t_method)pvcompand_bypass,gensym("bypass"),A_FLOAT,0);
+ class_addmethod(pvcompand_class,(t_method)pvcompand_overlap,gensym("overlap"),A_FLOAT,0);
+ class_addmethod(pvcompand_class,(t_method)pvcompand_winfac,gensym("winfac"),A_FLOAT,0);
+ class_addmethod(pvcompand_class,(t_method)pvcompand_fftinfo,gensym("fftinfo"),0);
+ class_addmethod(pvcompand_class,(t_method)pvcompand_normalize,gensym("normalize"),A_FLOAT,0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+
+#endif
+
+void pvcompand_bypass(t_pvcompand *x, t_floatarg f)
+{
+ x->bypass = (short)f;
+}
+
+void pvcompand_mute(t_pvcompand *x, t_floatarg f)
+{
+ x->mute = (short)f;
+}
+
+
+void pvcompand_free( t_pvcompand *x ){
+#if MSP
+ dsp_free( (t_pxobject *) x);
+#endif
+ freebytes(x->curthresh,0);
+ freebytes(x->atten,0);
+ freebytes(x->thresh,0);
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->input,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->buffer,0);
+ freebytes(x->channel,0);
+ freebytes(x->output,0);
+}
+
+void pvcompand_assist (t_pvcompand *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0:
+ sprintf(dst,"(signal) Input");
+ break;
+ case 1:
+ sprintf(dst,"(float/signal) Threshold");
+ break;
+
+ }
+ } else if (msg==2) {
+ sprintf(dst,"(signal) Output");
+ }
+}
+
+#if MSP
+void pvcompand_float(t_pvcompand *x, double f) // Look at floats at inlets
+{
+int inlet = x->x_obj.z_in;
+
+ if (inlet == 1)
+ {
+ x->last_max_atten = x->max_atten = f;
+ update_thresholds(x);
+
+ }
+}
+#endif
+
+void *pvcompand_new(t_symbol *s, int argc, t_atom *argv)
+{
+#if MSP
+ t_pvcompand *x = (t_pvcompand *)newobject(pvcompand_class);
+ dsp_setup((t_pxobject *)x,2);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+
+#if PD
+ t_pvcompand *x = (t_pvcompand *)pd_new(pvcompand_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+ // INITIALIZATIONS
+ x->D = sys_getblksize();
+ x->R = sys_getsr();
+ x->max_atten = atom_getfloatarg(0,argc,argv);
+ x->overlap = atom_getfloatarg(1,argc,argv);
+ x->winfac = atom_getfloatarg(2,argc,argv);
+ if(!x->max_atten)
+ x->max_atten = -6;
+
+ if(x->D <= 0)
+ x->D = 256;
+ if(x->R <= 0)
+ x->R = 44100;
+
+ pvcompand_init(x,0);
+ return (x);
+}
+
+void pvcompand_init(t_pvcompand *x,short initialized)
+{
+int i;
+
+ if(!power_of_two(x->overlap))
+ x->overlap = 4;
+ if(!power_of_two(x->winfac))
+ x->winfac = 1;
+
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+
+ if(!initialized){
+ x->norml = 0;
+ x->mute = 0;
+ x->bypass = 0;
+ x->thresh_interval = 1.0;
+ x->last_max_atten = x->max_atten;
+ x->atten_interval = 2.0 ;
+ x->tstep = 1.0 ;
+ x->gstep = 2.0 ;
+ x->Wanal = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->Wsyn = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->Hwin = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->input = (float *) getbytes(MAX_Nw * sizeof(float) );
+ x->buffer = (float *) getbytes(MAX_N * sizeof(float) );
+ x->channel = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->output = (float *) getbytes(MAX_N * sizeof(float) );
+ x->bitshuffle = (int *) getbytes(MAX_N * 2 * sizeof( int ) );
+ x->trigland = (float *) getbytes(MAX_N * 2 * sizeof( float ) );
+ x->thresh = (float *) getbytes(MAX_N * sizeof(float) );
+ x->atten = (float *) getbytes(MAX_N * sizeof(float) );
+ x->curthresh = (float *) getbytes(MAX_N * sizeof(float) );
+ }
+
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makewindows( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D);
+ update_thresholds(x);
+
+}
+
+void update_thresholds( t_pvcompand *x ) {
+ int i;
+
+ float nowamp = x->max_atten ;
+ float nowthresh = 0.0 ;
+
+ x->count = 0;
+ if( nowamp < 0.0 )
+ while( nowamp < 0.0 ){
+ x->atten[x->count] = pvcompand_ampdb( nowamp );
+ nowamp += x->gstep ;
+ ++(x->count);
+ if(x->count >= x->N){
+ error("count exceeds %d",x->N);
+ x->count = x->N - 1;
+ break;
+ }
+ }
+ else if( nowamp > 0.0 )
+ while( nowamp > 0.0 ){
+ x->atten[x->count] = pvcompand_ampdb( nowamp );
+ nowamp -= x->gstep ;
+ ++(x->count);
+ if(x->count >= x->N){
+ error("count exceeds %d",x->N);
+ x->count = x->N - 1;
+ break;
+ }
+ }
+
+ for( i = 0; i < x->count; i++){
+ x->thresh[i] = pvcompand_ampdb( nowthresh );
+ nowthresh -= x->tstep ;
+ }
+ /*
+ for( i = 0; i < count; i++)
+ fprintf(stderr,"thresh %f gain %f\n",thresh[i], atten[i]);
+ */
+}
+
+void pvcompand_normalize(t_pvcompand *x, t_floatarg val)
+{
+ x->norml = val;
+}
+
+t_int *pvcompand_perform(t_int *w)
+{
+ float sample, outsamp ;
+ int i,j;
+ float maxamp ;
+ float fmult;
+ float cutoff;
+ float avr, new_avr, rescale;
+
+ t_pvcompand *x = (t_pvcompand *) (w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ int n = (int)(w[5]);
+
+ int inCount = x->inCount;
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *input = x->input;
+ float *Hwin = x->Hwin;
+ float *buffer = x->buffer;
+ float *channel = x->channel;
+ float *output = x->output;
+
+ int D = x->D;
+ int I = D;
+ int R = x->R;
+ int Nw = x->Nw;
+ int N = x->N ;
+ int N2 = x-> N2;
+ int Nw2 = x->Nw2;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland;
+ float mult = x->mult;
+ int count = x->count;
+ float *atten = x->atten;
+ float *curthresh = x->curthresh;
+ float *thresh = x->thresh;
+ float max_atten = x->max_atten;
+
+if( x->mute ){
+ while( n-- ){
+ *out++ = 0.0;
+ }
+ return (w+6);
+}
+if( x->bypass ){
+ while( n-- ){
+ *out++ = *in++ * 0.5; // gain compensation
+ }
+ return (w+6);
+}
+
+#if MSP
+ if( x->connected[1] ){
+ max_atten = *in2++ ;
+ if(max_atten != x->last_max_atten) {
+ x->last_max_atten = x->max_atten = max_atten;
+ update_thresholds(x);
+ }
+ }
+#endif
+
+#if PD
+ max_atten = *in2++ ;
+ if(max_atten != x->last_max_atten) {
+ x->last_max_atten = x->max_atten = max_atten;
+ update_thresholds(x);
+ }
+#endif
+
+ inCount += D;
+
+ for ( j = 0 ; j < Nw - D ; j++ ){
+ input[j] = input[j+D];
+ }
+ for ( j = Nw - D; j < Nw; j++ ) {
+ input[j] = *in++;
+ }
+
+ fold( input, Wanal, Nw, buffer, N, inCount );
+ rdft( N, 1, buffer, bitshuffle, trigland );
+
+ leanconvert(buffer, channel, N2);
+
+ maxamp = 0.;
+ avr = 0;
+ for( i = 0; i < N; i+= 2 ){
+ avr += channel[i];
+ if( maxamp < channel[i] ){
+ maxamp = channel[i] ;
+ }
+ }
+ if(count <= 1){
+ // post("count too low!");
+ count = 1;
+ }
+ for( i = 0; i < count; i++ ){
+ curthresh[i] = thresh[i]*maxamp ;
+ }
+ cutoff = curthresh[count-1];
+ new_avr = 0;
+ for( i = 0; i < N; i += 2){
+ if( channel[i] > cutoff ){
+ j = count-1;
+ while( channel[i] > curthresh[j] ){
+ j--;
+ if( j < 0 ){
+ j = 0;
+ break;
+ }
+ }
+ channel[i] *= atten[j];
+ }
+ new_avr += channel[i] ;
+ }
+
+ leanunconvert( channel,buffer, N2);
+
+ rdft( N, -1, buffer, bitshuffle, trigland );
+
+ overlapadd( buffer, N, Wsyn, output, Nw, inCount);
+ if( x->norml ) {
+ if( new_avr <= 0 ){
+ new_avr = .0001;
+ }
+ rescale = avr / new_avr ;
+ mult *= rescale ;
+
+ } else {
+ mult *= pvcompand_ampdb( max_atten * -.5); ;
+ }
+
+ for ( j = 0; j < D; j++ ){
+ *out++ = output[j] * mult;
+
+ }
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+
+
+ /* restore state variables */
+ x->inCount = inCount % Nw;
+ return (w+6);
+}
+
+float pvcompand_ampdb(float db)
+{
+ float amp;
+ amp = pow((double)10.0, (double)(db/20.0)) ;
+ return(amp);
+}
+
+void pvcompand_overlap(t_pvcompand *x, t_floatarg f)
+{
+int i = (int) f;
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->overlap = i;
+ pvcompand_init(x,1);
+}
+
+void pvcompand_winfac(t_pvcompand *x, t_floatarg f)
+{
+int i = (int)f;
+
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = i;
+ pvcompand_init(x,2);
+}
+
+void pvcompand_fftinfo(t_pvcompand *x)
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+
+void pvcompand_dsp(t_pvcompand *x, t_signal **sp, short *count)
+{
+ long i;
+
+#if MSP
+ x->connected[1] = count[1];
+#endif
+
+ if(x->D != sp[0]->s_n || x->R != sp[0]->s_sr ){
+ x->D = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ pvcompand_init(x,1);
+ }
+
+ dsp_add(pvcompand_perform, 5,x,sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
diff --git a/pvgrain~.c b/pvgrain~.c
new file mode 100644
index 0000000..e3eee1d
--- /dev/null
+++ b/pvgrain~.c
@@ -0,0 +1,536 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *pvgrain_class;
+#endif
+
+#if PD
+static t_class *pvgrain_class;
+#endif
+
+#define OBJECT_NAME "pvgrain~"
+
+typedef struct _pvgrain
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ float *buffer;
+ float *channel;
+ float *output;
+ // for convert
+ float *c_lastphase_in;
+ float c_fundamental;
+ float c_factor_in;
+ float c_factor_out;
+float synt;
+ // for oscbank
+ int NP;
+ float P;
+ int L;
+ int first;
+ float Iinv;
+ float *lastamp;
+ float *lastfreq;
+ float *index;
+ float *table;
+ short *binsort;
+ float myPInc;
+ float ffac;
+ //
+ int lo_bin;
+ int hi_bin;
+ float topfreq;
+ float bottomfreq;
+ // for fast fft
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ //
+ int mute;
+ float grain_probability;
+ float sample_basefreq;
+ int grains_per_frame ;
+ void *list_outlet;
+ float *listdata;
+ short list_count;
+ void *m_clock;
+ int overlap;//overlap factor
+ int winfac;//window factor
+ int vs;//vector size
+
+} t_pvgrain;
+
+void *pvgrain_new(t_symbol *s, int argc, t_atom *argv);
+t_int *offset_perform(t_int *w);
+t_int *pvgrain_perform(t_int *w);
+void pvgrain_dsp(t_pvgrain *x, t_signal **sp, short *count);
+void pvgrain_assist(t_pvgrain *x, void *b, long m, long a, char *s);
+void pvgrain_mute(t_pvgrain *x, t_floatarg state);
+void pvgrain_float(t_pvgrain *x, double f);
+void pvgrain_tick(t_pvgrain *x);
+void pvgrain_printchan(t_pvgrain *x);
+void pvgrain_probability (t_pvgrain *x, t_floatarg prob);
+void pvgrain_framegrains (t_pvgrain *x, t_floatarg grains);
+void pvgrain_topfreq (t_pvgrain *x, t_floatarg top);
+void pvgrain_bottomfreq (t_pvgrain *x, t_floatarg f);
+void pvgrain_basefreq (t_pvgrain *x, t_floatarg base);
+float pvgrain_randf(float min, float max);
+void pvgrain_init(t_pvgrain *x, short initialized);
+void pvgrain_free(t_pvgrain *x);
+void pvgrain_winfac(t_pvgrain *x, t_floatarg factor);
+void pvgrain_overlap(t_pvgrain *x, t_floatarg o);
+void pvgrain_fftinfo(t_pvgrain *x) ;
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&pvgrain_class, (method)pvgrain_new, (method)pvgrain_free,
+ (short)sizeof(t_pvgrain), 0, A_GIMME, 0);
+ addmess((method)pvgrain_dsp, "dsp", A_CANT, 0);
+ addmess((method)pvgrain_assist,"assist",A_CANT,0);
+ addmess((method)pvgrain_mute,"mute",A_DEFFLOAT,0);
+ addmess((method)pvgrain_printchan,"printchan",A_DEFFLOAT,0);
+ addmess((method)pvgrain_probability,"probability",A_DEFFLOAT,0);
+ addmess((method)pvgrain_framegrains,"framegrains",A_DEFFLOAT,0);
+ addmess((method)pvgrain_topfreq,"topfreq",A_DEFFLOAT,0);
+ addmess((method)pvgrain_basefreq,"basefreq",A_DEFFLOAT,0);
+ addmess((method)pvgrain_overlap, "overlap", A_DEFFLOAT, 0);
+ addmess((method)pvgrain_winfac, "winfac", A_DEFFLOAT, 0);
+ addmess((method)pvgrain_fftinfo, "fftinfo", 0);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);}
+#endif
+#if PD
+void pvgrain_tilde_setup(void)
+{
+ pvgrain_class = class_new(gensym("pvgrain~"), (t_newmethod)pvgrain_new,
+ (t_method)pvgrain_free ,sizeof(t_pvgrain), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(pvgrain_class, t_pvgrain, x_f);
+ class_addmethod(pvgrain_class, (t_method)pvgrain_dsp, gensym("dsp"), 0);
+ class_addmethod(pvgrain_class, (t_method)pvgrain_mute, gensym("mute"), A_FLOAT, 0);
+ class_addmethod(pvgrain_class, (t_method)pvgrain_topfreq, gensym("topfreq"), A_FLOAT, 0);
+ class_addmethod(pvgrain_class, (t_method)pvgrain_bottomfreq, gensym("bottomfreq"), A_FLOAT, 0);
+ class_addmethod(pvgrain_class, (t_method)pvgrain_printchan, gensym("printchan"), A_FLOAT, 0);
+ class_addmethod(pvgrain_class, (t_method)pvgrain_probability, gensym("probability"), A_FLOAT, 0);
+ class_addmethod(pvgrain_class, (t_method)pvgrain_framegrains, gensym("framegrains"), A_FLOAT, 0);
+ class_addmethod(pvgrain_class, (t_method)pvgrain_basefreq, gensym("basefreq"), A_FLOAT, 0);
+ class_addmethod(pvgrain_class, (t_method)pvgrain_overlap, gensym("overlap"), A_DEFFLOAT,0);
+ class_addmethod(pvgrain_class, (t_method)pvgrain_winfac, gensym("winfac"), A_DEFFLOAT,0);
+ class_addmethod(pvgrain_class, (t_method)pvgrain_fftinfo, gensym("fftinfo"), 0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+void pvgrain_printchan(t_pvgrain *x)
+{
+ int i;
+ post("***");
+ for( i = 0 ; i < 30; i+= 2 ){
+ post("amp %f freq %f", x->channel[i*2], x->channel[i*2 + 1]);
+ }
+ post("***");
+}
+
+void pvgrain_basefreq (t_pvgrain *x, t_floatarg base)
+{
+ if( base < 0.0 )
+ base = 0. ;
+ if( base > x->R / 2 )
+ base = x->R / 2 ;
+ x->sample_basefreq = base;
+}
+
+void pvgrain_topfreq (t_pvgrain *x, t_floatarg top)
+{
+ float curfreq ;
+ if( top < 50. )
+ top = 50.;
+ if( top > x->R / 2 )
+ top = x->R / 2;
+ x->topfreq = top ;
+ curfreq = 0;
+ x->hi_bin = 0;
+ while( curfreq < x->topfreq ) {
+ ++(x->hi_bin);
+ curfreq += x->c_fundamental ;
+ }
+}
+
+void pvgrain_bottomfreq (t_pvgrain *x, t_floatarg f)
+{
+ float curfreq;
+ if( f >= x->topfreq || f >= x->R/2){
+ post("%f is too high a bottom freq",f);
+ return;
+ }
+
+ x->bottomfreq = f;
+ curfreq = 0;
+ x->lo_bin = 0;
+ while( curfreq < x->bottomfreq ) {
+ ++(x->lo_bin);
+ curfreq += x->c_fundamental ;
+ }
+// post("low bin: %d high bin: %d",x->lo_bin,x->hi_bin);
+}
+
+void pvgrain_probability (t_pvgrain *x, t_floatarg prob)
+{
+
+ if( prob < 0. )
+ prob = 0.;
+ if( prob > 1. )
+ prob = 1.;
+ x->grain_probability = prob ;
+}
+
+void pvgrain_framegrains (t_pvgrain *x, t_floatarg grains)
+{
+
+ if( grains < 1 )
+ grains = 1;
+ if( grains > x->N2 - 1 )
+ grains = x->N2 - 1;
+ x->grains_per_frame = grains ;
+
+}
+
+void pvgrain_tick(t_pvgrain *x)
+{
+ t_atom myList[2];
+ float *listdata = x->listdata;
+ int i;
+
+ for (i=0; i < 2; i++) {
+ SETFLOAT(myList+i,listdata[i]); /* macro for setting a t_atom */
+
+ }
+ outlet_list(x->list_outlet,0L,2,myList);
+
+}
+
+void pvgrain_assist (t_pvgrain *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0:
+ sprintf(dst,"(signal) Input");
+ break;
+
+ }
+ } else if (msg==2) {
+ sprintf(dst,"(list) Amplitude/Frequency Pairs");
+ }
+}
+
+void *pvgrain_new(t_symbol *s, int argc, t_atom *argv)
+{
+#if MSP
+ t_pvgrain *x = (t_pvgrain *)newobject(pvgrain_class);
+ dsp_setup((t_pxobject *)x,1);
+ x->list_outlet = listout(x);
+#endif
+#if PD
+ t_pvgrain *x = (t_pvgrain *)pd_new(pvgrain_class);
+ x->list_outlet = outlet_new(&x->x_obj,gensym("list"));
+#endif
+ x->vs = sys_getblksize();
+ x->R = sys_getsr();
+
+ x->grains_per_frame = atom_getfloatarg(0,argc,argv);
+ x->grain_probability = atom_getfloatarg(1,argc,argv);
+ x->topfreq = atom_getfloatarg(2,argc,argv);
+ x->overlap = atom_getfloatarg(3,argc,argv);
+ x->winfac = atom_getfloatarg(4,argc,argv);
+
+ if(!x->grains_per_frame)
+ x->grains_per_frame = 4;
+ if(!x->grain_probability)
+ x->grain_probability = .0001;
+ if(!x->topfreq)
+ x->topfreq = 1000;
+ if(!x->overlap)
+ x->overlap = 2;
+ if(!x->winfac)
+ x->winfac = 4;
+
+ pvgrain_init(x,0);
+ return (x);
+}
+
+void pvgrain_init(t_pvgrain *x, short initialized)
+{
+ float curfreq;
+
+ x->D = x->vs;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+ x->Iinv = 1./x->D;
+ x->myPInc = x->P*x->L/x->R;
+ x->ffac = x->P * PI/x->N;
+#if MSP
+ x->m_clock = clock_new(x,(method)pvgrain_tick);
+#endif
+#if PD
+ x->m_clock = clock_new(x,(void *)pvgrain_tick);
+#endif
+ x->c_fundamental = (float) x->R/(float)( (x->N2)<<1);
+ x->c_factor_in = (float) x->R/((float)x->D * TWOPI);
+ x->c_factor_out = TWOPI * (float) x->D / (float) x->R;
+
+
+ if(!initialized){
+ x->P = 1.0 ;
+ x->sample_basefreq = 261.0;
+ x->bottomfreq = 0.0;
+ x->mute = 0;
+ x->Wanal = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Wsyn = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Hwin = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->input = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->buffer = (float *) getbytes( MAX_N * sizeof(float) );
+ x->channel = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->output = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->bitshuffle = (int *) getbytes( MAX_N * 2 * sizeof( int ) );
+ x->trigland = (float *) getbytes( MAX_N * 2 * sizeof( float ) );
+ x->c_lastphase_in = (float *) getbytes((MAX_N2+1) * sizeof(float));
+ x->binsort = (short *) getbytes((MAX_N2+1) * sizeof(short) );
+ x->listdata = (float *) getbytes(40 * sizeof(float));
+
+ }
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ memset((char *)x->c_lastphase_in,0,(x->N2+1) * sizeof(float));
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makewindows( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D);
+ curfreq = 0;
+ x->hi_bin = 0;
+ x->lo_bin = 0;
+ while( curfreq < x->topfreq ) {
+ ++(x->hi_bin);
+ curfreq += x->c_fundamental ;
+ }
+ x->lo_bin = 0;
+ curfreq = 0;
+ while( curfreq < x->bottomfreq ) {
+ ++(x->lo_bin);
+ curfreq += x->c_fundamental ;
+ }
+
+}
+
+void pvgrain_overlap(t_pvgrain *x, t_floatarg o)
+{
+ if(!power_of_two((int)o)){
+ error("%f is not a power of two",o);
+ return;
+ }
+ x->overlap = (int)o;
+ pvgrain_init(x,1);
+}
+
+void pvgrain_winfac(t_pvgrain *x, t_floatarg f)
+{
+ if(!power_of_two((int)f)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = (int)f;
+ pvgrain_init(x,2);
+}
+
+void pvgrain_fftinfo( t_pvgrain *x )
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+
+void pvgrain_free(t_pvgrain *x)
+{
+#if MSP
+ dsp_free((t_pxobject *) x);
+#endif
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->input,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->buffer,0);
+ freebytes(x->channel,0);
+ freebytes(x->output,0);
+ freebytes(x->c_lastphase_in,0);
+ freebytes(x->binsort,0);
+ freebytes(x->listdata,0);
+}
+
+t_int *pvgrain_perform(t_int *w)
+{
+ int i,j, in;
+ float tmp, dice;
+ short print_grain;
+
+ t_pvgrain *x = (t_pvgrain *) (w[1]);
+ t_float *inbuf = (t_float *)(w[2]);
+ t_int n = w[3];
+
+ short *binsort = x->binsort;
+ int grains_per_frame = x->grains_per_frame ;
+ int hi_bin = x->hi_bin;
+ int lo_bin = x->lo_bin;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland;
+ float factor_in = x->c_factor_in;
+ int D = x->D;
+ int I = D;
+ int R = x->R;
+ int Nw = x->Nw;
+ int N = x->N ;
+ int N2 = x-> N2;
+ int Nw2 = x->Nw2;
+ float fundamental = x->c_fundamental;
+ float *lastphase_in = x->c_lastphase_in;
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *input = x->input;
+ float *Hwin = x->Hwin;
+ float *buffer = x->buffer;
+ float *channel = x->channel;
+ float selection_probability = x->grain_probability;
+
+ if (x->mute) {
+ return (w+4);
+ }
+
+
+ in = x->inCount ;
+ x->list_count = 0;
+
+ in += D;
+
+ for ( j = 0 ; j < (Nw - D) ; j++ ){
+ input[j] = input[j+D];
+ }
+ for ( j = (Nw-D), i = 0 ; j < Nw; j++, i++ ) {
+ input[j] = *inbuf++;
+ }
+
+ fold( input, Wanal, Nw, buffer, N, in );
+ rdft( N, 1, buffer, bitshuffle, trigland );
+ convert( buffer, channel, N2, lastphase_in, fundamental, factor_in );
+ if( grains_per_frame > hi_bin - lo_bin )
+ grains_per_frame = hi_bin - lo_bin;
+// binsort[0] = 0;
+ for( i = 0; i < hi_bin; i++ ){// could be hi_bin - lo_bin
+ binsort[i] = i + lo_bin;
+ }
+ for( i = lo_bin; i < hi_bin - 1; i++ ){
+ for( j = i+1; j < hi_bin; j++ ){
+ if(channel[binsort[j] * 2] > channel[binsort[i] * 2]) {
+ tmp = binsort[j];
+ binsort[j] = binsort[i];
+ binsort[i] = tmp;
+ }
+ }
+ }
+ for( i = 0; i < grains_per_frame; i++ ){
+ print_grain = 1;
+ dice = pvgrain_randf(0.,1.);
+ if( dice < 0.0 || dice > 1.0 ){
+ error("dice %f out of range", dice);
+ }
+ if( selection_probability < 1.0 ){
+ if( dice > selection_probability) {
+ print_grain = 0;
+ }
+ }
+ if( print_grain ){
+ x->listdata[ x->list_count * 2 ] = channel[ binsort[i]*2 ];
+ x->listdata[ (x->list_count * 2) + 1 ] = channel[(binsort[i]*2) + 1] ;
+ ++(x->list_count);
+ clock_delay(x->m_clock,0);
+ }
+ }
+ x->inCount = in % Nw;
+
+ return (w+4);
+}
+
+float pvgrain_randf(float min, float max) {
+ float guess;
+ guess = (float) (rand() % RAND_MAX) / (float) RAND_MAX ;
+ return ( min + guess * (max - min) );
+}
+
+void pvgrain_mute(t_pvgrain *x, t_floatarg state)
+{
+ x->mute = (short)state;
+}
+
+#if MSP
+void pvgrain_float(t_pvgrain *x, double f) // Look at floats at inlets
+{
+int inlet = x->x_obj.z_in;
+
+ if (inlet == 1)
+ {
+ x->P = f;
+ //post("P set to %f",f);
+ }
+ else if (inlet == 2)
+ {
+ x->synt = f;
+ //post("synt set to %f",f);
+ }
+}
+#endif
+
+void pvgrain_dsp(t_pvgrain *x, t_signal **sp, short *count)
+{
+ /* long i;
+ if( count[1] ){
+ x->pitch_connected = 1;
+ } else {
+ x->pitch_connected = 0;
+ }
+ if( count[2] ){
+ x->synt_connected = 1;
+ } else {
+ x->synt_connected = 0;
+ }
+ */
+ if(x->vs != sp[0]->s_n || x->R != sp[0]->s_sr){
+ x->vs = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ pvgrain_init(x,1);
+ }
+ dsp_add(pvgrain_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+}
+
diff --git a/pvharm~.c b/pvharm~.c
new file mode 100644
index 0000000..6952960
--- /dev/null
+++ b/pvharm~.c
@@ -0,0 +1,581 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *pvharm_class;
+#endif
+
+#if PD
+static t_class *pvharm_class;
+#endif
+
+#define OBJECT_NAME "pvharm~"
+
+typedef struct _pvharm
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ float *buffer;
+ float *channel;
+ float *output;
+ // for convert
+ float *c_lastphase_in;
+ // float *c_lastphase_out;
+ float c_fundamental;
+ float c_factor_in;
+ float c_factor_out;
+
+ float *table;
+ int NP;
+
+ int L;
+ int first;
+ float Iinv;
+
+ float ffac;
+ // for oscbank 1
+ float *lastamp;
+ float *lastfreq;
+ float *index;
+ int lo_bin;
+ int hi_bin;
+ float topfreq;
+ float P;
+ float myPInc;
+ //
+ // for oscbank 2
+ float *lastamp2;
+ float *lastfreq2;
+ float *index2;
+ int lo_bin2;
+ int hi_bin2;
+ float topfreq2;
+ float P2;
+ float myPInc2;
+ //
+
+ float synt;
+ float myPI;
+ float TWOmyPI;
+ // for fast fft
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ short pitch1_connected;
+ short pitch2_connected;
+ short synt_connected;
+ short mute;
+ int vs;//vector size
+ int overlap;//overlap factor
+ int winfac;//window size factor
+ float hifreq;//highest frequency to synthesize
+ float lofreq;//lowest frequency to synthesize
+} t_pvharm;
+
+void *pvharm_new(t_symbol *s, int argc, t_atom *argv);
+t_int *offset_perform(t_int *w);
+t_int *pvharm_perform(t_int *w);
+void pvharm_dsp(t_pvharm *x, t_signal **sp, short *count);
+void pvharm_assist(t_pvharm *x, void *b, long m, long a, char *s);
+void pvharm_float(t_pvharm *x, double f);
+void pvharm_mute(t_pvharm *x, t_floatarg f);
+void pvharm_init(t_pvharm *x, short initialized);
+void pvharm_lowfreq(t_pvharm *x, t_floatarg f);
+void pvharm_highfreq(t_pvharm *x, t_floatarg f);
+void pvharm_free(t_pvharm *x);
+void pvharm_fftinfo(t_pvharm *x);
+void pvharm_overlap(t_pvharm *x, t_floatarg f);
+void pvharm_winfac(t_pvharm *x, t_floatarg f);
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **) &pvharm_class, (method) pvharm_new, (method)pvharm_free,
+ (short)sizeof(t_pvharm), 0, A_GIMME, 0);
+ addmess((method)pvharm_dsp, "dsp", A_CANT, 0);
+ addmess((method)pvharm_assist,"assist",A_CANT,0);
+ addmess((method)pvharm_mute,"mute",A_DEFFLOAT,0);
+
+ addmess((method)pvharm_lowfreq,"lowfreq",A_FLOAT,0);
+ addmess((method)pvharm_highfreq,"highfreq",A_FLOAT,0);
+ addmess((method)pvharm_overlap,"overlap",A_DEFFLOAT,0);
+ addmess((method)pvharm_winfac,"winfac",A_DEFFLOAT,0);
+ addmess((method)pvharm_fftinfo,"fftinfo",0); addfloat((method)pvharm_float);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+#if PD
+void pvharm_tilde_setup(void)
+{
+ pvharm_class = class_new(gensym("pvharm~"), (t_newmethod)pvharm_new,
+ (t_method)pvharm_free ,sizeof(t_pvharm), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(pvharm_class, t_pvharm, x_f);
+ class_addmethod(pvharm_class, (t_method)pvharm_dsp, gensym("dsp"), 0);
+ class_addmethod(pvharm_class, (t_method)pvharm_assist, gensym("assist"), 0);
+ class_addmethod(pvharm_class, (t_method)pvharm_mute, gensym("mute"), A_DEFFLOAT,0);
+ class_addmethod(pvharm_class, (t_method)pvharm_highfreq, gensym("highfreq"), A_DEFFLOAT,0);
+ class_addmethod(pvharm_class, (t_method)pvharm_lowfreq, gensym("lowfreq"), A_DEFFLOAT,0);
+ class_addmethod(pvharm_class,(t_method)pvharm_overlap,gensym("overlap"),A_FLOAT,0);
+ class_addmethod(pvharm_class,(t_method)pvharm_winfac,gensym("winfac"),A_FLOAT,0);
+ class_addmethod(pvharm_class,(t_method)pvharm_fftinfo,gensym("fftinfo"),0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+void pvharm_free(t_pvharm *x)
+{
+#if MSP
+ dsp_free((t_pxobject *) x);
+#endif
+ freebytes(x->c_lastphase_in,0);
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->input,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->buffer,0);
+ freebytes(x->channel,0);
+ freebytes(x->output,0);
+ freebytes(x->lastamp,0);
+ freebytes(x->lastamp2,0);
+ freebytes(x->lastfreq,0);
+ freebytes(x->lastfreq2,0);
+ freebytes(x->index,0);
+ freebytes(x->index2,0);
+ freebytes(x->table,0);
+}
+
+void pvharm_assist (t_pvharm *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0: sprintf(dst,"(signal) Input"); break;
+ case 1: sprintf(dst,"(signal/float) Pitch Multiplier 1"); break;
+ case 2: sprintf(dst,"(signal/float) Pitch Multiplier 2"); break;
+ case 3: sprintf(dst,"(signal/float) Synthesis Threshold"); break;
+ }
+ } else if (msg==2) {
+ sprintf(dst,"(signal) Output");
+ }
+}
+
+void pvharm_overlap(t_pvharm *x, t_floatarg f)
+{
+ int i = (int) f;
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->overlap = i;
+ pvharm_init(x,1);
+}
+
+void pvharm_winfac(t_pvharm *x, t_floatarg f)
+{
+ int i = (int)f;
+
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = i;
+ pvharm_init(x,2);
+}
+
+void pvharm_fftinfo(t_pvharm *x)
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+
+
+void pvharm_highfreq(t_pvharm *x, t_floatarg f)
+{
+ float curfreq;
+
+ if(f < x->lofreq){
+ error("current minimum is %f",x->lofreq);
+ return;
+ }
+ if(f > x->R/2 ){
+ f = x->R/2;
+ }
+ x->hifreq = f;
+ x->hi_bin = 1;
+ curfreq = 0;
+ while(curfreq < x->hifreq) {
+ ++(x->hi_bin);
+ curfreq += x->c_fundamental;
+ }
+}
+
+void pvharm_lowfreq(t_pvharm *x, t_floatarg f)
+{
+ float curfreq;
+
+ if(f > x->hifreq){
+ error("current maximum is %f",x->lofreq);
+ return;
+ }
+ if(f < 0 ){
+ f = 0;
+ }
+ x->lofreq = f;
+ x->lo_bin = 0;
+ curfreq = 0;
+ while( curfreq < x->lofreq ) {
+ ++(x->lo_bin);
+ curfreq += x->c_fundamental ;
+ }
+}
+
+void *pvharm_new(t_symbol *s, int argc, t_atom *argv)
+{
+ // int i;
+#if MSP
+ t_pvharm *x = (t_pvharm *)newobject(pvharm_class);
+ dsp_setup((t_pxobject *)x,4);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+#if PD
+ t_pvharm *x = (t_pvharm *)pd_new(pvharm_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+ x->vs = sys_getblksize();
+ x->R = sys_getsr();
+
+ x->lofreq = atom_getfloatarg(0,argc,argv);
+ x->hifreq = atom_getfloatarg(1,argc,argv);
+ x->overlap = atom_getfloatarg(2,argc,argv);
+ x->winfac = atom_getfloatarg(3,argc,argv);
+ if(x->lofreq <0 || x->lofreq> 22050)
+ x->lofreq = 0;
+ if(x->hifreq <50 || x->hifreq> 22050)
+ x->hifreq = 4000;
+
+ if(!power_of_two(x->overlap))
+ x->overlap = 4;
+ if(!power_of_two(x->winfac))
+ x->winfac = 2;
+
+ pvharm_init(x,0);
+ return (x);
+}
+
+void pvharm_init(t_pvharm *x, short initialized)
+{
+ int i;
+ float curfreq;
+
+ x->D = x->vs;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+ x->Iinv = 1./x->D;
+ x->c_fundamental = (float) x->R/(float)((x->N2)<<1);
+ x->c_factor_in = (float) x->R/((float)x->D * TWOPI);
+ x->c_factor_out = TWOPI * (float) x->D / (float) x->R;
+
+ if(!initialized){
+ x->P = .5 ; // for testing purposes
+ x->P2 = .6666666666 ; // for testing purposes
+ x->L = 8192 ;
+ x->synt = .00005;
+ x->mute = 0;
+ x->Wanal = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Wsyn = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Hwin = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->input = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->output = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->buffer = (float *) getbytes( MAX_N * sizeof(float) );
+ x->channel = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->bitshuffle = (int *) getbytes( MAX_N * 2 * sizeof( int ) );
+ x->trigland = (float *) getbytes( MAX_N * 2 * sizeof( float ) );
+
+ x->lastamp = (float *) getbytes((MAX_N+1) * sizeof(float));
+ x->lastfreq = (float *) getbytes((MAX_N+1) * sizeof(float));
+ x->lastamp2 = (float *) getbytes((MAX_N+1) * sizeof(float));
+ x->lastfreq2 = (float *) getbytes((MAX_N+1) * sizeof(float));
+ x->index = (float *) getbytes((MAX_N+1) * sizeof(float));
+ x->index2 = (float *) getbytes((MAX_N+1) * sizeof(float));
+ x->table = (float *) getbytes(x->L * sizeof(float));
+ x->c_lastphase_in = (float *) getbytes((MAX_N2+1) * sizeof(float));
+ }
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ memset((char *)x->c_lastphase_in,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->lastamp,0,(x->N+1) * sizeof(float));
+ memset((char *)x->lastfreq,0,(x->N+1) * sizeof(float));
+ memset((char *)x->lastamp2,0,(x->N+1) * sizeof(float));
+ memset((char *)x->lastfreq2,0,(x->N+1) * sizeof(float));
+ memset((char *)x->index,0,(x->N+1) * sizeof(float));
+ memset((char *)x->index2,0,(x->N+1) * sizeof(float));
+
+ x->myPInc = x->P * x->L/x->R;
+ x->myPInc2 = x->P2 * x->L/x->R;
+ x->ffac = x->P * PI/x->N;
+ if(x->hifreq < x->c_fundamental) {
+ x->hifreq = 3000.0 ;
+ }
+ x->hi_bin = 1;
+ curfreq = 0;
+ while(curfreq < x->hifreq) {
+ ++(x->hi_bin);
+ curfreq += x->c_fundamental ;
+ }
+ if( x->hi_bin >= x->N2 ){
+ x->hi_bin = x->N2 - 1;
+ }
+ x->lo_bin = 0;
+ curfreq = 0;
+ while(curfreq < x->lofreq) {
+ ++(x->lo_bin);
+ curfreq += x->c_fundamental ;
+ }
+
+ for (i = 0; i < x->L; i++) {
+ x->table[i] = (float) x->N * cos((float)i * TWOPI / (float)x->L);
+ }
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makehanning( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 0);
+
+}
+
+t_int *pvharm_perform(t_int *w)
+{
+ int i,j, in,on;
+ int amp,freq,chan;
+ int breaker = 0;
+ float a,ainc,f,finc,address;
+ float tmpfreq;
+ t_pvharm *x = (t_pvharm *) (w[1]);
+ t_float *inbuf = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *in3 = (t_float *)(w[4]);
+ t_float *in4 = (t_float *)(w[5]);
+ t_float *outbuf = (t_float *)(w[6]);
+ t_int n = w[7];
+
+ int D = x->D;
+ int I = D;
+ int R = x->R;
+ int Nw = x->Nw;
+ int N = x->N ;
+ int N2 = x-> N2;
+ int Nw2 = x->Nw2;
+ int L = x->L;
+ float fundamental = x->c_fundamental;
+ float factor_in = x->c_factor_in;
+ float factor_out = x->c_factor_out;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland;
+ float mult = x->mult;
+ float synt = x->synt;
+ float P = x->P;
+ float P2 = x->P2;
+ float Iinv = x->Iinv;
+ float myPInc = x->myPInc;
+ float myPInc2 = x->myPInc2;
+ float *table = x->table;
+ float *lastamp = x->lastamp;
+ float *lastamp2 = x->lastamp2;
+ float *lastfreq = x->lastfreq;
+ float *lastfreq2 = x->lastfreq2;
+ float *bindex = x->index;
+ float *bindex2 = x->index2;
+ float *lastphase_in = x->c_lastphase_in;
+ // float *lastphase_out = x->c_lastphase_out;
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *input = x->input;
+ float *Hwin = x->Hwin;
+ float *buffer = x->buffer;
+ float *channel = x->channel;
+ float *output = x->output;
+ int hi_bin = x->hi_bin;
+ int lo_bin = x->lo_bin;
+ in = on = x->inCount ;
+
+ if( x->mute ){
+ for ( j = 0; j < n; j++ ){
+ *outbuf++ = 0.0;
+ }
+ return (w+8);
+ }
+
+
+ if( x->synt_connected ){
+ synt = *in4++;
+ }
+ if( x->pitch1_connected) {
+ P = *in2++;
+ myPInc = P * x->L/x->R;
+ }
+ if( x->pitch2_connected) {
+ P2 = *in3++;
+ myPInc2 = P2 * x->L/x->R;
+ }
+ in += D;
+ on += I;
+
+ for ( j = 0 ; j < (Nw - D) ; j++ ){
+ input[j] = input[j+D];
+ }
+ for ( j = (Nw-D), i = 0 ; j < Nw; j++, i++ ) {
+ input[j] = *inbuf++;
+ }
+
+ fold( input, Wanal, Nw, buffer, N, in );
+ rdft( N, 1, buffer, bitshuffle, trigland );
+ convert( buffer, channel, N2, lastphase_in, fundamental, factor_in );
+
+
+ for ( chan = lo_bin; chan < hi_bin; chan++ ) {
+
+ freq = ( amp = ( chan << 1 ) ) + 1;
+ if ( channel[amp] < synt ){
+ breaker = 1;
+ }
+ if( breaker ) {
+ breaker = 0 ;
+ } else {
+ tmpfreq = channel[freq] * myPInc;
+ finc = ( tmpfreq - ( f = lastfreq[chan] ) )*Iinv;
+ ainc = ( channel[amp] - ( a = lastamp[chan] ) )*Iinv;
+ address = bindex[chan];
+ for ( n = 0; n < I; n++ ) {
+ output[n] += a*table[ (int) address ];
+ address += f;
+ while ( address >= L )
+ address -= L;
+ while ( address < 0 )
+ address += L;
+ a += ainc;
+ f += finc;
+ }
+ lastfreq[chan] = tmpfreq;
+ lastamp[chan] = channel[amp];
+ bindex[chan] = address;
+ // OSC BANK 2
+ tmpfreq = channel[freq] * myPInc2;
+ finc = ( tmpfreq - ( f = lastfreq2[chan] ) )*Iinv;
+ ainc = ( channel[amp] - ( a = lastamp2[chan] ) )*Iinv;
+ address = bindex2[chan];
+ for ( n = 0; n < I; n++ ) {
+ output[n] += a*table[ (int) address ];
+
+ address += f;
+ while ( address >= L )
+ address -= L;
+ while ( address < 0 )
+ address += L;
+ a += ainc;
+ f += finc;
+ }
+ lastfreq2[chan] = tmpfreq;
+ lastamp2[chan] = channel[amp];
+ bindex2[chan] = address;
+
+ }
+ }
+
+ for ( j = 0; j < D; j++ ){
+ *outbuf++ = output[j] * mult;
+ }
+ for ( j = 0; j < Nw - D; j++ ){
+ output[j] = output[j+D];
+ }
+
+ for ( j = Nw - D; j < Nw; j++ ){
+ output[j] = 0.;
+ }
+
+ x->P = P;
+ x->P2 = P2;
+ x->inCount = in;
+ return (w+8);
+}
+
+#if MSP
+void pvharm_float(t_pvharm *x, double f) // Look at floats at inlets
+{
+ int inlet = x->x_obj.z_in;
+
+ if (inlet == 1)
+ {
+ x->P = f;
+ x->myPInc = x->P*x->L/x->R;
+
+ }
+ else if (inlet == 2)
+ {
+ x->P2 = f;
+ x->myPInc2 = x->P2*x->L/x->R;
+ }
+ else if (inlet == 3)
+ {
+ x->synt = f;
+ }
+
+}
+#endif
+
+void pvharm_mute(t_pvharm *x, t_floatarg state)
+{
+ x->mute = (short)state;
+}
+
+void pvharm_dsp(t_pvharm *x, t_signal **sp, short *count)
+{
+#if MSP
+ x->pitch1_connected = count[1];
+ x->pitch2_connected = count[2];
+ x->synt_connected = count[3];
+#endif
+#if PD
+ x->pitch1_connected = 1;
+ x->pitch2_connected = 1;
+ x->synt_connected = 1;
+#endif
+ if(x->vs != sp[0]->s_n || x->R != sp[0]->s_sr){
+ x->vs = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ pvharm_init(x,1);
+ }
+ // post("pvharm: sampling rate is %f",sp[0]->s_sr );
+ dsp_add(pvharm_perform, 7, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,
+ sp[3]->s_vec, sp[4]->s_vec, sp[0]->s_n);
+}
+
diff --git a/pvoc~.c b/pvoc~.c
new file mode 100644
index 0000000..2b806d9
--- /dev/null
+++ b/pvoc~.c
@@ -0,0 +1,564 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *pvoc_class;
+#endif
+
+#if PD
+static t_class *pvoc_class;
+#endif
+
+#define OBJECT_NAME "pvoc~"
+
+typedef struct _pvoc
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ float *buffer;
+ float *channel;
+ float *output;
+ // for convert
+ float *c_lastphase_in;
+ float *c_lastphase_out;
+ float c_fundamental;
+ float c_factor_in;
+ float c_factor_out;
+
+ // for oscbank
+ int NP;
+ float P;
+ int L;
+ int first;
+ float Iinv;
+ float *lastamp;
+ float *lastfreq;
+ float *index;
+ float *table;
+ float myPInc;
+ float ffac;
+ //
+ float lofreq;
+ float hifreq;
+ int lo_bin;
+ int hi_bin;
+ float topfreq;
+ float synt;
+ // for fast fft
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ //
+ int bypass_state;
+ int pitch_connected;
+ int synt_connected;
+ int overlap;
+ int winfac;
+ short mute;
+} t_pvoc;
+
+void *pvoc_new(t_symbol *s, int argc, t_atom *argv);
+t_int *offset_perform(t_int *w);
+t_int *pvoc_perform(t_int *w);
+void pvoc_dsp(t_pvoc *x, t_signal **sp, short *count);
+void pvoc_assist(t_pvoc *x, void *b, long m, long a, char *s);
+void pvoc_bypass(t_pvoc *x, t_floatarg state);//Pd does not accept A_LONG
+void pvoc_float(t_pvoc *x, double f);
+void pvoc_free(t_pvoc *x);
+void pvoc_mute(t_pvoc *x, t_floatarg tog);
+void pvoc_init(t_pvoc *x, short initialized);
+void pvoc_lowfreq(t_pvoc *x, t_floatarg f);
+void pvoc_highfreq(t_pvoc *x, t_floatarg f);
+void pvoc_overlap(t_pvoc *x, t_floatarg o);
+void pvoc_winfac(t_pvoc *x, t_floatarg f);
+void pvoc_fftinfo(t_pvoc *x);;
+
+#if PD
+/* Pd Initialization */
+void pvoc_tilde_setup(void)
+{
+ pvoc_class = class_new(gensym("pvoc~"), (t_newmethod)pvoc_new,
+ (t_method)pvoc_free ,sizeof(t_pvoc), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(pvoc_class, t_pvoc, x_f);
+ class_addmethod(pvoc_class, (t_method)pvoc_dsp, gensym("dsp"), 0);
+ class_addmethod(pvoc_class, (t_method)pvoc_mute, gensym("mute"), A_DEFFLOAT,0);
+ class_addmethod(pvoc_class, (t_method)pvoc_bypass, gensym("bypass"), A_DEFFLOAT,0);
+ class_addmethod(pvoc_class, (t_method)pvoc_highfreq, gensym("highfreq"), A_DEFFLOAT,0);
+ class_addmethod(pvoc_class, (t_method)pvoc_lowfreq, gensym("lowfreq"), A_DEFFLOAT,0);
+ class_addmethod(pvoc_class, (t_method)pvoc_overlap, gensym("overlap"), A_DEFFLOAT,0);
+ class_addmethod(pvoc_class, (t_method)pvoc_winfac, gensym("winfac"), A_DEFFLOAT,0);
+ class_addmethod(pvoc_class, (t_method)pvoc_fftinfo, gensym("fftinfo"),0);
+ class_addmethod(pvoc_class, (t_method)pvoc_assist, gensym("assist"), 0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&pvoc_class, (method)pvoc_new, (method)pvoc_free, (short)sizeof(t_pvoc), 0L, A_GIMME, 0);
+ addmess((method)pvoc_dsp, "dsp", A_CANT, 0);
+ addmess((method)pvoc_assist,"assist",A_CANT,0);
+ addmess((method)pvoc_bypass,"bypass",A_DEFFLOAT,0);
+ addmess((method)pvoc_mute,"mute",A_DEFFLOAT,0);
+ addmess((method)pvoc_lowfreq,"lowfreq",A_DEFFLOAT,0);
+ addmess((method)pvoc_highfreq,"highfreq",A_DEFFLOAT,0);
+ addmess((method)pvoc_fftinfo,"fftinfo",0);
+ addmess((method)pvoc_overlap, "overlap", A_DEFFLOAT, 0);
+ addmess((method)pvoc_winfac, "winfac", A_DEFFLOAT, 0);
+ addfloat((method)pvoc_float);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+void pvoc_mute(t_pvoc *x, t_floatarg tog)
+{
+ x->mute = (short)tog;
+}
+
+void pvoc_overlap(t_pvoc *x, t_floatarg f)
+{
+ int i = (int) f;
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->overlap = i;
+ pvoc_init(x,1);
+}
+
+void pvoc_winfac(t_pvoc *x, t_floatarg f)
+{
+ int i = (int)f;
+
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = i;
+ pvoc_init(x,2);
+}
+
+void pvoc_fftinfo(t_pvoc *x)
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+void pvoc_free(t_pvoc *x ){
+#if MSP
+ dsp_free((t_pxobject *) x);
+#endif
+ freebytes(x->c_lastphase_in,0);
+ freebytes(x->c_lastphase_out,0);
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->input,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->buffer,0);
+ freebytes(x->channel,0);
+ freebytes(x->output,0);
+ freebytes(x->lastamp,0);
+ freebytes(x->lastfreq,0);
+ freebytes(x->index,0);
+ freebytes(x->table,0);
+}
+
+/*MSP only but Pd crashes without it
+maybe because of function definition???
+*/
+void pvoc_assist (t_pvoc *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0: sprintf(dst,"(signal) Input"); break;
+ case 1: sprintf(dst,"(signal/float) Pitch Modification Factor"); break;
+ case 2: sprintf(dst,"(signal/float) Synthesis Threshold"); break;
+ }
+ } else if (msg==2) {
+ sprintf(dst,"(signal) Output");
+ }
+}
+
+void pvoc_highfreq(t_pvoc *x, t_floatarg f)
+{
+ float curfreq;
+
+ if(f < x->lofreq){
+ error("current minimum is %f",x->lofreq);
+ return;
+ }
+ if(f > x->R/2 ){
+ f = x->R/2;
+ }
+ x->hifreq = f;
+ x->hi_bin = 1;
+ curfreq = 0;
+ while(curfreq < x->hifreq) {
+ ++(x->hi_bin);
+ curfreq += x->c_fundamental;
+ }
+}
+
+void pvoc_lowfreq(t_pvoc *x, t_floatarg f)
+{
+ float curfreq;
+
+ if(f > x->hifreq){
+ error("current maximum is %f",x->lofreq);
+ return;
+ }
+ if(f < 0 ){
+ f = 0;
+ }
+ x->lofreq = f;
+ x->lo_bin = 0;
+ curfreq = 0;
+ while( curfreq < x->lofreq ) {
+ ++(x->lo_bin);
+ curfreq += x->c_fundamental ;
+ }
+}
+
+
+void pvoc_init(t_pvoc *x, short initialized)
+{
+ int i;
+ float curfreq;
+
+ if(!x->R)//temp init if MSP functions returned zero
+ x->R = 44100;
+ if(!x->D)
+ x->D = 256;
+ if(x->P <= 0)
+ x->P = 1.0;
+ if(!power_of_two(x->overlap))
+ x->overlap = 4;
+ if(!power_of_two(x->winfac))
+ x->winfac = 2;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = x->N / 2;
+ x->Nw2 = x->Nw / 2;
+ x->inCount = -(x->Nw);
+ x->bypass_state = 0;
+ x->mult = 1. / (float) x->N;
+ x->pitch_connected = 0;
+ x->synt_connected = 0;
+ x->mute = 0;
+ x->synt = .000001;
+ x->L = 8192 ;
+ x->c_fundamental = (float) x->R/(float)( (x->N2)<<1 );
+ x->c_factor_in = (float) x->R/((float)x->D * TWOPI);
+ x->c_factor_out = TWOPI * (float) x->D / (float) x->R;
+ x->Iinv = 1./x->D;
+ x->myPInc = x->P*x->L/x->R;
+ x->ffac = x->P * PI/x->N;
+
+ if(!initialized){
+ x->Wanal = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Wsyn = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Hwin = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->input = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->output = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->buffer = (float *) getbytes( MAX_N * sizeof(float) );
+ x->channel = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->bitshuffle = (int *) getbytes( MAX_N * 2 * sizeof( int ) );
+ x->trigland = (float *) getbytes( MAX_N * 2 * sizeof( float ) );
+ x->c_lastphase_in = (float *) getbytes( (MAX_N2+1) * sizeof(float) );
+ x->c_lastphase_out = (float *) getbytes( (MAX_N2+1) * sizeof(float) );
+ x->lastamp = (float *) getbytes( (MAX_N+1) * sizeof(float) );
+ x->lastfreq = (float *) getbytes( (MAX_N+1) * sizeof(float) );
+ x->index = (float *) getbytes( (MAX_N+1) * sizeof(float) );
+ x->table = (float *) getbytes( x->L * sizeof(float) );
+ x->P = 1.0;
+ x->ffac = x->P * PI/MAX_N;
+ }
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ memset((char *)x->c_lastphase_in,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->c_lastphase_out,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->lastamp,0,(x->N+1) * sizeof(float));
+ memset((char *)x->lastfreq,0,(x->N+1) * sizeof(float));
+ memset((char *)x->index,0,(x->N+1) * sizeof(float));
+
+ for ( i = 0; i < x->L; i++ ) {
+ x->table[i] = (float) x->N * cos((float)i * TWOPI / (float)x->L);
+ }
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makehanning( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 0);
+
+ if( x->hifreq < x->c_fundamental ) {
+ x->hifreq = 3000.0 ;
+ }
+ x->hi_bin = 1;
+ curfreq = 0;
+ while( curfreq < x->hifreq ) {
+ ++(x->hi_bin);
+ curfreq += x->c_fundamental ;
+ }
+
+ x->lo_bin = 0;
+ curfreq = 0;
+ while( curfreq < x->lofreq ) {
+ ++(x->lo_bin);
+ curfreq += x->c_fundamental ;
+ }
+
+}
+
+void *pvoc_new(t_symbol *s, int argc, t_atom *argv)
+{
+#if MSP
+ t_pvoc *x = (t_pvoc *)newobject(pvoc_class);
+ dsp_setup((t_pxobject *)x,3);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+
+#if PD
+ t_pvoc *x = (t_pvoc *)pd_new(pvoc_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+ x->lofreq = atom_getfloatarg(0,argc,argv);
+ x->hifreq = atom_getfloatarg(1,argc,argv);
+ x->overlap = atom_getfloatarg(2,argc,argv);
+ x->winfac = atom_getfloatarg(3,argc,argv);
+
+ if(x->lofreq <0 || x->lofreq> 22050)
+ x->lofreq = 0;
+ if(x->hifreq <50 || x->hifreq> 22050)
+ x->hifreq = 4000;
+
+
+ if(!power_of_two(x->overlap)){
+ x->overlap = 4;
+ }
+ if(!power_of_two(x->winfac)){
+ x->winfac = 2;
+ }
+ x->R = sys_getsr();
+ x->D = sys_getblksize();
+
+ pvoc_init(x,0);
+
+ return (x);
+}
+
+t_int *pvoc_perform(t_int *w)
+{
+ int i,j, in,on;
+ int amp,freq,chan,L = 8192;
+
+ float a,ainc,f,finc,address;
+ int breaker = 0;
+ t_pvoc *x = (t_pvoc *) (w[1]);
+ t_float *inbuf = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *in3 = (t_float *)(w[4]);
+ t_float *outbuf = (t_float *)(w[5]);
+ t_int n = w[6];
+
+ int D = x->D;
+ int I = D;
+ int R = x->R;
+ int Nw = x->Nw;
+ int N = x->N ;
+ int N2 = x-> N2;
+ int Nw2 = x->Nw2;
+ float fundamental = x->c_fundamental;
+ float factor_in = x->c_factor_in;
+ float factor_out = x->c_factor_out;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland;
+ float mult = x->mult;
+ float synt = x->synt;
+ float P = x->P;
+ float Iinv = 1./x->D;
+ float myPInc = x->myPInc;
+ float *table = x->table;
+ float *lastamp = x->lastamp ;
+ float *lastfreq = x->lastfreq ;
+ float *bindex = x->index;
+ float *lastphase_in = x->c_lastphase_in;
+ float *lastphase_out = x->c_lastphase_out;
+
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *input = x->input;
+ float *Hwin = x->Hwin;
+ float *buffer = x->buffer;
+ float *channel = x->channel;
+ float *output = x->output;
+ int hi_bin = x->hi_bin;
+ int lo_bin = x->lo_bin;
+ in = on = x->inCount ;
+
+
+ if(x->mute){
+ while(n--){
+ *outbuf++ = 0;
+ }
+ return w+7;
+ }
+#if MSP
+ if(x->pitch_connected) {
+ P = *in2;
+ myPInc = P * (float) x->L / (float)x->R;
+ }
+
+ if (x->synt_connected) {
+ synt = *in3;
+ }
+#endif
+ // Pd has superior float/signal inlet treatment
+#if PD
+ P = *in2;
+ synt = *in3;
+ myPInc = P * (float) x->L / (float)x->R;
+#endif
+
+ if (x->bypass_state) {
+ for( j = 0; j < D; j++ ) {
+ *outbuf++ = *inbuf++;
+ }
+ return w+7;
+ }
+
+ in = on = x->inCount ;
+
+ in += D;
+ on += I;
+
+ for ( j = 0 ; j < (Nw - D) ; j++ ){
+ input[j] = input[j+D];
+ }
+ for ( j = (Nw-D), i = 0 ; j < Nw; j++, i++ ) {// unneeded loop variable
+ input[j] = *inbuf++;
+ }
+
+ fold( input, Wanal, Nw, buffer, N, in );
+ rdft( N, 1, buffer, bitshuffle, trigland );
+ convert( buffer, channel, N2, lastphase_in, fundamental, factor_in );
+
+
+ // start osc bank
+
+ for ( chan = lo_bin; chan < hi_bin; chan++ ) {
+
+ freq = ( amp = ( chan << 1 ) ) + 1;
+ if ( channel[amp] < synt ){
+ breaker = 1;
+ }
+ if( breaker ) {
+ breaker = 0 ;
+ } else {
+ channel[freq] *= myPInc;
+ finc = ( channel[freq] - ( f = lastfreq[chan] ) )*Iinv;
+ ainc = ( channel[amp] - ( a = lastamp[chan] ) )*Iinv;
+ address = bindex[chan];
+ for ( n = 0; n < I; n++ ) {
+ output[n] += a*table[ (int) address ];
+
+ address += f;
+ while ( address >= L )
+ address -= L;
+ while ( address < 0 )
+ address += L;
+ a += ainc;
+ f += finc;
+ }
+ lastfreq[chan] = channel[freq];
+ lastamp[chan] = channel[amp];
+ bindex[chan] = address;
+ }
+ }
+
+
+ for ( j = 0; j < D; j++ ){
+ *outbuf++ = output[j] * mult;
+ }
+ for ( j = 0; j < Nw - D; j++ ){
+ output[j] = output[j+D];
+ }
+
+ for ( j = Nw - D; j < Nw; j++ ){
+ output[j] = 0.;
+ }
+
+
+
+ // restore state variables
+ x->inCount = in;
+ return (w+7);
+}
+
+void pvoc_bypass(t_pvoc *x, t_floatarg state)
+{
+ x->bypass_state = state;
+}
+
+#if MSP
+void pvoc_float(t_pvoc *x, double f) // Look at floats at inlets
+{
+ int inlet = x->x_obj.z_in;
+
+ if (inlet == 1)
+ {
+ x->P = (float)f;
+ x->myPInc = x->P*x->L/x->R;
+ }
+ else if (inlet == 2)
+ {
+ x->synt = (float)f;
+ }
+
+}
+#endif
+
+
+void pvoc_dsp(t_pvoc *x, t_signal **sp, short *count)
+{
+
+#if MSP // these blew up Pd
+ x->pitch_connected = count[1];
+ x->synt_connected = count[2];
+#endif
+
+ if(x->D != sp[0]->s_n || x->R != sp[0]->s_sr ){
+ x->D = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ pvoc_init(x,1);
+ }
+
+ dsp_add(pvoc_perform, 6, x,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec,
+ sp[0]->s_n);
+}
+
diff --git a/pvtuner~.c b/pvtuner~.c
new file mode 100644
index 0000000..a142680
--- /dev/null
+++ b/pvtuner~.c
@@ -0,0 +1,1232 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *pvtuner_class;
+#endif
+
+#if PD
+static t_class *pvtuner_class;
+#endif
+
+#define OBJECT_NAME "pvtuner~"
+
+#define MAXTONES (1024)
+#define BASE_FREQ (27.5) /* low A */
+#define DIATONIC 0
+#define EASTERN 1
+#define MINOR 2
+#define EQ12 3
+#define PENTATONIC 4
+#define MAJOR_ADDED_SIXTH 5
+#define MINOR_ADDED_SIXTH 6
+#define ADDED_SIXTH_MAJOR 5
+#define ADDED_SIXTH_MINOR 6
+#define MAJOR_SEVENTH_CHORD 7
+#define MINOR_SEVENTH_CHORD 8
+#define DOMINANT_SEVENTH_CHORD 9
+#define EQ8 10
+#define PENTACLUST 11
+#define QUARTERCLUST 12
+#define EQ5 13
+#define SLENDRO 14
+#define PELOG 15
+#define IMPORTED_SCALE 16
+
+
+typedef struct _pvtuner
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ float *buffer;
+ float *channel;
+ float *output;
+ float *bindex;
+ // for convert
+ float *c_lastphase_in;
+ float *c_lastphase_out;
+ float c_fundamental;
+ float c_factor_in;
+ float c_factor_out;
+
+ // for oscbank
+ int NP;
+ float P;
+ int L;
+ int first;
+ float Iinv;
+ float *lastamp;
+ float *lastfreq;
+ // float *osc_index;
+ float *table;
+ float myPInc;
+ float ffac;
+ //
+ int lo_bin;
+ int hi_bin;
+ int hi_tune_bin;
+ float topfreq;
+ float synt;
+ // for fast fft
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ //
+ // float *prebuffer;
+ // float *postbuffer;
+ //
+ int bypass_state;
+ int pitch_connected;
+ int synt_connected;
+ // TUNING
+ float *pitchgrid ;
+ float pbase ;
+ int scale_steps;
+ short current_scale;
+ short mute;
+ //
+ float lofreq;
+ float hifreq;
+ int vs;
+ float funda;
+ float curfreq;
+ int overlap;
+ int winfac;
+ float tabscale;
+ // int quality;
+ int scale_len;
+} t_pvtuner;
+
+
+float closestf(float test, float *arr) ;
+void pvtuner_diatonic( t_pvtuner *x );
+void pvtuner_eastern( t_pvtuner *x );
+void pvtuner_minor( t_pvtuner *x );
+void pvtuner_eq12( t_pvtuner *x );
+void pvtuner_pentatonic( t_pvtuner *x );
+void pvtuner_major_added_sixth( t_pvtuner *x );
+void pvtuner_minor_added_sixth( t_pvtuner *x );
+void pvtuner_major_seventh_chord( t_pvtuner *x );
+void pvtuner_minor_seventh_chord( t_pvtuner *x );
+void pvtuner_dominant_seventh_chord( t_pvtuner *x );
+void pvtuner_eq8( t_pvtuner *x );
+void pvtuner_pentaclust( t_pvtuner *x );
+void pvtuner_quarterclust( t_pvtuner *x );
+void pvtuner_eq5( t_pvtuner *x );
+void pvtuner_slendro( t_pvtuner *x );
+void pvtuner_pelog( t_pvtuner *x );
+void pvtuner_update_imported( t_pvtuner *x );
+void pvtuner_init(t_pvtuner *x,short initialized);
+void *pvtuner_new(t_symbol *s, int argc, t_atom *argv);
+void pvtuner_import_scale(t_pvtuner *x, t_symbol *filename);
+void pvtuner_list (t_pvtuner *x, t_symbol *msg, short argc, t_atom *argv);
+void pvtuner_topfreq( t_pvtuner *x, t_floatarg f );
+void pvtuner_toptune( t_pvtuner *x, t_floatarg f );
+void pvtuner_frequency_range(t_pvtuner *x, t_floatarg lo, t_floatarg hi);
+t_int *pvtuner_perform(t_int *w);
+void pvtuner_basefreq( t_pvtuner *x, t_floatarg bassfreq);
+void pvtuner_free(t_pvtuner *x);
+void pvtuner_assist (t_pvtuner *x, void *b, long msg, long arg, char *dst);
+void pvtuner_bypass(t_pvtuner *x, t_floatarg state);
+void pvtuner_mute(t_pvtuner *x, t_floatarg state);
+void pvtuner_dsp(t_pvtuner *x, t_signal **sp, short *count);
+void pvtuner_float(t_pvtuner *x, double f) ;
+void pvtuner_toptune(t_pvtuner *x, t_floatarg f);
+void pvtuner_topfreq(t_pvtuner *x, t_floatarg f);
+void pvtuner_list (t_pvtuner *x, t_symbol *msg, short argc, t_atom *argv);
+void pvtuner_fftinfo(t_pvtuner *x);
+void pvtuner_overlap(t_pvtuner *x, t_floatarg f);
+void pvtuner_winfac(t_pvtuner *x, t_floatarg f);
+void pvtuner_binfo(t_pvtuner *x);
+
+void *pvtuner_new(t_symbol *s, int argc, t_atom *argv)
+{
+#if MSP
+ t_pvtuner *x = (t_pvtuner *)newobject(pvtuner_class);
+ dsp_setup((t_pxobject *)x,3);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+#if PD
+ t_pvtuner *x = (t_pvtuner *)pd_new(pvtuner_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+ x->R = sys_getsr();
+ x->D = sys_getblksize();
+
+ x->lofreq = atom_getfloatarg(0, argc, argv);
+ x->hifreq = atom_getfloatarg(1, argc, argv);
+ x->overlap = atom_getfloatarg(2, argc, argv);
+ x->winfac = atom_getfloatarg(3, argc, argv);
+
+ if(x->lofreq <= 0 || x->lofreq >= x->R/2)
+ x->lofreq = 0;
+ if(x->hifreq <= 0 || x->hifreq > x->R/2)
+ x->hifreq = 4000.0;
+
+
+ pvtuner_init(x,0);
+
+ return (x);
+}
+
+void pvtuner_init(t_pvtuner *x,short initialized)
+{
+ int i, j;
+ int mem;
+ float curfreq;
+
+ if(!x->R)//temp init if MSP functions returned zero
+ x->R = 44100;
+ if(!x->D)
+ x->D = 256;
+
+ if(!power_of_two(x->overlap))
+ x->overlap = 4;
+ if(!power_of_two(x->winfac))
+ x->winfac = 2;
+
+ x->Iinv = 1./x->D;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+ x->c_fundamental = (float) x->R/(float)( (x->N2)<<1 );
+ x->c_factor_in = (float) x->R/((float)x->D * TWOPI);
+ x->c_factor_out = TWOPI * (float) x->D / (float) x->R;
+
+ if(!initialized){
+ x->P = 1.0 ; // default
+ x->bypass_state = 0;
+ x->mute = 0;
+ x->L = 8192;
+ x->synt = .000001;
+ mem = (MAX_Nw)*sizeof(float);
+ x->Wanal = (float *) getbytes(mem);
+ x->Wsyn = (float *) getbytes(mem);
+ x->Hwin = (float *) getbytes(mem);
+ x->input = (float *) getbytes(mem);
+ x->output = (float *) getbytes(mem);
+ mem = (MAX_N)*sizeof(float);
+ x->buffer = (float *) getbytes(mem);
+ mem = (MAX_N+2)*sizeof(float);
+ x->channel = (float *) getbytes(mem);
+ mem = (MAX_N*2)*sizeof(int);
+ x->bitshuffle = (int *) getbytes(mem);
+ mem = (MAX_N*2)*sizeof(float);
+ x->trigland = (float *) getbytes(mem);
+ mem = (MAXTONES+1)*sizeof(float);
+ x->pitchgrid = (float *) getbytes(mem);
+ mem = (MAX_N+1)*sizeof(float);
+ x->lastamp = (float *) getbytes(mem);
+ x->lastfreq = (float *) getbytes(mem);
+ x->bindex = (float *) getbytes(mem);
+ mem = (x->L)*sizeof(float);
+ x->table = (float *) getbytes(mem);
+ mem = (MAX_N2+1)*sizeof(float);
+ x->c_lastphase_in = (float *) getbytes(mem);
+ x->c_lastphase_out = (float *)getbytes(mem);
+
+ x->pbase = BASE_FREQ;
+ pvtuner_diatonic(x);// default scale
+ }
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ memset((char *)x->lastamp,0,(x->N+1) * sizeof(float));
+ memset((char *)x->lastfreq,0,(x->N+1) * sizeof(float));
+ memset((char *)x->bindex,0,(x->N+1) * sizeof(float));
+ memset((char *)x->c_lastphase_in,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->c_lastphase_out,0,(x->N2+1) * sizeof(float));
+
+ for ( i = 0; i < x->L; i++ ) {
+ x->table[i] = (float) x->N * cos((float)i * TWOPI / (float)x->L);
+ }
+
+ if( x->hifreq < x->c_fundamental ) {
+ x->hifreq = 3000.0 ;
+ }
+
+ x->hi_bin = 1;
+ x->curfreq = 0;
+
+ while( x->curfreq < x->hifreq ) {
+ ++(x->hi_bin);
+ x->curfreq += x->c_fundamental ;
+ }
+
+ x->lo_bin = 0;
+ x->curfreq = 0;
+ while( x->curfreq < x->lofreq ) {
+ ++(x->lo_bin);
+ x->curfreq += x->c_fundamental ;
+ }
+
+ if( x->hi_bin >= x->N2 )
+ x->hi_bin = x->N2 - 1;
+
+ x->hi_tune_bin = x->hi_bin;
+ x->myPInc = x->P*x->L/x->R;
+ x->ffac = x->P * PI/x->N;
+
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makehanning( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 0);
+
+}
+
+void pvtuner_toptune(t_pvtuner *x, t_floatarg f)
+{
+ int tbin;
+ float curfreq;
+ float fundamental = x->c_fundamental;
+ tbin = 1;
+ curfreq = 0;
+
+ if( f < 0 || f > x->R / 2.0 ){
+ error("frequency %f out of range", f);
+ return;
+ }
+
+ while( curfreq < f ) {
+ ++tbin;
+ curfreq += fundamental ;
+ }
+
+ if( tbin > x->lo_bin && tbin <= x->hi_bin ){
+ x->hi_tune_bin = tbin;
+ } else {
+ error("bin %d out of range", tbin);
+ }
+
+}
+
+void pvtuner_topfreq(t_pvtuner *x, t_floatarg f)
+{
+ int tbin;
+ float curfreq;
+ float fundamental = x->c_fundamental;
+ tbin = 1;
+ curfreq = 0;
+
+ if( f < 0 || f > x->R / 2.0 ){
+ error("frequency %f out of range", f);
+ return;
+ }
+
+ while( curfreq < f ) {
+ ++tbin;
+ curfreq += fundamental ;
+ }
+
+ if( tbin > x->lo_bin && tbin < x->N2 - 1 ){
+ x->hi_bin = tbin;
+ } else {
+ error("bin %d out of range", tbin);
+ }
+
+}
+
+void pvtuner_list (t_pvtuner *x, t_symbol *msg, short argc, t_atom *argv)
+{
+ float val;
+ float *pitchgrid = x->pitchgrid;
+
+
+ int i = 0;
+
+ if( ! atom_getfloatarg(i,argc,argv) ){
+ error("either zero length scale or 0.0 (prohibited) is first value");
+ return;
+ }
+ /* first set every value to maximum */
+ for(i=0; i < MAXTONES; i++){
+ pitchgrid[i] = (float)x->R / 2.0;
+
+ }
+ for( i = 0; i < argc; i++ ){
+ pitchgrid[ i ] = atom_getfloatarg(i,argc,argv) ;
+ }
+
+ x->scale_len = i;
+ // post("list scale is length %d", i);
+ x->current_scale = IMPORTED_SCALE;
+}
+
+void pvtuner_import_scale(t_pvtuner *x, t_symbol *filename) // seems to be broken now
+{
+ FILE *fp;
+ float val;
+ float *pitchgrid = x->pitchgrid;
+ int scale_len = x->scale_len;
+
+
+ if( ! (fp = fopen( filename->s_name, "r")) ){
+ error("could not open file %s", filename);
+ return;
+ }
+ scale_len = 0;
+ while( ( (fscanf(fp, "%f", &val)) != EOF) && (scale_len < MAXTONES) ){
+ pitchgrid[ scale_len++ ] = val;
+ }
+ fclose( fp );
+ x->scale_len = scale_len;
+ x->current_scale = IMPORTED_SCALE;
+ // post("read %s", filename->s_name);
+}
+
+void pvtuner_binfo(t_pvtuner *x)
+{
+ post("%s: frequency targets: %f %f", OBJECT_NAME, x->lofreq, x->hifreq);
+ post("synthesizing %d bins, from %d to %d",(x->hi_bin - x->lo_bin), x->lo_bin, x->hi_bin);
+}
+
+void pvtuner_frequency_range(t_pvtuner *x, t_floatarg lo, t_floatarg hi)
+{
+ x->lofreq = lo ;
+ x->hifreq = hi;
+
+
+ if( lo >= hi ){
+ error("low frequency must be lower than high frequency");
+ return;
+ }
+ x->curfreq = 0;
+ x->hi_bin = 0;
+
+ while( x->curfreq < x->hifreq ) {
+ ++(x->hi_bin);
+ x->curfreq += x->c_fundamental ;
+ }
+
+
+ x->curfreq = 0;
+ x->lo_bin = 0;
+ while( x->curfreq < x->lofreq ) {
+ ++(x->lo_bin);
+ x->curfreq += x->c_fundamental ;
+ }
+
+}
+
+
+t_int *pvtuner_perform(t_int *w)
+{
+ int i,j, in,on;
+ int amp,freq,chan;
+
+ float a,ainc,f,finc,address;
+ int breaker = 0;
+ t_pvtuner *x = (t_pvtuner *) (w[1]);
+
+ t_float *inbuf = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *in3 = (t_float *)(w[4]);
+ t_float *outbuf = (t_float *)(w[5]);
+ int n = (int)(w[6]);
+
+ int D = x->D;
+ int I = D;
+ int R = x->R;
+ int Nw = x->Nw;
+ int N = x->N ;
+ int N2 = x-> N2;
+ int Nw2 = x->Nw2;
+ float fundamental = x->c_fundamental;
+ float factor_in = x->c_factor_in;
+ float factor_out = x->c_factor_out;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland;
+ float mult = x->mult;
+ float synt = x->synt;
+ float P = x->P; // myPItchfac
+ float Iinv = x->Iinv;
+ float myPInc = x->myPInc;
+ int L = x->L;
+
+ /* assign pointers */
+ float *table = x->table;
+ float *lastamp = x->lastamp ;
+ float *lastfreq = x->lastfreq ;
+ float *bindex = x->bindex;
+ float *lastphase_in = x->c_lastphase_in;
+ float *lastphase_out = x->c_lastphase_out;
+
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *input = x->input;
+ float *Hwin = x->Hwin;
+ float *buffer = x->buffer;
+ float *channel = x->channel;
+ float *output = x->output;
+ float *pitchgrid = x->pitchgrid;
+ int hi_bin = x->hi_bin;
+ int lo_bin = x->lo_bin;
+ int hi_tune_bin = x->hi_tune_bin;
+ int inCount = x->inCount;
+
+ in = on = x->inCount ;
+
+ if( x->pitch_connected ) {
+ x->P = *in2++ ; // myPItchfac
+ x->myPInc = x->P*(float)x->L/(float)x->R;
+ }
+ if ( x->synt_connected ) {
+ synt = *in3++ ;
+ }
+
+
+ if (x->bypass_state) { // just send through
+ for( j = 0; j < D; j++ ) {
+ *outbuf++ = *inbuf++;
+ }
+ return (w+7);
+ }
+
+ if (x->mute) {
+ for( j = 0; j < D; j++ ) {
+ *outbuf++ = 0.0;
+ }
+ return (w+7);
+ }
+
+
+ inCount += D;
+
+ for ( j = 0 ; j < (Nw - D) ; j++ ){
+ input[j] = input[j+D];
+ }
+ for ( j = (Nw-D), i = 0 ; j < Nw; j++, i++ ) {
+ input[j] = *inbuf++;
+ }
+
+ fold( input, Wanal, Nw, buffer, N, inCount );
+ rdft( N, 1, buffer, bitshuffle, trigland );
+ convert( buffer, channel, N2, lastphase_in, fundamental, factor_in );
+
+ // start osc bank
+
+ for ( chan = lo_bin; chan < hi_bin; chan++ ) {
+
+ freq = ( amp = ( chan << 1 ) ) + 1;
+ if ( channel[amp] < synt ){
+ breaker = 1;
+ }
+ if( breaker ) {
+ breaker = 0 ;
+ } else {
+ if(chan <= hi_tune_bin){
+ channel[freq] = closestf(channel[freq], pitchgrid);
+ }
+ channel[freq] *= myPInc;
+ finc = ( channel[freq] - ( f = lastfreq[chan] ) )*Iinv;
+ ainc = ( channel[amp] - ( a = lastamp[chan] ) )*Iinv;
+ address = bindex[chan];
+ for ( n = 0; n < I; n++ ) {
+ output[n] += a*table[ (int) address ];
+
+ address += f;
+ while ( address >= L )
+ address -= L;
+ while ( address < 0 )
+ address += L;
+ a += ainc;
+ f += finc;
+ }
+ lastfreq[chan] = channel[freq];
+ lastamp[chan] = channel[amp];
+ bindex[chan] = address;
+ }
+ }
+
+ for ( j = 0; j < D; j++ ){
+ *outbuf++ = output[j] * mult;
+ }
+ for ( j = 0; j < Nw - D; j++ ){
+ output[j] = output[j+D];
+ }
+
+ for ( j = Nw - D; j < Nw; j++ ){
+ output[j] = 0.;
+ }
+
+ x->inCount = inCount % Nw;
+
+ return (w+7);
+}
+
+
+void pvtuner_basefreq( t_pvtuner *x, t_floatarg bassfreq)
+{
+ if( bassfreq < 10. )
+ bassfreq = 10. ;
+ if( bassfreq > 10000. )
+ bassfreq = 10000.;
+ x->pbase = bassfreq;
+ if( x->current_scale == IMPORTED_SCALE ){
+ pvtuner_update_imported( x );
+ }
+ else if( x->current_scale == DIATONIC ){
+ pvtuner_diatonic( x );
+ }
+ else if( x->current_scale == EASTERN) {
+ pvtuner_eastern( x );
+ }
+ else if( x->current_scale == MINOR) {
+ pvtuner_minor( x );
+ }
+ else if( x->current_scale == EQ12) {
+ pvtuner_eq12( x );
+ }
+ else if( x->current_scale == PENTATONIC) {
+ pvtuner_pentatonic( x );
+ }
+ else if( x->current_scale == MAJOR_ADDED_SIXTH) {
+ pvtuner_major_added_sixth( x );
+ }
+ else if( x->current_scale == MINOR_ADDED_SIXTH) {
+ pvtuner_minor_added_sixth( x );
+ }
+ else if( x->current_scale == MAJOR_SEVENTH_CHORD) {
+ pvtuner_major_seventh_chord( x );
+ }
+ else if( x->current_scale == MINOR_SEVENTH_CHORD) {
+ pvtuner_minor_seventh_chord( x );
+ }
+ else if( x->current_scale == DOMINANT_SEVENTH_CHORD) {
+ pvtuner_dominant_seventh_chord( x );
+ }
+ else if( x->current_scale == EQ8) {
+ pvtuner_eq8( x );
+ }
+ else if( x->current_scale == PENTACLUST) {
+ pvtuner_pentaclust( x );
+ }
+ else if( x->current_scale == QUARTERCLUST ) {
+ pvtuner_quarterclust( x );
+ }
+ else if( x->current_scale == EQ5 ) {
+ pvtuner_eq5( x );
+ }
+ else if( x->current_scale == SLENDRO ) {
+ pvtuner_slendro( x );
+ }
+ else if( x->current_scale == PELOG ) {
+ pvtuner_pelog( x );
+ }
+ else {
+ post("unknown scale");
+ }
+}
+
+void pvtuner_free(t_pvtuner *x)
+{
+#if MSP
+ dsp_free( (t_pxobject *) x);
+#endif
+ freebytes(x->c_lastphase_in,0);
+ freebytes(x->c_lastphase_out,0);
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->input,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->buffer,0);
+ freebytes(x->channel,0);
+ freebytes(x->output,0);
+ freebytes(x->lastamp,0);
+ freebytes(x->lastfreq,0);
+ freebytes(x->bindex,0);
+ freebytes(x->table,0);
+ freebytes(x->pitchgrid,0);
+}
+
+#if MSP
+void pvtuner_assist (t_pvtuner *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==ASSIST_INLET) {
+ switch (arg) {
+ case 0:
+ sprintf(dst,"(signal) Input");
+ break;
+ case 1:
+ sprintf(dst,"(signal/float) Pitch Modification Factor");
+ break;
+ case 2:
+ sprintf(dst,"(signal/float) Synthesis Threshold");
+ break;
+ }
+ } else if (msg==ASSIST_OUTLET) {
+ sprintf(dst,"(signal) Output");
+ }
+}
+#endif
+
+#if PD
+void pvtuner_assist (t_pvtuner *x, void *b, long msg, long arg, char *dst)
+{
+ post("INLETS: input pitch_factor synthesis_threshold");
+ post("ARGUMENTS: lo_freq hi_freq");
+}
+#endif
+
+
+void pvtuner_update_imported( t_pvtuner *x ){
+ float *pitchgrid = x->pitchgrid;
+ float factor = x->pbase / pitchgrid[0];
+ int i;
+ for( i = 0; i < x->scale_len; i++ )
+ pitchgrid[i] *= factor;
+}
+
+void pvtuner_diatonic( t_pvtuner *x ){
+ int i, j;
+ // post("calling diatonic for vs %d",x->vs);
+ x->pitchgrid[0] = x->pbase;
+ x->pitchgrid[1] = x->pbase * (9./8.);
+ x->pitchgrid[2] = x->pbase * (5./4.);
+ x->pitchgrid[3] = x->pbase * (4./3.);
+ x->pitchgrid[4] = x->pbase * (3./2.);
+ x->pitchgrid[5] = x->pbase * (27./16.);
+ x->pitchgrid[6] = x->pbase * (15./8.);
+ x->scale_steps = 7;
+ for( i = 1; i < 10; i++ ){
+ for( j = 0; j < x->scale_steps; j++ ){
+ x->pitchgrid[ i*x->scale_steps + j] = x->pitchgrid[j] * pow(2.0,(float)i);
+ }
+ }
+ x->current_scale = DIATONIC ;
+}
+
+void pvtuner_minor( t_pvtuner *x ){
+ int i, j;
+ x->pitchgrid[0] = x->pbase;
+ x->pitchgrid[1] = x->pbase * (9./8.);
+ x->pitchgrid[2] = x->pbase * (6./5.);
+ x->pitchgrid[3] = x->pbase * (4./3.);
+ x->pitchgrid[4] = x->pbase * (3./2.);
+ x->pitchgrid[5] = x->pbase * (8./5.);
+ x->pitchgrid[6] = x->pbase * (9./5.);
+ x->scale_steps = 7;
+ for( i = 1; i < 10; i++ ){
+ for( j = 0; j < x->scale_steps; j++ ){
+ x->pitchgrid[ i*x->scale_steps + j] = x->pitchgrid[j] * pow(2.0,(float)i);
+ }
+ }
+ x->current_scale = MINOR ;
+}
+
+void pvtuner_pentatonic( t_pvtuner *x ){
+ int i, j;
+
+ x->pitchgrid[0] = x->pbase;
+ x->pitchgrid[1] = x->pbase * (9./8.);
+ x->pitchgrid[2] = x->pbase * (81./64.);
+ x->pitchgrid[3] = x->pbase * (3./2.);
+ x->pitchgrid[4] = x->pbase * (27./16.);
+ x->scale_steps = 5;
+ for( i = 1; i < 10; i++ ){
+ for( j = 0; j < x->scale_steps; j++ ){
+ x->pitchgrid[ i*x->scale_steps + j] = x->pitchgrid[j] * pow(2.0,(float)i);
+ }
+ }
+ x->current_scale = PENTATONIC ;
+}
+
+void pvtuner_eq12( t_pvtuner *x ){
+ int i, j;
+ float expon;
+ x->pitchgrid[0] = x->pbase;
+ for( i = 0; i < 12; i++ ){
+ expon = (float) i / 12.0 ;
+ x->pitchgrid[i] = x->pbase * pow(2.0,expon);
+ }
+ x->scale_steps = 12;
+ for( i = 1; i < 10; i++ ){
+ for( j = 0; j < x->scale_steps; j++ ){
+ x->pitchgrid[ i*x->scale_steps + j] = x->pitchgrid[j] * pow(2.0,(float)i);
+ }
+ }
+ x->current_scale = EQ12 ;
+}
+
+void pvtuner_major_added_sixth( t_pvtuner *x ){
+ int i, j;
+ float *pitchgrid = x->pitchgrid;
+ float pbase = x->pbase;
+ int scale_steps;
+
+ pitchgrid[0] = pbase;
+ pitchgrid[1] = pbase * 1.259921;
+ pitchgrid[2] = pbase * 1.498307;
+ pitchgrid[3] = pbase * 1.681793;
+ scale_steps = 4 ;
+
+ for( i = 1; i < 10; i++ ){
+ for( j = 0; j < scale_steps; j++ ){
+ pitchgrid[ i * scale_steps + j] = pitchgrid[j] * pow(2.0,(float)i);
+ }
+ }
+ x->current_scale = MAJOR_ADDED_SIXTH;
+ x->scale_steps = scale_steps;
+}
+
+void pvtuner_minor_added_sixth( t_pvtuner *x ){
+ int i, j;
+ float *pitchgrid = x->pitchgrid;
+ float pbase = x->pbase;
+ int scale_steps;
+
+ pitchgrid[0] = pbase;
+ pitchgrid[1] = pbase * 1.189207;
+ pitchgrid[2] = pbase * 1.498307;
+ pitchgrid[3] = pbase * 1.587401;
+ scale_steps = 4 ;
+
+ for( i = 1; i < 10; i++ ){
+ for( j = 0; j < scale_steps; j++ ){
+ pitchgrid[ i * scale_steps + j] = pitchgrid[j] * pow(2.0,(float)i);
+ }
+ }
+ x->current_scale = MINOR_ADDED_SIXTH;
+ x->scale_steps = scale_steps;
+}
+
+void pvtuner_major_seventh_chord( t_pvtuner *x ){
+ int i, j;
+ float *pitchgrid = x->pitchgrid;
+ float pbase = x->pbase;
+ int scale_steps;
+ pitchgrid[0] = pbase;
+ pitchgrid[1] = pbase * 1.25;
+ pitchgrid[2] = pbase * 1.5;
+ pitchgrid[3] = pbase * 1.875;
+ scale_steps = 4 ;
+
+ for( i = 1; i < 10; i++ ){
+ for( j = 0; j < scale_steps; j++ ){
+ pitchgrid[ i * scale_steps + j] = pitchgrid[j] * pow(2.0,(float)i);
+ }
+ }
+ x->current_scale = MAJOR_SEVENTH_CHORD;
+ x->scale_steps = scale_steps;
+}
+
+void pvtuner_minor_seventh_chord( t_pvtuner *x ){
+ int i, j;
+ float *pitchgrid = x->pitchgrid;
+ float pbase = x->pbase;
+ int scale_steps;
+ pitchgrid[0] = pbase;
+ pitchgrid[1] = pbase * 1.2;
+ pitchgrid[2] = pbase * 1.5;
+ pitchgrid[3] = pbase * 1.781797;
+ scale_steps = 4 ;
+
+ for( i = 1; i < 10; i++ ){
+ for( j = 0; j < scale_steps; j++ ){
+ pitchgrid[ i * scale_steps + j] = pitchgrid[j] * pow(2.0,(float)i);
+ }
+ }
+ x->current_scale = MINOR_SEVENTH_CHORD;
+ x->scale_steps = scale_steps;
+}
+
+void pvtuner_dominant_seventh_chord( t_pvtuner *x ){
+ int i, j;
+ float *pitchgrid = x->pitchgrid;
+ float pbase = x->pbase;
+ int scale_steps;
+ pitchgrid[0] = pbase;
+ pitchgrid[1] = pbase * 1.25;
+ pitchgrid[2] = pbase * 1.5;
+ pitchgrid[3] = pbase * 1.781797;
+ scale_steps = 4 ;
+
+ for( i = 1; i < 10; i++ ){
+ for( j = 0; j < scale_steps; j++ ){
+ pitchgrid[ i * scale_steps + j] = pitchgrid[j] * pow(2.0,(float)i);
+ }
+ }
+ x->current_scale = DOMINANT_SEVENTH_CHORD;
+ x->scale_steps = scale_steps;
+}
+
+void pvtuner_eq8( t_pvtuner *x ){
+ int i, j;
+ float *pitchgrid = x->pitchgrid;
+ float pbase = x->pbase;
+ int scale_steps;
+ pitchgrid[0] = pbase;
+ pitchgrid[1] = pbase * 1.090508;
+ pitchgrid[2] = pbase * 1.189207;
+ pitchgrid[3] = pbase * 1.296840;
+ pitchgrid[4] = pbase * 1.414214;
+ pitchgrid[5] = pbase * 1.542211;
+ pitchgrid[6] = pbase * 1.681793;
+ pitchgrid[7] = pbase * 1.834008;
+
+ scale_steps = 8 ;
+
+ for( i = 1; i < 10; i++ ){
+ for( j = 0; j < scale_steps; j++ ){
+ pitchgrid[ i * scale_steps + j] = pitchgrid[j] * pow(2.0,(float)i);
+ }
+ }
+ x->current_scale = EQ8;
+ x->scale_steps = scale_steps;
+}
+
+void pvtuner_pentaclust( t_pvtuner *x ){
+ int i, j;
+ float *pitchgrid = x->pitchgrid;
+ float pbase = x->pbase;
+ int scale_steps;
+ pitchgrid[0] = pbase;
+ pitchgrid[1] = pbase * 1.059463;
+ pitchgrid[2] = pbase * 1.122462;
+ pitchgrid[3] = pbase * 1.189207;
+ pitchgrid[4] = pbase * 1.259921;
+
+ scale_steps = 5 ;
+
+ for( i = 1; i < 10; i++ ){
+ for( j = 0; j < scale_steps; j++ ){
+ pitchgrid[ i * scale_steps + j] = pitchgrid[j] * pow(2.0,(float)i);
+ }
+ }
+ x->current_scale = PENTACLUST;
+ x->scale_steps = scale_steps;
+}
+
+void pvtuner_quarterclust( t_pvtuner *x ){
+ int i, j;
+ float *pitchgrid = x->pitchgrid;
+ float pbase = x->pbase;
+ int scale_steps;
+ pitchgrid[0] = pbase;
+ pitchgrid[1] = pbase * 1.029302;
+ pitchgrid[2] = pbase * 1.059463;
+ pitchgrid[3] = pbase * 1.090508;
+ pitchgrid[4] = pbase * 1.122462;
+ pitchgrid[5] = pbase * 1.155353;
+ pitchgrid[6] = pbase * 1.189207;
+ pitchgrid[7] = pbase * 1.224054;
+
+ scale_steps = 8 ;
+
+ for( i = 1; i < 10; i++ ){
+ for( j = 0; j < scale_steps; j++ ){
+ pitchgrid[ i * scale_steps + j] = pitchgrid[j] * pow(2.0,(float)i);
+ }
+ }
+ x->current_scale = QUARTERCLUST;
+ x->scale_steps = scale_steps;
+}
+
+void pvtuner_eq5( t_pvtuner *x ){
+ int i, j;
+ float *pitchgrid = x->pitchgrid;
+ float pbase = x->pbase;
+ int scale_steps;
+ pitchgrid[0] = pbase;
+ pitchgrid[1] = pbase * 1.148698;
+ pitchgrid[2] = pbase * 1.319508;
+ pitchgrid[3] = pbase * 1.515717;
+ pitchgrid[4] = pbase * 1.741101;
+
+ scale_steps = 5 ;
+
+ for( i = 1; i < 10; i++ ){
+ for( j = 0; j < scale_steps; j++ ){
+ pitchgrid[ i * scale_steps + j] = pitchgrid[j] * pow(2.0,(float)i);
+ }
+ }
+ x->current_scale = EQ5;
+ x->scale_steps = scale_steps;
+}
+
+void pvtuner_pelog( t_pvtuner *x ){
+ int i, j;
+ float *pitchgrid = x->pitchgrid;
+ float pbase = x->pbase;
+ int scale_steps;
+ pitchgrid[0] = pbase;
+ pitchgrid[1] = pbase * 1.152;
+ pitchgrid[2] = pbase * 1.340;
+ pitchgrid[3] = pbase * 1.532;
+ pitchgrid[4] = pbase * 1.756;
+ scale_steps = 5 ;
+
+ for( i = 1; i < 10; i++ ){
+ for( j = 0; j < scale_steps; j++ ){
+ pitchgrid[ i * scale_steps + j] = pitchgrid[j] * pow(2.0,(float)i);
+ }
+ }
+ x->current_scale = PELOG;
+ x->scale_steps = scale_steps;
+}
+
+void pvtuner_slendro( t_pvtuner *x ){
+ int i, j;
+ float *pitchgrid = x->pitchgrid;
+ float pbase = x->pbase;
+ int scale_steps;
+ pitchgrid[0] = pbase;
+ pitchgrid[1] = pbase * 1.104;
+ pitchgrid[2] = pbase * 1.199;
+ pitchgrid[3] = pbase * 1.404;
+ pitchgrid[4] = pbase * 1.514;
+ pitchgrid[5] = pbase * 1.615;
+ pitchgrid[6] = pbase * 1.787;
+ scale_steps = 7 ;
+
+ for( i = 1; i < 10; i++ ){
+ for( j = 0; j < scale_steps; j++ ){
+ pitchgrid[ i * scale_steps + j] = pitchgrid[j] * pow(2.0,(float)i);
+ }
+ }
+ x->current_scale = SLENDRO;
+ x->scale_steps = scale_steps;
+}
+void pvtuner_eastern( t_pvtuner *x ){
+ int i, j;
+
+ x->pitchgrid[0] = x->pbase;
+ x->pitchgrid[1] = x->pbase * 1.059463;
+ x->pitchgrid[2] = x->pbase * 1.259921;
+ x->pitchgrid[3] = x->pbase * 1.334840;
+ x->pitchgrid[4] = x->pbase * 1.498307;
+ x->pitchgrid[5] = x->pbase * 1.587401;
+ x->pitchgrid[6] = x->pbase * 1.887749;
+ x->scale_steps = 7 ;
+
+ for( i = 1; i < 10; i++ ){
+ for( j = 0; j < x->scale_steps; j++ ){
+ x->pitchgrid[ i*x->scale_steps + j] = x->pitchgrid[j] * pow(2.0,(float)i);
+ }
+ }
+ x->current_scale = EASTERN ;
+ // post("eastern scale");
+}
+
+#if MSP
+void pvtuner_float(t_pvtuner *x, double f)
+{
+ // int inlet = ((t_pxobject*)x)->z_in;
+ int inlet = x->x_obj.z_in;
+
+ if (inlet == 1)
+ {
+ x->P = f;
+ x->myPInc = x->P*x->L/x->R;
+ // post("P set to %f",f);
+ }
+ else if (inlet == 2)
+ {
+ x->synt = f;
+ // post("synt set to %f",f);
+ }
+}
+#endif
+
+float closestf(float test, float *arr)
+{
+ int i;
+ i = 0;
+ if( test <= arr[0] ){
+ return arr[0];
+ }
+ while( i < MAXTONES ){
+ if( arr[i] > test ){
+ break;
+ }
+ ++i;
+ }
+ if( i >= MAXTONES - 1) {
+ return arr[MAXTONES - 1];
+ }
+ if( (test - arr[i-1]) > ( arr[i] - test) ) {
+ return arr[i];
+ } else {
+ return arr[i-1];
+ }
+}
+
+
+void pvtuner_bypass(t_pvtuner *x, t_floatarg state)
+{
+ x->bypass_state = state;
+}
+
+
+void pvtuner_mute(t_pvtuner *x, t_floatarg state)
+{
+ x->mute = state;
+ // post("mute: %d", state);
+}
+
+void pvtuner_overlap(t_pvtuner *x, t_floatarg f)
+{
+ int i = (int) f;
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->overlap = i;
+ pvtuner_init(x,1);
+}
+
+void pvtuner_winfac(t_pvtuner *x, t_floatarg f)
+{
+ int i = (int)f;
+
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = i;
+ pvtuner_init(x,2);
+}
+
+void pvtuner_fftinfo(t_pvtuner *x)
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+
+void pvtuner_dsp(t_pvtuner *x, t_signal **sp, short *count)
+{
+#if MSP
+ x->pitch_connected = count[1];
+ x->synt_connected = count[2];
+#endif
+#if PD
+ x->pitch_connected = 1;
+ x->synt_connected = 1;
+#endif
+
+ if(sp[0]->s_n != x->vs || x->R != sp[0]->s_sr ){
+
+ x->D = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ pvtuner_init(x,1);
+
+ }
+ dsp_add(pvtuner_perform, 6, x,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec,
+ sp[0]->s_n);
+}
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&pvtuner_class, (method)pvtuner_new, (method)pvtuner_free,
+ (short)sizeof(t_pvtuner), 0, A_GIMME, 0);
+ addmess((method)pvtuner_dsp, "dsp", A_CANT, 0);
+ addmess((method)pvtuner_assist,"assist",A_CANT,0);
+ addmess((method)pvtuner_bypass,"bypass",A_DEFFLOAT,0);
+ addmess((method)pvtuner_mute,"mute",A_DEFFLOAT,0);
+ addmess((method)pvtuner_basefreq,"basefreq",A_DEFFLOAT,0);
+ addmess((method)pvtuner_diatonic,"diatonic",0);
+ addmess((method)pvtuner_eastern,"eastern",0);
+ addmess((method)pvtuner_minor,"minor",0);
+ addmess((method)pvtuner_eq12,"eq12",0);
+ addmess((method)pvtuner_pentatonic,"pentatonic",0);
+ addmess((method)pvtuner_major_added_sixth,"added_sixth_major",0);
+ addmess((method)pvtuner_minor_added_sixth,"added_sixth_minor",0);
+ addmess((method)pvtuner_major_seventh_chord,"major_seventh_chord",0);
+ addmess((method)pvtuner_minor_seventh_chord,"minor_seventh_chord",0);
+ addmess((method)pvtuner_dominant_seventh_chord,"dominant_seventh_chord",0);
+ addmess((method)pvtuner_eq8,"eq8",0);
+ addmess((method)pvtuner_pentaclust,"pentaclust",0);
+ addmess((method)pvtuner_quarterclust,"quarterclust",0);
+ addmess((method)pvtuner_eq5,"eq5",0);
+ addmess((method)pvtuner_slendro,"slendro",0);
+ addmess((method)pvtuner_pelog,"pelog",0);
+ addmess((method)pvtuner_import_scale,"import_scale",A_DEFSYM,0);
+ addmess((method)pvtuner_list,"list",A_GIMME,0);
+ addmess((method)pvtuner_topfreq,"topfreq",A_DEFFLOAT,0);
+ addmess((method)pvtuner_toptune,"toptune",A_DEFFLOAT,0);
+ addmess((method)pvtuner_frequency_range,"frequency_range",A_FLOAT,A_FLOAT, 0);
+ addmess((method)pvtuner_overlap,"overlap",A_DEFFLOAT,0);
+ addmess((method)pvtuner_winfac,"winfac",A_DEFFLOAT,0);
+ addmess((method)pvtuner_fftinfo,"fftinfo",0);
+ addmess((method)pvtuner_binfo,"binfo",0);
+ addfloat((method)pvtuner_float);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+#if PD
+void pvtuner_tilde_setup(void)
+{
+ pvtuner_class = class_new(gensym("pvtuner~"), (t_newmethod)pvtuner_new,
+ (t_method)pvtuner_free ,sizeof(t_pvtuner), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(pvtuner_class, t_pvtuner, x_f );
+ class_addmethod(pvtuner_class, (t_method)pvtuner_dsp, gensym("dsp"), 0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_mute, gensym("mute"), A_DEFFLOAT,0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_bypass, gensym("bypass"), A_DEFFLOAT,0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_assist, gensym("assist"), 0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_basefreq,gensym("basefreq"),A_DEFFLOAT,0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_frequency_range,gensym("frequency_range"),A_DEFFLOAT,A_DEFFLOAT,0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_diatonic,gensym("diatonic"),0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_eastern,gensym("eastern"),0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_minor,gensym("minor"),0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_eq12,gensym("eq12"),0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_pentatonic,gensym("pentatonic"),0);
+ /* Pd cannot disambiguate */
+ /*
+ class_addmethod(pvtuner_class, (t_method)pvtuner_added_sixth_major,gensym("added_sixth_major"),0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_added_sixth_minor,gensym("added_sixth_minor"),0);
+ */
+ class_addmethod(pvtuner_class, (t_method)pvtuner_major_added_sixth,gensym("major_added_sixth"),0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_minor_added_sixth,gensym("minor_added_sixth"),0);
+
+ class_addmethod(pvtuner_class, (t_method)pvtuner_major_seventh_chord,gensym("major_seventh_chord"),0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_minor_seventh_chord,gensym("minor_seventh_chord"),0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_dominant_seventh_chord,gensym("dominant_seventh_chord"),0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_eq8,gensym("eq8"),0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_pentaclust,gensym("pentaclust"),0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_quarterclust,gensym("quarterclust"),0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_eq5,gensym("eq5"),0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_slendro,gensym("slendro"),0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_pelog,gensym("pelog"),0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_import_scale,gensym("import_scale"),A_DEFSYM,0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_toptune,gensym("toptune"),A_FLOAT, 0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_topfreq,gensym("topfreq"),A_FLOAT, 0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_list,gensym("list"),A_GIMME, 0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_frequency_range,gensym("frequency_range"),A_FLOAT,A_FLOAT, 0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_overlap,gensym("overlap"),A_FLOAT, 0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_winfac,gensym("winfac"),A_FLOAT, 0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_fftinfo,gensym("fftinfo"), 0);
+ class_addmethod(pvtuner_class, (t_method)pvtuner_binfo,gensym("binfo"), 0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
diff --git a/pvwarp~.c b/pvwarp~.c
new file mode 100644
index 0000000..63a97db
--- /dev/null
+++ b/pvwarp~.c
@@ -0,0 +1 @@
+#include "MSPd.h" #include "fftease.h" #if MSP void *pvwarp_class; #endif #if PD static t_class *pvwarp_class; #endif #define OBJECT_NAME "pvwarp~" typedef struct _pvwarp { #if MSP t_pxobject x_obj; #endif #if PD t_object x_obj; float x_f; #endif int R; int N; int N2; int Nw; int Nw2; int D; int i; int inCount; float *Wanal; float *Wsyn; float *input; float *Hwin; float *buffer; float *channel; float *output; // for convert float *c_lastphase_in; float *c_lastphase_out; float c_fundamental; float c_factor_in; float c_factor_out; float P; int L; int first; float Iinv; float *lastamp; float *lastfreq; float *windex; float *table; float myPInc; float ffac; // int lo_bin; int hi_bin; float lofreq;//user speficied lowest synthfreq float hifreq;// user specified highest synthfreq float topfreq; float synt; float myPI; float TWOmyPI; // for fast fft float mult; float *trigland; int *bitshuffle; // short *connections; short mute; short bypass; int pitch_connected; int synt_connected; float *warpfunc ; short please_update; short always_update; float cf1; float bw1; float warpfac1; float cf2; float bw2; float warpfac2; int funcoff; short verbose; short automate; int overlap;//overlap factor int winfac;// window factor int vs;//last measurement of vector size } t_pvwarp; void *pvwarp_new(t_symbol *s, int argc, t_atom *argv); //t_int *offset_perform(t_int *w); t_int *pvwarp_perform(t_int *w); void pvwarp_dsp(t_pvwarp *x, t_signal **sp, short *count); void pvwarp_assist(t_pvwarp *x, void *b, long m, long a, char *s); void pvwarp_bypass(t_pvwarp *x, t_floatarg state); void pvwarp_mute(t_pvwarp *x, t_floatarg state); void pvwarp_verbose(t_pvwarp *x, t_floatarg state); void pvwarp_overlap(t_pvwarp *x, t_floatarg o); void pvwarp_automate(t_pvwarp *x, t_floatarg state); void pvwarp_autofunc(t_pvwarp *x, t_floatarg minval, t_floatarg maxval); void pvwarp_float(t_pvwarp *x, t_float f); void pvwarp_dsp_free( t_pvwarp *x ); void pvwarp_fftinfo( t_pvwarp *x ); float myrand( float min, float max ); float closestf(float test, float *arr) ; int freq_to_bin( float target, float fundamental ); void update_warp_function( t_pvwarp *x ) ; void pvwarp_init(t_pvwarp *x, short initialized); void pvwarp_bottomfreq(t_pvwarp *x, t_floatarg f); void pvwarp_topfreq(t_pvwarp *x, t_floatarg f); void pvwarp_fftinfo(t_pvwarp *x); void pvwarp_overlap(t_pvwarp *x, t_floatarg f); void pvwarp_winfac(t_pvwarp *x, t_floatarg f);; #if MSP void main(void) { setup((t_messlist **)&pvwarp_class, (method)pvwarp_new, (method)pvwarp_dsp_free, (short)sizeof(t_pvwarp), 0, A_GIMME, 0); addmess((method)pvwarp_dsp, "dsp", A_CANT, 0); addmess((method)pvwarp_assist,"assist",A_CANT,0); addmess((method)pvwarp_bypass,"bypass",A_DEFFLOAT,0); addmess((method)pvwarp_mute,"mute",A_DEFFLOAT,0); addmess((method)pvwarp_verbose,"verbose",A_DEFFLOAT,0); addmess((method)pvwarp_overlap,"overlap",A_FLOAT,0); addmess((method)pvwarp_bottomfreq,"bottomfreq",A_FLOAT,0); addmess((method)pvwarp_topfreq,"topfreq",A_FLOAT,0); addmess((method)pvwarp_fftinfo,"fftinfo",0); addmess((method)pvwarp_autofunc,"autofunc",A_DEFFLOAT, A_DEFFLOAT,0); addmess((method)pvwarp_overlap,"overlap",A_DEFFLOAT,0); addmess((method)pvwarp_winfac,"winfac",A_DEFFLOAT,0); addmess((method)pvwarp_fftinfo,"fftinfo",0); addfloat((method)pvwarp_float); dsp_initclass(); post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT); } #endif #if PD /* Pd Initialization */ void pvwarp_tilde_setup(void) { pvwarp_class = class_new(gensym("pvwarp~"), (t_newmethod)pvwarp_new, (t_method)pvwarp_dsp_free ,sizeof(t_pvwarp), 0,A_GIMME,0); CLASS_MAINSIGNALIN(pvwarp_class, t_pvwarp, x_f); class_addmethod(pvwarp_class, (t_method)pvwarp_dsp, gensym("dsp"), 0); class_addmethod(pvwarp_class, (t_method)pvwarp_mute, gensym("mute"), A_DEFFLOAT,0); class_addmethod(pvwarp_class, (t_method)pvwarp_bypass, gensym("bypass"), A_DEFFLOAT,0); class_addmethod(pvwarp_class, (t_method)pvwarp_overlap, gensym("overlap"), A_DEFFLOAT,0); class_addmethod(pvwarp_class, (t_method)pvwarp_bottomfreq, gensym("bottomfreq"), A_DEFFLOAT,0); class_addmethod(pvwarp_class, (t_method)pvwarp_topfreq, gensym("topfreq"), A_DEFFLOAT, 0); class_addmethod(pvwarp_class, (t_method)pvwarp_automate, gensym("automate"), A_DEFFLOAT, 0); class_addmethod(pvwarp_class, (t_method)pvwarp_autofunc, gensym("autofunc"), A_DEFFLOAT,A_DEFFLOAT,0); class_addmethod(pvwarp_class,(t_method)pvwarp_overlap,gensym("overlap"),A_FLOAT,0); class_addmethod(pvwarp_class,(t_method)pvwarp_winfac,gensym("winfac"),A_FLOAT,0); class_addmethod(pvwarp_class,(t_method)pvwarp_fftinfo,gensym("fftinfo"),0); // addfloat((method)pvwarp_float); post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT); } #endif void pvwarp_automate(t_pvwarp *x, t_floatarg state) { x->automate = state; } void pvwarp_overlap(t_pvwarp *x, t_floatarg f) { int i = (int) f; if(!power_of_two(i)){ error("%f is not a power of two",f); return; } x->overlap = i; pvwarp_init(x,1); } void pvwarp_winfac(t_pvwarp *x, t_floatarg f) { int i = (int)f; if(!power_of_two(i)){ error("%f is not a power of two",f); return; } x->winfac = i; pvwarp_init(x,2); } void pvwarp_fftinfo(t_pvwarp *x) { if( ! x->overlap ){ post("zero overlap!"); return; } post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw); } float myrand ( float min, float max ) { return (min + (max-min) * ((float) (rand() % 32768) / (float) 32768.0)); } void update_warp_function( t_pvwarp *x ) { int i,j; int N2 = x->N2; float *warpfunc = x->warpfunc; float warpfac1 = x->warpfac1; float warpfac2 = x->warpfac2; float cf1 = x->cf1; float cf2 = x->cf2; float bw1 = x->bw1; float bw2 = x->bw2; float c_fundamental = x->c_fundamental; float deviation; float diff; int midbin, lobin, hibin ; float hif, lof; int bin_extent; short verbose = x->verbose; for( i = 0; i < N2; i++ ){ warpfunc[i] = 1.0; } hif = cf1 * (1. + bw1); lof = cf1 * (1. - bw1); midbin = freq_to_bin( cf1, c_fundamental ); hibin = freq_to_bin( hif, c_fundamental ); lobin = freq_to_bin( lof, c_fundamental ); if( hibin >= N2 - 1 ){ hibin = N2 - 1; } if( lobin < 0 ){ lobin = 0; } if( verbose ) post("bump1: hi %d mid %d lo %d",hibin,midbin,lobin); warpfunc[midbin] = warpfac1; diff = warpfac1 - 1.0 ; bin_extent = hibin - midbin ; for( i = midbin, j = 0; i < hibin; i++, j++ ){ deviation = diff * ((float)(bin_extent - j) / (float) bin_extent ); warpfunc[ i ] += deviation ; } bin_extent = midbin - lobin ; for( i = midbin, j = 0; i > lobin; i--, j++ ){ deviation = diff * ((float)(bin_extent - j) / (float) bin_extent ); warpfunc[ i ] += deviation ; } // NOW DO SECOND BUMP hif = cf2 * (1. + bw2); lof = cf2 * (1. - bw2); midbin = freq_to_bin( cf2, c_fundamental ); hibin = freq_to_bin( hif, c_fundamental ); lobin = freq_to_bin( lof, c_fundamental ); if( hibin >= N2 - 1 ){ hibin = N2 - 1; } if( lobin < 0 ){ lobin = 0; } if( verbose ) post("bump2: hi %d mid %d lo %d",hibin,midbin,lobin); warpfunc[midbin] = warpfac2; diff = warpfac2 - 1.0 ; bin_extent = hibin - midbin ; for( i = midbin, j = 0; i < hibin; i++, j++ ){ deviation = diff * ((float)(bin_extent - j) / (float) bin_extent ); warpfunc[ i ] += deviation ; } bin_extent = midbin - lobin ; for( i = midbin, j = 0; i > lobin; i--, j++ ){ deviation = diff * ((float)(bin_extent - j) / (float) bin_extent ); warpfunc[ i ] += deviation ; } x->please_update = 0; // return( x ); } void pvwarp_verbose(t_pvwarp *x, t_floatarg state) { x->verbose = state; } void pvwarp_autofunc(t_pvwarp *x, t_floatarg minval, t_floatarg maxval) { int minpoints, maxpoints, segpoints, i; int pointcount = 0; float target, lastval; float m1, m2; int N2 = x->N2; float *warpfunc = x->warpfunc; ///// minpoints = 0.05 * (float) N2; maxpoints = 0.25 * (float) N2; if( minval > 1000.0 || minval < .001 ){ minval = 0.5; } if( maxval < 0.01 || maxval > 1000.0 ){ minval = 2.0; } lastval = myrand(minval, maxval); // post("automate: min %d max %d",minpoints, maxpoints); while( pointcount < N2 ){ target = myrand(minval, maxval); segpoints = minpoints + (rand() % (maxpoints-minpoints)); if( pointcount + segpoints > N2 ){ segpoints = N2 - pointcount; } for( i = 0; i < segpoints; i++ ){ m2 = (float)i / (float) segpoints ; m1 = 1.0 - m2; warpfunc[ pointcount + i ] = m1 * lastval + m2 * target; } lastval = target; pointcount += segpoints; } } void pvwarp_bypass(t_pvwarp *x, t_floatarg state) { x->bypass = state; } void pvwarp_mute(t_pvwarp *x, t_floatarg state) { x->mute = state; } void pvwarp_dsp_free( t_pvwarp *x ){ #if MSP dsp_free( (t_pxobject *) x); #endif free(x->c_lastphase_in); free(x->c_lastphase_out); free(x->trigland); free(x->bitshuffle); free(x->Wanal); free(x->Wsyn); free(x->input); free(x->Hwin); free(x->buffer); free(x->channel); free(x->output); free(x->lastamp); free(x->lastfreq); free(x->windex); free(x->table); free(x->warpfunc); free(x->connections); } void pvwarp_assist (t_pvwarp *x, void *b, long msg, long arg, char *dst) { if (msg==1) { switch (arg) { case 0: sprintf(dst,"(signal) Input "); break; case 1: sprintf(dst,"(signal/float) Center Frequency 1"); break; case 2: sprintf(dst,"(signal/float) Bandwidth Factor 1"); break; case 3: sprintf(dst,"(signal/float) Warp Factor 1"); break; case 4: sprintf(dst,"(signal/float) Center Frequency 2"); break; case 5: sprintf(dst,"(signal/float) Bandwidth Factor 2"); break; case 6: sprintf(dst,"(signal/float) Warp Factor 2"); break; case 7: sprintf(dst,"(signal/float) Function Offset (0.0-1.0) "); break; case 8: sprintf(dst,"(signal/float) Pitch Factor"); break; case 9: sprintf(dst,"(signal/float) Synthesis Gate Value"); break; } } else if (msg==2) { sprintf(dst,"(signal) Output"); } } void *pvwarp_new(t_symbol *s, int argc, t_atom *argv) { #if MSP t_pvwarp *x = (t_pvwarp *)newobject(pvwarp_class); dsp_setup((t_pxobject *)x,10); outlet_new((t_pxobject *)x, "signal"); #endif #if PD int i; t_pvwarp *x = (t_pvwarp *)pd_new(pvwarp_class); for(i=0;i<9;i++) inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal")); outlet_new(&x->x_obj, gensym("signal")); #endif x->lofreq = atom_getfloatarg(0,argc,argv); x->hifreq = atom_getfloatarg(1,argc,argv); x->overlap = atom_getfloatarg(2,argc,argv); x->winfac = atom_getfloatarg(3,argc,argv); if(!x->overlap) x->overlap = 4; if(!x->winfac) x->winfac = 2; x->D = sys_getblksize(); x->R = sys_getsr(); pvwarp_init(x,0); return (x); } void pvwarp_init(t_pvwarp *x, short initialized) { int i, j; float funda, curfreq; x->N = x->D * x->overlap; x->Nw = x->N * x->winfac; limit_fftsize(&x->N,&x->Nw,OBJECT_NAME); x->N2 = (x->N)>>1; x->Nw2 = (x->Nw)>>1; x->c_fundamental = (float) x->R/(float)( (x->N2)<<1 ); x->c_factor_in = (float) x->R/((float)x->D * TWOPI); x->c_factor_out = TWOPI * (float) x->D / (float) x->R; x->inCount = -(x->Nw); x->mult = 1. / (float) x->N; x->Iinv = 1./x->D; x->myPInc = x->P*x->L/x->R;// really needed x->ffac = x->P * PI/x->N; if(!initialized){ srand(clock()); x->L = 8192; x->P = 1.0 ; //initialization only x->please_update = 0; x->verbose = 0; x->bypass = 0; x->mute = 0; x->topfreq = 3000. ; x->always_update = 0; x->automate = 0; x->warpfac1 = 1.0; x->warpfac2 = 1.0; x->funcoff = 0; x->cf1 = 500.; x->cf2 = 3000.; x->bw1 = 0.2; x->bw2 = 0.2; x->synt = .000001; x->connections = (short *) calloc(16, sizeof(short)); x->Wanal = (float *) calloc(MAX_Nw, sizeof(float)); x->Wsyn = (float *) calloc(MAX_Nw, sizeof(float)); x->input = (float *) calloc(MAX_Nw, sizeof(float)); x->Hwin = (float *) calloc(MAX_Nw, sizeof(float)); x->buffer = (float *) calloc(MAX_N, sizeof(float)); x->channel = (float *) calloc(MAX_N+2, sizeof(float)); x->output = (float *) calloc(MAX_Nw, sizeof(float)); x->bitshuffle = (int *) calloc(MAX_N * 2, sizeof(int)); x->trigland = (float *) calloc(MAX_N * 2, sizeof(float)); x->warpfunc = (float *) calloc(MAX_N2, sizeof(float)); x->lastamp = (float *) calloc(MAX_N+1, sizeof(float)); x->lastfreq = (float *) calloc(MAX_N+1, sizeof(float)); x->windex = (float *) calloc(MAX_N+1, sizeof(float)); x->table = (float *) calloc(x->L, sizeof(float)); x->c_lastphase_in = (float *) calloc(MAX_N2+1, sizeof(float)); x->c_lastphase_out = (float *) calloc(MAX_N2+1, sizeof(float)); } for (i = 0; i < x->L; i++) { x->table[i] = (float) x->N * cos((float)i * TWOPI / (float)x->L); } memset((char *)x->input,0,x->Nw * sizeof(float)); memset((char *)x->output,0,x->Nw * sizeof(float)); memset((char *)x->buffer,0,x->N * sizeof(float)); memset((char *)x->channel,0,(x->N+2) * sizeof(float)); memset((char *)x->lastfreq,0,(x->N+1) * sizeof(float)); memset((char *)x->lastamp,0,(x->N+1) * sizeof(float)); // added memset((char *)x->c_lastphase_in,0,(x->N2+1) * sizeof(float)); memset((char *)x->c_lastphase_out,0,(x->N2+1) * sizeof(float)); memset((char *)x->windex,0,(x->N+1) * sizeof(float)); if( x->hifreq < x->c_fundamental ) { x->hifreq = 1000.0;// arbitrary } x->hi_bin = 1; curfreq = 0; while( curfreq < x->hifreq ) { ++(x->hi_bin); curfreq += x->c_fundamental ; } if( x->hi_bin >= x->N2 ) x->hi_bin = x->N2 - 1; x->lo_bin = 0; curfreq = 0; while( curfreq < x->lofreq ) { ++(x->lo_bin); curfreq += x->c_fundamental ; } update_warp_function(x); init_rdft(x->N, x->bitshuffle, x->trigland); makehanning(x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 0); // post("FFT size: %d",x->N); } void pvwarp_bottomfreq(t_pvwarp *x, t_floatarg f) { int tbin; float curfreq; float fundamental = x->c_fundamental; tbin = 1; curfreq = 0; if( f < 0 || f > x->R / 2.0 ){ error("frequency %f out of range", f); return; } while( curfreq < f ) { ++tbin; curfreq += fundamental ; } if( tbin < x->hi_bin && tbin >= 0 ){ x->lo_bin = tbin; x->lofreq = f; } else { error("bin %d out of range", tbin); } } void pvwarp_topfreq(t_pvwarp *x, t_floatarg f) { int tbin; float curfreq; float fundamental = x->c_fundamental; tbin = 1; curfreq = 0; if( f < 0 || f > x->R / 2.0 ){ error("frequency %f out of range", f); return; } while( curfreq < f ) { ++tbin; curfreq += fundamental ; } if( tbin > x->lo_bin && tbin < x->N2 - 1 ){ x->hi_bin = tbin; x->hifreq = f; } else { error("bin %d out of range", tbin); } } t_int *pvwarp_perform(t_int *w) { int i,j, in,on; int amp,freq,chan,NP,L = 8192; float a,ainc,f,finc,address; int breaker = 0; t_pvwarp *x = (t_pvwarp *) (w[1]); t_float *inbuf = (t_float *)(w[2]); t_float *in1 = (t_float *)(w[3]); t_float *in2 = (t_float *)(w[4]); t_float *in3 = (t_float *)(w[5]); t_float *in4 = (t_float *)(w[6]); t_float *in5 = (t_float *)(w[7]); t_float *in6 = (t_float *)(w[8]); t_float *in7 = (t_float *)(w[9]); t_float *in8 = (t_float *)(w[10]); t_float *in9 = (t_float *)(w[11]); t_float *outbuf = (t_float *)(w[12]); t_int n = w[13]; int D = x->D; int I = D; int R = x->R; int Nw = x->Nw; int N = x->N ; int N2 = x-> N2; int Nw2 = x->Nw2; float fundamental = x->c_fundamental; float factor_in = x->c_factor_in; float factor_out = x->c_factor_out; int *bitshuffle = x->bitshuffle; float *trigland = x->trigland; float mult = x->mult; float warpfac1 = x->warpfac1; float warpfac2 = x->warpfac2; int funcoff; float P; float synt; float Iinv = 1./x->D; float myPInc = x->myPInc; /* assign pointers */ float *table = x->table; float *lastamp = x->lastamp ; float *lastfreq = x->lastfreq ; float *windex = x->windex; float *lastphase_in = x->c_lastphase_in; float *lastphase_out = x->c_lastphase_out; float *Wanal = x->Wanal; float *Wsyn = x->Wsyn; float *input = x->input; float *Hwin = x->Hwin; float *buffer = x->buffer; float *channel = x->channel; float *output = x->output; short *connections = x->connections; float *warpfunc; int hi_bin = x->hi_bin; int lo_bin = x->lo_bin; if(!x->automate) { if( connections[0] ) { x->cf1 = *in1 ; } if ( connections[1] ) { x->bw1 = *in2 ; } if ( connections[2] ) { x->warpfac1 = *in3 ; } if( connections[3] ) { x->cf2 = *in4 ; } if ( connections[4] ) { x->bw2 = *in5 ; } if ( connections[5] ) { x->warpfac2 = *in6 ; } } if( connections[6] ) { f = *in7 ; if( f < 0 ) { f = 0.0; } else if (f > 1.0 ){ f = 1.0; } x->funcoff = f * (float) (N2 - 1); } if ( connections[7] ) { x->P = *in8 ; x->myPInc = x->P*x->L/x->R; } if ( connections[8] ) { x->synt = *in9 ; } P= x->P; synt = x->synt; funcoff = x->funcoff; if( (x->please_update || x->always_update) && ! x->automate){ update_warp_function(x); } warpfunc = x->warpfunc; in = on = x->inCount ; if( x->mute) { for ( j = 0; j < n; j++ ){ outbuf[j] = 0.; } return (w+14); } else if( x->bypass ) { for ( j = 0; j < n; j++ ){ outbuf[j] = *inbuf++; } return (w+14); } else { in = on = x->inCount ; in += D; on += I; for ( j = 0 ; j < (Nw - D) ; j++ ){ input[j] = input[j+D]; } for ( j = (Nw-D), i = 0 ; j < Nw; j++, i++ ) { input[j] = *inbuf++; } fold( input, Wanal, Nw, buffer, N, in ); rdft( N, 1, buffer, bitshuffle, trigland ); convert( buffer, channel, N2, lastphase_in, fundamental, factor_in ); // start osc bank for ( chan = lo_bin; chan < hi_bin; chan++ ) { freq = ( amp = ( chan << 1 ) ) + 1; if ( channel[amp] < synt ){ breaker = 1; } if( breaker ) { breaker = 0 ; } else { /* HERE IS WHERE WE WARP THE SPECTRUM */ channel[freq] *= myPInc * warpfunc[(chan + funcoff) % N2]; finc = ( channel[freq] - ( f = lastfreq[chan] ) )*Iinv; ainc = ( channel[amp] - ( a = lastamp[chan] ) )*Iinv; address = windex[chan]; for ( n = 0; n < I; n++ ) { output[n] += a*table[ (int) address ]; address += f; while ( address >= L ) address -= L; while ( address < 0 ) address += L; a += ainc; f += finc; } lastfreq[chan] = channel[freq]; lastamp[chan] = channel[amp]; windex[chan] = address; } } for ( j = 0; j < D; j++ ){ *outbuf++ = output[j] * mult; } for ( j = 0; j < Nw - D; j++ ){ output[j] = output[j+D]; } for ( j = Nw - D; j < Nw; j++ ){ output[j] = 0.; } /* restore state variables */ x->inCount = in % Nw; return (w+14); } } int freq_to_bin( float target, float fundamental ){ float lastf = 0.0; float testf = 0.0; int thebin = 0; while( testf < target ){ ++thebin; lastf = testf; testf += fundamental; } if(fabs(target - testf) < fabs(target - lastf) ){ return thebin; } else { return (thebin - 1); } } #if MSP void pvwarp_float(t_pvwarp *x, t_float f) // Look at floats at inlets { int inlet = ((t_pxobject*)x)->z_in; int N2 = x->N2; if (inlet == 1){ x->cf1 = f; x->please_update = 1; } else if (inlet == 2) { x->bw1 = f; x->please_update = 1; } else if (inlet == 3) { x->warpfac1 = f; x->please_update = 1; } else if (inlet == 4) { x->cf2 = f; x->please_update = 1; } else if (inlet == 5) { x->bw2 = f; x->please_update = 1; } else if (inlet == 6) { x->warpfac2 = f; x->please_update = 1; } else if (inlet == 7) { if( f < 0 ) { f = 0.0; } else if (f > 1.0 ){ f = 1.0; } x->funcoff = f * (float) (x->N2 - 1); } else if (inlet == 8) { x->P = f; x->myPInc = x->P*x->L/x->R; } else if (inlet == 9) { x->synt = f; } } #endif void pvwarp_dsp(t_pvwarp *x, t_signal **sp, short *count) { long i; x->always_update = 0; #if MSP for( i = 1; i < 10; i++ ){ // only the first 6 inlets alter warp function if( i < 6 ){ x->always_update += count[i]; } x->connections[i-1] = count[i]; // post("connection %d: %d", i-1, count[i]); } #endif #if PD x->always_update = 1; for(i=0;i<10;i++){ x->connections[i] = 1; } #endif if(x->D != sp[0]->s_n || x->R != sp[0]->s_sr){ x->D = sp[0]->s_n; x->R = sp[0]->s_sr; pvwarp_init(x,1); } dsp_add(pvwarp_perform, 13, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[4]->s_vec, sp[5]->s_vec, sp[6]->s_vec, sp[7]->s_vec, sp[8]->s_vec, sp[9]->s_vec, sp[10]->s_vec, sp[0]->s_n); } \ No newline at end of file
diff --git a/reanimator~.c b/reanimator~.c
new file mode 100644
index 0000000..8afec93
--- /dev/null
+++ b/reanimator~.c
@@ -0,0 +1,698 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+
+#define THRESHOLD_MIN (.000001)
+
+#if MSP
+void *reanimator_class;
+#endif
+
+#if PD
+static t_class *reanimator_class;
+#endif
+
+
+#define OBJECT_NAME "reanimator~"
+
+typedef struct _reanimator
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ float *buffer;
+ float *channel;
+ float *output;
+ float **framebank;
+ float *normalized_frame;
+ float current_frame;
+ int framecount;
+ //
+ float frame_increment ;
+ float last_frame ;
+
+ float fpos;
+ float last_fpos;
+ float tadv;
+ // for convert
+ float *c_lastphase_in;
+ float *c_lastphase_out;
+ float c_fundamental;
+ float c_factor_in;
+ float c_factor_out;
+ // faster fft
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ int read_me;
+
+ int total_frames;
+ short mute;
+ short initialized;
+ float threshold;
+ short inverse;
+ int top_comparator_bin;
+ short residency_mode;
+ int vs;// vector size
+ int winfac;//window factor
+ int overlap;//overlap factor
+ float sample_len;//duration of texture sample
+ float sync;
+ int megs;
+} t_reanimator;
+
+void *reanimator_new(t_symbol *msg, short argc, t_atom *argv);
+// t_int *offset_perform(t_int *w);
+t_int *reanimator_perform(t_int *w);
+void reanimator_dsp(t_reanimator *x, t_signal **sp, short *count);
+void reanimator_assist(t_reanimator *x, void *b, long m, long a, char *s);
+void reanimator_analyze (t_reanimator *x);
+void reanimator_float(t_reanimator *x, double f) ;
+void reanimator_mute(t_reanimator *x, t_floatarg flag);
+void reanimator_inverse(t_reanimator *x, t_floatarg toggle);
+void reanimator_topbin(t_reanimator *x, t_floatarg bin);
+void reanimator_startframe(t_reanimator *x, t_floatarg start);
+void reanimator_endframe(t_reanimator *x, t_floatarg end);
+void reanimator_framerange(t_reanimator *x, t_floatarg start, t_floatarg end);
+void reanimator_inverse(t_reanimator *x, t_floatarg toggle);
+void reanimator_size(t_reanimator *x, t_floatarg size_ms);
+void reanimator_freeze_and_march(t_reanimator *x, t_floatarg f);
+void reanimator_resume( t_reanimator *x );
+void reanimator_threshold(t_reanimator *x, t_floatarg threshold);
+void reanimator_dsp_free( t_reanimator *x );
+void reanimator_framecount ( t_reanimator *x );
+void reanimator_init(t_reanimator *x, short initialized);
+void reanimator_fftinfo(t_reanimator *x);
+void reanimator_overlap(t_reanimator *x, t_floatarg f);
+void reanimator_winfac(t_reanimator *x, t_floatarg f);
+void reanimator_meminfo(t_reanimator *x);
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&reanimator_class, (method)reanimator_new,
+ (method)reanimator_dsp_free, (short)sizeof(t_reanimator), 0L, A_GIMME,0);
+ addmess((method)reanimator_dsp, "dsp", A_CANT, 0);
+ addmess((method)reanimator_assist,"assist",A_CANT,0);
+ addfloat((method)reanimator_float);
+ addmess ((method)reanimator_mute, "mute", A_FLOAT, 0);
+ addmess ((method)reanimator_inverse, "inverse", A_FLOAT, 0);
+ addmess ((method)reanimator_topbin, "topbin", A_FLOAT, 0);
+ addmess ((method)reanimator_threshold, "threshold", A_FLOAT, 0);
+ addmess ((method)reanimator_analyze, "analyze", 0);
+ addmess ((method)reanimator_framecount, "framecount", 0);
+ addmess ((method)reanimator_freeze_and_march, "freeze_and_march", A_FLOAT, 0);
+ addmess ((method)reanimator_resume, "resume", 0);
+ addmess((method)reanimator_overlap,"overlap",A_DEFFLOAT,0);
+ addmess((method)reanimator_winfac,"winfac",A_DEFFLOAT,0);
+ addmess((method)reanimator_fftinfo,"fftinfo",0);
+ addmess((method)reanimator_meminfo,"meminfo",0);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+#if PD
+/* Pd Initialization */
+void reanimator_tilde_setup(void)
+{
+ reanimator_class = class_new(gensym("reanimator~"), (t_newmethod)reanimator_new,
+ (t_method)reanimator_dsp_free ,sizeof(t_reanimator), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(reanimator_class, t_reanimator, x_f);
+ class_addmethod(reanimator_class, (t_method)reanimator_dsp, gensym("dsp"), 0);
+ class_addmethod(reanimator_class, (t_method)reanimator_mute, gensym("mute"), A_FLOAT,0);
+ class_addmethod(reanimator_class, (t_method)reanimator_inverse, gensym("inverse"), A_FLOAT,0);
+ class_addmethod(reanimator_class, (t_method)reanimator_topbin, gensym("topbin"), A_FLOAT,0);
+ class_addmethod(reanimator_class, (t_method)reanimator_threshold, gensym("threshold"), A_FLOAT,0);
+
+ class_addmethod(reanimator_class, (t_method)reanimator_freeze_and_march, gensym("freeze_and_march"), A_FLOAT, 0);
+ class_addmethod(reanimator_class, (t_method)reanimator_analyze, gensym("analyze"), 0);
+ class_addmethod(reanimator_class, (t_method)reanimator_framecount, gensym("framecount"), 0);
+ class_addmethod(reanimator_class, (t_method)reanimator_overlap, gensym("overlap"), A_FLOAT, 0);
+ class_addmethod(reanimator_class, (t_method)reanimator_winfac, gensym("winfac"), A_FLOAT, 0);
+ class_addmethod(reanimator_class, (t_method)reanimator_fftinfo, gensym("fftinfo"), 0);
+ class_addmethod(reanimator_class, (t_method)reanimator_meminfo, gensym("meminfo"), 0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+void reanimator_overlap(t_reanimator *x, t_floatarg f)
+{
+ int i = (int) f;
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->overlap = i;
+ reanimator_init(x,1);
+}
+
+void reanimator_winfac(t_reanimator *x, t_floatarg f)
+{
+ int i = (int)f;
+
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = i;
+ reanimator_init(x,2);
+}
+
+void reanimator_meminfo(t_reanimator *x)
+{
+ post("%s currently stores %d FFT Frames, duration: %f sec., size: %.2f MB",
+ OBJECT_NAME, x->framecount, x->tadv * x->framecount, (float)x->megs/1000000.0);
+}
+
+void reanimator_fftinfo(t_reanimator *x)
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+void reanimator_framecount ( t_reanimator *x )
+{
+ post("%d frames stored", x->total_frames);
+}
+
+void reanimator_freeze_and_march(t_reanimator *x, t_floatarg f)
+{
+ x->frame_increment = f;
+ x->residency_mode = 1;
+}
+
+void reanimator_resume( t_reanimator *x )
+{
+ x->residency_mode = 0;
+}
+
+void reanimator_dsp_free( t_reanimator *x ){
+ int i ;
+#if MSP
+ dsp_free( (t_pxobject *) x);
+#endif
+ for( i = 0; i < x->framecount; i++ ){
+ freebytes(x->framebank[i],0) ;
+ }
+
+ freebytes(x->c_lastphase_in,0);
+ freebytes(x->c_lastphase_out,0);
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->input,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->buffer,0);
+ freebytes(x->channel,0);
+ freebytes(x->normalized_frame,0);
+ freebytes(x->output,0);
+}
+
+
+void reanimator_assist (t_reanimator *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0:
+ sprintf(dst,"(signal) Driver Sound ");
+ break;
+ case 1:
+ sprintf(dst,"(signal) Texture Sound");
+ break;
+
+ }
+ } else if (msg==2) {
+ switch (arg) {
+ case 0:
+ sprintf(dst,"(signal) Output");
+ break;
+ case 1:
+ sprintf(dst,"(signal) Matched Frame");
+ break;
+ case 2:
+ sprintf(dst,"(signal) Sync");
+ break;
+
+ }
+ }
+}
+
+
+void *reanimator_new(t_symbol *msg, short argc, t_atom *argv)
+{
+#if MSP
+ t_reanimator *x = (t_reanimator *)newobject(reanimator_class);
+ dsp_setup((t_pxobject *)x,2);
+ outlet_new((t_pxobject *)x, "signal");
+ outlet_new((t_pxobject *)x, "signal");
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+#if PD
+ int i;
+ t_reanimator *x = (t_reanimator *)pd_new(reanimator_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ for(i=0;i<3;i++)
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+ x->vs = sys_getblksize();
+ x->R = sys_getsr();
+
+ x->sample_len = atom_getfloatarg(0,argc,argv) * .001;// convert to seconds
+ x->overlap = atom_getintarg(1,argc,argv);
+ x->winfac = atom_getintarg(2,argc,argv);
+
+ if(!x->overlap)
+ x->overlap = 4;
+ if(!x->winfac)
+ x->winfac = 1;
+ if(x->sample_len <= .05){
+ x->sample_len = 1.0;
+ post("%s: sample length set to default 1000 ms.",OBJECT_NAME);
+ }
+
+ reanimator_init(x,0);
+ return (x);
+}
+
+void reanimator_init(t_reanimator *x, short initialized)
+{
+ int i;
+ x->D = x->vs;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->tadv = (float)x->D/(float)x->R;
+ x->mult = 1. / (float) x->N;
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->current_frame = x->framecount = 0;
+ x->fpos = x->last_fpos = 0;
+ x->framecount = 0;
+ x->total_frames = x->sample_len / x->tadv;
+
+ if(!initialized){
+ x->sync = 0.0;
+ x->inverse = 0;
+ x->initialized = 0;
+ x->threshold = .0001;
+ x->top_comparator_bin = 10 ;
+ x->residency_mode = 0;
+ x->frame_increment = 1.0 ;
+ x->mute = 0;
+ x->read_me = 0;
+ x->framecount = 0;
+ x->Wanal = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Wsyn = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Hwin = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->input = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->output = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->buffer = (float *) getbytes( MAX_N * sizeof(float) );
+ x->channel = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->bitshuffle = (int *) getbytes( MAX_N * 2 * sizeof( int ) );
+ x->trigland = (float *) getbytes( MAX_N * 2 * sizeof( float ) );
+ x->c_lastphase_in = (float *) getbytes( (MAX_N2+1) * sizeof(float) );
+ x->c_lastphase_out = (float *) getbytes( (MAX_N2+1) * sizeof(float) );
+
+ x->total_frames = x->sample_len / x->tadv;
+ x->normalized_frame = (float *) getbytes( (MAX_N+2) * sizeof(float));
+ x->framebank = (float **) getbytes(x->total_frames * sizeof(float *));
+ /* taking a risk here */
+ while(x->framecount < x->total_frames ){
+ x->framebank[(x->framecount)] = (float *) getbytes((x->N+2) * sizeof(float));
+ memset((char *)x->framebank[(x->framecount)],0,(x->N+2) * sizeof(float));
+ ++(x->framecount);
+ }
+
+ } else {
+ while(x->framecount < x->total_frames ){
+ x->framebank[x->framecount] =
+ (float *) resizebytes((char *)x->framebank[x->framecount],0,(x->N+2) * sizeof(float));
+ memset((char *)x->framebank[(x->framecount)],0,(x->N+2) * sizeof(float));
+ ++(x->framecount);
+ }
+ }
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ memset((char *)x->c_lastphase_in,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->c_lastphase_out,0,(x->N2+1) * sizeof(float));
+
+
+ x->c_fundamental = (float) x->R/( (x->N2)<<1 );
+ x->c_factor_in = (float) x->R/((float)x->D * TWOPI);
+ x->c_factor_out =TWOPI * (float) x->D / (float) x->R;
+ init_rdft(x->N, x->bitshuffle, x->trigland);
+ makewindows( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D);
+
+ x->megs = sizeof(float) * x->framecount * (x->N+2);
+}
+
+t_int *reanimator_perform(t_int *w)
+{
+ float sample, outsamp ;
+ float ampsum, new_ampsum, rescale;
+ float min_difsum, difsum;
+ int
+ i,j, match_frame=0;
+
+
+ //////////////////////////////////////////////
+ t_reanimator *x = (t_reanimator *) (w[1]);
+ t_float *driver = (t_float *)(w[2]);
+ t_float *texture = (t_float *)(w[3]);
+ t_float *soundout = (t_float *)(w[4]);
+ t_float *matchout = (t_float *)(w[5]);
+ t_float *sync_vec = (t_float *)(w[6]);
+ int n = (int)(w[7]);
+
+ /* dereference structure */
+
+ int inCount = x->inCount;
+ int R = x->R;
+ int N = x->N;
+ int N2 = x->N2;
+ int D = x->D;
+ int Nw = x->Nw;
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *input = x->input;
+ float *output = x->output;
+ float *buffer = x->buffer;
+ float *channel = x->channel;
+ float *normalized_frame = x->normalized_frame;
+ int framecount = x->framecount;
+ int total_frames = x->total_frames;
+
+ float threshold = x->threshold;
+ int top_comparator_bin = x->top_comparator_bin ;
+
+ float mult = x->mult ;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland ;
+
+ float *c_lastphase_in = x->c_lastphase_in;
+ float *c_lastphase_out = x->c_lastphase_out;
+ float c_fundamental = x->c_fundamental;
+ float c_factor_in = x->c_factor_in;
+ float c_factor_out = x->c_factor_out;
+ float **framebank = x->framebank;
+ // for residency mode
+ float fframe = x->current_frame ;
+ float last_fpos = x->last_fpos ;
+ float fincr = x->frame_increment;
+ float fpos = x->fpos ;
+ float sync = x->sync;
+ /***********************************/
+ inCount += D;
+
+ /* SAMPLE MODE */
+ if( x->read_me ) {
+ for ( j = 0 ; j < Nw - D ; j++ ){
+ input[j] = input[j+D];
+ }
+ for ( j = Nw - D; j < Nw; j++ ) {
+ input[j] = *texture++;
+ }
+
+ fold( input, Wanal, Nw, buffer, N, inCount );
+ rdft( N, 1, buffer, bitshuffle, trigland );
+
+ sync = (float) framecount / (float) total_frames;
+ for ( j = 0; j < n; j++ ){
+ *sync_vec++ = sync;
+ *matchout++ = 0.0;
+ *soundout++ = 0.0;
+ }
+ convert( buffer, framebank[framecount], N2, c_lastphase_in, c_fundamental, c_factor_in );
+
+ new_ampsum = ampsum = 0;
+ for( j = 0; j < N; j+= 2 ){
+ ampsum += framebank[framecount][j];
+ }
+
+ if( ampsum > .00000001 ){
+ rescale = 1.0 / ampsum ;
+ for( i = 0; i < N; i+= 2 ){
+ framebank[framecount][i] *= rescale;
+ }
+
+ ++framecount;
+
+ } else {
+ post("amplitude for frame %d is too low\n", framecount);
+ }
+
+ // output empty buffers while reading
+
+
+ if( framecount >= total_frames ){
+ sync = 1.0;
+ x->read_me = 0;
+ // post("reanimator~: data acquisition completed");
+ x->initialized = 1;
+ // clear input buffer
+ for( i = 0; i < Nw; i++ )
+ input[i] = 0.0;
+ }
+
+ } else if (x->mute || ! x->initialized) {
+ for ( j = 0; j < D; j++ ){
+ *soundout++ = 0.0;
+ *matchout++ = 0.0;
+ *sync_vec++ = sync;
+ }
+ }
+ /* RESIDENCY RESYNTHESIS */
+ else if( x->residency_mode ) {
+ if( fpos < 0 )
+ fpos = 0;
+ if( fpos > 1 )
+ fpos = 1;
+ if( fpos != last_fpos ){
+ fframe = fpos * (float) framecount ;
+ last_fpos = fpos;
+ }
+
+
+ fframe += fincr;
+ while( fframe >= framecount ) {
+ fframe -= framecount;
+ }
+ while( fframe < 0. ) {
+ fframe += framecount ;
+ }
+
+ unconvert(framebank[(int) fframe ], buffer, N2, c_lastphase_out, c_fundamental, c_factor_out );
+
+ rdft( N, -1, buffer, bitshuffle, trigland );
+ overlapadd( buffer, N, Wsyn, output, Nw, inCount );
+
+ for ( j = 0; j < D; j++ ){
+ *soundout++ = output[j] * mult;
+ *matchout++ = (int) fframe;
+ *sync_vec++ = sync;
+ }
+ for ( j = 0; j < Nw - D; j++ ){
+ output[j] = output[j+D];
+ }
+
+ for ( j = Nw - D; j < Nw; j++ ){
+ output[j] = 0.;
+ }
+ x->current_frame = fframe;
+ x->frame_increment = fincr;
+ x->fpos = fpos;
+ x->sync = sync;
+ }
+ /* REANIMATION HERE */
+ else {
+ for ( j = 0 ; j < Nw - D ; j++ ){
+ input[j] = input[j+D];
+ }
+ for ( j = Nw - D; j < Nw; j++ ) {
+ input[j] = *driver++;
+ }
+
+ fold( input, Wanal, Nw, buffer, N, inCount );
+ rdft( N, 1, buffer, bitshuffle, trigland );
+ convert( buffer, channel, N2, c_lastphase_in, c_fundamental, c_factor_in );
+ ampsum = 0;
+ // NORMALIZE INPUT FRAME
+ for( i = 0; i < N+2; i += 2 ){
+ ampsum += channel[i];
+ }
+
+ if( ampsum > threshold ){
+ rescale = 1.0 / ampsum;
+ for( i = 0; i < N; i += 2 ){
+ channel[i] *= rescale;
+ }
+ } else {
+ // AMPLITUDE OF INPUT WAS TOO LOW - OUTPUT SILENCE AND RETURN
+ for ( j = 0; j < D; j++ ){
+ *soundout++ = 0.0;
+ *matchout++ = 0.0;
+ *sync_vec++ = sync;
+
+ }
+ x->inCount = inCount;
+ x->sync = sync;
+ return (w+8);
+
+ }
+ // NOW COMPARE TO STORED FRAMES
+ if( x->inverse ){ // INVERSE CASE
+ min_difsum = 0.0 ;
+
+ for( j = 0; j < framecount; j++ ){
+ difsum = 0;
+ for( i = 0; i < top_comparator_bin * 2; i += 2 ){
+ difsum += fabs( channel[i] - framebank[j][i] );
+ }
+ // fprintf(stderr,"bin 20: in %f compare %f\n", channel[40], frames[j][40]);
+ if( difsum > min_difsum ){
+ match_frame = j;
+ min_difsum = difsum;
+ }
+ }
+ } else { // NORMAL CASE
+ min_difsum = 1000000.0 ;
+
+ for( j = 0; j < framecount; j++ ){
+ difsum = 0;
+ for( i = 0; i < top_comparator_bin * 2; i += 2 ){
+ difsum += fabs( channel[i] - framebank[j][i] );
+ }
+ // fprintf(stderr,"bin 20: in %f compare %f\n", channel[40], frames[j][40]);
+ if( difsum < min_difsum ){
+ match_frame = j;
+ min_difsum = difsum;
+ }
+ }
+ }
+
+ unconvert( framebank[match_frame], buffer, N2, c_lastphase_out, c_fundamental, c_factor_out );
+
+ rdft( N, -1, buffer, bitshuffle, trigland );
+ overlapadd( buffer, N, Wsyn, output, Nw, inCount );
+
+ // scale back to match
+ for ( j = 0; j < D; j++ ){
+ *soundout++ = output[j] * (mult / rescale);
+ *matchout++ = (float) match_frame;
+ *sync_vec++ = sync;
+ }
+ for ( j = 0; j < Nw - D; j++ ){
+ output[j] = output[j+D];
+ }
+
+ for ( j = Nw - D; j < Nw; j++ ){
+ output[j] = 0.;
+ }
+ x->current_frame = match_frame; // for residency
+ x->sync = sync;
+ }
+
+ /* restore state variables */
+ x->framecount = framecount;
+ x->inCount = inCount % Nw;
+ x->sync = sync;
+
+ return (w+8);
+}
+
+#if MSP
+void reanimator_float(t_reanimator *x, double f) // Look at floats at inlets
+{
+ int inlet = x->x_obj.z_in;
+
+ if (inlet == 1)
+ {
+ x->frame_increment = f;
+ }
+ else if (inlet == 2)
+ {
+ if (f < 0 ){
+ f = 0;
+ } else if(f > 1) {
+ f = 1.;
+ }
+ x->fpos = f;
+
+ }
+}
+#endif
+
+void reanimator_analyze ( t_reanimator *x )
+{
+ // int i, j;
+
+ x->read_me = 1;
+ x->framecount = 0;
+ // post("reanimator: beginning spectral data acquisition");
+ return;
+
+}
+
+void reanimator_mute(t_reanimator *x, t_floatarg flag)
+{
+ x->mute = flag;
+ // post ("mute set to %d", flag);
+}
+
+void reanimator_topbin(t_reanimator *x, t_floatarg bin)
+{
+ if( bin > 1 && bin < x->N2 )
+ x->top_comparator_bin = bin;
+}
+
+
+void reanimator_inverse(t_reanimator *x, t_floatarg toggle)
+{
+ x->inverse = toggle;
+ // post ("inverse set to %d", toggle);
+}
+
+void reanimator_threshold(t_reanimator *x, t_floatarg threshold)
+{
+ if( threshold > THRESHOLD_MIN )
+ x->threshold = threshold;
+ else
+ x->threshold = THRESHOLD_MIN;
+}
+
+void reanimator_dsp(t_reanimator *x, t_signal **sp, short *count)
+{
+ // long i;
+
+ if(x->vs != sp[0]->s_n || x->R != sp[0]->s_sr){
+ x->vs = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ reanimator_init(x,1);
+ }
+ dsp_add(reanimator_perform, 7, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,
+ sp[3]->s_vec, sp[4]->s_vec, sp[0]->s_n);
+}
+
+
diff --git a/resent~.c b/resent~.c
new file mode 100644
index 0000000..704bb6a
--- /dev/null
+++ b/resent~.c
@@ -0,0 +1,766 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *resent_class;
+#endif
+
+#if PD
+static t_class *resent_class;
+#endif
+
+#define OBJECT_NAME "resent~"
+
+typedef struct _resent
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ float *buffer;
+ float *channel;
+ float *output;
+ float *frame_incr;
+ float *store_incr;
+ float *frame_phase;
+ float frameloc;
+ float **loveboat;
+ float current_frame;
+ int framecount;
+ //
+ float frame_increment ;
+ float *composite_frame ;
+ float fpos;
+ float last_fpos;
+ float tadv;
+ // for convert
+ float *c_lastphase_in;
+ float *c_lastphase_out;
+ float c_fundamental;
+ float c_factor_in;
+ float c_factor_out;
+ // faster fft
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ int read_me;
+ int frames_read;
+// int MAXFRAMES;
+ short mute;
+ void *m_clock;
+ void *m_bang;
+ short playthrough;
+ int hopsize;
+ int overlap;
+ int winfac;
+ short lock;
+ float duration;
+ short verbose;
+ float sync;
+} t_resent;
+
+void *resent_new(t_symbol *msg, short argc, t_atom *argv);
+t_int *offset_perform(t_int *w);
+t_int *resent_perform(t_int *w);
+void resent_dsp(t_resent *x, t_signal **sp, short *count);
+void resent_assist(t_resent *x, void *b, long m, long a, char *s);
+void resent_acquire_sample (t_resent *x) ;
+void resent_mute(t_resent *x, t_floatarg tog);
+void resent_bin(t_resent *x, t_floatarg fbin, t_floatarg speed);
+void resent_setphase(t_resent *x, t_floatarg phase);
+void resent_addphase(t_resent *x, t_floatarg phase);
+void resent_setspeed( t_resent *x, t_floatarg speed );
+void resent_addspeed( t_resent *x, t_floatarg speed );
+void resent_size( t_resent *x, t_floatarg size_ms );
+void resent_free( t_resent *x );
+void resent_store_incr( t_resent *x );
+void resent_setspeed_and_phase( t_resent *x, t_floatarg speed, t_floatarg phase );
+void resent_tick(t_resent *x);
+void resent_fftinfo(t_resent *x);
+void resent_init(t_resent *x, short flag);
+void resent_linephase(t_resent *x, t_symbol *msg, short argc, t_atom *argv);
+void resent_linespeed(t_resent *x, t_symbol *msg, short argc, t_atom *argv);
+void resent_randphase(t_resent *x, t_symbol *msg, short argc, t_atom *argv);
+void resent_randspeed(t_resent *x, t_symbol *msg, short argc, t_atom *argv);
+void resent_playthrough(t_resent *x, t_floatarg state);
+float resent_randf(float min, float max);
+void resent_winfac(t_resent *x, t_floatarg factor);
+
+void resent_verbose(t_resent *x, t_floatarg t);
+void resent_fftinfo(t_resent *x);
+void resent_overlap(t_resent *x, t_floatarg f);
+void resent_winfac(t_resent *x, t_floatarg f);
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&resent_class, (method)resent_new,
+ (method)resent_free, (short)sizeof(t_resent), 0L,A_GIMME,0);
+ addmess((method)resent_dsp, "dsp", A_CANT, 0);
+ addmess((method)resent_assist,"assist",A_CANT,0);
+ addbang((method)resent_acquire_sample);
+ addmess((method)resent_mute, "mute", A_FLOAT, 0);
+ addmess((method)resent_linespeed, "linespeed", A_GIMME, 0);
+ addmess((method)resent_linephase, "linephase", A_GIMME, 0);
+ addmess((method)resent_randspeed, "randspeed", A_GIMME, 0);
+ addmess((method)resent_randphase, "randphase", A_GIMME, 0);
+ addmess((method)resent_bin, "bin", A_DEFFLOAT, A_DEFFLOAT, 0);
+ addmess((method)resent_setphase, "setphase", A_DEFFLOAT, 0);
+ addmess((method)resent_addphase, "addphase", A_DEFFLOAT, 0);
+ addmess((method)resent_setspeed, "setspeed", A_DEFFLOAT, 0);
+ addmess((method)resent_addspeed, "addspeed", A_DEFFLOAT, 0);
+ addmess((method)resent_playthrough, "playthrough", A_DEFFLOAT, 0);
+ addmess((method)resent_store_incr, "store_incr",0);
+ addmess((method)resent_fftinfo, "fftinfo",0);
+ addmess((method)resent_overlap, "overlap",A_FLOAT,0);
+ addmess((method)resent_winfac, "winfac",A_FLOAT,0);
+ addmess((method)resent_setspeed_and_phase, "setspeed_and_phase", A_DEFFLOAT, A_DEFFLOAT, 0);
+ addmess((method)resent_size, "size", A_FLOAT,0);
+// addmess((method)resent_verbose, "verbose", A_FLOAT,0);
+ addmess((method)resent_overlap,"overlap",A_DEFFLOAT,0);
+ addmess((method)resent_winfac,"winfac",A_DEFFLOAT,0);
+ addmess((method)resent_fftinfo,"fftinfo",0);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+#if PD
+void resent_tilde_setup(void)
+{
+ resent_class = class_new(gensym("resent~"), (t_newmethod)resent_new,
+ (t_method)resent_free ,sizeof(t_resent), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(resent_class, t_resent, x_f);
+ class_addmethod(resent_class,(t_method)resent_dsp,gensym("dsp"),0);
+ class_addmethod(resent_class,(t_method)resent_mute,gensym("mute"),A_FLOAT,0);
+ class_addmethod(resent_class,(t_method)resent_linespeed,gensym("linespeed"),A_GIMME,0);
+ class_addmethod(resent_class,(t_method)resent_linephase,gensym("linephase"),A_GIMME,0);
+ class_addmethod(resent_class,(t_method)resent_randspeed,gensym("randspeed"),A_GIMME,0);
+ class_addmethod(resent_class,(t_method)resent_randphase,gensym("randphase"),A_GIMME,0);
+ class_addmethod(resent_class,(t_method)resent_bin,gensym("bin"),A_DEFFLOAT, A_DEFFLOAT,0);
+// Pd may still have parser bug for similar starting strings
+ class_addmethod(resent_class,(t_method)resent_setspeed_and_phase,gensym("ssap"),A_DEFFLOAT, A_DEFFLOAT,0);
+ class_addmethod(resent_class,(t_method)resent_setphase,gensym("setphase"),A_DEFFLOAT,0);
+ class_addmethod(resent_class,(t_method)resent_addphase,gensym("addphase"),A_DEFFLOAT,0);
+ class_addmethod(resent_class,(t_method)resent_setspeed,gensym("setspeed"),A_DEFFLOAT,0);
+ class_addmethod(resent_class,(t_method)resent_addspeed,gensym("addspeed"),A_DEFFLOAT,0);
+ class_addmethod(resent_class,(t_method)resent_fftinfo,gensym("fftinfo"),0);
+class_addmethod(resent_class,(t_method)resent_store_incr,gensym("store_incr"),0);
+ class_addmethod(resent_class,(t_method)resent_playthrough,gensym("playthrough"),A_FLOAT,0);
+ class_addmethod(resent_class,(t_method)resent_size,gensym("size"),A_FLOAT,0);
+ class_addmethod(resent_class,(t_method)resent_overlap,gensym("overlap"),A_FLOAT,0);
+ class_addmethod(resent_class,(t_method)resent_winfac,gensym("winfac"),A_FLOAT,0);
+ class_addmethod(resent_class,(t_method)resent_verbose,gensym("verbose"),A_FLOAT,0);
+ class_addmethod(resent_class,(t_method)resent_acquire_sample,gensym("acquire_sample"),0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+
+
+void resent_verbose(t_resent *x, t_floatarg t)
+{
+ x->verbose = (short)t;
+}
+
+
+void resent_overlap(t_resent *x, t_floatarg f)
+{
+int i = (int) f;
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->overlap = i;
+ resent_init(x,1);
+}
+
+void resent_winfac(t_resent *x, t_floatarg f)
+{
+int i = (int)f;
+
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = i;
+ resent_init(x,2);
+}
+
+void resent_fftinfo(t_resent *x)
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+void resent_size(t_resent *x, t_floatarg size)
+{
+ x->duration = size/1000.0;
+ resent_init(x,1);
+}
+
+void resent_store_incr(t_resent *x)
+{
+ int i;
+ float *store_incr = x->store_incr;
+ float *frame_incr = x->frame_incr;
+
+ for(i = 0; i < x->N2; i++){
+ store_incr[i] = frame_incr[i];
+ }
+}
+
+void resent_free(t_resent *x){
+ int i ;
+#if MSP
+ dsp_free((t_pxobject *) x);
+#endif
+ for(i = 0; i < x->framecount; i++){
+ freebytes(x->loveboat[i],0) ;
+ }
+ freebytes(x->frame_phase,0);
+ freebytes(x->composite_frame,0);
+ freebytes(x->c_lastphase_in,0);
+ freebytes(x->c_lastphase_out,0);
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->input,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->buffer,0);
+ freebytes(x->channel,0);
+ freebytes(x->output,0);
+ freebytes(x->frame_incr,0);
+ freebytes(x->store_incr,0);
+}
+
+void resent_bin(t_resent *x, t_floatarg fbin, t_floatarg speed)
+{
+int bin_num = (int) fbin;
+
+ if(bin_num >= 0 && bin_num < x->N2){
+ x->frame_incr[bin_num] = speed ;
+ } else {
+ post("resent~: bin %d is out of range", bin_num);
+ }
+}
+
+void resent_setphase( t_resent *x, t_floatarg phase)
+{
+ float scaled_phase ;
+ int i;
+
+ if( phase < 0. )
+ phase = 0. ;
+ if( phase > 1. )
+ phase = 1.;
+ scaled_phase = phase * (float) x->framecount ;
+ for( i = 0; i < x->N2; i++ ){
+ x->frame_phase[i] = scaled_phase ;
+ }
+
+}
+
+void resent_addphase( t_resent *x, t_floatarg phase )
+{
+ float scaled_phase ;
+ float *frame_phase = x->frame_phase;
+ int framecount = x->framecount;
+ int i;
+
+
+ if( phase < 0. )
+ phase = 0. ;
+ if( phase > 1. )
+ phase = 1.;
+ scaled_phase = phase * (float) framecount ;
+ for( i = 0; i < x->N2; i++ ){
+ frame_phase[i] += scaled_phase ;
+ while( frame_phase[i] < 0 )
+ frame_phase[i] += framecount;
+ while( frame_phase[i] > framecount - 1 )
+ frame_phase[i] -= framecount ;
+ }
+
+
+}
+
+void resent_setspeed( t_resent *x, t_floatarg speed )
+{
+ int i;
+
+ for( i = 0; i < x->N2; i++ ){
+
+ x->frame_incr[i] = speed ;
+ }
+ // post("speed reset to %f",speed);
+
+}
+
+void resent_addspeed( t_resent *x, t_floatarg speed )
+{
+ int i;
+ float *store_incr = x->store_incr;
+ float *frame_incr = x->frame_incr;
+
+ for( i = 0; i < x->N2; i++ ){
+ frame_incr[i] = store_incr[i] + speed ;
+ }
+
+
+}
+void resent_setspeed_and_phase( t_resent *x, t_floatarg speed, t_floatarg phase )
+{
+ float scaled_phase ;
+ int i;
+ if( phase < 0. )
+ phase = 0. ;
+ if( phase > 1. )
+ phase = 1.;
+
+ scaled_phase = phase * (float) x->framecount ;
+ for( i = 0; i < x->N2; i++ ){
+ x->frame_phase[i] = scaled_phase ;
+ x->frame_incr[i] = speed ;
+ }
+// post("ssap: speed reset to %f, phase reset to %f",speed,phase);
+
+}
+
+void resent_assist (t_resent *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0:
+ sprintf(dst,"(signal/bang) Input, Sample Trigger");
+ break;
+ }
+ } else if (msg==2) {
+ switch( arg){
+ case 0:
+ sprintf(dst,"(signal) Output ");
+ break;
+ case 1:
+ sprintf(dst,"(signal) Recording Sync");
+ break;
+ }
+
+ }
+}
+
+void resent_tick(t_resent *x) {
+ outlet_bang(x->m_bang);
+}
+
+void resent_init(t_resent *x,short initialized)
+{
+ int i;
+ int last_framecount = x->framecount;
+
+ x->lock = 1;
+
+ if(!x->D)
+ x->D = 256;
+ if(!x->R)
+ x->R = 44100;
+ if(!power_of_two(x->winfac))
+ x->winfac = 1;
+ if(!power_of_two(x->overlap))
+ x->overlap = 1;
+
+ x->verbose = 0; // testing only
+
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->current_frame = x->framecount = 0;
+ x->fpos = x->last_fpos = 0;
+ x->tadv = (float)x->D/(float)x->R;
+ x->mult = 1. / (float) x->N;
+ x->c_fundamental = (float) x->R/( (x->N2)<<1 );
+ x->c_factor_in = (float) x->R/((float)x->D * TWOPI);
+ x->c_factor_out = TWOPI * (float) x->D / (float) x->R;
+ if(x->duration < .005){
+ x->duration = 1.0;
+ }
+ x->framecount = x->duration/x->tadv ;
+ x->read_me = 0;
+
+ if(!initialized){
+ x->frame_increment = 1.0 ;
+ x->mute = 0;
+ x->playthrough = 0;
+ x->sync = 0;
+ x->frames_read = 0;
+
+ x->Wanal = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Wsyn = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Hwin = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->input = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->output = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->buffer = (float *) getbytes( MAX_N * sizeof(float) );
+ x->channel = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->bitshuffle = (int *) getbytes( MAX_N * 2 * sizeof( int ) );
+ x->trigland = (float *) getbytes( MAX_N * 2 * sizeof( float ) );
+ x->c_lastphase_in = (float *) getbytes( (MAX_N2+1) * sizeof(float) );
+ x->c_lastphase_out = (float *) getbytes( (MAX_N2+1) * sizeof(float) );
+ x->composite_frame = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->frame_incr = (float *) getbytes( MAX_N2 * sizeof(float) );
+ x->store_incr = (float *) getbytes( MAX_N2 * sizeof(float) );
+ x->frame_phase = (float *) getbytes( MAX_N2 * sizeof(float) );
+ x->loveboat = (float **) getbytes(x->framecount * sizeof(float *));
+
+ for(i=0;i<x->framecount;i++){
+ x->loveboat[i] = (float *) getbytes((x->N+2) * sizeof(float));
+ if(x->loveboat[i] == NULL){
+ error("Insufficient Memory!");
+ return;
+ }
+ memset((char *)x->loveboat[i],0,(x->N+2) * sizeof(float));
+ }
+ } else if(initialized == 1){
+ for(i = 0; i < last_framecount; i++){
+ freebytes(x->loveboat[i],0) ;
+ }
+ freebytes(x->loveboat,0);
+ x->loveboat = (float **) getbytes(x->framecount * sizeof(float *));
+ for(i=0;i<x->framecount;i++){
+ x->loveboat[i] = (float *) getbytes((x->N+2) *sizeof(float));
+ if(x->loveboat[i] == NULL){
+ error("Insufficient Memory!");
+ return;
+ }
+ memset((char *)x->loveboat[i],0,(x->N+2) * sizeof(float));
+ }
+ }
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ memset((char *)x->c_lastphase_in,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->c_lastphase_out,0,(x->N2+1)* sizeof(float));
+ memset((char *)x->frame_incr,0,(x->N2)* sizeof(float));
+ memset((char *)x->store_incr,0,(x->N2) * sizeof(float));
+ memset((char *)x->frame_phase,0,(x->N2) * sizeof(float));
+
+
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ x->hopsize = x->N / x->overlap;
+ makewindows( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D);
+
+
+ x->lock = 0;
+}
+
+void *resent_new(t_symbol *msg, short argc, t_atom *argv)
+{
+#if MSP
+ t_resent *x = (t_resent *)newobject(resent_class);
+// x->m_bang = bangout((t_pxobject *)x);
+// x->m_clock = clock_new(x,(method)resent_tick);
+ dsp_setup((t_pxobject *)x,1);
+ outlet_new((t_pxobject *)x, "signal");
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+
+#if PD
+ t_resent *x = (t_resent *)pd_new(resent_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+// x->m_bang = outlet_new(&x->x_obj,gensym("bang"));
+// x->m_clock = clock_new(x,(void *)resent_tick);
+#endif
+
+ srand(clock());
+
+ x->duration = atom_getfloatarg(0, argc, argv)/1000.0;
+ x->overlap = atom_getfloatarg(1, argc, argv);
+ x->winfac = atom_getfloatarg(2, argc, argv);
+ x->D = sys_getblksize();
+ x->R = sys_getsr();
+
+ resent_init(x,0);
+
+ return (x);
+}
+
+t_int *resent_perform(t_int *w)
+{
+
+ int iphase, amp, freq, i, j;
+ float fincr;
+ float fpos;
+ //////////////////////////////////////////////
+ t_resent *x = (t_resent *) (w[1]);
+ float *frame_incr = x->frame_incr ;
+ float *frame_phase = x->frame_phase ;
+ float *composite_frame = x->composite_frame ;
+ float in_sample;
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ t_float *sync_vec = (t_float *)(w[4]);
+ t_int n = w[5];
+
+ /* dereference structure */
+
+ int inCount = x->inCount;
+ int R = x->R;
+ int N = x->N;
+ int N2 = x->N2;
+ int D = x->D;
+ int Nw = x->Nw;
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *input = x->input;
+ float *output = x->output;
+ float *buffer = x->buffer;
+ float *channel = x->channel;
+ float fframe = x->current_frame ;
+ float last_fpos = x->last_fpos ;
+ int framecount = x->framecount;
+ float mult = x->mult ;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland ;
+ float *c_lastphase_in = x->c_lastphase_in;
+ float *c_lastphase_out = x->c_lastphase_out;
+ float c_fundamental = x->c_fundamental;
+ float c_factor_in = x->c_factor_in;
+ float c_factor_out = x->c_factor_out;
+ float sync = x->sync;
+
+ sync = (float)x->frames_read / (float)x->framecount;
+
+ if(x->mute || x->lock){
+ while(n--){
+ *out++ = 0.0;
+ *sync_vec++ = sync;
+ }
+ return (w+6);
+ }
+
+ inCount += D;
+
+
+
+ if(x->read_me){
+ for ( j = 0 ; j < Nw - D ; j++ ){
+ input[j] = input[j+D];
+ }
+ if(x->playthrough){
+ for (j = Nw - D; j < Nw; j++) {
+ in_sample = input[j] = *in++;
+ *out++ = in_sample * 0.5; // scale down
+ *sync_vec++ = sync;
+ }
+ } else{
+ for (j = Nw - D; j < Nw; j++) {
+ input[j] = *in++;
+ *out++ = 0.0;
+ *sync_vec++ = sync;
+ }
+ }
+
+ fold( input, Wanal, Nw, buffer, N, inCount );
+ rdft( N, 1, buffer, bitshuffle, trigland );
+
+ convert( buffer, x->loveboat[(x->frames_read)++], N2, c_lastphase_in, c_fundamental, c_factor_in );
+ if(x->frames_read >= x->framecount){
+ x->read_me = 0;
+ }
+ }
+ else {
+ for( i = 0 ; i < N2; i++ ){
+ amp = i<<1;
+ freq = amp + 1 ;
+ iphase = frame_phase[i] ;
+ if( iphase < 0 )
+ iphase = 0;
+ if( iphase > framecount - 1 )
+ iphase = framecount - 1;
+ composite_frame[amp] = x->loveboat[iphase][amp];
+ composite_frame[freq] = x->loveboat[iphase][freq];
+ frame_phase[i] += frame_incr[i] ;
+ while( frame_phase[i] > framecount - 1)
+ frame_phase[i] -= framecount ;
+ while( frame_phase[i] < 0. )
+ frame_phase[i] += framecount ;
+ }
+
+ unconvert(composite_frame, buffer, N2, c_lastphase_out, c_fundamental, c_factor_out);
+
+ rdft( N, -1, buffer, bitshuffle, trigland );
+ overlapadd( buffer, N, Wsyn, output, Nw, inCount );
+
+ for (j = 0; j < D; j++){
+ *out++ = output[j] * mult;
+ *sync_vec++ = sync;
+ }
+ for (j = 0; j < Nw - D; j++){
+ output[j] = output[j+D];
+ }
+
+ for (j = Nw - D; j < Nw; j++){
+ output[j] = 0.;
+ }
+ }
+
+ /* restore state variables */
+
+ x->inCount = inCount %Nw;
+ x->current_frame = fframe;
+ x->last_fpos = last_fpos;
+ x->sync = sync;
+
+
+ return (w+6);
+}
+
+
+
+void resent_acquire_sample(t_resent *x)
+{
+ x->read_me = 1;
+ x->frames_read = 0;
+
+ return;
+}
+
+void resent_mute(t_resent *x, t_floatarg tog)
+{
+ x->mute = tog;
+}
+
+void resent_playthrough(t_resent *x, t_floatarg state)
+{
+ x->playthrough = state;
+}
+
+void resent_linephase(t_resent *x, t_symbol *msg, short argc, t_atom *argv)
+{
+ int bin1, bin2;
+ float phase1, phase2, bindiff;
+ int i;
+ float m1, m2;
+
+ bin1 = (int) atom_getfloatarg(0, argc, argv);
+ phase1 = atom_getfloatarg(1, argc, argv) * x->framecount;
+ bin2 = (int) atom_getfloatarg(2, argc, argv);
+ phase2 = atom_getfloatarg(3, argc, argv) * x->framecount;
+
+ if( bin1 > x->N2 || bin2 > x->N2 ){
+ error("too high bin number");
+ return;
+ }
+ bindiff = bin2 - bin1;
+ if( bindiff < 1 ){
+ error("make bin2 higher than bin 1, bye now");
+ return;
+ }
+ for( i = bin1; i < bin2; i++ ){
+ m2 = (float) i / bindiff;
+ m1 = 1. - m2;
+ x->frame_phase[i] = m1 * phase1 + m2 * phase2;
+ }
+}
+
+void resent_randphase(t_resent *x, t_symbol *msg, short argc, t_atom *argv)
+{
+
+ float minphase, maxphase;
+ int i;
+ int framecount = x->framecount;
+
+ minphase = atom_getfloatarg(0, argc, argv);
+ maxphase = atom_getfloatarg(1, argc, argv);
+
+// post("minphase %f maxphase %f",minphase, maxphase);
+ if(minphase < 0.0)
+ minphase = 0.0;
+ if( maxphase > 1.0 )
+ maxphase = 1.0;
+
+ for( i = 0; i < x->N2; i++ ){
+ x->frame_phase[i] = (int) (resent_randf( minphase, maxphase ) * (float) (framecount - 1) ) ;
+ }
+}
+
+void resent_randspeed(t_resent *x, t_symbol *msg, short argc, t_atom *argv)
+{
+
+ float minspeed, maxspeed;
+ int i;
+
+
+ minspeed = atom_getfloatarg(0, argc, argv);
+ maxspeed = atom_getfloatarg(1, argc, argv);
+
+ for( i = 0; i < x->N2; i++ ){
+ x->frame_incr[i] = resent_randf(minspeed, maxspeed);
+ }
+}
+
+void resent_linespeed(t_resent *x, t_symbol *msg, short argc, t_atom *argv)
+{
+ int bin1, bin2;
+ float speed1, speed2, bindiff;
+ int i;
+ float m1, m2;
+
+ bin1 = (int) atom_getfloatarg(0, argc, argv);
+ speed1 = atom_getfloatarg(1, argc, argv);
+ bin2 = (int) atom_getfloatarg(2, argc, argv);
+ speed2 = atom_getfloatarg(3, argc, argv);
+
+ if( bin1 > x->N2 || bin2 > x->N2 ){
+ error("too high bin number");
+ return;
+ }
+ bindiff = bin2 - bin1;
+ if( bindiff < 1 ){
+ error("make bin2 higher than bin 1, bye now");
+ return;
+ }
+ for( i = bin1; i < bin2; i++ ){
+ m2 = (float) i / bindiff;
+ m1 = 1. - m2;
+ x->frame_incr[i] = m1 * speed1 + m2 * speed2;
+ }
+}
+void resent_dsp(t_resent *x, t_signal **sp, short *count)
+{
+ if(x->R != sp[0]->s_sr || x->D != sp[0]->s_n){
+ x->R = sp[0]->s_sr;
+ x->D = sp[0]->s_n;
+ if(x->verbose)
+ post("new vector size: %d, new sampling rate:%d",x->D,x->R);
+ resent_init(x,1);
+ }
+ dsp_add(resent_perform, 5, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+float resent_randf(float min,float max)
+{
+ float rval;
+ rval = (float) (rand() % RAND_MAX) / (float) RAND_MAX;
+ return ( min + (max-min) * rval );
+}
diff --git a/residency_buffer~.c b/residency_buffer~.c
new file mode 100644
index 0000000..5082990
--- /dev/null
+++ b/residency_buffer~.c
@@ -0,0 +1,565 @@
+#ifndef PD
+
+#include "MSPd.h"
+#include "fftease.h"
+/* #include "buffer.h" */
+
+/* Not ported to Pd due to array/buffer difference */
+// #define FLEN 1024
+
+#if MSP
+void *resident_class;
+#endif
+
+#if PD
+static t_class *resident_class;
+#endif
+
+#define OBJECT_NAME "residency_buffer~"
+
+typedef struct _resident
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ float *buffer;
+ float *channel;
+ float *output;
+ float current_frame;
+ int framecount;
+ //
+ float frame_increment ;
+ float fpos;
+ float last_fpos;
+ float tadv;
+ // for convert
+ float *c_lastphase_in;
+ float *c_lastphase_out;
+ float c_fundamental;
+ float c_factor_in;
+ float c_factor_out;
+ // faster fft
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ int read_me;
+ int frames_read;
+ int MAXFRAMES;
+ short mute;
+ short in2_connected;
+ short in3_connected;
+ int buffer_frame_count;
+ // buffer
+ t_symbol *l_sym;
+ t_buffer *l_buf;
+ short initialized;
+ float *tmpframe;
+ int hopsize;
+ int overlap;
+ int winfac;
+ short playthrough;
+ float sync;
+ short buffer_is_hosed;
+} t_resident;
+
+void *resident_new(t_symbol *msg, short argc, t_atom *argv);
+t_int *offset_perform(t_int *w);
+t_int *resident_perform(t_int *w);
+void resident_dsp(t_resident *x, t_signal **sp, short *count);
+void resident_assist(t_resident *x, void *b, long m, long a, char *s);
+void resident_bangname ( t_resident *x ) ;
+void resident_meminfo( t_resident *x ) ;
+void resident_float(t_resident *x, double f) ;
+void resident_mute(t_resident *x, long toggle);
+void resident_calcbuf(t_resident *x, double desired_duration);
+void resident_dsp_free( t_resident *x );
+void resident_fftinfo(t_resident *x);
+void resident_winfac(t_resident *x, t_floatarg f);
+void resident_playthrough(t_resident *x, t_floatarg f);
+void resident_overlap(t_resident *x, t_floatarg f);
+resident_init(t_resident *x, short initialized);
+
+
+void main(void)
+{
+ setup((t_messlist **)&resident_class, (method)resident_new, (method)resident_dsp_free, (short)sizeof(t_resident), 0L, A_GIMME,0);
+ addmess((method)resident_dsp, "dsp", A_CANT, 0);
+ addmess((method)resident_assist,"assist",A_CANT,0);
+ addfloat((method) resident_float);
+ addbang( (method) resident_bangname );
+ addmess ((method)resident_mute, "mute", A_LONG, 0);
+ addmess ((method)resident_fftinfo, "meminfo", 0);
+ addmess ((method)resident_calcbuf, "calcbuf", A_FLOAT, 0);
+ addmess ((method)resident_winfac, "winfac", A_FLOAT, 0);
+ addmess ((method)resident_overlap, "overlap", A_FLOAT, 0);
+ addmess ((method)resident_playthrough, "playthrough", A_FLOAT, 0);
+ addmess ((method)resident_fftinfo, "fftinfo", 0);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+
+void resident_meminfo( t_resident *x )
+{
+ post("%d frames in buffer", x->buffer_frame_count);
+ post("frame_duration: %f, actual time in buffer: %f", x->tadv, (float)(x->buffer_frame_count) * x->tadv);
+ post("actual time in buffer: %f", (float)(x->buffer_frame_count) * x->tadv);
+}
+
+
+
+void resident_fftinfo(t_resident *x)
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+
+void resident_dsp_free( t_resident *x ){
+ dsp_free( (t_pxobject *) x);
+ freebytes(x->c_lastphase_in,0);
+ freebytes(x->c_lastphase_out,0);
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->input,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->buffer,0);
+ freebytes(x->channel,0);
+ freebytes(x->output,0);
+ freebytes(x->tmpframe,0);
+
+}
+
+void resident_calcbuf(t_resident *x, double desired_duration)
+{
+ float ms_calc;
+ float frames_needed;
+ float seconds;
+ float frames;
+ float samples;
+
+ seconds = desired_duration / 1000.0;
+ frames = seconds / x->tadv;
+ samples = frames * (float) (x->N + 2);
+ ms_calc = (samples / x->R) * 1000.0;
+ post("you need %.0f milliseconds in buffer to get %.0f frames", ms_calc, frames);
+
+}
+
+void resident_assist (t_resident *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0:
+ sprintf(dst,"(signal/bang) Input, Sampling Trigger");
+ break;
+ case 1:
+ sprintf(dst,"(signal/float) Frame Increment");
+ break;
+ case 2:
+ sprintf(dst,"(signal/float) Frame Position [0-1]");
+ break;
+
+ }
+ } else if (msg==2) {
+ switch(arg) {
+ case 1: sprintf(dst,"(signal) Output"); break;
+ case 2: sprintf(dst,"(signal) Record Sync"); break;
+ }
+ }
+}
+
+void *resident_new(t_symbol *msg, short argc, t_atom *argv)
+{
+ t_resident *x = (t_resident *)newobject(resident_class);
+
+ dsp_setup((t_pxobject *)x,3);
+ outlet_new((t_pxobject *)x, "signal");
+ outlet_new((t_pxobject *)x, "signal");
+
+ x->D = sys_getblksize();
+ x->R = sys_getsr();
+
+ /* args: bufname, overlap, winfac */
+
+ x->l_sym = atom_getsymarg(0, argc, argv);
+ x->overlap = atom_getintarg(1, argc, argv);
+ x->winfac = atom_getintarg(2, argc, argv);
+
+// post("argc is %d", argc); it is the number of arguments, not including name of external
+ if(argc < 1){
+ error("%s: you must provide the name of a valid buffer.",OBJECT_NAME);
+ x->x_obj.z_disabled = 1;
+ return 0; // kills object for good
+ } else {
+ x->x_obj.z_disabled = 0;
+ }
+
+ resident_init(x,0);
+ return (x);
+}
+
+resident_init(t_resident *x, short initialized)
+{
+ int i;
+ if(!power_of_two(x->overlap))
+ x->overlap = 4;
+ if(!power_of_two(x->winfac))
+ x->winfac = 1;
+
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->hopsize = x->D;
+ x->tadv = (float) x->D / (float) x->R;
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+ x->c_fundamental = (float) x->R/( (x->N2)<<1 );
+ x->c_factor_in = (float) x->R/((float)x->D * TWOPI);
+ x->c_factor_out =TWOPI * (float) x->D / (float) x->R;
+
+ if(!initialized){
+ x->mute = 0;
+ x->sync = 0;
+ x->initialized = 1;
+ x->current_frame = x->framecount = 0;
+ x->frame_increment = 1.0 ;
+ x->fpos = x->last_fpos = 0;
+ x->Wanal = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->Wsyn = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->Hwin = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->input = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->output = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->buffer = (float *) getbytes( MAX_N * sizeof(float) );
+ x->channel = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->tmpframe = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->bitshuffle = (int *) getbytes( (MAX_N * 2) * sizeof( int ) );
+ x->trigland = (float *) getbytes( (MAX_N * 2) * sizeof( float ) );
+ x->c_lastphase_in = (float *) getbytes( (MAX_N2+1) * sizeof(float) );
+ x->c_lastphase_out = (float *) getbytes( (MAX_N2+1) * sizeof(float) );
+ }
+
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ memset((char *)x->c_lastphase_in,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->c_lastphase_out,0,(x->N2+1) * sizeof(float));
+
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makewindows( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D);
+}
+
+t_int *resident_perform(t_int *w)
+{
+ float sample, outsamp ;
+ int index_offset;
+ int i, j;
+
+ //////////////////////////////////////////////
+ t_resident *x = (t_resident *) (w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *increment = (t_float *)(w[3]);
+ t_float *position = (t_float *)(w[4]);
+ t_float *out = (t_float *)(w[5]);
+ t_float *vec_sync = (t_float *)(w[6]);
+ t_int n = w[7];
+
+ /* dereference structure */
+
+ int inCount = x->inCount;
+ int R = x->R;
+ int N = x->N;
+ int N2 = x->N2;
+ int D = x->D;
+ int Nw = x->Nw;
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *input = x->input;
+ float *output = x->output;
+ float *buffer = x->buffer;
+ float *channel = x->channel;
+ float fframe = x->current_frame ;
+ float fincr = x->frame_increment;
+ float fpos = x->fpos;
+ float last_fpos = x->last_fpos ;
+ int framecount = x->framecount;
+ float sync = x->sync;
+
+
+ float mult = x->mult ;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland ;
+
+ float *c_lastphase_in = x->c_lastphase_in;
+ float *c_lastphase_out = x->c_lastphase_out;
+ float c_fundamental = x->c_fundamental;
+ float c_factor_in = x->c_factor_in;
+ float c_factor_out = x->c_factor_out;
+
+ float *tmpframe = x->tmpframe;
+
+ t_buffer *l_buf = x->l_buf;
+
+ int frames_read = x->frames_read;
+ int buffer_frame_count = x->buffer_frame_count;
+
+ if (x->in2_connected) {
+ fincr = *increment++;
+ }
+
+ if (x->in3_connected) {
+ fpos = *position++;
+ }
+
+ inCount += D;
+
+ if( (! x->initialized) || x->mute || x->x_obj.z_disabled ) {
+ for ( j = 0; j < D; j++ ){
+ *out++ = 0.0;
+ *vec_sync++ = sync;
+ }
+ return (w+8); // must be index of "n" + 1
+ }
+ if( x->read_me ) {
+ for ( j = 0 ; j < Nw - D ; j++ ){
+ input[j] = input[j+D];
+ }
+ for ( j = Nw - D; j < Nw; j++ ) {
+ input[j] = *in++;
+ }
+
+ fold( input, Wanal, Nw, buffer, N, inCount );
+ rdft( N, 1, buffer, bitshuffle, trigland );
+
+ convert( buffer, tmpframe, N2, c_lastphase_in, c_fundamental, c_factor_in );
+
+ index_offset = (N+2) * frames_read;
+
+ for( i = index_offset, j = 0; i < index_offset + N + 2; i++, j++ ){
+ l_buf->b_samples[i] = tmpframe[j];
+ }
+
+ ++frames_read;
+ // output empty buffers while reading
+ sync = (float)frames_read/(float)(x->buffer_frame_count);
+
+ if(x->playthrough){
+ for ( i=0, j = Nw - D; j < Nw; j++, i++ ) {
+ out[i] = input[j];
+ vec_sync[j] = sync;
+ }
+ } else {
+ for ( j = 0; j < D; j++ ){
+ out[j] = 0.0;
+ vec_sync[j] = sync;
+ }
+ }
+
+ if( frames_read >= x->buffer_frame_count){
+ x->read_me = 0;
+ // post("resident_buffer: data acquisition completed");
+ }
+
+ } else if (x->mute ) {
+ // Process Muted
+ for ( j = 0; j < D; j++ ){
+ out[j] = 0.0;
+ vec_sync[j] = sync;
+ }
+ }
+ else {
+
+ if( fpos < 0 )
+ fpos = 0;
+ if( fpos > 1 )
+ fpos = 1;
+ if( fpos != last_fpos ){
+ fframe = fpos * (float) buffer_frame_count ;
+ last_fpos = fpos;
+ }
+
+
+ fframe += fincr;
+ while( fframe >= buffer_frame_count ) {
+ fframe -= buffer_frame_count;
+ }
+ while( fframe < 0. ) {
+ fframe += buffer_frame_count ;
+ }
+
+ index_offset = (N+2) * (int) fframe;
+
+ for( i = index_offset, j = 0; i < index_offset + N + 2; i++, j++ ){
+ tmpframe[j] = l_buf->b_samples[i];
+ }
+ // REPLACE loveboat with buffer
+ unconvert( tmpframe, buffer, N2, c_lastphase_out, c_fundamental, c_factor_out );
+
+ rdft( N, -1, buffer, bitshuffle, trigland );
+ overlapadd( buffer, N, Wsyn, output, Nw, inCount );
+
+ for ( j = 0; j < D; j++ ){
+ *out++ = output[j] * mult;
+ }
+ for ( j = 0; j < Nw - D; j++ ){
+ output[j] = output[j+D];
+ }
+
+ for ( j = Nw - D; j < Nw; j++ ){
+ output[j] = 0.;
+ vec_sync[0] = sync;
+ }
+ }
+
+ /* restore state variables */
+
+ x->inCount = inCount % Nw;
+ x->current_frame = fframe;
+ x->frame_increment = fincr;
+ x->fpos = fpos;
+ x->last_fpos = last_fpos;
+ x->frames_read = frames_read;
+ x->sync = sync;
+
+ return (w+8);
+}
+void resident_float(t_resident *x, double f) // Look at floats at inlets
+{
+ // int inlet = ((t_pxobject*)x)->z_in;
+ int inlet = x->x_obj.z_in;
+ if (inlet == 1)
+ {
+ x->frame_increment = f;
+ }
+ else if (inlet == 2)
+ {
+ if (f < 0 ){
+ f = 0;
+ } else if(f > 1) {
+ f = 1.;
+ }
+ x->fpos = f;
+
+ }
+}
+void resident_bangname ( t_resident *x )
+{
+ // int i, j;
+
+ x->read_me = 1;
+ x->frames_read = 0;
+ // post("resident_buffer: beginning spectral data acquisition");
+ return;
+
+}
+
+void resident_mute(t_resident *x, long toggle)
+{
+ x->mute = (short)toggle;
+}
+
+void resident_playthrough(t_resident *x, t_floatarg toggle)
+{
+ x->playthrough = (short)toggle;
+}
+
+void resident_winfac(t_resident *x, t_floatarg f)
+{
+ int i = (int)f;
+
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = i;
+ resident_init(x,2);
+}
+
+void resident_overlap(t_resident *x, t_floatarg f)
+{
+ int i = (int) f;
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->overlap = i;
+ resident_init(x,1);
+}
+
+
+void resident_dsp(t_resident *x, t_signal **sp, short *count)
+{
+ long i;
+ int buffer_samples;
+ t_buffer *b;
+
+ x->in2_connected = count[1];
+ x->in3_connected = count[2];
+
+ if(x->R != sp[0]->s_sr || x->D != sp[0]->s_n){
+ x->R = sp[0]->s_sr;
+ x->D = sp[0]->s_n;
+ resident_init(x,1);
+ }
+ /*
+ post("value of disabled is: %d",x->x_obj.z_disabled);
+ post("value of initialized is: %d",x->initialized);
+ */
+/* if(x->l_sym->s_name == ""){
+ post("this buffer was not even dignified with a name");
+ } */
+ /*
+ if(!x->l_sym->s_thing){
+ error("residency_buffer~: not linked to a valid buffer");
+ } */
+// else if(!x->initialized){
+
+ if ((b = (t_buffer *)(x->l_sym->s_thing)) && ob_sym(b) == gensym("buffer~")) {
+ x->l_buf = b;
+ x->initialized = 1;
+ if( x->l_buf->b_nchans != 1 ){
+ error("resident_buffer~: buffer \"%s\" must have 1 channel, not %d", x->l_sym->s_name, x->l_buf->b_nchans);
+ x->x_obj.z_disabled = 1;
+ }
+ }
+ else {
+ error("%s: buffer \"%s\" not found",OBJECT_NAME, x->l_sym->s_name);
+ x->x_obj.z_disabled = 1;
+ }
+
+ if( ! x->x_obj.z_disabled ){
+ x->buffer_frame_count = (float) (x->l_buf->b_frames) / (float)(x->N + 2 );
+ }
+
+// }
+
+
+ dsp_add(resident_perform, 7, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,
+ sp[3]->s_vec, sp[4]->s_vec, sp[0]->s_n);
+
+}
+
+
+
+#endif /* PD */
diff --git a/residency~.c b/residency~.c
new file mode 100644
index 0000000..6e84938
--- /dev/null
+++ b/residency~.c
@@ -0,0 +1,592 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *residency_class;
+#endif
+
+#if PD
+static t_class *residency_class;
+#endif
+
+#define OBJECT_NAME "residency~"
+
+typedef struct _residency
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ float *buffer;
+ float *channel;
+ float *output;
+ float **loveboat;
+ float current_frame;
+ int framecount;
+ //
+ float frame_increment ;
+ float fpos;
+ float last_fpos;
+ float tadv;
+ // for convert
+ float *c_lastphase_in;
+ float *c_lastphase_out;
+ float c_fundamental;
+ float c_factor_in;
+ float c_factor_out;
+ // faster fft
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ int read_me;
+ int frames_read;
+ // int MAXFRAMES;
+ short mute;
+ short virgin;
+ short playthrough;
+ short in2_connected;
+ short in3_connected;
+ int overlap;
+ int winfac;
+ int hopsize;
+ // int windowsize;
+ float duration;
+ short lock;
+ short verbose;
+ short override;
+ float *input_vec;
+ float sync;
+} t_residency;
+
+void *residency_new(t_symbol *s, int argc, t_atom *argv);
+t_int *residency_perform(t_int *w);
+void residency_dsp(t_residency *x, t_signal **sp, short *count);
+void residency_assist(t_residency *x, void *b, long m, long a, char *s);
+void residency_bangname(t_residency *x) ;
+void residency_fftinfo(t_residency *x) ;
+void residency_playthrough( t_residency *x, t_floatarg tog) ;
+void residency_float(t_residency *x, double f) ;
+void residency_mute(t_residency *x, t_floatarg tog);
+void residency_free(t_residency *x);
+void residency_init(t_residency *x, short initialized);
+void residency_size(t_residency *x, t_floatarg newsize);
+void residency_winfac(t_residency *x, t_floatarg factor);
+void residency_overlap(t_residency *x, t_floatarg o);
+void residency_verbose(t_residency *x, t_floatarg t);
+void residency_acquire_sample(t_residency *x);
+void residency_meminfo( t_residency *x );
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&residency_class, (method)residency_new, (method)residency_free,
+ (short)sizeof(t_residency), 0L, A_GIMME,0);
+ addmess((method)residency_dsp, "dsp", A_CANT, 0);
+ addmess((method)residency_assist,"assist",A_CANT,0);
+ addfloat((method)residency_float);
+ addbang((method)residency_bangname);
+ addmess((method)residency_mute, "mute", A_FLOAT, 0);
+ addmess((method)residency_fftinfo, "fftinfo", 0);
+ addmess((method)residency_meminfo, "meminfo", 0);
+ addmess((method)residency_playthrough, "playthrough", A_DEFFLOAT, 0);
+ addmess((method)residency_size, "size", A_DEFFLOAT, 0);
+ addmess((method)residency_overlap, "overlap", A_DEFFLOAT, 0);
+ addmess((method)residency_winfac, "winfac", A_DEFFLOAT, 0);
+ addmess((method)residency_verbose, "verbose", A_DEFFLOAT, 0);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+#if PD
+void residency_tilde_setup(void)
+{
+ residency_class = class_new(gensym("residency~"), (t_newmethod)residency_new,
+ (t_method)residency_free ,sizeof(t_residency), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(residency_class, t_residency, x_f);
+ class_addmethod(residency_class,(t_method)residency_dsp,gensym("dsp"),0);
+ class_addmethod(residency_class,(t_method)residency_mute,gensym("mute"),A_FLOAT,0);
+ class_addmethod(residency_class,(t_method)residency_fftinfo,gensym("fftinfo"),0);
+ class_addmethod(residency_class,(t_method)residency_meminfo,gensym("meminfo"),0);
+ class_addmethod(residency_class,(t_method)residency_playthrough,gensym("playthrough"),A_FLOAT,0);
+ class_addmethod(residency_class,(t_method)residency_size,gensym("size"),A_FLOAT,0);
+ class_addmethod(residency_class,(t_method)residency_overlap,gensym("overlap"),A_FLOAT,0);
+ class_addmethod(residency_class,(t_method)residency_winfac,gensym("winfac"),A_FLOAT,0);
+ class_addmethod(residency_class,(t_method)residency_verbose,gensym("verbose"),A_FLOAT,0);
+ class_addmethod(residency_class,(t_method)residency_acquire_sample,gensym("acquire_sample"),0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+void residency_meminfo( t_residency *x )
+{
+ post("%d frames in buffer", x->framecount);
+ post("frame_duration: %f, actual time in buffer: %f", x->tadv, (float)(x->framecount) * x->tadv);
+
+}
+
+void residency_overlap(t_residency *x, t_floatarg f)
+{
+ int i = (int) f;
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->overlap = i;
+ residency_init(x,1);
+}
+
+void residency_winfac(t_residency *x, t_floatarg f)
+{
+ int i = (int)f;
+
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = i;
+ // post("called winfac");
+ residency_init(x,2);
+}
+
+void residency_fftinfo(t_residency *x)
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+void residency_verbose(t_residency *x, t_floatarg t)
+{
+ x->verbose = t;
+}
+
+void residency_size(t_residency *x, t_floatarg newsize)
+{
+ //protect with DACs off?
+
+ if(newsize > 0.0){//could be horrendous size, but that's the user's problem
+ x->duration = newsize/1000.0;
+ residency_init(x,1);
+ }
+}
+
+void residency_playthrough (t_residency *x, t_floatarg tog)
+{
+ x->playthrough = tog;
+}
+
+void residency_free(t_residency *x){
+ int i ;
+#if MSP
+ dsp_free((t_pxobject *)x);
+#endif
+ for(i = 0; i < x->framecount; i++){
+ freebytes(x->loveboat[i],0) ;
+ }
+ freebytes(x->loveboat,0);
+ freebytes(x->c_lastphase_in,0);
+ freebytes(x->c_lastphase_out,0);
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->input,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->buffer,0);
+ freebytes(x->channel,0);
+ freebytes(x->output,0);
+}
+
+
+
+void residency_init(t_residency *x, short initialized)
+{
+ int i;
+
+ int last_framecount = x->framecount;
+ x->lock = 1;
+ x->virgin = 1;
+
+ if(!x->winfac)
+ x->winfac = 1;
+ if(!x->overlap)
+ x->overlap = 4;
+ if(!x->R)
+ x->R = 44100;
+ if(!x->D)
+ x->D = 256;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+ x->current_frame = 0;
+ x->fpos = x->last_fpos = 0;
+ x->tadv = (float)x->D/(float)x->R;
+ x->c_fundamental = (float)x->R/((x->N2)<<1);
+ x->c_factor_in = (float) x->R/((float)x->D * TWOPI);
+ x->c_factor_out = TWOPI * (float)x->D / (float)x->R;
+
+ if( x->duration <= 0 ){
+ x->duration = 1.0;
+ }
+
+ x->framecount = x->duration / x->tadv ;
+ x->hopsize = x->N / x->overlap;
+ x->read_me = 0;
+
+ if(!initialized){
+ x->sync = 0;
+ x->mute = 0;
+ x->in2_connected = 0;
+ x->in3_connected = 0;
+ x->playthrough = 0;
+ x->frame_increment = 1.0;
+ x->verbose = 0;
+
+
+ x->Wanal = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Wsyn = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Hwin = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->input = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->output = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->buffer = (float *) getbytes( MAX_N * sizeof(float) );
+ x->channel = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->bitshuffle = (int *) getbytes( MAX_N * 2 * sizeof( int ) );
+ x->trigland = (float *) getbytes( MAX_N * 2 * sizeof( float ) );
+ x->c_lastphase_in = (float *) getbytes( (MAX_N2+1) * sizeof(float) );
+ x->c_lastphase_out = (float *) getbytes( (MAX_N2+1) * sizeof(float) );
+
+ x->input_vec = (float *) getbytes(8192 * sizeof(float));
+ x->loveboat = (float **) getbytes(x->framecount * sizeof(float *));
+ for(i=0;i<x->framecount;i++){
+ x->loveboat[i] = (float *) getbytes(((x->N)+2) * sizeof(float));
+ if(x->loveboat[i] == NULL){
+ error("memory error");
+ return;
+ }
+ memset((char *)x->loveboat[i],0,(x->N+2)*sizeof(float));
+ }
+ } else if(initialized == 1){
+
+ for(i = 0; i < last_framecount; i++){
+ freebytes(x->loveboat[i],0) ;
+ }
+ freebytes(x->loveboat,0);
+ x->loveboat = (float **) getbytes(x->framecount * sizeof(float *));
+ for(i=0;i<x->framecount;i++){
+ x->loveboat[i] = (float *) getbytes((x->N+2) * sizeof(float));
+ if(x->loveboat[i] == NULL){
+ error("memory error");
+ return;
+ }
+ memset((char *)x->loveboat[i],0,(x->N+2)*sizeof(float));
+ }
+ }
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ memset((char *)x->c_lastphase_in,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->c_lastphase_out,0,(x->N2+1) * sizeof(float));
+
+ makewindows( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D);
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+
+ x->lock = 0;
+}
+
+void *residency_new(t_symbol *s, int argc, t_atom *argv)
+{
+#if MSP
+ t_residency *x = (t_residency *)newobject(residency_class);
+ dsp_setup((t_pxobject *)x,3);
+ outlet_new((t_pxobject *)x, "signal");
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+
+#if PD
+ t_residency *x = (t_residency *)pd_new(residency_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+ // x->x_obj.z_misc |= Z_NO_INPLACE;
+ x->duration = atom_getfloatarg(0,argc,argv)/1000.0;
+ x->overlap = atom_getfloatarg(1,argc,argv);
+ x->winfac = atom_getfloatarg(2,argc,argv);
+
+ x->D = sys_getblksize();
+ x->R = sys_getsr();
+
+ residency_init(x,0);
+
+ return (x);
+}
+
+t_int *residency_perform(t_int *w)
+{
+ int i, j;
+ float sample;
+
+ //////////////////////////////////////////////
+ t_residency *x = (t_residency *) (w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *increment = (t_float *)(w[3]);
+ t_float *position = (t_float *)(w[4]);
+ t_float *out = (t_float *)(w[5]);
+ t_float *vec_sync = (t_float *) (w[6]);
+ t_int n = w[7];
+
+ int inCount = x->inCount;
+ int R = x->R;
+ int N = x->N;
+ int N2 = x->N2;
+ int D = x->D;
+ int Nw = x->Nw;
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *input = x->input;
+ float *output = x->output;
+ float *buffer = x->buffer;
+ float *channel = x->channel;
+ float *input_vec = x->input_vec;
+ float fframe = x->current_frame ;
+ float last_fpos = x->last_fpos ;
+ int framecount = x->framecount;
+ float fincr = x->frame_increment;
+ float fpos = x->fpos;
+ float mult = x->mult;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland ;
+ float *c_lastphase_in = x->c_lastphase_in;
+ float *c_lastphase_out = x->c_lastphase_out;
+ float c_fundamental = x->c_fundamental;
+ float c_factor_in = x->c_factor_in;
+ float c_factor_out = x->c_factor_out;
+ float sync = x->sync;
+
+ if(x->lock || x->mute){
+ while(n--){
+ *out++ = 0.0;
+ *vec_sync++ = sync;
+ }
+ return (w+8);
+ }
+
+#if MSP
+ if (x->in2_connected) {
+ fincr = *increment;
+ }
+ if (x->in3_connected) {
+ fpos = *position;
+ }
+#endif
+
+#if PD
+ fincr = *increment;
+ fpos = *position;
+#endif
+
+ inCount += D;
+
+ for(i = 0; i < D; i++){
+ input_vec[i] = in[i];
+ }
+ if(x->read_me) {
+ for ( j = 0 ; j < Nw - D ; j++ ){
+ input[j] = input[j+D];
+ }
+ for (i = 0,j = Nw - D; j < Nw; j++, i++) {
+ input[j] = input_vec[i];
+ }
+ if(framecount > 0)
+ sync = (float)x->frames_read/(float)framecount;
+
+
+ if( x->playthrough ){
+ for ( i = 0, j = Nw - D; j < Nw; j++, i++ ) {
+ out[i] = input_vec[i] * 0.5;
+ vec_sync[i] = sync;
+ }
+ }
+ else {
+ for ( j = 0; j < D; j++ ){
+ out[j] = 0.0;
+ vec_sync[j] = sync;
+ }
+ }
+
+ fold(input, Wanal, Nw, buffer, N, inCount);
+ rdft(N, 1, buffer, bitshuffle, trigland);
+
+
+ if(x->frames_read >= framecount){
+ x->read_me = 0;
+ if(x->verbose){
+ post("residency: data acquisition completed");
+ }
+ } else {
+ convert(buffer, x->loveboat[(x->frames_read)++], N2, c_lastphase_in, c_fundamental, c_factor_in);
+ }
+ x->virgin = 0;
+ }
+ else if(x->playthrough && x->virgin){
+ for(i=0;i<D;i++){
+ sync = 0;
+ sample = input_vec[i] * 0.5;
+ out[i] = sample;
+ vec_sync[i] = sync;
+ }
+ }
+ else {
+ //sync = 1.0;
+
+ if(fpos < 0)
+ fpos = 0;
+ if(fpos > 1)
+ fpos = 1;
+ if(fpos != last_fpos){
+ fframe = fpos * (float) framecount ;
+ last_fpos = fpos;
+ }
+
+
+ fframe += fincr;
+ while(fframe >= framecount) {
+ fframe -= framecount;
+ }
+ while( fframe < 0. ) {
+ fframe += framecount ;
+ }
+
+ unconvert(x->loveboat[(int) fframe ], buffer, N2, c_lastphase_out, c_fundamental, c_factor_out);
+
+ rdft( N, -1, buffer, bitshuffle, trigland );
+ overlapadd( buffer, N, Wsyn, output, Nw, inCount );
+
+ for(i = 0; i < D; i++){
+ vec_sync[i] = sync;
+ }
+ for ( j = 0; j < D; j++ ){
+ out[j] = output[j] * mult;
+ }
+ for ( j = 0; j < Nw - D; j++ ){
+ output[j] = output[j+D];
+ }
+
+ for ( j = Nw - D; j < Nw; j++ ){
+ output[j] = 0.;
+ }
+
+ }
+
+ /* restore state variables */
+
+ x->inCount = inCount % Nw;
+ x->current_frame = fframe;
+ x->frame_increment = fincr;
+ x->fpos = fpos;
+ x->last_fpos = last_fpos;
+ x->sync = sync;
+ return (w+8);
+}
+
+#if MSP
+void residency_float(t_residency *x, double f) // Look at floats at inlets
+{
+ int inlet = x->x_obj.z_in;
+
+ if (inlet == 1)
+ {
+ x->frame_increment = f;
+ }
+ else if (inlet == 2)
+ {
+ if (f < 0 ){
+ f = 0;
+ } else if(f > 1) {
+ f = 1.;
+ }
+ x->fpos = f;
+
+ }
+}
+#endif
+
+void residency_acquire_sample(t_residency *x)
+{
+ x->read_me = 1;
+ x->frames_read = 0;
+ post("beginning spectral data acquisition");
+ return;
+}
+
+void residency_bangname (t_residency *x)
+{
+ x->read_me = 1;
+ x->frames_read = 0;
+ if(x->verbose)
+ post("beginning spectral data acquisition");
+ return;
+}
+
+void residency_mute(t_residency *x, t_floatarg tog)
+{
+ x->mute = tog;
+}
+
+void residency_dsp(t_residency *x, t_signal **sp, short *count)
+{
+#if MSP
+ x->in2_connected = count[1];
+ x->in3_connected = count[2];
+#endif
+
+ if(x->R != sp[0]->s_sr || x->D != sp[0]->s_n){
+ x->R = sp[0]->s_sr;
+ x->D = sp[0]->s_n;
+ if(x->verbose)
+ post("new vsize: %d, new SR:%d",x->D,x->R);
+ residency_init(x,1);
+ }
+
+ dsp_add(residency_perform, 7, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,
+ sp[3]->s_vec, sp[4]->s_vec, sp[0]->s_n);
+}
+
+void residency_assist(t_residency *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0: sprintf(dst,"(signal/bang) Input, Sampling Trigger"); break;
+ case 1: sprintf(dst,"(signal/float) Frame Increment");break;
+ case 2:sprintf(dst,"(signal/float) Frame Position [0-1]");break;
+
+ }
+ } else if (msg==2) {
+ switch(arg){
+ case 0: sprintf(dst,"(signal) Output"); break;
+ case 1: sprintf(dst,"(signal) Recording Sync"); break;
+ }
+ }
+}
diff --git a/scrape~.c b/scrape~.c
new file mode 100644
index 0000000..bd435f7
--- /dev/null
+++ b/scrape~.c
@@ -0,0 +1,494 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+
+#if MSP
+void *scrape_class;
+#endif
+
+#if PD
+static t_class *scrape_class;
+#endif
+
+#define OBJECT_NAME "scrape~"
+
+typedef struct _scrape
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ float *buffer;
+ float *channel;
+ float *output;
+ //
+ float knee;
+ float cutoff;
+ float scrape_mult;
+ float thresh1;
+ float thresh2;
+ float *threshfunc;
+ short connected[8];
+ short mute;
+ short bypass;
+ //
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ int overlap;//overlap factor
+ int winfac;//window factor
+ int vs;//vector size
+} t_scrape;
+
+void *scrape_new(t_symbol *msg, short argc, t_atom *argv);
+t_int *offset_perform(t_int *w);
+t_int *scrape_perform(t_int *w);
+void scrape_dsp(t_scrape *x, t_signal **sp, short *count);
+void scrape_assist(t_scrape *x, void *b, long m, long a, char *s);
+void scrape_float(t_scrape *x, double f) ;
+void update_thresh_function( t_scrape *x );
+void scrape_frowned( float *S, float *C, float *threshfunc, float fmult, int N2 );
+void scrape_mute(t_scrape *x, t_floatarg toggle);
+void scrape_bypass(t_scrape *x, t_floatarg toggle);
+void scrape_dsp_free( t_scrape *x );
+void update_thresh_function( t_scrape *x );
+void scrape_init(t_scrape *x, short initialized);
+void scrape_fftinfo(t_scrape *x);
+void scrape_overlap(t_scrape *x, t_floatarg f);
+void scrape_winfac(t_scrape *x, t_floatarg f);
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **) &scrape_class, (method)scrape_new, (method)scrape_dsp_free,
+ (short)sizeof(t_scrape), 0, A_GIMME, 0);
+ addmess((method)scrape_dsp, "dsp", A_CANT, 0);
+ addmess((method)scrape_assist,"assist",A_CANT,0);
+ addmess ((method)scrape_mute, "mute", A_FLOAT, 0);
+ addmess ((method)scrape_bypass, "bypass", A_FLOAT, 0);
+ addmess((method)scrape_overlap,"overlap",A_DEFFLOAT,0);
+ addmess((method)scrape_winfac,"winfac",A_DEFFLOAT,0);
+ addmess((method)scrape_fftinfo,"fftinfo",0); addfloat((method) scrape_float);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+#if PD
+void scrape_tilde_setup(void)
+{
+ scrape_class = class_new(gensym("scrape~"), (t_newmethod)scrape_new,
+ (t_method)scrape_dsp_free ,sizeof(t_scrape), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(scrape_class, t_scrape, x_f);
+ class_addmethod(scrape_class, (t_method)scrape_dsp, gensym("dsp"), 0);
+ class_addmethod(scrape_class, (t_method)scrape_assist, gensym("assist"), 0);
+ class_addmethod(scrape_class, (t_method)scrape_mute, gensym("mute"), A_DEFFLOAT,0);
+ class_addmethod(scrape_class, (t_method)scrape_bypass, gensym("bypass"), A_DEFFLOAT,0);
+ class_addmethod(scrape_class, (t_method)scrape_overlap, gensym("overlap"), A_DEFFLOAT,0);
+ class_addmethod(scrape_class,(t_method)scrape_winfac,gensym("winfac"),A_FLOAT,0);
+ class_addmethod(scrape_class,(t_method)scrape_fftinfo,gensym("fftinfo"),0);
+
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+
+void scrape_dsp_free( t_scrape *x )
+{
+#if MSP
+ dsp_free( (t_pxobject *) x);
+#endif
+
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->input,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->buffer,0);
+ freebytes(x->channel,0);
+ freebytes(x->output,0);
+ freebytes(x->threshfunc,0);
+}
+
+void scrape_assist (t_scrape *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0: sprintf(dst,"(signal) Input ");break;
+ case 1: sprintf(dst,"(float/signal) Knee Frequency"); break;
+ case 2: sprintf(dst,"(float/signal) Cutoff Frequency"); break;
+ case 3: sprintf(dst,"(float/signal) Knee Threshold"); break;
+ case 4: sprintf(dst,"(float/signal) Cutoff Threshold"); break;
+ case 5: sprintf(dst,"(float/signal) Multiplier For Weak Bins"); break;
+ }
+ } else if (msg==2) {
+ sprintf(dst,"(signal) Output");
+ }
+}
+
+void *scrape_new(t_symbol *msg, short argc, t_atom *argv)
+{
+#if MSP
+ t_scrape *x = (t_scrape *)newobject(scrape_class);
+ dsp_setup((t_pxobject *)x,6);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+#if PD
+ int i;
+ t_scrape *x = (t_scrape *)pd_new(scrape_class);
+ for(i=0;i<5;i++)
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+ x->knee = atom_getfloatarg(0, argc, argv);
+ x->cutoff = atom_getfloatarg(1, argc, argv);
+ x->thresh1 = atom_getfloatarg(2, argc, argv);
+ x->thresh2 = atom_getfloatarg(3, argc, argv);
+ x->scrape_mult = atom_getfloatarg(4, argc, argv);
+ x->overlap = atom_getfloatarg(5, argc, argv);
+ x->winfac = atom_getfloatarg(6, argc, argv);
+ if(x->knee <= 0)
+ x->knee = 1000.0;
+ if(x->cutoff <= 0)
+ x->cutoff = 4000.0;
+ if(x->thresh1 <= 0)
+ x->thresh1 = .0001 ;
+ if(x->thresh2 <= 0)
+ x->thresh2 = .09 ;
+ if( x->scrape_mult < 0 || x->scrape_mult > 10 ){
+ x->scrape_mult = 0.1;
+ }
+ if(!power_of_two(x->overlap))
+ x->overlap = 4;
+ if(!power_of_two(x->winfac))
+ x->winfac = 1;
+
+ x->vs = sys_getblksize();
+ x->R = sys_getsr();
+ scrape_init(x,0);
+ return (x);
+}
+
+void scrape_init(t_scrape *x, short initialized)
+{
+ int i;
+
+ x->D = x->vs;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+
+ if(!initialized){
+ x->mute = 0;
+
+ x->Wanal = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Wsyn = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Hwin = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->input = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->output = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->buffer = (float *) getbytes( MAX_N * sizeof(float) );
+ x->channel = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->bitshuffle = (int *) getbytes( MAX_N * 2 * sizeof( int ) );
+ x->trigland = (float *) getbytes( MAX_N * 2 * sizeof( float ) );
+ x->threshfunc = (float *) getbytes(MAX_N2 * sizeof(float));
+ }
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ makehanning( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 0);
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ if(initialized != 2)
+ update_thresh_function(x);
+}
+
+void scrape_overlap(t_scrape *x, t_floatarg f)
+{
+ int i = (int) f;
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->overlap = i;
+ scrape_init(x,1);
+}
+
+void scrape_winfac(t_scrape *x, t_floatarg f)
+{
+ int i = (int)f;
+
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = i;
+ scrape_init(x,2);
+}
+
+void scrape_fftinfo(t_scrape *x)
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+#if MSP
+void scrape_float(t_scrape *x, double f) // Look at floats at inlets
+{
+ int inlet = x->x_obj.z_in;
+
+ if (inlet == 1)
+ {
+ if( f> 50 && f < 18000) {
+ x->knee = f ;
+ update_thresh_function( x );
+ }
+
+ }
+ else if (inlet == 2)
+ {
+ if( (f > x->knee) && (f < 20000) ) {
+ x->cutoff = f ;
+ update_thresh_function( x );
+ }
+ }
+ else if (inlet == 3)
+ {
+ x->thresh1 = f;
+ update_thresh_function( x );
+ }
+ else if (inlet == 4)
+ {
+ x->thresh2 = f;
+ update_thresh_function( x );
+ }
+ else if (inlet == 5)
+ {
+ if( f > 0 ) {
+ x->scrape_mult = f;
+ }
+ }
+}
+#endif
+void update_thresh_function( t_scrape *x )
+{
+ float funda, curfreq, m1, m2;
+ int i;
+
+ funda = (float) x->R / ((float)x->N * 2.0 );
+ curfreq = funda ;
+ for( i = 0; i < x->N2; i++ ) {
+ if( curfreq < x->knee ){
+ x->threshfunc[i] = 0.0 ;
+ } else if( curfreq >= x->knee && curfreq < x->cutoff ) {
+ m2 = (x->knee - curfreq) / (x->cutoff - x->knee) ;
+ m1 = 1.0 - m2 ;
+ x->threshfunc[i] = m1 * x->thresh1 + m2 * x->thresh2 ;
+ } else {
+ x->threshfunc[i] = x->thresh2;
+ }
+ curfreq += funda ;
+ }
+}
+
+void scrape_mute(t_scrape *x, t_floatarg toggle)
+{
+ x->mute = (short)toggle;
+}
+
+void scrape_bypass(t_scrape *x, t_floatarg toggle)
+{
+ x->bypass = (short)toggle;
+}
+
+
+t_int *scrape_perform(t_int *w)
+{
+ float sample, outsamp ;
+
+
+
+ int i,j;
+ float tmp ;
+
+ short update = 0;
+
+ t_scrape *x = (t_scrape *) (w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *knee_freq = (t_float *)(w[3]);
+ t_float *cut_freq = (t_float *)(w[4]);
+ t_float *thresh1 = (t_float *)(w[5]);
+ t_float *thresh2 = (t_float *)(w[6]);
+ t_float *scrape_mult = (t_float *)(w[7]);
+ t_float *out = (t_float *)(w[8]);
+ t_int n = w[9];
+
+ int inCount = x->inCount;
+ int R = x->R;
+ int N = x->N;
+ int N2 = x->N2;
+ int D = x->D;
+ int Nw = x->Nw;
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *input = x->input;
+ float *output = x->output;
+ float *buffer = x->buffer;
+ float *channel = x->channel;
+ float mult = x->mult ;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland ;
+ float *threshfunc = x->threshfunc ;
+ short *connected = x->connected;
+
+ if( x->mute ){
+ while( n-- ){
+ *out++ = 0.0;
+ }
+ return (w+10); // always what dsp_add says + 1
+ }
+ if( x->bypass ){
+ while( n-- ){
+ *out++ = *in++ * 0.5; // gain compensation
+ }
+ return (w+10); // always what dsp_add says + 1
+ }
+ if( connected[1] ){
+ tmp = *knee_freq++;
+ if( tmp > 50 && tmp < 20000 ){
+ x->knee = tmp;
+ update = 1;
+ }
+ }
+ if( connected[2] ){
+ tmp = *cut_freq++;
+ if( tmp > x->knee && tmp < 20000 ){
+ x->cutoff = *cut_freq++;
+ update = 1;
+ }
+ }
+ if( connected[3] ){
+ x->thresh1 = *thresh1++ ;
+ update = 1;
+ }
+ if( connected[4] ){
+ x->thresh2 = *thresh2++ ;
+ update = 1;
+ }
+ if( connected[5] ){
+ x->scrape_mult = *scrape_mult++ ;
+ }
+
+ if( update ){
+ update_thresh_function( x );
+ }
+
+ x->inCount += D;
+
+ for ( j = 0 ; j < Nw - D ; j++ ){
+ input[j] = input[j+D];
+ }
+ for ( j = Nw - D; j < Nw; j++ ) {
+ input[j] = *in++;
+ }
+
+ fold( input, Wanal, Nw, buffer, N, inCount );
+ rdft( N, 1, buffer, bitshuffle, trigland );
+
+ scrape_frowned( buffer, channel, threshfunc, x->scrape_mult, N2 );
+
+ rdft( N, -1, buffer, bitshuffle, trigland );
+ overlapadd( buffer, N, Wsyn, output, Nw, inCount);
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+ return (w+10); // always what dsp_add says + 1
+}
+
+
+
+void scrape_frowned( float *S, float *C, float *threshfunc, float fmult, int N2 )
+
+{
+ int real, imag, amp, phase;
+ float a, b;
+ int i;
+ float maxamp = 1.;
+
+ for( i = 0; i <= N2; i++ ){
+ amp = i<<1;
+ if( maxamp < C[amp] ){
+ maxamp = C[amp];
+ }
+ }
+
+ for ( i = 0; i <= N2; i++ ) {
+ imag = phase = ( real = amp = i<<1 ) + 1;
+ a = ( i == N2 ? S[1] : S[real] );
+ b = ( i == 0 || i == N2 ? 0. : S[imag] );
+ C[amp] = hypot( a, b );
+
+ if ( (C[amp]) < threshfunc[i] * maxamp ){
+ C[amp] *= fmult;
+ }
+ C[phase] = -atan2( b, a );
+ }
+
+ for ( i = 0; i <= N2; i++ ) {
+ imag = phase = ( real = amp = i<<1 ) + 1;
+ S[real] = *(C+amp) * cos( *(C+phase) );
+ if ( i != N2 )
+ S[imag] = -*(C+amp) * sin( *(C+phase) );
+ }
+}
+
+void scrape_dsp(t_scrape *x, t_signal **sp, short *count)
+{
+ long i;
+#if MSP
+ for( i = 0; i < 6; i++ ){
+ x->connected[i] = count[i];
+ }
+#endif
+#if PD
+ for( i = 0; i < 6; i++ ){
+ x->connected[i] = 1;
+ }
+#endif
+ if(x->vs != sp[0]->s_n || x->R != sp[0]->s_sr){
+ x->vs = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ scrape_init(x,1);
+ }
+ dsp_add(scrape_perform, 9, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec,
+ sp[4]->s_vec, sp[5]->s_vec,
+ sp[6]->s_vec, sp[0]->s_n);
+}
+
diff --git a/shapee~.c b/shapee~.c
new file mode 100644
index 0000000..95a19d8
--- /dev/null
+++ b/shapee~.c
@@ -0,0 +1,506 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *shapee_class;
+#endif
+
+#if PD
+static t_class *shapee_class;
+#endif
+
+#define OBJECT_NAME "shapee~"
+
+typedef struct _shapee
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ int widthConnected;
+ int *bitshuffle;
+
+ float shapeWidth;
+ float *Wanal;
+ float *Wsyn;
+ float *inputOne;
+ float *inputTwo;
+ float *Hwin;
+ float *bufferOne;
+ float *bufferTwo;
+ float *channelOne;
+ float *channelTwo;
+ float *output;
+ float mult;
+ float *trigland;
+ int overlap;//overlap factor
+ int winfac;// window factor
+ int vs;//last measurement of vector size
+ short mute;
+} t_shapee;
+
+
+/* msp function prototypes */
+
+void *shapee_new(t_symbol *s, int argc, t_atom *argv);
+t_int *shapee_perform(t_int *w);
+void shapee_dsp(t_shapee *x, t_signal **sp, short *count);
+void shapee_float(t_shapee *x, double myFloat);
+void shapee_assist(t_shapee *x, void *b, long m, long a, char *s);
+void shapee_init(t_shapee *x, short initialized);
+void shapee_mute(t_shapee *x, t_floatarg state);
+void shapee_free(t_shapee *x);
+void shapee_overlap(t_shapee *x, t_floatarg o);
+void shapee_winfac(t_shapee *x, t_floatarg wf);
+void shapee_fftinfo(t_shapee *x);
+
+/* first calling */
+
+/* float input handling routine for shape width */
+#if MSP
+void shapee_float( t_shapee *x, double myFloat )
+{
+
+ if ( x->x_obj.z_in == 2 ) {
+
+ if ( myFloat >= 1. && myFloat <= (double) x->N )
+ x->shapeWidth = (float)myFloat;
+ }
+}
+
+void main(void)
+{
+ setup( (t_messlist **) &shapee_class, (method) shapee_new,
+ (method) shapee_free, (short) sizeof(t_shapee), 0, A_GIMME, 0);
+
+ addmess((method)shapee_dsp, "dsp", A_CANT, 0);
+ addmess((method)shapee_assist,"assist",A_CANT,0);
+ addfloat((method)shapee_float);
+ addmess((method)shapee_mute,"mute",A_FLOAT,0);
+ addmess((method)shapee_overlap,"overlap",A_FLOAT,0);
+ addmess((method)shapee_winfac,"winfac",A_FLOAT,0);
+ addmess((method)shapee_fftinfo,"fftinfo",0);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+ }
+#endif
+
+#if PD
+void shapee_tilde_setup(void)
+{
+ shapee_class = class_new(gensym("shapee~"), (t_newmethod)shapee_new,
+ (t_method)shapee_free ,sizeof(t_shapee), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(shapee_class, t_shapee, x_f);
+ class_addmethod(shapee_class, (t_method)shapee_dsp, gensym("dsp"), 0);
+ class_addmethod(shapee_class, (t_method)shapee_mute, gensym("mute"), A_DEFFLOAT,0);
+ class_addmethod(shapee_class, (t_method)shapee_overlap, gensym("overlap"), A_DEFFLOAT,0);
+ class_addmethod(shapee_class, (t_method)shapee_winfac, gensym("winfac"), A_DEFFLOAT,0);
+ class_addmethod(shapee_class, (t_method)shapee_fftinfo, gensym("fftinfo"),0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+
+
+/* diagnostic messages for Max */
+
+void shapee_assist (t_shapee *x, void *b, long msg, long arg, char *dst)
+{
+
+ if (msg == 1) {
+ switch (arg) {
+ case 0: sprintf(dst,"(signal) Frequency Reference");break;
+ case 1: sprintf(dst,"(signal) Amplitude Reference");break;
+ case 2: sprintf(dst,"(signal/float) Shape Width"); break;
+ }
+ }
+
+ else {
+
+ if (msg == 2)
+ sprintf(dst,"(signal) Output");
+ }
+}
+
+
+void *shapee_new(t_symbol *s, int argc, t_atom *argv)
+{
+
+#if MSP
+ t_shapee *x = (t_shapee *) newobject(shapee_class);
+ dsp_setup((t_pxobject *)x, 3);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+#if PD
+ t_shapee *x = (t_shapee *)pd_new(shapee_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+/* INITIALIZATIONS */
+ x->overlap = atom_getfloatarg(0,argc,argv);
+ x->winfac = atom_getfloatarg(1,argc,argv);
+ if(!x->winfac)
+ x->winfac = 1;
+ if(!x->overlap)
+ x->overlap = 4;
+ x->vs = sys_getblksize();
+ x->R = sys_getsr();
+ shapee_init(x,0);
+
+ return (x);
+}
+
+void shapee_init(t_shapee *x, short initialized)
+{
+ int i;
+ x->D = x->vs;
+ x->N = x->vs * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+
+ if(!initialized){
+ x->mute = 0;
+
+ x->Wanal = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->Wsyn = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->Hwin = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->inputOne = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->inputTwo = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->bufferOne = (float *) getbytes( MAX_N * sizeof(float) );
+ x->bufferTwo = (float *) getbytes( MAX_N * sizeof(float) );
+ x->channelOne = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->channelTwo = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->output = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->bitshuffle = (int *) getbytes( MAX_N * 2 * sizeof( int ) );
+ x->trigland = (float *) getbytes( MAX_N * 2 * sizeof( float ) );
+ }
+ memset((char *)x->inputOne,0,x->Nw * sizeof(float));
+ memset((char *)x->inputTwo,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+
+ init_rdft(x->N, x->bitshuffle, x->trigland);
+ makehanning(x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 1);// wants an ODD window
+}
+
+void shapee_fftinfo(t_shapee *x)
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+void shapee_mute(t_shapee *x, t_floatarg state)
+{
+ x->mute = (short)state;
+}
+
+void shapee_overlap(t_shapee *x, t_floatarg o)
+{
+int test = (int) o;
+ if(!power_of_two(test)){
+ post("%d is not a power of two",test);
+ return;
+ }
+ x->overlap = test;
+ shapee_init(x,1);
+}
+
+void shapee_winfac(t_shapee *x, t_floatarg wf)
+{
+int test = (int) wf;
+if(!power_of_two(test)){
+ post("%d is not a power of two",test);
+ return;
+}
+x->winfac = test;
+shapee_init(x,1);
+
+}
+
+t_int *shapee_perform(t_int *w)
+{
+
+ int n,
+ i,j,
+ inCount,
+ R,
+ N,
+ N2,
+ D,
+ Nw,
+ invert = 1,
+ shapeWidth,
+ remainingWidth,
+ even, odd,
+ *bitshuffle;
+
+ float maxamp,
+ threshMult = 1.,
+ mult,
+ a1, b1,
+ a2, b2,
+ *inputOne,
+ *inputTwo,
+ *bufferOne,
+ *bufferTwo,
+ *output,
+ *Wanal,
+ *Wsyn,
+ *channelOne,
+ *channelTwo,
+ *trigland;
+
+ t_float *inOne,
+ *inTwo,
+ *inShape,
+ *out;
+
+
+/* get our inlets and outlets */
+
+ t_shapee *x = (t_shapee *) (w[1]);
+ inOne = (t_float *) (w[2]);
+ inTwo = (t_float *) (w[3]);
+ inShape = (t_float *) (w[4]);
+ out = (t_float *)(w[5]);
+ n = (t_int) (w[6]);
+
+/* get our shapeWidth -- from either a signal our float input */
+#if MSP
+ shapeWidth = x->widthConnected ? (int) *inShape : (int) x->shapeWidth;
+#endif
+#if PD
+ shapeWidth = (int) *inShape;
+#endif
+
+/* dereference structure */
+if(x->mute){
+ while(n--) *out++ = 0.0;
+ return w+7;
+}
+
+ inputOne = x->inputOne;
+ inputTwo = x->inputTwo;
+ bufferOne = x->bufferOne;
+ bufferTwo = x->bufferTwo;
+ inCount = x->inCount;
+ R = x->R;
+ N = x->N;
+ N2 = x->N2;
+ D = x->D;
+ Nw = x->Nw;
+ Wanal = x->Wanal;
+ Wsyn = x->Wsyn;
+ output = x->output;
+ channelOne = x->channelOne;
+ channelTwo = x->channelTwo;
+ bitshuffle = x->bitshuffle;
+ trigland = x->trigland;
+ mult = x->mult;
+
+
+
+ if(shapeWidth < 1 || shapeWidth > N2)
+ shapeWidth = 1;
+
+ inCount += D;
+
+ for ( j = 0 ; j < Nw - D ; j++ ) {
+ inputOne[j] = inputOne[j+D];
+ inputTwo[j] = inputTwo[j+D];
+ }
+
+ for ( j = Nw - D; j < Nw; j++ ) {
+ inputOne[j] = *inOne++;
+ inputTwo[j] = *inTwo++;
+ }
+
+/* apply hamming window and fold our window buffer into the fft buffer */
+
+ fold( inputOne, Wanal, Nw, bufferOne, N, inCount );
+ fold( inputTwo, Wanal, Nw, bufferTwo, N, inCount );
+
+/* do an fft */
+
+ rdft( N, 1, bufferOne, bitshuffle, trigland );
+ rdft( N, 1, bufferTwo, bitshuffle, trigland );
+
+/* convert to polar coordinates from complex values */
+
+ for ( i = 0; i <= N2; i++ ) {
+ odd = ( even = i<<1 ) + 1;
+
+ a1 = ( i == N2 ? *(bufferOne+1) : *(bufferOne+even) );
+ b1 = ( i == 0 || i == N2 ? 0. : *(bufferOne+odd) );
+
+ a2 = ( i == N2 ? *(bufferTwo+1) : *(bufferTwo+even) );
+ b2 = ( i == 0 || i == N2 ? 0. : *(bufferTwo+odd) );
+
+/* replace signal one's phases with those of signal two */
+
+ *(channelOne+even) = hypot( a1, b1 );
+ *(channelOne+odd) = -atan2( b1, a1 );
+
+ *(channelTwo+even) = hypot( a2, b2 );
+ *(channelTwo+odd) = -atan2( b2, a2 );
+ }
+
+/* constrain our shapeWidth value */
+
+ if ( shapeWidth > N2 )
+ shapeWidth = N2;
+
+ if ( shapeWidth < 1 )
+ shapeWidth = 1;
+
+
+/* lets just shape the entire signal by the shape width */
+
+ for ( i=0; i < N; i += shapeWidth << 1 ) {
+
+ float amplSum = 0.,
+ freqSum = 0.,
+ factor;
+
+ for ( j = 0; j < shapeWidth << 1; j += 2 ) {
+
+ amplSum += *(channelTwo+i+j);
+ freqSum += *(channelOne+i+j);
+ }
+ if(freqSum <= 0.001){
+ freqSum = 1.0;
+ }
+ if (amplSum < 0.000000001)
+ factor = 0.000000001;
+
+ else
+ factor = amplSum / freqSum;
+
+ for ( j = 0; j < shapeWidth * 2; j += 2 )
+ *(channelOne+i+j) *= factor;
+ }
+
+/* copy remaining magnitudes */
+
+ if ( (remainingWidth = N2 % shapeWidth) ) {
+
+ int bindex = (N2 - remainingWidth) << 1;
+
+
+ float amplSum = 0.,
+ freqSum = 0.,
+ factor;
+
+ for ( j = 0; j < remainingWidth * 2; j += 2 ) {
+
+ amplSum += *(channelTwo+bindex+j);
+ freqSum += *(channelOne+bindex+j);
+ }
+ if(freqSum <= 0.00001){
+ freqSum = 1.0;
+ }
+ if (amplSum < 0.000000001)
+ factor = 0.000000001;
+
+ else
+ factor = amplSum / freqSum;
+
+ for ( j = 0; j < remainingWidth * 2; j += 2 )
+ *(channelOne+bindex+j) *= factor;
+ }
+
+
+/* convert from polar to cartesian */
+
+ for ( i = 0; i <= N2; i++ ) {
+
+ odd = ( even = i<<1 ) + 1;
+
+ *(bufferOne+even) = *(channelOne+even) * cos( *(channelOne+odd) );
+
+ if ( i != N2 )
+ *(bufferOne+odd) = (*(channelOne+even)) * -sin( *(channelOne+odd) );
+ }
+
+
+/* do an inverse fft */
+
+ rdft( N, -1, bufferOne, bitshuffle, trigland );
+
+/* dewindow our result */
+
+ overlapadd( bufferOne, N, Wsyn, output, Nw, inCount);
+
+/* set our output and adjust our retaining output buffer */
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+
+/* restore state variables */
+
+ x->inCount = inCount % Nw;
+ return (w+7);
+}
+void shapee_free( t_shapee *x )
+{
+#if MSP
+ dsp_free( (t_pxobject *) x);
+#endif
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->inputOne,0);
+ freebytes(x->inputTwo,0);
+ freebytes(x->bufferOne,0);
+ freebytes(x->bufferTwo,0);
+ freebytes(x->channelOne,0);
+ freebytes(x->channelTwo,0);
+ freebytes(x->output,0);
+}
+
+void shapee_dsp(t_shapee *x, t_signal **sp, short *count)
+{
+#if MSP
+ x->widthConnected = count[2];
+#endif
+ if(x->vs != sp[0]->s_n || x->R != sp[0]->s_sr){
+ x->vs = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ shapee_init(x,1);
+ }
+ dsp_add(shapee_perform, 6, x,
+ sp[0]->s_vec,
+ sp[1]->s_vec,
+ sp[2]->s_vec,
+ sp[3]->s_vec,
+ sp[0]->s_n);
+}
+
diff --git a/swinger~.c b/swinger~.c
new file mode 100644
index 0000000..b1c2b3d
--- /dev/null
+++ b/swinger~.c
@@ -0,0 +1,408 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *swinger_class;
+#endif
+
+#if PD
+static t_class *swinger_class;
+#endif
+
+#define OBJECT_NAME "swinger~"
+
+typedef struct _swinger
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ int *bitshuffle;
+
+ float *Wanal;
+ float *Wsyn;
+ float *inputOne;
+ float *inputTwo;
+ float *Hwin;
+ float *bufferOne;
+ float *bufferTwo;
+ float *channelOne;
+ float *channelTwo;
+ float *output;
+ float mult;
+ float *trigland;
+ int overlap;//overlap factor
+ int winfac;// window factor
+ int vs;//last measurement of vector size
+ short mute;
+
+} t_swinger;
+
+
+/* msp function prototypes */
+
+void *swinger_new(t_symbol *s, int argc, t_atom *argv);
+t_int *swinger_perform(t_int *w);
+void swinger_dsp(t_swinger *x, t_signal **sp, short *count);
+void swinger_assist(t_swinger *x, void *b, long m, long a, char *s);
+void swinger_mute(t_swinger *x, t_floatarg state);
+void swinger_init(t_swinger *x, short initialized);
+void swinger_dsp_free(t_swinger *x);
+void swinger_overlap(t_swinger *x, t_floatarg o);
+void swinger_winfac(t_swinger *x, t_floatarg o);
+//int power_of_two(int p);
+void swinger_fftinfo(t_swinger *x);
+
+#if MSP
+
+void main(void)
+{
+ setup((t_messlist **)&swinger_class, (method) swinger_new, (method)dsp_free, (short)sizeof(t_swinger),
+ 0L, A_GIMME, 0);
+
+ addmess((method)swinger_dsp, "dsp", A_CANT, 0);
+ addmess((method)swinger_assist,"assist",A_CANT,0);
+ addmess((method)swinger_mute,"mute",A_FLOAT,0);
+ addmess((method)swinger_overlap,"overlap",A_FLOAT,0);
+ addmess((method)swinger_winfac,"winfac",A_FLOAT,0);
+ addmess((method)swinger_fftinfo,"fftinfo",0);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+#if PD
+/* Pd Initialization */
+void swinger_tilde_setup(void)
+{
+ swinger_class = class_new(gensym("swinger~"), (t_newmethod)swinger_new,
+ (t_method)swinger_dsp_free ,sizeof(t_swinger), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(swinger_class, t_swinger, x_f);
+ class_addmethod(swinger_class, (t_method)swinger_dsp, gensym("dsp"), 0);
+ class_addmethod(swinger_class, (t_method)swinger_mute, gensym("mute"), A_DEFFLOAT,0);
+ class_addmethod(swinger_class, (t_method)swinger_overlap, gensym("overlap"), A_DEFFLOAT,0);
+ class_addmethod(swinger_class, (t_method)swinger_winfac, gensym("winfac"), A_DEFFLOAT,0);
+ class_addmethod(swinger_class, (t_method)swinger_fftinfo, gensym("fftinfo"),0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+/* diagnostic messages for Max */
+void swinger_fftinfo(t_swinger *x)
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+
+void swinger_mute(t_swinger *x, t_floatarg state)
+{
+ x->mute = state;
+}
+
+void swinger_assist (t_swinger *x, void *b, long msg, long arg, char *dst)
+{
+
+ if (msg == 1) {
+
+ switch (arg) {
+
+ case 0: sprintf(dst,"(signal) Signal to be Phase Replaced ");
+ break;
+
+ case 1: sprintf(dst,"(signal) Signal to Supply Phase Information ");
+ break;
+ }
+ }
+
+ else {
+
+ if (msg == 2)
+ sprintf(dst,"(signal) Swinger Output");
+
+ }
+}
+
+
+void *swinger_new(t_symbol *s, int argc, t_atom *argv)
+{
+#if MSP
+ t_swinger *x = (t_swinger *) newobject(swinger_class);
+ dsp_setup((t_pxobject *)x,2);
+ outlet_new((t_pxobject *)x, "signal");
+ /* make sure that signal inlets and outlets have their own memory */
+ x->x_obj.z_misc |= Z_NO_INPLACE;
+#endif
+#if PD
+ t_swinger *x = (t_swinger *)pd_new(swinger_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+ /* INITIALIZATIONS */
+ x->overlap = atom_getfloatarg(0,argc,argv);
+ x->winfac = atom_getfloatarg(1,argc,argv);
+ if(!x->winfac)
+ x->winfac = 1;
+ if(!x->overlap)
+ x->overlap = 4;
+ x->vs = sys_getblksize();
+ x->R = sys_getsr();
+ swinger_init(x,0);
+ return (x);
+}
+
+void swinger_overlap(t_swinger *x, t_floatarg o)
+{
+ if(!power_of_two(o)){
+ post("%f is not a power of two",o);
+ return;
+ }
+ x->overlap = o;
+ swinger_init(x,1);
+}
+
+void swinger_winfac(t_swinger *x, t_floatarg f)
+{
+ if(!power_of_two(f)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = (int)f;
+ swinger_init(x,1);
+}
+
+void swinger_init(t_swinger *x, short initialized)
+{
+ int i;
+ x->D = x->vs;
+ x->N = x->vs * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+
+ if(!initialized){
+ x->Wanal = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->Wsyn = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->Hwin = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->inputOne = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->inputTwo = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->bufferOne = (float *) getbytes( MAX_N * sizeof(float) );
+ x->bufferTwo = (float *) getbytes( MAX_N * sizeof(float) );
+ x->channelOne = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->channelTwo = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->output = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->bitshuffle = (int *) getbytes( MAX_N * 2 * sizeof( int ) );
+ x->trigland = (float *) getbytes( MAX_N * 2 * sizeof( float ) );
+ }
+ memset((char *)x->inputOne,0,x->Nw * sizeof(float));
+ memset((char *)x->inputTwo,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+
+ init_rdft(x->N, x->bitshuffle, x->trigland);
+ makehanning(x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 1);// wants an ODD window
+
+}
+
+t_int *swinger_perform(t_int *w)
+{
+
+ int n,
+ i,j,
+ inCount,
+ R,
+ N,
+ N2,
+ D,
+ Nw,
+ invert = 1,
+ even, odd,
+ *bitshuffle;
+
+ float maxamp,
+ threshMult = 1.,
+ mult,
+ a1, b1,
+ a2, b2,
+ *inputOne,
+ *inputTwo,
+ *bufferOne,
+ *bufferTwo,
+ *output,
+ *Wanal,
+ *Wsyn,
+ *channelOne,
+ *channelTwo,
+ *trigland;
+ t_float *inOne,
+ *inTwo,
+ *out;
+
+ /* get our inlets and outlets */
+
+ t_swinger *x = (t_swinger *) (w[1]);
+ inOne = (t_float *)(w[2]);
+ inTwo = (t_float *)(w[3]);
+
+ out = (t_float *)(w[4]);
+ n = (int)(w[5]);
+
+ /* dereference structure */
+
+ inputOne = x->inputOne;
+ inputTwo = x->inputTwo;
+ bufferOne = x->bufferOne;
+ bufferTwo = x->bufferTwo;
+ inCount = x->inCount;
+ R = x->R;
+ N = x->N;
+ N2 = x->N2;
+ D = x->D;
+ Nw = x->Nw;
+ Wanal = x->Wanal;
+ Wsyn = x->Wsyn;
+ output = x->output;
+ channelOne = x->channelOne;
+ channelTwo = x->channelTwo;
+ bitshuffle = x->bitshuffle;
+ trigland = x->trigland;
+ mult = x->mult;
+
+ /* no computation if muted */
+
+ if(x->mute){
+ while(n--)
+ *out++ = 0.0;
+ return w+6;
+ }
+
+ inCount += D;
+
+ for ( j = 0 ; j < Nw - D ; j++ ) {
+ inputOne[j] = inputOne[j+D];
+ inputTwo[j] = inputTwo[j+D];
+ }
+
+ for ( j = Nw-D; j < Nw; j++ ) {
+ inputOne[j] = *inOne++;
+ inputTwo[j] = *inTwo++;
+ }
+
+ /* apply hamming window and fold our window buffer into the fft buffer */
+
+ fold( inputOne, Wanal, Nw, bufferOne, N, inCount );
+ fold( inputTwo, Wanal, Nw, bufferTwo, N, inCount );
+
+ /* do an fft */
+
+ rdft( N, 1, bufferOne, bitshuffle, trigland );
+ rdft( N, 1, bufferTwo, bitshuffle, trigland );
+
+ /* use redundant coding for speed, even though moving the invert variable
+ comparison outside of the for loop will give us only a minimal performance
+ increase (hypot and atan2 are the most intensive portions of this code).
+ consider adding a table lookup for atan2 instead.
+ */
+
+ /* convert to polar coordinates from complex values */
+
+ for ( i = 0; i <= N2; i++ ) {
+ odd = ( even = i<<1 ) + 1;
+
+ a1 = ( i == N2 ? *(bufferOne+1) : *(bufferOne+even) );
+ b1 = ( i == 0 || i == N2 ? 0. : *(bufferOne+odd) );
+
+ a2 = ( i == N2 ? *(bufferTwo+1) : *(bufferTwo+even) );
+ b2 = ( i == 0 || i == N2 ? 0. : *(bufferTwo+odd) );
+
+ /* replace signal one's phases with those of signal two */
+
+ *(channelOne+even) = hypot( a1, b1 );
+ *(channelOne+odd) = -atan2( b2, a2 );
+ }
+
+ for ( i = 0; i <= N2; i++ ) {
+
+ odd = ( even = i<<1 ) + 1;
+
+ *(bufferOne+even) = *(channelOne+even) * cos( *(channelOne+odd) );
+
+ if ( i != N2 )
+ *(bufferOne+odd) = -(*(channelOne+even)) * sin( *(channelOne+odd) );
+ }
+
+
+ /* do an inverse fft */
+
+ rdft( N, -1, bufferOne, bitshuffle, trigland );
+
+
+
+ /* dewindow our result */
+
+ overlapadd( bufferOne, N, Wsyn, output, Nw, inCount);
+
+ /* set our output and adjust our retaining output buffer */
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+
+ /* restore state variables */
+
+ x->inCount = inCount % Nw;
+ return (w+6);
+}
+
+void swinger_dsp_free( t_swinger *x )
+{
+#if MSP
+ dsp_free((t_pxobject *) x);
+#endif
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->inputOne,0);
+ freebytes(x->inputTwo,0);
+ freebytes(x->bufferOne,0);
+ freebytes(x->bufferTwo,0);
+ freebytes(x->channelOne,0);
+ freebytes(x->channelTwo,0);
+ freebytes(x->output,0);
+}
+
+void swinger_dsp(t_swinger *x, t_signal **sp, short *count)
+{
+ if(x->vs != sp[0]->s_n || x->R != sp[0]->s_sr){
+ x->vs = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ swinger_init(x,1);
+ }
+ dsp_add(swinger_perform, 5, x,
+ sp[0]->s_vec,sp[1]->s_vec,sp[2]->s_vec,sp[0]->s_n);
+}
+
diff --git a/taint~.c b/taint~.c
new file mode 100644
index 0000000..e7f7c14
--- /dev/null
+++ b/taint~.c
@@ -0,0 +1,596 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *taint_class;
+#endif
+#if PD
+static t_class *taint_class;
+#endif
+
+#define OBJECT_NAME "taint~"
+
+
+/*
+Adding -32dB pad for invert option. Also added latency mechanism in
+ switching from normal to "invert" to avoid glitches from extreme
+ amplitude disparities.
+
+ Made all inlets of type signal (with float options).
+
+ Threshold input is now linear, not dB (with Max doing the conversion
+ if desired).
+
+ -EL 10/1/2005
+
+ */
+
+typedef struct _taint
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ int invert;
+ int *bitshuffle;
+
+ float threshold;
+ float exponent;
+ float *Wanal;
+ float *Wsyn;
+ float *inputOne;
+ float *inputTwo;
+ float *Hwin;
+ float *bufferOne;
+ float *bufferTwo;
+ float *channelOne;
+ float *channelTwo;
+ float *output;
+ float mult;
+ float *trigland;
+
+ short connected[8];
+ short mute;
+ int overlap;//overlap factor
+ int winfac;//window factor
+ int vs;//vector size
+ int invert_countdown; // delay onset of invert effect to avoid loud glitches
+ int invert_nextstate;// next state for invert
+ float invert_pad;
+} t_taint;
+
+
+/* msp function prototypes */
+
+void *taint_new(t_symbol *s, int argc, t_atom *argv);
+t_int *offset_perform(t_int *w);
+t_int *taint_perform(t_int *w);
+void taint_dsp(t_taint *x, t_signal **sp, short *count);
+void taint_assist(t_taint *x, void *b, long m, long a, char *s);
+void taint_dest(t_taint *x, double f);
+void taint_invert(t_taint *x, t_floatarg toggle);
+void taint_free(t_taint *x);
+void taint_mute(t_taint *x, t_floatarg toggle);
+void taint_fftinfo(t_taint *x);
+void taint_tilde_setup(void);
+void taint_overlap(t_taint *x, t_floatarg o);
+void taint_winfac(t_taint *x, t_floatarg o);
+void taint_init(t_taint *x, short initialized);
+void taint_pad(t_taint *x, t_floatarg pad);
+
+
+#if MSP
+void main(void)
+{
+ setup( (struct messlist **) &taint_class, (void *) taint_new,
+ (method)dsp_free, (short) sizeof(t_taint),
+ 0, A_GIMME, 0);
+
+ addmess((method)taint_dsp, "dsp", A_CANT, 0);
+ addmess((method)taint_assist,"assist",A_CANT,0);
+ addmess((method)taint_invert,"invert", A_FLOAT, 0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+
+ addmess((method)taint_overlap,"overlap", A_FLOAT, 0);
+ addmess((method)taint_winfac,"winfac", A_FLOAT, 0);
+ addmess((method)taint_mute,"mute", A_FLOAT, 0);
+ addmess((method)taint_pad,"pad", A_FLOAT, 0);
+ addmess((method)taint_fftinfo,"fftinfo", 0);
+ addfloat((method) taint_dest);
+ dsp_initclass();
+}
+
+/* float input handling routine (MSP only)*/
+void taint_dest(t_taint *x, double f)
+{
+ int inlet = x->x_obj.z_in;
+
+ if ( inlet == 2 ) {
+ x->exponent = f;
+ }
+
+ if ( inlet == 3 ){
+ /* x->threshold = (float) (pow( 10., (f * .05))); */
+ x->threshold = f;
+ }
+}
+#endif
+
+#if PD
+void taint_tilde_setup(void)
+{
+ taint_class = class_new(gensym("taint~"), (t_newmethod)taint_new,
+ (t_method)taint_free ,sizeof(t_taint), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(taint_class, t_taint, x_f);
+ class_addmethod(taint_class, (t_method)taint_dsp, gensym("dsp"), 0);
+ class_addmethod(taint_class, (t_method)taint_assist, gensym("assist"), 0);
+ class_addmethod(taint_class, (t_method)taint_invert, gensym("invert"), A_FLOAT,0);
+ class_addmethod(taint_class, (t_method)taint_overlap, gensym("overlap"), A_FLOAT,0);
+ class_addmethod(taint_class, (t_method)taint_mute, gensym("mute"), A_FLOAT,0);
+ class_addmethod(taint_class, (t_method)taint_pad, gensym("pad"), A_FLOAT,0);
+ class_addmethod(taint_class, (t_method)taint_fftinfo, gensym("fftinfo"), A_CANT,0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+
+void taint_mute(t_taint *x, t_floatarg toggle)
+{
+ x->mute = (short)toggle;
+ // post("mute set to %f, %d",toggle,x->mute);
+}
+
+void taint_overlap(t_taint *x, t_floatarg o)
+{
+ if(!power_of_two(o)){
+ error("%f is not a power of two",o);
+ return;
+ }
+ x->overlap = (int)o;
+ taint_init(x,1);
+}
+
+void taint_winfac(t_taint *x, t_floatarg f)
+{
+ if(!power_of_two(f)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = (int)f;
+ taint_init(x,1);
+}
+
+void taint_fftinfo( t_taint *x )
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+
+}
+
+void taint_free(t_taint *x)
+{
+#if MSP
+ dsp_free((t_pxobject *) x);
+#endif
+ free(x->trigland);
+ free(x->bitshuffle);
+ free(x->Wanal);
+ free(x->Wsyn);
+ free(x->Hwin);
+ free(x->inputOne);
+ free(x->inputTwo);
+ free(x->bufferOne);
+ free(x->bufferTwo);
+ free(x->channelOne);
+ free(x->channelTwo);
+ free(x->output);
+}
+
+void taint_pad(t_taint *x, t_floatarg pad)
+{
+ x->invert_pad = pad;
+ taint_invert(x,x->invert);//resubmit to invert
+}
+
+void taint_invert(t_taint *x, t_floatarg toggle)
+{
+
+ x->invert_nextstate = toggle;
+ x->invert_countdown = x->overlap; // delay effect for "overlap" vectors
+
+ if(x->invert_nextstate){ // lower gain immediately; delay going to invert
+ x->mult = (1. / (float) x->N) * x->invert_pad;
+ } else {
+ x->invert = 0; //immediately turn off invert; delay raising gain
+ }
+
+}
+
+void taint_assist (t_taint *x, void *b, long msg, long arg, char *dst)
+{
+
+ if (msg == 1) {
+
+ switch (arg) {
+ case 0: sprintf(dst,"(signal) Input One");break;
+ case 1: sprintf(dst,"(signal) Input Two"); break;
+ case 2: sprintf(dst,"(signal/float) Scaling Exponent"); break;
+ case 3: sprintf(dst,"(signal/float) Inverse Threshold"); break;
+ }
+ }
+
+ else {
+
+ if (msg == 2)
+ sprintf(dst,"(signal) Output");
+
+ }
+}
+
+
+void *taint_new(t_symbol *s, int argc, t_atom *argv)
+{
+
+#if MSP
+ t_taint *x = (t_taint *) newobject(taint_class);
+ dsp_setup((t_pxobject *)x,4);
+ outlet_new((t_pxobject *)x, "signal");
+ // x->x_obj.z_misc |= Z_NO_INPLACE; // probably not needed
+#endif
+#if PD
+ t_taint *x = (t_taint *)pd_new(taint_class);
+ /* add three additional signal inlets */
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+
+ /* optional arguments: scaling exponent, threshold (now linear), overlap, winfac */
+ x->exponent = atom_getfloatarg(0,argc,argv);
+ x->threshold = atom_getfloatarg(1,argc,argv);
+ x->overlap = atom_getfloatarg(2,argc,argv);
+ x->winfac = atom_getfloatarg(3,argc,argv);
+
+ /*
+ x->threshold = (float) pow(10.0,(x->threshold * .05));
+ */
+ /* sanity check */
+ if(x->exponent < 0.25)
+ x->exponent = 0.25;
+
+ if(!power_of_two(x->overlap)){
+ x->overlap = 4;
+ }
+ if(!power_of_two(x->winfac)){
+ x->winfac = 1;
+ }
+
+ x->vs = sys_getblksize();
+ x->R = sys_getsr();
+
+ taint_init(x,0);
+
+ return (x);
+}
+
+void taint_init(t_taint *x, short initialized)
+{
+ int i;
+ x->D = x->vs;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+ if(!initialized){
+ x->invert_pad = 0.025; // -32 dB
+ x->invert_countdown = 0;
+ x->mute = 0;
+ x->invert = 0;
+ x->Wanal = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->Wsyn = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->Hwin = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->inputOne = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->inputTwo = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->bufferOne = (float *) getbytes( MAX_N * sizeof(float) );
+ x->bufferTwo = (float *) getbytes( MAX_N * sizeof(float) );
+ x->channelOne = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->channelTwo = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->output = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->bitshuffle = (int *) getbytes( MAX_N * 2 * sizeof( int ) );
+ x->trigland = (float *) getbytes( MAX_N * 2 * sizeof( float ) );
+ }
+ if(x->invert){
+ x->mult *= x->invert_pad;
+ }
+ memset((char *)x->inputOne,0,x->Nw * sizeof(float));
+ memset((char *)x->inputTwo,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makehanning( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 1);
+
+}
+
+
+t_int *taint_perform(t_int *w)
+{
+
+ int
+ i,j,
+ inCount,
+ R,
+ N,
+ N2,
+ D,
+ Nw,
+ invert = 0,
+ even, odd,
+ *bitshuffle;
+
+ float maxamp,
+ threshold = 1.,
+ mult,
+ exponent,
+ a1, b1,
+ a2, b2,
+ *inputOne,
+ *inputTwo,
+ *bufferOne,
+ *bufferTwo,
+ *output,
+ *Wanal,
+ *Wsyn,
+ *channelOne,
+ *channelTwo,
+ *trigland;
+
+
+
+ /* get our inlets and outlets */
+
+ t_taint *x = (t_taint *) (w[1]);
+ t_float *inOne = (t_float *)(w[2]);
+ t_float *inTwo = (t_float *)(w[3]);
+ t_float *vec_exponent = (t_float *)(w[4]);
+ t_float *vec_threshold = (t_float *)(w[5]);
+ t_float *out = (t_float *)(w[6]);
+ t_int n = w[7];
+
+ short *connected = x->connected;
+ /* dereference structure */
+ if(connected[2])
+ x->exponent = *vec_exponent;
+ if(connected[3]){
+ x->threshold = *vec_threshold;
+ /*
+ x->threshold = (float) (pow( 10., (x->threshold * .05)));
+ */
+ }
+
+ if(x->mute){
+ while(n--)
+ *out++ = 0.0;
+ return w+8;
+ }
+ // do countdown
+ if(x->invert_countdown > 0){
+
+ if(x->invert) { // we
+ } else {
+ }
+ --(x->invert_countdown);
+ if(! x->invert_countdown){ // countdown just ended
+ if(x->invert_nextstate){ // moving to invert (gain is already down)
+ x->invert = x->invert_nextstate;
+ } else { // invert is already off - now reset gain
+ x->mult = 1. / (float) x->N;
+ }
+ }
+ }
+
+ inputOne = x->inputOne;
+ inputTwo = x->inputTwo;
+ bufferOne = x->bufferOne;
+ bufferTwo = x->bufferTwo;
+ inCount = x->inCount;
+ R = x->R;
+ N = x->N;
+ N2 = x->N2;
+ D = x->D;
+ Nw = x->Nw;
+ Wanal = x->Wanal;
+ Wsyn = x->Wsyn;
+ output = x->output;
+ channelOne = x->channelOne;
+ channelTwo = x->channelTwo;
+ bitshuffle = x->bitshuffle;
+ trigland = x->trigland;
+ mult = x->mult;
+ invert = x->invert;
+ exponent = x->exponent;
+
+ if ( x->threshold != 0. )
+ threshold = x->threshold;
+
+ /* fill our retaining buffers */
+
+ inCount += D;
+
+ for ( j = 0 ; j < Nw - D ; j++ ) {
+ inputOne[j] = inputOne[j+D];
+ inputTwo[j] = inputTwo[j+D];
+ }
+
+ for ( j = Nw - D; j < Nw; j++ ) {
+ inputOne[j] = *inOne++;
+ inputTwo[j] = *inTwo++;
+ }
+
+ /* apply hamming window and fold our window buffer into the fft buffer */
+
+ fold( inputOne, Wanal, Nw, bufferOne, N, inCount );
+ fold( inputTwo, Wanal, Nw, bufferTwo, N, inCount );
+
+ /* do an fft */
+
+ rdft( N, 1, bufferOne, bitshuffle, trigland );
+ rdft( N, 1, bufferTwo, bitshuffle, trigland );
+
+ /* convert to polar coordinates from complex values */
+
+ if (invert) {
+
+ for ( i = 0; i <= N2; i++ ) {
+
+ float magnitude;
+
+ odd = ( even = i<<1 ) + 1;
+
+ a1 = ( i == N2 ? *(bufferOne+1) : *(bufferOne+even) );
+ b1 = ( i == 0 || i == N2 ? 0. : *(bufferOne+odd) );
+
+ a2 = ( i == N2 ? *(bufferTwo+1) : *(bufferTwo+even) );
+ b2 = ( i == 0 || i == N2 ? 0. : *(bufferTwo+odd) );
+
+ *(channelOne+even) = hypot( a1, b1 );
+ *(channelOne+odd) = -atan2( b1, a1 );
+
+ magnitude = *(channelTwo+even) = hypot( a2, b2 );
+ *(channelTwo+odd) = -atan2( b2, a2 );
+
+ /* use threshold for inverse filtering to avoid division by zero */
+
+ if ( magnitude < threshold )
+ magnitude = 0.;
+
+ else
+ magnitude = 1. / magnitude;
+
+ *(channelOne+even) *= magnitude;
+ *(channelOne+even) = pow( *(channelOne+even), exponent );
+ }
+ }
+
+
+ else {
+
+ for ( i = 0; i <= N2; i++ ) {
+
+ odd = ( even = i<<1 ) + 1;
+
+ a1 = ( i == N2 ? *(bufferOne+1) : *(bufferOne+even) );
+ b1 = ( i == 0 || i == N2 ? 0. : *(bufferOne+odd) );
+
+ a2 = ( i == N2 ? *(bufferTwo+1) : *(bufferTwo+even) );
+ b2 = ( i == 0 || i == N2 ? 0. : *(bufferTwo+odd) );
+
+ *(channelOne+even) = hypot( a1, b1 );
+ *(channelOne+odd) = -atan2( b1, a1 );
+
+ *(channelTwo+even) = hypot( a2, b2 );
+ *(channelTwo+odd) = -atan2( b2, a2 );
+
+ /* simple multiplication of magnitudes */
+
+ *(channelOne+even) *= *(channelTwo+even);
+
+ *(channelOne+even) = pow( *(channelOne+even), exponent );
+ }
+ }
+
+ /* convert back to complex form, read for the inverse fft */
+
+ for ( i = 0; i <= N2; i++ ) {
+
+ odd = ( even = i<<1 ) + 1;
+
+ *(bufferOne+even) = *(channelOne+even) * cos( *(channelOne+odd) );
+
+ if ( i != N2 )
+ *(bufferOne+odd) = -(*(channelOne+even)) * sin( *(channelOne+odd) );
+ }
+
+
+ /* do an inverse fft */
+
+ rdft( N, -1, bufferOne, bitshuffle, trigland );
+
+ /* use slow inverse fft */
+
+ // rfft( bufferOne, N2, INVERSE );
+
+ /* dewindow our result */
+
+ overlapadd( bufferOne, N, Wsyn, output, Nw, inCount);
+
+ /* set our output and adjust our retaining output buffer */
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+
+ /* restore state variables */
+
+ x->inCount = inCount % Nw;
+ return (w+8);
+}
+
+
+void taint_dsp(t_taint *x, t_signal **sp, short *count)
+{
+ long i;
+
+#if MSP
+ for( i = 0; i < 4; i++ ){
+ x->connected[i] = count[i];
+ }
+#endif
+ /* signal is always connected in Pd */
+#if PD
+ for( i = 0; i < 4; i++ ){
+ x->connected[i] = 1;
+ }
+#endif
+
+ /* reinitialize if vector size or sampling rate has been changed */
+ if(x->vs != sp[0]->s_n || x->R != sp[0]->s_sr){
+ x->vs = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ taint_init(x,1);
+ }
+
+ dsp_add(taint_perform, 7, x,
+ sp[0]->s_vec,
+ sp[1]->s_vec,
+ sp[2]->s_vec,
+ sp[3]->s_vec,
+ sp[4]->s_vec,
+ sp[0]->s_n);
+}
+
diff --git a/thresher~.c b/thresher~.c
new file mode 100644
index 0000000..02c486c
--- /dev/null
+++ b/thresher~.c
@@ -0,0 +1,444 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *thresher_class;
+#endif
+
+#if PD
+static t_class *thresher_class;
+#endif
+
+#define OBJECT_NAME "thresher~"
+
+#define DEFAULT_HOLD (40.0)
+
+
+
+typedef struct _thresher
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int in_count;
+ float *Wanal;
+ float *Wsyn;
+ float *input;
+ float *Hwin;
+ // float *winput;
+ float *buffer;
+ float *channel;
+ float *output;
+ /* thresher vars */
+ float move_threshold;
+ float *composite_frame ;
+ int *frames_left;
+ int max_hold_frames;
+ float max_hold_time;
+ int first_frame;
+ float damping_factor ;
+ short thresh_connected;
+ short damping_connected;
+ // for convert
+ float *c_lastphase_in;
+ float *c_lastphase_out;
+ float c_fundamental;
+ float c_factor_in;
+ float c_factor_out;
+ // for fast fft
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ short mute;
+ short bypass;
+ int winfac;
+ int overlap;
+ float tadv;
+} t_thresher;
+
+void *thresher_new(t_symbol *s, int argc, t_atom *argv);
+t_int *offset_perform(t_int *w);
+t_int *thresher_perform(t_int *w);
+void thresher_dsp(t_thresher *x, t_signal **sp, short *count);
+void thresher_assist(t_thresher *x, void *b, long m, long a, char *s);
+void thresher_float(t_thresher *x, double f);
+void thresher_mute(t_thresher *x, t_floatarg f);
+void thresher_bypass(t_thresher *x, t_floatarg f);
+void thresher_free( t_thresher *x );
+void thresher_overlap(t_thresher *x, t_floatarg f);
+void thresher_winfac(t_thresher *x, t_floatarg f);
+void thresher_fftinfo(t_thresher *x);
+void thresher_init(t_thresher *x, short initialized);
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&thresher_class, (method)thresher_new, (method)thresher_free,
+ (short)sizeof(t_thresher), 0L, A_GIMME, 0);
+ addmess((method)thresher_dsp, "dsp", A_CANT, 0);
+ addmess((method)thresher_assist,"assist",A_CANT,0);
+ addmess((method)thresher_mute,"mute",A_FLOAT,0);
+ addmess((method)thresher_bypass,"bypass",A_FLOAT,0);
+ addmess((method)thresher_overlap,"overlap",A_DEFFLOAT,0);
+ addmess((method)thresher_winfac,"winfac",A_DEFFLOAT,0);
+ addmess((method)thresher_fftinfo,"fftinfo",0);
+ addfloat((method)thresher_float);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+
+}
+#endif
+
+#if PD
+void thresher_tilde_setup(void)
+{
+ thresher_class = class_new(gensym("thresher~"), (t_newmethod)thresher_new,
+ (t_method)thresher_free ,sizeof(t_thresher), 0,A_GIMME,0);
+
+ CLASS_MAINSIGNALIN(thresher_class, t_thresher, x_f );
+ class_addmethod(thresher_class, (t_method)thresher_dsp, gensym("dsp"), 0);
+ class_addmethod(thresher_class, (t_method)thresher_mute, gensym("mute"), A_DEFFLOAT,0);
+ class_addmethod(thresher_class, (t_method)thresher_bypass, gensym("bypass"), A_DEFFLOAT,0);
+ class_addmethod(thresher_class, (t_method)thresher_assist, gensym("assist"), 0);
+ class_addmethod(thresher_class,(t_method)thresher_overlap,gensym("overlap"),A_FLOAT,0);
+ class_addmethod(thresher_class,(t_method)thresher_winfac,gensym("winfac"),A_FLOAT,0);
+ class_addmethod(thresher_class,(t_method)thresher_fftinfo,gensym("fftinfo"),0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+void thresher_overlap(t_thresher *x, t_floatarg f)
+{
+ int i = (int) f;
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->overlap = i;
+ thresher_init(x,1);
+}
+
+void thresher_winfac(t_thresher *x, t_floatarg f)
+{
+ int i = (int)f;
+
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = i;
+ thresher_init(x,2);
+}
+
+void thresher_fftinfo(t_thresher *x)
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+
+void thresher_free(t_thresher *x){
+#if MSP
+ dsp_free( (t_pxobject *) x);
+#endif
+ freebytes(x->c_lastphase_in,0);
+ freebytes(x->c_lastphase_out,0);
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->input,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->buffer,0);
+ freebytes(x->channel,0);
+ freebytes(x->output,0);
+ freebytes(x->composite_frame,0);
+ freebytes(x->frames_left,0);
+}
+void thresher_mute(t_thresher *x, t_floatarg f){
+ x->mute = (short)f;
+}
+
+void thresher_bypass(t_thresher *x, t_floatarg f){
+ x->bypass = (short)f;
+}
+
+void thresher_assist (t_thresher *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0:
+ sprintf(dst,"(signal) Input");
+ break;
+ case 1:
+ sprintf(dst,"(signal/float) Threshold");
+ break;
+ case 2:
+ sprintf(dst,"(signal/float) Damping Factor");
+ break;
+ }
+ } else if (msg==2) {
+ sprintf(dst,"(signal) Output");
+ }
+}
+
+
+void *thresher_new(t_symbol *s, int argc, t_atom *argv)
+{
+#if MSP
+ t_thresher *x = (t_thresher *)newobject(thresher_class);
+ dsp_setup((t_pxobject *)x,3);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+
+#if PD
+ t_thresher *x = (t_thresher *)pd_new(thresher_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+
+ x->move_threshold = atom_getfloatarg(0, argc, argv);
+ x->damping_factor = atom_getfloatarg(1, argc, argv);
+ x->overlap = atom_getfloatarg( 2, argc, argv );
+ x->winfac = atom_getfloatarg( 3, argc, argv );
+
+ x->D = sys_getblksize();
+ x->R = sys_getsr();
+
+ thresher_init(x,0);
+ return (x);
+}
+
+void thresher_init(t_thresher *x, short initialized)
+{
+ int i;
+
+ if(!x->D)
+ x->D = 256;
+ if(!x->R)
+ x->R = 44100;
+ if(!power_of_two(x->overlap))
+ x->overlap = 4;
+ if(!power_of_two(x->winfac))
+ x->winfac = 1;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->in_count = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+ x->tadv = (float) x->D / (float) x->R ;
+
+
+
+ if(!initialized){
+ x->mute = 0;
+ x->bypass = 0;
+ if(!x->damping_factor){
+ x->damping_factor = .95;
+ }
+ x->first_frame = 1;
+ x->move_threshold = .00001 ;
+ x->max_hold_time = DEFAULT_HOLD ;
+ x->max_hold_frames = x->max_hold_time / x->tadv;
+ x->c_fundamental = (float) x->R/( (x->N2)<<1 );
+ x->c_factor_in = (float) x->R/((float)x->D * TWOPI);
+ x->c_factor_out = TWOPI * (float) x->D / (float) x->R;
+
+ x->Wanal = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Wsyn = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->Hwin = (float *) getbytes( (MAX_Nw) * sizeof(float));
+ x->input = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->output = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->buffer = (float *) getbytes( MAX_N * sizeof(float) );
+ x->channel = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->bitshuffle = (int *) getbytes( MAX_N * 2 * sizeof( int ) );
+ x->trigland = (float *) getbytes( MAX_N * 2 * sizeof( float ) );
+ x->c_lastphase_in = (float *) getbytes( (MAX_N2+1) * sizeof(float) );
+ x->c_lastphase_out = (float *) getbytes( (MAX_N2+1) * sizeof(float) );
+ x->composite_frame = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->frames_left = (int *) getbytes( (MAX_N+2) * sizeof(int) );
+
+ }
+ memset((char *)x->input,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ memset((char *)x->c_lastphase_in,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->c_lastphase_out,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->frames_left,0,(x->N+2) * sizeof(float));
+
+ init_rdft(x->N, x->bitshuffle, x->trigland);
+ makehanning(x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 0);
+}
+
+t_int *thresher_perform(t_int *w)
+{
+ float sample, outsamp ;
+ int i,j;
+
+ t_thresher *x = (t_thresher *) (w[1]);
+
+ float *in = (t_float *)(w[2]);
+ float *inthresh = (t_float *)(w[3]);
+ float *damping = (t_float *)(w[4]);
+ float *out = (t_float *)(w[5]);
+ int n = (int)(w[6]);
+
+ float *input = x->input;
+ float *output = x->output;
+ float *buffer = x->buffer;
+ float *Wanal = x->Wanal;
+ float *Wsyn = x->Wsyn;
+ float *channel = x->channel;
+ float damping_factor = x->damping_factor;
+ int max_hold_frames = x->max_hold_frames;
+ int *frames_left = x->frames_left;
+ float *composite_frame = x->composite_frame;
+ float *c_lastphase_in = x->c_lastphase_in;
+ float *c_lastphase_out = x->c_lastphase_out;
+ float c_fundamental = x->c_fundamental;
+ float c_factor_in = x->c_factor_in;
+ float c_factor_out = x->c_factor_out;
+ int *bitshuffle = x->bitshuffle;
+ float *trigland = x->trigland;
+ float mult = x->mult;
+ int in_count = x->in_count;
+ int R = x->R;
+ int N = x->N;
+ int N2 = x->N2;
+ int D = x->D;
+ int Nw = x->Nw;
+ float move_threshold = x->move_threshold;
+
+
+ if( x->mute ) {
+ for( j = 0; j < D; j++) {
+ *out++ = 0.0 ;
+ }
+ return (w+7);
+ }
+
+ if ( x->bypass ) {
+ for( j = 0; j < D; j++) {
+ *out++ = *in++ ;
+ }
+ return (w+7);
+ }
+
+
+
+
+ if( x->thresh_connected ) {
+ move_threshold = *inthresh ;
+ }
+ if( x->damping_connected ) {
+ damping_factor = *damping ;
+ }
+
+ in_count += D;
+
+ for ( j = 0 ; j < Nw - D ; j++ )
+ input[j] = input[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ ) {
+ input[j] = *in++;
+ }
+
+ fold( input, Wanal, Nw, buffer, N, in_count );
+
+ rdft( N, 1, buffer, bitshuffle, trigland );
+
+ convert( buffer, channel, N2, c_lastphase_in, c_fundamental, c_factor_in );
+
+ if( x->first_frame ){
+ for ( i = 0; i < N+2; i++ ){
+ composite_frame[i] = channel[i];
+ frames_left[i] = max_hold_frames;
+ }
+ x->first_frame = 0;
+ } else {
+ for( i = 0; i < N+2; i += 2 ){
+ if(fabs( composite_frame[i] - channel[i] ) > move_threshold ||
+ frames_left[i] <= 0 ){
+ composite_frame[i] = channel[i];
+ composite_frame[i+1] = channel[i+1];
+ frames_left[i] = max_hold_frames;
+ } else {
+ --(frames_left[i]);
+ composite_frame[i] *= damping_factor;
+ }
+ }
+ }
+
+
+ unconvert( composite_frame, buffer, N2, c_lastphase_out, c_fundamental, c_factor_out );
+ rdft( N, -1, buffer, bitshuffle, trigland );
+
+ overlapadd( buffer, N, Wsyn, output, Nw, in_count );
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+ x->in_count = in_count;
+ x->damping_factor = damping_factor;
+
+ return (w+7);
+}
+
+#if MSP
+void thresher_float(t_thresher *x, double f) // Look at floats at inlets
+{
+ int inlet = x->x_obj.z_in;
+
+ if (inlet == 1)
+ {
+ x->move_threshold = f;
+ } else if (inlet == 2) {
+ x->damping_factor = f;
+ }
+}
+#endif
+
+void thresher_dsp(t_thresher *x, t_signal **sp, short *count)
+{
+#if MSP
+ x->thresh_connected = count[1];
+ x->damping_connected = count[2];
+#endif
+
+#if PD
+ x->thresh_connected = 1;
+ x->damping_connected = 1;
+#endif
+
+ if(sp[0]->s_n != x->D || x->R != sp[0]->s_sr){
+ x->D = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ thresher_init(x,1);
+ }
+ dsp_add(thresher_perform, 6, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec,
+ sp[0]->s_n);
+}
+
diff --git a/vacancy~.c b/vacancy~.c
new file mode 100644
index 0000000..0be6087
--- /dev/null
+++ b/vacancy~.c
@@ -0,0 +1,582 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *vacancy_class;
+#endif
+#if PD
+static t_class *vacancy_class;
+#endif
+
+#define OBJECT_NAME "vacancy~"
+
+/*
+Added inlet for compositing threshold, which is now
+given linearly, not in dB (since Max can do that).
+
+-EL 02.10.2005
+
+*/
+typedef struct _vacancy
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ int inCount;
+ int invert;
+ int useRms;
+ int swapPhase;
+ int *bitshuffle;
+
+ float threshold;
+ float *Wanal;
+ float *Wsyn;
+ float *inputOne;
+ float *inputTwo;
+ float *Hwin;
+ float *bufferOne;
+ float *bufferTwo;
+ float *channelOne;
+ float *channelTwo;
+ float *output;
+ float mult;
+ float *trigland;
+ short connected[8];
+ short mute;
+ int overlap;//overlap factor
+ int winfac;//window factor
+ int vs;//vector size
+
+} t_vacancy;
+
+
+/* msp function prototypes */
+
+void *vacancy_new(t_symbol *s, int argc, t_atom *argv);
+t_int *vacancy_perform(t_int *w);
+void vacancy_dsp(t_vacancy *x, t_signal **sp, short *count);
+void vacancy_assist(t_vacancy *x, void *b, long m, long a, char *s);
+void vacancy_dest(t_vacancy *x, double f);
+
+void vacancy_rms(t_vacancy *x, t_floatarg f);
+void vacancy_invert(t_vacancy *x, t_floatarg f);
+void vacancy_swapphase(t_vacancy *x, t_floatarg f);
+
+void vacancy_free(t_vacancy *x);
+void vacancy_mute(t_vacancy *x, t_floatarg toggle);
+void vacancy_fftinfo(t_vacancy *x);
+void vacancy_tilde_setup(void);
+void vacancy_overlap(t_vacancy *x, t_floatarg o);
+void vacancy_winfac(t_vacancy *x, t_floatarg o);
+void vacancy_init(t_vacancy *x, short initialized);
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&vacancy_class, (method)vacancy_new, (method)vacancy_free,
+ (short) sizeof(t_vacancy), 0, A_GIMME, 0);
+
+ addmess((method)vacancy_dsp, "dsp", A_CANT, 0);
+ addmess((method)vacancy_assist,"assist",A_CANT,0);
+ addmess((method)vacancy_rms,"rms", A_FLOAT, 0);
+ addmess((method)vacancy_invert,"invert", A_FLOAT, 0);
+ addmess((method)vacancy_swapphase,"swapphase", A_FLOAT, 0);
+ addmess((method)vacancy_mute,"mute", A_FLOAT, 0);
+ addmess((method)vacancy_overlap,"overlap", A_FLOAT, 0);
+ addmess((method)vacancy_winfac,"winfac", A_FLOAT, 0);
+ addmess((method)vacancy_fftinfo,"fftinfo", 0);
+ addfloat((method)vacancy_dest);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+
+void vacancy_dest(t_vacancy *x, double f)
+{
+int inlet = x->x_obj.z_in;
+
+ if(inlet == 2)
+ x->threshold = (float) f;
+}
+#endif
+
+#if PD
+void vacancy_tilde_setup(void)
+{
+ vacancy_class = class_new(gensym("vacancy~"), (t_newmethod)vacancy_new,
+ (t_method)vacancy_free ,sizeof(t_vacancy), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(vacancy_class, t_vacancy, x_f);
+ class_addmethod(vacancy_class, (t_method)vacancy_dsp, gensym("dsp"), 0);
+ class_addmethod(vacancy_class, (t_method)vacancy_assist, gensym("assist"), 0);
+ class_addmethod(vacancy_class, (t_method)vacancy_invert, gensym("invert"), A_FLOAT,0);
+ class_addmethod(vacancy_class, (t_method)vacancy_swapphase, gensym("swapphase"), A_FLOAT,0);
+ class_addmethod(vacancy_class, (t_method)vacancy_overlap, gensym("overlap"), A_FLOAT,0);
+ class_addmethod(vacancy_class, (t_method)vacancy_winfac, gensym("winfac"), A_FLOAT,0);
+ class_addmethod(vacancy_class, (t_method)vacancy_mute, gensym("mute"), A_FLOAT,0);
+ class_addmethod(vacancy_class, (t_method)vacancy_fftinfo, gensym("fftinfo"), A_CANT,0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+
+#endif
+
+
+void vacancy_rms(t_vacancy *x, t_floatarg f)
+{
+ x->useRms = (int) f;
+}
+
+void vacancy_invert(t_vacancy *x, t_floatarg f)
+{
+ x->invert = (int) f;
+}
+
+void vacancy_swapphase(t_vacancy *x, t_floatarg f)
+{
+ x->swapPhase = (int) f;
+}
+
+
+void vacancy_assist (t_vacancy *x, void *b, long msg, long arg, char *dst)
+{
+
+ if (msg == 1) {
+
+ switch (arg) {
+
+ case 0: sprintf(dst,"(signal) Input One"); break;
+ case 1: sprintf(dst,"(signal) Input Two"); break;
+ case 2: sprintf(dst,"(signal) Mixing Threshold"); break;
+ }
+ }
+
+ else {
+
+ if (msg == 2)
+ sprintf(dst,"(signal) Output");
+
+ }
+}
+
+void vacancy_fftinfo( t_vacancy *x )
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+void vacancy_mute(t_vacancy *x, t_floatarg toggle)
+{
+ x->mute = (short)toggle;
+}
+
+void vacancy_overlap(t_vacancy *x, t_floatarg o)
+{
+ if(!power_of_two(o)){
+ error("%f is not a power of two",o);
+ return;
+ }
+ x->overlap = (int)o;
+ vacancy_init(x,1);
+}
+
+void vacancy_winfac(t_vacancy *x, t_floatarg f)
+{
+ if(!power_of_two(f)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = (int)f;
+ vacancy_init(x,1);
+}
+
+void *vacancy_new(t_symbol *s, int argc, t_atom *argv)
+{
+#if MSP
+ t_vacancy *x = (t_vacancy *) newobject(vacancy_class);
+ dsp_setup((t_pxobject *)x,3);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+
+#if PD
+ t_vacancy *x = (t_vacancy *)pd_new(vacancy_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+
+
+
+/* optional arguments: overlap, window factor */
+
+ x->overlap = atom_getfloatarg(0,argc,argv);
+ x->winfac = atom_getfloatarg(1,argc,argv);
+
+ if(!power_of_two(x->overlap)){
+ x->overlap = 4;
+ }
+ if(!power_of_two(x->winfac)){
+ x->winfac = 1;
+ }
+
+ x->vs = sys_getblksize();
+ x->R = sys_getsr();
+
+ vacancy_init(x,0);
+
+ return (x);
+}
+
+void vacancy_init(t_vacancy *x, short initialized)
+{
+ int i;
+
+ x->D = x->vs;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+ if(!initialized){
+ x->mute = 0;
+ x->invert = 0;
+ x->threshold = 0.;
+ x->useRms = 1;
+ x->swapPhase = 0;
+ x->Wanal = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->Wsyn = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->Hwin = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->inputOne = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->inputTwo = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->bufferOne = (float *) getbytes( MAX_N * sizeof(float) );
+ x->bufferTwo = (float *) getbytes( MAX_N * sizeof(float) );
+ x->channelOne = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->channelTwo = (float *) getbytes( (MAX_N+2) * sizeof(float) );
+ x->output = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->bitshuffle = (int *) getbytes( MAX_N * 2 * sizeof( int ) );
+ x->trigland = (float *) getbytes( MAX_N * 2 * sizeof( float ) );
+ }
+ memset((char *)x->inputOne,0,x->Nw * sizeof(float));
+ memset((char *)x->inputTwo,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makehanning( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 0);
+
+}
+
+void vacancy_free(t_vacancy *x)
+{
+#if MSP
+ dsp_free((t_pxobject *) x);
+#endif
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->inputOne,0);
+ freebytes(x->inputTwo,0);
+ freebytes(x->bufferOne,0);
+ freebytes(x->bufferTwo,0);
+ freebytes(x->channelOne,0);
+ freebytes(x->channelTwo,0);
+ freebytes(x->output,0);
+}
+
+t_int *vacancy_perform(t_int *w)
+{
+
+ int
+ i,j,
+ inCount,
+ R,
+ N,
+ N2,
+ D,
+ Nw,
+ invert = 0,
+ useRms = 1,
+ swapPhase = 0,
+ even, odd,
+ *bitshuffle;
+
+ float maxamp,
+ threshold = .001,
+ mult,
+ useme,
+ rms = 0.,
+ a1, b1,
+ a2, b2,
+ *inputOne,
+ *inputTwo,
+ *bufferOne,
+ *bufferTwo,
+ *output,
+ *Wanal,
+ *Wsyn,
+ *channelOne,
+ *channelTwo,
+ *trigland;
+
+
+
+/* get our inlets and outlets */
+
+ t_vacancy *x = (t_vacancy *) (w[1]);
+ t_float *inOne = (t_float *)(w[2]);
+ t_float *inTwo = (t_float *)(w[3]);
+ t_float *vec_threshold = (t_float *)(w[4]);
+ t_float *out = (t_float *)(w[5]);
+ t_int n = (t_int)(w[6]);
+
+ short *connected = x->connected;
+
+ if(x->mute){
+ while(n--)
+ *out++ = 0.0;
+ return w+7;
+ }
+
+/* dereference structure */
+
+ inputOne = x->inputOne;
+ inputTwo = x->inputTwo;
+ bufferOne = x->bufferOne;
+ bufferTwo = x->bufferTwo;
+ inCount = x->inCount;
+ R = x->R;
+ N = x->N;
+ N2 = x->N2;
+ D = x->D;
+ Nw = x->Nw;
+ Wanal = x->Wanal;
+ Wsyn = x->Wsyn;
+ output = x->output;
+ channelOne = x->channelOne;
+ channelTwo = x->channelTwo;
+ bitshuffle = x->bitshuffle;
+ trigland = x->trigland;
+ mult = x->mult;
+ invert = x->invert;
+ useRms = x->useRms;
+ swapPhase = x->swapPhase;
+
+ threshold = connected[2] ? *vec_threshold : x->threshold;
+
+ /*
+ a bug?? Threshold could be -90 to 90 (dB)
+
+ if ( x->threshold > 0. )
+ threshold = x->threshold;
+ */
+
+
+/* fill our retaining buffers */
+
+ inCount += D;
+
+ for ( j = 0 ; j < Nw - D ; j++ ) {
+ inputOne[j] = inputOne[j+D];
+ inputTwo[j] = inputTwo[j+D];
+ }
+
+ for ( j = Nw - D; j < Nw; j++ ) {
+ inputOne[j] = *inOne++;
+ inputTwo[j] = *inTwo++;
+ }
+
+ if (useRms) {
+
+ rms = 0.;
+
+ for ( i=0; i < Nw; i++ )
+ rms += *(inputOne+i) * *(inputOne+i);
+
+ rms = sqrt( rms / Nw );
+
+ useme = rms * threshold;
+ }
+
+ else
+ useme = threshold;
+
+
+/* apply hamming window and fold our window buffer into the fft buffer */
+
+ fold( inputOne, Wanal, Nw, bufferOne, N, inCount );
+ fold( inputTwo, Wanal, Nw, bufferTwo, N, inCount );
+
+
+/* do an fft */
+
+ rdft( N, 1, bufferOne, bitshuffle, trigland );
+ rdft( N, 1, bufferTwo, bitshuffle, trigland );
+
+/* use slow fft */
+
+// rfft( bufferOne, N2, FORWARD );
+// rfft( bufferTwo, N2, FORWARD );
+
+
+/* convert to polar coordinates from complex values */
+
+ for ( i = 0; i <= N2; i++ ) {
+
+ odd = ( even = i<<1 ) + 1;
+
+ a1 = ( i == N2 ? *(bufferOne+1) : *(bufferOne+even) );
+ b1 = ( i == 0 || i == N2 ? 0. : *(bufferOne+odd) );
+
+ a2 = ( i == N2 ? *(bufferTwo+1) : *(bufferTwo+even) );
+ b2 = ( i == 0 || i == N2 ? 0. : *(bufferTwo+odd) );
+
+ *(channelOne+even) = hypot( a1, b1 );
+ *(channelOne+odd) = -atan2( b1, a1 );
+
+ *(channelTwo+even) = hypot( a2, b2 );
+ *(channelTwo+odd) = -atan2( b2, a2 );
+ }
+
+
+ /* composite here please */
+
+ if (invert) {
+
+ if (swapPhase) {
+
+ for ( i=0; i < N2; i+=2 ) {
+ if ( *(channelOne+i) > useme && *(channelTwo+i) < *(channelOne+i) ) {
+ *(channelOne+i) = *(channelTwo+i);
+ *(channelOne+i+1) = *(channelTwo+i+1);
+ }
+ }
+ }
+
+ else {
+
+ for ( i=0; i < N2; i+=2 ) {
+ if ( *(channelOne+i) > useme && *(channelTwo+i) < *(channelOne+i) ) {
+ *(channelOne+i) = *(channelTwo+i);
+
+ if ( *(channelOne+i+1) == 0. )
+ *(channelOne+i+1) = *(channelTwo+i+1);
+ }
+ }
+ }
+ }
+
+ else {
+
+ if (swapPhase) {
+
+ for ( i=0; i < N2; i+=2 ) {
+ if ( *(channelOne+i) < useme && *(channelTwo+i) > *(channelOne+i) ) {
+ *(channelOne+i) = *(channelTwo+i);
+ *(channelOne+i+1) = *(channelTwo+i+1);
+ }
+ }
+ }
+
+ else {
+
+ for ( i=0; i < N2; i+=2 ) {
+
+ if ( *(channelOne+i) < useme && *(channelTwo+i) > *(channelOne+i) ) {
+ *(channelOne+i) = *(channelTwo+i);
+
+ if ( *(channelOne+i+1) == 0. )
+ *(channelOne+i+1) = *(channelTwo+i+1);
+ }
+ }
+ }
+ }
+
+
+/* convert back to complex form, read for the inverse fft */
+
+ for ( i = 0; i <= N2; i++ ) {
+
+ odd = ( even = i<<1 ) + 1;
+
+ *(bufferOne+even) = *(channelOne+even) * cos( *(channelOne+odd) );
+
+ if ( i != N2 )
+ *(bufferOne+odd) = -(*(channelOne+even)) * sin( *(channelOne+odd) );
+ }
+
+
+/* do an inverse fft */
+
+ rdft( N, -1, bufferOne, bitshuffle, trigland );
+
+/* dewindow our result */
+
+ overlapadd( bufferOne, N, Wsyn, output, Nw, inCount);
+
+/* set our output and adjust our retaining output buffer */
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+
+/* restore state variables */
+
+ x->inCount = inCount % Nw;
+ return (w+7);
+}
+
+
+
+
+
+void vacancy_dsp(t_vacancy *x, t_signal **sp, short *count)
+{
+long i;
+
+#if MSP
+ for( i = 0; i < 3; i++ ){
+ x->connected[i] = count[i];
+ }
+#endif
+ /* signal is always connected in Pd */
+#if PD
+ for( i = 0; i < 3; i++ ){
+ x->connected[i] = 1;
+ }
+#endif
+
+ /* reinitialize if vector size or sampling rate has been changed */
+ if(x->vs != sp[0]->s_n || x->R != sp[0]->s_sr){
+ x->vs = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ vacancy_init(x,1);
+ }
+
+ dsp_add(vacancy_perform, 6, x,
+ sp[0]->s_vec,
+ sp[1]->s_vec,
+ sp[2]->s_vec,
+ sp[3]->s_vec,
+ sp[0]->s_n);
+}
+
diff --git a/xsyn~.c b/xsyn~.c
new file mode 100644
index 0000000..2940935
--- /dev/null
+++ b/xsyn~.c
@@ -0,0 +1,381 @@
+#include "MSPd.h"
+#include "fftease.h"
+
+#if MSP
+void *xsyn_class;
+#endif
+
+#if PD
+static t_class *xsyn_class;
+#endif
+
+#define OBJECT_NAME "xsyn~"
+
+typedef struct _xsyn
+{
+#if MSP
+ t_pxobject x_obj;
+#endif
+#if PD
+ t_object x_obj;
+ float x_f;
+#endif
+
+ int R;
+ int N;
+ int N2;
+ int Nw;
+ int Nw2;
+ int D;
+ int i;
+ float *input1;
+ float *buffer1;
+ float *channel1;
+
+
+ float *input2;
+ float *buffer2;
+ float *channel2;
+ //
+ int inCount;
+ float *Hwin;
+ float *Wanal;
+ float *Wsyn;
+ float *output;
+ /* xsyn vars */
+
+ float *c_lastphase_in1;
+ float *c_lastphase_in2;
+ float *c_lastphase_out;
+ float c_fundamental;
+ float c_factor_in;
+ float c_factor_out;
+
+ // float *filter ;
+ // for fast fft
+ float mult;
+ float *trigland;
+ int *bitshuffle;
+ int overlap;//overlap factor
+ int winfac;//window factor
+ int vs;//vector size
+ short mute;//flag
+} t_xsyn;
+
+void *xsyn_new(t_symbol *s, int argc, t_atom *argv);
+t_int *offset_perform(t_int *w);
+t_int *xsyn_perform(t_int *w);
+void xsyn_dsp(t_xsyn *x, t_signal **sp, short *count);
+void xsyn_assist(t_xsyn *x, void *b, long m, long a, char *s);
+void xsyn_dsp_free( t_xsyn *x );
+void xsyn_init(t_xsyn *x, short initialized);
+void xsyn_mute(t_xsyn *x, t_floatarg toggle);
+void xsyn_fftinfo(t_xsyn *x);
+void xsyn_overlap(t_xsyn *x, t_floatarg f);
+void xsyn_winfac(t_xsyn *x, t_floatarg f);
+
+void xsyn_dsp_free( t_xsyn *x )
+{
+#if MSP
+ dsp_free( (t_pxobject *) x);
+#endif
+ freebytes(x->c_lastphase_in1,0);
+ freebytes(x->c_lastphase_in2,0);
+ freebytes(x->c_lastphase_out,0);
+ freebytes(x->trigland,0);
+ freebytes(x->bitshuffle,0);
+ freebytes(x->Wanal,0);
+ freebytes(x->Wsyn,0);
+ freebytes(x->Hwin,0);
+ freebytes(x->input1,0);
+ freebytes(x->buffer1,0);
+ freebytes(x->channel1,0);
+ freebytes(x->input2,0);
+ freebytes(x->buffer2,0);
+ freebytes(x->channel2,0);
+ freebytes(x->output,0);
+}
+
+#if MSP
+void main(void)
+{
+ setup((t_messlist **)&xsyn_class, (method) xsyn_new, (method)xsyn_dsp_free,
+ (short)sizeof(t_xsyn), 0, A_GIMME, 0);
+ addmess((method)xsyn_dsp, "dsp", A_CANT, 0);
+ addmess((method)xsyn_assist,"assist",A_CANT,0);
+ addmess((method)xsyn_mute,"mute",A_FLOAT,0);
+ addmess((method)xsyn_overlap,"overlap",A_FLOAT,0);
+ addmess((method)xsyn_winfac,"winfac",A_DEFFLOAT,0);
+ addmess((method)xsyn_fftinfo,"fftinfo",0);
+ dsp_initclass();
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+#if PD
+void xsyn_tilde_setup(void)
+{
+ xsyn_class = class_new(gensym("xsyn~"), (t_newmethod)xsyn_new,
+ (t_method)xsyn_dsp_free ,sizeof(t_xsyn), 0,A_GIMME,0);
+ CLASS_MAINSIGNALIN(xsyn_class, t_xsyn, x_f);
+ class_addmethod(xsyn_class, (t_method)xsyn_dsp, gensym("dsp"), 0);
+ class_addmethod(xsyn_class, (t_method)xsyn_assist, gensym("assist"), 0);
+ class_addmethod(xsyn_class, (t_method)xsyn_mute, gensym("mute"), A_DEFFLOAT,0);
+ class_addmethod(xsyn_class, (t_method)xsyn_overlap, gensym("overlap"), A_DEFFLOAT,0);
+ class_addmethod(xsyn_class,(t_method)xsyn_winfac,gensym("winfac"),A_FLOAT,0);
+ class_addmethod(xsyn_class,(t_method)xsyn_fftinfo,gensym("fftinfo"),0);
+ post("%s %s",OBJECT_NAME,FFTEASE_ANNOUNCEMENT);
+}
+#endif
+
+void xsyn_mute(t_xsyn *x, t_floatarg toggle)
+{
+ x->mute = (short)toggle;
+}
+
+void xsyn_overlap(t_xsyn *x, t_floatarg f)
+{
+ int i = (int) f;
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->overlap = i;
+ xsyn_init(x,1);
+}
+
+void xsyn_winfac(t_xsyn *x, t_floatarg f)
+{
+ int i = (int)f;
+
+ if(!power_of_two(i)){
+ error("%f is not a power of two",f);
+ return;
+ }
+ x->winfac = i;
+ xsyn_init(x,2);
+}
+
+void xsyn_fftinfo(t_xsyn *x)
+{
+ if( ! x->overlap ){
+ post("zero overlap!");
+ return;
+ }
+ post("%s: FFT size %d, hopsize %d, windowsize %d", OBJECT_NAME, x->N, x->N/x->overlap, x->Nw);
+}
+
+
+void xsyn_assist (t_xsyn *x, void *b, long msg, long arg, char *dst)
+{
+ if (msg==1) {
+ switch (arg) {
+ case 0:
+ sprintf(dst,"(signal) Input 1 ");
+ break;
+ case 1:
+ sprintf(dst,"(signal) Input 2 ");
+ break;
+ }
+ } else if (msg==2) {
+ sprintf(dst,"(signal) Output ");
+ }
+}
+
+void *xsyn_new(t_symbol *s, int argc, t_atom *argv)
+{
+#if MSP
+ t_xsyn *x = (t_xsyn *)newobject(xsyn_class);
+ dsp_setup((t_pxobject *)x,2);
+ outlet_new((t_pxobject *)x, "signal");
+#endif
+#if PD
+ t_xsyn *x = (t_xsyn *)pd_new(xsyn_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+#endif
+ x->overlap = atom_getfloatarg(0,argc,argv);
+ x->winfac = atom_getfloatarg(1,argc,argv);
+ if(!power_of_two(x->overlap))
+ x->overlap = 4;
+ if(!power_of_two(x->winfac))
+ x->winfac = 1;
+
+ x->R = sys_getsr();
+ x->vs = sys_getblksize();
+
+ xsyn_init(x,0);
+ return (x);
+}
+
+void xsyn_init(t_xsyn *x, short initialized)
+{
+
+
+ x->D = x->vs;
+ x->N = x->D * x->overlap;
+ x->Nw = x->N * x->winfac;
+ limit_fftsize(&x->N,&x->Nw,OBJECT_NAME);
+ x->N2 = (x->N)>>1;
+ x->Nw2 = (x->Nw)>>1;
+ x->inCount = -(x->Nw);
+ x->mult = 1. / (float) x->N;
+
+ x->c_fundamental = (float) x->R/( (x->N2)<<1 );
+ x->c_factor_in = (float) x->R/((float)x->D * TWOPI);
+ x->c_factor_out = TWOPI * (float) x->D / (float) x->R;
+ if(!initialized){
+ x->mute = 0;
+ x->Wanal = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->Wsyn = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->Hwin = (float *) getbytes( MAX_Nw * sizeof(float) );
+ x->input1 = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->buffer1 = (float *) getbytes(MAX_N * sizeof(float));
+ x->channel1 = (float *) getbytes((MAX_N+2) * sizeof(float));
+ x->input2 = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->buffer2 = (float *) getbytes(MAX_N * sizeof(float));
+ x->channel2 = (float *) getbytes((MAX_N+2) * sizeof(float));
+ x->output = (float *) getbytes(MAX_Nw * sizeof(float));
+ x->bitshuffle = (int *) getbytes(MAX_N * 2 * sizeof(int));
+ x->trigland = (float *) getbytes(MAX_N * 2 * sizeof(float));
+ x->c_lastphase_in1 = (float *) getbytes((MAX_N2+1) * sizeof(float));
+ x->c_lastphase_in2 = (float *) getbytes((MAX_N2+1) * sizeof(float));
+ x->c_lastphase_out = (float *) getbytes((MAX_N2+1) * sizeof(float));
+ }
+ memset((char *)x->input1,0,x->Nw * sizeof(float));
+ memset((char *)x->input2,0,x->Nw * sizeof(float));
+ memset((char *)x->output,0,x->Nw * sizeof(float));
+ memset((char *)x->c_lastphase_in1,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->c_lastphase_in2,0,(x->N2+1) * sizeof(float));
+ memset((char *)x->c_lastphase_out,0,(x->N2+1) * sizeof(float));
+
+ init_rdft( x->N, x->bitshuffle, x->trigland);
+ makehanning( x->Hwin, x->Wanal, x->Wsyn, x->Nw, x->N, x->D, 0);
+}
+
+t_int *xsyn_perform(t_int *w)
+{
+ t_float *in1,*out, *in2;
+
+ float sample, outsamp ;
+
+ float *input1, *input2,
+ *output,
+ *buffer1, *buffer2,
+ *Wanal,
+ *Wsyn,
+ *channel1, *channel2;
+
+ int n,
+ i,j,
+ inCount,
+ R,
+ N,
+ N2,
+ D,
+ Nw;
+ float maxamp ;
+ int *bitshuffle;
+ float *trigland;
+ float mult;
+ float a1, a2, b1, b2;
+ int even, odd;
+
+
+
+ t_xsyn *x = (t_xsyn *) (w[1]);
+ in1 = (t_float *)(w[2]);
+ in2 = (t_float *)(w[3]);
+ out = (t_float *)(w[4]);
+ n = (int)(w[5]);
+
+ /* dereference struncture */
+ input1 = x->input1;
+ input2 = x->input2;
+ buffer1 = x->buffer1;
+ buffer2 = x->buffer2;
+ inCount = x->inCount;
+ R = x->R;
+ N = x->N;
+ N2 = x->N2;
+ D = x->D;
+ Nw = x->Nw;
+ Wanal = x->Wanal;
+ Wsyn = x->Wsyn;
+ output = x->output;
+ buffer1 = x->buffer1;
+ buffer2 = x->buffer2;
+ channel1 = x->channel1;
+ channel2 = x->channel2;
+ bitshuffle = x->bitshuffle;
+ trigland = x->trigland;
+ mult = x->mult;
+
+ if(x->mute){
+ while(n--){
+ *out++ = 0.0;
+ }
+ return (w+6);
+ }
+ x->inCount += D;
+
+ for ( j = 0 ; j < Nw - D ; j++ ){
+ input1[j] = input1[j+D];
+ input2[j] = input2[j+D];
+ }
+ for ( j = Nw - D; j < Nw; j++ ) {
+ input1[j] = *in1++;
+ input2[j] = *in2++;
+ }
+
+ fold( input1, Wanal, Nw, buffer1, N, inCount );
+ fold( input2, Wanal, Nw, buffer2, N, inCount );
+ rdft( N, 1, buffer1, bitshuffle, trigland );
+ rdft( N, 1, buffer2, bitshuffle, trigland );
+ leanconvert( buffer1, channel1, N2 );
+ leanconvert( buffer2, channel2, N2 );
+ maxamp = 0 ;
+ for( i = 0; i < N; i+= 2 ) {
+ if( channel2[i] > maxamp ) {
+ maxamp = channel2[i];
+ }
+ }
+ if( maxamp == 0.0 )
+ maxamp = 1.0 ;
+ for( i = 0; i < N; i+= 2 ) {
+ channel1[i] *= (channel2[i] / maxamp );
+ }
+
+ leanunconvert( channel1, buffer1, N2 );
+
+ rdft( N, -1, buffer1, bitshuffle, trigland );
+
+ overlapadd( buffer1, N, Wsyn, output, Nw, inCount);
+
+ for ( j = 0; j < D; j++ )
+ *out++ = output[j] * mult;
+
+ for ( j = 0; j < Nw - D; j++ )
+ output[j] = output[j+D];
+
+ for ( j = Nw - D; j < Nw; j++ )
+ output[j] = 0.;
+
+
+
+ /* restore state variables */
+ x->inCount = inCount;
+ return (w+6);
+}
+
+void xsyn_dsp(t_xsyn *x, t_signal **sp, short *count)
+{
+ if(x->vs != sp[0]->s_n || x->R != sp[0]->s_sr ){
+ x->vs = sp[0]->s_n;
+ x->R = sp[0]->s_sr;
+ xsyn_init(x,1);
+ }
+
+ dsp_add(xsyn_perform, 5, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+