aboutsummaryrefslogtreecommitdiff
path: root/pvwarp~.c
diff options
context:
space:
mode:
Diffstat (limited to 'pvwarp~.c')
-rw-r--r--pvwarp~.c873
1 files changed, 872 insertions, 1 deletions
diff --git a/pvwarp~.c b/pvwarp~.c
index 63a97db..3aa4209 100644
--- a/pvwarp~.c
+++ b/pvwarp~.c
@@ -1 +1,872 @@
-#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
+#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(!fftease_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(!fftease_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);
+}
+