#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(!fftease_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(!fftease_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); }