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 --- mindwarp~.c | 643 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 643 insertions(+) create mode 100644 mindwarp~.c (limited to 'mindwarp~.c') 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); +} + -- cgit v1.2.1