From b418fb91e7bb45d7b5f1eb8b19703441ae94eb13 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 9 Feb 2006 16:18:39 +0000 Subject: 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 system svn path=/trunk/externals/fftease/; revision=4574 --- pvgrain~.c | 536 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 536 insertions(+) create mode 100644 pvgrain~.c (limited to 'pvgrain~.c') 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); +} + -- cgit v1.2.1