pax_global_header00006660000000000000000000000064140170771000014507gustar00rootroot0000000000000052 comment=931d966dc0d0222fe09f3993af6a6bc386527567 pd-fftease-3.0.1/000077500000000000000000000000001401707710000135265ustar00rootroot00000000000000pd-fftease-3.0.1/CHANGELOG.txt000066400000000000000000000014661401707710000155650ustar00rootroot00000000000000FFTease Changelog Version 3.0.1 All the help files are updated. Several of the externals had an initialization bug that prevented them from being correctly initialized, if parameters were sent to them prior to the DACs being turned on. The following objects received this update: - burrow~ - disarrain~ - disarray~ - pvharm~ - pvoc~ - pvwarpb~ - pvwarp~ - shapee~ Some other externals may still have this issue. - pileup~ had a bug fixed where its “invert” mode previously did not work correctly. - shapee~ had a crashing bug fixed where previously the shape width put some internal indexes out of range. Version 3.0.0 This is a major cleanup and update from the original Pd version of FFTease, first written in 2006. The new version updates array access, provides help files, and implements a few bug fixes.pd-fftease-3.0.1/LICENSE.txt000066400000000000000000000021131401707710000153460ustar00rootroot00000000000000FFTease 3.0 is Copyright (c) 1999-2021 Eric Lyon and Christopher Penrose Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pd-fftease-3.0.1/MSPd.h000066400000000000000000000003241401707710000145010ustar00rootroot00000000000000#include #include #include #include /* for compiling under XP */ #ifndef PIOVERTWO #define PIOVERTWO 1.5707963268 #endif #ifndef TWOPI #define TWOPI 6.2831853072 #endif pd-fftease-3.0.1/Makefile000066400000000000000000000026621401707710000151740ustar00rootroot00000000000000# Makefile to build the 'fftease' library for Pure Data. # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. # library name lib.name = fftease # sources for the shared library shared.sources = \ bloscbank.c \ convert.c \ fft.c \ fft4.c \ fftease_setup.c \ fftease_utilities.c \ fold.c \ leanconvert.c \ leanunconvert.c \ limit_fftsize.c \ limited_oscbank.c \ makewindows.c \ oscbank.c \ overlapadd.c \ PenroseOscil.c \ PenroseRand.c \ power_of_two.c \ unconvert.c \ $(empty) # sources for the objectclasses class.sources = \ bthresher~.c \ burrow~.c \ cavoc~.c \ cavoc27~.c \ centerring~.c \ codepend~.c \ cross~.c \ dentist~.c \ disarrain~.c \ disarray~.c \ drown~.c \ enrich~.c \ ether~.c \ leaker~.c \ mindwarp~.c \ morphine~.c \ multyq~.c \ pileup~.c \ pvcompand~.c \ pvgrain~.c \ pvharm~.c \ pvoc~.c \ pvtuner~.c \ pvwarp~.c \ pvwarpb~.c \ reanimator~.c \ resent~.c \ residency~.c \ residency_buffer~.c \ schmear~.c \ scrape~.c \ shapee~.c \ swinger~.c \ taint~.c \ thresher~.c \ vacancy~.c \ xsyn~.c \ $(empty) # extra files datafiles = \ $(wildcard fftease-helpfiles/*.pd) \ LICENSE.txt \ README.md \ fftease-meta.pd \ lyonpotpourri-meta.pd \ smap.pd \ collect.pl \ $(empty) # extra dirs datadirs = sound \ $(empty) # include the actual build-system PDLIBBUILDER_DIR=pd-lib-builder include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder pd-fftease-3.0.1/PenroseOscil.c000066400000000000000000000014361401707710000163030ustar00rootroot00000000000000#include #include "PenroseOscil.h" t_float fftease_frequencyToIncrement( t_float samplingRate, t_float frequency, int bufferLength ) { return (frequency / samplingRate) * (t_float) bufferLength; } void fftease_makeSineBuffer( t_float *buffer, int bufferLength ) { int i; t_float myTwoPi = 8. * atan(1.); for ( i=0; i <= bufferLength; i++ ) *(buffer+i) = sin( myTwoPi * ((t_float) i / (t_float) bufferLength) ); return; } t_float fftease_bufferOscil( t_float *phase, t_float increment, t_float *buffer, int bufferLength ) { t_float sample; while ( *phase > bufferLength ) *phase -= bufferLength; while ( *phase < 0. ) *phase += bufferLength; sample = *( buffer + (int) (*phase) ); *phase += increment; return sample; } pd-fftease-3.0.1/PenroseOscil.h000066400000000000000000000004101401707710000162770ustar00rootroot00000000000000#include "fftease.h" t_float frequencyToIncrement( t_float samplingRate, t_float frequency, int bufferLength ); void makeSineBuffer( t_float *buffer, int bufferLength ); t_float bufferOscil( t_float *phase, t_float increment, t_float *buffer, int bufferLength ); pd-fftease-3.0.1/PenroseRand.c000066400000000000000000000004421401707710000161120ustar00rootroot00000000000000#include "PenroseRand.h" float fftease_rrand(int *seed) { int i = ((*seed = *seed * 1103515245 + 12345)>>16) & 077777; return((float)i/16384. - 1.); } float fftease_prand(int *seed) { int i = ((*seed = *seed * 1103515245 + 12345)>>16) & 077777; return((float)i/32768.); } pd-fftease-3.0.1/PenroseRand.h000066400000000000000000000001011401707710000161070ustar00rootroot00000000000000 float fftease_rrand(int *seed); float fftease_prand(int *seed); pd-fftease-3.0.1/README.md000066400000000000000000000065341401707710000150150ustar00rootroot00000000000000# Welcome to FFTease! **About FFTease** FFTease is a collection of objects designed to facilitate spectral sound processing in Max and Pd. The collection was designed by Eric Lyon and Christopher Penrose in 1999, and has been maintained by Eric Lyon since 2003. **List of Objects** - bthresher~ similar to thresher~ but with more control - burrow~ a cross-referenced filtering object - cavoc~ an 8-rule cellular automata that generates spectra - cavoc27~ a 27-rule cellular automata object - centerring~ a spectral modulation object - codepend~ a classic block convolution object - cross~ a cross synthesis object with gating - dentist~ a partial knockout object - disarrain~ an interpolating version of disarray~ - disarray~ a spectral redistribution object - drown~ a noise reduction (or increase) object - enrich~ an oscillator resynthesis with a user-designed waveform - ether~ another spectral compositing object - leaker~ a sieve-based cross fader - mindwarp~ a spectral formant warping object - morphine~ a morphing object - multyq~ a four band filter - pileup~ a spectral accumulation object - pvcompand~ a spectral compressor/expander object - pvgrain~ a spectrum analyzer for granular resynthesis - pvharm~ a harmonizer - pvoc~ an additive synthesis phase vocoder - pvtuner~ a spectrum quantizer for tuning to arbitrary scales - pvwarp~ a non-linear frequency warper - pvwarpb~ a non-linear frequency warper with a user-accessible warp array - reanimator~ an audio texture mapper - resent~ similar to residency~ but with independent bin control - residency~ a spectral sampler useful for time scaling - residency_buffer~ a spectral sampler that writes analysis data to a Pd array - schmear~ a spectral smear object - scrape~ a noise reduction (or increase) object with frequency control - shapee~ a frequency shaping object - swinger~ a phase swapping object - taint~ a cross synthesis object - thresher~ an amplitude/frequency sensitive gating object - vacancy~ a spectral compositing object - xsyn~ a cross synthesis with compression object **Compilation and Installation** All necessary files are contained in the folder "fftease," compiled for various flavors of Linux, macOS, and Windows. Download the appropriate package and move the folder "fftease" to a location accessible by Pd. On macOS, that location is typically "~/Documents/Pd/externals/". Alternatively, FFTease can be installed via Deken. Under the Pd menu item Help -> Find externals, search for "fftease" and then install it. You could also compile FFTease directly from the code in this repository. **Performance Considerations** The default Pd audio buffer settings for both I/O vector size and signal vector size will work fine for FFT sizes up to around 4096 or so. For larger FFT sizes, adjusting the Pd signal vector size and I/O vector size upward can dramatically improve performance. With larger FFT sizes, the reported CPU load may fluctuate. This is because a large FFT is being performed only once for several vectors worth of samples. The default FFT size is 1024, and the default overlap factor is 8. The maximum FFT size is 1073741824. **Acknowledgements** This update of FFTease was supported by coding, advice, and bug reports from @porres, @umlaeute, and @Lucarda. Happy sonic explorations! Eric Lyon ericlyon@vt.edu Blacksburg, Virginia February 28, 2021 pd-fftease-3.0.1/bloscbank.c000066400000000000000000000017341401707710000156350ustar00rootroot00000000000000#include "fftease.h" void fftease_bloscbank( t_float *S, t_float *O, int D, t_float iD, t_float *lf, t_float *la, t_float *index, t_float *tab, int len, t_float synt, int lo, int hi ) { int amp,freq,chan, i; t_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; } } } pd-fftease-3.0.1/bthresher~.c000066400000000000000000000362601401707710000160650ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *bthresher_class; #define OBJECT_NAME "bthresher~" typedef struct _bthresher { t_object x_obj; t_float x_f; t_fftease *fft; /* bthresher vars */ t_float *move_threshold; t_float *composite_frame ; int *frames_left; int max_hold_frames; t_float max_hold_time; int first_frame; t_float *damping_factor ; t_float thresh_scalar; t_float damp_scalar; short thresh_connected; short damping_connected; void *list_outlet; void *misc_outlet; t_atom *list_data; short mute; short bypass; t_float init_thresh; t_float init_damping; t_float tadv; short inf_hold; } t_bthresher; static void *bthresher_new(t_symbol *s, int argc, t_atom *argv); static void bthresher_dsp(t_bthresher *x, t_signal **sp); static t_int *bthresher_perform(t_int *w); static void bthresher_mute(t_bthresher *x, t_float f); static void bthresher_fftinfo(t_bthresher *x); static void bthresher_free(t_bthresher *x); static void bthresher_bin(t_bthresher *x, t_float bin_num, t_float threshold, t_float damper); static void bthresher_rdamper(t_bthresher *x, t_float min, t_float max ); static void bthresher_rthreshold(t_bthresher *x, t_float min, t_float max); static void bthresher_dump(t_bthresher *x ); static void bthresher_list (t_bthresher *x, t_symbol *msg, short argc, t_atom *argv); static void bthresher_init(t_bthresher *x); static t_float bthresher_boundrand(t_float min, t_float max); static void bthresher_allthresh(t_bthresher *x, t_float f); static void bthresher_alldamp(t_bthresher *x, t_float f); static void bthresher_inf_hold(t_bthresher *x, t_float f); static void bthresher_max_hold(t_bthresher *x, t_float f); static void do_bthresher(t_bthresher *x); static void bthresher_oscbank(t_bthresher *x, t_float flag); static void bthresher_synthresh(t_bthresher *x, t_float thresh); static void bthresher_transpose(t_bthresher *x, t_float tf); static void bthresher_version(void); void bthresher_tilde_setup(void) { t_class *c; c = class_new(gensym("bthresher~"), (t_newmethod)bthresher_new, (t_method)bthresher_free,sizeof(t_bthresher), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_bthresher, x_f); class_addmethod(c,(t_method)bthresher_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)bthresher_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)bthresher_fftinfo,gensym("fftinfo"),0); class_addmethod(c,(t_method)bthresher_oscbank,gensym("oscbank"),A_FLOAT,0); class_addmethod(c,(t_method)bthresher_transpose,gensym("transpose"),A_FLOAT,0); class_addmethod(c,(t_method)bthresher_synthresh,gensym("synthresh"),A_FLOAT,0); class_addmethod(c,(t_method)bthresher_bin, gensym("bin"), A_FLOAT, A_FLOAT, A_FLOAT, 0); class_addmethod(c,(t_method)bthresher_rdamper, gensym("rdamper"), A_DEFFLOAT, A_DEFFLOAT, 0); class_addmethod(c,(t_method)bthresher_rthreshold, gensym("rthreshold"), A_DEFFLOAT, A_DEFFLOAT, 0); class_addmethod(c,(t_method)bthresher_dump,gensym("dump"),0); class_addmethod(c,(t_method)bthresher_list,gensym("list"),A_GIMME,0); class_addmethod(c,(t_method)bthresher_alldamp,gensym("alldamp"),A_FLOAT,0); class_addmethod(c,(t_method)bthresher_allthresh,gensym("allthresh"),A_FLOAT,0); class_addmethod(c,(t_method)bthresher_inf_hold,gensym("inf_hold"),A_FLOAT,0); class_addmethod(c,(t_method)bthresher_max_hold,gensym("max_hold"),A_FLOAT,0); bthresher_class = c; fftease_announce(OBJECT_NAME); } void bthresher_fftinfo( t_bthresher *x ) { fftease_fftinfo( x->fft, OBJECT_NAME ); } void bthresher_free( t_bthresher *x ){ t_fftease *fft = x->fft; fftease_free(fft); /* external-specific memory */ free(x->composite_frame); free(x->frames_left); free(x->move_threshold); free(x->damping_factor); free(x->list_data); } void bthresher_max_hold(t_bthresher *x, t_float 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_float f) { x->inf_hold = (int)f; } void bthresher_allthresh(t_bthresher *x, t_float f) { int i; t_fftease *fft = x->fft; //post("thresh %f",f); for(i=0;i < fft->N2+1;i++) x->move_threshold[i] = f; } void bthresher_alldamp(t_bthresher *x, t_float f) { int i; t_fftease *fft = x->fft; //post("damp %f",f); for(i=0;i < fft->N2+1;i++) x->damping_factor[i] = f; } void bthresher_mute(t_bthresher *x, t_float f){ x->mute = f; } void bthresher_list (t_bthresher *x, t_symbol *msg, short argc, t_atom *argv) { int i, bin, idiv; t_float fdiv; t_float *damping_factor = x->damping_factor; t_float *move_threshold = x->move_threshold; // post("reading %d elements", argc); idiv = fdiv = (t_float) argc / 3.0 ; if( fdiv - idiv > 0.0 ) { post("list must be in triplets"); return; } 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); } } void bthresher_dump (t_bthresher *x) { t_atom *list_data = x->list_data; t_float *damping_factor = x->damping_factor; t_float *move_threshold = x->move_threshold; int i,j, count; for( i = 0, j = 0; i < x->fft->N2 * 3 ; i += 3, j++ ) { SETFLOAT(list_data+i,(t_float)j); SETFLOAT(list_data+(i+1),damping_factor[j]); SETFLOAT(list_data+(i+2),move_threshold[j]); } count = x->fft->N2 * 3; outlet_list(x->list_outlet,0,count,list_data); return; } void *bthresher_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft; 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")); x->fft = (t_fftease *) calloc( 1, sizeof(t_fftease) ); fft = x->fft; fft->initialized = 0; x->init_thresh = 0.1; x->init_damping = 0.99; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void bthresher_transpose(t_bthresher *x, t_float tf) { x->fft->P = (t_float) tf; } void bthresher_synthresh(t_bthresher *x, t_float thresh) { x->fft->synt = (t_float) thresh; } void bthresher_init(t_bthresher *x) { int i; t_fftease *fft = x->fft; short initialized = fft->initialized; fftease_init(fft); 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->composite_frame = (t_float *) calloc(fft->N + 2, sizeof(t_float)); x->frames_left = (int *) calloc(fft->N + 2, sizeof(int)); // TRIPLETS OF bin# damp_factor threshold x->list_data = (t_atom *) calloc((fft->N2 + 1) * 3, sizeof(t_atom)); x->move_threshold = (t_float *) calloc((fft->N2+1), sizeof(t_float)); x->damping_factor = (t_float *) calloc((fft->N2+1), sizeof(t_float)); for(i = 0; i < fft->N2+1; i++) { x->move_threshold[i] = x->init_thresh; x->damping_factor[i] = x->init_damping; } } else { x->list_data = (t_atom *) realloc((void *)x->list_data, (fft->N2 + 1) * 3 * sizeof(t_atom)); x->move_threshold = (t_float *) realloc((void *)x->move_threshold, (fft->N2+1) * sizeof(t_float)); x->damping_factor = (t_float *) realloc((void *)x->damping_factor, (fft->N2+1) * sizeof(t_float)); } // NEED TO HANDLE REALLOC CASE!!! x->tadv = (t_float) fft->D / (t_float) fft->R; x->max_hold_frames = x->max_hold_time / x->tadv; } void bthresher_version(void) { fftease_version(OBJECT_NAME); } void bthresher_rdamper(t_bthresher *x, t_float min, t_float max) { int i; for( i = 0; i < x->fft->N2; i++ ) { x->damping_factor[i] = bthresher_boundrand(min, max); } } void bthresher_rthreshold( t_bthresher *x, t_float min, t_float max ) { int i; for( i = 0; i < x->fft->N2; i++ ) { x->move_threshold[i] = bthresher_boundrand(min, max); } } void bthresher_bin(t_bthresher *x, t_float bin_num, t_float damper, t_float threshold) { int bn = (int) bin_num; if( bn >= 0 && bn < x->fft->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); } } static void do_bthresher(t_bthresher *x) { t_fftease *fft = x->fft; int N = fft->N; t_float *channel = fft->channel; t_float *damping_factor = x->damping_factor; t_float *move_threshold = x->move_threshold; t_float *composite_frame = x->composite_frame; int max_hold_frames = x->max_hold_frames; int *frames_left = x->frames_left; t_float thresh_scalar = x->thresh_scalar; t_float damp_scalar = x->damp_scalar; short inf_hold = x->inf_hold; int i, j; fftease_fold(fft); fftease_rdft(fft,1); fftease_convert(fft); 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; /* denormals protection */ if( composite_frame[i] < 0.000001 ) composite_frame[i] = 0.0; } } } 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]; // was a bug here ?? composite_frame[i] *= damping_factor[j] * damp_scalar; if( composite_frame[i] < 0.000001 ) /* denormals protection */ composite_frame[i] = 0.0; } } } } // use memcopy for(i = 0; i < N+2; i++){ channel[i] = composite_frame[i]; } if(fft->obank_flag){ fftease_oscbank(fft); } else { fftease_unconvert(fft); fftease_rdft(fft,-1); fftease_overlapadd(fft); } } void bthresher_oscbank(t_bthresher *x, t_float flag) { x->fft->obank_flag = (short) flag; } t_int *bthresher_perform(t_int *w) { int i,j; t_bthresher *x = (t_bthresher *) (w[1]); t_sample *MSPInputVector = (t_sample *)(w[2]); t_sample *inthresh = (t_sample *)(w[3]); t_sample *damping = (t_sample *)(w[4]); t_sample *MSPOutputVector = (t_sample *)(w[5]); t_fftease *fft = x->fft; int MSPVectorSize = fft->MSPVectorSize; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; t_float *input = fft->input; t_float *output = fft->output; int Nw = fft->Nw; t_float mult = fft->mult; int D = fft->D; if(x->mute) { for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+6; } x->thresh_scalar = *inthresh; x->damp_scalar = *damping; if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_bthresher(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_bthresher(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_bthresher(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+6; } void bthresher_dsp(t_bthresher *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ bthresher_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(bthresher_perform, 5, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); } } t_float bthresher_boundrand( t_float min, t_float max) { t_float frand; frand = (t_float) (rand() % 32768)/ 32768.0; return (min + frand * (max-min) ); } pd-fftease-3.0.1/burrow~.c000066400000000000000000000256661401707710000154270ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *burrow_class; #define OBJECT_NAME "burrow~" typedef struct _burrow { t_object x_obj; t_float x_f; t_fftease *fft; t_fftease *fft2; // for cross synthesis use int invert; t_float threshold; t_float multiplier; short mute; short bypass; } t_burrow; static void *burrow_new(t_symbol *s, int argc, t_atom *argv); static void burrow_dsp(t_burrow *x, t_signal **sp); static t_int *burrow_perform(t_int *w); static void burrow_init(t_burrow *x); static void burrow_free(t_burrow *x); static void burrow_invert(t_burrow *x, t_floatarg toggle); static void burrow_mute(t_burrow *x, t_floatarg toggle); static void burrow_fftinfo(t_burrow *x); static void burrow_bypass(t_burrow *x, t_floatarg toggle); static void burrow_winfac(t_burrow *x, t_floatarg f); static void do_burrow(t_burrow *x); void burrow_tilde_setup(void) { t_class *c; c = class_new(gensym("burrow~"), (t_newmethod)burrow_new, (t_method)burrow_free,sizeof(t_burrow), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_burrow, x_f); class_addmethod(c,(t_method)burrow_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)burrow_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)burrow_fftinfo,gensym("fftinfo"),0); class_addmethod(c,(t_method)burrow_invert,gensym("invert"), A_FLOAT, 0); burrow_class = c; fftease_announce(OBJECT_NAME); } void burrow_free(t_burrow *x) { fftease_free(x->fft); fftease_free(x->fft2); } void burrow_invert(t_burrow *x, t_floatarg toggle) { x->invert = (int)toggle; } void burrow_mute(t_burrow *x, t_floatarg toggle) { x->mute = (int)toggle; } void burrow_bypass(t_burrow *x, t_floatarg toggle) { x->bypass = (short)toggle; } void burrow_winfac(t_burrow *x, t_floatarg f) { x->fft->winfac = (int) f; x->fft2->winfac = (int) f; burrow_init(x); } void burrow_fftinfo( t_burrow *x ) { fftease_fftinfo(x->fft, OBJECT_NAME); } void burrow_init(t_burrow *x) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; short initialized = fft->initialized; fftease_init(fft); fftease_init(fft2); } void *burrow_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft, *fft2; t_burrow *x = (t_burrow *) pd_new(burrow_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")); x->fft = (t_fftease *) calloc(1, sizeof(t_fftease)); x->fft2 = (t_fftease *) calloc(1, sizeof(t_fftease)); fft = x->fft; fft2 = x->fft2; fft->initialized = fft2->initialized = 0; x->threshold = 0.0; x->multiplier = 0.01; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; fft2->N = FFTEASE_DEFAULT_FFTSIZE; fft2->overlap = FFTEASE_DEFAULT_OVERLAP; fft2->winfac = FFTEASE_DEFAULT_WINFAC; // additional initializations (which may be reset when DACs are turned on) fft2->MSPVectorSize = fft->MSPVectorSize = sys_getblksize(); fft2->R = fft->R = sys_getsr(); x->mute = 0; x->invert = 0; if(argc > 0){ fft->N = fft2->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = fft2->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } t_int *burrow_perform(t_int *w) { /* get our inlets and outlets */ t_burrow *x = (t_burrow *) (w[1]); t_sample *MSPInputVector1 = (t_sample *)(w[2]); t_sample *MSPInputVector2 = (t_sample *)(w[3]); t_sample *flt_threshold = (t_sample *)(w[4]); t_sample *flt_multiplier = (t_sample *)(w[5]); t_sample *MSPOutputVector = (t_sample *)(w[6]); t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int MSPVectorSize = fft->MSPVectorSize; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; t_float *internalInputVector1 = fft->internalInputVector; t_float *internalInputVector2 = fft2->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int D = fft->D; int Nw = fft->Nw; t_float *output = fft->output; t_float mult = fft->mult; if( fft->obank_flag ) mult *= FFTEASE_OSCBANK_SCALAR; int i,j, invert = 0, threshold = 1., multiplier = 1.; t_float *inputOne, *inputTwo, *bufferOne, *bufferTwo, *channelOne, *channelTwo; /* dereference structure */ inputOne = fft->input; inputTwo = fft2->input; bufferOne = fft->buffer; bufferTwo = fft2->buffer; channelOne = fft->channel; channelTwo = fft2->channel; multiplier = x->multiplier; threshold = x->threshold; invert = x->invert; mult = fft->mult; x->threshold = *flt_threshold; x->multiplier = *flt_multiplier; /* save some CPUs if muted */ if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+7; } if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), MSPInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), MSPInputVector2, D * sizeof(t_float)); do_burrow(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw-D), MSPInputVector1 + (D*i), D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw-D), MSPInputVector2 + (D*i), D * sizeof(t_float)); do_burrow(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector1 + (operationCount * MSPVectorSize), MSPInputVector1, MSPVectorSize * sizeof(t_float)); memcpy(internalInputVector2 + (operationCount * MSPVectorSize), MSPInputVector2, MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize), MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), internalInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), internalInputVector2, D * sizeof(t_float)); do_burrow(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+7; } static void do_burrow(t_burrow *x) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int i; int N2 = fft->N2; t_float a1, b1, a2, b2; int even, odd; /* dereference structure */ t_float *bufferOne = fft->buffer; t_float *bufferTwo = fft2->buffer; t_float *channelOne = fft->channel; t_float *channelTwo = fft2->channel; t_float multiplier = x->multiplier; t_float threshold = x->threshold; int invert = x->invert; /* apply hamming window and fold our window buffer into the fft buffer */ fftease_fold(fft); fftease_fold(fft2); /* do an fft */ fftease_rdft(fft, 1); fftease_rdft(fft2, 1); 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; } } 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; } } /* 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 */ fftease_rdft(fft, -1); /* dewindow our result */ fftease_overlapadd(fft); } void burrow_dsp(t_burrow *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(!samplerate) return; if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); fft2->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft2); } if(fft->R != samplerate ){ fft->R = samplerate; fft2->R = samplerate; } if(reset_required){ burrow_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(burrow_perform, 6, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[4]->s_vec); } } pd-fftease-3.0.1/cavoc27~.c000066400000000000000000000453511401707710000153440ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *cavoc27_class; #define OBJECT_NAME "cavoc27~" /* NOTE THIS IS A MORE COMPLEX CA WITH 3 DIFFERENT STATES */ typedef struct _cavoc27 { t_object x_obj; float x_f; t_fftease *fft; t_float *ichannel; //for interpolation t_float *tmpchannel; // for spectrum capture t_float frame_duration; int max_bin; t_float fundamental; t_float *last_frame; short left; short right; short center; short *rule; t_float start_breakpoint; int hold_frames; int frames_left; int set_count; short interpolate_flag; short capture_flag; short capture_lock; void *list_outlet; t_atom *list_data; short mute; short external_trigger; short trigger_value; // set to 1 when a bang is received t_float topfreq; // highest to synthesize - Nyquist by default t_float bottomfreq; t_float *freqs; t_float *amps; short manual_mode; // respond to outside short freeze; // flag to maintain current spectrum long fftsize_attr; long overlap_attr; t_float density; t_float hold_time; //hold time in seconds } t_cavoc27; static void *cavoc27_new(t_symbol *s, int argc, t_atom *argv); static void cavoc27_dsp(t_cavoc27 *x, t_signal **sp); static t_int *cavoc27_perform(t_int *w); static void cavoc27_free( t_cavoc27 *x); static int cavoc27_apply_rule( short left, short right, short center, short *rule); static void cavoc27_rule (t_cavoc27 *x, t_symbol *msg, short argc, t_atom *argv); static void cavoc27_density (t_cavoc27 *x, t_floatarg density); static void cavoc27_hold_time (t_cavoc27 *x, t_floatarg hold_time); static void cavoc27_interpolate (t_cavoc27 *x, t_floatarg interpolate); static void cavoc27_capture_spectrum (t_cavoc27 *x, t_floatarg flag ); static void cavoc27_retune (t_cavoc27 *x, t_floatarg min, t_floatarg max); static void cavoc27_mute (t_cavoc27 *x, t_floatarg toggle); static void cavoc27_init(t_cavoc27 *x); static void cavoc27_rand_set_spectrum(t_cavoc27 *x); static void cavoc27_rand_set_rule(t_cavoc27 *x); static void cavoc27_fftinfo(t_cavoc27 *x); static void cavoc27_oscbank(t_cavoc27 *x, t_floatarg flag); static void cavoc27_transpose (t_cavoc27 *x, t_floatarg pfac); static void cavoc27_noalias(t_cavoc27 *x, t_floatarg flag); static void cavoc27_manual(t_cavoc27 *x, t_floatarg tog); static void cavoc27_trigger(t_cavoc27 *x); static void cavoc27_freeze(t_cavoc27 *x, t_floatarg tog); void cavoc27_tilde_setup(void) { t_class *c; c = class_new(gensym("cavoc27~"), (t_newmethod)cavoc27_new, (t_method)cavoc27_free,sizeof(t_cavoc27), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_cavoc27, x_f); class_addmethod(c,(t_method)cavoc27_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)cavoc27_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)cavoc27_oscbank,gensym("oscbank"),A_FLOAT,0); class_addmethod(c,(t_method)cavoc27_transpose,gensym("transpose"),A_FLOAT,0); class_addmethod(c,(t_method)cavoc27_fftinfo,gensym("fftinfo"),0); class_addmethod(c,(t_method)cavoc27_rule,gensym("rule"),A_GIMME,0); class_addmethod(c,(t_method)cavoc27_interpolate,gensym("interpolate"),A_FLOAT,0); class_addmethod(c,(t_method)cavoc27_retune,gensym("retune"),A_FLOAT,A_FLOAT,0); class_addmethod(c,(t_method)cavoc27_capture_spectrum,gensym("capture_spectrum"),A_FLOAT,0); class_addmethod(c,(t_method)cavoc27_noalias,gensym("noalias"),A_FLOAT,0); class_addmethod(c,(t_method)cavoc27_manual,gensym("manual"),A_FLOAT,0); class_addmethod(c,(t_method)cavoc27_freeze,gensym("freeze"),A_FLOAT,0); class_addmethod(c,(t_method)cavoc27_trigger,gensym("trigger"),0); class_addmethod(c,(t_method)cavoc27_density,gensym("density"),A_FLOAT,0); class_addmethod(c,(t_method)cavoc27_hold_time,gensym("hold_time"),A_FLOAT,0); cavoc27_class = c; fftease_announce(OBJECT_NAME); } void cavoc27_rand_set_rule(t_cavoc27 *x) { int i; float rval; for( i = 0; i < 27; i++ ){ rval = fftease_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_freeze(t_cavoc27 *x, t_floatarg tog) { x->freeze = (short) tog; } void cavoc27_manual(t_cavoc27 *x, t_floatarg tog) { x->manual_mode = (short) tog; } void cavoc27_trigger(t_cavoc27 *x) { x->external_trigger = 1; } void cavoc27_retune(t_cavoc27 *x, t_floatarg min, t_floatarg max) { int i; t_fftease *fft = x->fft; t_float *tmpchannel = x->tmpchannel; t_float *last_frame = x->last_frame; 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 = 1; i < fft->N + 1; i += 2 ){ last_frame[i] = tmpchannel[i] = fft->c_fundamental * (float) (i / 2) * fftease_randf(min, max); } } void cavoc27_transpose (t_cavoc27 *x, t_floatarg pfac) { t_fftease *fft = x->fft; fft->P = (float) pfac; fft->pitch_increment = fft->P*fft->L/fft->R; } void cavoc27_mute (t_cavoc27 *x, t_floatarg toggle) { x->mute = (short)toggle; } void cavoc27_interpolate(t_cavoc27 *x, t_floatarg flag) { x->interpolate_flag = (short) flag; } void cavoc27_capture_spectrum(t_cavoc27 *x, t_floatarg flag ) { x->capture_lock = (short)flag; // post("capture flag: %d", x->capture_lock); } 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 ){ fftease_free(x->fft); free(x->fft); free(x->ichannel); free(x->tmpchannel); free(x->last_frame); free(x->rule); } void *cavoc27_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft; t_cavoc27 *x = (t_cavoc27 *)pd_new(cavoc27_class); outlet_new(&x->x_obj, gensym("signal")); x->fft = (t_fftease *) calloc(1, sizeof(t_fftease)); fft = x->fft; fft->initialized = 0; x->hold_time = 1000.0; x->density = 0.1; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; x->freeze = 0; x->start_breakpoint = 1.0 - x->density; fft->obank_flag = 0; // x->manual_mode = 0; // new try // x->frames_left = 0; // new try if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv); } if(argc > 2){ x->density = atom_getfloatarg(2, argc, argv); } if(argc > 3){ x->hold_time = atom_getfloatarg(3, argc, argv); } return x; } void cavoc27_noalias(t_cavoc27 *x, t_floatarg flag) { x->fft->noalias = (short) flag; } void cavoc27_oscbank(t_cavoc27 *x, t_floatarg flag) { x->fft->obank_flag = (short) flag; } void cavoc27_fftsize(t_cavoc27 *x, t_floatarg f) { x->fft->N = (int) f; cavoc27_init(x); } void cavoc27_overlap(t_cavoc27 *x, t_floatarg f) { x->fft->overlap = (int) f; cavoc27_init(x); } void cavoc27_winfac(t_cavoc27 *x, t_floatarg f) { x->fft->winfac = (int) f; cavoc27_init(x); } void cavoc27_fftinfo(t_cavoc27 *x) { fftease_fftinfo( x->fft, OBJECT_NAME ); post("frames left %d", x->frames_left); post("no alias: %d", x->fft->noalias); } void cavoc27_init(t_cavoc27 *x) { int i; t_fftease *fft = x->fft; short initialized = fft->initialized; fftease_init(fft); if(! fft->R ){ error("cavoc27~: zero sampling rate!"); return; } x->frame_duration = (float)fft->D/(float) fft->R; x->hold_frames = (int) ( (x->hold_time/1000.0)/x->frame_duration); x->frames_left = x->hold_frames; x->trigger_value = 0; x->set_count = 0; if(!initialized){ srand(time(0)); x->interpolate_flag = 0; x->capture_lock = 0; x->mute = 0; x->ichannel = (t_float *) calloc((fft->N+2), sizeof(t_float)); x->tmpchannel = (t_float *) calloc((fft->N+2), sizeof(t_float)); x->last_frame = (t_float *) calloc((fft->N+2), sizeof(t_float)); x->rule = (short *) calloc(27, sizeof(short)); } else { x->ichannel = (t_float *)realloc(x->ichannel,(fft->N+2)*sizeof(t_float)); x->tmpchannel = (t_float *)realloc(x->tmpchannel,(fft->N+2)*sizeof(t_float)); x->last_frame = (t_float *)realloc(x->last_frame,(fft->N+2)*sizeof(t_float)); } if(x->frame_duration != 0){ x->hold_frames = (int) ( (x->hold_time/1000.0) / x->frame_duration); } else { post("%s: zero FFT frame duration", OBJECT_NAME); } if( x->hold_frames < 1 ) x->hold_frames = 1; cavoc27_rand_set_rule(x); cavoc27_rand_set_spectrum(x); for( i = 0; i < fft->N+2; i++ ){ x->last_frame[i] = fft->channel[i]; } } void cavoc27_rand_set_spectrum(t_cavoc27 *x) { int i; float rval; t_fftease *fft = x->fft; t_float *channel = x->tmpchannel; //set spectrum for( i = 0; i < fft->N2 + 1; i++ ){ if( fftease_randf(0.0, 1.0) > x->start_breakpoint){ rval = fftease_randf(0.0, 1.0); if( rval < 0.5 ){ channel[ i * 2 ] = 1; } else { channel[ i * 2 ] = 2; } ++(x->set_count); } else { channel[ i * 2 ] = 0; } channel[ i * 2 + 1 ] = fft->c_fundamental * (float) i * fftease_randf(.9,1.1); } } static void do_cavoc27(t_cavoc27 *x) { t_fftease *fft = x->fft; int i; int frames_left = x->frames_left; int N = fft->N; t_float *tmpchannel = x->tmpchannel; t_float *ichannel = x->ichannel; int hold_frames = x->hold_frames; short *rule = x->rule; short left = x->left; short right = x->right; short center = x->center; t_float *last_frame = x->last_frame; t_float frak; short manual_mode = x->manual_mode; short trigger; short interpolate_flag = x->interpolate_flag; t_float *channel = fft->channel; if( manual_mode ){ trigger = x->external_trigger; } else { trigger = 0; } if( x->capture_flag || (x->capture_lock && ! x->freeze)) { fftease_fold(fft); fftease_rdft(fft,1); fftease_convert(fft); for( i = 1; i < fft->N+1; i += 2){ tmpchannel[i] = channel[i]; } } if( ! manual_mode ){ if( --frames_left <= 0 ){ trigger = 1; } // post("frames left %d trigger %d\n", frames_left, trigger); } if(trigger && ! x->freeze){ for( i = 0; i < fft->N+1; i++ ){ last_frame[i] = tmpchannel[i]; } frames_left = hold_frames; for( i = 2; i < fft->N; i+=2 ){ left = last_frame[ i - 2 ]; center = last_frame[i] ; right = last_frame[i+2]; tmpchannel[i] = cavoc27_apply_rule(left, right, center, rule ); } // boundary cases center = last_frame[0]; right = last_frame[2]; left = last_frame[N]; tmpchannel[0] = cavoc27_apply_rule(left, right, center, rule ); center = last_frame[N]; right = last_frame[0]; left = last_frame[N - 2]; tmpchannel[N] = cavoc27_apply_rule(left, right, center, rule ); x->external_trigger = trigger = 0 ; } if( interpolate_flag && ! x->freeze){ frak = 1.0 - ((float) frames_left / (float) hold_frames); for( i = 0; i freeze){ for( i = 0; i < N+2; i++){ channel[i] = tmpchannel[i]; } } if(fft->obank_flag){ fftease_oscbank(fft); } else { fftease_unconvert(fft); fftease_rdft(fft, -1); fftease_overlapadd(fft); } x->frames_left = frames_left; } t_int *cavoc27_perform(t_int *w) { int i,j; //////////// t_cavoc27 *x = (t_cavoc27 *) (w[1]); t_float *MSPInputVector = (t_float *) (w[2]); t_float *MSPOutputVector = (t_float *) (w[3]); t_fftease *fft = x->fft; int D = fft->D; int Nw = fft->Nw; t_float *input = fft->input; t_float *output = fft->output; t_float mult = fft->mult; int MSPVectorSize = fft->MSPVectorSize; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+4; } if(fft->obank_flag){ mult *= FFTEASE_OSCBANK_SCALAR; } if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_cavoc27(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_cavoc27(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_cavoc27(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+4; } 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 } void cavoc27_density(t_cavoc27 *x, t_floatarg density) { int i; t_fftease *fft = x->fft; t_float *channel = x->tmpchannel; 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 < fft->N2 + 1; i++ ){ if( fftease_randf(0.0, 1.0) > x->start_breakpoint ){ if( fftease_randf(0.0,1.0) > 0.5 ){ channel[ i * 2 ] = 1; } else { channel[ i * 2 ] = 2; } ++(x->set_count); } else { channel[ i * 2 ] = 0; } } for( i = 0; i < fft->N+2; i++ ){ x->last_frame[i] = channel[i]; } } 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->fft->initialized){ return; } if(! x->frame_duration){ error("%s: zero frame duration",OBJECT_NAME); return; } x->hold_frames = (int) ( (x->hold_time/1000.0) / x->frame_duration); if( x->hold_frames < 1 ) x->hold_frames = 1; } void cavoc27_dsp(t_cavoc27 *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(!samplerate) return; if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate ){ fft->R = samplerate; } if(reset_required){ cavoc27_init(x); } dsp_add(cavoc27_perform, 3, x, sp[0]->s_vec, sp[1]->s_vec); } pd-fftease-3.0.1/cavoc~.c000066400000000000000000000321731401707710000151710ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *cavoc_class; #define OBJECT_NAME "cavoc~" typedef struct _cavoc { t_object x_obj; float x_f; t_fftease *fft; t_float frame_duration; int max_bin; t_float fundamental; short left; short right; short center; short *rule; t_float start_breakpoint; int hold_frames; int frames_left; int set_count; void *list_outlet; t_atom *list_data; short mute; short external_trigger; short trigger_value; // set to 1 when a bang is received t_float topfreq; // highest to synthesize - Nyquist by default t_float bottomfreq; t_float *freqs; t_float *amps; t_float *cavoc; t_float density; // treat as attribute t_float hold_time; // treat as attribute } t_cavoc; static void *cavoc_new(t_symbol *msg, short argc, t_atom *argv); static void cavoc_dsp(t_cavoc *x, t_signal **sp); static t_int *cavoc_perform(t_int *w); static void cavoc_free( t_cavoc *x ); static int cavoc_apply_rule( short left, short right, short center, short *rule); static float cavoc_randf(float min, float max); static void cavoc_rule (t_cavoc *x, t_symbol *msg, short argc, t_atom *argv); static void cavoc_retune (t_cavoc *x, t_floatarg min, t_floatarg max); static void cavoc_mute (t_cavoc *x, t_floatarg toggle); static void cavoc_external_trigger(t_cavoc *x, t_floatarg toggle); static void cavoc_init(t_cavoc *x); static void cavoc_bang(t_cavoc *x); static void cavoc_topfreq(t_cavoc *x, t_floatarg tf); static void cavoc_oscbank(t_cavoc *x, t_floatarg flag); static void cavoc_density(t_cavoc *x, t_floatarg f); static void cavoc_hold_time(t_cavoc *x, t_floatarg f); static void build_spectrum(t_cavoc *x, float min, float max); static void cavoc_bottomfreq(t_cavoc *x, t_floatarg bf); static void cavoc_fftinfo( t_cavoc *x ); void cavoc_tilde_setup(void) { t_class *c; c = class_new(gensym("cavoc~"), (t_newmethod)cavoc_new, (t_method)cavoc_free,sizeof(t_cavoc), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_cavoc, x_f); class_addmethod(c,(t_method)cavoc_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)cavoc_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)cavoc_oscbank,gensym("oscbank"),A_FLOAT,0); class_addmethod(c,(t_method)cavoc_rule,gensym("rule"),A_GIMME,0); class_addmethod(c,(t_method)cavoc_external_trigger,gensym("external_trigger"),A_FLOAT,0); class_addmethod(c,(t_method)cavoc_bang,gensym("bang"),0); class_addmethod(c,(t_method)cavoc_retune,gensym("retune"),A_FLOAT,A_FLOAT,0); class_addmethod(c,(t_method)cavoc_topfreq,gensym("topfreq"),A_FLOAT,0); class_addmethod(c,(t_method)cavoc_bottomfreq,gensym("bottomfreq"),A_FLOAT,0); class_addmethod(c,(t_method)cavoc_density,gensym("density"),A_FLOAT,0); class_addmethod(c,(t_method)cavoc_hold_time,gensym("hold_time"),A_FLOAT,0); cavoc_class = c; fftease_announce(OBJECT_NAME); } void cavoc_fftinfo( t_cavoc *x ) { t_fftease *fft = x->fft; fftease_fftinfo( fft, OBJECT_NAME ); } void cavoc_density(t_cavoc *x, t_floatarg density) { int i; t_fftease *fft = x->fft; 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 < fft->N2 + 1; i++ ){ if( cavoc_randf(0.0, 1.0) > x->start_breakpoint ){ x->amps[ i ] = 1; ++(x->set_count); } else { x->amps[ i ] = 0; } } } void cavoc_hold_time(t_cavoc *x, t_floatarg f) { if(f <= 0) 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_external_trigger(t_cavoc *x, t_floatarg toggle) { x->external_trigger = (short)toggle; } void cavoc_mute (t_cavoc *x, t_floatarg toggle) { x->mute = (short)toggle; } void cavoc_retune(t_cavoc *x, t_floatarg min, t_floatarg max) { 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; build_spectrum(x, (float)min, (float)max); } void cavoc_bang(t_cavoc *x) { if(x->external_trigger) x->trigger_value = 1; } void cavoc_oscbank(t_cavoc *x, t_floatarg flag) { x->fft->obank_flag = (short) flag; } 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); } } void cavoc_free( t_cavoc *x ){ fftease_free(x->fft); free(x->fft); free(x->amps); free(x->freqs); free(x->rule); } void *cavoc_new(t_symbol *msg, short argc, t_atom *argv) { t_cavoc *x = (t_cavoc *)pd_new(cavoc_class); t_fftease *fft; outlet_new(&x->x_obj, gensym("signal")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; x->fft->initialized = 0; x->density = 0.1; x->hold_time = 500.0; // convert from ms x->fft->obank_flag = 0; x->fft->N = FFTEASE_DEFAULT_FFTSIZE; x->fft->overlap = FFTEASE_DEFAULT_OVERLAP; x->fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv); } if(argc > 2){ x->density = atom_getfloatarg(2, argc, argv); } if(argc > 3){ x->hold_time = atom_getfloatarg(3, argc, argv); } return x; } void cavoc_init(t_cavoc *x) { t_fftease *fft = x->fft; short initialized = fft->initialized; fftease_init(fft); fft->lo_bin = 0; fft->hi_bin = fft->N2 - 1; if(! fft->R ){ error("zero sampling rate!"); return; } x->frame_duration = (float)fft->D/(float) fft->R; if(x->hold_time <= 0.0) x->hold_time = 150; x->hold_frames = (int) ((x->hold_time * 0.001) / x->frame_duration) ; x->frames_left = x->hold_frames; x->trigger_value = 0; x->topfreq = fft->R / 2.0; x->bottomfreq = 0.0; if(!initialized){ srand(time(0)); x->mute = 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->freqs = (t_float *) calloc((fft->N2 + 1), sizeof(t_float)); x->amps = (t_float *) calloc((fft->N2 + 1), sizeof(t_float)); x->cavoc = (t_float *) calloc((fft->N + 2), sizeof(t_float)); 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; } else { x->freqs = (t_float *) realloc(x->freqs, (fft->N2 + 1) * sizeof(t_float)); x->amps = (t_float *) realloc(x->amps, (fft->N2 + 1) * sizeof(t_float)); } build_spectrum(x, 0.9, 1.1); } void build_spectrum(t_cavoc *x, float min, float max) { t_fftease *fft = x->fft; float basefreq; int i; x->set_count = 0; for(i = 0; i < fft->N2 + 1; i++){ if(cavoc_randf(0.0, 1.0) > x->start_breakpoint){ x->amps[i] = 1; ++(x->set_count); } else { x->amps[i] = 0; } basefreq = x->bottomfreq + (( (x->topfreq - x->bottomfreq) / (float) fft->N2 ) * (float) i ); x->freqs[i] = basefreq * cavoc_randf(min,max); } for( i = 0; i < fft->N2 + 1; i++ ){ fft->channel[i * 2] = x->amps[i]; fft->channel[i * 2 + 1] = x->freqs[i]; } } void cavoc_topfreq(t_cavoc *x, t_floatarg tf) { t_fftease *fft = x->fft; if(tf < 100 || tf > fft->R / 2.0){ error("%s: top frequency out of range: %f",OBJECT_NAME, tf); return; } x->topfreq = (float) tf; build_spectrum(x, 0.9, 1.1); } void cavoc_bottomfreq(t_cavoc *x, t_floatarg bf) { if(bf < 0 && bf > x->topfreq){ error("%s: bottom frequency out of range: %f",OBJECT_NAME, bf); return; } x->bottomfreq = (float) bf; build_spectrum(x, 0.9, 1.1); } static void do_cavoc(t_cavoc *x) { int i; t_fftease *fft = x->fft; int N = fft->N; int N2 = fft->N2; t_float *channel = fft->channel; int hold_frames = x->hold_frames; short *rule = x->rule; short left = x->left; short right = x->right; short center = x->center; short external_trigger = x->external_trigger; short new_event = 0; t_float *amps = x->amps; t_float *freqs = x->freqs; if(external_trigger){// only accurate to within a vector because of FFT if(x->trigger_value){ x->trigger_value = 0; new_event = 1; } } else if(--(x->frames_left) <= 0){ x->frames_left = hold_frames; new_event = 1; } if(new_event){ for( i = 1; i < N2; i++ ){ left = amps[i - 1]; center = amps[i] ; right = amps[i + 1]; channel[i * 2] = cavoc_apply_rule(left, right, center, rule); } center = amps[0]; right = amps[1]; left = amps[N2]; channel[0] = cavoc_apply_rule(left, right, center, rule); center = amps[N2]; right = amps[0]; left = amps[N2 - 1]; channel[N] = cavoc_apply_rule(left, right, center, rule); for(i = 0; i < N2 + 1; i++){ channel[(i*2) + 1] = freqs[i]; amps[i] = channel[i * 2]; } } if(fft->obank_flag){ for(i = 0; i < N2 + 1; i++){ channel[(i*2) + 1] = freqs[i]; channel[i * 2] = amps[i]; } fftease_oscbank(fft); } else { fftease_unconvert(fft); fftease_rdft(fft, -1); fftease_overlapadd(fft); } } t_int *cavoc_perform(t_int *w) { int i,j; t_cavoc *x = (t_cavoc *) (w[1]); t_float *MSPOutputVector = (t_float *)(w[2]); t_fftease *fft = x->fft; int D = fft->D; int Nw = fft->Nw; t_float *output = fft->output; float mult = fft->mult ; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; t_float *internalOutputVector = fft->internalOutputVector; int MSPVectorSize = fft->MSPVectorSize; if(fft->obank_flag){ mult *= FFTEASE_OSCBANK_SCALAR; } if( x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+3; } if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ do_cavoc(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ do_cavoc(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize), MSPVectorSize * sizeof(float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { do_cavoc(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+3; } 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; } 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) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(!samplerate) return; if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate ){ fft->R = samplerate; } if(reset_required){ cavoc_init(x); } dsp_add(cavoc_perform, 2, x, sp[1]->s_vec); } pd-fftease-3.0.1/centerring~.c000066400000000000000000000260521401707710000162350ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" #define OBJECT_NAME "centerring~" #define MAX_WARP 16.0 static t_class *centerring_class; #define OBJECT_NAME "centerring~" typedef struct _centerring { t_object x_obj; float x_f; t_fftease *fft; int bufferLength; int recalc; int seed; t_float baseFreq; t_float constFreq; t_float bandFreq; t_float frameR; t_float *ringPhases; t_float *ringIncrements; t_float *sineBuffer; t_float *bufferOne; t_float *channelOne; short connected[8]; short mute; short bypass; } t_centerring; static void *centerring_new(t_symbol *s, int argc, t_atom *argv); static t_int *centerring_perform(t_int *w); static void centerring_dsp(t_centerring *x, t_signal **sp); static void centerring_messages(t_centerring *x, t_symbol *s, short argc, t_atom *argv); static void centerring_adjust( t_centerring *x ); static void centerring_zerophases( t_centerring *x ); static void centerring_randphases( t_centerring *x ); static void centerring_free(t_centerring *x); static void centerring_init(t_centerring *x); static void centerring_mute(t_centerring *x, t_floatarg toggle); static void centerring_fftinfo( t_centerring *x ); static void centerring_bypass(t_centerring *x, t_floatarg toggle); static void centerring_fftsize(t_centerring *x, t_floatarg f); static void centerring_overlap(t_centerring *x, t_floatarg f); static void centerring_winfac(t_centerring *x, t_floatarg f); void centerring_tilde_setup(void) { t_class *c; c = class_new(gensym("centerring~"), (t_newmethod)centerring_new, (t_method)centerring_free,sizeof(t_centerring), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_centerring, x_f); class_addmethod(c,(t_method)centerring_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)centerring_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)centerring_fftinfo,gensym("fftinfo"),0); class_addmethod(c,(t_method)centerring_messages,gensym("seed"), A_GIMME, 0); class_addmethod(c,(t_method)centerring_messages,gensym("zerophases"), 0); class_addmethod(c,(t_method)centerring_messages,gensym("randphases"), 0); centerring_class = c; fftease_announce(OBJECT_NAME); } 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 ); } void *centerring_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft; 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")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; /* optional arguments: baseFreq, bandFreq, constFreq, seed, overlap, winfac */ x->baseFreq = 1.0; x->bandFreq = 0.2; x->constFreq = 1.0; x->seed = 1977; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void centerring_init(t_centerring *x) { t_fftease *fft = x->fft; int Nw; int N; int N2; short initialized= fft->initialized; fftease_init(fft); Nw = fft->Nw; N = fft->N; N2 = fft->N2; if(! fftease_msp_sanity_check(fft,OBJECT_NAME)){ post("failed sanity check!"); return; } x->frameR = (float) fft->R / (float) fft->D; if(!initialized){ x->mute = 0; x->bufferLength = 131072; x->recalc = 0; x->ringPhases = (t_float *) calloc((N2 + 1), sizeof(t_float)); x->ringIncrements = (t_float *) calloc((N2 + 1), sizeof(t_float)); x->sineBuffer = (t_float *) calloc((x->bufferLength + 1), sizeof(t_float)); fftease_makeSineBuffer(x->sineBuffer, x->bufferLength); } else { x->ringIncrements = (t_float *)realloc((void *)x->ringIncrements, (N2 + 1) * sizeof(t_float)); x->ringPhases = (t_float *)realloc((void *)x->ringPhases, (N2 + 1) * sizeof(t_float)); } centerring_adjust(x); centerring_zerophases(x); } void centerring_free(t_centerring *x) { fftease_free(x->fft); free(x->fft); free(x->ringPhases); free(x->ringIncrements); free(x->sineBuffer); } void centerring_adjust( t_centerring *x ) { int i; t_float *ringIncrements = x->ringIncrements; int N2 = x->fft->N2; if(x->frameR == 0){ post("centerring_adjust got at 0 SR!"); return; } for (i=0; i < N2; i++) { *(ringIncrements+i) = fftease_frequencyToIncrement( x->frameR, x->baseFreq * ((fftease_rrand(&(x->seed)) * x->bandFreq) + x->constFreq ), x->bufferLength ); } } void centerring_zerophases( t_centerring *x ) { int i; for (i=0; i < x->fft->N2; i++) *((x->ringPhases)+i) = 0.; } void centerring_randphases( t_centerring *x ) { int i; for (i=0; i < x->fft->N2; i++) *((x->ringPhases)+i) = fftease_prand(&(x->seed)) * (float) (x->bufferLength); } static void do_centerring(t_centerring *x) { t_fftease *fft = x->fft; t_float *buffer = fft->buffer; t_float *channel = fft->channel; int i, odd, even; t_float a1,b1; int N2 = fft->N2; int bufferLength = x->bufferLength; t_float *ringPhases = x->ringPhases; t_float *ringIncrements = x->ringIncrements; t_float *sineBuffer = x->sineBuffer; /* recalculate our oscillator values if object inputs have been updated */ if (x->recalc) centerring_adjust( x ); x->recalc = 0; fftease_fold(fft); fftease_rdft(fft,1); /* convert to polar coordinates from complex values */ for ( i = 0; i <= N2; i++ ) { odd = ( even = i<<1 ) + 1; a1 = ( i == N2 ? *(buffer+1) : *(buffer + even) ); b1 = ( i == 0 || i == N2 ? 0. : *(buffer + odd) ); *(channel + even) = hypot( a1, b1 ); *(channel + odd) = -atan2( b1, a1 ); } /* perform ring modulation on successive fft frames */ for (i=0; i < N2; i++) { even = i<<1; *(channel + even) *= fftease_bufferOscil( ringPhases+i, *(ringIncrements+i), sineBuffer, bufferLength ); } /* convert from polar to cartesian */ for ( i = 0; i <= N2; i++ ) { odd = ( even = i<<1 ) + 1; *(buffer + even) = *(channel + even) * cos( *(channel + odd) ); if ( i != N2 ) *(buffer + odd) = (*(channel + even)) * -sin( *(channel + odd) ); } fftease_rdft(fft,-1); fftease_overlapadd(fft); } t_int *centerring_perform(t_int *w) { int i, j; t_centerring *x = (t_centerring *) (w[1]); t_fftease *fft = x->fft; t_float *MSPInputVector = (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 *MSPOutputVector = (t_float *)(w[6]); t_float *input = fft->input; int D = fft->D; int Nw = fft->Nw; t_float *output = fft->output; float mult = fft->mult ; int MSPVectorSize = fft->MSPVectorSize; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+7; } x->recalc = 1; x->baseFreq = *vec_baseFreq; x->bandFreq = *vec_bandFreq; x->constFreq = *vec_constFreq; if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_centerring(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_centerring(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_centerring(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+7; } void centerring_mute(t_centerring *x, t_floatarg toggle) { x->mute = (short)toggle; } void centerring_bypass(t_centerring *x, t_floatarg toggle) { x->bypass = (short)toggle; } void centerring_overlap(t_centerring *x, t_floatarg f) { x->fft->overlap = (int) f; centerring_init(x); } void centerring_winfac(t_centerring *x, t_floatarg f) { x->fft->winfac = (int) f; centerring_init(x); } void centerring_fftsize(t_centerring *x, t_floatarg f) { x->fft->N = (int) f; centerring_init(x); } void centerring_fftinfo( t_centerring *x ) { fftease_fftinfo( x->fft, OBJECT_NAME ); } void centerring_dsp(t_centerring *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ centerring_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(centerring_perform, 6, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[4]->s_vec); } } pd-fftease-3.0.1/codepend~.c000066400000000000000000000271211401707710000156540ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *codepend_class; #define OBJECT_NAME "codepend~" typedef struct _codepend { t_object x_obj; float x_f; t_fftease *fft; t_fftease *fft2; // for cross synthesis use t_float threshold; t_float exponent; short connected[8]; short mute; short bypass; int invert_countdown; // delay onset of invert effect to avoid loud glitches int invert_nextstate;// next state for invert int invert; t_float invert_pad; } t_codepend; static void *codepend_new(t_symbol *s, int argc, t_atom *argv); static void codepend_dsp(t_codepend *x, t_signal **sp); static t_int *codepend_perform(t_int *w); static void codepend_invert(t_codepend *x, t_floatarg toggle); static void codepend_free(t_codepend *x); static void codepend_mute(t_codepend *x, t_floatarg toggle); static void codepend_fftinfo(t_codepend *x); static void codepend_init(t_codepend *x); static void codepend_pad(t_codepend *x, t_floatarg pad); void codepend_tilde_setup(void) { t_class *c; c = class_new(gensym("codepend~"), (t_newmethod)codepend_new, (t_method)codepend_free,sizeof(t_codepend), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_codepend, x_f); class_addmethod(c,(t_method)codepend_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)codepend_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)codepend_fftinfo,gensym("fftinfo"),0); class_addmethod(c,(t_method)codepend_invert,gensym("invert"), A_FLOAT, 0); class_addmethod(c,(t_method)codepend_pad,gensym("pad"), A_FLOAT, 0); codepend_class = c; fftease_announce(OBJECT_NAME); } void codepend_mute(t_codepend *x, t_floatarg toggle) { x->mute = (short)toggle; } void codepend_fftinfo( t_codepend *x ) { fftease_fftinfo(x->fft, OBJECT_NAME); } void codepend_free(t_codepend *x) { fftease_free(x->fft); fftease_free(x->fft2); free(x->fft); free(x->fft2); } 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->fft->overlap; // delay effect for "overlap" vectors if(x->invert_nextstate){ // lower gain immediately; delay going to invert x->fft->mult = (1. / (float) x->fft->N) * x->invert_pad; } else { x->invert = 0; //immediately turn off invert; delay raising gain } } void *codepend_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft, *fft2; t_codepend *x = (t_codepend *)pd_new(codepend_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")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); x->fft2 = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft2 = x->fft2; fft->initialized = 0; fft2->initialized = 0; /* optional arguments: scaling exponent, threshold (now linear), overlap, winfac */ x->exponent = 0.25; x->threshold = 0.01; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; fft2->N = FFTEASE_DEFAULT_FFTSIZE; fft2->overlap = FFTEASE_DEFAULT_OVERLAP; fft2->winfac = FFTEASE_DEFAULT_WINFAC; fft2->MSPVectorSize = fft->MSPVectorSize = sys_getblksize(); if(argc > 0){ fft->N = fft2->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = fft2->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void codepend_init(t_codepend *x ) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; short initialized = fft->initialized; fftease_init(fft); fftease_init(fft2); if(!initialized){ x->invert_pad = 0.025; // -32 dB x->invert_countdown = 0; x->mute = 0; x->invert = 0; } if(x->invert){ x->fft->mult *= x->invert_pad; } } static void do_codepend(t_codepend *x) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int i; int N2 = fft->N2; float a1, b1, a2, b2, threshold = 0.1; int even, odd; int invert = x->invert; t_float exponent = x->exponent; t_float *bufferOne = fft->buffer; t_float *bufferTwo = fft2->buffer; t_float *channelOne = fft->channel; // float *channelTwo = fft2->channel; 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->fft->mult = 1. / (float) x->fft->N; } } } if ( x->threshold != 0. ) threshold = x->threshold; fftease_fold(fft); fftease_fold(fft2); fftease_rdft(fft, 1); fftease_rdft(fft2, 1); 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) ); } fftease_rdft(fft, -1); fftease_overlapadd(fft); } t_int *codepend_perform(t_int *w) { int i, j; /* get our inlets and outlets */ t_codepend *x = (t_codepend *) (w[1]); t_float *MSPInputVector1 = (t_float *)(w[2]); t_float *MSPInputVector2 = (t_float *)(w[3]); t_float *vec_exponent = (t_float *)(w[4]); t_float *vec_threshold = (t_float *)(w[5]); t_float *MSPOutputVector = (t_float *)(w[6]); x->exponent = *vec_exponent; x->threshold = *vec_threshold; t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int MSPVectorSize = fft->MSPVectorSize; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; t_float *internalInputVector1 = fft->internalInputVector; t_float *internalInputVector2 = fft2->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; t_float *inputOne = fft->input; t_float *inputTwo = fft2->input; t_float *output = fft->output; int D = fft->D; int Nw = fft->Nw; float mult = fft->mult; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+7; } if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), MSPInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), MSPInputVector2, D * sizeof(t_float)); do_codepend(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw-D), MSPInputVector1 + (D*i), D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw-D), MSPInputVector2 + (D*i), D * sizeof(t_float)); do_codepend(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector1 + (operationCount * MSPVectorSize), MSPInputVector1, MSPVectorSize * sizeof(t_float)); memcpy(internalInputVector2 + (operationCount * MSPVectorSize), MSPInputVector2, MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize), MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), internalInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), internalInputVector2, D * sizeof(t_float)); do_codepend(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+7; } void codepend_dsp(t_codepend *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(!samplerate) return; if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); fft2->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft2); } if(fft->R != samplerate ){ fft->R = samplerate; fft2->R = samplerate; } if(reset_required){ codepend_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(codepend_perform, 6, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[4]->s_vec); } } pd-fftease-3.0.1/collect.pl000066400000000000000000000002161401707710000155070ustar00rootroot00000000000000if(! -e fftease){ mkdir("fftease"); } while(<*>){ chomp; if(/darwin$/ || /libfftease.pd_darwin.dylib/){ `mv $_ fftease`; } } pd-fftease-3.0.1/convert.c000066400000000000000000000030641401707710000153550ustar00rootroot00000000000000#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 fftease_convert(t_fftease *fft) { t_float *buffer = fft->buffer; t_float *channel = fft->channel; int N2 = fft->N2; t_float *lastphase = fft->c_lastphase_in; t_float fundamental = fft->c_fundamental; t_float factor = fft->c_factor_in; t_float phase, phasediff; int real,imag,amp,freq; t_float a,b; int i; for ( i = 0; i <= N2; i++ ) { imag = freq = ( real = amp = i<<1 ) + 1; a = ( i == N2 ? buffer[1] : buffer[real] ); b = ( i == 0 || i == N2 ? 0. : buffer[imag] ); channel[amp] = hypot( a, b ); if ( channel[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; } channel[freq] = phasediff*factor + i*fundamental; } } pd-fftease-3.0.1/cross~.c000066400000000000000000000222471401707710000152300ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *cross_class; #define OBJECT_NAME "cross~" typedef struct _cross { t_object x_obj; float x_f; t_fftease *fft; t_fftease *fft2; t_float threshie; short mute;//flag short autonorm;// for self gain regulation t_float normult; // adjusted multiplier on a per-frame basis } t_cross; static void *cross_new(t_symbol *s, int argc, t_atom *argv); static t_int *cross_perform(t_int *w); static void cross_dsp(t_cross *x, t_signal **sp); static void *cross_new(t_symbol *s, int argc, t_atom *argv); static void cross_init(t_cross *x); static void cross_mute(t_cross *x, t_floatarg toggle); static void cross_autonorm(t_cross *x, t_floatarg toggle); static void cross_free(t_cross *x); static void cross_fftsize(t_cross *x, t_floatarg f); void cross_tilde_setup(void) { t_class *c; c = class_new(gensym("cross~"), (t_newmethod)cross_new, (t_method)cross_free,sizeof(t_cross), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_cross, x_f); class_addmethod(c,(t_method)cross_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)cross_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)cross_autonorm, gensym("autonorm"), A_FLOAT, 0); cross_class = c; fftease_announce(OBJECT_NAME); } void cross_autonorm(t_cross *x, t_floatarg toggle) { x->autonorm = (short) toggle; } void cross_fftsize(t_cross *x, t_floatarg f) { x->fft->N = (int) f; x->fft2->N = (int) f; cross_init(x); } void cross_mute(t_cross *x, t_floatarg toggle) { x->mute = (short)toggle; } void cross_free(t_cross *x) { fftease_free(x->fft); fftease_free(x->fft2); free(x->fft); free(x->fft2); } void *cross_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft, *fft2; t_cross *x = (t_cross *)pd_new(cross_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->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); x->fft2 = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft2 = x->fft2; fft->initialized = 0; fft2->initialized = 0; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; fft2->N = FFTEASE_DEFAULT_FFTSIZE; fft2->overlap = FFTEASE_DEFAULT_OVERLAP; fft2->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = fft2->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = fft2->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void cross_init(t_cross *x) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; short initialized; initialized = fft->initialized; fftease_init(fft); fftease_init(fft2); if(!initialized){ x->threshie = .001 ; x->autonorm = 0; x->mute = 0; } } static void do_cross(t_cross *x) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int i; int N2 = fft->N2; t_float a1, b1, a2, b2; t_float *buffer1 = fft->buffer; t_float *buffer2 = fft2->buffer; t_float *channel1 = fft->channel; short autonorm = x->autonorm; int N = fft->N; t_float mult = fft->mult; int even, odd; t_float gainer; t_float threshie = x->threshie; t_float ingain = 0; t_float outgain, rescale; t_float mymult; fftease_fold(fft); fftease_fold(fft2); fftease_rdft(fft,1); fftease_rdft(fft2,1); /* 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); x->normult = mult * rescale; } else { x->normult = mult; //post("mymult: %f", mymult); } fftease_rdft(fft, -1); fftease_overlapadd(fft); } t_int *cross_perform(t_int *w) { int i, j; t_cross *x = (t_cross *) (w[1]); t_float *MSPInputVector1 = (t_float *)(w[2]); t_float *MSPInputVector2 = (t_float *)(w[3]); t_float *threshold = (t_float *)(w[4]); t_float *MSPOutputVector = (t_float *)(w[5]); t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int MSPVectorSize = fft->MSPVectorSize; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; t_float *internalInputVector1 = fft->internalInputVector; t_float *internalInputVector2 = fft2->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; t_float *inputOne = fft->input; t_float *inputTwo = fft2->input; t_float *output = fft->output; int D = fft->D; int Nw = fft->Nw; t_float mult = fft->mult; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+6; } x->threshie = *threshold; if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), MSPInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), MSPInputVector2, D * sizeof(t_float)); do_cross(x); mult = x->normult; for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw-D), MSPInputVector1 + (D*i), D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw-D), MSPInputVector2 + (D*i), D * sizeof(t_float)); do_cross(x); mult = x->normult; for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector1 + (operationCount * MSPVectorSize), MSPInputVector1, MSPVectorSize * sizeof(t_float)); memcpy(internalInputVector2 + (operationCount * MSPVectorSize), MSPInputVector2, MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize), MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), internalInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), internalInputVector2, D * sizeof(t_float)); do_cross(x); mult = x->normult; for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+6; } void cross_dsp(t_cross *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(!samplerate) return; if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); fft2->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft2); } if(fft->R != samplerate ){ fft->R = samplerate; fft2->R = samplerate; } if(reset_required){ cross_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(cross_perform, 5, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); } } pd-fftease-3.0.1/dentist~.c000066400000000000000000000402751401707710000155520ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *dentist_class; #define OBJECT_NAME "dentist~" typedef struct _dentist { t_object x_obj; float x_f; t_fftease *fft; short *bin_selection; short *last_bin_selection; int *active_bins; int tooth_count; int ramp_frames; int frames_left; t_float frame_duration; int max_bin; t_float topfreq; t_float funda; void *list_outlet; short direct_update; short mute; t_atom *list_data; short interpolate_singles; t_float sync; t_float ramp_ms; } t_dentist; static void *dentist_new(t_symbol *msg, short argc, t_atom *argv); static void dentist_dsp(t_dentist *x, t_signal **sp); static t_int *dentist_perform(t_int *w); static void reset_shuffle(t_dentist *x); static void dentist_showstate(t_dentist *x); static void dentist_mute(t_dentist *x, t_floatarg toggle); static void dentist_setstate(t_dentist *x, t_symbol *msg, short argc, t_atom *argv); static void dentist_ramptime(t_dentist *x, t_floatarg ramp_ms); static int rand_index(int max); static void dentist_init(t_dentist *x); static void dentist_topfreq(t_dentist *x, t_floatarg f); static void dentist_free(t_dentist *x); static void dentist_toothcount(t_dentist *x, t_floatarg newcount); static void dentist_scramble(t_dentist *x); static void dentist_interpolate_singles(t_dentist *x, t_floatarg f); static void dentist_fftinfo(t_dentist *x); static void dentist_mute(t_dentist *x, t_floatarg toggle); static void dentist_activate_bins(t_dentist *x, t_floatarg f); static void dentist_bins_pd (t_dentist *x, t_floatarg i); static void dentist_direct_update( t_dentist *x, t_floatarg toggle); static void dentist_fftsize(t_dentist *x, t_floatarg f); static void dentist_overlap(t_dentist *x, t_floatarg f); static void dentist_winfac(t_dentist *x, t_floatarg f); void dentist_tilde_setup(void) { t_class *c; c = class_new(gensym("dentist~"), (t_newmethod)dentist_new, (t_method)dentist_free,sizeof(t_dentist), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_dentist, x_f); class_addmethod(c,(t_method)dentist_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)dentist_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)dentist_fftinfo,gensym("fftinfo"),0); class_addmethod(c,(t_method)dentist_showstate,gensym("showstate"),0); class_addmethod(c,(t_method)dentist_setstate, gensym("setstate"), A_GIMME, 0); class_addmethod(c,(t_method)dentist_ramptime, gensym("ramptime"), A_FLOAT, 0); class_addmethod(c,(t_method)dentist_topfreq, gensym("topfreq"), A_FLOAT, 0); class_addmethod(c,(t_method)dentist_toothcount, gensym("toothcount"), A_FLOAT, 0); class_addmethod(c,(t_method)dentist_interpolate_singles, gensym("interpolate_singles"), A_FLOAT, 0); class_addmethod(c,(t_method)dentist_scramble, gensym("scramble"), 0); dentist_class = c; fftease_announce(OBJECT_NAME); } 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) { fftease_free(x->fft); free(x->fft); free(x->bin_selection); free(x->active_bins); free(x->last_bin_selection); free(x->list_data); } void dentist_fftsize(t_dentist *x, t_floatarg f) { t_fftease *fft = x->fft; fft->N = (int) f; dentist_init(x); } void dentist_overlap(t_dentist *x, t_floatarg f) { x->fft->overlap = (int) f; dentist_init(x); } void dentist_winfac(t_dentist *x, t_floatarg f) { t_fftease *fft = x->fft; fft->winfac = (int) f; dentist_init(x); } void dentist_fftinfo( t_dentist *x ) { fftease_fftinfo( x->fft, OBJECT_NAME ); } 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_new(t_symbol *msg, short argc, t_atom *argv) { t_fftease *fft; 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")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft->initialized = 0; x->topfreq = 3000; // an attribute candidate x->ramp_ms = 1000.0; x->tooth_count = 3; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void dentist_topfreq(t_dentist *x, t_floatarg f) { float funda = x->funda; float curfreq; t_fftease *fft = x->fft; if(f < 50 || f > fft->R/2.0) return; x->topfreq = f; if(! x->fft->initialized){ return; } x->max_bin = 1; curfreq = 0; while(curfreq < x->topfreq) { ++(x->max_bin); curfreq += funda ; } } void dentist_init(t_dentist *x) { int i; t_fftease *fft = x->fft; short initialized = fft->initialized; fftease_init(fft); if(!initialized){ x->sync = 0; x->mute = 0; x->direct_update = 0; if(x->topfreq < 100) x->topfreq = 100.0; x->bin_selection = (short *) calloc(fft->N, sizeof(short)); x->active_bins = (int *) calloc(fft->N2, sizeof(int)); x->last_bin_selection = (short *) calloc(fft->N2, sizeof(short)) ; x->list_data = (t_atom *) calloc((fft->N + 2), sizeof(t_atom)); x->interpolate_singles = 1; x->ramp_frames = 0; } else { x->bin_selection = (short *) realloc((void *)x->bin_selection, fft->N * sizeof(short)); x->active_bins = (int *) realloc((void *)x->active_bins, fft->N2 * sizeof(int)); x->last_bin_selection = (short *) realloc((void *)x->last_bin_selection, fft->N2 * sizeof(short)) ; x->list_data = (t_atom *) realloc((void *)x->list_data, (fft->N + 2) * sizeof(t_atom)); } dentist_scramble(x); fft->mult = 1. / (t_float) fft->N; x->frame_duration = (t_float) fft->D / (t_float) fft->R; x->frames_left = x->ramp_frames = (int)(x->ramp_ms * .001 / x->frame_duration); x->funda = (t_float) fft->R / (t_float) fft->N; x->max_bin = 1; 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; for( i = 0; i < fft->N2; i++) { x->last_bin_selection[i] = x->bin_selection[i]; } dentist_toothcount(x, x->tooth_count); } static void do_dentist(t_dentist *x) { int i; t_float oldfrac,newfrac; t_fftease *fft = x->fft; t_float *channel = fft->channel; 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; int N2 = fft->N2; float sync = x->sync; fftease_fold(fft); fftease_rdft(fft,1); fftease_leanconvert(fft); 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]) { 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; } fftease_leanunconvert(fft); fftease_rdft(fft,-1); fftease_overlapadd(fft); x->frames_left = frames_left; x->sync = sync; } t_int *dentist_perform(t_int *w) { int i,j; t_dentist *x = (t_dentist *) (w[1]); t_float *MSPInputVector = (t_float *)(w[2]); t_float *MSPOutputVector = (t_float *)(w[3]); t_float *sync_vec = (t_float *)(w[4]); t_fftease *fft = x->fft; t_float *input = fft->input; int D = fft->D; int Nw = fft->Nw; t_float *output = fft->output; t_float mult = fft->mult ; int MSPVectorSize = fft->MSPVectorSize; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } for(i=0; i < MSPVectorSize; i++){ sync_vec[i] = 0.0; } return w+5; } if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_dentist(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_dentist(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_dentist(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } for(i = 0; i < MSPVectorSize; i++){ sync_vec[i] = x->sync; } return w+5; } void set_switch_bins (t_dentist *x, int i) { if( i < 0 ){ i = 0; } if( i > x->fft->N2 ) { i = x->fft->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->fft->N2 ) { i = x->fft->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){ post("* %d bin out of range",(int)f); 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->fft->N2; int i,tmp,b1,b2; int maxswap = x->max_bin; if(!x->fft->initialized){ return; } for(i=0; i 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 tooth_count = x->tooth_count; if(! x->fft->initialized){ x->tooth_count = newcount; return; } if(nc < 0 || nc > x->fft->N2){ error("dentist~: %d out of range",nc); return; } 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->fft->N2; i++){ x->last_bin_selection[i] = x->bin_selection[i]; } } x->tooth_count = nc; } void reset_shuffle (t_dentist *x) { int i; int max; max = x->max_bin; for(i = 0; i < x->fft->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->fft->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; int N2 = x->fft->N2; for(i = 0; i < 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 < 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 < N2; i++){ last_bin_selection[i] = bin_selection[i]; } } return; } void dentist_ramptime (t_dentist *x, t_floatarg ramp_ms) { if(ramp_ms <= 0){ return; } x->ramp_ms = ramp_ms; if(!x->fft->initialized){ return; } x->frames_left = x->ramp_frames = (int)(x->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]; SETFLOAT(list_data+count,(t_float)x->active_bins[i]); ++count; } outlet_list(x->list_outlet,0,x->tooth_count,list_data); return; } void dentist_dsp(t_dentist *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ dentist_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(dentist_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); } } pd-fftease-3.0.1/disarrain~.c000066400000000000000000000516351401707710000160560ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *disarrain_class; #define OBJECT_NAME "disarrain~" typedef struct _disarrain { t_object x_obj; float x_f; t_fftease *fft; t_float *last_channel; t_float *composite_channel; 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; void *list_outlet; t_atom *list_data; short mute; short bypass; t_float frame_duration; // duration in seconds of a single frame t_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 perform_method;// 0 for lean, 1 for full conversion float ival; 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 long fftsize_attr; long overlap_attr; t_float top_frequency;// for remapping spectrum (NOW AN ATTRIBUTE) short reset_flag; // call for reset short switchcount_flag; // call for switch count int switchcount; int new_shuffle_count; // call to change switch count } t_disarrain; static void *disarrain_new(t_symbol *msg, short argc, t_atom *argv); static void disarrain_dsp(t_disarrain *x, t_signal **sp); static t_int *disarrain_perform(t_int *w); static void disarrain_switch_count(t_disarrain *x, t_floatarg i); static void disarrain_fadetime(t_disarrain *x, t_floatarg f); static void disarrain_topfreq(t_disarrain *x, t_floatarg f); static void reset_shuffle( t_disarrain *x ); static void disarrain_showstate( t_disarrain *x ); static void disarrain_setstate (t_disarrain *x, t_symbol *msg, short argc, t_atom *argv); static void disarrain_isetstate (t_disarrain *x, t_symbol *msg, short argc, t_atom *argv); static void disarrain_mute(t_disarrain *x, t_floatarg toggle); static void copy_shuffle_array(t_disarrain *x); static void disarrain_killfade(t_disarrain *x); static void disarrain_init(t_disarrain *x); static void disarrain_free(t_disarrain *x); //static void disarrain_bypass(t_disarrain *x, t_floatarg toggle); static void disarrain_fftinfo( t_disarrain *x ); //static void disarrain_fftsize(t_disarrain *x, t_floatarg f); //static void disarrain_forcefade(t_disarrain *x, t_floatarg toggle); //static void disarrain_force_switch(t_disarrain *x, t_floatarg f); //static void disarrain_list (t_disarrain *x, t_symbol *msg, short argc, t_atom *argv); //static void disarrain_overlap(t_disarrain *x, t_floatarg f); //static void disarrain_winfac(t_disarrain *x, t_floatarg f); void disarrain_tilde_setup(void) { t_class *c; c = class_new(gensym("disarrain~"), (t_newmethod)disarrain_new, (t_method)disarrain_free,sizeof(t_disarrain), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_disarrain, x_f); class_addmethod(c,(t_method)disarrain_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)disarrain_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)reset_shuffle, gensym("bang"), 0); class_addmethod(c,(t_method)disarrain_showstate,gensym("showstate"),0); class_addmethod(c,(t_method)disarrain_fftinfo,gensym("fftinfo"),0); class_addmethod(c,(t_method)disarrain_setstate, gensym("setstate"), A_GIMME, 0); class_addmethod(c,(t_method)disarrain_isetstate, gensym("isetstate"), A_GIMME, 0); class_addmethod(c,(t_method)disarrain_topfreq, gensym("topfreq"), A_FLOAT, 0); class_addmethod(c,(t_method)disarrain_fadetime, gensym("fadetime"), A_FLOAT, 0); class_addmethod(c,(t_method)disarrain_switch_count, gensym("switch_count"), A_FLOAT, 0); class_addmethod(c,(t_method)disarrain_killfade, gensym("killfade"), 0); disarrain_class = c; fftease_announce(OBJECT_NAME); } void disarrain_free(t_disarrain *x) { fftease_free(x->fft); free(x->fft); free(x->last_channel); free(x->composite_channel); free(x->shuffle_mapping); free(x->last_shuffle_mapping); free(x->shuffle_tmp); free(x->list_data); } void disarrain_init(t_disarrain *x) { int i; t_float curfreq; t_fftease *fft = x->fft; t_float c_fundamental; short initialized = fft->initialized; fftease_init(fft); int N2 = fft->N2; int N = fft->N; int D = fft->D; int R = fft->R; c_fundamental = fft->c_fundamental; if(initialized == 0){ x->mute = 0; x->bypass = 0; x->force_fade = 0; if( x->interpolation_duration <= 0.0){ x->interpolation_duration = 1.0; //seconds } x->shuffle_mapping = (int *) calloc( N2, sizeof(int) ) ; x->last_shuffle_mapping = (int *) calloc( N2, sizeof(int) ) ; x->shuffle_tmp = (int *) calloc( N2, sizeof(int) ) ; x->list_data = (t_atom *) calloc((N+2), sizeof(t_atom) ) ; x->last_channel = (t_float *) calloc((N+2), sizeof(float)); x->composite_channel = (t_float *) calloc((N+2), sizeof(float)); x->reset_flag = 0; x->new_shuffle_count = 0; } else { x->shuffle_mapping = (int *)realloc(x->shuffle_mapping, N2 * sizeof(int)); x->last_shuffle_mapping = (int *)realloc(x->last_shuffle_mapping, N2 * sizeof(int)); x->shuffle_tmp = (int *)realloc(x->shuffle_tmp, N2 * sizeof(int)); x->list_data = (t_atom *)realloc(x->list_data, (N+2) * sizeof(t_atom)); x->last_channel = (t_float *)realloc(x->last_channel,(N+2) * sizeof(t_float)); x->composite_channel = (t_float *)realloc(x->composite_channel, (N+2) * sizeof(t_float)); } if( x->top_frequency < c_fundamental || x->top_frequency > 20000) { x->top_frequency = 20000.0 ; } x->max_bin = 1; curfreq = 0; while( curfreq < x->top_frequency ) { ++(x->max_bin); curfreq += c_fundamental ; } for( i = 0; i < 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) D / (float) R; x->interpolation_frames = x->interpolation_duration / x->frame_duration; x->frame_countdown = 0; x->shuffle_count = 0; x->last_shuffle_count = 0; if(x->switchcount > 0){ disarrain_switch_count (x, (t_float)x->switchcount); } } 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; if(f > 0.0){ x->interpolation_duration = f * 0.001; } else { return; } if(! x->fft->initialized){ return; } if(x->frame_duration <= 0.0){ // error("%s: frame duration %f is too low", OBJECT_NAME, x->frame_duration); return; } // duration = f * .001; frames = x->interpolation_duration / x->frame_duration; if( frames <= 1){ error("%s: fadetime too short",OBJECT_NAME); return; } x->interpolation_frames = frames; } void disarrain_killfade(t_disarrain *x) { x->frame_countdown = 0; } void *disarrain_new(t_symbol *msg, short argc, t_atom *argv) { t_fftease *fft; 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")); srand(time(0)); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft->initialized = 0; x->top_frequency = 3000; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv); } 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_fftsize(t_disarrain *x, t_floatarg f) { t_fftease *fft = x->fft; fft->N = (int) f; disarrain_init(x); } void disarrain_overlap(t_disarrain *x, t_floatarg f) { t_fftease *fft = x->fft; fft->overlap = (int) f; disarrain_init(x); } void disarrain_winfac(t_disarrain *x, t_floatarg f) { t_fftease *fft = x->fft; fft->winfac = (int) f; disarrain_init(x); /* calling lighter reinit routine */ } void disarrain_fftinfo( t_disarrain *x ) { fftease_fftinfo( x->fft, OBJECT_NAME ); } static void do_disarrain(t_disarrain *x) { t_fftease *fft = x->fft; t_float *channel = fft->channel; int N = fft->N; int N2 = fft->N2; t_float *last_channel = x->last_channel; int i,j; int max = x->max_bin; int temp, p1, p2; float tmp; int *shuffle_mapping = x->shuffle_mapping; int shuffle_count = x->shuffle_count; int *last_shuffle_mapping = x->last_shuffle_mapping; int *shuffle_tmp = x->shuffle_tmp; int last_shuffle_count = x->last_shuffle_count; int frame_countdown = x->frame_countdown; // will read from variable int interpolation_frames = x->interpolation_frames; float ival = x->ival; int new_shuffle_count = x->new_shuffle_count; if(x->switchcount_flag){ if( new_shuffle_count < 0 ){ new_shuffle_count = 0; } if( new_shuffle_count > N2 ) { new_shuffle_count = N2; } if( new_shuffle_count > x->max_bin){ new_shuffle_count = x->max_bin; post("disarrain~: switch constrained to %d", x->max_bin); } memcpy(last_shuffle_mapping, shuffle_mapping, N2 * sizeof(int)); x->last_shuffle_count = x->shuffle_count; x->shuffle_count = new_shuffle_count; x->frame_countdown = x->interpolation_frames; // force interpolation shuffle_count = x->shuffle_count; frame_countdown = x->frame_countdown; x->switchcount_flag = 0; x->reset_flag = 0; } else if(x->reset_flag){ memcpy(last_shuffle_mapping, shuffle_mapping, N2 * sizeof(int)); last_shuffle_count = shuffle_count; shuffle_count = new_shuffle_count; // post("%d %d %d", last_shuffle_count, shuffle_count, new_shuffle_count); for( i = 0; i < N2; i++ ) { shuffle_tmp[i] = i; } // crashed before here for( i = 0; i < max; i++ ) { p1 = rand() % max; p2 = rand() % max; if(p1 < 0 || p1 > max || p2 < 0 || p2 > max){ error("disarrain~: bad remaps: %d %d against %d", p1, p2, max); } else { temp = shuffle_tmp[p1]; shuffle_tmp[ p1 ] = shuffle_tmp[ p2 ]; shuffle_tmp[ p2 ] = temp; } } for( i = 0; i < N2; i++ ) { shuffle_tmp[i] *= 2; } frame_countdown = interpolation_frames; // post("in: countdown: %d, frames: %d", frame_countdown, interpolation_frames); // dangerous??? memcpy(shuffle_mapping, shuffle_tmp, N2 * sizeof(int)); x->reset_flag = 0; } fftease_fold(fft); fftease_rdft(fft,1); fftease_leanconvert(fft); // 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; } // test only 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){ for(i = 0; iframe_countdown = frame_countdown; x->last_shuffle_count = last_shuffle_count; x->shuffle_count = shuffle_count; x->ival = ival; } t_int *disarrain_perform(t_int *w) { int i,j; t_disarrain *x = (t_disarrain *) (w[1]); t_float *MSPInputVector = (t_float *)(w[2]); t_float *MSPOutputVector = (t_float *)(w[3]); t_float *sync_vec = (t_float *)(w[4]); t_fftease *fft = x->fft; t_float *input = fft->input; int D = fft->D; int Nw = fft->Nw; t_float *output = fft->output; t_float mult = fft->mult; int MSPVectorSize = fft->MSPVectorSize; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } for(i=0; i < MSPVectorSize; i++){ sync_vec[i] = 0.0; } return w+5; } if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_disarrain(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_disarrain(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_disarrain(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } /* send out sync signal */ for(j = 0; j < MSPVectorSize; j++){ sync_vec[j] = 1.0 - x->ival; } return w+5; } 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; t_float *channel = x->fft->channel; t_float *last_channel = x->last_channel; 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; int local_max_bins; int N = x->fft->N; ival = (t_float)frame_countdown/(t_float)interpolation_frames; local_max_bins = (shuffle_count > last_shuffle_count)? shuffle_count : last_shuffle_count; 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] += ival * (last_channel[j] - channel[j]); } } void disarrain_switch_count (t_disarrain *x, t_floatarg f) { int i = f; x->switchcount = i; if(! x->fft->initialized){ return; } if( i < 0 ){ i = 0; } if( i > x->max_bin ) { i = x->max_bin; } x->reset_flag = 1; x->new_shuffle_count = i; } void reset_shuffle (t_disarrain *x) { x->reset_flag = 1; } void copy_shuffle_array(t_disarrain *x) { int N2 = x->fft->N2; int *shuffle_mapping = x->shuffle_mapping; int *last_shuffle_mapping = x->last_shuffle_mapping; memcpy(shuffle_mapping, last_shuffle_mapping, N2 * sizeof(int)); x->last_shuffle_count = x->shuffle_count; } int rand_index(int max) { return (rand() % max); } void disarrain_topfreq (t_disarrain *x, t_floatarg freq) { t_float funda = (t_float) x->fft->R / (t_float) x->fft->N; t_float curfreq; if(freq <= 0 || freq > 22050){ post("freq %f is out of range", freq); return; } x->top_frequency = freq; if(! x->fft->initialized){ return; } funda = (t_float) x->fft->R / (t_float) x->fft->N; x->max_bin = 1; curfreq = 0; while( curfreq < freq ) { ++(x->max_bin); curfreq += funda ; } } void disarrain_list (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 = (int)argv[i].a_w.w_float; if (ival < x->fft->N2) { x->shuffle_mapping[i] = ival; } } return; } void disarrain_isetstate (t_disarrain *x, t_symbol *msg, short argc, t_atom *argv) { short i; int ival; int N2 = x->fft->N2; copy_shuffle_array(x); x->shuffle_count = argc; for (i=0; i < argc; i++) { ival = 2 * atom_getfloatarg(i,argc,argv); if ( ival < N2 && ival >= 0) { x->shuffle_mapping[ i ] = ival; }else { error("%s: %d is out of range",OBJECT_NAME, ival); } } 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; int N2 = x->fft->N2; x->shuffle_count = argc; for (i=0; i < argc; i++) { ival = 2 *atom_getfloatarg(i,argc,argv); if ( ival < N2 && ival >= 0) { x->last_shuffle_mapping[i] = 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; for( i = 0; i < x->shuffle_count; i++ ) { SETFLOAT(list_data+i,(t_float)x->shuffle_mapping[i]/2); } outlet_list(x->list_outlet,0,x->shuffle_count,list_data); return; } void disarrain_dsp(t_disarrain *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ disarrain_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(disarrain_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); } } pd-fftease-3.0.1/disarray~.c000066400000000000000000000266721401707710000157230ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *disarray_class; #define OBJECT_NAME "disarray~" typedef struct _disarray { t_object x_obj; float x_f; t_fftease *fft; t_float top_frequency; int *shuffle_in; int *shuffle_out; int shuffle_count; int max_bin; void *list_outlet; t_atom *list_data; short mute; short bypass; long fftsize_attr; long overlap_attr; } t_disarray; static void *disarray_new(t_symbol *msg, short argc, t_atom *argv); static void disarray_dsp(t_disarray *x, t_signal **sp); static t_int *disarray_perform(t_int *w); static void disarray_topfreq (t_disarray *x, t_floatarg freq); static void reset_shuffle( t_disarray *x ); static void disarray_showstate( t_disarray *x ); static void disarray_setstate (t_disarray *x, t_symbol *msg, short argc, t_atom *argv); static int rand_index(int max); static void disarray_mute(t_disarray *x, t_floatarg toggle); static void disarray_init(t_disarray *x); static void disarray_free(t_disarray *x); static void switch_count (t_disarray *x, t_floatarg i); // static void iswitch_count(t_disarray *x, int i); //static void disarray_bypass(t_disarray *x, t_floatarg toggle); static void disarray_fftinfo( t_disarray *x ); //static void disarray_fftsize(t_disarray *x, t_floatarg f); //static void disarray_overlap(t_disarray *x, t_floatarg f); //static void disarray_winfac(t_disarray *x, t_floatarg f); //static void disarray_list (t_disarray *x, t_symbol *msg, short argc, t_atom *argv); void disarray_tilde_setup(void) { t_class *c; c = class_new(gensym("disarray~"), (t_newmethod)disarray_new, (t_method)disarray_free,sizeof(t_disarray), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_disarray, x_f); class_addmethod(c,(t_method)disarray_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)disarray_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)reset_shuffle, gensym("bang"), 0); class_addmethod(c,(t_method)disarray_fftinfo, gensym("fftinfo"), 0); class_addmethod(c,(t_method)disarray_showstate,gensym("showstate"),0); class_addmethod(c,(t_method)disarray_setstate, gensym("setstate"), A_GIMME, 0); class_addmethod(c,(t_method)disarray_topfreq, gensym("topfreq"), A_FLOAT, 0); class_addmethod(c,(t_method)switch_count, gensym("switch_count"), A_FLOAT, 0); disarray_class = c; fftease_announce(OBJECT_NAME); } void iswitch_count(t_disarray *x, 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->fft->N2 ) { i = x->fft->N2; } */ // introduces potential bug of not checking for big numbers - put test into DSP x->shuffle_count = i; } void disarray_free(t_disarray *x) { fftease_free(x->fft); free(x->fft); free(x->list_data); free(x->shuffle_in); free(x->shuffle_out); } void disarray_init(t_disarray *x ) { t_float curfreq; t_fftease *fft = x->fft; t_float c_fundamental; fftease_init(fft); int N2 = fft->N2; int N = fft->N; short initialized = fft->initialized; c_fundamental = fft->c_fundamental; if(initialized == 0){ x->mute = 0; x->bypass = 0; x->list_data = (t_atom *) calloc((N+2), sizeof(t_atom)) ; x->shuffle_in = (int *) calloc(N2, sizeof(int)); x->shuffle_out = (int *) calloc(N2, sizeof(int)); } else if (initialized == 1) { x->list_data = (t_atom *)realloc(x->list_data, (N+2) * sizeof(t_atom)); x->shuffle_in = (int *) realloc(x->shuffle_in, N2 * sizeof(int)); x->shuffle_out = (int *) realloc(x->shuffle_out, N2 * sizeof(int)); } // force update on DSP reset if( x->top_frequency < c_fundamental || x->top_frequency > 20000) { x->top_frequency = 20000.0 ; } x->max_bin = 1; curfreq = 0; while( curfreq < x->top_frequency ) { ++(x->max_bin); curfreq += c_fundamental ; } reset_shuffle(x); // set shuffle lookup // x->shuffle_count = 0; } void disarray_topfreq (t_disarray *x, t_floatarg freq) { t_float funda = (t_float) x->fft->R / (t_float) x->fft->N; t_float curfreq; if( freq < 0 || freq > 20000) { post("freq %f is out of range", freq); return; } x->top_frequency = freq; if(! x->fft->initialized){ return; } x->max_bin = 1; curfreq = 0; while( curfreq < freq ) { ++(x->max_bin); curfreq += funda ; } } void *disarray_new(t_symbol *msg, short argc, t_atom *argv) { t_fftease *fft; 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")); srand(time(0)); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft->initialized = 0; x->top_frequency = 15000; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void disarray_mute(t_disarray *x, t_floatarg toggle) { x->mute = (short)toggle; } void disarray_bypass(t_disarray *x, t_floatarg toggle) { x->bypass = (short)toggle; } void disarray_fftsize(t_disarray *x, t_floatarg f) { t_fftease *fft = x->fft; fft->N = (int) f; disarray_init(x); } void disarray_overlap(t_disarray *x, t_floatarg f) { t_fftease *fft = x->fft; fft->overlap = (int) f; disarray_init(x); } void disarray_winfac(t_disarray *x, t_floatarg f) { t_fftease *fft = x->fft; fft->winfac = (int) f; disarray_init(x); /* calling lighter reinit routine */ } void disarray_fftinfo( t_disarray *x ) { fftease_fftinfo( x->fft, OBJECT_NAME ); } static void do_disarray(t_disarray *x) { t_fftease *fft = x->fft; t_float *channel = fft->channel; int i; t_float tmp; int shuffle_count = x->shuffle_count; int *shuffle_in = x->shuffle_in; int *shuffle_out = x->shuffle_out; fftease_fold(fft); fftease_rdft(fft,1); fftease_leanconvert(fft); // check that shuffle count is reasonable if( shuffle_count > x->fft->N2 ) { shuffle_count = x->fft->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; } fftease_leanunconvert(fft); fftease_rdft(fft,-1); fftease_overlapadd(fft); } t_int *disarray_perform(t_int *w) { int i,j; t_disarray *x = (t_disarray *) (w[1]); t_float *MSPInputVector = (t_float *)(w[2]); t_float *MSPOutputVector = (t_float *)(w[3]); t_fftease *fft = x->fft; t_float *input = fft->input; int D = fft->D; int Nw = fft->Nw; t_float *output = fft->output; t_float mult = fft->mult; int MSPVectorSize = fft->MSPVectorSize; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+4; } if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_disarray(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_disarray(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_disarray(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+4; } 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->fft->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_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->fft->N2 ) { x->shuffle_out[ i ] = ival; } else { post ("%d out of range",ival); } } } 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->fft->N2 && ival >= 0) { x->shuffle_out[ i ] = ival; } else { error("%s: %d is out of range",OBJECT_NAME, ival); } } } void disarray_showstate (t_disarray *x ) { t_atom *list_data = x->list_data; short i; // post("showstate: %d", x->shuffle_count); for( i = 0; i < x->shuffle_count; i++ ) { SETFLOAT(list_data+i,(t_float)x->shuffle_out[i]); // post(x->shuffle_out[i]); } outlet_list(x->list_outlet,0,x->shuffle_count,list_data); } void disarray_dsp(t_disarray *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ disarray_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(disarray_perform, 3, x, sp[0]->s_vec, sp[1]->s_vec); } } pd-fftease-3.0.1/drown~.c000066400000000000000000000160511401707710000152240ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *drown_class; #define OBJECT_NAME "drown~" typedef struct _drown { t_object x_obj; float x_f; t_fftease *fft; t_float drownmult; short mute; short bypass; t_float threshold; short peakflag; } t_drown; static t_int *drown_perform(t_int *w); static void drown_dsp(t_drown *x, t_signal **sp); static void *drown_new(t_symbol *s, int argc, t_atom *argv); static void drown_mute(t_drown *x, t_floatarg toggle); static void drown_adaptive(t_drown *x, t_floatarg toggle); static void drown_free(t_drown *x); static void drown_init(t_drown *x); static void drown_fftinfo(t_drown *x); static void drown_bypass(t_drown *x, t_floatarg toggle); static void drown_fftsize(t_drown *x, t_floatarg f); static void drown_overlap(t_drown *x, t_floatarg f); static void drown_winfac(t_drown *x, t_floatarg f); void drown_tilde_setup(void) { t_class *c; c = class_new(gensym("drown~"), (t_newmethod)drown_new, (t_method)drown_free,sizeof(t_drown), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_drown, x_f); class_addmethod(c,(t_method)drown_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)drown_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)drown_fftinfo,gensym("fftinfo"),0); class_addmethod(c,(t_method)drown_adaptive,gensym("adaptive"),A_FLOAT,0); drown_class = c; fftease_announce(OBJECT_NAME); } void drown_fftsize(t_drown *x, t_floatarg f) { x->fft->N = (int) f; drown_init(x); } void drown_overlap(t_drown *x, t_floatarg f) { x->fft->overlap = (int) f; drown_init(x); } void drown_winfac(t_drown *x, t_floatarg f) { x->fft->winfac = (int) f; drown_init(x); } void drown_fftinfo(t_drown *x) { fftease_fftinfo(x->fft, OBJECT_NAME); } void drown_adaptive(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_bypass(t_drown *x, t_floatarg toggle) { x->bypass = (short)toggle; } void *drown_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft; 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")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; x->fft->initialized = 0; x->threshold = 0.001; x->drownmult = 0.1; x->mute = 0; x->peakflag = 1; x->fft->N = FFTEASE_DEFAULT_FFTSIZE; x->fft->overlap = FFTEASE_DEFAULT_OVERLAP; x->fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void drown_init(t_drown *x) { fftease_init(x->fft); } void drown_free(t_drown *x) { fftease_free(x->fft); free(x->fft); } static void do_drown(t_drown *x) { int i; t_fftease *fft = x->fft; t_float *channel = fft->channel; t_float threshold = x->threshold; t_float drownmult = x->drownmult; t_float frame_peak = 0.0, local_thresh; int N = fft->N; fftease_fold(fft); fftease_rdft(fft,1); fftease_leanconvert(fft); if(x->peakflag){ for(i = 0; i < N; i += 2){ if(frame_peak < channel[i]) frame_peak = channel[i]; } local_thresh = frame_peak * threshold; } else { local_thresh = threshold; } for(i = 0; i < N; i += 2){ if(channel[i] < local_thresh) channel[i] *= drownmult; } fftease_leanunconvert(fft); fftease_rdft(fft,-1); fftease_overlapadd(fft); } t_int *drown_perform(t_int *w) { int i,j; t_drown *x = (t_drown *) (w[1]); t_float *MSPInputVector = (t_float *)(w[2]); t_float *threshold = (t_float *)(w[3]); t_float *drownmult = (t_float *)(w[4]); t_float *MSPOutputVector = (t_float *)(w[5]); t_fftease *fft = x->fft; int D = fft->D; int Nw = fft->Nw; t_float *input = fft->input; t_float *output = fft->output; t_float mult = fft->mult; int MSPVectorSize = fft->MSPVectorSize; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+6; } x->threshold = *threshold; x->drownmult = *drownmult; if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_drown(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_drown(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_drown(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+6; } void drown_dsp(t_drown *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ drown_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(drown_perform, 5, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); } } pd-fftease-3.0.1/enrich~.c000066400000000000000000000236271401707710000153520ustar00rootroot00000000000000/* FFTease for Pd */ /* STILL NEEDS Pd Array code installed */ #include "fftease.h" static t_class *enrich_class; #define OBJECT_NAME "enrich~" typedef struct _enrich { t_object x_obj; float x_f; t_fftease *fft; t_symbol *buffername; t_float lofreq; t_float hifreq; int lo_bin; int hi_bin; t_float topfreq; short mute; int b_valid; long b_frames; long b_errorstatus; t_word *b_samples; } t_enrich; static void enrich_dsp(t_enrich *x, t_signal **sp); static t_int *enrich_perform(t_int *w); static void *enrich_new(t_symbol *s, int argc, t_atom *argv); static void enrich_free(t_enrich *x); static void enrich_mute(t_enrich *x, t_floatarg tog); static void enrich_init(t_enrich *x); static void enrich_lowfreq(t_enrich *x, t_floatarg f); static void enrich_highfreq(t_enrich *x, t_floatarg f); static void enrich_dolowfreq(t_enrich *x); static void enrich_dohighfreq(t_enrich *x); static void enrich_attachbuf(t_enrich *x); static void enrich_binstats(t_enrich *x); static void enrich_fftinfo(t_enrich *x); static void enrich_fftsize(t_enrich *x, t_floatarg f); static void enrich_overlap(t_enrich *x, t_floatarg f); static void enrich_setbuf(t_enrich *x, t_symbol *newbufname); static void enrich_winfac(t_enrich *x, t_floatarg f); void enrich_tilde_setup(void) { t_class *c; c = class_new(gensym("enrich~"), (t_newmethod)enrich_new, (t_method)enrich_free,sizeof(t_enrich), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_enrich, x_f); class_addmethod(c,(t_method)enrich_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)enrich_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)enrich_lowfreq,gensym("lowfreq"),A_FLOAT,0); class_addmethod(c,(t_method)enrich_highfreq,gensym("highfreq"),A_FLOAT,0); enrich_class = c; fftease_announce(OBJECT_NAME); } void enrich_mute(t_enrich *x, t_floatarg tog) { x->mute = (short)tog; } void enrich_fftsize(t_enrich *x, t_floatarg f) { t_fftease *fft = x->fft; fft->N = (int) f; enrich_init(x); } void enrich_overlap(t_enrich *x, t_floatarg f) { x->fft->overlap = (int) f; enrich_init(x); } void enrich_winfac(t_enrich *x, t_floatarg f) { x->fft->winfac = (int) f; enrich_init(x); } void enrich_fftinfo(t_enrich *x) { fftease_fftinfo( x->fft, OBJECT_NAME ); } void enrich_free(t_enrich *x ){ fftease_free(x->fft); free(x->fft); } void enrich_highfreq(t_enrich *x, t_floatarg f) { t_fftease *fft = x->fft; float curfreq; if(f < x->lofreq){ error("current minimum is %f",x->lofreq); return; } if(f > fft->R/2 ){ f = fft->R/2; } x->hifreq = f; fft->hi_bin = 1; curfreq = 0; while(curfreq < x->hifreq) { ++(fft->hi_bin); curfreq += fft->c_fundamental; } } void enrich_lowfreq(t_enrich *x, t_floatarg f) { t_fftease *fft = x->fft; float curfreq; if(f > x->hifreq){ error("current maximum is %f",x->lofreq); return; } if(f < 0 ){ f = 0; } x->lofreq = f; fft->lo_bin = 0; curfreq = 0; while( curfreq < x->lofreq ) { ++(fft->lo_bin); curfreq += fft->c_fundamental ; } } void enrich_dohighfreq(t_enrich *x) { t_fftease *fft = x->fft; t_float curfreq; if( fft->c_fundamental <= 0.0){ return; } if(x->hifreq <= 0.0){ x->hifreq = 100.0; } fft->hi_bin = 1; curfreq = 0.0; while(curfreq < x->hifreq) { ++(fft->hi_bin); curfreq += fft->c_fundamental; } } void enrich_dolowfreq(t_enrich *x) { t_fftease *fft = x->fft; if(x->lofreq < 0){ x->lofreq = 0.0; } if(x->lofreq >= x->hifreq){ x->lofreq = 0.0; } t_float curfreq; if( fft->c_fundamental <= 0.0){ return; } fft->lo_bin = 0; curfreq = 0; while( curfreq < x->lofreq ) { ++(fft->lo_bin); curfreq += fft->c_fundamental ; } } void enrich_init(t_enrich *x) { fftease_init(x->fft); fftease_oscbank_setbins(x->fft, x->lofreq, x->hifreq); } void enrich_setbuf(t_enrich *x, t_symbol *newbufname) { x->buffername = newbufname; } void *enrich_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft; t_enrich *x = (t_enrich *)pd_new(enrich_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->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft->initialized = 0; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ x->buffername = atom_getsymbolarg(0, argc, argv); } else { post("%s: Must specify array name", OBJECT_NAME); return NULL; } if(argc > 1){ fft->N = (int) atom_getfloatarg(1, argc, argv); } if(argc > 2){ fft->overlap = (int) atom_getfloatarg(2, argc, argv); } x->b_errorstatus = 0; return x; } void enrich_attachbuf(t_enrich *x) { int frames; t_symbol *buffername = x->buffername; t_garray *a; x->b_frames = 0; x->b_valid = 0; if (!(a = (t_garray *)pd_findbyclass(buffername, garray_class))) { if (*buffername->s_name) { if(x->b_errorstatus == 0) { pd_error(x, "enrich~: %s: no such array", buffername->s_name); x->b_errorstatus = 1; } } } else if (!garray_getfloatwords(a, &frames, &x->b_samples)) { if(x->b_errorstatus == 0) { pd_error(x, "%s: bad template for enrich~", buffername->s_name); x->b_errorstatus = 1; } } else { x->b_frames = frames; x->b_valid = 1; x->b_errorstatus = 0; garray_usedindsp(a); } } void enrich_binstats(t_enrich *x) { post("lo freq %f hi freq %f lo bin %d hi bin %d",x->lofreq, x->fft->lo_bin,x->hifreq,x->fft->hi_bin); } static void do_enrich(t_enrich *x) { t_fftease *fft = x->fft; enrich_dolowfreq(x); enrich_dohighfreq(x); fftease_fold(fft); fftease_rdft(fft,1); fftease_convert(fft); fftease_oscbank(fft); } t_int *enrich_perform(t_int *w) { t_enrich *x = (t_enrich *) (w[1]); t_float *MSPInputVector = (t_float *)(w[2]); t_float *transpose = (t_float *)(w[3]); t_float *synt = (t_float *)(w[4]); t_float *MSPOutputVector = (t_float *)(w[5]); t_fftease *fft = x->fft; int i, j; int D = fft->D; int Nw = fft->Nw; t_float mult = fft->mult; t_float *input = fft->input; t_float *output = fft->output; int MSPVectorSize = fft->MSPVectorSize; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; t_word *b_samples; enrich_attachbuf(x); if(x->mute || ! x->b_valid){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+6; } if(x->b_frames < fft->L){ post("enrich~: table too small or not mono"); return w+6; } b_samples = x->b_samples; mult *= fft->N; // copy buffer to internal table (try more efficient means later) for(i = 0; i < fft->L; i++){ fft->table[i] = b_samples[i].w_float; } fft->P = *transpose; fft->synt = *synt; if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_enrich(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_enrich(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_enrich(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+6; } void enrich_dsp(t_enrich *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ enrich_init(x); enrich_dolowfreq(x); enrich_dohighfreq(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(enrich_perform, 5, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); } } pd-fftease-3.0.1/ether~.c000066400000000000000000000230311401707710000151760ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *ether_class; #define OBJECT_NAME "ether~" /* Added a new inlet for the composite index */ typedef struct _ether { t_object x_obj; float x_f; t_fftease *fft; t_fftease *fft2; int invert; t_float threshMult; short mute; } t_ether; static void ether_dsp(t_ether *x, t_signal **sp); static t_int *ether_perform(t_int *w); static void *ether_new(t_symbol *s, int argc, t_atom *argv); static void ether_invert(t_ether *x, t_floatarg toggle); static void ether_init(t_ether *x); static void ether_free(t_ether *x); static void ether_mute(t_ether *x, t_floatarg toggle); void ether_tilde_setup(void) { t_class *c; c = class_new(gensym("ether~"), (t_newmethod)ether_new, (t_method)ether_free,sizeof(t_ether), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_ether, x_f); class_addmethod(c,(t_method)ether_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)ether_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)ether_invert,gensym("invert"), A_FLOAT, 0); ether_class = c; fftease_announce(OBJECT_NAME); } void ether_free(t_ether *x) { fftease_free(x->fft); fftease_free(x->fft2); free(x->fft); free(x->fft2); } void *ether_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft, *fft2; t_ether *x = (t_ether *)pd_new(ether_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->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); x->fft2 = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft2 = x->fft2; fft->initialized = 0; fft2->initialized = 0; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; fft2->N = FFTEASE_DEFAULT_FFTSIZE; fft2->overlap = FFTEASE_DEFAULT_OVERLAP; fft2->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = fft2->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = fft2->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void ether_init(t_ether *x) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; short initialized = fft->initialized; fftease_init(fft); fftease_init(fft2); if(!initialized){ x->mute = 0; x->invert = 0; x->threshMult = 0.; } else { x->fft->input = (t_float *) realloc(fft->input,fft->Nw * sizeof(t_float)); x->fft2->input = (t_float *) realloc(fft2->input,fft2->Nw * sizeof(t_float)); x->fft->output = (t_float *) realloc(fft->output,fft->Nw * sizeof(t_float)); } } static void do_ether(t_ether *x) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int i; int N2 = fft->N2; float a1, b1, a2, b2; int even, odd; int invert = x->invert; t_float threshMult = x->threshMult; t_float *bufferOne = fft->buffer; t_float *bufferTwo = fft2->buffer; t_float *channelOne = fft->channel; t_float *channelTwo = fft2->channel; fftease_fold(fft); fftease_fold(fft2); fftease_rdft(fft,1); fftease_rdft(fft2,1); if (invert) { 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 ); if ( *(channelOne+even) > *(channelTwo+even) * threshMult ) *(channelOne+even) = *(channelTwo+even); if ( *(channelOne+odd) == 0. ) *(channelOne+odd) = *(channelTwo+odd); } } 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 ); if ( *(channelOne+even) < *(channelTwo+even) * threshMult ) *(channelOne+even) = *(channelTwo+even); if ( *(channelOne+odd) == 0. ) *(channelOne+odd) = *(channelTwo+odd); } } 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) ); } fftease_rdft(fft, -1); fftease_overlapadd(fft); } t_int *ether_perform(t_int *w) { int i,j; t_ether *x = (t_ether *) (w[1]); t_float *MSPInputVector1 = (t_float *)(w[2]); t_float *MSPInputVector2 = (t_float *)(w[3]); t_float *vec_threshMult = (t_float *)(w[4]); t_float *MSPOutputVector = (t_float *)(w[5]); t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int MSPVectorSize = fft->MSPVectorSize; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; t_float *internalInputVector1 = fft->internalInputVector; t_float *internalInputVector2 = fft2->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; t_float *inputOne = fft->input; t_float *inputTwo = fft2->input; t_float *output = fft->output; int D = fft->D; int Nw = fft->Nw; t_float mult = fft->mult; x->threshMult = *vec_threshMult; if ( x->threshMult == 0. ){ x->threshMult = 0.0001; } if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+6; } if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), MSPInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), MSPInputVector2, D * sizeof(t_float)); do_ether(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw-D), MSPInputVector1 + (D*i), D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw-D), MSPInputVector2 + (D*i), D * sizeof(t_float)); do_ether(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector1 + (operationCount * MSPVectorSize), MSPInputVector1, MSPVectorSize * sizeof(t_float)); memcpy(internalInputVector2 + (operationCount * MSPVectorSize), MSPInputVector2, MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize), MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), internalInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), internalInputVector2, D * sizeof(t_float)); do_ether(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+6; } 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) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(!samplerate) return; if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); fft2->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft2); } if(fft->R != samplerate ){ fft->R = samplerate; fft2->R = samplerate; } if(reset_required){ ether_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(ether_perform, 5, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,sp[3]->s_vec); } } pd-fftease-3.0.1/fft.c000066400000000000000000000074701401707710000144610ustar00rootroot00000000000000#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 fftease_rfft( t_float *x, int N, int forward ) { t_float c1,c2, h1r,h1i, h2r,h2i, wr,wi, wpr,wpi, temp, theta; t_float xr,xi; int i, i1,i2,i3,i4, N2p1; static int first = 1; /*t_float PI, TWOPI;*/ void fftease_cfft(); if ( first ) { first = 0; } theta = PI/N; wr = 1.; wi = 0.; c1 = 0.5; if ( forward ) { c2 = -0.5; fftease_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 fftease_cfft( x, N, forward ); } /* cfft replaces t_float array x containing NC complex values (2*NC t_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 fftease_cfft( t_float *x, int NC, int forward ) { t_float wr,wi, wpr,wpi, theta, scale; int mmax, ND, m, i,j, delta; void fftease_bitreverse(); ND = NC<<1; fftease_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 t_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 t_float *xi=x, *xe=x+ND; while ( xi < xe ) *xi++ *= scale; } } /* bitreverse places t_float array x containing N/2 complex values into bit-reversed order */ void fftease_bitreverse( t_float *x, int N ) { t_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; } } pd-fftease-3.0.1/fft4.c000066400000000000000000000176621401707710000145510ustar00rootroot00000000000000#include #include "fftease.h" /* forward declarations */ static void rftsub(int n, t_float *a, int nc, t_float *c); static void fftease_bitrv2(int n, int *ip, t_float *a); static void fftease_cftsub(int n, t_float *a, t_float *w); void fftease_init_rdft(int n, int *ip, t_float *w) { int nw, nc; void fftease_makewt(int nw, int *ip, t_float *w); void fftease_makect(int nc, int *ip, t_float *c); nw = n >> 2; fftease_makewt(nw, ip, w); nc = n >> 2; fftease_makect(nc, ip, w + nw); return; } void fftease_rdft(t_fftease *fft, int isgn) { int n = fft->N; t_float *a = fft->buffer; int *ip = fft->bitshuffle; t_float *w = fft->trigland; int j, nw, nc; t_float xi; 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); fftease_bitrv2(n, ip + 2, a); } fftease_cftsub(n, a, w); for (j = 1; j <= n - 1; j += 2) { a[j] = -a[j]; } } else { if (n > 4) { fftease_bitrv2(n, ip + 2, a); } fftease_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 fftease_bitrv2(int n, int *ip, t_float *a) { int j, j1, k, k1, l, m, m2; t_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 fftease_cftsub(int n, t_float *a, t_float *w) { int j, j1, j2, j3, k, k1, ks, l, m; t_float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; t_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; } } } static void rftsub(int n, t_float *a, int nc, t_float *c) { int j, k, kk, ks; t_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 fftease_makewt(int nw, int *ip, t_float *w) { void fftease_bitrv2(int n, int *ip, t_float *a); int nwh, j; t_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; } fftease_bitrv2(nw, ip + 2, w); } } void fftease_makect(int nc, int *ip, t_float *c) { int nch, j; t_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); } } } pd-fftease-3.0.1/fftease-helpfiles/000077500000000000000000000000001401707710000171145ustar00rootroot00000000000000pd-fftease-3.0.1/fftease-helpfiles/bthresher~-help.pd000077500000000000000000001122121401707710000225550ustar00rootroot00000000000000#N canvas 600 60 628 653 12; #X floatatom 234 493 5 0 0 0 - - -; #X obj 237 467 hsl 128 15 0.25 1 0 0 empty \$0-damping empty -2 -8 0 10 -228856 -1 -1 11853 1; #X floatatom 148 456 5 0 0 0 - - -; #X obj 151 430 hsl 128 15 0.5 1.25 0 0 empty \$0-threshold empty -2 -8 0 10 -228856 -1 -1 4233 1; #X obj 62 570 ./gain.dsp~; #X text 48 87 [bthresher~] extends the thresher~ model to allow independent control over the parameters of each individual bin. You can also randomly set damping and threshold values \, and can dump the current values (to possibly send as input to another bthresher~ unit). It is recommended that you familiarize yourself with [thresher~] before exploring the more complicated [bthresher~]., f 74; #X text 345 171 see also:; #X text 283 426 threshold factor for all bins, f 19; #X text 284 487 damping factor for all bins, f 14; #X obj 62 190 noise~; #N canvas 897 222 309 224 init 0; #X obj 24 55 f \$0; #X obj 24 27 loadbang; #X msg 24 82 \; \$1-threshold 0.75 \; \$1-damping 0.95 \; \$1-maxhold 5000 \; \$1-transpose-slider 1; #X connect 0 0 2 0; #X connect 1 0 0 0; #X restore 431 243 pd init; #X obj 57 22 ./icon bthresher~; #X text 296 52 - Bin level feedback; #N canvas 705 264 390 253 random_control 0; #X obj 37 49 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X obj 37 79 t b b; #X msg 172 144 rthreshold 0.06 0.2; #X msg 37 143 rdamper 0.6 1.1; #X text 34 25 randomize parameters for each individual bin; #X obj 37 196 s bthresher~_msgs; #X text 155 106 args: min and max values; #X connect 0 0 1 0; #X connect 1 0 3 0; #X connect 1 1 2 0; #X connect 2 0 5 0; #X connect 3 0 5 0; #X restore 431 315 pd random_control; #X obj 118 398 r bthresher~_msgs; #N canvas 523 234 587 327 global_control 0; #X obj 37 245 s bthresher~_msgs; #X floatatom 37 67 5 1 200000 0 - #0-maxhold -; #X msg 37 95 max_hold \$1; #X msg 131 151 inf_hold \$1; #X obj 131 118 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X text 151 115 sets the maximum hold time to infinity; #X text 92 64 set the maximum hold time in milliseconds; #X msg 109 214 dump; #X text 149 209 sends all current parameters to the right outlet. Format: [bin # \, dampfactor \, threshold]; #X connect 1 0 2 0; #X connect 2 0 0 0; #X connect 3 0 0 0; #X connect 4 0 3 0; #X connect 7 0 0 0; #X restore 431 278 pd global_control; #X obj 62 533 fftease/bthresher~ 1024 8; #N canvas 543 274 709 407 single-bin-control 0; #X obj 37 349 s bthresher~_msgs; #X obj 37 187 pack f f f; #X floatatom 37 61 5 0 511 0 - - -; #X floatatom 70 140 5 0 0 0 - - -; #X floatatom 152 158 5 0 0 0 - - -; #X obj 73 99 hsl 128 15 0.5 0.999 0 0 empty empty damping-factor -2 -8 0 10 -262144 -1 -1 0 1; #X obj 155 138 hsl 128 15 0.01 0.5 0 0 empty empty threshold -2 -8 0 10 -262144 -1 -1 0 1; #X msg 37 216 bin \$1 \$2 \$3; #X text 77 59 bin number; #X text 33 26 Use this patch to individually set the parameters for each bin, f 80; #X text 195 179 send bin data in a list of triplets: [bin # \, damp factor \, threshold], f 73; #X msg 200 203 3 0.99 0.01 11 0.99 0.01 15 0.99 0.01 23 0.99 0.01 52 0.99 0.01 56 0.99 0.01; #N canvas 0 23 987 961 big-data 0; #X obj 21 40 inlet; #X msg 75 -12 0 0.624338 0.0864722 1 0.71734 0.084353 2 0.875696 0.188823 3 0.945581 0.133623 4 0.999185 0.126851 5 0.877267 0.181513 6 0.777124 0.170093 7 0.717798 0.181026 8 0.659799 0.0966663 9 0.863901 0.176416 10 0.674844 0.088399 11 1.06915 0.174058 12 0.805078 0.189037 13 0.915048 0.184961 14 0.711572 0.188088 15 0.871866 0.0963672 16 1.04043 0.0841992 17 0.656107 0.140587 18 0.779596 0.159565 19 0.678995 0.0856219 20 0.92933 0.0626703 21 0.77572 0.174122 22 0.955927 0.12304 23 0.703546 0.123997 24 0.621423 0.198351 25 0.791147 0.13085 26 0.943857 0.173891 27 1.03173 0.155011 28 0.797372 0.138682 29 0.999872 0.0838831 30 0.99592 0.0981445 31 0.963586 0.0956366 32 0.610086 0.140468 33 0.630457 0.0813794 34 1.03173 0.07242 35 0.972818 0.109731 36 0.748239 0.137575 37 0.778238 0.1941 38 0.752924 0.163449 39 0.919626 0.12818 40 0.648004 0.096145 41 0.654428 0.136439 42 0.922617 0.159792 43 0.875421 0.0997638 44 0.75622 0.158583 45 0.910745 0.105352 46 0.936151 0.182 47 0.813654 0.0959827 48 0.674707 0.188434 49 0.898813 0.16588 50 0.929514 0.106971 51 0.747537 0.066366 52 0.984842 0.101665 53 0.656488 0.0966064 54 0.749521 0.191062 55 0.666544 0.0736761 56 0.626093 0.0959528 57 0.813394 0.0796362 58 0.807657 0.113705 59 0.9311 0.110641 60 1.08236 0.157263 61 0.872461 0.168051 62 0.894876 0.177018 63 0.791681 0.116644 64 0.753549 0.12225 65 0.924875 0.0968628 66 1.00565 0.124245 67 0.622354 0.166606 68 0.908197 0.0866687 69 1.01052 0.156921 70 0.982446 0.155695 71 0.928644 0.107869 72 0.756952 0.0720953 73 1.08625 0.107928 74 0.601999 0.198287 75 0.902414 0.136686 76 0.831567 0.138583 77 0.721979 0.110671 78 0.783075 0.130863 79 0.6746 0.136033 80 1.02203 0.182103 81 0.773294 0.13843 82 0.824472 0.137908 83 0.807245 0.0835327 84 0.974664 0.0795892 85 0.679758 0.087959 86 0.726434 0.180518 87 0.830392 0.0877112 88 0.997385 0.173647 89 0.647134 0.143398 90 0.982416 0.11306 91 0.978098 0.189584 92 0.889566 0.165081 93 0.899057 0.061709 94 1.03121 0.149632 95 1.05808 0.111932 96 0.789133 0.136255 97 0.957513 0.150427 98 0.899057 0.0773932 99 0.939111 0.0858099 100 0.621393 0.142963 101 0.825693 0.173481 102 1.06275 0.139724 103 0.794199 0.198244 104 0.727411 0.153892 105 1.00034 0.0710101 106 0.945718 0.071557 107 0.602655 0.159963 108 0.82821 0.159835 109 0.674951 0.145223 110 1.00849 0.0734454 111 0.645517 0.0856091 112 0.758051 0.169469 113 0.69169 0.0755176 114 0.66308 0.185243 115 0.92254 0.171464 116 1.05326 0.107591 117 0.722681 0.165231 118 1.09223 0.0995972 119 0.688135 0.174438 120 0.981256 0.124677 121 0.976129 0.133606 122 0.846002 0.139109 123 0.900262 0.0643323 124 0.790277 0.138207 125 0.738428 0.0881299 126 0.657785 0.0871899 127 0.865579 0.13376 128 0.789346 0.100088 129 0.634744 0.0704675 130 0.691888 0.15707 131 0.610956 0.125399 132 0.803186 0.141237 133 1.07774 0.149077 134 0.974374 0.174656 135 0.801218 0.125176 136 0.672357 0.160676 137 0.775232 0.141809 138 0.772256 0.145859 139 0.820764 0.153934 140 0.649454 0.0929065 141 0.904764 0.165598 142 0.783762 0.0992767 143 0.701669 0.109355 144 0.953302 0.102434 145 1.07209 0.10983 146 0.671274 0.133965 147 1.03288 0.172088 148 1.01225 0.136695 149 0.842752 0.103271 150 0.624673 0.0795892 151 1.04173 0.174335 152 0.929178 0.0977899 153 0.68197 0.0765002 154 0.886011 0.0621918 155 0.78811 0.12081 156 0.922556 0.101644 157 0.868234 0.132106 158 0.960962 0.120545 159 0.92843 0.139357 160 1.06269 0.176929 161 0.698724 0.115405 162 0.98858 0.170323 163 0.656595 0.111927 164 0.8108 0.0782776 165 1.07414 0.160587 166 0.954019 0.13496 167 0.698892 0.0723987 168 0.777475 0.173754 169 0.989709 0.0938934 170 0.989328 0.108262 171 0.755396 0.185662 172 0.895227 0.163492 173 0.710138 0.145137 174 0.891229 0.0908899 175 1.03724 0.109693 176 0.867075 0.15446 177 0.895395 0.106091 178 0.943033 0.106758 179 0.637247 0.156083 180 0.737497 0.189601 181 0.635965 0.169815 182 0.653406 0.144796 183 0.910791 0.0655585 184 0.670313 0.105087 185 0.847406 0.0927441 186 0.987558 0.109099 187 1.03309 0.138626 188 0.692972 0.0711255 189 0.932977 0.153836 190 1.0521 0.132623 191 0.740121 0.181915 192 0.828165 0.0880914 193 0.968347 0.172588 194 0.921976 0.10178 195 0.685602 0.0745862 196 0.84292 0.112299 197 1.0025 0.148538 198 0.604501 0.078017 199 0.928796 0.191288 200 0.734003 0.11717 201 0.927728 0.122245 202 0.942087 0.0668359 203 0.627817 0.153212 204 0.694971 0.115666 205 1.0234 0.183705 206 0.951151 0.0888605 207 1.03636 0.0749835 208 1.01377 0.071792 209 1.00956 0.171836 210 0.615488 0.0914069 211 0.608423 0.162052 212 0.837671 0.154268 213 0.787317 0.193792 214 0.887399 0.165927 215 0.971292 0.0680493 216 0.948602 0.119776 217 0.630777 0.12137 218 0.91929 0.159587 219 0.613107 0.142279 220 0.61796 0.152704 221 0.649301 0.10598 222 0.727655 0.199521 223 0.639108 0.17965 224 0.95614 0.101024 225 0.942545 0.0879462 226 0.878946 0.114893 227 0.944589 0.185418 228 0.833841 0.147889 229 0.850031 0.0741974 230 1.01592 0.136977 231 0.735956 0.131675 232 0.862344 0.063999 233 1.0664 0.131034 234 1.09826 0.0770258 235 1.06346 0.110291 236 1.06758 0.180441 237 0.850168 0.106707 238 0.83204 0.109086 239 0.700143 0.0796106 240 0.812387 0.145107 241 0.839822 0.139015 242 0.902582 0.19692 243 0.797662 0.100875 244 0.833688 0.0888007 245 0.877313 0.199504 246 0.612146 0.163906 247 0.879037 0.0795166 248 0.958444 0.0926886 249 0.62243 0.113628 250 0.709695 0.129184 251 0.981622 0.0656055 252 0.636316 0.0609485 253 1.02828 0.074129 254 0.883005 0.136063 255 1.06101 0.124523 256 1.0276 0.0824902 257 0.747095 0.106501 258 0.965265 0.132363 259 0.781183 0.101234 260 0.911554 0.0856091 261 1.07844 0.171054 262 0.89715 0.0856091 263 1.04614 0.164201 264 0.887445 0.136383 265 0.890009 0.0864038 266 0.774942 0.0806744 267 0.872736 0.0967218 268 0.982324 0.168768 269 1.06082 0.0663403 270 1.07997 0.0819775 271 1.07566 0.161578 272 0.620172 0.142266 273 0.706293 0.102498 274 0.751123 0.0820673 275 0.600916 0.12248 276 0.608606 0.192109 277 0.973673 0.0736121 278 0.650171 0.0878094 279 1.05099 0.162056 280 0.93252 0.0675836 281 0.948709 0.178651 282 1.02934 0.0631958 283 1.0794 0.184628 284 1.008 0.19248 285 0.989542 0.120237 286 0.75596 0.1995 287 1.05134 0.130355 288 0.980844 0.141741 289 0.692911 0.109578 290 0.900797 0.196454 291 0.822458 0.157181 292 0.987817 0.162018 293 0.714166 0.136674 294 0.993997 0.191904 295 0.708643 0.0833319 296 0.753427 0.0738727 297 0.948602 0.159476 298 0.675317 0.105113 299 1.06661 0.0864508 300 0.640802 0.162347 301 1.02519 0.0937567 302 0.894022 0.186422 303 0.933862 0.0963928 304 0.893533 0.0646954 305 0.714685 0.163851 306 0.658044 0.13646 307 0.683557 0.0802472 308 0.646661 0.195608 309 1.09213 0.186153 310 0.789301 0.0614355 311 0.78309 0.112214 312 1.01286 0.157062 313 0.650995 0.160048 314 0.913126 0.194241 315 0.912485 0.154263 316 0.77363 0.156805 317 1.00018 0.176219 318 0.971597 0.109761 319 1.09893 0.081059 320 0.860712 0.117823 321 0.891702 0.194813 322 0.798685 0.150119 323 0.917719 0.0967517 324 0.715845 0.110056 325 0.613458 0.112162 326 1.03765 0.0775726 327 0.938409 0.187794 328 0.970041 0.171349 329 1.00858 0.12231 330 0.873636 0.109253 331 0.853983 0.0778418 332 0.891672 0.0775128 333 0.781412 0.158737 334 0.690698 0.158015 335 0.99328 0.176997 336 1.0503 0.156015 337 0.85264 0.17137 338 0.768915 0.0658276 339 0.650217 0.18696 340 0.80285 0.174297 341 0.636285 0.115533 342 0.696405 0.194001 343 1.08886 0.091817 344 0.995126 0.189092 345 0.698068 0.198693 346 1.01878 0.105168 347 0.610452 0.196236 348 0.877756 0.0821356 349 0.99267 0.1475 350 0.853998 0.120404 351 0.712244 0.0621576 352 0.832285 0.102118 353 0.795908 0.146052 354 0.71998 0.138976 355 0.761881 0.111141 356 0.85882 0.137054 357 0.81048 0.135729 358 0.806757 0.169439 359 0.642236 0.11429 360 1.0267 0.196381 361 0.708505 0.0708606 362 0.922296 0.0734753 363 0.997644 0.16899 364 0.84086 0.163744 365 0.91427 0.137327 366 0.689767 0.127137 367 0.998834 0.0862628 368 0.825769 0.109052 369 0.825891 0.191908 370 0.703989 0.148508 371 0.89277 0.129005 372 0.879739 0.0792517 373 0.88122 0.153336 374 0.801569 0.104139 375 1.04699 0.101904 376 0.867075 0.150029 377 0.872614 0.128855 378 0.970773 0.133828 379 0.692346 0.102806 380 0.877634 0.197112 381 0.984155 0.131346 382 0.653741 0.100217 383 0.940393 0.123848 384 0.655679 0.0618201 385 1.07592 0.157515 386 0.629205 0.0632086 387 0.966791 0.14571 388 0.91221 0.173566 389 1.07737 0.0603503 390 0.89541 0.117264 391 1.08657 0.155131 392 0.606058 0.132346 393 0.91691 0.121583 394 1.00871 0.135845 395 0.870935 0.0942224 396 0.731744 0.116354 397 0.99209 0.1103 398 1.06576 0.139557 399 0.6233 0.197039 400 0.768152 0.185559 401 0.81283 0.15992 402 0.78895 0.153336 403 0.872034 0.0844257 404 0.809915 0.135584 405 0.841287 0.0651141 406 0.934732 0.06 407 0.637262 0.122502 408 0.874185 0.140237 409 0.877664 0.130782 410 0.922556 0.157545 411 1.00602 0.158984 412 0.683725 0.133747 413 0.860117 0.152418 414 1.09826 0.177288 415 1.06594 0.124886 416 0.765054 0.137874 417 0.877054 0.182641 418 0.72413 0.0749707 419 1.08735 0.118541 420 0.722452 0.0832422 421 0.752969 0.160655 422 0.602701 0.164654 423 0.634622 0.160326 424 0.631342 0.0800207 425 0.947473 0.192408 426 0.76713 0.0621576 427 0.795053 0.128235 428 0.91781 0.192912 429 1.06977 0.0841608 430 0.624658 0.164974 431 0.735971 0.142634 432 1.07664 0.151294 433 1.07104 0.0792047 434 1.07198 0.173007 435 0.904077 0.15566 436 0.734537 0.118443 437 0.952692 0.0952478 438 0.913629 0.142202 439 1.01609 0.148342 440 0.947977 0.145842 441 0.731317 0.170751 442 0.689462 0.0770001 443 0.917932 0.181393 444 0.664865 0.121062 445 0.96171 0.161868 446 0.891718 0.164222 447 1.07032 0.106651 448 1.02859 0.141348 449 0.898767 0.0827551 450 0.630212 0.0857031 451 0.622079 0.182791 452 0.902292 0.111265 453 0.865152 0.144347 454 1.06349 0.0765387 455 0.912241 0.163607 456 1.07705 0.0724072 457 1.05703 0.157241 458 0.963983 0.0891937 459 1.08238 0.177958 460 0.973947 0.0684979 461 0.67692 0.097901 462 0.9815 0.116452 463 1.02847 0.113773 464 0.850412 0.1724 465 0.968393 0.168662 466 0.696939 0.184888 467 0.925836 0.190989 468 0.626321 0.131192 469 1.07992 0.182509 470 0.683588 0.092774 471 1.04846 0.199897 472 1.04485 0.185999 473 0.93313 0.0898773 474 0.692896 0.180116 475 0.983682 0.0896252 476 0.687189 0.0622388 477 0.613153 0.17707 478 0.808756 0.114435 479 0.832162 0.0783801 480 0.731409 0.160236 481 0.892999 0.121609 482 0.656351 0.10369 483 0.875131 0.0882025 484 0.771997 0.0657165 485 0.938837 0.141352 486 0.9311 0.10457 487 1.01849 0.177305 488 0.826791 0.125497 489 1.02204 0.0842206 490 1.01862 0.190571 491 1.07374 0.0820673 492 0.889475 0.102596 493 1.05102 0.189836 494 1.06797 0.0778418 495 0.830576 0.070459 496 1.01446 0.144266 497 1.03024 0.144257 498 0.711923 0.0780383 499 0.833276 0.153071 500 0.925974 0.157767 501 0.774866 0.0704034 502 0.754282 0.0625293 503 0.745874 0.0806573 504 0.893228 0.19642 505 1.03625 0.0885272 506 0.641672 0.086015 507 0.710245 0.130739 508 0.677805 0.10848 509 0.891595 0.0641614 510 1.0498 0.15854 511 0.983591 0.193852; #X obj 46 2576 outlet; #X connect 0 0 1 0; #X connect 1 0 2 0; #X restore 225 289 pd big-data; #X obj 225 256 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X text 308 291 captured using the "dump" method; #X text 247 255 load parameter set; #X connect 1 0 7 0; #X connect 2 0 1 0; #X connect 3 0 1 1; #X connect 4 0 1 2; #X connect 5 0 3 0; #X connect 6 0 4 0; #X connect 7 0 0 0; #X connect 11 0 0 0; #X connect 12 0 0 0; #X connect 13 0 12 0; #X restore 431 352 pd single-bin-control; #X text 245 532 <= arguments: FFT size and; #X text 266 548 overlap factor (default: 1024 \, 8); #N canvas 539 348 632 212 utilities 0; #X obj 27 158 s bthresher~_msgs; #X msg 27 65 mute \$1; #X obj 27 31 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1 ; #X text 91 65 toggle object computation to lower CPU load when muted ; #X msg 39 119 fftinfo; #X text 104 121 print FFT size \, hop size \, signal vector size \, and sample rate, f 61; #X connect 1 0 0 0; #X connect 2 0 1 0; #X connect 4 0 0 0; #X restore 431 426 pd utilities; #N canvas 492 223 750 484 oscbank 0; #X obj 38 392 s bthresher~_msgs; #X msg 38 72 oscbank \$1; #X obj 38 38 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1 ; #X msg 69 292 transpose \$1; #X floatatom 69 252 5 0 0 0 - - -; #X obj 72 218 hsl 128 15 0.25 1.5 0 0 empty \$0-transpose-slider transposition-factor -2 -8 0 10 -228856 -1 -1 7620 1; #X text 64 35 oscbank mode (careful - louder!); #X msg 271 350 synthresh \$1; #X obj 274 295 hsl 128 15 0 1 0 0 empty empty synthesis-threshold -2 -8 0 10 -228856 -1 -1 0 1; #X floatatom 271 318 5 0 0 0 - - -; #X text 81 138 the following controllers only work when oscbank mode is turned on, f 70; #X text 270 215 with a synthesis threshold of 0 \, all bins are synthsized \; at higher thresholds \, bins with amplitudes below the threshold are suppressed \, thinning the texture and also lowering the CPU load of the object; #X connect 1 0 0 0; #X connect 2 0 1 0; #X connect 3 0 0 0; #X connect 4 0 3 0; #X connect 5 0 4 0; #X connect 7 0 0 0; #X connect 8 0 9 0; #X connect 9 0 7 0; #X restore 431 389 pd oscbank; #N canvas 306 195 929 761 capture-current-thresher-state 0; #X obj 108 71 inlet; #N canvas 0 23 908 1185 build-data-message 0; #X obj 72 57 inlet; #X obj 51 211 outlet; #X text 74 20 size of message is ((FFT size) / 2) * 3; #X msg 136 117 set \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8 \$9 \$10 \$11 \$12 \$13 \$14 \$15 \$16 \$17 \$18 \$19 \$20 \$21 \$22 \$23 \$24 \$25 \$26 \$27 \$28 \$29 \$30 \$31 \$32 \$33 \$34 \$35 \$36 \$37 \$38 \$39 \$40 \$41 \$42 \$43 \$44 \$45 \$46 \$47 \$48 \$49 \$50 \$51 \$52 \$53 \$54 \$55 \$56 \$57 \$58 \$59 \$60 \$61 \$62 \$63 \$64 \$65 \$66 \$67 \$68 \$69 \$70 \$71 \$72 \$73 \$74 \$75 \$76 \$77 \$78 \$79 \$80 \$81 \$82 \$83 \$84 \$85 \$86 \$87 \$88 \$89 \$90 \$91 \$92 \$93 \$94 \$95 \$96 \$97 \$98 \$99 \$100 \$101 \$102 \$103 \$104 \$105 \$106 \$107 \$108 \$109 \$110 \$111 \$112 \$113 \$114 \$115 \$116 \$117 \$118 \$119 \$120 \$121 \$122 \$123 \$124 \$125 \$126 \$127 \$128 \$129 \$130 \$131 \$132 \$133 \$134 \$135 \$136 \$137 \$138 \$139 \$140 \$141 \$142 \$143 \$144 \$145 \$146 \$147 \$148 \$149 \$150 \$151 \$152 \$153 \$154 \$155 \$156 \$157 \$158 \$159 \$160 \$161 \$162 \$163 \$164 \$165 \$166 \$167 \$168 \$169 \$170 \$171 \$172 \$173 \$174 \$175 \$176 \$177 \$178 \$179 \$180 \$181 \$182 \$183 \$184 \$185 \$186 \$187 \$188 \$189 \$190 \$191 \$192 \$193 \$194 \$195 \$196 \$197 \$198 \$199 \$200 \$201 \$202 \$203 \$204 \$205 \$206 \$207 \$208 \$209 \$210 \$211 \$212 \$213 \$214 \$215 \$216 \$217 \$218 \$219 \$220 \$221 \$222 \$223 \$224 \$225 \$226 \$227 \$228 \$229 \$230 \$231 \$232 \$233 \$234 \$235 \$236 \$237 \$238 \$239 \$240 \$241 \$242 \$243 \$244 \$245 \$246 \$247 \$248 \$249 \$250 \$251 \$252 \$253 \$254 \$255 \$256 \$257 \$258 \$259 \$260 \$261 \$262 \$263 \$264 \$265 \$266 \$267 \$268 \$269 \$270 \$271 \$272 \$273 \$274 \$275 \$276 \$277 \$278 \$279 \$280 \$281 \$282 \$283 \$284 \$285 \$286 \$287 \$288 \$289 \$290 \$291 \$292 \$293 \$294 \$295 \$296 \$297 \$298 \$299 \$300 \$301 \$302 \$303 \$304 \$305 \$306 \$307 \$308 \$309 \$310 \$311 \$312 \$313 \$314 \$315 \$316 \$317 \$318 \$319 \$320 \$321 \$322 \$323 \$324 \$325 \$326 \$327 \$328 \$329 \$330 \$331 \$332 \$333 \$334 \$335 \$336 \$337 \$338 \$339 \$340 \$341 \$342 \$343 \$344 \$345 \$346 \$347 \$348 \$349 \$350 \$351 \$352 \$353 \$354 \$355 \$356 \$357 \$358 \$359 \$360 \$361 \$362 \$363 \$364 \$365 \$366 \$367 \$368 \$369 \$370 \$371 \$372 \$373 \$374 \$375 \$376 \$377 \$378 \$379 \$380 \$381 \$382 \$383 \$384 \$385 \$386 \$387 \$388 \$389 \$390 \$391 \$392 \$393 \$394 \$395 \$396 \$397 \$398 \$399 \$400 \$401 \$402 \$403 \$404 \$405 \$406 \$407 \$408 \$409 \$410 \$411 \$412 \$413 \$414 \$415 \$416 \$417 \$418 \$419 \$420 \$421 \$422 \$423 \$424 \$425 \$426 \$427 \$428 \$429 \$430 \$431 \$432 \$433 \$434 \$435 \$436 \$437 \$438 \$439 \$440 \$441 \$442 \$443 \$444 \$445 \$446 \$447 \$448 \$449 \$450 \$451 \$452 \$453 \$454 \$455 \$456 \$457 \$458 \$459 \$460 \$461 \$462 \$463 \$464 \$465 \$466 \$467 \$468 \$469 \$470 \$471 \$472 \$473 \$474 \$475 \$476 \$477 \$478 \$479 \$480 \$481 \$482 \$483 \$484 \$485 \$486 \$487 \$488 \$489 \$490 \$491 \$492 \$493 \$494 \$495 \$496 \$497 \$498 \$499 \$500 \$501 \$502 \$503 \$504 \$505 \$506 \$507 \$508 \$509 \$510 \$511 \$512 \$513 \$514 \$515 \$516 \$517 \$518 \$519 \$520 \$521 \$522 \$523 \$524 \$525 \$526 \$527 \$528 \$529 \$530 \$531 \$532 \$533 \$534 \$535 \$536 \$537 \$538 \$539 \$540 \$541 \$542 \$543 \$544 \$545 \$546 \$547 \$548 \$549 \$550 \$551 \$552 \$553 \$554 \$555 \$556 \$557 \$558 \$559 \$560 \$561 \$562 \$563 \$564 \$565 \$566 \$567 \$568 \$569 \$570 \$571 \$572 \$573 \$574 \$575 \$576 \$577 \$578 \$579 \$580 \$581 \$582 \$583 \$584 \$585 \$586 \$587 \$588 \$589 \$590 \$591 \$592 \$593 \$594 \$595 \$596 \$597 \$598 \$599 \$600 \$601 \$602 \$603 \$604 \$605 \$606 \$607 \$608 \$609 \$610 \$611 \$612 \$613 \$614 \$615 \$616 \$617 \$618 \$619 \$620 \$621 \$622 \$623 \$624 \$625 \$626 \$627 \$628 \$629 \$630 \$631 \$632 \$633 \$634 \$635 \$636 \$637 \$638 \$639 \$640 \$641 \$642 \$643 \$644 \$645 \$646 \$647 \$648 \$649 \$650 \$651 \$652 \$653 \$654 \$655 \$656 \$657 \$658 \$659 \$660 \$661 \$662 \$663 \$664 \$665 \$666 \$667 \$668 \$669 \$670 \$671 \$672 \$673 \$674 \$675 \$676 \$677 \$678 \$679 \$680 \$681 \$682 \$683 \$684 \$685 \$686 \$687 \$688 \$689 \$690 \$691 \$692 \$693 \$694 \$695 \$696 \$697 \$698 \$699 \$700 \$701 \$702 \$703 \$704 \$705 \$706 \$707 \$708 \$709 \$710 \$711 \$712 \$713 \$714 \$715 \$716 \$717 \$718 \$719 \$720 \$721 \$722 \$723 \$724 \$725 \$726 \$727 \$728 \$729 \$730 \$731 \$732 \$733 \$734 \$735 \$736 \$737 \$738 \$739 \$740 \$741 \$742 \$743 \$744 \$745 \$746 \$747 \$748 \$749 \$750 \$751 \$752 \$753 \$754 \$755 \$756 \$757 \$758 \$759 \$760 \$761 \$762 \$763 \$764 \$765 \$766 \$767 \$768 \$769 \$770 \$771 \$772 \$773 \$774 \$775 \$776 \$777 \$778 \$779 \$780 \$781 \$782 \$783 \$784 \$785 \$786 \$787 \$788 \$789 \$790 \$791 \$792 \$793 \$794 \$795 \$796 \$797 \$798 \$799 \$800 \$801 \$802 \$803 \$804 \$805 \$806 \$807 \$808 \$809 \$810 \$811 \$812 \$813 \$814 \$815 \$816 \$817 \$818 \$819 \$820 \$821 \$822 \$823 \$824 \$825 \$826 \$827 \$828 \$829 \$830 \$831 \$832 \$833 \$834 \$835 \$836 \$837 \$838 \$839 \$840 \$841 \$842 \$843 \$844 \$845 \$846 \$847 \$848 \$849 \$850 \$851 \$852 \$853 \$854 \$855 \$856 \$857 \$858 \$859 \$860 \$861 \$862 \$863 \$864 \$865 \$866 \$867 \$868 \$869 \$870 \$871 \$872 \$873 \$874 \$875 \$876 \$877 \$878 \$879 \$880 \$881 \$882 \$883 \$884 \$885 \$886 \$887 \$888 \$889 \$890 \$891 \$892 \$893 \$894 \$895 \$896 \$897 \$898 \$899 \$900 \$901 \$902 \$903 \$904 \$905 \$906 \$907 \$908 \$909 \$910 \$911 \$912 \$913 \$914 \$915 \$916 \$917 \$918 \$919 \$920 \$921 \$922 \$923 \$924 \$925 \$926 \$927 \$928 \$929 \$930 \$931 \$932 \$933 \$934 \$935 \$936 \$937 \$938 \$939 \$940 \$941 \$942 \$943 \$944 \$945 \$946 \$947 \$948 \$949 \$950 \$951 \$952 \$953 \$954 \$955 \$956 \$957 \$958 \$959 \$960 \$961 \$962 \$963 \$964 \$965 \$966 \$967 \$968 \$969 \$970 \$971 \$972 \$973 \$974 \$975 \$976 \$977 \$978 \$979 \$980 \$981 \$982 \$983 \$984 \$985 \$986 \$987 \$988 \$989 \$990 \$991 \$992 \$993 \$994 \$995 \$996 \$997 \$998 \$999 \$1000 \$1001 \$1002 \$1003 \$1004 \$1005 \$1006 \$1007 \$1008 \$1009 \$1010 \$1011 \$1012 \$1013 \$1014 \$1015 \$1016 \$1017 \$1018 \$1019 \$1020 \$1021 \$1022 \$1023 \$1024 \$1025 \$1026 \$1027 \$1028 \$1029 \$1030 \$1031 \$1032 \$1033 \$1034 \$1035 \$1036 \$1037 \$1038 \$1039 \$1040 \$1041 \$1042 \$1043 \$1044 \$1045 \$1046 \$1047 \$1048 \$1049 \$1050 \$1051 \$1052 \$1053 \$1054 \$1055 \$1056 \$1057 \$1058 \$1059 \$1060 \$1061 \$1062 \$1063 \$1064 \$1065 \$1066 \$1067 \$1068 \$1069 \$1070 \$1071 \$1072 \$1073 \$1074 \$1075 \$1076 \$1077 \$1078 \$1079 \$1080 \$1081 \$1082 \$1083 \$1084 \$1085 \$1086 \$1087 \$1088 \$1089 \$1090 \$1091 \$1092 \$1093 \$1094 \$1095 \$1096 \$1097 \$1098 \$1099 \$1100 \$1101 \$1102 \$1103 \$1104 \$1105 \$1106 \$1107 \$1108 \$1109 \$1110 \$1111 \$1112 \$1113 \$1114 \$1115 \$1116 \$1117 \$1118 \$1119 \$1120 \$1121 \$1122 \$1123 \$1124 \$1125 \$1126 \$1127 \$1128 \$1129 \$1130 \$1131 \$1132 \$1133 \$1134 \$1135 \$1136 \$1137 \$1138 \$1139 \$1140 \$1141 \$1142 \$1143 \$1144 \$1145 \$1146 \$1147 \$1148 \$1149 \$1150 \$1151 \$1152 \$1153 \$1154 \$1155 \$1156 \$1157 \$1158 \$1159 \$1160 \$1161 \$1162 \$1163 \$1164 \$1165 \$1166 \$1167 \$1168 \$1169 \$1170 \$1171 \$1172 \$1173 \$1174 \$1175 \$1176 \$1177 \$1178 \$1179 \$1180 \$1181 \$1182 \$1183 \$1184 \$1185 \$1186 \$1187 \$1188 \$1189 \$1190 \$1191 \$1192 \$1193 \$1194 \$1195 \$1196 \$1197 \$1198 \$1199 \$1200 \$1201 \$1202 \$1203 \$1204 \$1205 \$1206 \$1207 \$1208 \$1209 \$1210 \$1211 \$1212 \$1213 \$1214 \$1215 \$1216 \$1217 \$1218 \$1219 \$1220 \$1221 \$1222 \$1223 \$1224 \$1225 \$1226 \$1227 \$1228 \$1229 \$1230 \$1231 \$1232 \$1233 \$1234 \$1235 \$1236 \$1237 \$1238 \$1239 \$1240 \$1241 \$1242 \$1243 \$1244 \$1245 \$1246 \$1247 \$1248 \$1249 \$1250 \$1251 \$1252 \$1253 \$1254 \$1255 \$1256 \$1257 \$1258 \$1259 \$1260 \$1261 \$1262 \$1263 \$1264 \$1265 \$1266 \$1267 \$1268 \$1269 \$1270 \$1271 \$1272 \$1273 \$1274 \$1275 \$1276 \$1277 \$1278 \$1279 \$1280 \$1281 \$1282 \$1283 \$1284 \$1285 \$1286 \$1287 \$1288 \$1289 \$1290 \$1291 \$1292 \$1293 \$1294 \$1295 \$1296 \$1297 \$1298 \$1299 \$1300 \$1301 \$1302 \$1303 \$1304 \$1305 \$1306 \$1307 \$1308 \$1309 \$1310 \$1311 \$1312 \$1313 \$1314 \$1315 \$1316 \$1317 \$1318 \$1319 \$1320 \$1321 \$1322 \$1323 \$1324 \$1325 \$1326 \$1327 \$1328 \$1329 \$1330 \$1331 \$1332 \$1333 \$1334 \$1335 \$1336 \$1337 \$1338 \$1339 \$1340 \$1341 \$1342 \$1343 \$1344 \$1345 \$1346 \$1347 \$1348 \$1349 \$1350 \$1351 \$1352 \$1353 \$1354 \$1355 \$1356 \$1357 \$1358 \$1359 \$1360 \$1361 \$1362 \$1363 \$1364 \$1365 \$1366 \$1367 \$1368 \$1369 \$1370 \$1371 \$1372 \$1373 \$1374 \$1375 \$1376 \$1377 \$1378 \$1379 \$1380 \$1381 \$1382 \$1383 \$1384 \$1385 \$1386 \$1387 \$1388 \$1389 \$1390 \$1391 \$1392 \$1393 \$1394 \$1395 \$1396 \$1397 \$1398 \$1399 \$1400 \$1401 \$1402 \$1403 \$1404 \$1405 \$1406 \$1407 \$1408 \$1409 \$1410 \$1411 \$1412 \$1413 \$1414 \$1415 \$1416 \$1417 \$1418 \$1419 \$1420 \$1421 \$1422 \$1423 \$1424 \$1425 \$1426 \$1427 \$1428 \$1429 \$1430 \$1431 \$1432 \$1433 \$1434 \$1435 \$1436 \$1437 \$1438 \$1439 \$1440 \$1441 \$1442 \$1443 \$1444 \$1445 \$1446 \$1447 \$1448 \$1449 \$1450 \$1451 \$1452 \$1453 \$1454 \$1455 \$1456 \$1457 \$1458 \$1459 \$1460 \$1461 \$1462 \$1463 \$1464 \$1465 \$1466 \$1467 \$1468 \$1469 \$1470 \$1471 \$1472 \$1473 \$1474 \$1475 \$1476 \$1477 \$1478 \$1479 \$1480 \$1481 \$1482 \$1483 \$1484 \$1485 \$1486 \$1487 \$1488 \$1489 \$1490 \$1491 \$1492 \$1493 \$1494 \$1495 \$1496 \$1497 \$1498 \$1499 \$1500 \$1501 \$1502 \$1503 \$1504 \$1505 \$1506 \$1507 \$1508 \$1509 \$1510 \$1511 \$1512 \$1513 \$1514 \$1515 \$1516 \$1517 \$1518 \$1519 \$1520 \$1521 \$1522 \$1523 \$1524 \$1525 \$1526 \$1527 \$1528 \$1529 \$1530 \$1531 \$1532 \$1533 \$1534 \$1535 \$1536 ; #X connect 0 0 3 0; #X connect 3 0 1 0; #X restore 108 102 pd build-data-message; #X msg 108 144 0 0.811273 0.133448 1 1.03295 0.172079 2 0.821924 0.11946 3 1.00776 0.130692 4 0.874902 0.0628796 5 1.01345 0.0689764 6 0.731454 0.149406 7 1.03117 0.0957904 8 0.879144 0.069267 9 0.688699 0.153605 10 1.0624 0.141749 11 0.812128 0.0809692 12 1.08212 0.130115 13 1.08354 0.171721 14 0.634683 0.126787 15 1.03027 0.0968671 16 0.812051 0.19859 17 0.716638 0.180885 18 0.619882 0.133192 19 0.796304 0.062948 20 0.612436 0.0608588 21 0.645761 0.0824902 22 0.797922 0.0820758 23 0.722162 0.153956 24 0.929727 0.145048 25 0.928857 0.106219 26 0.808862 0.192198 27 0.998712 0.172229 28 0.888025 0.0833575 29 0.990305 0.10619 30 0.615442 0.109142 31 0.830667 0.168879 32 0.941126 0.113829 33 0.619409 0.130756 34 0.883905 0.152213 35 0.895151 0.141091 36 0.832056 0.076684 37 0.954431 0.0740009 38 1.04089 0.0676904 39 0.834543 0.140186 40 0.674692 0.129278 41 0.671594 0.0735822 42 0.927133 0.165325 43 0.880426 0.161031 44 0.766229 0.063999 45 1.05891 0.13772 46 1.09799 0.148713 47 0.796686 0.103024 48 0.807336 0.0718646 49 0.961206 0.164513 50 0.901468 0.0908856 51 1.02354 0.082298 52 0.607126 0.11062 53 1.04008 0.193245 54 0.645517 0.135507 55 0.61329 0.0653406 56 0.702982 0.0831012 57 0.609232 0.160245 58 1.00038 0.153328 59 0.724054 0.103237 60 0.744089 0.19081 61 0.931482 0.0691644 62 1.0669 0.124514 63 0.875284 0.0962476 64 0.92898 0.173579 65 0.899835 0.0856006 66 1.01534 0.136105 67 0.839761 0.173032 68 0.775385 0.165517 69 0.804651 0.171486 70 0.765955 0.10331 71 0.874765 0.112124 72 0.745248 0.163953 73 0.844308 0.172742 74 0.763513 0.0805463 75 0.773859 0.145633 76 0.686258 0.160219 77 0.967905 0.118003 78 0.982599 0.162014 79 1.04646 0.0737018 80 0.937097 0.106754 81 0.743646 0.168243 82 0.608682 0.062431 83 0.617349 0.0662506 84 0.832925 0.13264 85 1.03452 0.128291 86 0.705621 0.15757 87 0.991495 0.115636 88 0.644708 0.0834644 89 0.73269 0.0616876 90 0.848505 0.15173 91 0.912973 0.106536 92 0.896204 0.151332 93 0.901682 0.15114 94 1.05502 0.139634 95 1.07443 0.0984778 96 0.940607 0.142288 97 0.697916 0.0728943 98 0.841913 0.088429 99 0.609232 0.112944 100 0.933801 0.122203 101 0.929407 0.143535 102 0.943018 0.140596 103 0.882791 0.168187 104 0.615167 0.0924322 105 1.01792 0.177065 106 0.790994 0.0650885 107 0.815988 0.0689465 108 0.75976 0.13267 109 0.80932 0.0899713 110 0.898462 0.0703607 111 0.908701 0.191122 112 0.990198 0.100943 113 0.82168 0.137114 114 1.02731 0.178458 115 0.979318 0.0703479 116 0.802423 0.15587 117 0.79693 0.0905011 118 1.04444 0.164487 119 0.941248 0.0786877 120 1.05564 0.137366 121 0.701166 0.174771 122 0.896249 0.140168 123 0.91604 0.112009 124 1.03619 0.159574 125 0.82464 0.0919153 126 0.625543 0.173823 127 0.626779 0.127501 128 0.92309 0.194019 129 1.0149 0.0608246 130 0.910883 0.0879761 131 0.857263 0.179864 132 1.05457 0.0812299 133 0.703546 0.151768 134 0.651727 0.17519 135 0.605463 0.197825 136 0.647668 0.0917828 137 0.925043 0.188323 138 0.672113 0.145172 139 0.809854 0.10155 140 0.652673 0.0780383 141 1.02778 0.136977 142 0.845758 0.117153 143 0.761346 0.0924963 144 0.951776 0.122668 145 0.653009 0.171554 146 0.746072 0.124954 147 0.641443 0.0765729 148 0.756372 0.152841 149 0.918771 0.149752 150 0.838434 0.15907 151 0.961801 0.113786 152 1.008 0.12683 153 0.688562 0.0705188 154 0.761911 0.0858099 155 1.09469 0.183658 156 0.953699 0.0957776 157 0.96377 0.13094 158 1.03291 0.159681 159 0.667047 0.0850067 160 1.01756 0.121848 161 0.721765 0.111329 162 0.734338 0.119985 163 0.666483 0.124531 164 1.01177 0.0652594 165 0.897348 0.164534 166 0.84408 0.175698 167 1.096 0.153217 168 0.916727 0.0815033 169 0.854028 0.131846 170 0.658899 0.114747 171 0.693857 0.129889 172 0.691644 0.153798 173 0.883005 0.161292 174 0.78811 0.116696 175 0.859583 0.103195 176 0.646722 0.193147 177 0.616144 0.164517 178 1.08811 0.112192 179 0.950266 0.066037 180 0.672067 0.18077 181 1.01464 0.180714 182 0.689935 0.162347 183 0.87121 0.188584 184 0.969782 0.199248 185 0.679803 0.188704 186 0.99418 0.0970337 187 0.661264 0.108565 188 0.85708 0.132205 189 0.890482 0.149072 190 0.817331 0.117811 191 0.998438 0.136746 192 0.778238 0.119669 193 0.812326 0.162595 194 0.791437 0.160035 195 0.692407 0.13088 196 0.808923 0.151623 197 0.62594 0.145466 198 0.775644 0.163825 199 0.824869 0.109629 200 0.993951 0.197526 201 0.795862 0.0702753 202 0.632745 0.159134 203 0.955484 0.0976148 204 0.769083 0.0691132 205 0.956491 0.133145 206 0.649866 0.0953033 207 0.758646 0.123027 208 1.08096 0.120592 209 0.77334 0.126676 210 1.09577 0.15496 211 0.750879 0.0655414 212 0.645975 0.111406 213 1.02621 0.106279 214 1.03599 0.198112 215 0.915094 0.137797 216 0.885446 0.183282 217 0.801584 0.114299 218 0.6811 0.140271 219 0.767069 0.0607349 220 0.669809 0.130914 221 0.940775 0.1172 222 0.65896 0.199863 223 0.743295 0.161432 224 1.09365 0.109911 225 1.00067 0.0749707 226 0.684305 0.104955 227 0.618448 0.176813 228 0.884027 0.158245 229 0.828729 0.1396 230 1.05799 0.107224 231 0.805322 0.145565 232 0.64248 0.129782 233 0.808221 0.162928 234 0.731271 0.179471 235 1.01447 0.184329 236 0.744089 0.197172 237 0.850443 0.192715 238 0.993097 0.194125 239 1.08218 0.184431 240 0.606866 0.0748383 241 1.09509 0.125155 242 0.692972 0.0724072 243 0.692758 0.192237 244 0.631235 0.0783203 245 0.690363 0.145364 246 1.02102 0.195792 247 0.710748 0.0961194 248 0.688715 0.102387 249 0.698145 0.178719 250 0.769296 0.158745 251 0.678629 0.125164 252 0.640756 0.0850708 253 0.716028 0.177809 254 0.767877 0.0752869 255 0.777399 0.118144 256 0.78573 0.110906 257 0.676386 0.11649 258 1.07725 0.190908 259 0.764215 0.159578 260 0.663019 0.160091 261 0.976373 0.110018 262 0.858133 0.165914 263 0.695062 0.0720099 264 0.813852 0.178851 265 1.05935 0.0989648 266 1.01991 0.0692798 267 1.04078 0.126086 268 0.835489 0.1771 269 0.700937 0.0997852 270 1.05998 0.0951025 271 0.946512 0.109355 272 1.07519 0.0939319 273 0.725549 0.165594 274 0.711328 0.170127 275 0.917108 0.0787988 276 0.851862 0.172955 277 0.841745 0.116666 278 0.634805 0.0769019 279 0.734338 0.130748 280 0.615488 0.145278 281 1.04308 0.176993 282 0.628687 0.119225 283 0.738474 0.0995801 284 0.617441 0.177228 285 0.897623 0.0978027 286 0.858347 0.147308 287 0.855264 0.147222 288 1.07777 0.114196 289 0.667413 0.153174 290 0.866983 0.181235 291 0.790445 0.163876 292 0.620355 0.179966 293 0.909433 0.0668573 294 0.813593 0.153191 295 1.09135 0.176454 296 0.912027 0.116508 297 1.01838 0.172242 298 1.06169 0.170477 299 0.712762 0.079649 300 0.950082 0.0600299 301 0.645563 0.0698437 302 0.996973 0.0657806 303 0.700418 0.12445 304 0.883966 0.102272 305 0.916086 0.0672888 306 0.739221 0.0704504 307 1.0353 0.18837 308 0.762628 0.0996313 309 1.02151 0.171362 310 1.07212 0.0805249 311 1.07121 0.112773 312 0.811151 0.136631 313 1.07762 0.147671 314 1.05247 0.0920136 315 0.82966 0.0983154 316 0.684595 0.192557 317 0.979639 0.15807 318 0.687296 0.153097 319 0.951303 0.119951 320 0.997141 0.0941626 321 0.953958 0.156331 322 0.823969 0.0691644 323 1.0366 0.113679 324 0.615137 0.127441 325 1.03243 0.148231 326 0.673151 0.142839 327 0.72883 0.0611749 328 1.04545 0.132798 329 0.925668 0.134131 330 0.812738 0.13044 331 0.613535 0.164607 332 0.814645 0.0871985 333 0.86738 0.100665 334 0.690241 0.101554 335 0.886682 0.162261 336 0.606317 0.161932 337 0.939096 0.0647211 338 0.949991 0.0892749 339 1.08238 0.162539 340 0.9284 0.195873 341 0.626993 0.16312 342 0.858514 0.167841 343 0.684686 0.129799 344 0.64509 0.1369 345 0.625925 0.0780341 346 0.897272 0.116183 347 0.933191 0.193356 348 0.62124 0.143817 349 0.667261 0.161749 350 0.701501 0.117037 351 1.04518 0.177258 352 0.826547 0.0962048 353 0.723444 0.128556 354 1.04618 0.0984436 355 0.628549 0.08396 356 1.09777 0.185756 357 0.809717 0.126364 358 0.829675 0.0857373 359 0.810342 0.0656396 360 0.963037 0.0928851 361 0.875818 0.0705829 362 0.812296 0.16676 363 0.73472 0.145142 364 1.0807 0.106617 365 0.713342 0.178014 366 0.695428 0.186046 367 0.710138 0.0836823 368 0.710535 0.0982513 369 1.09278 0.0996655 370 0.951395 0.108339 371 1.08116 0.0943207 372 0.913065 0.0969867 373 0.80755 0.119584 374 1.07141 0.0965936 375 1.00738 0.129265 376 1.05799 0.132824 377 0.721216 0.187875 378 0.874338 0.14794 379 1.06222 0.140634 380 0.659647 0.0894629 381 0.832208 0.115115 382 0.870752 0.185884 383 0.714914 0.124147 384 1.05512 0.0802386 385 1.0044 0.0740009 386 1.02761 0.103571 387 0.714761 0.187281 388 1.00579 0.136541 389 0.977213 0.0675922 390 1.0502 0.164761 391 1.08471 0.166282 392 0.803339 0.13722 393 0.697168 0.152285 394 0.948602 0.182329 395 0.746729 0.166521 396 0.848932 0.0941284 397 1.03938 0.137708 398 0.707651 0.0616577 399 0.895074 0.0960681 400 0.936441 0.0622772 401 0.675653 0.132 402 0.855219 0.19959 403 0.737741 0.0772095 404 0.756235 0.12915 405 0.603128 0.134473 406 0.766519 0.152729 407 0.848077 0.11153 408 0.75361 0.138891 409 0.850275 0.0794482 410 0.665262 0.0658533 411 0.651254 0.069613 412 0.658441 0.101101 413 0.941446 0.117849 414 0.935587 0.180197 415 1.03111 0.19924 416 0.899942 0.076748 417 0.772577 0.162667 418 0.624719 0.143309 419 1.07156 0.150341 420 0.642816 0.127189 421 0.895471 0.0828577 422 0.624002 0.134102 423 1.03179 0.0641229 424 0.802591 0.0916504 425 0.647623 0.171221 426 1.0657 0.0969653 427 0.757211 0.156536 428 0.967676 0.139998 429 0.638864 0.0828705 430 0.918726 0.150247 431 1.01762 0.0903174 432 0.738962 0.0641058 433 0.766443 0.0750391 434 1.068 0.180048 435 0.998743 0.0775385 436 0.921579 0.172784 437 1.07902 0.174297 438 1.00828 0.174352 439 0.8034 0.120447 440 0.847543 0.080072 441 0.661935 0.0734113 442 0.650613 0.0693866 443 0.997217 0.189866 444 0.864526 0.132277 445 0.642603 0.10642 446 0.795023 0.196253 447 1.04571 0.127885 448 0.737161 0.191733 449 0.625223 0.150909 450 0.674097 0.0821613 451 0.691095 0.134661 452 0.875482 0.115956 453 0.882761 0.196578 454 0.95997 0.133427 455 0.766214 0.0671606 456 0.913644 0.154302 457 0.690866 0.1066 458 0.884103 0.115247 459 1.03156 0.172353 460 1.03489 0.116085 461 0.909494 0.101131 462 0.851938 0.0845966 463 1.03855 0.0773676 464 0.959146 0.0923126 465 0.778009 0.107031 466 0.62298 0.123232 467 1.07542 0.108727 468 0.976938 0.0818878 469 0.824716 0.196791 470 0.949381 0.0870489 471 0.743646 0.116033 472 1.06335 0.0766882 473 0.684717 0.139698 474 0.989099 0.0684979 475 0.803629 0.153503 476 0.651407 0.0819476 477 0.670419 0.174878 478 0.638773 0.136319 479 0.908823 0.132358 480 1.02407 0.165978 481 0.70437 0.0834686 482 0.960413 0.174758 483 0.682352 0.0728601 484 0.688242 0.100661 485 0.815485 0.120015 486 0.764078 0.0830115 487 0.90954 0.160651 488 0.709116 0.085921 489 1.0175 0.0696387 490 0.998651 0.0771625 491 0.745737 0.149679 492 0.655511 0.0635803 493 0.751855 0.0845068 494 0.96795 0.138186 495 0.964532 0.10877 496 0.869287 0.186922 497 1.08103 0.0925092 498 1.05313 0.0754449 499 0.983743 0.126326 500 0.722177 0.170913 501 0.762186 0.130602 502 0.956796 0.190434 503 0.789529 0.150213 504 0.768335 0.0807428 505 1.04112 0.126898 506 1.0481 0.099422 507 1.00018 0.177894 508 0.985529 0.15334 509 0.933511 0.173938 510 0.971582 0.132726 511 0.976907 0.0898645 ; #X text 107 22 using this subpatch \, the current set of internal parameters can be captured for later reuse \; send the message "dump" to bthresher~ to capture these parameters; #X connect 0 0 1 0; #X connect 1 0 2 0; #X restore 256 577 pd capture-current-thresher-state; #X obj 276 26 cnv 15 100 30 empty empty fftease/bthresher~ 20 12 0 24 -262144 -1 0; #X obj 325 189 cnv 15 100 20 empty empty fftease/thresher~ 20 12 0 14 -262144 -1 0; #X connect 0 0 16 2; #X connect 1 0 0 0; #X connect 2 0 16 1; #X connect 3 0 2 0; #X connect 9 0 16 0; #X connect 14 0 16 0; #X connect 16 0 4 0; #X connect 16 1 22 0; pd-fftease-3.0.1/fftease-helpfiles/burrow~-help.pd000077500000000000000000000057271401707710000221230ustar00rootroot00000000000000#N canvas 451 35 796 659 12; #X msg 223 385 invert \$1; #X obj 223 358 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X obj 329 382 noise~; #X floatatom 381 382 5 0 0 0 - - -; #X text 204 308 source sound; #X msg 170 431 mute \$1; #X obj 119 31 ./icon; #X obj 298 598 ./gain.dsp~; #X text 436 63 - Cross filtering; #X obj 441 415 expr pow(10 \, $f1/20); #X obj 449 499 expr pow(10 \, $f1/20); #X obj 170 404 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X obj 298 560 fftease/burrow~ 2048 4; #X obj 348 420 bp~ 600 30; #X obj 298 308 noise~; #X msg 103 448 fftinfo; #X obj 384 356 hsl 128 15 100 1000 0 0 empty \$0-freq empty -2 -8 0 10 -228856 -1 -1 7056 1; #X text 414 355 frequency; #X text 598 407 below (if inverted); #X text 115 91 [burrow~] filters the sound in the left input by utilizing a second signal input as a filter threshold reference. When the bins of second signal are above the threshold \, the same bins of the first signal are affected by the multiplier (so you can attenuate or boost them). Threshold inversion is available via the invert message. This way \, [burrow~] acts when the bins of the second sound are below the threshold., f 81; #X obj 441 393 nbx 5 14 -1e+037 1e+037 0 0 \$0-dummy \$0-threshold empty 0 -8 0 10 -228856 -1 -1 -45 256; #X obj 449 479 nbx 5 14 -1e+037 1e+037 0 0 \$0-dummy \$0-multiplier empty 0 -8 0 10 -228856 -1 -1 -35 256; #X floatatom 449 522 7 0 0 0 - - -; #X text 500 390 <= threshold (dB) - acts above or; #X text 510 476 <= multiplier factor (dB); #X floatatom 441 439 7 0 0 0 - - -; #X text 494 439 (linear); #X text 506 522 (linear); #X text 115 185 Here we have a noise input and a bandpass filtered noise as the filtering sound. With the initial settings (in dB) \, the input signal gets attenuated when the bins of the second input are above the threshold. This acts sort of like a notch filter. With the invert message on \, it's more like a bandpass. But if you have a positive dB multiplier \, it boosts the bins above the threshold (sort of like a peak filter) or boosts the bins below the threshold if inverted., f 81; #X text 65 432 Get FFT info, f 7; #X text 51 386 turn off the object \, saving CPU power, f 20; #X text 70 357 set to invert mode =>; #X text 461 559 <= arguments: window size and; #X text 482 574 overlap (default: 1024 \, 8); #X text 325 345 filter sound, f 6; #N canvas 650 70 277 215 init 0; #X msg 72 96 \; \$1-freq 600 \; \$1-threshold -45 \; \$1-multiplier -35; #X obj 72 69 f \$0; #X obj 72 41 loadbang; #X connect 1 0 0 0; #X connect 2 0 1 0; #X restore 225 583 pd init; #X obj 419 35 cnv 15 100 30 empty empty fftease/burrow~ 20 12 0 24 -262144 -1 0; #X connect 0 0 12 0; #X connect 1 0 0 0; #X connect 2 0 13 0; #X connect 3 0 13 1; #X connect 5 0 12 0; #X connect 9 0 25 0; #X connect 10 0 22 0; #X connect 11 0 5 0; #X connect 12 0 7 0; #X connect 13 0 12 1; #X connect 14 0 12 0; #X connect 15 0 12 0; #X connect 16 0 3 0; #X connect 20 0 9 0; #X connect 21 0 10 0; #X connect 22 0 12 3; #X connect 25 0 12 2; pd-fftease-3.0.1/fftease-helpfiles/cavoc27~-help.pd000077500000000000000000000120751401707710000220410ustar00rootroot00000000000000#N canvas 600 60 639 452 12; #N canvas 25 82 621 482 rules 0; #X msg 34 61 rule 1 0 1 0 0 0 1 0 0 1 2 1 0 2 0 2 0 0 1 0 2 0 2 1 2 1 1; #X msg 56 88 rule 0 2 1 0 0 1 0 0 0 1 1 2 0 1 2 1 1 1 1 0 0 0 1 1 0 1 1; #X msg 78 116 rule 2 2 0 1 0 2 1 1 0 2 1 2 0 1 1 2 0 2 2 1 2 1 1 2 0 0 0; #X obj 34 186 outlet; #X msg 118 148 rule 2 1 0 1 0 2 1 1 0 1 0 1 0 1 1 2 0 0 0 0 0 0 1 2 0 0 1; #X text 31 28 Here are a few rules to start. Try making up your own! ; #X text 29 216 a rule is the initial state for the automaton \, with 27 elements \, each of which can be either 0 \, 1 \, or 2 Each time the automaton is triggered (either internally or externally) \, each value of the rule receives a new value \, determined by the values of each cell (of which there are 27) \, and those of its neighboring cells. As in the Game of Life \, on each iteration \, the value of each cell may change \, and large-scale patterns emerge. The resulting new rule is copied as necessary to generate gain values for each FFT bin (either 0 \, 1 \, or 2).; #X connect 0 0 3 0; #X connect 1 0 3 0; #X connect 2 0 3 0; #X connect 4 0 3 0; #X restore 168 253 pd rules; #N canvas 730 31 527 400 triggering 0; #X msg 87 140 trigger; #X msg 119 206 manual \$1; #X obj 87 84 metro 250; #X obj 87 52 tgl 17 0 \$0-dummy \$0-metro-tog empty 17 7 0 10 -228856 -1 -1 1 1; #X floatatom 147 53 5 0 0 0 - - -; #X obj 119 174 tgl 17 0 \$0-dummy \$0-triggertog empty 17 7 0 10 -228856 -1 -1 0 1; #X obj 87 247 outlet; #X obj 87 111 bng 18 250 50 0 empty empty empty 17 7 0 10 -228856 -1 -1; #X text 86 27 turn on to repeatedly send external triggers; #X text 143 179 turn off internal clock to receive external triggers ; #X connect 0 0 6 0; #X connect 1 0 6 0; #X connect 2 0 7 0; #X connect 3 0 2 0; #X connect 4 0 2 1; #X connect 5 0 1 0; #X connect 7 0 0 0; #X restore 157 225 pd triggering; #N canvas 467 193 247 190 init 0; #X obj 62 69 f \$0; #X obj 62 41 loadbang; #X msg 62 94 \; \$1-metro-tog 1 \; \$1-infreq 133 \; \$1-holdtime 250 ; #X connect 0 0 2 0; #X connect 1 0 0 0; #X restore 217 331 pd init; #N canvas 264 104 957 558 more-msgs 0; #X msg 34 140 density \$1; #X floatatom 34 106 5 0 0 0 - - -; #X msg 154 162 oscbank \$1; #X obj 258 162 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X msg 258 199 interpolate \$1; #X msg 587 352 transpose \$1; #X floatatom 587 323 5 0 0 0 - - -; #X obj 590 298 hsl 128 15 0.5 2 0 0 empty empty empty -2 -8 0 10 -228856 -1 -1 0 1; #X msg 353 364 retune 0.5 2; #X msg 528 447 freeze \$1; #X msg 281 300 hold_time \$1; #X floatatom 281 273 5 0 0 0 - #0-holdtime -; #X obj 79 516 outlet; #X obj 154 133 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X obj 528 419 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X text 286 165 ramp interpolation from one spectrum to the next; #X text 553 416 freeze current spectrum; #X text 585 254 transposition (most effective with oscbank turned on) ; #X text 280 251 time interval for internal clock; #X text 347 343 reset phases or frequencies; #X text 178 135 use oscillator bank resynthesis; #X text 31 33 randomly repopulate current amplitude spectrum \; the argument is odds of either a 1 or 2 amplitude value \, otherwise zero \; lower values create sparser spectra; #X connect 0 0 12 0; #X connect 1 0 0 0; #X connect 2 0 12 0; #X connect 3 0 4 0; #X connect 4 0 12 0; #X connect 5 0 12 0; #X connect 6 0 5 0; #X connect 7 0 6 0; #X connect 8 0 12 0; #X connect 9 0 12 0; #X connect 10 0 12 0; #X connect 11 0 10 0; #X connect 13 0 2 0; #X connect 14 0 9 0; #X restore 180 284 pd more-msgs; #X msg 146 195 capture_spectrum \$1; #X obj 146 167 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #N canvas 722 391 582 329 input 0; #X obj 42 104 phasor~; #X obj 42 137 -~ 0.5; #X obj 95 104 phasor~; #X obj 95 137 -~ 0.5; #X obj 150 104 phasor~; #X obj 150 137 -~ 0.5; #X obj 95 231 outlet~; #X obj 95 71 * 1.25; #X obj 150 71 * 1.5; #X obj 95 26 inlet; #X obj 95 190 *~ 0.333; #X text 147 21 external spectral source \, when capture_spectrum is turned on; #X text 218 118 a bank of three non-bandlimited sawtooths \, tuned to a just major triad; #X connect 0 0 1 0; #X connect 1 0 10 0; #X connect 2 0 3 0; #X connect 3 0 10 0; #X connect 4 0 5 0; #X connect 5 0 10 0; #X connect 7 0 2 0; #X connect 8 0 4 0; #X connect 9 0 0 0; #X connect 9 0 7 0; #X connect 9 0 8 0; #X connect 10 0 6 0; #X restore 68 195 pd input; #X text 43 166 hz; #X obj 68 343 fftease/cavoc27~; #X obj 68 378 ./gain.dsp~; #X obj 44 23 ./icon; #X text 315 56 - Cellular Automata-generated spectra; #X text 42 107 [cavoc27~] generates spectra with a 27 rule cellular automaton. Start with very low gain.; #X obj 68 166 nbx 5 14 -1e+037 1e+037 0 0 \$0-dummy \$0-infreq empty 0 -8 0 10 -228856 -1 -1 133 256; #X text 168 160 turn on to capture input spectra as tuning source; #X obj 317 25 cnv 15 100 30 empty empty fftease/cavoc27~ 20 12 0 24 -262144 -1 0; #X text 388 256 see also:; #X obj 368 273 cnv 15 100 20 empty empty fftease/cavoc~ 20 12 0 14 -262144 -1 0; #X connect 0 0 8 0; #X connect 1 0 8 0; #X connect 3 0 8 0; #X connect 4 0 8 0; #X connect 5 0 4 0; #X connect 6 0 8 0; #X connect 8 0 9 0; #X connect 13 0 6 0; pd-fftease-3.0.1/fftease-helpfiles/cavoc~-help.pd000077500000000000000000000070031401707710000216630ustar00rootroot00000000000000#N canvas 600 60 689 351 12; #N canvas 162 45 900 665 more-messages 0; #X msg 431 484 retune 0.5 1.5; #X msg 253 313 bottomfreq \$1; #X msg 399 313 topfreq \$1; #X floatatom 399 288 8 500 8000 0 - - -; #X floatatom 253 288 8 0 400 0 - - -; #X msg 106 317 mute \$1; #X obj 106 287 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X msg 109 68 external_trigger \$1; #X msg 408 367 hold_time \$1; #X floatatom 408 342 5 10 1000 0 - - -; #X floatatom 222 212 5 0.01 0.25 0 - - -; #X msg 222 234 density \$1; #X msg 420 424 oscbank \$1; #X obj 420 397 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X obj 225 190 hsl 128 15 0.01 0.5 1 0 empty empty empty -2 -8 0 10 -228856 -1 -1 0 1; #X obj 176 149 bng 18 250 50 0 empty empty empty 17 7 0 10 -228856 -1 -1; #X obj 109 38 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X msg 419 460 retune 0.95 1.05; #N canvas 754 288 275 142 random-metro 0; #X obj 62 17 inlet; #X obj 62 48 metro; #X obj 62 90 outlet; #X obj 115 58 expr random(20 \, 300); #X connect 0 0 1 0; #X connect 1 0 2 0; #X connect 1 0 3 0; #X connect 3 0 1 1; #X restore 176 120 pd random-metro; #X obj 176 96 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X text 204 145 trigger with bangs if external_trigger is on, f 22 ; #X obj 402 262 hsl 128 15 100 10000 1 0 empty empty empty -2 -8 0 10 -228856 -1 -1 0 1; #X obj 256 262 hsl 128 15 100 10000 1 0 empty empty empty -2 -8 0 10 -228856 -1 -1 0 1; #X obj 252 577 outlet; #X text 451 344 time interval (ms) for internal clock; #X text 132 37 turn off internal clock \, and trigger changes with "bang"; #X text 206 99 an example of an external clock; #X text 546 458 <= reset phase "tunings" with minimum and maximum transposition factors, f 46; #X text 357 189 density of spectral fill (bins initialized to be non-zero) ; #X text 547 262 control frequency range; #X connect 0 0 23 0; #X connect 1 0 23 0; #X connect 2 0 23 0; #X connect 3 0 2 0; #X connect 4 0 1 0; #X connect 5 0 23 0; #X connect 6 0 5 0; #X connect 7 0 23 0; #X connect 8 0 23 0; #X connect 9 0 8 0; #X connect 10 0 11 0; #X connect 11 0 23 0; #X connect 12 0 23 0; #X connect 13 0 12 0; #X connect 14 0 10 0; #X connect 15 0 23 0; #X connect 16 0 7 0; #X connect 17 0 23 0; #X connect 18 0 15 0; #X connect 19 0 18 0; #X connect 21 0 3 0; #X connect 22 0 4 0; #X restore 88 195 pd more-messages; #N canvas 279 285 419 376 rules 0; #X msg 74 65 rule 0 1 0 1 0 0 1 1; #X msg 57 41 rule 0 1 1 0 1 0 0 1; #X msg 87 88 rule 0 0 0 0 1 1 1 1; #X msg 102 112 rule 0 0 0 1 1 0 0 0; #X msg 114 136 rule 1 0 0 1 1 0 0 1; #X msg 127 160 rule 1 1 0 1 0 1 0 0; #X msg 141 187 rule 1 1 0 1 0 1 1 0; #X msg 154 213 rule 1 1 0 0 1 1 0 0; #X msg 167 242 rule 0 0 1 0 1 0 1 1; #X obj 74 306 outlet; #X connect 0 0 9 0; #X connect 1 0 9 0; #X connect 2 0 9 0; #X connect 3 0 9 0; #X connect 4 0 9 0; #X connect 5 0 9 0; #X connect 6 0 9 0; #X connect 7 0 9 0; #X connect 8 0 9 0; #X restore 68 160 pd rules; #X obj 61 19 ./icon; #X obj 68 285 ./gain.dsp~; #X text 54 92 [cavoc~] generates spectra with an 8 rule cellular automaton. Start with very low gain.; #X text 337 48 - Cellular Automata-generated spectra; #X obj 68 235 fftease/cavoc~ 2048 4 0.2 250; #X text 282 232 <= arguments: window size \, overlap \, density; #X text 304 247 and hold time (default: 1024 \, 8 \, 0.1 \, 500); #X obj 325 20 cnv 15 100 30 empty empty fftease/cavoc~ 20 12 0 24 -262144 -1 0; #X text 425 143 see also:; #X obj 405 161 cnv 15 100 20 empty empty fftease/cavoc27~ 20 12 0 14 -262144 -1 0; #X connect 0 0 6 0; #X connect 1 0 6 0; #X connect 6 0 3 0; pd-fftease-3.0.1/fftease-helpfiles/centerring~-help.pd000077500000000000000000000037411401707710000227350ustar00rootroot00000000000000#N canvas 600 60 624 591 12; #X floatatom 170 334 5 0 0 0 - freq -; #X floatatom 214 403 5 0 0 0 - centerring-basefreq -; #X floatatom 256 429 5 0 0 0 - centerring-freqbandw -; #X floatatom 300 456 5 0 0 0 - centerring-freqconst -; #X msg 79 260 zerophases; #X msg 122 299 randphases; #N canvas 804 464 450 300 init 0; #X msg 132 216 \; centerring-basefreq \$1 \; centerring-freqbandw \$2 \; centerring-freqconst \$3 \;; #X msg 81 167 300 0.2 1; #X msg 164 168 1.1 10 7; #X msg 249 169 1 1 1; #X text 82 146 a few other settings; #X msg 60 66 \; centerring-basefreq 1 \; centerring-freqbandw 0.15 \; centerring-freqconst 1 \; freq 67; #X obj 60 36 loadbang; #X connect 1 0 0 0; #X connect 2 0 0 0; #X connect 3 0 0 0; #X connect 6 0 5 0; #X restore 86 490 pd init; #X obj 170 481 fftease/centerring~; #X obj 170 520 ./gain.dsp~; #X text 53 141 [centerring~] performs frequency independent amplitude modulation upon the spectral magnitudes of input signals. The effect is somewhat akin to flanging. The base frequency is used to derive the frequency of an oscillator associated with each frequency band. The frequency bandwidth and constant control the deviation of a particular frequency band's modulation oscillator frequency., f 65; #X obj 63 31 ./icon; #X text 259 69 - Frequency independent amplitude modulation; #N canvas 416 120 336 327 sawtooth 0; #X obj 134 136 -~ 0.5; #X obj 134 173 *~ 2; #X obj 134 63 inlet; #X obj 134 217 outlet~; #X obj 134 101 phasor~; #X connect 0 0 1 0; #X connect 1 0 3 0; #X connect 2 0 4 0; #X connect 4 0 0 0; #X restore 170 364 pd sawtooth; #X text 164 260 zero oscillator phases; #X text 205 299 randomize oscillator phases; #X text 255 403 base frequency; #X text 297 430 frequency bandwidth; #X text 341 456 frequency constant; #X obj 246 34 cnv 15 100 30 empty empty fftease/centerring~ 20 12 0 24 -262144 -1 0; #X connect 0 0 12 0; #X connect 1 0 7 1; #X connect 2 0 7 2; #X connect 3 0 7 3; #X connect 4 0 7 0; #X connect 5 0 7 0; #X connect 7 0 8 0; #X connect 12 0 7 0; pd-fftease-3.0.1/fftease-helpfiles/codepend~-help.pd000077500000000000000000000042711401707710000223550ustar00rootroot00000000000000#N canvas 600 60 722 703 12; #X floatatom 317 448 5 0 0 0 - codepend-scalingexp -; #X floatatom 372 550 5 0 0 0 - - -; #X floatatom 372 499 5 -120 0 1 inverse-threshold - -; #X text 361 442 scaling exponent (lower values increase distortion) , f 27; #N canvas 516 425 450 300 init 0; #X msg 124 172 \; codepend-scalingexp 0.2 \; codepend-invertscale -36 ; #X restore 110 601 pd init; #X msg 122 364 invert \$1; #X obj 122 339 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X msg 52 344 pad \$1; #X floatatom 52 321 5 0 0 0 - - -; #X floatatom 52 265 5 0 0 0 - codepend-invertscale -; #X obj 262 363 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X obj 207 632 ./gain.dsp~; #X obj 372 525 expr pow(10 \, $f1/20); #X obj 52 296 expr pow(10 \, $f1/20); #X obj 52 28 ./icon; #X text 310 63 - Block convolution; #X text 48 109 [codepend~] is a classic "block convolution" processor. It performs a complex multiply upon the spectra of two input signals. Multiplication of spectra can cause significant drops in the amplitude of the output signal., f 78; #X text 48 161 The invert message causes [codepend~] to perform complex division of the input spectra rather than multiplication. Be careful! This can cause huge amplitude gains. A "pad" message is provided to allow for empirical amplitude balancing between the normal and "invert" states. Experiment at low volume levels while getting a feel for this external., f 78; #X text 417 553 (lower values intensify effect but only when "invert" is turned on), f 34; #X text 209 264 pad only affects the gain when "invert" is turned on \, thus it may be used to balance levels between the two states of [codepend~]., f 27; #X obj 170 399 sfplay~; #X obj 262 399 sfplay~; #X text 284 363 play both; #X text 96 265 <==============; #X obj 207 596 fftease/codepend~ 1024 8; #X obj 292 32 cnv 15 100 30 empty empty fftease/codepend~ 20 12 0 24 -262144 -1 0; #X connect 0 0 24 2; #X connect 1 0 24 3; #X connect 2 0 12 0; #X connect 5 0 24 0; #X connect 6 0 5 0; #X connect 7 0 24 0; #X connect 8 0 7 0; #X connect 9 0 13 0; #X connect 10 0 20 0; #X connect 10 0 21 0; #X connect 12 0 1 0; #X connect 13 0 8 0; #X connect 20 0 24 0; #X connect 21 0 24 1; #X connect 24 0 11 0; pd-fftease-3.0.1/fftease-helpfiles/cross~-help.pd000077500000000000000000000023641401707710000217260ustar00rootroot00000000000000#N canvas 600 60 594 442 12; #X floatatom 312 263 5 0 0 0 - - -; #X msg 312 218 1e-06; #X msg 357 218 0.25; #X msg 399 218 0.05; #X obj 42 213 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 1 1; #X obj 233 168 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X obj 34 26 ./icon; #X text 276 60 - Block convolution; #X obj 154 384 ./gain.dsp~; #X obj 154 202 ./sfplay~; #X obj 233 203 ./sfplay~; #X text 254 170 play both; #X obj 154 345 fftease/cross~ 2048 8, f 23; #X msg 42 246 autonorm \$1; #X obj 42 183 loadbang; #X text 354 264 threshold of cross synthesis; #X obj 255 29 cnv 15 100 30 empty empty fftease/cross~ 20 12 0 24 -262144 -1 0; #X text 35 95 [cross~] uses a threshold to determine whether to perform spectral multiplication or maintain the last calculated magnitude/phase pair. An autonorm option attempts to keep overall frame amplitudes consistent.; #X msg 43 318 mute \$1; #X obj 43 282 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X connect 0 0 12 2; #X connect 1 0 0 0; #X connect 2 0 0 0; #X connect 3 0 0 0; #X connect 4 0 13 0; #X connect 5 0 9 0; #X connect 5 0 10 0; #X connect 9 0 12 0; #X connect 10 0 12 1; #X connect 12 0 8 0; #X connect 13 0 12 0; #X connect 14 0 4 0; #X connect 18 0 12 0; #X connect 19 0 18 0; pd-fftease-3.0.1/fftease-helpfiles/dentist~-help.pd000077500000000000000000000073441401707710000222520ustar00rootroot00000000000000#N canvas 600 60 667 431 12; #X obj 98 130 r fftz-dentist-msgs; #X obj 46 131 noise~; #N canvas 404 737 450 300 showsync 0; #X obj 205 102 inlet~; #X obj 205 159 snapshot~; #X obj 325 121 metro 50; #X obj 325 89 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1 1; #X obj 325 22 loadbang; #X msg 325 57 1; #X obj 205 225 outlet; #X connect 0 0 1 0; #X connect 1 0 6 0; #X connect 2 0 1 0; #X connect 3 0 2 0; #X connect 4 0 5 0; #X connect 5 0 3 0; #X restore 177 288 pd showsync; #X msg 142 225 scramble; #X obj 142 195 metro 7000; #X obj 142 161 tgl 15 0 empty dentist-scrambletog empty 17 7 0 10 -228856 -1 -1 1 1; #N canvas 434 141 629 376 interpolation-and-control 0; #X msg 54 100 ramptime \$1; #X floatatom 54 64 5 0 0 0 - dentist-ramptime -; #X obj 54 289 s fftz-dentist-msgs; #X msg 192 107 topfreq \$1; #X floatatom 192 71 5 0 0 0 - dentist-topfreq -; #X msg 281 168 toothcount \$1; #X floatatom 281 133 5 0 0 0 - dentist-toothcount -; #X text 235 73 highest allowable frequency (Hz) for a new scramble ; #X text 324 132 the number of spikes in the new filter; #X text 51 30 time (in ms) to interpolate from one configuration to the next; #X connect 0 0 2 0; #X connect 1 0 0 0; #X connect 3 0 2 0; #X connect 4 0 3 0; #X connect 5 0 2 0; #X connect 6 0 5 0; #X restore 419 223 pd interpolation-and-control; #N canvas 666 211 384 290 init 0; #X msg 118 125 \; dentist-ramptime 7000 \; dentist-topfreq 3000 \; dentist-toothcount 18 \; dentist-scrambletog 1 \;; #X obj 118 96 loadbang; #X connect 1 0 0 0; #X restore 421 277 pd init; #X floatatom 177 315 5 0 0 0 - - -; #N canvas 194 69 1077 634 data-storage 0; #X obj 57 311 s fftz-dentist-msgs; #X msg 116 144 setstate 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40; #X msg 58 51 setstate 10 11 12 13 14 50 51 52 53 43; #X msg 66 634 showstate; #X msg 131 209 setstate 55 6 37 13 64 26 24 30 11 0 22 25 60 17 53 8 34 12 5 14; #X msg 175 575 \; dentist-toothcount 20; #X obj 129 515 t b b b; #X msg 152 611 scramble; #X obj 152 670 s fftz-dentist-msgs; #X obj 129 468 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 -1; #X obj 604 68 inlet; #X msg 604 178 setstate 30 13 16 22 9 25 5 10 19 1 31 26 24 7 29 32 27 11 2 4; #X msg 604 100 set setstate \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8 \$9 \$10 \$11 \$12 \$13 \$14 \$15 \$16 \$17 \$18 \$19 \$20; #X msg 144 258 setstate 54 25 46 4 32 12 18 53 29 50 16 17 6 52 10 34 42 37 51 22; #X text 153 467 scramble \, and then store a new 20-bin filter; #X text 55 15 turn a group of bins on (all others will be turned off) using "setstate" followed by a list of bin numbers; #X msg 106 108 setstate 15 10 74; #X msg 94 74 setstate 27 31 40; #X text 625 143 display current internal bin state (this message can be used to restore the current state of the filter); #X text 655 61 change this message if you want more \, or fewer bins in the new filter (currently set for 20); #X connect 1 0 0 0; #X connect 2 0 0 0; #X connect 3 0 8 0; #X connect 4 0 0 0; #X connect 6 0 3 0; #X connect 6 1 7 0; #X connect 6 2 5 0; #X connect 7 0 8 0; #X connect 9 0 6 0; #X connect 10 0 12 0; #X connect 12 0 11 0; #X connect 13 0 0 0; #X connect 16 0 0 0; #X connect 17 0 0 0; #X restore 420 252 pd data-storage; #X obj 98 358 ./gain.dsp~; #X obj 38 20 ./icon; #X text 279 59 - Spiky filtering; #X text 40 84 [dentist~] punches out all but a select set of partials. , f 31; #X obj 98 258 fftease/dentist~ 1024 8; #X text 222 313 show interpolation progress; #X text 207 226 randomize filter; #X obj 255 28 cnv 15 100 30 empty empty fftease/dentist~ 20 12 0 24 -262144 -1 0; #X connect 0 0 14 0; #X connect 1 0 14 0; #X connect 2 0 8 0; #X connect 3 0 14 0; #X connect 4 0 3 0; #X connect 5 0 4 0; #X connect 14 0 10 0; #X connect 14 1 2 0; #X connect 14 2 9 0; pd-fftease-3.0.1/fftease-helpfiles/disarrain~-help.pd000077500000000000000000000075761401707710000225630ustar00rootroot00000000000000#N canvas 600 60 643 647 12; #X obj 167 328 phasor~ 261; #X obj 167 356 -~ 0.5; #X msg 303 255 fadetime \$1; #X floatatom 303 233 5 0 0 0 - disarrain-fadetime -; #X floatatom 363 348 5 0 0 0 - disarrain-switchct -; #N canvas 650 70 450 300 showsync 0; #X obj 205 102 inlet~; #X obj 205 159 snapshot~; #X obj 325 121 metro 50; #X obj 325 89 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1 1; #X obj 325 22 loadbang; #X msg 325 57 1; #X obj 205 225 outlet; #X connect 0 0 1 0; #X connect 1 0 6 0; #X connect 2 0 1 0; #X connect 3 0 2 0; #X connect 4 0 5 0; #X connect 5 0 3 0; #X restore 260 518 pd showsync; #X floatatom 260 544 5 0 0 0 - - -; #X msg 363 373 switch_count \$1; #X obj 76 400 metro 3000; #X obj 77 194 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 1 1; #N canvas 650 70 450 300 init 0; #X obj 32 29 loadbang; #X msg 32 56 \; disarrain-fadetime 3000 \; disarrain-switchct 70 \; disarrain-topfreq 2000; #X connect 0 0 1 0; #X restore 389 573 pd init; #N canvas 650 70 632 675 showbins 0; #X obj 42 48 inlet; #X msg 42 140 45 47 48 50 4 39 20 16 40 28 59 15 43 63 41 6 7 36 5 14; #X obj 42 71 list prepend set; #X obj 42 94 list trim; #X msg 42 292 setstate 40 27 39 13 8 5 41 14 34 31 10 0 9 18 17 37 21 38 6 30 26 4 42 1 24 22 7 43 28 32 19 20 29 23 15 36 33 25 2 35 11 3 16 12; #X msg 116 440 isetstate 45 47 48 50 4 39 20 16 40 28 59 15 43 63 41 6 7 36 5 14; #X msg 148 489 isetstate 40 27 39 13 8 5 41 14 34 31 10 0 9 18 17 37 21 38 6 30 26 4 42 1 24 22 7 43 28 32 19 20 29 23 15 36 33 25 2 35 11 3 16 12; #X msg 88 356 setstate 16 29 23 25 4 42 22 7 32 37 10 3 12 13 31 33 9 27 18 17 41 38 30; #X obj 60 612 s msg-disarrain; #X text 39 184 use the above data to craft the following messages \, in order to recall stored states; #X msg 266 42 showstate; #X text 263 20 dump current scramble to 3rd outlet; #X obj 266 71 s msg-disarrain; #X text 126 112 displays current scramble; #X text 39 265 instantly recall a scramble; #X text 102 407 recall a scramble with interpolation; #X connect 0 0 2 0; #X connect 2 0 3 0; #X connect 3 0 1 0; #X connect 4 0 8 0; #X connect 5 0 8 0; #X connect 6 0 8 0; #X connect 7 0 8 0; #X connect 10 0 12 0; #X restore 353 516 pd showbins; #X obj 77 223 t f b b; #X obj 123 249 s disarrain-switchct; #X obj 100 273 s disarrain-fadetime; #X floatatom 324 286 5 0 0 0 - disarrain-topfreq -; #X msg 324 314 topfreq \$1; #X obj 167 480 fftease/disarrain~, f 27; #X obj 167 585 ./gain.dsp~; #X obj 43 30 ./icon; #X text 49 110 [disarrain~] reorders a certain number of bins \, which can significantly transform the timbre. The spectral reordering is reported from the third outlet., f 43; #X text 407 346 number of bins to switch; #X obj 301 39 cnv 15 100 30 empty empty fftease/disarrain~ 20 12 0 24 -262144 -1 0; #X text 312 70 - Spectrum scrambler with interpolation; #X text 368 288 highest frequency (Hz) to scramble; #X text 344 231 interpolation time; #X obj 250 448 r msg-disarrain; #X text 442 516 <- pattern management; #N canvas 650 70 450 300 utilities 0; #X obj 39 123 s msg-disarrain; #X msg 39 59 fftinfo; #X msg 111 58 mute \$1; #X obj 111 27 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X obj 198 25 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X msg 198 56 bypass \$1; #X connect 1 0 0 0; #X connect 2 0 0 0; #X connect 3 0 2 0; #X connect 4 0 5 0; #X connect 5 0 0 0; #X restore 353 540 pd utilities; #X text 100 192 turn on for repeated spectral scrambles with interpolation ; #X text 442 117 see also:; #X obj 421 141 cnv 15 100 20 empty empty fftease/disarray~ 20 12 0 14 -262144 -1 0; #X connect 0 0 1 0; #X connect 1 0 17 0; #X connect 2 0 17 0; #X connect 3 0 2 0; #X connect 4 0 7 0; #X connect 5 0 6 0; #X connect 7 0 17 0; #X connect 8 0 17 0; #X connect 9 0 12 0; #X connect 12 0 8 0; #X connect 12 1 14 0; #X connect 12 2 13 0; #X connect 15 0 16 0; #X connect 16 0 17 0; #X connect 17 0 18 0; #X connect 17 1 5 0; #X connect 17 2 11 0; #X connect 26 0 17 0; pd-fftease-3.0.1/fftease-helpfiles/disarray~-help.pd000077500000000000000000000046231401707710000224130ustar00rootroot00000000000000#N canvas 600 60 876 544 12; #X obj 181 220 phasor~ 261; #X obj 181 247 -~ 0.5; #X msg 240 286 switch_count \$1; #X floatatom 240 253 5 0 0 0 - disarray-swcnt -; #X msg 146 184 topfreq \$1; #X floatatom 146 155 5 0 0 0 - disarray-topf -; #X msg 403 447 68 23 20 16 53 18 14 32 5 58 50 8 33 28 3 29 52 62 70 35 13 48 42 69 26 12 37 39 17 0; #X msg 255 323 showstate; #N canvas 650 70 450 300 init 0; #X msg 130 129 \; disarray-swcnt 30 \; disarray-topf 3000 \;; #X obj 167 74 loadbang; #X connect 1 0 0 0; #X restore 102 433 pd init; #X obj 182 412 fftease/disarray~, f 26; #X obj 403 397 list prepend set; #X obj 403 421 list trim; #X obj 125 298 bng 18 250 50 0 empty empty empty 17 7 0 10 -228856 -1 -1; #X text 47 77 [disarray~] reorders a certain number of bins \, which can significantly transform the timbre. The spectral reordering is reported from the second outlet.; #X text 282 253 number of bins to switch; #X obj 48 15 ./icon; #X text 454 49 - Spectrum scrambler; #X obj 182 451 ./gain.dsp~; #X text 60 279 force new scramble, f 10; #N canvas 650 70 450 300 utilities 0; #X msg 39 59 fftinfo; #X msg 111 58 mute \$1; #X obj 111 27 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X obj 39 122 s msg-disarray; #X connect 0 0 3 0; #X connect 1 0 3 0; #X connect 2 0 1 0; #X restore 86 457 pd utilities; #X obj 253 363 r msg-disarray; #X obj 435 19 cnv 15 100 30 empty empty fftease/disarray~ 20 12 0 24 -262144 -1 0; #X text 526 144 see also:; #X obj 505 168 cnv 15 100 20 empty empty fftease/disarrain~ 20 12 0 14 -262144 -1 0; #N canvas 650 70 620 269 mapping-presets 0; #X msg 48 56 setstate 68 23 20 16 53 18 14 32 5 58 50 8 33 28 3 29 52 62 70 35 13 48 42 69 26 12 37 39 17 0; #X msg 74 92 setstate 40 108 102 115 104 49 10 21 89 45 84 22 4 28 92 83 68 14 46 65 110 63 25 116 24 117 30 32 31 72; #X text 50 23 set a particular mapping; #X obj 48 150 s msg-disarray; #X connect 0 0 3 0; #X connect 1 0 3 0; #X restore 404 360 pd mapping-presets; #X text 331 324 send current state to right outlet; #X text 189 158 Highest frequency to scramble; #X text 268 219 input signal; #X text 538 359 <- use custom mappings; #X text 542 421 display current mapping state; #X connect 0 0 1 0; #X connect 1 0 9 0; #X connect 2 0 9 0; #X connect 3 0 2 0; #X connect 4 0 9 0; #X connect 5 0 4 0; #X connect 7 0 9 0; #X connect 9 0 17 0; #X connect 9 1 10 0; #X connect 10 0 11 0; #X connect 11 0 6 0; #X connect 12 0 9 0; #X connect 20 0 9 0; pd-fftease-3.0.1/fftease-helpfiles/drown~-help.pd000066400000000000000000000047171401707710000217270ustar00rootroot00000000000000#N canvas 391 37 848 633 12; #X floatatom 322 464 5 0 0 0 - - -; #X obj 325 440 hsl 128 15 0.01 4 1 0 empty empty empty -2 -8 0 10 -228856 -1 -1 0 1; #X floatatom 250 431 5 0 0 0 - - -; #X obj 253 401 hsl 128 15 0 1 0 0 empty empty empty -2 -8 0 12 -228856 -1 -1 0 1; #X msg 156 331 adaptive \$1; #X obj 156 302 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X msg 178 388 mute \$1; #X obj 178 362 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X obj 132 262 noise~; #X obj 54 262 osc~ 440; #X msg 41 456 fftinfo; #X text 40 435 Get FFT info; #X obj 178 535 fftease/drown~ 2048 4; #X obj 34 31 ./icon; #X obj 178 578 ./gain.dsp~; #X text 281 399 Threshold; #X text 350 439 Gain factor; #X text 178 302 <= adaptive mode; #X text 527 66 - Reduce/increase spectral noise floor; #X obj 114 378 +~; #X text 395 393 Per-bin noise floor amplitude threshold. Higher values result in greater noise reduction., f 47; #X text 33 108 [drown~] changes the energy of FFT bins whose level are below a given threshold (or "noise floor"). You can then perform noise reduction with a gain factor less than 1 \, or increase it with a factor greater than 1! In adaptive mode \, instead of an absolute value \, the threshold is determined relative to each FFT frame peak. , f 73; #X text 33 187 This example has a sine wave with white noise added to it so you can check to remove the noise and just keep the sine wave. , f 73; #X text 371 462 Gain factor applied to bin amplitudes below threshold. A gain of 1 leaves the bin amplitude unchanged. Values above 1 increase the noise in the signal. Lower values result in more noise reduction and 0 completely removes that bin., f 58; #X obj 512 36 cnv 15 100 30 empty empty fftease/drown~ 20 12 0 24 -262144 -1 0; #X text 336 534 <= arguments: FFT size and overlap factor (default: 1024 \, 8); #X text 189 261 <= input signal is white noise + a sine wave; #X text 312 292 (Adaptive noise reduction can be more effective than non-adaptive NR \, especially when the input signal has a time-varying amplitude envelope), f 53; #X text 613 211 see also:; #X obj 593 229 cnv 15 100 20 empty empty fftease/scrape~ 20 12 0 14 -262144 -1 0; #X text 203 362 <= turns off the object (saving CPU cycles); #X connect 0 0 12 2; #X connect 1 0 0 0; #X connect 2 0 12 1; #X connect 3 0 2 0; #X connect 4 0 12 0; #X connect 5 0 4 0; #X connect 6 0 12 0; #X connect 7 0 6 0; #X connect 8 0 19 1; #X connect 9 0 19 0; #X connect 10 0 12 0; #X connect 12 0 14 0; #X connect 19 0 12 0; pd-fftease-3.0.1/fftease-helpfiles/enrich~-help.pd000077500000000000000000000040401401707710000220360ustar00rootroot00000000000000#N canvas 600 60 713 569 12; #N canvas 0 22 450 278 (subpatch) 0; #X array enrich-buffer 8195 float 0; #X coords 0 1 8194 -1 150 80 1 0 0; #X restore 461 387 graph; #X obj 131 419 sig~ 1; #X obj 231 414 sig~ 0.001; #X obj 134 369 hsl 128 15 0.5 1.9999 0 0 empty enrich-tfac empty -2 -8 0 12 -228856 -1 -1 4234 1; #X floatatom 131 392 9 0 0 0 - - -; #N canvas 365 262 450 300 init 0; #X msg 87 143 \; enrich-hfr 10000 \; enrich-tfac 1 \; enrich-lofr 0 ; #X obj 101 105 loadbang; #X connect 1 0 0 0; #X restore 257 469 pd init; #X obj 92 320 r fftz-enrich-msgs; #X obj 31 449 fftease/enrich~ enrich-buffer; #X obj 33 155 sfplay~; #X text 142 367 transpose-factor; #X text 34 94 [enrich~] synthesizes an oscillator bank that reads from a Pd array \, which can contain any user-specified waveform. Useful for distortion., f 53; #X obj 38 25 ./icon; #X text 461 478 try drawing directly into the array for lots of harmonics , f 29; #X obj 31 483 ./gain.dsp~; #X msg 66 234 highfreq \$1; #X floatatom 66 208 5 0 0 0 - enrich-hfr -; #X floatatom 86 258 5 0 0 0 - enrich-lofr -; #X msg 86 284 lowfreq \$1; #N canvas 0 23 577 247 resynthesis-waveforms 0; #X msg 7 45 \; enrich-buffer cosinesum 8192 0 1; #X msg 7 96 \; enrich-buffer cosinesum 8192 0 0.333 0.333 0.33; #X text 241 51 normal resynthesis with a cosine; #X text 351 104 add more harmonics; #X msg 7 137 \; enrich-buffer cosinesum 8192 0 0 0 0 0.2 0.4 0 0 0.4 ; #X obj 7 18 loadbang; #X text 386 146 way high harmonics; #X connect 5 0 0 0; #X restore 459 344 pd resynthesis-waveforms; #X text 108 206 highest frequency of input signal to resynthesize; #X text 145 260 lowest frequency of input signal to resynthesize; #X text 228 394 synthesis threshold; #X obj 340 29 cnv 15 100 30 empty empty fftease/enrich~ 20 12 0 24 -262144 -1 0; #X text 357 57 - Additive synthesis with an arbitrary waveform; #X connect 1 0 7 1; #X connect 2 0 7 2; #X connect 3 0 4 0; #X connect 4 0 1 0; #X connect 6 0 7 0; #X connect 7 0 13 0; #X connect 8 0 7 0; #X connect 14 0 7 0; #X connect 15 0 14 0; #X connect 16 0 17 0; #X connect 17 0 7 0; pd-fftease-3.0.1/fftease-helpfiles/ether~-help.pd000077500000000000000000000026031401707710000217000ustar00rootroot00000000000000#N canvas 600 60 598 510 12; #X floatatom 325 330 5 0 512 0 - - -; #X msg 66 328 invert \$1; #X obj 66 294 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X text 320 309 composite index; #X obj 153 301 sfplay~; #X obj 239 300 sfplay~; #X obj 153 422 ./gain.dsp~; #X obj 153 377 fftease/ether~, f 25; #X text 56 89 [ether~] selects portions of two input signals and creates a composite output spectrum based upon the amplitude of the inputs. In a bin-by-bin comparison \, the strongest bin of the two inputs will be selected. Sending the inverse message will reverse this behavior \, selecting the weakest bins. The composite index is a scalar for the selection of the second input. Higher values for the composite index will favor the second input. Useful values will vary according to the amplitude characteristics of the input signals. Try values greater than 0 and less than 100 But higher values may be effective depending upon the input signals.; #X obj 59 22 ./icon; #X text 334 56 - Spectral compositing; #X obj 319 27 cnv 15 100 30 empty empty fftease/ether~ 20 12 0 24 -262144 -1 0; #X text 389 245 see also:; #X obj 369 263 cnv 15 100 20 empty empty fftease/ether~ 20 12 0 14 -262144 -1 0; #X obj 369 284 cnv 15 100 20 empty empty fftease/leaker~ 20 12 0 14 -262144 -1 0; #X connect 0 0 7 2; #X connect 1 0 7 0; #X connect 2 0 1 0; #X connect 4 0 7 0; #X connect 5 0 7 1; #X connect 7 0 6 0; pd-fftease-3.0.1/fftease-helpfiles/gain.dsp~.pd000066400000000000000000000014521401707710000213440ustar00rootroot00000000000000#N canvas 600 60 496 310 12; #X obj 76 245 dac~; #X obj 156 106 hsl 128 15 0 1 0 0 dummy \$0-main-gain Gain 48 8 0 11 -228856 -1 -1 0 1; #X obj 76 181 *~; #X obj 153 163 line~; #X msg 153 140 \$1 10; #X obj 153 187 *~; #X obj 153 211 *~; #X obj 76 62 inlet~; #X obj 293 105 tgl 16 0 \$0-dsp \$0-dummy DSP 19 8 0 11 -228856 -1 -1 0 1; #X obj 212 136 sel 0; #X obj 244 162 != 0; #X msg 293 134 \; pd dsp \$1; #X text 213 205 A helper abstraction used in the documentation of FFTease. , f 29; #X connect 1 0 4 0; #X connect 1 0 9 0; #X connect 2 0 0 0; #X connect 2 0 0 1; #X connect 3 0 5 0; #X connect 3 0 5 1; #X connect 4 0 3 0; #X connect 5 0 6 1; #X connect 5 0 6 0; #X connect 6 0 2 1; #X connect 7 0 2 0; #X connect 8 0 11 0; #X connect 9 1 10 0; #X connect 10 0 8 0; #X coords 0 -1 1 1 185 26 2 150 100; pd-fftease-3.0.1/fftease-helpfiles/icon.pd000077500000000000000000000005561401707710000204020ustar00rootroot00000000000000#N canvas 600 60 416 319 12; #X obj 101 101 cnv 15 175 40 empty \$0-header FFTease\ 3.0.1 5 19 1 26 -191407 -4160 0; #X obj 110 228 s \$0-header; #X obj 111 169 loadbang; #X text 85 36 A helper abstraction used in the documentation of FFTease. , f 29; #X msg 110 198 label FFTease\ 3.0.1; #X connect 2 0 4 0; #X connect 4 0 1 0; #X coords 0 -1 1 1 177 42 2 100 100; pd-fftease-3.0.1/fftease-helpfiles/leaker~-help.pd000077500000000000000000000024631401707710000220400ustar00rootroot00000000000000#N canvas 600 60 549 452 12; #X floatatom 315 339 5 0 0 0 - - -; #X obj 318 317 hsl 128 15 0 1 0 0 empty empty empty -2 -8 0 10 -228856 -1 -1 0 1; #X msg 96 209 upsieve; #X msg 115 235 downsieve; #X msg 126 261 randsieve; #X obj 115 366 fftease/leaker~, f 29; #X obj 136 299 ./sfplay~; #X obj 215 299 ./sfplay~; #X obj 115 400 ./gain.dsp~; #X obj 36 25 ./icon; #X text 287 54 - Spectral crossfade; #X text 31 91 [leaker~] combines two input sounds \, with the spectral contribution of each sound determined by an internally maintained sieve and a threshold selection value. At value 0 \, only sound 1 is heard and at value 1 \, only sound 2 is heard. At intermediate values \, parts of each spectrum are aggregated according to the sieve structure which may be specified as upsieve \, downsieve or randsieve., f 69 ; #X text 313 298 slide to crossfade; #X text 148 280 select 2 sounds to crossfade; #X obj 267 28 cnv 15 100 30 empty empty fftease/leaker~ 20 12 0 24 -262144 -1 0; #X text 360 190 see also:; #X obj 340 208 cnv 15 100 20 empty empty fftease/ether~ 20 12 0 14 -262144 -1 0; #X obj 340 230 cnv 15 100 20 empty empty fftease/vacancy~ 20 12 0 14 -262144 -1 0; #X connect 0 0 5 2; #X connect 1 0 0 0; #X connect 2 0 5 0; #X connect 3 0 5 0; #X connect 4 0 5 0; #X connect 5 0 8 0; #X connect 6 0 5 0; #X connect 7 0 5 1; pd-fftease-3.0.1/fftease-helpfiles/mindwarp~-help.pd000077500000000000000000000050461401707710000224160ustar00rootroot00000000000000#N canvas 600 60 621 652 12; #N canvas 936 204 312 312 selector 0; #X obj 135 50 inlet~; #X obj 195 50 inlet~; #X obj 35 50 inlet; #X obj 135 264 outlet~; #X obj 195 158 *~; #X obj 135 162 *~ 1; #X obj 35 115 expr 1-$f1; #X connect 0 0 5 0; #X connect 1 0 4 0; #X connect 2 0 4 1; #X connect 2 0 6 0; #X connect 4 0 3 0; #X connect 5 0 3 0; #X connect 6 0 5 1; #X restore 177 551 pd selector; #X obj 177 500 tgl 17 0 empty mindwarp-tog empty 17 7 0 10 -228856 -1 -1 1 1; #X floatatom 258 385 5 0 0 0 - mindwarp-tfac -; #X floatatom 319 425 5 0 16 0 - mindwarp-wfac -; #X obj 302 385 sig~ 0.001; #X floatatom 388 452 5 1 50 0 - mindwarp-shapew -; #X text 75 497 1 - mindwarp; #N canvas 456 230 450 300 init 0; #X obj 36 100 loadbang; #X msg 36 135 \; mindwarp-tfac 1 \; mindwarp-wfac 1 \; mindwarp-shapew 10 \; mindwarp-tog 1 \; mindwarp-tfac&warpfac 1; #X connect 0 0 1 0; #X restore 303 536 pd init; #X obj 403 332 hsl 128 15 0.5 2 0 0 empty mindwarp-tfac&warpfac tfac&warpfac -2 -8 0 10 -262144 -1 -1 4233 1; #X obj 400 392 s mindwarp-tfac; #X obj 416 363 s mindwarp-wfac; #X obj 214 320 ./sfplay~; #X obj 251 484 fftease/mindwarp~, f 20; #X obj 177 585 ./gain.dsp~; #X text 45 101 [mindwarp~] performs spectral envelope warping. It can be used to correct for the formant shifting effects of pitch-scaling. The warp factor is tuned to warp spectra to compensate for directly corresponding pitch-scaling values., f 77; #X text 45 149 For example \, if you have pitch-scaled a signal by a factor of two \, increasing its frequency content by an octave \, by providing [mindwarp~] with a warp factor of 2 and the pitch-scaled signal \, [mindwarp~] will restore the spectral formant of the signal to an estimation of the shape present in the original unscaled signal. , f 77; #X text 45 224 [mindwarp~] utilizes frequency shaping to perform its duty. You may need to fiddle with the shape width to best catch the formants. It can be fun to decorrelate the warp factor from the transposition factor. Currently \, warp factor values are restricted to the range [1/16 ... 16.]., f 77; #X obj 214 418 fftease/pvoc~; #X text 76 481 0 - raw pvoc~; #X obj 48 26 ./icon; #X text 312 57 - Spectral envelope warping; #X text 364 423 warp factor; #X text 429 450 shape width; #X obj 291 27 cnv 15 100 30 empty empty fftease/mindwarp~ 20 12 0 24 -262144 -1 0; #X connect 0 0 13 0; #X connect 1 0 0 0; #X connect 2 0 17 1; #X connect 3 0 12 1; #X connect 4 0 17 2; #X connect 5 0 12 2; #X connect 8 0 9 0; #X connect 8 0 10 0; #X connect 11 0 17 0; #X connect 12 0 0 2; #X connect 17 0 0 1; #X connect 17 0 12 0; pd-fftease-3.0.1/fftease-helpfiles/morphine~-help.pd000077500000000000000000000030721401707710000224130ustar00rootroot00000000000000#N canvas 600 60 731 434 12; #X msg 59 285 transition \$1; #X floatatom 59 254 5 -30 0 0 - morphine-trans -; #X obj 358 282 hsl 128 15 0 1 0 0 empty empty morph-index -2 -8 0 12 -228856 -1 -1 0 1; #X floatatom 355 308 5 0 0 0 - - -; #N canvas 492 206 450 300 init 0; #X msg 151 157 \; morphine-trans -5; #X obj 151 125 loadbang; #X connect 1 0 0 0; #X restore 118 385 pd init; #X obj 190 337 fftease/morphine~ 4096 8; #X text 31 99 [morphine~] performs spectral morphing \, creating a new spectrum from its two inputs. Values between 0 and 1 are the useful range for the morph index. The progression depends upon the exponential transition scaling value. Progressively smaller negative values will widen the transition space between the two sounds. Larger FFT sizes \, such as 4096 \, produce smoother results., f 65; #X obj 190 260 ./sfplay~; #X obj 272 260 ./sfplay~; #X obj 190 380 ./gain.dsp~; #X obj 36 29 ./icon; #X text 395 59 - Spectral morphing; #X text 368 338 <= args: FFT size \, overlap factor; #X text 524 149 see also:; #X obj 504 167 cnv 15 100 20 empty empty fftease/ether~ 20 12 0 14 -262144 -1 0; #X obj 504 190 cnv 15 100 20 empty empty fftease/leaker~ 20 12 0 14 -262144 -1 0; #X obj 376 30 cnv 15 100 30 empty empty fftease/morphine~ 20 12 0 24 -262144 -1 0; #X text 57 197 exponential transition scaling \; this parameter affects the "shape" of the morph-index transition \; lower values result in a more concave transition shape; #X connect 0 0 5 0; #X connect 1 0 0 0; #X connect 2 0 3 0; #X connect 3 0 5 2; #X connect 5 0 9 0; #X connect 7 0 5 0; #X connect 8 0 5 1; pd-fftease-3.0.1/fftease-helpfiles/multyq~-help.pd000077500000000000000000000041301401707710000221210ustar00rootroot00000000000000#N canvas 600 60 635 455 12; #X obj 59 256 noise~; #X floatatom 100 306 5 0 0 0 - multyq-f1 -; #X floatatom 141 306 5 0 0 0 - multyq-bw1 -; #X floatatom 182 305 5 0 0 0 - multyq-g1 -; #N canvas 650 70 450 300 init 0; #X msg 33 95 \; multyq-f1 565 \; multyq-bw1 0.5 \; multyq-g1 4 \; multyq-bw2 0.45 \; multyq-bw3 0.2 \; multyq-g3 12 \;; #X obj 33 64 loadbang; #X connect 1 0 0 0; #X restore 444 390 pd init; #X obj 223 304 *~; #X obj 223 247 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X obj 277 225 osc~ 0.2; #X obj 277 247 *~ 1000; #X obj 277 269 +~ 1300; #X obj 305 313 * 4; #X floatatom 264 332 5 0 0 0 - multyq-bw2 -; #X text 150 246 autosweep; #X floatatom 511 291 5 0 0 0 - multyq-bw3 -; #X floatatom 553 291 5 0 0 0 - multyq-g3 -; #X obj 473 263 hsl 128 15 1000 10000 0 0 empty empty empty -2 -8 0 10 -228856 -1 -1 0 1; #X floatatom 470 292 5 0 0 0 - - -; #X text 474 239 sweep high end; #X text 326 339 room for one more; #X obj 59 362 fftease/multyq~ 1024 8, f 71; #X obj 59 407 ./gain.dsp~; #X obj 54 35 ./icon; #X text 361 71 - Spectral EQ; #X obj 342 39 cnv 15 100 30 empty empty fftease/multyq~ 20 12 0 24 -262144 -1 0; #X text 55 104 [multyq~] is a four band equalizer. The leftmost inlet takes input signal. After that each of the four filter regions is controlled with a triplet of inlets \, specifying [frequency \, bandwidth \, gain]. Gain values below 0 create notches rather than peaks \, but only go as far as -1.0. Bandwidth is from 0 to +1. Only three bands are used in this example \, but CPU usage is the same regardless of how many are used. As the filter is FFT-based \, its performance is spotty in the low frequency range. Larger FFT sizes will increase frequency resolution \, at the cost of less precise time resolution., f 77; #X connect 0 0 19 0; #X connect 1 0 19 1; #X connect 2 0 19 2; #X connect 3 0 19 3; #X connect 5 0 19 4; #X connect 6 0 5 0; #X connect 6 0 10 0; #X connect 7 0 8 0; #X connect 8 0 9 0; #X connect 9 0 5 1; #X connect 10 0 19 6; #X connect 11 0 19 5; #X connect 13 0 19 11; #X connect 14 0 19 12; #X connect 15 0 16 0; #X connect 16 0 19 10; #X connect 19 0 20 0; pd-fftease-3.0.1/fftease-helpfiles/pileup~-help.pd000077500000000000000000000050121401707710000220640ustar00rootroot00000000000000#N canvas 600 60 537 461 12; #X msg 47 291 mode \$1; #X obj 151 317 r fftz-pileup-msgs; #N canvas 137 73 1107 615 controls 0; #X obj 87 559 s fftz-pileup-msgs; #X msg 87 149 persistence \$1; #X floatatom 87 110 5 0 1 0 - pileup-pers -; #X msg 278 160 oscbank \$1, f 11; #X obj 278 126 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X msg 484 232 synthresh \$1; #X floatatom 484 207 5 0 0 0 - - -; #X obj 487 182 hsl 128 15 0 0.2 0 0 empty empty empty -2 -8 0 10 -262144 -1 -1 0 1; #X floatatom 773 256 5 0 0 0 - - -; #X obj 776 233 hsl 128 15 0.5 1.999 0 0 empty pileup-transp empty -2 -8 0 10 -262144 -1 -1 4236 1; #X msg 773 286 transpose \$1; #X msg 517 335 clear; #X obj 90 82 hsl 128 15 0 1 0 0 pileup-pers empty empty -2 -8 0 10 -262144 -1 -1 0 1; #X text 272 106 toggle oscillator bank resynthesis; #X text 85 53 spectral "feedback" factor; #X msg 500 484 lowfreq \$1; #X floatatom 500 448 5 0 5000 0 - pileup-lofreq -; #X floatatom 634 449 5 100 24000 0 - pileup-hifreq -; #X msg 634 484 highfreq \$1; #X text 489 407 oscillator bank only: low \, and high frequency resynthesis limits; #X text 769 211 transpose \, only works with oscbank turned on; #X text 478 162 synthesis threshold \, only for oscbank; #X text 418 304 erase previously stored spectral frame; #X connect 1 0 0 0; #X connect 2 0 1 0; #X connect 3 0 0 0; #X connect 4 0 3 0; #X connect 5 0 0 0; #X connect 6 0 5 0; #X connect 7 0 6 0; #X connect 8 0 10 0; #X connect 9 0 8 0; #X connect 10 0 0 0; #X connect 11 0 0 0; #X connect 15 0 0 0; #X connect 16 0 15 0; #X connect 17 0 18 0; #X connect 18 0 0 0; #X restore 221 269 pd controls; #N canvas 385 287 450 300 init 0; #X obj 97 107 loadbang; #X msg 97 151 \; pileup-transp 1 \; pileup-pers 0.99 \; pileup-lofreq 0 \; pileup-hifreq 20000; #X connect 0 0 1 0; #X restore 241 357 pd init; #X obj 47 180 vradio 17 1 0 3 empty empty empty 0 -8 0 10 -228856 -1 -1 2; #X text 67 178 persistent amplitude and phase; #X text 67 195 persistent amplitude only, f 30; #X text 67 213 inverse persistence, f 30; #X obj 120 254 ./sfplay~; #X obj 120 356 fftease/pileup~; #X obj 120 400 ./gain.dsp~; #X text 27 111 [pileup~] maintains amplitude/phase information in bins (with possible damping) until new information comes in above a given threshold. This is useful for various reverberant effects., f 63; #X obj 32 45 ./icon; #X text 264 69 - Spectral persistence; #X obj 241 43 cnv 15 100 30 empty empty fftease/pileup~ 20 12 0 24 -262144 -1 0; #X connect 0 0 9 0; #X connect 1 0 9 0; #X connect 4 0 0 0; #X connect 8 0 9 0; #X connect 9 0 10 0; pd-fftease-3.0.1/fftease-helpfiles/pvcompand~-help.pd000077500000000000000000000013011401707710000225520ustar00rootroot00000000000000#N canvas 600 60 593 365 12; #X floatatom 172 228 5 -80 80 0 - - -; #X text 47 104 [pvcompand~] either expands or compresses the differences between the amplitudes of the spectral frames. The threshold is interpreted as dB and useful ranges are from about -60 to +60. Positive values increase the "peakiness" of the sound and negative values tend to whiten the spectrum., f 70; #X obj 49 258 fftease/pvcompand~; #X obj 49 199 ./sfplay~; #X obj 49 299 ./gain.dsp~; #X obj 46 26 ./icon; #X text 295 62 - Spectral compander; #X text 215 228 threshold factor (dB); #X obj 276 28 cnv 15 100 30 empty empty fftease/pvcompand~ 20 12 0 24 -262144 -1 0; #X connect 0 0 2 1; #X connect 2 0 4 0; #X connect 3 0 2 0; pd-fftease-3.0.1/fftease-helpfiles/pvgrain~-help.pd000077500000000000000000000263301401707710000222420ustar00rootroot00000000000000#N canvas 600 60 572 436 12; #X obj 44 295 *~; #X floatatom 62 262 5 0 0 0 - mix-in-orig -; #N canvas 0 22 450 278 (subpatch) 0; #X array pvgrain-pf 46379 float 2; #X coords 0 1 46379 -1 200 140 1; #X restore 289 211 graph; #X obj 135 219 r pvgrain-msgs; #N canvas 345 28 684 740 control 0; #X obj 36 677 s pvgrain-msgs; #X msg 36 139 probability \$1; #X floatatom 36 106 7 0 0 0 - - -; #X obj 39 64 hsl 128 15 0.0001 0.1 0 0 empty pvgrain-prob empty -2 -8 0 10 -262144 -1 -1 2530 1; #X msg 71 249 framegrains \$1; #X floatatom 71 217 5 1 60 0 - pvgrain-fgr -; #X msg 148 523 topfreq \$1; #X floatatom 148 488 7 50 20000 0 - pvgrain-topf -; #X floatatom 246 350 5 0 0 0 - base-freq -; #X obj 246 375 s base-frequency; #X obj 487 444 hsl 128 15 0 1 0 0 mix-in-orig empty mix-in-original-signal -2 -8 0 10 -262144 -1 -1 0 1; #X text 239 328 fundamental frequency of grain sample; #X msg 294 590 bottomfreq \$1; #X floatatom 294 559 5 0 0 0 - - -; #X text 206 489 highest grain frequency data to generate; #X text 338 560 lowest grain frequency to generate; #X text 120 193 maximum number of grains to synthesize per FFT-frame \; at SR = 48000 and FFT size = 1024 \, grain duration is about 0.02 seconds; #X text 34 25 probability that each grain in a given FFT frame is actually synthesized; #X connect 1 0 0 0; #X connect 2 0 1 0; #X connect 3 0 2 0; #X connect 4 0 0 0; #X connect 5 0 4 0; #X connect 6 0 0 0; #X connect 7 0 6 0; #X connect 8 0 9 0; #X connect 12 0 0 0; #X connect 13 0 12 0; #X restore 138 176 pd control; #N canvas 650 70 404 268 init 0; #X obj 86 34 loadbang; #X msg 113 67 \; base-freq 261 \; pvgrain-topf 4000 \; pvgrain-fgr 20 \; pvgrain-prob 0.02; #X obj 86 197 soundfiler; #X msg 86 167 read -resize sound/Piano.aif pvgrain-pf; #X connect 0 0 1 0; #X connect 0 0 3 0; #X connect 3 0 2 0; #X restore 153 323 pd init; #N canvas 523 84 689 382 playback 0; #X obj 51 29 inlet; #X obj 92 104 + 1; #X obj 92 139 % 8; #N canvas 650 70 610 733 gate8 0; #X obj 33 22 inlet; #X obj 525 101 inlet; #X obj 33 75 sel 0 1 2 3 4 5 6 7; #X obj 14 508 spigot; #X obj 14 530 outlet; #X obj 64 508 spigot; #X obj 64 530 outlet; #X obj 115 510 spigot; #X obj 115 532 outlet; #X obj 165 510 spigot; #X obj 165 532 outlet; #X obj 216 508 spigot; #X obj 216 530 outlet; #X obj 266 508 spigot; #X obj 266 530 outlet; #X obj 317 510 spigot; #X obj 317 532 outlet; #X obj 367 510 spigot; #X obj 367 532 outlet; #X obj 11 461 unpack f f f f f f f f, f 59; #X msg 34 115 1 0 0 0 0 0 0 0; #X msg 43 139 0 1 0 0 0 0 0 0; #X msg 57 161 0 0 1 0 0 0 0 0; #X msg 70 187 0 0 0 1 0 0 0 0; #X msg 90 221 0 0 0 0 1 0 0 0 0; #X msg 100 250 0 0 0 0 0 1 0 0 0; #X msg 117 279 0 0 0 0 0 0 1 0 0; #X msg 129 309 0 0 0 0 0 0 0 1 0; #X msg 142 337 0 0 0 0 0 0 0 0 1, f 79; #X connect 0 0 2 0; #X connect 1 0 3 0; #X connect 1 0 5 0; #X connect 1 0 7 0; #X connect 1 0 9 0; #X connect 1 0 11 0; #X connect 1 0 13 0; #X connect 1 0 15 0; #X connect 1 0 17 0; #X connect 2 0 20 0; #X connect 2 1 21 0; #X connect 2 2 22 0; #X connect 2 3 23 0; #X connect 2 4 24 0; #X connect 2 5 25 0; #X connect 2 6 26 0; #X connect 2 7 27 0; #X connect 2 8 28 0; #X connect 3 0 4 0; #X connect 5 0 6 0; #X connect 7 0 8 0; #X connect 9 0 10 0; #X connect 11 0 12 0; #X connect 13 0 14 0; #X connect 15 0 16 0; #X connect 17 0 18 0; #X connect 19 0 3 1; #X connect 19 1 5 1; #X connect 19 2 7 1; #X connect 19 3 9 1; #X connect 19 4 11 1; #X connect 19 5 13 1; #X connect 19 6 15 1; #X connect 19 7 17 1; #X connect 20 0 19 0; #X connect 21 0 19 0; #X connect 22 0 19 0; #X connect 23 0 19 0; #X connect 24 0 19 0; #X connect 25 0 19 0; #X connect 26 0 19 0; #X connect 27 0 19 0; #X connect 28 0 19 0; #X restore 92 165 pd gate8; #X obj 51 60 t l b; #N canvas 650 70 588 642 playlet 0; #X obj 200 43 inlet; #X obj 200 95 unpack f f; #X obj 267 130 / 261; #X obj 65 407 line~; #X obj 65 444 tabread4~ pvgrain-pf; #X obj 65 499 *~ 0.1; #X floatatom 267 164 5 0 0 0 - - -; #X msg 20 375 1; #X msg 65 279 1051; #X obj 65 317 /; #X obj 267 200 t b f; #X obj 65 342 t f b; #X obj 65 545 outlet~; #X msg 65 374 46376 \$1; #X obj 299 75 r base-frequency; #X text 143 361 hard-coded for provided Piano sample \; change sample length here if using a different sample; #X text 100 279 <- duration of the grain sample in milliseconds; #X text 301 47 base frequency of grain sample; #X connect 0 0 1 0; #X connect 1 0 5 1; #X connect 1 1 2 0; #X connect 2 0 6 0; #X connect 3 0 4 0; #X connect 4 0 5 0; #X connect 5 0 12 0; #X connect 6 0 10 0; #X connect 7 0 3 0; #X connect 8 0 9 0; #X connect 9 0 11 0; #X connect 10 0 8 0; #X connect 10 1 9 1; #X connect 11 0 13 0; #X connect 11 1 7 0; #X connect 13 0 3 0; #X connect 14 0 2 1; #X restore 92 211 pd playlet; #X obj 92 263 outlet~; #X obj 51 105 f 0; #N canvas 775 197 588 642 playlet 0; #X obj 200 43 inlet; #X obj 200 95 unpack f f; #X obj 257 130 / 261; #X obj 65 407 line~; #X obj 65 444 tabread4~ pvgrain-pf; #X obj 65 499 *~ 0.1; #X floatatom 257 164 5 0 0 0 - - -; #X msg 20 375 1; #X msg 65 279 1051; #X obj 65 317 /; #X obj 257 200 t b f; #X obj 65 342 t f b; #X text 15 29 assumes 44100 SR; #X obj 65 545 outlet~; #X msg 65 374 46376 \$1; #X obj 299 75 r base-frequency; #X connect 0 0 1 0; #X connect 1 0 5 1; #X connect 1 1 2 0; #X connect 2 0 6 0; #X connect 3 0 4 0; #X connect 4 0 5 0; #X connect 5 0 13 0; #X connect 6 0 10 0; #X connect 7 0 3 0; #X connect 8 0 9 0; #X connect 9 0 11 0; #X connect 10 0 8 0; #X connect 10 1 9 1; #X connect 11 0 14 0; #X connect 11 1 7 0; #X connect 14 0 3 0; #X connect 15 0 2 1; #X restore 163 211 pd playlet; #N canvas 775 197 588 642 playlet 0; #X obj 200 43 inlet; #X obj 200 95 unpack f f; #X obj 257 130 / 261; #X obj 65 407 line~; #X obj 65 444 tabread4~ pvgrain-pf; #X obj 65 499 *~ 0.1; #X floatatom 257 164 5 0 0 0 - - -; #X msg 20 375 1; #X msg 65 279 1051; #X obj 65 317 /; #X obj 257 200 t b f; #X obj 65 342 t f b; #X text 15 29 assumes 44100 SR; #X obj 65 545 outlet~; #X msg 65 374 46376 \$1; #X obj 299 75 r base-frequency; #X connect 0 0 1 0; #X connect 1 0 5 1; #X connect 1 1 2 0; #X connect 2 0 6 0; #X connect 3 0 4 0; #X connect 4 0 5 0; #X connect 5 0 13 0; #X connect 6 0 10 0; #X connect 7 0 3 0; #X connect 8 0 9 0; #X connect 9 0 11 0; #X connect 10 0 8 0; #X connect 10 1 9 1; #X connect 11 0 14 0; #X connect 11 1 7 0; #X connect 14 0 3 0; #X connect 15 0 2 1; #X restore 238 210 pd playlet; #N canvas 775 197 588 642 playlet 0; #X obj 200 43 inlet; #X obj 200 95 unpack f f; #X obj 257 130 / 261; #X obj 65 407 line~; #X obj 65 444 tabread4~ pvgrain-pf; #X obj 65 499 *~ 0.1; #X floatatom 257 164 5 0 0 0 - - -; #X msg 20 375 1; #X msg 65 279 1051; #X obj 65 317 /; #X obj 257 200 t b f; #X obj 65 342 t f b; #X text 15 29 assumes 44100 SR; #X obj 65 545 outlet~; #X msg 65 374 46376 \$1; #X obj 299 75 r base-frequency; #X connect 0 0 1 0; #X connect 1 0 5 1; #X connect 1 1 2 0; #X connect 2 0 6 0; #X connect 3 0 4 0; #X connect 4 0 5 0; #X connect 5 0 13 0; #X connect 6 0 10 0; #X connect 7 0 3 0; #X connect 8 0 9 0; #X connect 9 0 11 0; #X connect 10 0 8 0; #X connect 10 1 9 1; #X connect 11 0 14 0; #X connect 11 1 7 0; #X connect 14 0 3 0; #X connect 15 0 2 1; #X restore 309 210 pd playlet; #N canvas 775 197 588 642 playlet 0; #X obj 200 43 inlet; #X obj 200 95 unpack f f; #X obj 257 130 / 261; #X obj 65 407 line~; #X obj 65 444 tabread4~ pvgrain-pf; #X obj 65 499 *~ 0.1; #X floatatom 257 164 5 0 0 0 - - -; #X msg 20 375 1; #X msg 65 279 1051; #X obj 65 317 /; #X obj 257 200 t b f; #X obj 65 342 t f b; #X text 15 29 assumes 44100 SR; #X obj 65 545 outlet~; #X msg 65 374 46376 \$1; #X obj 299 75 r base-frequency; #X connect 0 0 1 0; #X connect 1 0 5 1; #X connect 1 1 2 0; #X connect 2 0 6 0; #X connect 3 0 4 0; #X connect 4 0 5 0; #X connect 5 0 13 0; #X connect 6 0 10 0; #X connect 7 0 3 0; #X connect 8 0 9 0; #X connect 9 0 11 0; #X connect 10 0 8 0; #X connect 10 1 9 1; #X connect 11 0 14 0; #X connect 11 1 7 0; #X connect 14 0 3 0; #X connect 15 0 2 1; #X restore 383 209 pd playlet; #N canvas 775 197 588 642 playlet 0; #X obj 200 43 inlet; #X obj 200 95 unpack f f; #X obj 257 130 / 261; #X obj 65 407 line~; #X obj 65 444 tabread4~ pvgrain-pf; #X obj 65 499 *~ 0.1; #X floatatom 257 164 5 0 0 0 - - -; #X msg 20 375 1; #X msg 65 279 1051; #X obj 65 317 /; #X obj 257 200 t b f; #X obj 65 342 t f b; #X text 15 29 assumes 44100 SR; #X obj 65 545 outlet~; #X msg 65 374 46376 \$1; #X obj 299 75 r base-frequency; #X connect 0 0 1 0; #X connect 1 0 5 1; #X connect 1 1 2 0; #X connect 2 0 6 0; #X connect 3 0 4 0; #X connect 4 0 5 0; #X connect 5 0 13 0; #X connect 6 0 10 0; #X connect 7 0 3 0; #X connect 8 0 9 0; #X connect 9 0 11 0; #X connect 10 0 8 0; #X connect 10 1 9 1; #X connect 11 0 14 0; #X connect 11 1 7 0; #X connect 14 0 3 0; #X connect 15 0 2 1; #X restore 454 209 pd playlet; #N canvas 775 197 588 642 playlet 0; #X obj 200 43 inlet; #X obj 200 95 unpack f f; #X obj 257 130 / 261; #X obj 65 407 line~; #X obj 65 444 tabread4~ pvgrain-pf; #X obj 65 499 *~ 0.1; #X floatatom 257 164 5 0 0 0 - - -; #X msg 20 375 1; #X msg 65 279 1051; #X obj 65 317 /; #X obj 257 200 t b f; #X obj 65 342 t f b; #X text 15 29 assumes 44100 SR; #X obj 65 545 outlet~; #X msg 65 374 46376 \$1; #X obj 299 75 r base-frequency; #X connect 0 0 1 0; #X connect 1 0 5 1; #X connect 1 1 2 0; #X connect 2 0 6 0; #X connect 3 0 4 0; #X connect 4 0 5 0; #X connect 5 0 13 0; #X connect 6 0 10 0; #X connect 7 0 3 0; #X connect 8 0 9 0; #X connect 9 0 11 0; #X connect 10 0 8 0; #X connect 10 1 9 1; #X connect 11 0 14 0; #X connect 11 1 7 0; #X connect 14 0 3 0; #X connect 15 0 2 1; #X restore 529 208 pd playlet; #N canvas 775 197 588 642 playlet 0; #X obj 200 43 inlet; #X obj 200 95 unpack f f; #X obj 257 130 / 261; #X obj 65 407 line~; #X obj 65 444 tabread4~ pvgrain-pf; #X obj 65 499 *~ 0.1; #X floatatom 257 164 5 0 0 0 - - -; #X msg 20 375 1; #X msg 65 279 1051; #X obj 65 317 /; #X obj 257 200 t b f; #X obj 65 342 t f b; #X text 15 29 assumes 44100 SR; #X obj 65 545 outlet~; #X msg 65 374 46376 \$1; #X obj 299 75 r base-frequency; #X connect 0 0 1 0; #X connect 1 0 5 1; #X connect 1 1 2 0; #X connect 2 0 6 0; #X connect 3 0 4 0; #X connect 4 0 5 0; #X connect 5 0 13 0; #X connect 6 0 10 0; #X connect 7 0 3 0; #X connect 8 0 9 0; #X connect 9 0 11 0; #X connect 10 0 8 0; #X connect 10 1 9 1; #X connect 11 0 14 0; #X connect 11 1 7 0; #X connect 14 0 3 0; #X connect 15 0 2 1; #X restore 600 208 pd playlet; #X connect 0 0 4 0; #X connect 1 0 2 0; #X connect 1 0 7 1; #X connect 2 0 3 0; #X connect 3 0 5 0; #X connect 3 1 8 0; #X connect 3 2 9 0; #X connect 3 3 10 0; #X connect 3 4 11 0; #X connect 3 5 12 0; #X connect 3 6 13 0; #X connect 3 7 14 0; #X connect 4 0 3 1; #X connect 4 1 7 0; #X connect 5 0 6 0; #X connect 7 0 1 0; #X connect 8 0 6 0; #X connect 9 0 6 0; #X connect 10 0 6 0; #X connect 11 0 6 0; #X connect 12 0 6 0; #X connect 13 0 6 0; #X connect 14 0 6 0; #X restore 135 292 pd playback; #X obj 44 172 ./sfplay~; #X obj 135 255 fftease/pvgrain~; #X obj 44 367 ./gain.dsp~; #X obj 39 31 ./icon; #X text 276 54 - Spectral granulator; #X obj 258 28 cnv 15 100 30 empty empty fftease/pvgrain~ 20 12 0 24 -262144 -1 0; #X text 38 105 [pvgrain~] tracks an input sound and outputs control data in the form of [amplitude \, frequency] pairs that can be used to play notes on a synthesizer or sampler.; #X connect 0 0 9 0; #X connect 1 0 0 1; #X connect 3 0 8 0; #X connect 6 0 9 0; #X connect 7 0 0 0; #X connect 7 0 8 0; #X connect 8 0 6 0; pd-fftease-3.0.1/fftease-helpfiles/pvharm~-help.pd000077500000000000000000000034171401707710000220720ustar00rootroot00000000000000#N canvas 600 60 648 398 12; #X obj 180 182 phasor~ 261; #X obj 180 209 -~ 0.5; #X floatatom 230 281 5 0 0 0 - pvharm-t1 -; #X floatatom 280 280 5 0 0 0 - pvharm-t2 -; #X obj 331 279 sig~ 0.001; #N canvas 405 302 269 190 init 0; #X obj 65 55 loadbang; #X msg 66 95 \; pvharm-t1 1.25 \; pvharm-t2 1.5 \; pvharm-basefreq 261 \; pvharm-hifreq 4000 \; pvharm-osclim 300; #X connect 0 0 1 0; #X restore 385 347 pd init; #X obj 201 236 r pvharm-msgs; #N canvas 436 152 789 262 control 0; #X obj 73 216 s pvharm-msgs; #X msg 73 135 lowfreq \$1; #X floatatom 73 53 5 0 0 0 - - -; #X floatatom 230 79 5 0 0 0 - pvharm-hifreq -; #X msg 230 132 highfreq \$1; #X msg 419 176 osclimit \$1; #X floatatom 419 123 5 0 0 0 - pvharm-osclim -; #X text 371 90 limit the maximum number of active oscillators in the oscillator bank; #X text 228 62 highest frequency to synthesize; #X text 70 30 lowest frequency to synthesize; #X connect 1 0 0 0; #X connect 2 0 1 0; #X connect 3 0 4 0; #X connect 4 0 0 0; #X connect 5 0 0 0; #X connect 6 0 5 0; #X restore 281 182 pd control; #X obj 180 313 fftease/pvharm~, f 22; #X text 39 98 [pvharm~] provides basic harmonizing with two transpositions of the input internally calculated and mixed to the output.; #X obj 180 344 ./gain.dsp~; #X obj 33 30 ./icon; #X text 275 64 - Harmonizer; #X obj 254 35 cnv 15 100 30 empty empty fftease/pvharm~ 20 12 0 24 -262144 -1 0; #X text 277 262 transp2; #X text 215 264 transp1; #X obj 92 315 *~ 0.85; #X floatatom 180 142 5 100 10000 0 - pvharm-basefreq -; #X text 337 243 synthesis threshold for oscillator bank; #X text 17 316 add source; #X connect 0 0 1 0; #X connect 1 0 8 0; #X connect 1 0 16 0; #X connect 2 0 8 1; #X connect 3 0 8 2; #X connect 4 0 8 3; #X connect 6 0 8 0; #X connect 8 0 10 0; #X connect 16 0 10 0; #X connect 17 0 0 0; pd-fftease-3.0.1/fftease-helpfiles/pvoc~-help.pd000077500000000000000000000032271401707710000215430ustar00rootroot00000000000000#N canvas 600 60 609 556 12; #X obj 295 411 sig~ 0.001; #X floatatom 216 376 5 0 0 0 - - -; #X obj 216 398 sig~ 1.5; #X msg 64 328 mute \$1; #X obj 64 298 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X floatatom 295 389 5 0 0 0 - - -; #X obj 219 327 hsl 128 15 0.2 2 0 0 empty pvoc-transpose transposition -2 9 0 10 -228856 -1 -1 9172 1; #X obj 151 293 phasor~ 220; #X obj 151 318 -~ 0.5; #X msg 117 203 lowfreq \$1; #X floatatom 117 172 5 0 0 0 - pvoc-lofreq -; #X floatatom 135 232 5 0 0 0 - pvoc-hifreq -; #X msg 135 263 highfreq \$1; #X obj 137 490 ./gain.dsp~; #X obj 137 441 fftease/pvoc~ 2048 8, f 23; #X obj 45 37 ./icon; #X text 343 68 - Phase vocoder; #X text 44 115 [pvoc~] performs phase vocoding with the option to limit minimum and maximum frequency to synthesize.; #N canvas 299 399 450 300 init 0; #X obj 111 46 loadbang; #X msg 111 86 \; pvoc-transpose 1.5 \; pvoc-lofreq 40 \; pvoc-hifreq 5000 \; pvoc-threshold 0.001; #X connect 0 0 1 0; #X restore 341 494 pd init; #X text 160 170 lowest frequency to synthesize; #X text 179 234 highest frequency to synthesize; #X text 337 389 synthesis threshold; #X obj 321 41 cnv 15 100 30 empty empty fftease/pvoc~ 20 12 0 24 -262144 -1 0; #X obj 298 362 hsl 128 15 0 1 0 0 empty pvoc-threshold threshold -2 9 0 10 -228856 -1 -1 13 1; #X text 151 463 args: FFT size \, overlap factor (defaults 1024 8) ; #X connect 0 0 14 2; #X connect 1 0 2 0; #X connect 2 0 14 1; #X connect 3 0 14 0; #X connect 4 0 3 0; #X connect 5 0 0 0; #X connect 6 0 1 0; #X connect 7 0 8 0; #X connect 8 0 14 0; #X connect 9 0 14 0; #X connect 10 0 9 0; #X connect 11 0 12 0; #X connect 12 0 14 0; #X connect 14 0 13 0; #X connect 23 0 5 0; pd-fftease-3.0.1/fftease-helpfiles/pvtuner~-help.pd000077500000000000000000000071011401707710000222720ustar00rootroot00000000000000#N canvas 600 60 627 489 12; #X obj 92 221 r pvtuner-msgs; #N canvas 276 201 613 398 control 0; #X obj 76 231 s pvtuner-msgs; #X msg 76 153 basefreq \$1; #X floatatom 76 121 5 0 0 0 - - -; #X msg 177 161 interpolation \$1; #X obj 177 134 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X obj 76 78 mtof; #X floatatom 76 40 5 21 64 0 - pvtuner-scalestp -; #X text 169 100 turn this on to allow interpolation between the current scale and the previous scale; #X text 120 43 set the MIDI note for the base frequency of the current scale; #X connect 1 0 0 0; #X connect 2 0 1 0; #X connect 3 0 0 0; #X connect 4 0 3 0; #X connect 5 0 2 0; #X connect 6 0 5 0; #X restore 339 393 pd control; #X obj 110 336 sig~ 1; #X obj 337 325 sig~ 0; #X floatatom 337 299 5 0 1 0 - - -; #X obj 340 274 hsl 128 15 0 1 0 0 empty pvtuner-interslide empty -2 -8 0 10 -228856 -1 -1 12700 1; #X obj 58 191 noise~; #N canvas 248 95 395 610 scales 0; #X obj 95 550 s pvtuner-msgs; #X msg 118 153 minor_seventh_chord; #X msg 132 181 diatonic; #X msg 177 294 eq12; #N canvas 433 202 604 288 werkmeisterIII 0; #X msg 68 84 32.625 36.4726 40.9036 43.4989 48.7835 54.5367 61.357 65.25 72.9451 81.8072 86.9977 97.5671 109.073 122.714 130.5 145.89 163.614 173.995 195.134 218.147 245.428 261 291.78 327.229 347.991 390.268 436.294 490.856 522 583.561 654.458 695.982 780.537 872.588 981.712 1044 1167.12 1308.92 1391.96 1561.07 1745.18 1963.42 2088 2334.24 2617.83 2783.93 3122.15 3490.35 3926.85 4176 4668.49 5235.66 5567.86 6244.29 6980.7 7853.7; #X obj 68 46 inlet; #X obj 68 210 outlet; #X text 121 45 any scale can be specified as a list of frequencies ; #X connect 0 0 2 0; #X connect 1 0 0 0; #X restore 54 44 pd werkmeisterIII; #X msg 71 71 added_sixth_minor; #X msg 92 100 added_sixth_major; #X msg 105 125 major_seventh_chord; #X msg 188 320 pelog; #X msg 217 408 slendro; #X msg 204 381 pentaclust; #X msg 223 438 pentatonic; #X msg 197 353 quarterclust; #X msg 168 264 eq8; #X msg 146 209 eq5; #X msg 156 237 eqn 7; #X obj 54 19 bng 18 250 50 0 empty empty empty 17 7 0 10 -228856 -1 -1; #X text 181 44 <= custom scale; #X connect 1 0 0 0; #X connect 2 0 0 0; #X connect 3 0 0 0; #X connect 4 0 0 0; #X connect 5 0 0 0; #X connect 6 0 0 0; #X connect 7 0 0 0; #X connect 8 0 0 0; #X connect 9 0 0 0; #X connect 10 0 0 0; #X connect 11 0 0 0; #X connect 12 0 0 0; #X connect 13 0 0 0; #X connect 14 0 0 0; #X connect 15 0 0 0; #X connect 16 0 4 0; #X restore 339 371 pd scales; #N canvas 301 393 450 300 init 0; #X obj 108 104 loadbang; #X msg 108 135 \; pvtuner-scalestp 21 \; pvtuner-interslide 1 \; pvtuner-transpose 1 \; pvtuner-synt 0.001; #X connect 0 0 1 0; #X restore 339 415 pd init; #X obj 58 377 fftease/pvtuner~ 2048 8; #X obj 58 421 ./gain.dsp~; #X text 42 112 [pvtuner~] allows you to impose an arbitrary tuning scale on any input sound. Several scales are built into the object \, and you can provide arbitrary tunings with a sorted list of numbers representing Hz values., f 71; #X obj 43 45 ./icon; #X obj 163 337 sig~ 0.001; #X text 334 238 Interpolate between scales \, when interpolation is togggled on, f 32; #X floatatom 110 268 5 0 0 0 - pvtuner-transpose -; #X text 158 290 synthesis threshold; #X floatatom 163 309 5 0 0 0 - pvtuner-synt -; #X text 107 250 transposition factor; #X obj 258 43 cnv 15 100 30 empty empty fftease/pvtuner~ 20 12 0 24 -262144 -1 0; #X text 273 73 - Frequency-quantized oscillator bank resynthesis, f 61; #X connect 0 0 9 0; #X connect 2 0 9 1; #X connect 3 0 9 3; #X connect 4 0 3 0; #X connect 5 0 4 0; #X connect 6 0 9 0; #X connect 9 0 10 0; #X connect 13 0 9 2; #X connect 15 0 2 0; #X connect 17 0 13 0; pd-fftease-3.0.1/fftease-helpfiles/pvwarpb~-help.pd000077500000000000000000000151521401707710000222550ustar00rootroot00000000000000#N canvas 455 70 762 510 12; #N canvas 495 165 450 278 (subpatch) 0; #X array pvwarpb-array 512 float 1; #A 0 1.28362 1.28387 1.28412 1.28436 1.28461 1.28486 1.28511 1.28536 1.28561 1.28586 1.28611 1.28635 1.2866 1.28685 1.2871 1.28735 1.2876 1.28785 1.2881 1.28835 1.28859 1.28884 1.28909 1.28934 1.28959 1.28984 1.29009 1.29034 1.29058 1.29083 1.29108 1.29133 1.29158 1.29183 1.29208 1.29233 1.29257 1.29282 1.29307 1.29332 1.29357 1.29382 1.29407 1.29432 1.29456 1.29481 1.29506 1.25699 1.21891 1.18084 1.14276 1.10468 1.06661 1.02853 0.990456 0.95238 0.914305 0.876229 0.838153 0.800077 0.762002 0.723926 0.68585 0.647774 0.609699 0.571623 0.533547 0.495471 0.457395 0.41932 0.381244 0.343168 0.305092 0.267017 0.269425 0.271834 0.274243 0.276652 0.279061 0.281469 0.283878 0.286287 0.288696 0.291104 0.293513 0.295922 0.298331 0.30074 0.303148 0.305557 0.307966 0.310375 0.312783 0.315192 0.317601 0.32001 0.322419 0.324827 0.327236 0.329645 0.332054 0.334463 0.336871 0.33928 0.341689 0.344098 0.346506 0.348915 0.351324 0.353733 0.356142 0.35855 0.360959 0.363368 0.365777 0.368186 0.370594 0.373003 0.375412 0.377821 0.380229 0.382638 0.385047 0.387456 0.389865 0.392273 0.394682 0.397091 0.3995 0.401908 0.404317 0.406726 0.409135 0.411544 0.413952 0.416361 0.41877 0.421179 0.423588 0.425996 0.428405 0.430814 0.433223 0.435631 0.43804 0.440449 0.442858 0.445267 0.447675 0.450084 0.452493 0.454902 0.457311 0.459719 0.462128 0.464537 0.466946 0.469354 0.471763 0.474172 0.476581 0.47899 0.481398 0.483807 0.486216 0.488625 0.491033 0.493442 0.495851 0.49826 0.500669 0.503077 0.505486 0.507895 0.510304 0.512713 0.515121 0.51753 0.519939 0.522348 0.524756 0.527165 0.529574 0.531983 0.534392 0.5368 0.539209 0.541618 0.544027 0.546436 0.546053 0.54567 0.545287 0.544904 0.544522 0.544139 0.543756 0.543373 0.54299 0.542607 0.542225 0.541842 0.541459 0.541076 0.540693 0.540311 0.539928 0.539545 0.539162 0.538779 0.538397 0.538014 0.537631 0.537248 0.536865 0.536483 0.5361 0.535717 0.535334 0.534951 0.534569 0.534186 0.533803 0.53342 0.533037 0.532655 0.532272 0.531889 0.531506 0.531123 0.530741 0.530358 0.529975 0.529592 0.529209 0.528827 0.528444 0.528061 0.527678 0.527295 0.526913 0.52653 0.526147 0.525764 0.525381 0.524998 0.524616 0.524233 0.52385 0.523467 0.523084 0.522702 0.522319 0.521936 0.521553 0.52117 0.520788 0.520405 0.520022 0.519639 0.519256 0.518874 0.518491 0.518108 0.517725 0.517342 0.51696 0.516577 0.516194 0.515811 0.520641 0.52547 0.5303 0.53513 0.539959 0.544789 0.549618 0.554448 0.559278 0.564107 0.568937 0.573766 0.578596 0.583426 0.588255 0.593085 0.597915 0.602744 0.607574 0.612403 0.617233 0.622063 0.626892 0.631722 0.636551 0.641381 0.646211 0.65104 0.65587 0.660699 0.665529 0.670359 0.675188 0.680018 0.684847 0.689677 0.694507 0.699336 0.704166 0.708996 0.713825 0.718655 0.723484 0.728314 0.733144 0.737973 0.742803 0.747632 0.752462 0.757292 0.762121 0.766951 0.77178 0.77661 0.78144 0.786269 0.791099 0.795928 0.800758 0.805588 0.810417 0.815247 0.820077 0.824906 0.829736 0.834565 0.839395 0.844225 0.849054 0.853884 0.858713 0.863543 0.868373 0.873202 0.878032 0.882861 0.887691 0.892521 0.89735 0.90218 0.90701 0.911839 0.916669 0.921498 0.926328 0.931158 0.935987 0.940817 0.945646 0.950476 0.955306 0.960135 0.964965 0.969794 0.974624 0.979454 0.984283 0.989113 0.993942 0.998772 1.0036 1.00843 1.01326 1.01809 1.02292 1.02775 1.03258 1.03741 1.04224 1.04707 1.0519 1.05673 1.06156 1.05673 1.0519 1.04707 1.04224 1.03741 1.03258 1.02776 1.02293 1.0181 1.01327 1.00844 1.00361 0.998784 0.993955 0.989126 0.984298 0.979469 0.97464 0.969811 0.964983 0.960154 0.955325 0.950497 0.945668 0.940839 0.93601 0.931182 0.926353 0.921524 0.916696 0.911867 0.907038 0.90221 0.897381 0.892552 0.887723 0.882895 0.878066 0.873237 0.868409 0.86358 0.858751 0.853922 0.849094 0.844265 0.839436 0.834607 0.829779 0.82495 0.820121 0.815293 0.810464 0.805635 0.800807 0.795978 0.791149 0.78632 0.781492 0.776663 0.771834 0.767006 0.762177 0.757348 0.752519 0.747691 0.742862 0.756896 0.77093 0.784965 0.798999 0.813033 0.827068 0.841102 0.855136 0.86917 0.883205 0.897239 0.911273 0.925307 0.939342 0.953376 0.96741 0.981445 0.995479 1.00951 1.02355 1.03758 1.05162 1.06565 1.07968 1.09372 1.10775 1.12179 1.13582 1.14986 1.16389 1.17792 1.19196 1.20599 1.22003 1.23406 1.2481 1.26213 1.27616 1.2902 1.30423 1.31827 1.3323 1.34634 1.36037 1.3744 1.38844 1.40247 1.41651 1.4225 1.42849 1.43448 1.44047 1.44646 1.45245 1.45844 1.46443 1.47043 1.47642 1.48241 1.4884 1.49439 1.50038 1.50637; #X coords 0 2 511 0 200 140 1 0 0; #X restore 462 273 graph; #X obj 357 334 sig~ 0.0001; #X obj 274 327 sig~ 1; #X floatatom 191 270 5 0 0 0 - - -; #X obj 194 235 hsl 128 15 0 1 0 0 empty empty function-read-offset -2 9 0 10 -228856 -1 -1 0 1; #X obj 277 275 hsl 128 15 0.2 2 0 0 empty pvwarpb-transpose transposition -2 9 0 10 -228856 -1 -1 5644 1; #X obj 108 366 fftease/pvwarpb~ pvwarpb-array, f 36; #X obj 108 212 ./sfplay~; #X obj 108 419 ./gain.dsp~; #X obj 41 27 ./icon; #X text 388 61 - Spectral Warp; #X obj 374 33 cnv 15 100 30 empty empty fftease/pvwarpb~ 20 12 0 24 -262144 -1 0; #X text 41 94 Spectrum warper. An internal frequency warping function is created either with the autofunc message. Try it on vocal sounds. In this version \, the warp function is read from a Pd array that can be redrawn by hand if desired.; #X floatatom 274 299 5 0 0 0 - - -; #X text 486 180 see also:; #X obj 468 199 cnv 15 100 20 empty empty fftease/pvwarp~ 20 12 0 14 -262144 -1 0; #N canvas 650 70 355 208 init 0; #X obj 39 22 loadbang; #X msg 39 81 \; pvwarpb-transpose 1 \; pvwarpb-bottomfreq 0 \; pvwarpb-topfreq 8000; #X connect 0 0 1 0; #X restore 310 429 pd init; #X obj 87 185 r pvwarpb-msgs; #N canvas 557 86 709 307 controls 0; #X obj 44 254 s pvwarpb-msgs; #X msg 159 106 topfreq \$1; #X floatatom 159 78 5 0 0 0 - - -; #X floatatom 44 42 5 0 0 0 - - -; #X msg 44 76 bottomfreq \$1; #X msg 283 126 autofunc 0.2 1.7; #X text 406 128 <= update the warp function; #X msg 300 155 \; pvwarpb-array const 1; #X text 462 162 <= flatten the warp function; #X obj 47 15 hsl 128 15 0 800 0 0 empty pvwarpb-bottomfreq bottomfreq -2 9 0 10 -228856 -1 -1 0 1; #X obj 162 54 hsl 128 15 1000 20000 0 0 empty pvwarpb-topfreq topfreq -2 9 0 10 -228856 -1 -1 4679 1; #X connect 1 0 0 0; #X connect 2 0 1 0; #X connect 3 0 4 0; #X connect 4 0 0 0; #X connect 5 0 0 0; #X connect 7 0 0 0; #X connect 9 0 3 0; #X connect 10 0 2 0; #X restore 310 402 pd controls; #X text 455 420 you can also modify the warp function by drawing into the pvwarpb-array, f 37; #X connect 1 0 6 3; #X connect 2 0 6 2; #X connect 3 0 6 1; #X connect 4 0 3 0; #X connect 5 0 13 0; #X connect 6 0 8 0; #X connect 7 0 6 0; #X connect 13 0 2 0; #X connect 17 0 6 0; pd-fftease-3.0.1/fftease-helpfiles/pvwarp~-help.pd000077500000000000000000000056221401707710000221140ustar00rootroot00000000000000#N canvas 547 24 663 687 12; #X floatatom 396 636 5 0 0 0 - - -; #X floatatom 353 636 5 0 0 0 - - -; #X msg 112 431 autofunc 0.1 2; #X obj 399 511 hsl 128 15 0.25 2 0 0 empty pvwarp-transpose Transposition -2 -8 0 10 -262144 -1 -1 5443 1; #X obj 356 471 hsl 128 15 0 1 0 0 empty empty function-read-offset -2 -8 0 10 -262144 -1 -1 0 1; #X obj 51 194 sfplay~; #X obj 51 743 fftease/pvwarp~, f 56; #X obj 51 785 ./gain.dsp~; #X obj 51 35 ./icon; #X text 389 65 - Spectral Warp; #X floatatom 180 661 5 0 0 0 - pvwarp-w1 -; #X floatatom 137 661 5 0 0 0 - pvwarp-bw1 -; #X floatatom 94 661 5 0 0 0 - pvwarp-cf1 -; #X text 96 643 cf1; #X text 138 643 bw1; #X text 178 643 warp1; #X floatatom 310 661 5 0 0 0 - pvwarp-w2 -; #X floatatom 267 661 5 0 0 0 - pvwarp-bw2 -; #X floatatom 223 661 5 0 0 0 - pvwarp-cf2 -; #X text 225 643 cf2; #X text 267 643 bw2; #X text 306 642 warp2; #X msg 76 291 bottomfreq \$1; #X obj 79 251 hsl 128 15 0 500 0 0 empty pvwarp-lofreq empty -2 -8 0 10 -228856 -1 -1 0 1; #X obj 97 318 hsl 128 15 1000 5000 0 0 empty pvwarp-hifreq empty -2 -8 0 10 -228856 -1 -1 12700 1; #X msg 94 357 topfreq \$1; #X floatatom 76 271 5 0 0 0 - - -; #X floatatom 94 337 5 0 0 0 - - -; #X obj 367 39 cnv 15 100 30 empty empty fftease/pvwarp~ 20 12 0 24 -262144 -1 0; #X text 409 211 see also:; #X obj 388 235 cnv 15 100 20 empty empty fftease/pvwarpb~ 20 12 0 14 -262144 -1 0; #N canvas 650 70 450 300 init 0; #X obj 59 21 loadbang; #X msg 60 76 \; pvwarp-transpose 1 \; pvwarp-hifreq 5000 \; pvwarp-lofreq 0 \; pvwarp-cf1 665 \; pvwarp-bw1 0.45 \; pvwarp-w1 0.25 \; pvwarp-cf2 1500 \; pvwarp-bw2 0.25 \; pvwarp-w2 1.7; #X connect 0 0 1 0; #X restore 338 786 pd init; #X text 437 643 synthesis threshold; #X obj 440 661 sig~ 0.001; #X msg 113 581 automate 0; #X msg 111 501 autofunc 1 1; #X text 112 482 flatten warp function; #X text 117 273 lowest frequency to synthesize; #X text 137 340 highest frequency to synthesize; #X text 196 575 turn off the warp function \, and return control to the two "bumps" controlled by inlets 2 - 7; #X text 46 89 [pvwarp~] creates an internal frequency warping function either according to specification or with the autofunc message. You can also manually control warping with two "bumps" defined by [center freq \, bandwidth factor \, warp factor] triplets \, using inlets 2-7. Try this external on vocal sounds., f 50; #X text 108 386 build a random warp function (args: minimum and maximum transpose factors) \; this internally turns on the "automate" state ; #X connect 0 0 6 8; #X connect 1 0 6 7; #X connect 2 0 6 0; #X connect 3 0 0 0; #X connect 4 0 1 0; #X connect 5 0 6 0; #X connect 6 0 7 0; #X connect 10 0 6 3; #X connect 11 0 6 2; #X connect 12 0 6 1; #X connect 16 0 6 6; #X connect 17 0 6 5; #X connect 18 0 6 4; #X connect 22 0 6 0; #X connect 23 0 26 0; #X connect 24 0 27 0; #X connect 25 0 6 0; #X connect 26 0 22 0; #X connect 27 0 25 0; #X connect 33 0 6 9; #X connect 34 0 6 0; #X connect 35 0 6 0; pd-fftease-3.0.1/fftease-helpfiles/reanimator~-help.pd000077500000000000000000000074161401707710000227410ustar00rootroot00000000000000#N canvas 600 60 744 533 12; #X floatatom 279 403 5 0 0 0 - - -; #X floatatom 172 423 5 0 0 0 - - -; #N canvas 650 70 450 300 showframe 0; #X obj 205 102 inlet~; #X obj 205 159 snapshot~; #X obj 325 121 metro 50; #X obj 325 89 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1 1; #X obj 325 22 loadbang; #X msg 325 57 1; #X obj 205 225 outlet; #X connect 0 0 1 0; #X connect 1 0 6 0; #X connect 2 0 1 0; #X connect 3 0 2 0; #X connect 4 0 5 0; #X connect 5 0 3 0; #X restore 172 370 pd showframe; #X msg 80 259 analyze; #N canvas 650 70 450 300 show-analysis-progress 0; #X obj 205 102 inlet~; #X obj 205 159 snapshot~; #X obj 325 121 metro 50; #X obj 325 89 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1 1; #X obj 325 22 loadbang; #X msg 325 57 1; #X obj 205 225 outlet; #X connect 0 0 1 0; #X connect 1 0 6 0; #X connect 2 0 1 0; #X connect 3 0 2 0; #X connect 4 0 5 0; #X connect 5 0 3 0; #X restore 279 369 pd show-analysis-progress; #X text 50 95 [reanimator~] first analyzes a "texture" sound \, and then resynthesizes a "driver" sound by finding the spectral frame in the texture sound that is closest to the current driver frame.; #X obj 65 455 ./gain.dsp~; #X obj 378 205 ./sfplay~; #X obj 65 202 ./sfplay~; #X obj 38 33 ./icon; #X text 394 59 - Audio texture mapping; #X text 378 177 texture sound; #X text 62 178 driver sound; #X text 288 329 <= args: analysis buffer size (ms) \, FFT size \, overlap factor; #X text 141 257 <= with texture sound playing \, hit this to capture analysis; #X obj 65 331 fftease/reanimator~ 5000 1024 8; #X text 324 403 analysis progress sync signal; #X obj 90 302 r reanimator-msgs; #X obj 374 33 cnv 15 100 30 empty empty fftease/reanimator~ 20 12 0 24 -262144 -1 0; #N canvas 650 70 899 801 more-controls 0; #X obj 82 740 s reanimator-msgs; #X msg 82 128 topbin \$1; #X floatatom 82 85 5 0 0 0 - reanimator-topbin -; #X msg 227 208 oscbank \$1; #X obj 227 173 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X text 251 176 turn on the oscillator bank; #X msg 280 266 transpose \$1; #X floatatom 280 238 5 0 0 0 - reanimator-transpose -; #X text 318 236 transpose (only works with oscillator bank); #X msg 277 340 synthresh \$1; #X text 280 362 synthesis threshold (only works with oscillator bank) ; #X floatatom 277 305 5 0 0 0 - reanimator-synthresh -; #X msg 352 542 resume; #X msg 290 423 freeze_and_march 0; #X msg 292 448 freeze_and_march -0.2; #X text 348 521 resume normal speed; #X msg 291 475 freeze_and_march 10; #X text 287 392 set increment (playback speed) to argument \; zero freezes the sound; #X msg 383 626 inverse \$1; #X obj 383 593 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X text 403 593 toggle on to look for the "worst" match for each frame ; #X msg 345 698 mute \$1; #X obj 345 669 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X text 371 672 turn off object and save CPU cycles; #X text 122 69 highest bin to take into account when looking for a matching spectrum \; lower values often work better than very high ones; #X connect 1 0 0 0; #X connect 2 0 1 0; #X connect 3 0 0 0; #X connect 4 0 3 0; #X connect 6 0 0 0; #X connect 7 0 6 0; #X connect 9 0 0 0; #X connect 11 0 9 0; #X connect 12 0 0 0; #X connect 13 0 0 0; #X connect 14 0 0 0; #X connect 16 0 0 0; #X connect 18 0 0 0; #X connect 19 0 18 0; #X connect 21 0 0 0; #X connect 22 0 21 0; #X restore 306 459 pd more-controls; #N canvas 650 70 450 300 init 0; #X obj 39 25 loadbang; #X msg 39 69 \; reanimator-topbin 40 \; reanimator-transpose 1 \; reanimator-synthresh 0.001; #X connect 0 0 1 0; #X restore 444 459 pd init; #X text 211 422 current matched frame from the texture analysis; #X connect 2 0 1 0; #X connect 3 0 15 0; #X connect 4 0 0 0; #X connect 7 0 15 1; #X connect 8 0 15 0; #X connect 15 0 6 0; #X connect 15 1 2 0; #X connect 15 2 4 0; #X connect 17 0 15 0; pd-fftease-3.0.1/fftease-helpfiles/resent~-help.pd000077500000000000000000000104161401707710000220720ustar00rootroot00000000000000#N canvas 600 60 731 486 12; #N canvas 650 70 450 300 showsync 0; #X obj 205 102 inlet~; #X obj 205 159 snapshot~; #X obj 325 121 metro 50; #X obj 325 89 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1 1; #X obj 325 22 loadbang; #X msg 325 57 1; #X obj 205 225 outlet; #X connect 0 0 1 0; #X connect 1 0 6 0; #X connect 2 0 1 0; #X connect 3 0 2 0; #X connect 4 0 5 0; #X connect 5 0 3 0; #X restore 238 368 pd showsync; #X floatatom 238 393 5 0 0 0 - - -; #X msg 51 171 acquire_sample; #X obj 118 288 r resent-msgs; #N canvas 650 70 773 411 speed-and-phase 0; #X obj 133 352 s resent-msgs; #X msg 23 139 setspeed \$1; #X floatatom 23 113 5 0 0 0 - - -; #X obj 26 84 hsl 128 15 -2 2 0 0 empty empty empty -2 -8 0 10 -262144 -1 -1 7500 1; #X msg 411 294 addphase \$1; #X floatatom 411 272 5 0 0 0 - - -; #X obj 414 243 hsl 128 15 0 1 0 0 empty empty empty -2 -8 0 10 -262144 -1 -1 1300 1; #X floatatom 133 203 5 0 0 0 - - -; #X obj 136 174 hsl 128 15 0 1 0 0 empty empty empty -2 -8 0 10 -262144 -1 -1 0 1; #X msg 133 225 setphase \$1; #X msg 368 139 setspeed_and_phase \$1 \$2; #X msg 368 89 1 0; #X msg 412 89 0 0; #X msg 458 89 -1 1; #X text 129 150 set location in sample; #X text 411 219 set phase relative to current location; #X text 20 67 change the global speed; #X text 509 87 set speeds and phases globally; #X connect 1 0 0 0; #X connect 2 0 1 0; #X connect 3 0 2 0; #X connect 4 0 0 0; #X connect 5 0 4 0; #X connect 6 0 5 0; #X connect 7 0 9 0; #X connect 8 0 7 0; #X connect 9 0 0 0; #X connect 10 0 0 0; #X connect 11 0 10 0; #X connect 12 0 10 0; #X connect 13 0 10 0; #X restore 234 240 pd speed-and-phase; #N canvas 650 70 624 316 oscbank 0; #X obj 103 241 s resent-msgs; #X msg 103 144 oscbank \$1; #X obj 103 96 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X msg 190 140 transpose \$1; #X floatatom 190 106 5 0 0 0 - - -; #X obj 193 73 hsl 128 15 0.1 2 0 0 empty empty empty -2 -8 0 10 -262144 -1 -1 1200 1; #X msg 312 184 synthresh \$1; #X msg 312 146 0.001; #X text 30 77 toggle oscbank; #X text 182 43 transposition (oscbank only); #X text 307 117 synthesis threshold (oscbank only); #X connect 1 0 0 0; #X connect 2 0 1 0; #X connect 3 0 0 0; #X connect 4 0 3 0; #X connect 5 0 4 0; #X connect 6 0 0 0; #X connect 7 0 6 0; #X restore 233 269 pd oscbank; #N canvas 650 70 719 379 individual-bin-control 0; #X obj 34 343 s resent-msgs; #X msg 151 105 linespeed 0 -1 511 1; #X msg 183 184 randspeed 0.5 0.9; #X msg 245 217 randphase 0 1; #X msg 340 311 setspeed_and_phase \$1 \$2; #X msg 340 278 0 0; #X text 369 274 first freeze sound to hear effects; #X msg 32 174 bin \$1 \$2; #X obj 32 126 pack f f; #X floatatom 85 68 5 0 0 0 - - -; #X floatatom 32 44 5 0 511 0 - - -; #X text 129 69 speed; #X text 70 47 bin number; #X text 304 103 linear distribution of speeds. (we assume here an FFT size of 1024.); #X text 308 148 likewise for phase; #X text 320 183 randomly set all speeds within min/max parameters; #X text 30 23 set individual bin speeds with [bin \, speed] pairs; #X text 227 48 (highest bin limited by FFT size / 2); #X msg 159 149 linephase 0 0 511 1; #X text 348 222 randomize all phases; #X connect 1 0 0 0; #X connect 2 0 0 0; #X connect 3 0 0 0; #X connect 4 0 0 0; #X connect 5 0 4 0; #X connect 7 0 0 0; #X connect 8 0 7 0; #X connect 9 0 8 1; #X connect 10 0 8 0; #X connect 18 0 0 0; #X restore 234 212 pd individual-bin-control; #X obj 101 229 ./sfplay~; #X text 46 94 [resent~] follows the model of residency~ but allows independent control over each bin. It is recommended that you familiarize yourself with residency~ before working with the more complicated resent~ , f 52; #X obj 101 428 ./gain.dsp~; #X obj 48 33 ./icon; #X text 410 67 - Spectral sample buffer; #X text 301 330 <= args: sample duration in ms \, FFT size \, overlap factor; #X obj 388 33 cnv 15 100 30 empty empty fftease/resent~ 20 12 0 24 -262144 -1 0; #X text 452 232 see also:; #X obj 431 256 cnv 15 100 20 empty empty fftease/residency~ 20 12 0 14 -262144 -1 0; #X obj 431 281 cnv 15 100 20 empty empty fftease/residency_buffer~ 20 12 0 14 -262144 -1 0; #X text 276 394 show location into sample or recording progress; #X obj 101 329 fftease/resent~ 6000 1024 8; #X text 161 170 capture input signal; #X connect 0 0 1 0; #X connect 2 0 18 0; #X connect 3 0 18 0; #X connect 7 0 18 0; #X connect 18 0 9 0; #X connect 18 1 0 0; pd-fftease-3.0.1/fftease-helpfiles/residency_buffer~-help.pd000077500000000000000000000053141401707710000241110ustar00rootroot00000000000000#N canvas 414 37 855 609 12; #N canvas 0 22 450 278 (subpatch) 0; #X array analysis-array1 1.92375e+006 float 2; #X coords 0 32767 1.92375e+006 -32768 100 70 1 0 0; #X restore 589 306 graph; #X floatatom 280 313 5 0 0 0 - - -; #X floatatom 422 305 5 0 0 0 - - -; #X obj 425 274 hsl 128 15 0 1 0 0 empty empty position -2 -8 0 10 -262144 -1 -1 0 1; #X msg 73 211 calcbuf 5000; #N canvas 158 177 450 300 showsync 0; #X obj 205 102 inlet~; #X obj 205 159 snapshot~; #X obj 325 121 metro 50; #X obj 325 89 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1 1; #X obj 325 22 loadbang; #X msg 325 57 1; #X obj 205 225 outlet; #X connect 0 0 1 0; #X connect 1 0 6 0; #X connect 2 0 1 0; #X connect 3 0 2 0; #X connect 4 0 5 0; #X connect 5 0 3 0; #X restore 280 420 pd showsync; #X floatatom 280 445 5 0 0 0 - - -; #X obj 280 340 sig~ 0; #X obj 422 337 sig~ 0; #X text 527 377 warning: do not write into this array \, as you will create extremely loud glitches if you do so., f 38; #X obj 138 377 fftease/residency_buffer~ analysis-array1; #X obj 138 289 ./sfplay~; #X obj 138 493 ./gain.dsp~; #X obj 38 21 ./icon; #X text 413 47 - Spectral sample buffer; #X floatatom 422 439 12 0 0 0 - - -; #X obj 422 483 array size analysis-array1; #X text 178 199 Report the required size of storage buffer for a desired number of milliseconds. This will automatically resize the array in this patch. (DACs must be on first.), f 28; #X msg 12 343 acquire_sample; #X text 447 463 array size is set in samples here; #X text 280 294 speed; #X text 7 322 record sample; #X text 33 87 residency_buffer~ is like residency~ except that it uses a Pd array rather than an internal buffer. This makes it more complicated to work with \, but potentially more efficient than residency~. Any number of units may access the same array (or different ones). The array name is the obligatory first argument. Do NOT attempt to play the recorded buffer with tabread~ or other time-domain audio objects unless you have some idea of what you are doing (and turn the volume way down before attempting this). Multiple copies of this object accessing the same array is the killer app here., f 91; #X obj 390 20 cnv 15 100 30 empty empty fftease/residency_buffer~ 20 12 0 24 -262144 -1 0; #X text 592 189 see also:; #X obj 571 213 cnv 15 100 20 empty empty fftease/residency~ 20 12 0 14 -262144 -1 0; #X obj 571 238 cnv 15 100 20 empty empty fftease/resent~ 20 12 0 14 -262144 -1 0; #X text 150 437 current phase in buffer (0 - 1); #X connect 1 0 7 0; #X connect 2 0 8 0; #X connect 3 0 2 0; #X connect 4 0 10 0; #X connect 5 0 6 0; #X connect 7 0 10 1; #X connect 8 0 10 2; #X connect 10 0 12 0; #X connect 10 1 5 0; #X connect 10 2 15 0; #X connect 11 0 10 0; #X connect 15 0 16 0; #X connect 18 0 10 0; pd-fftease-3.0.1/fftease-helpfiles/residency~-help.pd000077500000000000000000000047221401707710000225620ustar00rootroot00000000000000#N canvas 481 52 774 373 12; #N canvas 222 184 450 300 showsync 0; #X obj 205 102 inlet~; #X obj 205 159 snapshot~; #X obj 325 121 metro 50; #X obj 325 89 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1 1; #X obj 325 22 loadbang; #X msg 325 57 1; #X obj 205 225 outlet; #X connect 0 0 1 0; #X connect 1 0 6 0; #X connect 2 0 1 0; #X connect 3 0 2 0; #X connect 4 0 5 0; #X connect 5 0 3 0; #X restore 362 292 pd showsync; #X floatatom 362 317 5 0 0 0 - - -; #X floatatom 258 216 5 0 0 0 - - -; #X floatatom 362 216 5 0 0 0 - - -; #X msg 108 165 acquire_sample; #X obj 365 188 hsl 128 15 0 1 0 0 empty empty position -2 -8 0 10 -262144 -1 -1 0 1; #X text 256 193 speed; #X obj 155 300 ./gain.dsp~; #X obj 154 195 ./sfplay~; #X text 42 97 [residency~] samples input to an internal buffer \, after which the sound can be resynthesized with arbitrary speed and pitch. , f 71; #X obj 40 24 ./icon; #X text 419 56 -Spectral sample buffer; #X obj 155 255 fftease/residency~ 5000 1024 8; #X text 383 253 <= args: size in ms \, FFT size \, overlap factor; #X text 404 318 phase in internal buffer (0 - 1); #N canvas 203 236 829 320 oscbank 0; #X msg 103 144 oscbank \$1; #X obj 103 96 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X msg 190 140 transpose \$1; #X floatatom 190 106 5 0 0 0 - - -; #X obj 193 73 hsl 128 15 0.1 2 0 0 empty residency-transpose empty -2 -8 0 10 -262144 -1 -1 6016 1; #X msg 426 117 synthresh \$1; #X text 69 72 toggle oscbank; #X text 182 43 transposition (oscbank only); #X text 421 50 synthesis threshold (oscbank only); #X obj 103 241 s residency-msgs; #X floatatom 426 82 5 0 0 0 - residency-synt -; #X connect 0 0 9 0; #X connect 1 0 0 0; #X connect 2 0 9 0; #X connect 3 0 2 0; #X connect 4 0 3 0; #X connect 5 0 9 0; #X connect 10 0 5 0; #X restore 51 272 pd oscbank; #X obj 57 140 r residency-msgs; #N canvas 354 247 450 300 init 0; #X obj 95 59 loadbang; #X msg 95 97 \; residency-transpose 1 \; residency-synt 0.001; #X connect 0 0 1 0; #X restore 51 297 pd init; #X obj 399 27 cnv 15 100 30 empty empty fftease/residency~ 20 12 0 24 -262144 -1 0; #X text 212 165 record sample; #X text 534 150 see also:; #X obj 513 174 cnv 15 100 20 empty empty fftease/resent~ 20 12 0 14 -262144 -1 0; #X obj 513 199 cnv 15 100 20 empty empty fftease/residency_buffer~ 20 12 0 14 -262144 -1 0; #X connect 0 0 1 0; #X connect 2 0 12 1; #X connect 3 0 12 2; #X connect 4 0 12 0; #X connect 5 0 3 0; #X connect 8 0 12 0; #X connect 12 0 7 0; #X connect 12 1 0 0; #X connect 16 0 12 0; pd-fftease-3.0.1/fftease-helpfiles/schmear~-help.pd000077500000000000000000000037001401707710000222120ustar00rootroot00000000000000#N canvas 600 60 580 379 12; #X obj 29 234 r schmear-msgs; #X obj 141 216 osc~ 140; #N canvas 650 70 472 423 vibrato 0; #X obj 110 127 osc~ 0.3; #X obj 110 168 *~ 50; #X obj 110 209 +~ 100; #X obj 110 250 *~; #X obj 365 140 inlet; #X obj 110 344 outlet~; #X obj 110 303 +~ 140; #X connect 0 0 1 0; #X connect 1 0 2 0; #X connect 2 0 3 0; #X connect 3 0 6 0; #X connect 4 0 3 1; #X connect 6 0 5 0; #X restore 141 181 pd vibrato; #X obj 141 148 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #N canvas 650 70 519 322 impulses 0; #X msg 16 64 schmimp 1; #X msg 36 121 schmimp 0 0 0 0 0 0 0.25 0 0 1 1 1 1; #X msg 49 154 schmimp 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.001 0 1 0 0 1 0 0 0 1; #X msg 66 199 schmimp 0 0 0 0 0 0 0 0 0 0 1 0.1 0 1 0.1 0 0.1 1 0.1 0 0; #X obj 16 255 s schmear-msgs; #X text 89 64 no smear; #X text 102 99 a few different kernels:; #X connect 0 0 4 0; #X connect 1 0 4 0; #X connect 2 0 4 0; #X connect 3 0 4 0; #X restore 265 209 pd impulses; #N canvas 650 70 450 300 control 0; #X obj 51 185 s schmear-msgs; #X msg 51 135 threshold \$1; #X floatatom 51 98 5 0 0 0 - - -; #X obj 54 67 hsl 128 15 0 1 0 0 empty empty empty -2 -8 0 10 -262144 -1 -1 0 1; #X msg 248 138 shift \$1; #X floatatom 248 109 5 0 511 0 - - -; #X text 245 84 shift bin energy upward; #X text 57 46 processing threshold; #X connect 1 0 0 0; #X connect 2 0 1 0; #X connect 3 0 2 0; #X connect 4 0 0 0; #X connect 5 0 4 0; #X restore 265 234 pd control; #X obj 141 274 fftease/schmear~; #X obj 141 318 ./gain.dsp~; #X text 29 97 [schmear~] convolves the amplitude spectrum with a user-supplied impulse response \, thus smearing the spectrum \, for those times when you need a New York moment., f 51; #X obj 33 31 ./icon; #X text 298 52 - Spectral smearing; #X obj 286 22 cnv 15 100 30 empty empty fftease/schmear~ 20 12 0 24 -262144 -1 0; #X text 159 146 add vibrato to input signal; #X connect 0 0 6 0; #X connect 1 0 6 0; #X connect 2 0 1 0; #X connect 3 0 2 0; #X connect 6 0 7 0; pd-fftease-3.0.1/fftease-helpfiles/scrape~-help.pd000077500000000000000000000025061401707710000220500ustar00rootroot00000000000000#N canvas 600 60 600 441 12; #X floatatom 290 204 5 0 0 1 knee scrape-knee -; #X floatatom 291 228 5 0 0 1 cutoff scrape-cutoff -; #X floatatom 291 254 5 0 0 1 thresh1 scrape-t1 -; #X floatatom 292 277 5 0 0 1 thresh2 scrape-t2 -; #X floatatom 292 302 5 0 0 1 weak-bin-multiplier scrape-wbm -; #N canvas 650 70 450 300 init 0; #X msg 72 99 \; scrape-knee 1000 \; scrape-cutoff 4000 \; scrape-t1 0.001 \; scrape-t2 0.05 \; scrape-wbm 0.1; #X obj 72 65 loadbang; #X connect 1 0 0 0; #X restore 317 336 pd init; #X text 47 103 scrape~ is like drown~ except that it only operates between the frequencies specified by knee and cutoff to the Nyquist. Between knee and cutoff is a transition range to gradually increase the noise reduction. This is good if you just want to scrape some noise off the upper frequency range without affecting lower parts of the spectrum (much).; #X obj 64 337 fftease/scrape~, f 33; #X obj 64 257 ./sfplay~; #X obj 64 372 ./gain.dsp~; #X obj 49 36 ./icon; #X text 343 71 - Shaped noise reduction; #X obj 321 38 cnv 15 100 30 empty empty fftease/scrape~ 20 12 0 24 -262144 -1 0; #X text 429 205 see also:; #X obj 409 223 cnv 15 100 20 empty empty fftease/drown~ 20 12 0 14 -262144 -1 0; #X connect 0 0 7 1; #X connect 1 0 7 2; #X connect 2 0 7 3; #X connect 3 0 7 4; #X connect 4 0 7 5; #X connect 7 0 9 0; #X connect 8 0 7 0; pd-fftease-3.0.1/fftease-helpfiles/sfplay~.pd000066400000000000000000000017751401707710000211470ustar00rootroot00000000000000#N canvas 869 385 456 434 12; #X obj 49 22 inlet; #X obj 103 123 bng 16 250 50 0 \$0-bang \$0-dummy empty 17 7 0 10 -228856 -1 -1; #X obj 49 62 route bang float; #X obj 103 104 tgl 16 0 \$0-tgl \$0-dummy empty 17 7 0 10 -228856 -1 -1 0 1; #X obj 103 185 openpanel; #X msg 103 296 open \$1 \, 1; #X obj 215 332 readsf~; #X obj 317 215 spigot; #X obj 215 382 outlet~; #X obj 184 172 != 0; #X text 120 122 Choose; #X text 120 103 Play, f 6; #X obj 184 143 trigger float float, f 25; #X obj 184 201 sel 1; #X text 195 52 Helper abstraction used in the documentation of FFTease to play sound files., f 30; #X obj 184 115 r \$0-tgl; #X obj 103 271 symbol \$1; #X connect 0 0 2 0; #X connect 1 0 4 0; #X connect 2 0 1 0; #X connect 2 1 3 0; #X connect 4 0 16 0; #X connect 5 0 6 0; #X connect 6 0 8 0; #X connect 6 1 7 0; #X connect 7 0 16 0; #X connect 9 0 13 0; #X connect 12 0 9 0; #X connect 12 1 7 1; #X connect 13 0 16 0; #X connect 13 1 6 0; #X connect 15 0 12 0; #X connect 16 0 5 0; #X coords 0 -1 1 1 67 43 2 100 100; pd-fftease-3.0.1/fftease-helpfiles/shapee~-help.pd000077500000000000000000000014621401707710000220400ustar00rootroot00000000000000#N canvas 600 60 537 435 12; #X floatatom 261 290 5 1 511 2 shape-width shapee-width -; #X text 28 97 shapee~ shapes the frequency evolution of one signal with that of another. The shape width controls the amount of the frequency shaping effect., f 56; #X obj 61 241 ./sfplay~; #X obj 161 241 ./sfplay~; #X obj 61 328 fftease/shapee~, f 29; #X obj 61 372 ./gain.dsp~; #X obj 23 26 ./icon; #X text 295 54 - Frequency shaping; #X text 58 179 frequency reference source, f 10; #X text 162 181 formant reference source, f 9; #X obj 273 28 cnv 15 100 30 empty empty fftease/shapee~ 20 12 0 24 -262144 -1 0; #N canvas 650 70 289 179 init 0; #X obj 14 43 loadbang; #X msg 14 75 \; shapee-width 8; #X connect 0 0 1 0; #X restore 266 374 pd init; #X connect 0 0 4 2; #X connect 2 0 4 0; #X connect 3 0 4 1; #X connect 4 0 5 0; pd-fftease-3.0.1/fftease-helpfiles/swinger~-help.pd000077500000000000000000000013341401707710000222470ustar00rootroot00000000000000#N canvas 600 60 555 406 12; #X obj 85 204 ./sfplay~; #X obj 194 204 ./sfplay~; #X obj 85 269 fftease/swinger~; #X obj 85 315 ./gain.dsp~; #X text 37 99 [swinger~] replaces the phases of one signal (left) with those from another (right). The result often sounds like victory. A swinging trick: Don't connect any signal to the right inlet and listen to the result.; #X obj 42 30 ./icon; #X text 272 69 - Cross synthesis; #X text 40 176 amplitude source; #X text 192 176 phase source; #X obj 250 35 cnv 15 100 30 empty empty fftease/swinger~ 20 12 0 24 -262144 -1 0; #X text 344 233 see also:; #X obj 323 257 cnv 15 100 20 empty empty fftease/xsyn~ 20 12 0 14 -262144 -1 0; #X connect 0 0 2 0; #X connect 1 0 2 1; #X connect 2 0 3 0; pd-fftease-3.0.1/fftease-helpfiles/taint~-help.pd000077500000000000000000000043201401707710000217060ustar00rootroot00000000000000#N canvas 600 60 727 591 12; #X obj 294 443 expr pow(10 \, $f1/20); #X floatatom 294 415 5 -180 0 0 - taint-invthresh -; #X floatatom 239 360 5 0 0 0 - - -; #X obj 34 366 r taint-msgs; #N canvas 650 70 472 261 control 0; #X obj 30 216 s taint-msgs; #X floatatom 29 64 5 0 0 0 - taint-pad -; #X obj 29 93 expr pow(10 \, $f1/20); #X floatatom 29 122 5 0 0 0 - - -; #X msg 29 151 pad \$1; #X msg 122 175 invert \$1; #X obj 122 142 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X text 21 11 this pad only affects the gain when "invert" is turned on thus it may be used to balance levels between the two states of taint~; #X text 141 138 warning: can produce very loud levels; #X connect 1 0 2 0; #X connect 2 0 3 0; #X connect 3 0 4 0; #X connect 4 0 0 0; #X connect 5 0 0 0; #X connect 6 0 5 0; #X restore 471 476 pd control; #N canvas 650 70 311 217 init 0; #X obj 72 59 loadbang; #X msg 72 93 \; taint-pad -36 \; taint-scaleexp 0.2 \; taint-invthresh -40; #X connect 0 0 1 0; #X restore 472 511 pd init; #X text 340 408 inverse threshold (lower values intensify effect but only when "invert" is turned on), f 44; #X obj 242 328 hsl 128 15 0.05 1 0 0 empty taint-scaleexp empty -2 -8 0 10 -262144 -1 -1 2005 1; #X obj 129 471 fftease/taint~, f 24; #X obj 129 208 ./sfplay~; #X obj 184 262 ./sfplay~; #X text 38 99 [taint~] multiplies the spectra of two input signals. Multiplication of spectra can cause significant drops in the amplitude of the output signal. The inverse option allows division of the input spectra. Division requires the use of a threshold to avert division by zero. Also \, signal division will cause massive amplitude gains. Be careful of your ears and equipment. Start the amplitude very low (-100dB) and slowly work up to an acceptable level. A pad is provided to balance gain between normal and invert options., f 83; #X text 278 360 <= scaling exponent (lower values increase amplitude) ; #X obj 129 515 ./gain.dsp~; #X obj 39 30 ./icon; #X text 369 61 - Spectral multiplication; #X obj 350 30 cnv 15 100 30 empty empty fftease/taint~ 20 12 0 24 -262144 -1 0; #X connect 0 0 8 3; #X connect 1 0 0 0; #X connect 2 0 8 2; #X connect 3 0 8 0; #X connect 7 0 2 0; #X connect 8 0 13 0; #X connect 9 0 8 0; #X connect 10 0 8 1; pd-fftease-3.0.1/fftease-helpfiles/thresher~-help.pd000077500000000000000000000050511401707710000224150ustar00rootroot00000000000000#N canvas 600 60 707 455 12; #X floatatom 289 323 6 0 0 0 - - -; #X floatatom 368 323 6 0 0 0 - - -; #N canvas 650 70 314 277 init 0; #X obj 51 39 loadbang; #X msg 51 97 \; thresher-thresh 0.17 \; thresher-damp 0.99 \; thresher-synt 0.001 \; thresher-transpose 0; #X connect 0 0 1 0; #X restore 136 381 pd init; #X obj 210 395 ./gain.dsp~; #X obj 371 297 hsl 128 15 0.5 1 0 0 empty thresher-damp empty -2 -8 0 10 -228856 -1 -1 12446 1; #X obj 292 266 hsl 128 15 0 0.5 0 0 empty thresher-thresh empty -2 -8 0 10 -228856 -1 -1 4318 1; #X text 389 297 damping factor; #X text 316 266 threshold; #X msg 127 243 mute \$1; #X obj 127 212 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1; #X obj 28 27 ./icon; #X text 397 60 - Damped bin-level feedback; #X text 30 90 [thresher~] sustains the amplitude and frequency in lower-energy FFT bins. The extent of this effect is controlled by the threshold parameter: at 0 all frames pass \, at higher values more frames are sustained. The feedback damping factor controls the decay time. A value of 1 results in an infinite freeze., f 66; #N canvas 650 70 509 414 oscbank 0; #X msg 79 64 oscbank \$1; #X msg 144 289 transpose \$1; #X obj 147 187 hsl 128 15 -1200 1200 0 0 empty thresher-transpose transpose -2 10 0 10 -228856 -1 -1 6350 1; #X msg 116 147 synthresh \$1; #X floatatom 116 122 5 0 0 0 - - -; #X obj 79 39 tgl 17 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1 ; #X obj 119 100 hsl 128 15 0 1 0 0 empty thresher-synt synthesis_threshold -2 10 0 10 -228856 -1 -1 13 1; #X obj 144 235 expr pow(2 \, ($f1/1200)); #X floatatom 144 210 7 0 0 0 - - -; #X floatatom 144 263 7 0 0 0 - - -; #X text 198 211 cents; #X text 202 264 ratio; #X obj 79 331 outlet; #X text 108 39 toggle oscbank: careful - raises volume; #X connect 0 0 12 0; #X connect 1 0 12 0; #X connect 2 0 8 0; #X connect 3 0 12 0; #X connect 4 0 3 0; #X connect 5 0 0 0; #X connect 6 0 4 0; #X connect 7 0 9 0; #X connect 8 0 7 0; #X connect 9 0 1 0; #X restore 244 221 pd oscbank; #X obj 210 175 noise~; #X text 427 265 (frames above are sustained); #X text 509 291 (the higher the factor \, the more sustain), f 23 ; #X msg 81 303 fftinfo; #X obj 210 355 fftease/thresher~ 512 4; #X text 464 185 see also:; #X obj 443 209 cnv 15 100 20 empty empty fftease/bthresher~ 20 12 0 14 -262144 -1 0; #X obj 379 28 cnv 15 100 30 empty empty fftease/thresher~ 20 12 0 24 -262144 -1 0; #X connect 0 0 18 1; #X connect 1 0 18 2; #X connect 4 0 1 0; #X connect 5 0 0 0; #X connect 8 0 18 0; #X connect 9 0 8 0; #X connect 13 0 18 0; #X connect 14 0 18 0; #X connect 17 0 18 0; #X connect 18 0 3 0; pd-fftease-3.0.1/fftease-helpfiles/vacancy~-help.pd000077500000000000000000000037641401707710000222260ustar00rootroot00000000000000#N canvas 600 60 558 490 12; #X floatatom 360 356 5 0 0 0 - - -; #N canvas 650 70 450 300 control 0; #X msg 35 141 rms \$1; #X obj 35 38 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1 1 ; #X obj 115 63 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X msg 115 141 invert \$1; #X obj 209 96 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1 1; #X msg 209 141 swapphase \$1; #X obj 35 217 outlet; #X text 54 36 track RMS; #X text 135 60 invert threshold; #X text 226 94 swap phase source; #X connect 0 0 6 0; #X connect 1 0 0 0; #X connect 2 0 3 0; #X connect 3 0 6 0; #X connect 4 0 5 0; #X connect 5 0 6 0; #X restore 66 337 pd control; #X obj 160 237 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1; #X obj 160 257 t f f; #X obj 160 287 ./sfplay~; #X obj 261 287 ./sfplay~; #X obj 160 387 fftease/vacancy~, f 29; #X obj 160 419 ./gain.dsp~; #X obj 42 24 ./icon; #X text 269 60 - Spectral compositing; #X obj 250 31 cnv 15 100 30 empty empty fftease/vacancy~ 20 12 0 24 -262144 -1 0; #X text 53 88 [vacancy~] performs spectral compositing. The threshold controls the compositing. Useful values lie in the range from -90 dB to 90 dB. Threshold inversion is available via the invert message. The threshold can also track the current RMS value of of the signal. In RMS tracking mode \, the useful threshold range will be somewhat different depending upon the character of the input signals. Phases will be derived from the left input unless phase swapping is specified. In this case phases will be taken from the right input signal when the threshold test is true. Best results are obtained when both source files are normalized., f 65; #X text 377 239 see also:; #X obj 356 263 cnv 15 100 20 empty empty fftease/ether~ 20 12 0 14 -262144 -1 0; #X text 357 334 threshold; #X obj 356 286 cnv 15 100 20 empty empty fftease/leaker~ 20 12 0 14 -262144 -1 0; #X connect 0 0 6 2; #X connect 1 0 6 0; #X connect 2 0 3 0; #X connect 3 0 4 0; #X connect 3 1 5 0; #X connect 4 0 6 0; #X connect 5 0 6 1; #X connect 6 0 7 0; pd-fftease-3.0.1/fftease-helpfiles/xsyn~-help.pd000077500000000000000000000011731401707710000215730ustar00rootroot00000000000000#N canvas 600 60 534 358 12; #X obj 87 286 ./gain.dsp~; #X obj 87 166 ./sfplay~; #X obj 182 167 ./sfplay~; #X obj 87 240 fftease/xsyn~, f 14; #X obj 54 29 ./icon; #X text 309 54 - Cross synthesis; #X obj 267 28 cnv 15 100 30 empty empty fftease/xsyn~ 20 12 0 24 -262144 -1 0; #X text 301 214 see also:; #X obj 280 238 cnv 15 100 20 empty empty fftease/swinger~ 20 12 0 14 -262144 -1 0; #X text 49 100 [xsyn~] filters the first input with the second input \, creating a spectral cross synthesis effect. The leftmost sound will provide the phase information (pitch material).; #X connect 1 0 3 0; #X connect 2 0 3 1; #X connect 3 0 0 0; pd-fftease-3.0.1/fftease-meta.pd000066400000000000000000000002671401707710000164210ustar00rootroot00000000000000#N canvas 15 49 195 101 10; #N canvas 285 484 420 300 META 0; #X text 10 25 AUTHOR ericlyon@vt.edu; #X text 13 41 NAME FFTease; #X text 10 10 VERSION 3.0.1; #X restore 10 10 pd META; pd-fftease-3.0.1/fftease.h000066400000000000000000000120171401707710000153150ustar00rootroot00000000000000/* FFTease for Pd */ #include #include #include #include #include #include "m_pd.h" #define MAX_N 1073741824 #define MAX_Nw MAX_N #ifndef FFTEASE_VERSION # define FFTEASE_VERSION "3.0.1" #endif #ifndef FFTEASE_COMPILE_DATE # define FFTEASE_COMPILE_DATE __DATE__ #endif #define FFTEASE_ANNOUNCEMENT "<[ FFTease " FFTEASE_VERSION " ]> | " #define FFTEASE_VERSION4PD "FFTease " FFTEASE_VERSION " for Pd" #define fftease_announce(objname) post("%s ( %s )",FFTEASE_ANNOUNCEMENT,objname) #define fftease_version(objectname) post("%s: version %s compiled %s",objectname,FFTEASE_VERSION4PD,FFTEASE_COMPILE_DATE); #define BIGGER_THAN_MSP_VECTOR 0 #define SMALLER_THAN_MSP_VECTOR 1 #define EQUAL_TO_MSP_VECTOR 2 #define FFTEASE_DEFAULT_FFTSIZE 1024 #define FFTEASE_DEFAULT_OVERLAP 8 #define FFTEASE_DEFAULT_WINFAC 1 #define DEFAULT_FFTEASE_FFTSIZE 1024 #define FFTEASE_MAX_FFTSIZE 1073741824 #define FFTEASE_OSCBANK_SCALAR (0.25) #define FFTEASE_OSCBANK_TABLESIZE (8192) #define FFTEASE_BYPASS_GAIN (0.5) #define FFT_FORWARD 1 #define FFT_INVERSE -1 #ifndef PIOVERTWO #define PIOVERTWO 1.5707963268 #endif #ifndef TWOPI #define TWOPI 6.2831853072 #endif #ifndef PI #define PI 3.14159265358979 #endif typedef struct _fftease { int R; int N; int N2; int Nw; int Nw2; int D; int in_count; int out_count; t_float *Wanal; t_float *Wsyn; t_float *input; t_float *Hwin; t_float *buffer; t_float *channel; t_float *output; // for convert t_float *c_lastphase_in; t_float *c_lastphase_out; t_float c_fundamental; t_float c_factor_in; t_float c_factor_out; // for oscbank int NP; t_float P; int L; int first; t_float Iinv; t_float *lastamp; t_float *lastfreq; t_float *bindex; t_float *table; t_float pitch_increment; t_float ffac; int hi_bin; int lo_bin; // for fast fft t_float mult; t_float *trigland; int *bitshuffle; int overlap; int winfac; int last_overlap; // save values to test if memory reallocation needed int last_winfac; int last_N; int last_R; t_float synt; t_float *internalInputVector; // hold input data from smaller MSP buffers t_float *internalOutputVector; // hold output data for smaller MSP buffers int operationRepeat; // how many times to do whatever on each perform call int operationCount; // keep track of where we are in buffer operation int bufferStatus; // relations between MSP vector size and internal buffer size int MSPVectorSize; // what it says short obank_flag; // resynthesis method flag short init_status; // whether initialization has successfully occurred short noalias; // inhibit aliasing in oscbank mode t_float nyquist; // nyquest frequency == R/2 short initialized; // set to 0 for the first time in new(); after that it will be 1 } t_fftease; void fftease_convert(t_fftease *fft); void fftease_unconvert(t_fftease *fft); void fftease_rfft( t_float *x, int N, int forward ); void fftease_cfft( t_float *x, int NC, int forward ); void fftease_bitreverse( t_float *x, int N ); void fftease_fold( t_fftease *fft ); void fftease_init_rdft(int n, int *ip, t_float *w); void fftease_rdft(t_fftease *fft, int isgn); void fftease_makewt(int nw, int *ip, t_float *w); void fftease_makect(int nc, int *ip, t_float *c); void fftease_leanconvert(t_fftease *fft); void fftease_leanunconvert(t_fftease *fft); void fftease_makewindows( t_float *H, t_float *A, t_float *S, int Nw, int N, int I ); void fftease_makehamming( t_float *H, t_float *A, t_float *S, int Nw, int N, int I,int odd ); void fftease_makehanning( t_float *H, t_float *A, t_float *S, int Nw, int N, int I,int odd ); void fftease_overlapadd(t_fftease *fft); void fftease_bloscbank( t_float *S, t_float *O, int D, t_float iD, t_float *lf, t_float *la, t_float *bindex, t_float *tab, int len, t_float synt, int lo, int hi ); void fftease_oscbank( t_fftease *fft ); int fftease_power_of_two(int test); void fftease_limit_fftsize(int *N, int *Nw, char *OBJECT_NAME); int fftease_fft_size(int testfft); void fftease_free(t_fftease *fft); void fftease_init(t_fftease *fft); int fftease_winfac(int winfac); int fftease_overlap(int overlap); void fftease_set_fft_buffers(t_fftease *fft); void fftease_fftinfo(t_fftease *fft, char *object_name); int fftease_msp_sanity_check(t_fftease *fft, char *oname); t_float fftease_randf(t_float min, t_float max); void fftease_noalias(t_fftease* fft, short flag); void fftease_oscbank_setbins(t_fftease *fft, t_float lowfreq, t_float highfreq); void fftease_limited_oscbank(t_fftease *fft, int osclimit, t_float framethresh); t_float fftease_randf(t_float min, t_float max); // Penrose extras t_float fftease_frequencyToIncrement( t_float samplingRate, t_float frequency, int bufferLength ); void fftease_makeSineBuffer( t_float *buffer, int bufferLength ); t_float fftease_bufferOscil( t_float *phase, t_float increment, t_float *buffer, int bufferLength ); float fftease_rrand(int *seed); float fftease_prand(int *seed); pd-fftease-3.0.1/fftease_setup.c000066400000000000000000000001521401707710000165250ustar00rootroot00000000000000void fftease_setup(void) { // post("Loaded FFTease Library"); // printf("Loaded FFTease Library(2)"); } pd-fftease-3.0.1/fftease_utilities.c000066400000000000000000000221301401707710000174000ustar00rootroot00000000000000#include "fftease.h" #define FFTEASE_LIB_VERSION "FFTease library 3.0" void fftease_noalias(t_fftease* fft, short flag) { fft->noalias = flag; } int fftease_fft_size( int testfft ) { int test = 2; if( testfft <= 0 ) return DEFAULT_FFTEASE_FFTSIZE; while( test < testfft && test < FFTEASE_MAX_FFTSIZE){ test *= 2; } if( test != testfft ){ post("incorrect FFT size specified, using %d", DEFAULT_FFTEASE_FFTSIZE); test = DEFAULT_FFTEASE_FFTSIZE; } if( test == FFTEASE_MAX_FFTSIZE){ post("fftsize capped at maximum: %d", test); } return test; } void fftease_set_fft_buffers(t_fftease *fft) { if( fft->D <= 0 || fft->MSPVectorSize <= 0 ){ return; } // post("setting up FFTease buffers"); fft->operationCount = 0; if( fft->D > fft->MSPVectorSize ){ fft->operationRepeat = fft->D / fft->MSPVectorSize; fft->bufferStatus = BIGGER_THAN_MSP_VECTOR; // post("fftease_set_fft_buffers: bigger than MSP vector"); } else if( fft->D < fft->MSPVectorSize ){ fft->operationRepeat = fft->MSPVectorSize / fft->D; fft->bufferStatus = SMALLER_THAN_MSP_VECTOR; // post("fftease_set_fft_buffers: smaller than MSP buffer"); } else { fft->operationRepeat = 1; fft->bufferStatus = EQUAL_TO_MSP_VECTOR; // post("fftease_set_fft_buffers: equal to MSP buffer"); } } int fftease_overlap( int overlap ) { int target = 1; while( target < overlap && target < 64 ){ target *= 2; } if( target != overlap ){ error("fftease_overlap: %d is not a legal overlap factor",overlap); return 1; } return overlap; } int fftease_winfac( int winfac) { int target = 1; while( target < winfac && target < 64 ){ target *= 2; } if( target != winfac ){ // error("%d is not a legal window factor", winfac); return 1; } return winfac; } void fftease_oscbank_setbins(t_fftease *fft, t_float lowfreq, t_float highfreq) { if(fft->initialized == -1){ post("oscbank setbins inhibited"); return; } t_float curfreq = 0; fft->hi_bin = 1; int N2 = fft->N2; while(curfreq < highfreq){ ++(fft->hi_bin); curfreq += fft->c_fundamental; } fft->lo_bin = 0; curfreq = 0; while(curfreq < lowfreq){ ++(fft->lo_bin); curfreq += fft->c_fundamental; } if(fft->hi_bin > N2) fft->hi_bin = N2; // post("lowfreq %f highfreq %f low bin %d high bin %d",lowfreq, highfreq, fft->lo_bin, fft->hi_bin); } void fftease_init(t_fftease *fft) { int i; int mem; if(fft->initialized == -1){ // post("fftease_init manually aborted with initialization status -1"); return; } if(!fft->R){ // post("fftease_init: zero sample rate, aborting init"); return; } // fft->init_status = 0; fft->overlap = fftease_overlap(fft->overlap); fft->winfac = fftease_winfac(fft->winfac); if(fft->P <= 0) fft->P = 1.0; fft->N = fftease_fft_size( fft->N ); fft->D = fft->N / fft->overlap; fft->Nw = fft->N * fft->winfac; fft->Iinv = 1.0/fft->D; fft->N2 = fft->N / 2; fft->Nw2 = fft->Nw / 2; fft->in_count = -(fft->Nw); fft->out_count = fft->in_count; fft->mult = 1.0 / (t_float) fft->N; fft->c_fundamental = (t_float) fft->R/(t_float) fft->N; fft->c_factor_in = (t_float) fft->R/((t_float)fft->D * TWOPI); fft->c_factor_out = TWOPI * (t_float) fft->D / (t_float) fft->R; // fft->synt = 0.001; fft->L = FFTEASE_OSCBANK_TABLESIZE; fft->pitch_increment = fft->P * fft->L / fft->R; fft->ffac = fft->P * PI / fft->N; fft->nyquist = (t_float) fft->R / 2.0; if(! fft->initialized){ // post("Initializing FFT Memory"); fft->P = 1.0; fft->obank_flag = 0; // default no oscbank fft->lo_bin = 0; fft->hi_bin = fft->N2; mem = (fft->Nw) * sizeof(t_float); fft->Wanal = (t_float *) calloc(1,mem); fft->Wsyn = (t_float *) calloc(1,mem); fft->Hwin = (t_float *) calloc(1,mem); fft->input = (t_float *) calloc(1,mem); fft->output = (t_float *) calloc(1,mem); mem = (fft->N + 2) * sizeof(t_float); fft->buffer = (t_float *) calloc(1,mem); mem = (fft->N + 2) * sizeof(t_float); fft->channel = (t_float *) calloc(1,mem); mem = (fft->N * 2) * sizeof(int); fft->bitshuffle = (int *) calloc(1,mem); mem = (fft->N*2)*sizeof(t_float); fft->trigland = (t_float *) calloc(1,mem); mem = (fft->N2+1)*sizeof(t_float); fft->c_lastphase_in = (t_float *) calloc(1,mem); fft->c_lastphase_out = (t_float *)calloc(1,mem); // oscbank stuff mem = (fft->N+1)*sizeof(t_float); fft->lastamp = (t_float *) calloc(1,mem); fft->lastfreq = (t_float *) calloc(1,mem); fft->bindex = (t_float *) calloc(1,mem); mem = (2 + fft->L)*sizeof(t_float); // includes guardpoint fft->table = (t_float *) calloc(1,mem); // t_float buffering mem = fft->D * sizeof(t_float); fft->internalInputVector = (t_float *) calloc(1,mem); fft->internalOutputVector = (t_float *) calloc(1,mem); fft->initialized = 1; } else if( (fft->N == fft->last_N) && (fft->overlap == fft->last_overlap) && (fft->winfac == fft->last_winfac) && (fft->last_R == fft->R) ) { //post("fftease_init: no change in vital parameters so memory reallocation skipped"); return; } else { // post("Resizing FFT Memory"); mem = (fft->Nw)*sizeof(t_float); fft->Wanal = (t_float *) realloc((void *) fft->Wanal, mem); fft->Wsyn = (t_float *) realloc((void *) fft->Wsyn, mem); fft->Hwin = (t_float *)realloc((void *) fft->Hwin, mem); fft->input = (t_float *) realloc((void *) fft->input, mem); fft->output = (t_float *) realloc((void *) fft->output, mem); mem = (fft->N + 2)*sizeof(t_float); fft->buffer = (t_float *) realloc((void *) fft->buffer, mem); mem = (fft->N+2)*sizeof(t_float); fft->channel = (t_float *) realloc((void *) fft->channel, mem); mem = (fft->N*2)*sizeof(int); fft->bitshuffle = (int *) realloc((void *) fft->bitshuffle, mem); mem = (fft->N*2)*sizeof(t_float); fft->trigland = (t_float *) realloc((void *) fft->trigland, mem); mem = (fft->N2+1)*sizeof(t_float); fft->c_lastphase_in = (t_float *) realloc((void *) fft->c_lastphase_in, mem); fft->c_lastphase_out = (t_float *)realloc((void *)fft->c_lastphase_out, mem); mem = (fft->N+1)*sizeof(t_float); fft->lastamp = (t_float *) realloc((void *) fft->lastamp, mem); fft->lastfreq = (t_float *) realloc((void *) fft->lastfreq, mem); fft->bindex = (t_float *) realloc((void *) fft->bindex, mem); mem = fft->D * sizeof(t_float); fft->internalInputVector = (t_float *)realloc((void *) fft->internalInputVector, mem); fft->internalOutputVector = (t_float *) realloc((void *) fft->internalOutputVector, mem); } fft->last_N = fft->N; fft->last_overlap = fft->overlap; fft->last_winfac = fft->winfac; fft->last_R = fft->R; for ( i = 0; i < fft->L; i++ ) { fft->table[i] = (t_float) fft->N * cos((t_float)i * TWOPI / (t_float)fft->L); } fft->table[fft->L] = fft->table[fft->L - 1]; // guard point fftease_makewindows( fft->Hwin, fft->Wanal, fft->Wsyn, fft->Nw, fft->N, fft->D); fftease_init_rdft( fft->N, fft->bitshuffle, fft->trigland); fftease_set_fft_buffers(fft); fftease_oscbank_setbins(fft,0,fft->nyquist); fft->init_status = 1; } void fftease_free(t_fftease *fft) { if(fft->init_status == 1){ free(fft->trigland); free(fft->bitshuffle); free(fft->Wanal); free(fft->Wsyn); free(fft->Hwin); free(fft->buffer); free(fft->channel); // this is the killer free(fft->input); free(fft->output); free(fft->internalInputVector); free(fft->internalOutputVector); free(fft->c_lastphase_in); free(fft->c_lastphase_out); free(fft->lastamp); free(fft->lastfreq); free(fft->bindex); free(fft->table); } } void fftease_fftinfo(t_fftease *fft, char *object_name) { if( ! fft->overlap ){ post("%s: zero overlap!", object_name); return; } post("%s: FFT size %d, hop size %d, signal vector size %d, sample rate %d", object_name, fft->N, fft->N/fft->overlap, fft->MSPVectorSize, fft->R); // post("%s\n", FFTEASE_LIB_VERSION); } int fftease_msp_sanity_check(t_fftease *fft, char *oname) { if( fft->R <= 0 || fft->R > 10000000 || fft->MSPVectorSize <= 0 || fft->D <= 0){ post("%s is concerned that perhaps no audio driver has been loaded",oname); post("R: %d, vector size: %d, D: %d", fft->R, fft->MSPVectorSize, fft->D); return 0; } else { return 1; } } t_float fftease_randf(t_float min, t_float max) { t_float randv; randv = (t_float) (rand() % 32768) / 32768.0 ; return min + (max-min) * randv; } pd-fftease-3.0.1/fold.c000066400000000000000000000014071401707710000146200ustar00rootroot00000000000000#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 fftease_fold( t_fftease *fft ) { int Nw = fft->Nw; int N = fft->N; t_float *Wanal = fft->Wanal; t_float *input = fft->input; t_float *buffer = fft->buffer; int in_count = fft->in_count; int i; memset(buffer, 0.0, N * sizeof(t_float)); while ( in_count < 0 ) in_count += N; in_count %= N; for ( i = 0; i < Nw; i++ ) { buffer[in_count] += input[i] * Wanal[i]; if ( ++in_count == N ) in_count = 0; } fft->in_count = (fft->in_count + fft->D) % fft->Nw; } pd-fftease-3.0.1/leaker~.c000066400000000000000000000222551401707710000153410ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *leaker_class; #define OBJECT_NAME "leaker~" typedef struct _leaker { t_object x_obj; float x_f; t_fftease *fft; t_fftease *fft2; int *sieve; short mute; t_float fade_value; } t_leaker; static void leaker_dsp(t_leaker *x, t_signal **sp); static t_int *leaker_perform(t_int *w); static void leaker_free(t_leaker *x); static void *leaker_new(t_symbol *msg, short argc, t_atom *argv); static void leaker_upsieve(t_leaker *x) ; static void leaker_downsieve(t_leaker *x) ; static void leaker_randsieve(t_leaker *x) ; static void leaker_mute(t_leaker *x, t_floatarg state); static void leaker_init(t_leaker *x); void leaker_tilde_setup(void) { t_class *c; c = class_new(gensym("leaker~"), (t_newmethod)leaker_new, (t_method)leaker_free,sizeof(t_leaker), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_leaker, x_f); class_addmethod(c,(t_method)leaker_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)leaker_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)leaker_upsieve,gensym("upsieve"), 0); class_addmethod(c,(t_method)leaker_downsieve,gensym("downsieve"), 0); class_addmethod(c,(t_method)leaker_randsieve,gensym("randsieve"), 0); leaker_class = c; fftease_announce(OBJECT_NAME); } void leaker_free( t_leaker *x ){ fftease_free(x->fft); fftease_free(x->fft2); free(x->fft); free(x->fft2); free(x->sieve); } void leaker_upsieve(t_leaker *x) { int i; int *sieve = x->sieve; for( i = 0; i < x->fft->N2; i++ ){ sieve[i] = i + 1; } } void leaker_downsieve(t_leaker *x) { int i; int *sieve = x->sieve; int N2 = x->fft->N2; for( i = 0; i < N2; i++ ){ sieve[i] = N2 - i; } } void leaker_randsieve(t_leaker *x) { int i; int temp; int pos1, pos2; int N2 = x->fft->N2; int *sieve = x->sieve; int maxswap = N2 - 1; for( i = 0; i < N2; i++ ){ sieve[i] = i + 1; } while(maxswap > 0){ pos1 = maxswap; pos2 = rand() % (N2 - 1); temp = sieve[pos1]; sieve[pos1] = sieve[pos2]; sieve[pos2] = temp; --maxswap; } } void leaker_mute(t_leaker *x, t_floatarg state) { x->mute = (short)state; } void *leaker_new(t_symbol *msg, short argc, t_atom *argv) { t_fftease *fft, *fft2; 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")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); x->fft2 = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft2 = x->fft2; fft->initialized = 0; fft2->initialized = 0; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; fft2->N = FFTEASE_DEFAULT_FFTSIZE; fft2->overlap = FFTEASE_DEFAULT_OVERLAP; fft2->winfac = FFTEASE_DEFAULT_WINFAC; return x; } void leaker_init(t_leaker *x) { int i; t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; short initialized = fft->initialized; fftease_init(fft); fftease_init(fft2); if(!initialized) { x->mute = 0; x->fade_value = 0; x->sieve = (int *) calloc((fft->N2 + 1),sizeof(int)); } if(initialized != 2){ for(i = 0; i < fft->N2; i++){ x->sieve[i] = i; } } } static void do_leaker(t_leaker *x) { int i,odd,even; t_float a1,a2,b1,b2; t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int N2 = fft->N2; t_float *buffer1 = fft->buffer; t_float *buffer2 = fft2->buffer; t_float *channel1 = fft->channel; int *sieve = x->sieve; t_float fade_value = x->fade_value; fftease_fold(fft); fftease_fold(fft2); fftease_rdft(fft,1); fftease_rdft(fft2,1); 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) ); } } } fftease_rdft(fft,-1); fftease_overlapadd(fft); } t_int *leaker_perform(t_int *w) { int i,j; t_leaker *x = (t_leaker *) (w[1]); t_float *MSPInputVector1 = (t_float *)(w[2]); t_float *MSPInputVector2 = (t_float *)(w[3]); t_float *fade_value = (t_float *)(w[4]); t_float *MSPOutputVector = (t_float *)(w[5]); t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int MSPVectorSize = fft->MSPVectorSize; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; t_float *internalInputVector1 = fft->internalInputVector; t_float *internalInputVector2 = fft2->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; t_float *inputOne = fft->input; t_float *inputTwo = fft2->input; t_float *output = fft->output; int D = fft->D; int Nw = fft->Nw; t_float mult = fft->mult; int N2 = fft->N2; x->fade_value = *fade_value * (float) N2; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+6; } if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), MSPInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), MSPInputVector2, D * sizeof(t_float)); do_leaker(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw-D), MSPInputVector1 + (D*i), D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw-D), MSPInputVector2 + (D*i), D * sizeof(t_float)); do_leaker(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector1 + (operationCount * MSPVectorSize), MSPInputVector1, MSPVectorSize * sizeof(t_float)); memcpy(internalInputVector2 + (operationCount * MSPVectorSize), MSPInputVector2, MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize), MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), internalInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), internalInputVector2, D * sizeof(t_float)); do_leaker(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+6; } void leaker_dsp(t_leaker *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(!samplerate) return; if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); fft2->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft2); } if(fft->R != samplerate ){ fft->R = samplerate; fft2->R = samplerate; } if(reset_required){ leaker_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(leaker_perform, 5, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,sp[3]->s_vec); } } pd-fftease-3.0.1/leanconvert.c000066400000000000000000000010011401707710000162020ustar00rootroot00000000000000#include "fftease.h" void fftease_leanconvert(t_fftease *fft) { int real, imag, amp, phase; t_float a, b; int i; t_float *buffer = fft->buffer; t_float *channel = fft->channel; int N2 = fft->N2; for ( i = 0; i <= N2; i++ ) { imag = phase = ( real = amp = i<<1 ) + 1; a = ( i == N2 ? buffer[1] : buffer[real] ); b = ( i == 0 || i == N2 ? 0. : buffer[imag] ); channel[amp] = hypot( a, b ); channel[phase] = -atan2( b, a ); } } pd-fftease-3.0.1/leanunconvert.c000066400000000000000000000007351401707710000165620ustar00rootroot00000000000000#include "fftease.h" void fftease_leanunconvert(t_fftease *fft) { int real, imag, amp, phase; register int i; t_float *buffer = fft->buffer; t_float *channel = fft->channel; int N2 = fft->N2; for ( i = 0; i <= N2; i++ ) { imag = phase = ( real = amp = i<<1 ) + 1; buffer[real] = *(channel+amp) * cos( *(channel+phase) ); if ( i != N2 ) buffer[imag] = -*(channel+amp) * sin( *(channel+phase) ); } } pd-fftease-3.0.1/legacy.c000066400000000000000000000030301401707710000151320ustar00rootroot00000000000000#include "fftease.h" void old_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 ; } } void old_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; 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; } } void old_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 ); } } pd-fftease-3.0.1/limit_fftsize.c000066400000000000000000000014221401707710000165410ustar00rootroot00000000000000#include "fftease.h" extern void post(const char *fmt, ...); void fftease_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); *N = MAX_N; } if(*Nw > MAX_Nw){ // post("%s: Nw set to maximum window size of %d",OBJECT_NAME,MAX_Nw); *Nw = MAX_Nw; } } int fftease_FFT_size( int testfft ) { int test = 2; if( testfft <= 0 ) return DEFAULT_FFTEASE_FFTSIZE; while( test < testfft && test < FFTEASE_MAX_FFTSIZE){ test *= 2; } if( test != testfft ){ post("incorrect FFT size specified, using %d", test); } if( test == FFTEASE_MAX_FFTSIZE){ post("fftsize capped at maximum: %d", test); } return test; } pd-fftease-3.0.1/limited_oscbank.c000066400000000000000000000075371401707710000170350ustar00rootroot00000000000000#include "fftease.h" // extern void post(const char *fmt, ...); #define PARANOID 0 void fftease_limited_oscbank( t_fftease *fft, int osclimit, t_float framethresh) { int amp,freq,chan, n; t_float a,ainc,f,finc,address; int D = fft->D; int I = D; int L = fft->L; t_float synt = fft->synt; t_float P = fft->P; int R = fft->R; int N2 = fft->N2; t_float Iinv = 1./fft->D; t_float pitch_increment = fft->pitch_increment; t_float *table = fft->table; t_float *lastamp = fft->lastamp ; t_float *lastfreq = fft->lastfreq ; t_float *bindex = fft->bindex; t_float *channel = fft->channel; t_float *output = fft->output; int hi_bin = fft->hi_bin; int lo_bin = fft->lo_bin; t_float maxamp = 0.0; t_float localthresh, testamp; short noalias = fft->noalias; t_float nyquist = fft->nyquist; int oscnt = 0; #ifdef PARANOID if(! fft->init_status ){ // means memory alloc in effect goto exit; } #endif if(R == 0){ post("FFTeaseLib: limited oscbank got 0 SR"); return; } if(lo_bin < 0 || hi_bin > N2){ post("FFTeaseLib: limited oscbank: bad bins: %d %d",lo_bin,hi_bin); } pitch_increment = P * (t_float) L / (t_float) R; if( synt > 0.0 ){ maxamp = 0.0; for ( chan = lo_bin; chan < hi_bin; chan++ ){ amp = chan << 1; testamp = fabs( channel[amp] ); if( testamp > maxamp ) maxamp = testamp; } } if(maxamp > framethresh){ localthresh = synt * maxamp; } else { localthresh = synt * framethresh; // watch this line! } for ( chan = lo_bin; chan < hi_bin; chan++ ) { #ifdef PARANOID if(! fft->init_status ){ // means memory alloc in effect goto exit; } #endif freq = ( amp = ( chan << 1 ) ) + 1; if(noalias){ if( channel[freq] * P >= nyquist ) channel[amp] = 0; } if ( channel[amp] > localthresh ){ ++oscnt; #ifdef PARANOID if(! fft->init_status ){ // means memory alloc in effect goto exit; } #endif if(oscnt > osclimit){ goto exit; } channel[freq] *= pitch_increment; finc = ( channel[freq] - ( f = lastfreq[chan] ) )*Iinv; ainc = ( channel[amp] - ( a = lastamp[chan] ) )*Iinv; address = bindex[chan]; // this was the bug - somewhere bindex was not properly initialized! //i_address = (int) address; if( address < 0 || address >= L){ address = 0; // post("limited oscbank: bad address"); } for ( n = 0; n < I; n++ ) { #ifdef PARANOID if(! fft->init_status ){ // means memory alloc in effect goto exit; } #endif // this is a suspected bug line: /* iAddress = (int) address; if( iAddress == L ){ iAddress = L - 1; } if( iAddress < 0 || iAddress >= L ){ post("limited oscbank: bad address: %d", iAddress); } else { output[n] += a*table[ iAddress ]; } */ // skip excessive paranoia for efficiency output[n] += a*table[ (int) address ]; // this WILL go to L, so tab needs a guardpoint 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; } } exit:; } pd-fftease-3.0.1/makewindows.c000066400000000000000000000054421401707710000162270ustar00rootroot00000000000000#include "fftease.h" void fftease_makewindows( t_float *H, t_float *A, t_float *S, int Nw, int N, int I ) { int i ; t_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 ) { t_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++ ) { t_float afac = 2./sum ; t_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 fftease_makehamming( t_float *H, t_float *A, t_float *S, int Nw, int N, int I, int odd ) { int i; t_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 ) { t_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++ ) { t_float afac = 2./sum ; t_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 fftease_makehanning( t_float *H, t_float *A, t_float *S, int Nw, int N, int I, int odd ) { int i; t_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 ) { t_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++ ) { t_float afac = 2./sum ; t_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 ; } } pd-fftease-3.0.1/mindwarp~.c000066400000000000000000000256151401707710000157220ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *mindwarp_class; #define OBJECT_NAME "mindwarp~" #define MAX_WARP 16.0 typedef struct _mindwarp { t_object x_obj; float x_f; t_fftease *fft; t_float warpFactor; t_float shapeWidth; t_float *newChannel; t_float *channelOne; t_float *newAmplitudes; short mute; } t_mindwarp; static void mindwarp_dsp(t_mindwarp *x, t_signal **sp); static t_int *mindwarp_perform(t_int *w); static void *mindwarp_new(t_symbol *s, int argc, t_atom *argv); static void mindwarp_init(t_mindwarp *x); static void mindwarp_free(t_mindwarp *x); static void mindwarp_mute(t_mindwarp *x, t_floatarg toggle); void mindwarp_tilde_setup(void) { t_class *c; c = class_new(gensym("mindwarp~"), (t_newmethod)mindwarp_new, (t_method)mindwarp_free,sizeof(t_mindwarp), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_mindwarp, x_f); class_addmethod(c,(t_method)mindwarp_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)mindwarp_mute,gensym("mute"),A_FLOAT,0); mindwarp_class = c; fftease_announce(OBJECT_NAME); } void *mindwarp_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft; 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")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; /* args: warpfactor, shape width, overlap, window factor */ x->warpFactor = 1.0; x->shapeWidth = 3.0; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv); } fft->initialized = 0;// prepare for init in DSP routine return x; } void mindwarp_init(t_mindwarp *x) { short initialized = x->fft->initialized; fftease_init(x->fft); if(!initialized){ x->mute = 0; x->newAmplitudes = (t_float *)calloc(((x->fft->N2 + 1) * 16), sizeof(t_float)); x->newChannel = (t_float *)calloc (2*(x->fft->N + 1), sizeof(t_float)); x->channelOne = (t_float *)calloc (2*(x->fft->N + 1), sizeof(t_float)); } else if(initialized == 1) { x->newAmplitudes = (t_float *)realloc(x->newAmplitudes, ((x->fft->N2 + 1) * 16) * sizeof(t_float)); x->newChannel = (t_float *)realloc(x->newChannel, 2*(x->fft->N + 1) * sizeof(t_float)); x->channelOne = (t_float *)realloc(x->newChannel, 2*(x->fft->N + 1) * sizeof(t_float)); } } void mindwarp_free(t_mindwarp *x) { short initialized = x->fft->initialized; fftease_free(x->fft); free(x->fft); if(initialized){ free(x->newAmplitudes); free(x->newChannel); free(x->channelOne); } } static void copyArray(t_float*src, t_float*dst, size_t size, size_t zerosize) { size_t i; for(i=0; inewChannel; t_fftease *fft = x->fft; t_float *newAmplitudes = x->newAmplitudes; t_float *channelOne = x->channelOne; int i,j, bindex, N = fft->N, N2 = fft->N2, Nw = fft->Nw, shapeWidth = (int) x->shapeWidth, remainingWidth, newLength; float cutoff = N2 * .9, filterMult = .00001, interpIncr, interpPhase; t_float warpFactor; fftease_fold(fft); fftease_rdft(fft,FFT_FORWARD); fftease_leanconvert(fft); warpFactor = x->warpFactor; if(warpFactor <= 0){ error("bad warp, resetting"); warpFactor = 1.0; } newLength = (int) ((t_float) N2 / warpFactor); if(newLength <= 0){ error("bad length: resetting"); newLength = 1.0; } interpIncr = (t_float) N2 / (t_float) newLength; interpPhase = 0.; // copy from incoming FFT channel to a larger channel, allowing for spectral spread memcpy(channelOne, fft->channel, (N+2) * sizeof(t_float)); // zero pad the larger channel for(i = N + 2; i < (2 * N) + 2; i++){ channelOne[i] = 0.0; } // do simple linear interpolation on magnitudes for ( bindex=0; bindex < newLength; bindex++ ) { int localbindex = ((int) interpPhase) << 1; t_float lower = *(channelOne + localbindex), upper = *(channelOne + localbindex + 2), diff = interpPhase - ( (t_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; } } // 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 ) { t_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; t_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; } // copy from temporary channel back to working FFT channel memcpy(fft->channel, channelOne, (N+2) * sizeof(t_float)); fftease_leanunconvert(fft); fftease_rdft(fft,FFT_INVERSE); fftease_overlapadd(fft); } t_int *mindwarp_perform(t_int *w) { t_mindwarp *x = (t_mindwarp *) (w[1]); t_float *MSPInputVector = (t_float *)(w[2]); t_float *vec_warpFactor = (t_float *)(w[3]); t_float *vec_shapeWidth = (t_float *)(w[4]); t_float *MSPOutputVector = (t_float *)(w[5]); t_fftease *fft = x->fft; int i, j; int D = fft->D; int Nw = fft->Nw; t_float mult = fft->mult; t_float *input = fft->input; t_float *output = fft->output; int MSPVectorSize = fft->MSPVectorSize; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+6; } x->warpFactor = *vec_warpFactor; x->shapeWidth = *vec_shapeWidth; if(x->warpFactor <= 0.0625){ x->warpFactor = 1.0; // error("%s: zero warp factor is illegal",OBJECT_NAME); } if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_mindwarp(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_mindwarp(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_mindwarp(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+6; } void mindwarp_mute(t_mindwarp *x, t_floatarg toggle) { x->mute = (short)toggle; } void mindwarp_dsp(t_mindwarp *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ mindwarp_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(mindwarp_perform, 5, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); } } pd-fftease-3.0.1/morphine~.c000066400000000000000000000275051401707710000157220ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *morphine_class; #define OBJECT_NAME "morphine~" typedef struct _pickme { int bin; float value; } t_pickme; typedef struct _morphine { t_object x_obj; t_float x_f; t_fftease *fft; t_fftease *fft2; t_pickme *picks; t_pickme *mirror; t_float morphIndex; t_float exponScale; short mute; } t_morphine; static void morphine_dsp(t_morphine *x, t_signal **sp); static t_int *morphine_perform(t_int *w); static void *morphine_new(t_symbol *s, int argc, t_atom *argv); static void morphine_transition(t_morphine *x, t_floatarg f); static void morphine_free(t_morphine *x); static void morphine_mute(t_morphine *x, t_floatarg toggle); static void morphine_init(t_morphine *x); void quicksort(t_pickme *a,int first,int last); void morphine_tilde_setup(void) { t_class *c; c = class_new(gensym("morphine~"), (t_newmethod)morphine_new, (t_method)morphine_free,sizeof(t_morphine), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_morphine, x_f); class_addmethod(c,(t_method)morphine_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)morphine_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)morphine_transition,gensym("transition"), A_FLOAT, 0); morphine_class = c; fftease_announce(OBJECT_NAME); } void morphine_transition(t_morphine *x, t_floatarg f) { x->exponScale = f; } void *morphine_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft, *fft2; 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")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); x->fft2 = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft2 = x->fft2; fft->initialized = 0; fft2->initialized = 0; x->exponScale = -5.0; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; fft2->N = FFTEASE_DEFAULT_FFTSIZE; fft2->overlap = FFTEASE_DEFAULT_OVERLAP; fft2->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = fft2->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = fft2->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void quicksort(t_pickme *a,int first,int last) { int i, j, pivot; t_pickme tmp_pick; if(first a[pivot].value) j--; if(ifft; t_fftease *fft2 = x->fft2; short initialized = fft->initialized; fftease_init(fft); fftease_init(fft2); if(!initialized){ x->morphIndex = 0.; x->mute = 0; x->picks = (t_pickme *) calloc((fft->N2+1), sizeof(t_pickme)); x->mirror = (t_pickme *) calloc((fft->N2+1), sizeof(t_pickme)); } else if(x->fft->initialized == 1) { x->picks = (t_pickme *) realloc(x->picks, (fft->N2+1) * sizeof(t_pickme)); x->mirror = (t_pickme *) realloc(x->mirror, (fft->N2+1) * sizeof(t_pickme)); } } static void do_morphine(t_morphine *x) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int i; int lookupIndex,even, odd; t_float mult, morphIndex, exponScale, a1, b1, a2, b2; t_float *bufferOne = fft->buffer; t_float *bufferTwo = fft2->buffer; t_float *channelOne = fft->channel; t_float *channelTwo = fft2->channel; int N2 = fft->N2; t_pickme *picks = x->picks; t_pickme *mirror = x->mirror; mult = fft->mult; morphIndex = x->morphIndex; exponScale = x->exponScale; fftease_fold(fft); fftease_fold(fft2); /* do an fft */ fftease_rdft(fft,1); fftease_rdft(fft2,1); /* 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; } /* implement quick sort, low to high, on picks */ quicksort(picks, 0, N2); /* 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) ); } fftease_rdft(fft,-1); fftease_overlapadd(fft); } t_int *morphine_perform(t_int *w) { int i, j; t_morphine *x = (t_morphine *) (w[1]); t_float *MSPInputVector1 = (t_float *)(w[2]); t_float *MSPInputVector2 = (t_float *)(w[3]); t_float *vec_morphIndex = (t_float *)(w[4]); t_float *MSPOutputVector = (t_float *)(w[5]); t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int MSPVectorSize = fft->MSPVectorSize; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; t_float *internalInputVector1 = fft->internalInputVector; t_float *internalInputVector2 = fft2->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; t_float *inputOne = fft->input; t_float *inputTwo = fft2->input; t_float *output = fft->output; int D = fft->D; int Nw = fft->Nw; t_float mult = fft->mult; t_float morphIndex = x->morphIndex; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+6; } morphIndex = *vec_morphIndex; if ( morphIndex < 0 ) morphIndex = 0.; else { if ( morphIndex > 1. ) morphIndex = 1.; } x->morphIndex = morphIndex; if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), MSPInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), MSPInputVector2, D * sizeof(t_float)); do_morphine(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw-D), MSPInputVector1 + (D*i), D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw-D), MSPInputVector2 + (D*i), D * sizeof(t_float)); do_morphine(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector1 + (operationCount * MSPVectorSize), MSPInputVector1, MSPVectorSize * sizeof(t_float)); memcpy(internalInputVector2 + (operationCount * MSPVectorSize), MSPInputVector2, MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize), MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), internalInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), internalInputVector2, D * sizeof(t_float)); do_morphine(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+6; } void morphine_free(t_morphine *x) { if(x->fft->initialized){ free(x->picks); free(x->mirror); } fftease_free(x->fft); fftease_free(x->fft2); free(x->fft); free(x->fft2); } void morphine_mute(t_morphine *x, t_floatarg toggle) { x->mute = (short)toggle; } void morphine_dsp(t_morphine *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(!samplerate) return; if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); fft2->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft2); } if(fft->R != samplerate ){ fft->R = samplerate; fft2->R = samplerate; } if(reset_required){ morphine_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(morphine_perform, 5, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,sp[3]->s_vec); } } pd-fftease-3.0.1/multyq~.c000066400000000000000000000305731401707710000154330ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *multyq_class; #define OBJECT_NAME "multyq~" typedef struct _multyq { t_object x_obj; t_float x_f; t_fftease *fft; t_float cf1; t_float gainfac1; t_float bw1; t_float cf2; t_float gainfac2; t_float bw2; t_float cf3; t_float gainfac3; t_float bw3; t_float cf4; t_float gainfac4; t_float bw4; t_float *rcos; t_float *filt; t_float *freqs; int rcoslen; short please_update; short always_update; short mute; } t_multyq; static void multyq_dsp(t_multyq *x, t_signal **sp); static t_int *multyq_perform(t_int *w); static void *multyq_new(t_symbol *s, int argc, t_atom *argv); static void multyq_mute(t_multyq *x, t_floatarg state); static void update_filter_function(t_multyq *x); static void multyq_init(t_multyq *x); static void multyq_free(t_multyq *x); static void filtyQ( float *S, float *C, float *filtfunc, int N2 ); void multyq_tilde_setup(void) { t_class *c; c = class_new(gensym("multyq~"), (t_newmethod)multyq_new, (t_method)multyq_free,sizeof(t_multyq), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_multyq, x_f); class_addmethod(c,(t_method)multyq_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)multyq_mute,gensym("mute"),A_FLOAT,0); multyq_class = c; fftease_announce(OBJECT_NAME); } void multyq_free(t_multyq *x) { if(x->fft->initialized){ free(x->rcos); free(x->freqs); free(x->filt); } fftease_free(x->fft); free(x->fft); } void *multyq_new(t_symbol *s, int argc, t_atom *argv) { int i; t_fftease *fft; 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")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft->R = sys_getsr(); fft->MSPVectorSize = sys_getblksize(); fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; fft->initialized = 0; if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void multyq_init(t_multyq *x) { int i; t_float funda, base; t_fftease *fft = x->fft; short initialized = fft->initialized; fftease_init(fft); if(!initialized){ x->please_update = 0; x->always_update = 0; x->rcoslen = 8192 ; x->rcos = (t_float *) calloc(x->rcoslen, sizeof( t_float )); x->freqs = (t_float *) calloc(fft->N2, sizeof( t_float )); x->filt = (t_float *) calloc((fft->N2 + 1), sizeof( t_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; for (i = 0; i < x->rcoslen; i++){ x->rcos[i] = .5 - .5 * cos(((float)i/(float)x->rcoslen) * TWOPI); } } else { x->freqs = (t_float *) realloc(x->freqs, fft->N2 * sizeof( t_float )); x->filt = (t_float *) realloc(x->filt, (fft->N2 + 1) * sizeof( t_float )); } x->fft->input = (t_float *)realloc(fft->input, fft->Nw * sizeof(t_float)); x->fft->output = (t_float *)realloc(fft->output, fft->Nw * sizeof(t_float)); funda = base = (t_float)fft->R /(t_float)fft->N ; for(i = 0; i < fft->N2; i++){ x->freqs[i] = base; base += funda; } update_filter_function(x); } static void do_multyq(t_multyq *x) { int real, imag, amp, phase; t_float a, b; int i; t_fftease *fft = x->fft; t_float *S = fft->buffer; t_float *C = fft->channel; t_float *filtfunc = x->filt; int N2 = fft->N2; fftease_fold(fft); fftease_rdft(fft,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) ); } fftease_rdft(fft,-1); fftease_overlapadd(fft); } t_int *multyq_perform(t_int *w) { int i, j; t_multyq *x = (t_multyq *) (w[1]); t_float *MSPInputVector = (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 *in5 = (t_float *)(w[6]); t_float *in6 = (t_float *)(w[7]); t_float *in7 = (t_float *)(w[8]); t_float *in8 = (t_float *)(w[9]); t_float *in9 = (t_float *)(w[10]); t_float *in10 = (t_float *)(w[11]); t_float *in11 = (t_float *)(w[12]); t_float *in12 = (t_float *)(w[13]); t_float *in13 = (t_float *)(w[14]); t_float *MSPOutputVector = (t_float *)(w[15]); t_fftease *fft = x->fft; int D = fft->D; int Nw = fft->Nw; t_float *input = fft->input; t_float *output = fft->output; t_float mult = fft->mult; int MSPVectorSize = fft->MSPVectorSize; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; 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; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+16; } update_filter_function(x); if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_multyq(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_multyq(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_multyq(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+16; } void multyq_mute(t_multyq *x, t_floatarg state) { x->mute = (short)state; } void update_filter_function(t_multyq *x) { t_float lo, hi ; t_float ploc, gainer; int i; t_float nyquist = (float)x->fft->R / 2.0; t_float *filt = x->filt; t_float *rcos = x->rcos; t_float *freqs = x->freqs; int rcoslen = x->rcoslen; int N2 = x->fft->N2; // 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 < 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 < 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 < 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 < 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 < 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 ; } } } void filtyQ( float *S, float *C, float *filtfunc, int N2 ) { int real, imag, amp, phase; t_float a, b; int i; 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) ); } } void multyq_dsp(t_multyq *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ multyq_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(multyq_perform, 15, 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); } } pd-fftease-3.0.1/oscbank.c000066400000000000000000000050661401707710000153210ustar00rootroot00000000000000#include "fftease.h" void fftease_oscbank( t_fftease *fft ) { int amp,freq,chan, n; t_float a,ainc,f,finc,address; int D = fft->D; int I = D; int L = fft->L; t_float synt = fft->synt; t_float P = fft->P; int R = fft->R; t_float Iinv = 1./fft->D; t_float pitch_increment = fft->pitch_increment; t_float *table = fft->table; t_float *lastamp = fft->lastamp ; t_float *lastfreq = fft->lastfreq ; t_float *bindex = fft->bindex; t_float *channel = fft->channel; t_float *output = fft->output; int hi_bin = fft->hi_bin; int lo_bin = fft->lo_bin; t_float maxamp = 0.0; t_float localthresh, testamp; short noalias = fft->noalias; t_float nyquist = fft->nyquist; if(! fft->init_status ){ // means memory alloc in effect goto exit; } if(R == 0){ post("oscbank got 0 SR"); return; } pitch_increment = P * (t_float) L / (t_float) R; if( synt > 0.0 ){ maxamp = 0.0; for ( chan = lo_bin; chan < hi_bin; chan++ ){ amp = chan << 1; testamp = fabs( channel[amp] ); if( testamp > maxamp ) maxamp = testamp; } } localthresh = synt * maxamp; for ( chan = lo_bin; chan < hi_bin; chan++ ) { if(! fft->init_status ){ // means memory alloc in effect goto exit; } freq = ( amp = ( chan << 1 ) ) + 1; if(noalias){ if( channel[freq] * P >= nyquist ) channel[amp] = 0; } if ( channel[amp] > localthresh ){ channel[freq] *= pitch_increment; finc = ( channel[freq] - ( f = lastfreq[chan] ) )*Iinv; ainc = ( channel[amp] - ( a = lastamp[chan] ) )*Iinv; address = bindex[chan]; if( address < 0 || address >= L){ address = 0.0; // post("limited oscbank: bad address"); } for ( n = 0; n < I; n++ ) { // taking this out now: if(! fft->init_status ){ // means memory alloc in effect goto exit; } 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; } } exit:; } pd-fftease-3.0.1/overlapadd.c000066400000000000000000000013161401707710000160140ustar00rootroot00000000000000/* * 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 fftease_overlapadd(t_fftease *fft) { t_float *buffer = fft->buffer; int N = fft->N; t_float *Wsyn = fft->Wsyn; t_float *output = fft->output; int Nw = fft->Nw; int out_count = fft->out_count; int i ; while ( out_count < 0 ) out_count += N ; out_count %= N ; for ( i = 0 ; i < Nw ; i++ ) { output[i] += buffer[out_count] * Wsyn[i]; if ( ++out_count == N ) out_count = 0 ; } fft->out_count = (fft->out_count + fft->D) % fft->Nw; } pd-fftease-3.0.1/pd-lib-builder/000077500000000000000000000000001401707710000163215ustar00rootroot00000000000000pd-fftease-3.0.1/pd-lib-builder/CHANGELOG.txt000066400000000000000000000066431401707710000203620ustar00rootroot00000000000000Changelog for Makefile.pdlibbuilder. v0.6.0, dated 2019-12-21 - detect target platform (OS and architecture) rather than build platform (#55) - introduce optional user variable 'PLATFORM' for cross compilation - no longer build OSX/MacOS fat binaries by default (#21, #50) - do build fat binaries when 'extension=d_fat' is specified for OSX/MacOS - fix bug where minimum OSX/MacOS version wasn't defined, and set it to 10.6 v0.5.1, dated 2018-03-15 Fixes and improvements for Windows builds: - properly evaluate variables 'PDDIR' and 'PDBINDIR' to find pd.dll - define default path of 32 bit Pd on 64 bit Windows - link C++ externals with standard C libs on Windows, they don't load otherwise - strip installed Windows binaries by default (issues #34, #39, #41, #42 respectively) Warning for all platforms: variable 'PD_PATH' is no longer supported, use the equivalent 'PDDIR'. v0.5.0, dated 2018-01-23 Implement target architecture detection for Windows builds, and set appropriate options for 32 and 64 bit (used to be for 32 bit only). (feature, issue #37 #38, merge commit 215bf3e) v0.4.4, dated 2016-11-22 Use variable 'system' when evaluating 'for{Linux,Darwin,Windows}' (bugfix, issue #31, commit 2c14110) v0.4.3, dated 2016-11-02 Replace flags '-fpic' by 'fPIC'. (bugfix, issue #29, commit 426b38b) v0.4.2, dated 2016-10-30 Fix issue where incorrect message about m_pd.h is given. (bugfix, commit 2e13d8f) v0.4.1, dated 2016-10-27 Respect cflag for minimum OSX version when defined by lib makefile. (bugfix, pull request #22, commit 48c4127) v0.4.0, dated 2016-10-14 Introduced path variables PDDIR, PDINCLUDEDIR, PDBINDIR, PDLIBDIR which can also be defined in environment. (feature, issue #27, commit b0dab72) v0.3.1, dated 2016-10-13 Fix bug where pd.dll wouldn't be found. (bugfix, commit a0c87be) v0.3.0, dated 2016-10-09 Variable 'PD_PATH' introduced for pd-extended / pd-l2ork compatibility. (feature, issue #26, commit 41e9743) v0.2.8, dated 2016-10-09 Allow installed files to contain weird characters (notably '$'). (bugfix, pull request #20, commit 5b920b1) v0.2.7, dated 2016-10-04 Remove all default pd search paths except vanilla's. (discussion, issue #25, commit a6a89dc) v0.2.6, dated 2016-09-20 Redefined dependency checking so it won't stall rebuilds on OSX. (bugfix, issue #16, commit 9fd1795) v0.2.5, dated 2016-06-26 Fixed dependency checking for object files in other directories. (bugfix, commit f06e550) v0.2.4, dated 2016-06-25 Fixed regression bug that disabled all dependency checking. (bugfix, commit 1d7bb5e) v0.2.3, dated 2016-03-29 Disabled dependency checking for OSX <= 10.5 because it stalled rebuilds. (bugfix, issue #16, commit eb614fd) v0.2.2, dated 2016-03-28 Removed target 'pre' because it forced rebuild of everything in 'all'. (bugfix, issue #17, commit c989c8e) v0.2.1, dated 2015-12-27 Implement / respect 'CPPFLAGS','CFLAGS'and 'LDFLAGS'. (bugfix, issue #5, commit 98f3582) v0.2.0, dated 2015-12-19 Added per-platform multiline defines 'forLinux', 'forDarwin', 'forWindows'. (feature, pull request #9, commit 3946ea5) v0.1.0, dated 2015-12-08 Added targets 'pre' and 'post' to automatically run before and after 'all'. (feature, pull request #4, commit a5678ac) v0.0.2, dated 2015-12-06 Improved methods for searching pd paths. (bugfix, commit ed37e6b) v0.0.1, dated 2015-10-31 Fixed expansion of variable 'lib.version'. (bugfix, issue #1, commit 974b617) v0.0.0, dated 2015-06-24 Initial version. (commit 16517a2) pd-fftease-3.0.1/pd-lib-builder/Makefile.pdlibbuilder000066400000000000000000001270261401707710000224310ustar00rootroot00000000000000# Makefile.pdlibbuilder dated 2019-12-21 version = 0.6.0 # Helper makefile for Pure Data external libraries. # Written by Katja Vetter March-June 2015 for the public domain. No warranties. # Inspired by Hans Christoph Steiner's Makefile Template and Stephan Beal's # ShakeNMake. # # Grab the newest version of Makefile.pdlibbuilder from # https://github.com/pure-data/pd-lib-builder/ # # GNU make version >= 3.81 required. # # #=== characteristics =========================================================== # # # - defines build settings based on autodetected OS and architecture # - defines rules to build Pd class- or lib executables from C or C++ sources # - defines rules for libdir installation # - defines convenience targets for developer and user # - evaluates implicit dependencies for non-clean builds # # #=== basic usage =============================================================== # # # In your Makefile, define your Pd lib name and class files, and include # Makefile.pdlibbuilder at the end of the Makefile. Like so: # # ________________________________________________________________________ # # # Makefile for mylib # # lib.name = mylib # # class.sources = myclass1.c myclass2.c # # datafiles = myclass1-help.pd myclass2-help.pd README.txt LICENSE.txt # # include Makefile.pdlibbuilder # ________________________________________________________________________ # # # For files in class.sources it is assumed that class basename == source file # basename. The default target builds all classes as individual executables # with Pd's default extension for the platform. For anything more than the # most basic usage, continue reading. # # #=== list of Makefile.pdlibbuilder API variables =============================== # # # Variables available for definition in your library Makefile: # # - lib.name # - lib.setup.sources # - class.sources # - common.sources # - shared.sources # - .class.sources # - .class.ldflags # - .class.ldlibs # - cflags # - ldflags # - ldlibs # - datafiles # - datadirs # - makefiles # - makefiledirs # - externalsdir # # Optional multiline defines evaluated per operating system: # # - forLinux # - forDarwin # - forWindows # # Variables available for your makefile or make command line: # # - make-lib-executable # - suppress-wunused # # Path variables for make command line or environment: # # - PDDIR # - PDINCLUDEDIR # - PDBINDIR # - PDLIBDIR # # Standard make variables for make command line or environment: # # - CPPFLAGS # - CFLAGS # - LDFLAGS # - CC # - CXX # - INSTALL # - STRIP # - DESTDIR # # Optional user variables for make command line or environment: # # - PLATFORM # # Deprecated path variables: # # - pdincludepath # - pdbinpath # - objectsdir # # #=== descriptions of Makefile.pdlibbuilder API variables ======================= # # # lib.name: # Name of the library directory as it will be installed / distributed. Also the # name of the lib executable in the case where all classes are linked into # a single binary. # # lib.setup.sources: # Source file(s) (C or C++) which must be compiled only when linking all classes # into a single lib binary. # # class.sources: # All sources files (C or C++) for which the condition holds that # class name == source file basename. # # .class.sources: # Source file(s) (C or C++) specific to class . Use this for # multiple-source classes or when class name != source file basename. # # common.sources: # Source file(s) which must be statically linked to each class in the library. # # shared.sources: # Source file(s) (C or C++) to build a shared dynamic link lib, to be linked # with all class executables. # # cflags, ldflags, ldlibs: # Define cflags (preprocessor&compiler), ldflags (linker) and ldlibs (dynamic # link libs) for the whole library. These flags are added to platform-specific # flags defined by Makefile.pdlibbuilder. # # .class.ldflags and .class.ldlibs: # Define ldflags resp. ldlibs specific to class . These flags are # added to platform-specific flags defined by Makefile.pdlibbuilder, and flags # defined in your Makefile for the whole library. Note: cflags can not be # defined per class in the current implementation. # # datafiles and datadirs: # All extra files you want to include in binary distributions of the # library: abstractions and help patches, example patches, meta patch, readme # and license texts, manuals, sound files, etcetera. Use 'datafiles' for all # files that should go into your lib rootdir and 'datadirs' for complete # directories you want to copy from source to distribution. # # forLinux, forDarwin, forWindows: # Shorthand for 'variable definitions for Linux only' etc. Use like: # define forLinux # cflags += -DLINUX # class.sources += linuxthing.c # endef # # makefiles and makefiledirs: # Extra makefiles or directories with makefiles that should be made in sub-make # processes. # # make-lib-executable: # When this variable is defined 'yes' in your makefile or as command argument, # Makefile.pdlibbuilder will try to build all classes into a single library # executable (but it will force exit if lib.setup.sources is undefined). # If your makefile defines 'make-lib-executable=yes' as the library default, # this can still be overridden with 'make-lib-executable=no' as command argument # to build individual class executables (the Makefile.pdlibbuilder default.) # # suppress-wunused: # When this variable is defined ('yes' or any other value), -Wunused-variable, # -Wunused-parameter, -Wunused-value and -Wunused-function are suppressed, # but the other warnings from -Wall are retained. # # PDDIR: # Root directory of 'portable' pd package. When defined, PDINCLUDEDIR and # PDBINDIR will be evaluated as $(PDDIR)/src and $(PDDIR)/bin. # # PDINCLUDEDIR: # Directory where Pd API m_pd.h should be found, and other Pd header files. # Overrides the default search path. # # PDBINDIR: # Directory where pd.dll should be found for linking (Windows only). Overrides # the default search path. # # PDLIBDIR: # Root directory for installation of Pd library directories. Overrides the # default install location. # # DESTDIR: # Prepended path component for staged install. # # PLATFORM: # Target platform for cross compilation in the form of GNU triplet: # cpu-vendor-os. Example: x86_64-w64-mingw32. This specifies the tool chain that # pdlibbuilder will use, if installed and locatable. System and architecture # will then be autodefined accordingly. In most cases no other variables need to # be overridden. # # CPPFLAGS: # Preprocessor flags which are not strictly required for building. # # CFLAGS: # Compiler flags which are not strictly required for building. Compiler flags # defined by Makefile.pdlibbuilder for warning, optimization and architecture # specification are overriden by CFLAGS. # # LDFLAGS: # Linker flags which are not strictly required for building. Linker flags # defined by Makefile.pdlibbuilder for architecture specification are overriden # by LDFLAGS. # # CC and CXX: # C and C++ compiler programs as defined in your build environment. # # INSTALL # Definition of install program. # # STRIP # Name of strip program. Default 'strip' can be overridden in cross compilation # environments. # # objectsdir: # Root directory for installation of Pd library directories, like PDLIBDIR but # not overridable by environment. Supported for compatibility with pd-extended # central makefile, but deprecated otherwise. # # pdincludepath, pdbinpath: # As PDINCLUDEDIR and PDBINDIR but not overridable by environment. Deprecated # as user variables. # # #=== paths ===================================================================== # # # Source files in directories other than current working directory must be # prefixed with their relative path. Do not rely on VPATH or vpath. # Object (.o) files are built in the directory of their source files. # Executables are built in current working directory. # # Default search path for m_pd.h and other API header files is platform # dependent, and overridable by PDINCLUDEDIR: # # Linux: /usr/include/pd # # OSX: /Applications/Pd*.app/Contents/Resources/src # # Windows: %PROGRAMFILES%/Pd/src # %PROGRAMFILES(X86)%/Pd/src (32 bit builds on 64 bit Windows) # # Default search path for binary pd.dll (Windows), overridable by PDBINDIR # # %PROGRAMFILES%/Pd/bin # %PROGRAMFILES(X86)%/Pd/bin (32 bit builds on 64 bit Windows) # # Default location to install pd libraries is platform dependent, and # overridable by PDLIBDIR: # # Linux: /usr/local/lib/pd-externals # OSX: ~/Library/Pd # Windows: %APPDATA%/Pd # # https://puredata.info/docs/faq/how-do-i-install-externals-and-help-files # The rationale for not installing to ~/pd-externals by default on Linux # is that some people share the home dir between 32 and 64 bit installations. # # #=== targets =================================================================== # # # all: build $(executables) plus optional post target # post: target to build after $(executables) # alldebug: build all with -g option turned on for debug symbols # : force clean build of an individual class # .pre: make preprocessor output file in current working directory # .lst: make asm/source output file in current working directory # # install: install executables and data files # clean: remove build products from source tree # # help: print help text # vars: print makefile variables # allvars: print all variables # depend: print generated prerequisites # dumpmachine: print compiler output of option '-dumpmachine' # coffee: dummy target # # Variable $(executables) expands to class executables plus optional shared lib, # or alternatively to single lib executable when make-lib-executable=true. # Targets pre and post can be defined by library makefile. Make sure to include # Makefile.pdlibbuilder first so default target all will not be redefined. # # #=== Pd-extended libdir concept ================================================ # # # For libdir layout as conceived by Hans-Christoph Steiner, see: # # https://puredata.info/docs/developer/Libdir # # Files README.txt, LICENSE.txt and -meta.pd are part of the libdir # convention. Help patches for each class and abstraction are supposed to be # available. Makefile.pdlibbuilder does not force the presence of these files # however. It does not automatically include such files in libdir installations. # Data files you want to include in distributions must be defined explicitly in # your Makefile. # # #=== Makefile.pdlibbuilder syntax conventions ================================== # # # Makefile.pdlibbuilder variable names are lower case. Default make variables, # environment variables, and standard user variables (CC, CXX, CFLAGS, DESTDIR) # are upper case. Use target 'allvars' to print all variables and their values. # # 'Fields' in data variables are separated by dots, like in 'foo.class.sources'. # Words in variables expressing a function or command are separated by dashes, # like in 'make-lib-executable'. # # #=== useful make options ======================================================= # # # Use 'make -d ' to print debug details of the make process. # Use 'make -p ' to print make's database. # # #=== TODO ====================================================================== # # # - decide whether to use -static-libgcc or shared dll in MinGW # - cygwin support # - android support # - figure out how to handle '$' in filenames # - add makefile template targets dpkg-source dist libdir distclean tags? # # #=== end of documentation sections ============================================= # # ################################################################################ ################################################################################ ################################################################################ # GNU make version 3.81 (2006) or higher is required because of the following: # - function 'info' # - variable '.DEFAULT_GOAL' # force exit when make version is < 3.81 ifneq ($(firstword $(sort 3.81 $(MAKE_VERSION))), 3.81) $(error GNU make version 3.81 or higher is required) endif # Relative path to externals root dir in multi-lib source tree like # pd-extended SVN. Default is parent of current working directory. May be # defined differently in including makefile. externalsdir ?= .. # variable you can use to check if Makefile.pdlibbuilder is already included Makefile.pdlibbuilder = true ################################################################################ ### target platform detection ################################################## ################################################################################ #=== target platform =========================================================== # PLATFORM: optional user variable to define target platform for cross # compilation. Redefine build tools accordingly. PLATFORM should match # the exact target prefix of tools present in $PATH, like x86_64-w64-mingw32, # x86_64-apple-darwin12 etc. Tool definitions are exported to ensure submakes # will get the same. ifneq ($(PLATFORM),) ifneq ($(findstring darwin, $(PLATFORM)),) export CC = $(PLATFORM)-cc export CXX = $(PLATFORM)-c++ export CPP = $(PLATFORM)-cc else export CC = $(PLATFORM)-gcc export CXX = $(PLATFORM)-g++ export CPP = $(PLATFORM)-cpp endif STRIP = $(PLATFORM)-strip endif # Let (native or cross-) compiler report target triplet and isolate individual # words therein to facilitate later processing. target.triplet := $(subst -, ,$(shell $(CC) -dumpmachine)) #=== operating system ========================================================== # The following systems are defined: Linux, Darwin, Windows. GNU and # GNU/kFreeBSD are treated as Linux to get the same options. ifneq ($(filter linux gnu% kfreebsd, $(target.triplet)),) system = Linux endif ifneq ($(filter darwin%, $(target.triplet)),) system = Darwin endif ifneq ($(filter mingw% cygwin%, $(target.triplet)),) system = Windows endif # evaluate possible system-specific multiline defines from library makefile $(eval $(for$(system))) # TODO: Cygwin, Android #=== architecture ============================================================== # The following CPU names can be processed by pdlibbuilder: # i*86 Intel 32 bit # x86_64 Intel 64 bit # arm ARM 32 bit # aarch64 ARM 64 bit target.arch := $(firstword $(target.triplet)) ################################################################################ ### variables per platform ##################################################### ################################################################################ #=== flags per architecture ==================================================== # Set architecture-dependent cflags, mainly for Linux. For Mac and Windows, # arch.c.flags are overriden below. To see gcc's default architecture flags: # $ gcc -Q --help=target # ARMv6: Raspberry Pi 1st gen, not detectable from target.arch ifeq ($(shell uname), armv6l) arch.c.flags = -march=armv6 -mfpu=vfp -mfloat-abi=hard # ARMv7: Beagle, Udoo, RPi2 etc. else ifeq ($(target.arch), arm) arch.c.flags = -march=armv7-a -mfpu=vfpv3 -mfloat-abi=hard # ARMv8 64 bit, not tested yet else ifeq ($(target.arch), aarch64) arch.c.flags = -mcpu=cortex-a53 # Intel 32 bit, build with SSE and SSE2 instructions else ifneq ($(filter i%86, $(target.arch)),) arch.c.flags = -march=pentium4 -mfpmath=sse -msse -msse2 # Intel/AMD 64 bit, build with SSE, SSE2 and SSE3 instructions else ifeq ($(target.arch), x86_64) arch.c.flags = -march=core2 -mfpmath=sse -msse -msse2 -msse3 # if none of the above architectures detected else arch.c.flags = endif #=== flags and paths for Linux ================================================= ifeq ($(system), Linux) prefix = /usr/local libdir := $(prefix)/lib pkglibdir = $(libdir)/pd-externals pdincludepath := $(wildcard /usr/include/pd) extension = pd_linux cpp.flags := -DUNIX c.flags := -fPIC c.ldflags := -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags c.ldlibs := -lc -lm cxx.flags := -fPIC -fcheck-new cxx.ldflags := -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags cxx.ldlibs := -lc -lm -lstdc++ shared.extension = so shared.ldflags = -rdynamic -fPIC -shared -Wl,-soname,$(shared.lib) endif #=== flags and paths for Darwin ================================================ # LLVM-clang doesn't support -fcheck-new, therefore this flag is only used when # compiling with g++. ifeq ($(system), Darwin) pkglibdir = $(HOME)/Library/Pd pdincludepath := $(firstword $(wildcard \ /Applications/Pd*.app/Contents/Resources/src)) extension = pd_darwin cpp.flags := -DUNIX -DMACOSX -I /sw/include c.flags := c.ldflags := -undefined suppress -flat_namespace -bundle c.ldlibs := -lc cxx.ldflags := -undefined suppress -flat_namespace -bundle cxx.ldlibs := -lc shared.extension = dylib shared.ldflags = -dynamiclib -undefined dynamic_lookup \ -install_name @loader_path/$(shared.lib) \ -compatibility_version 1 -current_version 1.0 ifneq ($(filter %g++, $(CXX)),) cxx.flags := -fcheck-new endif ifeq ($(extension), d_fat) arch := i386 x86_64 else arch := $(target.arch) endif ifneq ($(filter -mmacosx-version-min=%, $(cflags)),) version.flag := $(filter -mmacosx-version-min=%, $(cflags)) else version.flag = -mmacosx-version-min=10.6 endif arch.c.flags := $(addprefix -arch , $(arch)) $(version.flag) arch.ld.flags := $(arch.c.flags) endif #=== flags and paths for Windows =============================================== # Standard paths on Windows contain spaces, and GNU make functions treat such # paths as lists, with unintended effects. Therefore we must use shell function # ls instead of make's wildcard when probing for a path, and use double quotes # when specifying a path in a command argument. # Default paths in Mingw / Mingw-w64 environments. 'PROGRAMFILES' is standard # location for builds with native architecture, 'ProgramFiles(x86)' for i686 # builds on x86_64 Windows (detection method by Lucas Cordiviola). Curly braces # required because of parentheses in variable name. ifeq ($(system), Windows) pkglibdir := $(APPDATA)/Pd ifeq ($(target.arch), i686) programfiles := ${ProgramFiles(x86)} else programfiles := $(PROGRAMFILES) endif pdbinpath := $(programfiles)/Pd/bin pdincludepath := $(programfiles)/Pd/src endif # Store default path to pd.dll in PDBINDIR if the latter is not user-defined. # For include path this is done in the platform-independent paths section below, # but for PDBINDIR it is done here so ld flags can be evaluated as immediate # variables. ifeq ($(system), Windows) ifdef PDDIR PDBINDIR := $(PDDIR)/bin endif PDBINDIR ?= $(pdbinpath) endif # TODO: decide whether -mms-bitfields should be specified. ifeq ($(system), Windows) cpp.flags := -DMSW -DNT ifeq ($(target.arch), i686) arch.c.flags := -march=pentium4 -msse -msse2 -mfpmath=sse else ifeq ($(target.arch), x86_64) cpp.flags := -DMSW -DNT -DPD_LONGINTTYPE=__int64 arch.c.flags := -march=core2 -msse -msse2 -msse3 -mfpmath=sse else arch.c.flags = endif extension = dll c.flags := c.ldflags := -static-libgcc -shared \ -Wl,--enable-auto-import "$(PDBINDIR)/pd.dll" c.ldlibs := cxx.flags := -fcheck-new cxx.ldflags := -static-libgcc -static-libstdc++ -shared \ -Wl,--enable-auto-import "$(PDBINDIR)/pd.dll" cxx.ldlibs := shared.extension = dll shared.ldflags := -static-libgcc -shared "$(PDBINDIR)/pd.dll" stripflags = --strip-all endif #=== paths ===================================================================== # Platform-dependent default paths are specified above, but overridable. # Path variables in upper case can be defined as make command argument or in the # environment. Variable 'objectsdir' is supported for compatibility with # the build system that pd-l2ork has inherited from pd-extended. PDINCLUDEDIR ?= $(pdincludepath) PDLIBDIR ?= $(firstword $(objectsdir) $(pkglibdir)) ifdef PDDIR PDINCLUDEDIR := $(wildcard $(PDDIR)/src) endif # base path where all components of the lib will be installed by default installpath := $(DESTDIR)$(PDLIBDIR)/$(lib.name) # check if include path contains spaces (as is often the case on Windows) # if so, store the path so we can later do checks with it pdincludepathwithspaces := $(if $(word 2, $(PDINCLUDEDIR)), $(PDINCLUDEDIR)) #=== accumulated build flags =================================================== # From GNU make docs: 'Users expect to be able to specify CFLAGS freely # themselves.' So we use CFLAGS to define options which are not strictly # required for compilation: optimizations, architecture specifications, and # warnings. CFLAGS can be safely overriden using a make command argument. # Variables cflags, ldflags and ldlibs may be defined in including makefile. optimization.flags = -O3 -ffast-math -funroll-loops -fomit-frame-pointer warn.flags = -Wall -Wextra -Wshadow -Winline -Wstrict-aliasing # suppress -Wunused-variable & Co if you don't want to clutter a build log ifdef suppress-wunused warn.flags += $(addprefix -Wno-unused-, function parameter value variable) endif CFLAGS = $(warn.flags) $(optimization.flags) $(arch.c.flags) # preprocessor flags cpp.flags := -DPD -I "$(PDINCLUDEDIR)" $(cpp.flags) $(CPPFLAGS) # flags for dependency checking (cflags from makefile may define -I options) depcheck.flags := $(cpp.flags) $(cflags) # architecture specifications for linker are overridable by LDFLAGS LDFLAGS := $(arch.ld.flags) # now add the same ld flags to shared dynamic lib shared.ldflags += $(LDFLAGS) # accumulated flags for C compiler / linker c.flags := $(cpp.flags) $(c.flags) $(cflags) $(CFLAGS) c.ldflags := $(c.ldflags) $(ldflags) $(LDFLAGS) c.ldlibs := $(c.ldlibs) $(ldlibs) # accumulated flags for C++ compiler / linker cxx.flags := $(cpp.flags) $(cxx.flags) $(cflags) $(CFLAGS) cxx.ldflags := $(cxx.ldflags) $(ldflags) $(LDFLAGS) cxx.ldlibs := $(cxx.ldlibs) $(ldlibs) ################################################################################ ### variables: library name and version ######################################## ################################################################################ # strip possibles spaces from lib.name, they mess up calculated file names lib.name := $(strip $(lib.name)) # if meta file exists, check library version metafile := $(wildcard $(lib.name)-meta.pd) ifdef metafile lib.version := $(shell sed -n \ 's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' \ $(metafile)) endif ################################################################################ ### variables: files ########################################################### ################################################################################ #=== sources =================================================================== # (re)define .class.sources using file names in class.sources define add-class-source $(notdir $(basename $v)).class.sources += $v endef $(foreach v, $(class.sources), $(eval $(add-class-source))) # derive class names from .class.sources variables sourcevariables := $(filter %.class.sources, $(.VARIABLES)) classes := $(basename $(basename $(sourcevariables))) # accumulate all source files specified in makefile classes.sources := $(sort $(foreach v, $(sourcevariables), $($v))) all.sources := $(classes.sources) $(lib.setup.sources) \ $(shared.sources) $(common.sources) #=== object files ============================================================== # construct object filenames from all C and C++ source file names classes.objects := $(addsuffix .o, $(basename $(classes.sources))) common.objects := $(addsuffix .o, $(basename $(common.sources))) shared.objects := $(addsuffix .o, $(basename $(shared.sources))) lib.setup.objects := $(addsuffix .o, $(basename $(lib.setup.sources))) all.objects = $(classes.objects) $(common.objects) $(shared.objects) \ $(lib.setup.objects) #=== executables =============================================================== # construct class executable names from class names classes.executables := $(addsuffix .$(extension), $(classes)) # Construct shared lib executable name if shared sources are defined. If # extension and shared extension are not identical, use both to facilitate co- # installation for different platforms, like .m_i386.dll and .m_amd64.dll. ifdef shared.sources ifeq ($(extension), $(shared.extension)) shared.lib = lib$(lib.name).$(shared.extension) else shared.lib = lib$(lib.name).$(extension).$(shared.extension) endif else shared.lib := endif ################################################################################ ### variables: tools ########################################################### ################################################################################ # aliases so we can later define 'compile-$1' and set 'c' or 'cxx' as argument compile-c := $(CC) compile-cxx := $(CXX) ################################################################################ ### checks ##################################################################### ################################################################################ # At this point most variables are defined. Now do some checks and info's # before rules begin. # print Makefile.pdlibbuilder version before possible termination $(info ++++ info: using Makefile.pdlibbuilder version $(version)) # Terminate if target triplet remained empty, to avoid all sorts of confusing # scenarios and spurious bugs. ifeq ($(target.triplet),) $(error Command "$(CC) -dumpmachine" did not return a target triplet, \ needed for a build. \ Is compiler "$(CC)" installed in your PATH? ($(PATH)). \ Does compiler "$(CC)" support option "-dumpmachine"?) endif # 'forward declaration' of default target, needed to do checks all: # To avoid unpredictable results, make sure the default target is not redefined # by including makefile. ifneq ($(.DEFAULT_GOAL), all) $(error Default target must be 'all'.) endif # find out which target(s) will be made ifdef MAKECMDGOALS goals := $(MAKECMDGOALS) else goals := all endif # store path to Pd API m_pd.h if it is found ifdef PDINCLUDEDIR mpdh := $(shell ls "$(PDINCLUDEDIR)/m_pd.h") endif # store path to pd.dll; if not found, ls will give a useful error ifeq ($(system), Windows) pddll := $(shell ls "$(PDBINDIR)/pd.dll") endif # when making target all, check if m_pd.h is found and print info about it ifeq ($(goals), all) $(if $(mpdh), \ $(info ++++ info: using Pd API $(mpdh)), \ $(warning Where is Pd API m_pd.h? Do 'make help' for info.)) endif # print target info $(info ++++ info: making target $(goals) $(if $(lib.name),in lib $(lib.name))) # when installing, print installpath info $(if $(filter install install-lib, $(goals)), $(info ++++ info: \ installpath is '$(installpath)')) #=== define executables ======================================================== # By default we build class executables, and optionally a shared dynamic link # lib. When make-lib-executable=yes we build all classes into a single lib # executable, on the condition that variable lib.setup.sources is defined. ifeq ($(make-lib-executable),yes) $(if $(lib.setup.sources), ,\ $(error Can not build library blob because lib.setup.sources is undefined)) executables := $(lib.name).$(extension) else executables := $(classes.executables) $(shared.lib) endif ################################################################################ ### rules: special targets ##################################################### ################################################################################ # Disable built-in rules. If some target can't be built with the specified # rules, it should not be built at all. MAKEFLAGS += --no-builtin-rules .PRECIOUS: .SUFFIXES: .PHONY: all post build-lib \ $(classes) $(makefiledirs) $(makefiles) \ install install-executables install-datafiles install-datadirs \ force clean vars allvars depend help ################################################################################ ### rules: build targets ####################################################### ################################################################################ # Target all forces the build of targets [$(executables) post] in # deterministic order. Target $(executables) builds class executables plus # optional shared lib or alternatively a single lib executable when # make-lib-executable=true. Target post is optionally defined by # library makefile. all: post post: $(executables) all: $(info ++++info: target all in lib $(lib.name) completed) # build all with -g option turned on for debug symbols alldebug: c.flags += -g alldebug: cxx.flags += -g alldebug: all #=== class executable ========================================================== # recipe for linking objects in class executable # argument $1 = compiler type (c or cxx) # argument $2 = class basename define link-class $(compile-$1) \ $($1.ldflags) $($2.class.ldflags) \ -o $2.$(extension) \ $(addsuffix .o, $(basename $($2.class.sources))) \ $(addsuffix .o, $(basename $(common.sources))) \ $($1.ldlibs) $($2.class.ldlibs) $(shared.lib) endef # general rule for linking object files in class executable %.$(extension): $(shared.lib) $(info ++++ info: linking objects in $@ for lib $(lib.name)) $(if $(filter %.cc %.cpp, $($*.class.sources)), \ $(call link-class,cxx,$*), \ $(call link-class,c,$*)) #=== library blob ============================================================== # build all classes into single executable build-lib: $(lib.name).$(extension) $(info ++++ info: library blob $(lib.name).$(extension) completed) # recipe for linking objects in lib executable # argument $1 = compiler type (c or cxx) define link-lib $(compile-$1) \ $($1.ldflags) $(lib.ldflags) \ -o $(lib.name).$(extension) $(all.objects) \ $($1.ldlibs) $(lib.ldlibs) endef # rule for linking objects in lib executable # declared conditionally to avoid name clashes ifeq ($(make-lib-executable),yes) $(lib.name).$(extension): $(all.objects) $(if $(filter %.cc %.cpp, $(all.sources)), \ $(call link-lib,cxx), \ $(call link-lib,c)) endif #=== shared dynamic lib ======================================================== # recipe for linking objects in shared executable # argument $1 = compiler type (c or cxx) define link-shared $(compile-$1) \ $(shared.ldflags) \ -o $(shared.lib) $(shared.objects) \ $($1.ldlibs) $(shared.ldlibs) endef # rule for linking objects in shared executable # build recipe is in macro 'link-shared' $(shared.lib): $(shared.objects) $(info ++++ info: linking objects in shared lib $@) $(if $(filter %.cc %.cpp, $(shared.sources)), \ $(call link-shared,cxx), \ $(call link-shared,c)) #=== object files ============================================================== # recipe to make .o file from source # argument $1 is compiler type (c or cxx) define make-object-file $(info ++++ info: making $@ in lib $(lib.name)) $(compile-$1) \ $($1.flags) \ -o $@ -c $< endef # Three rules to create .o files. These are double colon 'terminal' rules, # meaning they are the last in a rules chain. %.o:: %.c $(call make-object-file,c) %.o:: %.cc $(call make-object-file,cxx) %.o:: %.cpp $(call make-object-file,cxx) #=== explicit prerequisites for class executables ============================== # For class executables, prerequisite rules are declared in run time. Target # 'depend' prints these rules for debugging purposes. # declare explicit prerequisites rule like 'class: class.extension' # argument $v is class basename define declare-class-target $v: $v.$(extension) endef # declare explicit prerequisites rule like 'class.extension: object1.o object2.o' # argument $v is class basename define declare-class-executable-target $v.$(extension): $(addsuffix .o, $(basename $($v.class.sources))) \ $(addsuffix .o, $(basename $(common.sources))) endef # evaluate explicit prerequisite rules for all classes $(foreach v, $(classes), $(eval $(declare-class-target))) $(foreach v, $(classes), $(eval $(declare-class-executable-target))) #=== implicit prerequisites for class executables ============================== # Evaluating implicit prerequisites (header files) with help from the # preprocessor is 'expensive' so this is done conditionally and selectively. # Note that it is also possible to trigger a build via install targets, in # which case implicit prerequisites are not checked. # When the Pd include path contains spaces it will mess up the implicit # prerequisites rules. disable-dependency-tracking := $(strip $(pdincludepathwithspaces)) ifndef disable-dependency-tracking must-build-everything := $(filter all, $(goals)) must-build-class := $(filter $(classes), $(goals)) must-build-sources := $(foreach v, $(must-build-class), $($v.class.sources)) endif # declare implicit prerequisites rule like 'object.o: header1.h header2.h ...' # argument $1 is input source file(s) # dir is explicitly added because option -MM strips it by default define declare-object-target $(dir $1)$(filter %.o: %.h, $(shell $(CPP) $(depcheck.flags) -MM $1)) $(MAKEFILE_LIST) endef # evaluate implicit prerequisite rules when rebuilding everything ifdef must-build-everything $(if $(wildcard $(all.objects)), \ $(info ++++ info: evaluating implicit prerequisites in lib $(lib.name).....) \ $(foreach v, $(all.sources), $(eval $(call declare-object-target, $v)))) endif # evaluate implicit prerequisite rules when selectively building classes ifdef must-build-class $(foreach v, $(must-build-sources), \ $(eval $(call declare-object-target, $v))) $(foreach v, $(shared.sources), \ $(eval $(call declare-object-target, $v))) endif ################################################################################ ### rules: preprocessor and assembly files ##################################### ################################################################################ # Preprocessor and assembly output files for bug tracing etc. They are not part # of the build processes for executables. By default these files are created in # the current working directory. Dependency tracking is not performed, the build # is forced instead to make sure it's up to date. force: #=== preprocessor file ========================================================= # make preprocessor output file with extension .pre # argument $1 = compiler type (c or cxx) define make-preprocessor-file $(info ++++ info: making preprocessor output file $(notdir $*.pre) \ in current working directory) $(compile-$1) -E $< $(c.flags) $($1.flags) -o $(notdir $*.pre) endef %.pre:: %.c force $(call make-preprocessor-file,c) %.pre:: %.cc force $(call make-preprocessor-file,cxx) %.pre:: %.cpp force $(call make-preprocessor-file,cxx) #=== assembly file ============================================================= # make C / assembly interleaved output file with extension .lst # argument $1 = compiler type (c or cxx) define make-assembly-file $(info ++++ info: making assembly output file $(notdir $*.lst) \ in current working directory) $(compile-$1) \ -c -Wa,-a,-ad -fverbose-asm \ $($1.flags) \ $< > $(notdir $*.lst) endef %.lst:: %.c force $(call make-assembly-file,c) %.lst:: %.cc force $(call make-assembly-file,cxx) %.lst:: %.cpp force $(call make-assembly-file,cxx) ################################################################################ ### rules: installation targets ################################################ ################################################################################ #=== strip ===================================================================== # Stripping of installed binaries will only be done when variable 'stripflags' # is defined non-empty. No default definition is provided except for Windows # where the unstripped binaries are large, especially in the case of Mingw-w64. # Note: while stripping all symbols ('-s' or '--strip-all') is possible for # Linux and Windows, in the case of OSX only non-global symbols can be stripped # (option '-x' or '--discard-all'). # Make definition of strip command overridable so it can be defined in an # environment for cross-compilation. STRIP ?= strip # Commands in 'strip-executables' will be executed conditionally in the rule for # target 'install-executables'. strip-executables = cd "$(installpath)" && \ $(foreach v, $(executables), $(STRIP) $(stripflags) '$v';) #=== install =================================================================== # Install targets depend on successful exit status of target all because nothing # must be installed in case of a build error. # -p = preserve time stamps # -m = set permission mode (as in chmod) # -d = create all components of specified directories INSTALL = install INSTALL_PROGRAM := $(INSTALL) -p -m 644 INSTALL_DATA := $(INSTALL) -p -m 644 INSTALL_DIR := $(INSTALL) -m 755 -d # strip spaces from file names executables := $(strip $(executables)) datafiles := $(strip $(datafiles)) datadirs := $(strip $(datadirs)) # Do not make any install sub-target with empty variable definition because the # install program would exit with an error. install: $(if $(executables), install-executables) install: $(if $(datafiles), install-datafiles) install: $(if $(datadirs), install-datadirs) install-executables: all $(INSTALL_DIR) -v "$(installpath)" $(foreach v, $(executables), \ $(INSTALL_PROGRAM) '$v' "$(installpath)";) $(info ++++ info: executables of lib $(lib.name) installed \ from $(CURDIR) to $(installpath)) $(if $(stripflags), $(strip-executables),) install-datafiles: all $(INSTALL_DIR) -v "$(installpath)" $(foreach v, $(datafiles), \ $(INSTALL_DATA) '$(v)' "$(installpath)";) $(info ++++ info: data files of lib $(lib.name) installed \ from $(CURDIR) to $(installpath)) install-datadirs: all $(foreach v, $(datadirs), $(INSTALL_DIR) "$(installpath)/$v";) $(foreach v, $(datadirs), \ $(INSTALL_DATA) $(wildcard $v/*) "$(installpath)/$v";) $(info ++++ info: data directories of lib $(lib.name) installed \ from $(CURDIR) to $(installpath)) ################################################################################ ### rules: distribution targets ################################################ ################################################################################ # TODO # These targets are implemented in Makefile Template, but I have to figure out # how to do it under the not-so-strict conditions of Makefile.pdlibbuilder. # make source package dist: @echo "target dist not yet implemented" # make Debian source package dpkg-source: @echo "target dpkg-source not yet implemented" $(ORIGDIR): $(DISTDIR): ################################################################################ ### rules: clean targets ####################################################### ################################################################################ # delete build products from build tree clean: rm -f $(all.objects) rm -f $(classes.executables) $(lib.name).$(extension) $(shared.lib) rm -f *.pre *.lst # remove distribution directories and tarballs from build tree distclean: clean @echo "target distclean not yet implemented" ################################################################################ ### rules: submake targets ##################################################### ################################################################################ # Iterate over sub-makefiles or makefiles in other directories. # When 'continue-make=yes' is set, sub-makes will report 'true' to the parent # process regardless of their real exit status. This prevents the parent make # from being aborted by a sub-make error. Useful when you want to quickly find # out which sub-makes from a large set will succeed. ifeq ($(continue-make),yes) continue = || true endif # These targets will trigger sub-make processes for entries in 'makefiledirs' # and 'makefiles'. all alldebug install clean distclean dist dkpg-source: \ $(makefiledirs) $(makefiles) # this expands to identical rules for each entry in 'makefiledirs' $(makefiledirs): $(MAKE) --directory=$@ $(MAKECMDGOALS) $(continue) # this expands to identical rules for each entry in 'makefiles' $(makefiles): $(MAKE) --directory=$(dir $@) --makefile=$(notdir $@) $(MAKECMDGOALS) $(continue) ################################################################################ ### rules: convenience targets ################################################# ################################################################################ #=== show variables ============================================================ # Several 'function' macro's cause errors when expanded within a rule or without # proper arguments. Variables which are set with the define directive are only # shown by name for that reason. functions = \ add-class-source \ declare-class-target \ declare-class-executable-target \ declare-object-target \ link-class \ link-lib \ link-shared \ make-object-file \ make-preprocessor-file \ make-assembly-file # show variables from makefiles vars: $(info ++++ info: showing makefile variables:) $(foreach v,\ $(sort $(filter-out $(functions) functions, $(.VARIABLES))),\ $(if $(filter file, $(origin $v)),\ $(info variable $v = $($v)))) $(foreach v, $(functions), $(info 'function' name: $v)) @echo # show all variables allvars: $(info ++++ info: showing default, automatic and makefile variables:) $(foreach v, \ $(sort $(filter-out $(functions) functions, $(.VARIABLES))), \ $(info variable ($(origin $v)) $v = $($v))) $(foreach v, $(functions), $(info 'function' name: $v)) @echo #=== show dependencies ========================================================= # show generated prerequisites rules depend: $(info ++++ info: generated prerequisite rules) $(foreach v, $(classes), $(info $(declare-class-target))) $(foreach v, $(classes), $(info $(declare-class-executable-target))) $(foreach v, $(all.sources), $(info $(call declare-object-target, $v))) @echo #=== show help text ============================================================ # brief info about targets and paths ifdef mpdh mpdhinfo := $(mpdh) else mpdhinfo := m_pd.h was not found. Is Pd installed? endif help: @echo @echo " Main targets:" @echo " all: build executables (default target)" @echo " install: install all components of the library" @echo " vars: print makefile variables for troubleshooting" @echo " allvars: print all variables for troubleshooting" @echo " help: print this help text" @echo @echo " Pd API m_pd.h:" @echo " $(mpdhinfo)" @echo " You may specify your preferred Pd include directory as argument" @echo " to the make command, like 'PDINCLUDEDIR=path/to/pd/src'." @echo @echo " Path for installation of your libdir(s):" @echo " $(PDLIBDIR)" @echo " Alternatively you may specify your path for installation as argument" @echo " to the make command, like 'PDLIBDIR=path/to/pd-externals'." @echo @echo " Default paths are listed in the doc sections in Makefile.pdlibbuilder." @echo #=== platform test ============================================================= # This target can be used to test if the compiler for specified PLATFORM is # correctly defined and available. dumpmachine: @$(CC) -dumpmachine #=== dummy target ============================================================== coffee: @echo "Makefile.pdlibbuilder: Can not make coffee. Sorry." ################################################################################ ### end of rules sections ###################################################### ################################################################################ # for syntax highlighting in vim and github # vim: set filetype=make: pd-fftease-3.0.1/pd-lib-builder/README.md000066400000000000000000000130711401707710000176020ustar00rootroot00000000000000 ### Makefile.pdlibbuilder ### Helper makefile for Pure Data external libraries. Written by Katja Vetter March-June 2015 for the public domain and since then developed as a Pd community project. No warranties. Inspired by Hans Christoph Steiner's Makefile Template and Stephan Beal's ShakeNMake. GNU make version >= 3.81 required. ### characteristics ### * defines build settings based on autodetected target platform * defines rules to build Pd class- or lib executables from C or C++ sources * defines rules for libdir installation * defines convenience targets for developer and user * evaluates implicit dependencies for non-clean builds ### basic usage ### In your Makefile, define your Pd lib name and class files, and include Makefile.pdlibbuilder at the end of the Makefile. Like so: # Makefile for mylib lib.name = mylib class.sources = myclass1.c myclass2.c datafiles = myclass1-help.pd myclass2-help.pd README.txt LICENSE.txt include Makefile.pdlibbuilder For files in class.sources it is assumed that class name == source file basename. The default target builds all classes as individual executables with Pd's default extension for the platform. For anything more than the most basic usage, read the documentation sections in Makefile.pdlibbuilder. ### paths ### Makefile.pdlibbuilder >= v0.4.0 supports pd path variables which can be defined not only as make command argument but also in the environment, to override platform-dependent defaults: PDDIR: Root directory of 'portable' pd package. When defined, PDINCLUDEDIR and PDBINDIR will be evaluated as $(PDDIR)/src and $(PDDIR)/bin. PDINCLUDEDIR: Directory where Pd API m_pd.h should be found, and other Pd header files. Overrides the default search path. PDBINDIR: Directory where pd.dll should be found for linking (Windows only). Overrides the default search path. PDLIBDIR: Root directory for installation of Pd library directories. Overrides the default install location. ### platform detection and predefined variables ### Makefile.pdlibbuilder tries to detect architecture and operating system in order to define platform-specific variables. Since v0.6.0 we let the compiler report target platform, rather than taking the build machine as reference. This simplifies cross compilation. The kind of build options that are predefined: - optimizations useful for realtime DSP processing - options strictly required for the platform - options to make the build work accross a range of CPU's and OS versions The exact choice and definition predefined variables changes over time, as new platforms arrive and older platforms become obsolete. The easiest way to get an overview for your platform is by checking the flags categories in the output of target `vars`. Variables written in capitals (like `CFLAGS`) are intentionally exposed as user variables, although technically all makefile variables can be overridden by make command arguments. ### specific language versions ### Makefile.pdlibbuilder handles C and C++, but can not detect if your code uses features of a specific version (like C99, C++11, C++14 etc.). In such cases your makefile should specify that version as compiler option: cflags = -std=c++11 Also you may need to be explicit about minimum OSX version. For example, C++11 needs OSX 10.9 or higher: define forDarwin cflags = -mmacosx-version-min=10.9 endef ### documentation ### This README.md provides only basic information. A large comment section inside Makefile.pdlibbuilder lists and explains the available user variables, default paths, and targets. The internal documentation reflects the exact functionality of the particular version. For suggestions about project maintenance and advanced compilation see tips-tricks.md. ### versioning ### The project is versioned in MAJOR.MINOR.BUGFIX format (see http://semver.org), and maintained at https://github.com/pure-data/pd-lib-builder. Pd lib developers are invited to regulary check for updates, and to contribute and discuss improvements here. If you really need to distribute a personalized version with your library, rename Makefile.pdlibbuilder to avoid confusion. ### examples ### The list of projects using pd-lib-builder can be helpful if you are looking for examples, from the simplest use case to more complex implementations. - helloworld: traditional illustration of simplest use case - pd-windowing: straightforward real world use case of a small library - pd-nilwind / pd-cyclone: more elaborate source tree - zexy: migrated from autotools to pd-lib-builder ### projects using pd-lib-builder ### non-exhaustive list https://github.com/pure-data/helloworld https://github.com/electrickery/pd-nilwind https://github.com/electrickery/pd-maxlib https://github.com/electrickery/pd-sigpack https://github.com/electrickery/pd-tof https://github.com/electrickery/pd-windowing https://github.com/electrickery/pd-smlib https://github.com/porres/pd-cyclone https://github.com/porres/pd-else https://github.com/porres/pd-psycho https://git.iem.at/pd/comport https://git.iem.at/pd/hexloader https://git.iem.at/pd/iemgui https://git.iem.at/pd/iemguts https://git.iem.at/pd/iemlib https://git.iem.at/pd/iemnet https://git.iem.at/pd/iem_ambi https://git.iem.at/pd/iem_tab https://git.iem.at/pd/iem_adaptfilt https://git.iem.at/pd/iem_roomsim https://git.iem.at/pd/iem_spec2 https://git.iem.at/pd/mediasettings https://git.iem.at/pd/zexy https://git.iem.at/pd-gui/punish https://github.com/residuum/PuRestJson https://github.com/libpd/abl_link https://github.com/wbrent/timbreID https://github.com/MetaluNet/moonlib pd-fftease-3.0.1/pd-lib-builder/tests/000077500000000000000000000000001401707710000174635ustar00rootroot00000000000000pd-fftease-3.0.1/pd-lib-builder/tests/Makefile000066400000000000000000000005421401707710000211240ustar00rootroot00000000000000# recursively build all example projects in the subdirectories makefiledirs := $(filter-out _%, $(dir $(wildcard */Makefile))) PDLIBBUILDER_DIR = ../ include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder buildcheck installcheck: $(makefiledirs) runcheck: PDBINDIR=$(PDBINDIR) ./test-patches.sh $(makefiledirs:%=%*.pd) projects: @echo $(makefiledirs) pd-fftease-3.0.1/pd-lib-builder/tests/_template_/000077500000000000000000000000001401707710000215745ustar00rootroot00000000000000pd-fftease-3.0.1/pd-lib-builder/tests/_template_/Makefile000066400000000000000000000014231401707710000232340ustar00rootroot00000000000000# Makefile to build class '_template_' for Pure Data. # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. # library name lib.name = _template_ # input source file (class name == source file basename) class.sources = _template_.c # all extra files to be included in binary distribution of the library datafiles = _template_-help.pd _template_-meta.pd # include Makefile.pdlibbuilder # (for real-world projects see the "Project Management" section # in tips-tricks.md) PDLIBBUILDER_DIR=../.. include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder # simplistic tests whether all expected files have been produced/installed buildcheck: all test -e _template_.$(extension) installcheck: install test -e $(installpath)/_template_.$(extension) pd-fftease-3.0.1/pd-lib-builder/tests/_template_/_template_-help.pd000066400000000000000000000001361401707710000251600ustar00rootroot00000000000000#N canvas 335 160 450 300 12; #X obj 143 125 _template_; #X msg 143 93 7; #X connect 1 0 0 0; pd-fftease-3.0.1/pd-lib-builder/tests/_template_/_template_-meta.pd000066400000000000000000000005211401707710000251540ustar00rootroot00000000000000#N canvas 966 322 200 200 10; #N canvas 19 51 420 300 META 0; #X text 10 10 META this is a prototype of a libdir meta file; #X text 10 51 AUTHOR IOhannes m zmolnig; #X text 10 110 VERSION 1.0.0; #X text 10 90 LICENSE CC0; #X text 10 70 DESCRIPTION Example "_template_" external.; #X text 10 30 NAME _template_; #X restore 10 10 pd META; pd-fftease-3.0.1/pd-lib-builder/tests/_template_/_template_.c000066400000000000000000000006631401707710000240560ustar00rootroot00000000000000#include t_class*_template__class; static void _template__float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*_template__new(void) { return pd_new(_template__class); } void _template__setup(void) { post("%s", __FUNCTION__); _template__class = class_new(gensym("_template_"), _template__new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(_template__class, _template__float); } pd-fftease-3.0.1/pd-lib-builder/tests/make-from-template.sh000066400000000000000000000015741401707710000235150ustar00rootroot00000000000000#!/bin/sh template=_template_ template_dir=${0%/*}/${template} outdir=$1 outdir=${outdir%/} outname=${outdir##*/} usage() { cat 1>&2 < creates a new test-directory from _template_; must not exist yet. EOL if [ "x$@" != "x" ]; then echo echo " $@" 1>&2 fi exit 1 } if [ "x${outdir}" = "x" ]; then usage fi if [ -d "${outdir}" ]; then usage "output directory '${outdir}' already exists!" fi if [ ! -d "${template_dir}" ]; then echo "unable to find '${template_dir}'" 1>&2 exit 1 fi mkdir -p "${outdir}" || usage "unable to create '${outdir}'!" rmdir "${outdir}" cp -r "${template_dir}" "${outdir}" find "${outdir}" -type f -exec sed -e "s|${template}|${outname}|g" -i {} + for f in "${outdir}"/*; do g=$(echo $f | sed -e "s|${template}|${outname}|g") if [ "x${f}" != "x${g}" ]; then mv "${f}" "${g}" fi done pd-fftease-3.0.1/pd-lib-builder/tests/multifor/000077500000000000000000000000001401707710000213245ustar00rootroot00000000000000pd-fftease-3.0.1/pd-lib-builder/tests/multifor/Makefile000066400000000000000000000021411401707710000227620ustar00rootroot00000000000000# Makefile to build class 'multifor' for Pure Data. # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. # library name lib.name = multifor # input source file (class name == source file basename) class.sources = multiforA.c # additional classes define forLinux class.sources += multiforB.c endef define forDarwin class.sources += multiforB.c endef define forWindows class.sources += multiforB.c endef # all extra files to be included in binary distribution of the library datafiles = multifor-help.pd multifor-meta.pd # include Makefile.pdlibbuilder # (for real-world projects see the "Project Management" section # in tips-tricks.md) PDLIBBUILDER_DIR=../.. include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder # simplistic tests whether all expected files have been produced/installed buildcheck: all test -e multiforA.$(extension) test -e multiforB.$(extension) installcheck: install test -e $(installpath)/multiforA.$(extension) test -e $(installpath)/multiforB.$(extension) test -e $(installpath)/multifor-help.pd test -e $(installpath)/multifor-meta.pd pd-fftease-3.0.1/pd-lib-builder/tests/multifor/README.md000066400000000000000000000005251401707710000226050ustar00rootroot00000000000000multifor ======== minimal pd-lib-builder project that shows how to compile a library that contains multiple C-files that are compiled into multiple binaries each containing a different Pd-objectclass. some of the objectclasses are only compiled on specific platforms. this is a special case of the one-object-per-binary library structure. pd-fftease-3.0.1/pd-lib-builder/tests/multifor/multifor-help.pd000066400000000000000000000002351401707710000244400ustar00rootroot00000000000000#N canvas 335 160 450 300 12; #X msg 143 93 7; #X obj 143 125 multiforA; #X obj 223 125 multiforB; #X msg 223 93 12; #X connect 0 0 1 0; #X connect 3 0 2 0; pd-fftease-3.0.1/pd-lib-builder/tests/multifor/multifor-meta.pd000066400000000000000000000005151401707710000244370ustar00rootroot00000000000000#N canvas 966 322 200 200 10; #N canvas 19 51 420 300 META 0; #X text 10 10 META this is a prototype of a libdir meta file; #X text 10 51 AUTHOR IOhannes m zmolnig; #X text 10 110 VERSION 1.0.0; #X text 10 90 LICENSE CC0; #X text 10 70 DESCRIPTION Example "multifor" external.; #X text 10 30 NAME multifor; #X restore 10 10 pd META; pd-fftease-3.0.1/pd-lib-builder/tests/multifor/multiforA.c000066400000000000000000000006511401707710000234340ustar00rootroot00000000000000#include t_class*multiforA_class; static void multiforA_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*multiforA_new(void) { return pd_new(multiforA_class); } void multiforA_setup(void) { post("%s", __FUNCTION__); multiforA_class = class_new(gensym("multiforA"), multiforA_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multiforA_class, multiforA_float); } pd-fftease-3.0.1/pd-lib-builder/tests/multifor/multiforB.c000066400000000000000000000006511401707710000234350ustar00rootroot00000000000000#include t_class*multiforB_class; static void multiforB_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*multiforB_new(void) { return pd_new(multiforB_class); } void multiforB_setup(void) { post("%s", __FUNCTION__); multiforB_class = class_new(gensym("multiforB"), multiforB_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multiforB_class, multiforB_float); } pd-fftease-3.0.1/pd-lib-builder/tests/multilib/000077500000000000000000000000001401707710000213045ustar00rootroot00000000000000pd-fftease-3.0.1/pd-lib-builder/tests/multilib/Makefile000066400000000000000000000017141401707710000227470ustar00rootroot00000000000000# Makefile to build class 'multilib' for Pure Data. # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. # library name lib.name = multilib make-lib-executable=yes # input source file (class name == source file basename) class.sources = multilibA.c multilibB.c # glue for building a multi-object library lib.setup.sources = $(lib.name).c # all extra files to be included in binary distribution of the library datafiles = multilib-help.pd multilib-meta.pd # include Makefile.pdlibbuilder # (for real-world projects see the "Project Management" section # in tips-tricks.md) PDLIBBUILDER_DIR=../.. include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder # simplistic tests whether all expected files have been produced/installed buildcheck: all test -e multilib.$(extension) installcheck: install test -e $(installpath)/multilib.$(extension) test -e $(installpath)/multilib-help.pd test -e $(installpath)/multilib-meta.pd pd-fftease-3.0.1/pd-lib-builder/tests/multilib/README.md000066400000000000000000000004061401707710000225630ustar00rootroot00000000000000multilib ======== minimal pd-lib-builder project that shows how to compile a library that contains multiple C-files that are compiled into a single binary containing different Pd-objectclasses. this is the general case of the single-binary library structure. pd-fftease-3.0.1/pd-lib-builder/tests/multilib/multilib-help.pd000066400000000000000000000003341401707710000244000ustar00rootroot00000000000000#N canvas 335 160 450 300 12; #X declare -lib multilib; #X msg 143 93 7; #X obj 143 125 multilibA; #X obj 223 125 multilibB; #X msg 223 93 12; #X obj 136 47 declare -lib multilib; #X connect 0 0 1 0; #X connect 3 0 2 0; pd-fftease-3.0.1/pd-lib-builder/tests/multilib/multilib-meta.pd000066400000000000000000000005151401707710000243770ustar00rootroot00000000000000#N canvas 966 322 200 200 10; #N canvas 19 51 420 300 META 0; #X text 10 10 META this is a prototype of a libdir meta file; #X text 10 51 AUTHOR IOhannes m zmolnig; #X text 10 110 VERSION 1.0.0; #X text 10 90 LICENSE CC0; #X text 10 70 DESCRIPTION Example "multiple" external.; #X text 10 30 NAME multiple; #X restore 10 10 pd META; pd-fftease-3.0.1/pd-lib-builder/tests/multilib/multilib.c000066400000000000000000000002021401707710000232630ustar00rootroot00000000000000 void multilibA_setup(void); void multilibB_setup(void); void multilib_setup(void) { multilibA_setup(); multilibB_setup(); } pd-fftease-3.0.1/pd-lib-builder/tests/multilib/multilibA.c000066400000000000000000000006511401707710000233740ustar00rootroot00000000000000#include t_class*multilibA_class; static void multilibA_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*multilibA_new(void) { return pd_new(multilibA_class); } void multilibA_setup(void) { post("%s", __FUNCTION__); multilibA_class = class_new(gensym("multilibA"), multilibA_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multilibA_class, multilibA_float); } pd-fftease-3.0.1/pd-lib-builder/tests/multilib/multilibB.c000066400000000000000000000006511401707710000233750ustar00rootroot00000000000000#include t_class*multilibB_class; static void multilibB_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*multilibB_new(void) { return pd_new(multilibB_class); } void multilibB_setup(void) { post("%s", __FUNCTION__); multilibB_class = class_new(gensym("multilibB"), multilibB_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multilibB_class, multilibB_float); } pd-fftease-3.0.1/pd-lib-builder/tests/multiple/000077500000000000000000000000001401707710000213165ustar00rootroot00000000000000pd-fftease-3.0.1/pd-lib-builder/tests/multiple/Makefile000066400000000000000000000016651401707710000227660ustar00rootroot00000000000000# Makefile to build class 'multiple' for Pure Data. # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. # library name lib.name = multiple # input source file (class name == source file basename) class.sources = multipleA.c multipleB.c # all extra files to be included in binary distribution of the library datafiles = multiple-help.pd multiple-meta.pd # include Makefile.pdlibbuilder # (for real-world projects see the "Project Management" section # in tips-tricks.md) PDLIBBUILDER_DIR=../.. include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder # simplistic tests whether all expected files have been produced/installed buildcheck: all test -e multipleA.$(extension) test -e multipleB.$(extension) installcheck: install test -e $(installpath)/multipleA.$(extension) test -e $(installpath)/multipleB.$(extension) test -e $(installpath)/multiple-help.pd test -e $(installpath)/multiple-meta.pd pd-fftease-3.0.1/pd-lib-builder/tests/multiple/README.md000066400000000000000000000004241401707710000225750ustar00rootroot00000000000000multiple ======== minimal pd-lib-builder project that shows how to compile a library that contains multiple C-files that are compiled into multiple binaries each containing a different Pd-objectclass. this is the general case of the one-object-per-binary library structure. pd-fftease-3.0.1/pd-lib-builder/tests/multiple/multiple-help.pd000066400000000000000000000002351401707710000244240ustar00rootroot00000000000000#N canvas 335 160 450 300 12; #X msg 143 93 7; #X obj 143 125 multipleA; #X obj 223 125 multipleB; #X msg 223 93 12; #X connect 0 0 1 0; #X connect 3 0 2 0; pd-fftease-3.0.1/pd-lib-builder/tests/multiple/multiple-meta.pd000066400000000000000000000005151401707710000244230ustar00rootroot00000000000000#N canvas 966 322 200 200 10; #N canvas 19 51 420 300 META 0; #X text 10 10 META this is a prototype of a libdir meta file; #X text 10 51 AUTHOR IOhannes m zmolnig; #X text 10 110 VERSION 1.0.0; #X text 10 90 LICENSE CC0; #X text 10 70 DESCRIPTION Example "multiple" external.; #X text 10 30 NAME multiple; #X restore 10 10 pd META; pd-fftease-3.0.1/pd-lib-builder/tests/multiple/multipleA.c000066400000000000000000000006511401707710000234200ustar00rootroot00000000000000#include t_class*multipleA_class; static void multipleA_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*multipleA_new(void) { return pd_new(multipleA_class); } void multipleA_setup(void) { post("%s", __FUNCTION__); multipleA_class = class_new(gensym("multipleA"), multipleA_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multipleA_class, multipleA_float); } pd-fftease-3.0.1/pd-lib-builder/tests/multiple/multipleB.c000066400000000000000000000006511401707710000234210ustar00rootroot00000000000000#include t_class*multipleB_class; static void multipleB_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*multipleB_new(void) { return pd_new(multipleB_class); } void multipleB_setup(void) { post("%s", __FUNCTION__); multipleB_class = class_new(gensym("multipleB"), multipleB_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multipleB_class, multipleB_float); } pd-fftease-3.0.1/pd-lib-builder/tests/multiplexx/000077500000000000000000000000001401707710000216765ustar00rootroot00000000000000pd-fftease-3.0.1/pd-lib-builder/tests/multiplexx/Makefile000066400000000000000000000017171401707710000233440ustar00rootroot00000000000000# Makefile to build class 'multiplexx' for Pure Data. # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. # library name lib.name = multiplexx # input source file (class name == source file basename) class.sources = multiplexxA.cpp multiplexxB.c # all extra files to be included in binary distribution of the library datafiles = multiplexx-help.pd multiplexx-meta.pd # include Makefile.pdlibbuilder # (for real-world projects see the "Project Management" section # in tips-tricks.md) PDLIBBUILDER_DIR=../.. include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder # simplistic tests whether all expected files have been produced/installed buildcheck: all test -e multiplexxA.$(extension) test -e multiplexxB.$(extension) installcheck: install test -e $(installpath)/multiplexxA.$(extension) test -e $(installpath)/multiplexxB.$(extension) test -e $(installpath)/multiplexx-help.pd test -e $(installpath)/multiplexx-meta.pd pd-fftease-3.0.1/pd-lib-builder/tests/multiplexx/README.md000066400000000000000000000004321401707710000231540ustar00rootroot00000000000000multiplexx ======== minimal pd-lib-builder project that shows how to compile a library that contains multiplexx C-files that are compiled into multiplexx binaries each containing a different Pd-objectclass. this is the general case of the one-object-per-binary library structure. pd-fftease-3.0.1/pd-lib-builder/tests/multiplexx/multiplexx-help.pd000066400000000000000000000002411401707710000253610ustar00rootroot00000000000000#N canvas 335 160 450 300 12; #X msg 143 93 7; #X obj 143 125 multiplexxA; #X obj 223 125 multiplexxB; #X msg 223 93 12; #X connect 0 0 1 0; #X connect 3 0 2 0; pd-fftease-3.0.1/pd-lib-builder/tests/multiplexx/multiplexx-meta.pd000066400000000000000000000005211401707710000253600ustar00rootroot00000000000000#N canvas 966 322 200 200 10; #N canvas 19 51 420 300 META 0; #X text 10 10 META this is a prototype of a libdir meta file; #X text 10 51 AUTHOR IOhannes m zmolnig; #X text 10 110 VERSION 1.0.0; #X text 10 90 LICENSE CC0; #X text 10 70 DESCRIPTION Example "multiplexx" external.; #X text 10 30 NAME multiplexx; #X restore 10 10 pd META; pd-fftease-3.0.1/pd-lib-builder/tests/multiplexx/multiplexxA.cpp000066400000000000000000000011201401707710000247100ustar00rootroot00000000000000#include #include t_class*multiplexxA_class; static void multiplexxA_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*multiplexxA_new(void) { return pd_new(multiplexxA_class); } #if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) extern "C" { void multiplexxA_setup(void); } #endif void multiplexxA_setup(void) { std::cerr << __FUNCTION__ << std::endl; multiplexxA_class = class_new(gensym("multiplexxA"), multiplexxA_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multiplexxA_class, multiplexxA_float); } pd-fftease-3.0.1/pd-lib-builder/tests/multiplexx/multiplexxB.c000066400000000000000000000006751401707710000243670ustar00rootroot00000000000000#include t_class*multiplexxB_class; static void multiplexxB_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*multiplexxB_new(void) { return pd_new(multiplexxB_class); } void multiplexxB_setup(void) { post("%s", __FUNCTION__); multiplexxB_class = class_new(gensym("multiplexxB"), multiplexxB_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multiplexxB_class, multiplexxB_float); } pd-fftease-3.0.1/pd-lib-builder/tests/multishared/000077500000000000000000000000001401707710000220045ustar00rootroot00000000000000pd-fftease-3.0.1/pd-lib-builder/tests/multishared/Makefile000066400000000000000000000025271401707710000234520ustar00rootroot00000000000000# Makefile to build class 'multishared' for Pure Data. # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. # library name lib.name = multishared # common functions shared.sources = shared.c # input source file (class name == source file basename) class.sources = multisharedA.c multisharedB.c # all extra files to be included in binary distribution of the library datafiles = multishared-help.pd multishared-meta.pd # include Makefile.pdlibbuilder # (for real-world projects see the "Project Management" section # in tips-tricks.md) PDLIBBUILDER_DIR=../.. include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder # simplistic tests whether all expected files have been produced/installed buildcheck: all ifeq ($(shared.extension), $(extension)) test -e lib$(lib.name).$(shared.extension) else test -e lib$(lib.name).$(extension).$(shared.extension) endif test -e multisharedA.$(extension) test -e multisharedB.$(extension) installcheck: install ifeq ($(shared.extension), $(extension)) test -e $(installpath)/lib$(lib.name).$(shared.extension) else test -e $(installpath)/lib$(lib.name).$(extension).$(shared.extension) endif test -e $(installpath)/multisharedA.$(extension) test -e $(installpath)/multisharedB.$(extension) test -e $(installpath)/multishared-help.pd test -e $(installpath)/multishared-meta.pd pd-fftease-3.0.1/pd-lib-builder/tests/multishared/README.md000066400000000000000000000005201401707710000232600ustar00rootroot00000000000000multishared =========== minimal pd-lib-builder project that shows how to compile a library that contains multiple C-files that are compiled into multiple binaries each containing a different Pd-objectclass. a local shared library is used for common components. this is an extended case of the one-object-per-binary library structure. pd-fftease-3.0.1/pd-lib-builder/tests/multishared/multishared-help.pd000066400000000000000000000002431401707710000255770ustar00rootroot00000000000000#N canvas 335 160 450 300 12; #X msg 143 93 7; #X obj 143 125 multisharedA; #X obj 223 125 multisharedB; #X msg 223 93 12; #X connect 0 0 1 0; #X connect 3 0 2 0; pd-fftease-3.0.1/pd-lib-builder/tests/multishared/multishared-meta.pd000066400000000000000000000005231401707710000255760ustar00rootroot00000000000000#N canvas 966 322 200 200 10; #N canvas 19 51 420 300 META 0; #X text 10 10 META this is a prototype of a libdir meta file; #X text 10 51 AUTHOR IOhannes m zmolnig; #X text 10 110 VERSION 1.0.0; #X text 10 90 LICENSE CC0; #X text 10 70 DESCRIPTION Example "multishared" external.; #X text 10 30 NAME multishared; #X restore 10 10 pd META; pd-fftease-3.0.1/pd-lib-builder/tests/multishared/multishared.h000066400000000000000000000000641401707710000244760ustar00rootroot00000000000000#include void multishared_foo(t_float f); pd-fftease-3.0.1/pd-lib-builder/tests/multishared/multisharedA.c000066400000000000000000000007451401707710000246000ustar00rootroot00000000000000#include "multishared.h" t_class*multisharedA_class; static void multisharedA_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); multishared_foo(f1); } static void*multisharedA_new(void) { return pd_new(multisharedA_class); } void multisharedA_setup(void) { post("%s", __FUNCTION__); multisharedA_class = class_new(gensym("multisharedA"), multisharedA_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multisharedA_class, multisharedA_float); } pd-fftease-3.0.1/pd-lib-builder/tests/multishared/multisharedB.c000066400000000000000000000007451401707710000246010ustar00rootroot00000000000000#include "multishared.h" t_class*multisharedB_class; static void multisharedB_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); multishared_foo(f1); } static void*multisharedB_new(void) { return pd_new(multisharedB_class); } void multisharedB_setup(void) { post("%s", __FUNCTION__); multisharedB_class = class_new(gensym("multisharedB"), multisharedB_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(multisharedB_class, multisharedB_float); } pd-fftease-3.0.1/pd-lib-builder/tests/multishared/shared.c000066400000000000000000000001411401707710000234120ustar00rootroot00000000000000#include "multishared.h" void multishared_foo(t_float f) { post("%s(%f)", __FUNCTION__, f); } pd-fftease-3.0.1/pd-lib-builder/tests/single/000077500000000000000000000000001401707710000207445ustar00rootroot00000000000000pd-fftease-3.0.1/pd-lib-builder/tests/single/Makefile000066400000000000000000000013671401707710000224130ustar00rootroot00000000000000# Makefile to build class 'single' for Pure Data. # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. # library name lib.name = single # input source file (class name == source file basename) class.sources = single.c # all extra files to be included in binary distribution of the library datafiles = single-help.pd single-meta.pd # include Makefile.pdlibbuilder # (for real-world projects see the "Project Management" section # in tips-tricks.md) PDLIBBUILDER_DIR=../.. include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder # simplistic tests whether all expected files have been produced/installed buildcheck: all test -e single.$(extension) installcheck: install test -e $(installpath)/single.$(extension) pd-fftease-3.0.1/pd-lib-builder/tests/single/README.md000066400000000000000000000004051401707710000222220ustar00rootroot00000000000000single ====== minimal pd-lib-builder project that shows how to compile a library that contains a single C-file that is compiled into a single binary containing a single Pd-objectclass. this is a degenerate case of the one-object-per-binary library structure. pd-fftease-3.0.1/pd-lib-builder/tests/single/single-help.pd000066400000000000000000000001321401707710000234740ustar00rootroot00000000000000#N canvas 335 160 450 300 12; #X obj 143 125 single; #X msg 143 93 7; #X connect 1 0 0 0; pd-fftease-3.0.1/pd-lib-builder/tests/single/single-meta.pd000066400000000000000000000005111401707710000234730ustar00rootroot00000000000000#N canvas 966 322 200 200 10; #N canvas 19 51 420 300 META 0; #X text 10 10 META this is a prototype of a libdir meta file; #X text 10 51 AUTHOR IOhannes m zmolnig; #X text 10 110 VERSION 1.0.0; #X text 10 90 LICENSE CC0; #X text 10 70 DESCRIPTION Example "single" external.; #X text 10 30 NAME single; #X restore 10 10 pd META; pd-fftease-3.0.1/pd-lib-builder/tests/single/single.c000066400000000000000000000006131401707710000223710ustar00rootroot00000000000000#include t_class*single_class; static void single_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*single_new(void) { return pd_new(single_class); } void single_setup(void) { post("%s", __FUNCTION__); single_class = class_new(gensym("single"), single_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(single_class, single_float); } pd-fftease-3.0.1/pd-lib-builder/tests/subdir/000077500000000000000000000000001401707710000207535ustar00rootroot00000000000000pd-fftease-3.0.1/pd-lib-builder/tests/subdir/Makefile000066400000000000000000000015251401707710000224160ustar00rootroot00000000000000# Makefile to build class 'subdir' for Pure Data. # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. # library name lib.name = subdir # input source file (class name == source file basename) class.sources = src/subdir.c src/subdir~.c # all extra files to be included in binary distribution of the library datafiles = subdir-help.pd subdir-meta.pd # include Makefile.pdlibbuilder # (for real-world projects see the "Project Management" section # in tips-tricks.md) PDLIBBUILDER_DIR=../.. include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder # simplistic tests whether all expected files have been produced/installed buildcheck: all test -e subdir.$(extension) test -e subdir~.$(extension) installcheck: install test -e $(installpath)/subdir.$(extension) test -e $(installpath)/subdir~.$(extension) pd-fftease-3.0.1/pd-lib-builder/tests/subdir/README.md000066400000000000000000000004301401707710000222270ustar00rootroot00000000000000subdir ====== pd-lib-builder project that shows how to compile a library that contains a single C-file in a separate src/ directory, that is compiled into a single binary containing a subdir Pd-objectclass. this is a special case of the one-object-per-binary library structure. pd-fftease-3.0.1/pd-lib-builder/tests/subdir/src/000077500000000000000000000000001401707710000215425ustar00rootroot00000000000000pd-fftease-3.0.1/pd-lib-builder/tests/subdir/src/subdir.c000066400000000000000000000006131401707710000231760ustar00rootroot00000000000000#include t_class*subdir_class; static void subdir_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*subdir_new(void) { return pd_new(subdir_class); } void subdir_setup(void) { post("%s", __FUNCTION__); subdir_class = class_new(gensym("subdir"), subdir_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(subdir_class, subdir_float); } pd-fftease-3.0.1/pd-lib-builder/tests/subdir/src/subdir~.c000066400000000000000000000007021401707710000233730ustar00rootroot00000000000000#include t_class*subdir_tilde_class; static void subdir_tilde_float(t_object*x, t_float f1) { pd_error(x, "%s got %f", __FUNCTION__, f1); } static void*subdir_tilde_new(void) { return pd_new(subdir_tilde_class); } void subdir_tilde_setup(void) { post("%s", __FUNCTION__); subdir_tilde_class = class_new(gensym("subdir~"), subdir_tilde_new, 0, sizeof(t_object), 0, A_NULL); class_addfloat(subdir_tilde_class, subdir_tilde_float); } pd-fftease-3.0.1/pd-lib-builder/tests/subdir/subdir-help.pd000066400000000000000000000001321401707710000235120ustar00rootroot00000000000000#N canvas 335 160 450 300 12; #X obj 143 125 subdir; #X msg 143 93 7; #X connect 1 0 0 0; pd-fftease-3.0.1/pd-lib-builder/tests/subdir/subdir-meta.pd000066400000000000000000000005111401707710000235110ustar00rootroot00000000000000#N canvas 966 322 200 200 10; #N canvas 19 51 420 300 META 0; #X text 10 10 META this is a prototype of a libdir meta file; #X text 10 51 AUTHOR IOhannes m zmolnig; #X text 10 110 VERSION 1.0.0; #X text 10 90 LICENSE CC0; #X text 10 70 DESCRIPTION Example "subdir" external.; #X text 10 30 NAME subdir; #X restore 10 10 pd META; pd-fftease-3.0.1/pd-lib-builder/tests/subdir/subdir~-help.pd000066400000000000000000000001331401707710000237110ustar00rootroot00000000000000#N canvas 335 160 450 300 12; #X obj 143 125 subdir~; #X msg 143 93 7; #X connect 1 0 0 0; pd-fftease-3.0.1/pd-lib-builder/tests/test-patches.sh000066400000000000000000000031141401707710000224220ustar00rootroot00000000000000#!/bin/sh ## simple script to open patches via Pd, and check for errors ## - each patch is opened separately ## - if an error is encountered, the Pd-printout is displayed ## (else it is suppressed) ## - if any of the patches encountered an error, the script will ## exit with a non-0 code if [ "x${PD}" = "x" ]; then if [ "x${PDBINDIR}" != "x" ]; then for exe in pd.com pd pd.exe; do if [ -x "${PDBINDIR}/${exe}" ]; then PD="${PDBINDIR}/${exe}" break fi done if [ "x${PD}" = "x" ]; then echo "WARNING: couldn't find a usable Pd in '${PDBINDIR}'" 1>&2 fi fi fi if [ "x${PD}" = "x" ]; then PD=pd fi echo "using Pd: ${PD}" failed=0 failed_tests="" succeeded=0 open1patch() { logfile=$(mktemp) local patch=$1 local patchdir=${patch%%/*} local patchfile=${patch#*/} patchfile=${patchfile#/} #echo "INFO: running ${patchfile} in ${patchdir}" cd "${patchdir}" && \ ${PD} -batch -nrt -noprefs -nostdpath -open "${patchfile}" -send "pd quit" \ >"${logfile}" 2>&1 ret=$? if grep "error: ... couldn't create" "${logfile}" >/dev/null; then ret=1 fi if [ "x${ret}" != "x0" ]; then echo "" cat "${logfile}" echo "FAILED[$ret]: ${patch}" else echo "SUCCEEDED: ${patch}" fi rm "${logfile}" return $ret } for p in "${@}"; do if (open1patch "${p}"); then succeeded=$((succeeded+1)) else failed=$((failed+1)) failed_tests="${failed_tests} ${p}" fi done echo "" echo "SUCCESS: ${succeeded}" echo "FAILURE: ${failed}" test ${failed} -eq 0 || echo "FAILS :${failed_tests}" test ${failed} -eq 0 pd-fftease-3.0.1/pd-lib-builder/tips-tricks.md000066400000000000000000000164001401707710000211200ustar00rootroot00000000000000pd-lib-builder cheatsheet ========================= # Creating special builds ## building for non-native platform Using pd-lib-builder >=0.6.0 we can define variable `PLATFORM` to specify a target triplet for cross-compilation. Assuming a W32 package for Pd is unzipped into path `${PDWIN32}`, to build for Windows 32 bit: make PLATFORM=i686-w64-mingw32 PDDIR="${PDWIN32}" #### older pd-lib-builder versions Using pd-lib-builder < 0.6.0, in the absence of variable `PLATFORM`, you would instead override variables `system`, `target.arch`, `CC` and / or `CXX`, `STRIP`. Example: make system=Windows target.arch=i686 CC=i686-w64-mingw32-gcc STRIP=i686-w64-mingw32-strip PDDIR="${PDWIN32}" #### toolchains To build for non-native OS and/or architecture you need a cross toolchain. On Linux such toolchains are relatively easy to get. For example Debian Buster amd64 provides them for the following platforms (install g++ with dependencies for a given platform to get the whole toolchain): - `arm-linux-gnueabihf` - `aarch64-linux-gnu` - `i686-linux-gnu` - `i686-w64-mingw32` and `x86_64-w64-mingw32` (install `mingw-w64`) Cross toolchains for OSX/MacOS are not generally distributed. Project `osxcross` from Thomas Poechtraeger can create them for Linux. ## building double-precision externals At the time of writing (2018-02) there is no official Pd that supports double-precision numbers yet. However, if you do get hold of an experimental double-precision Pd, you can easily build your externals for 64-bit numbers: make CPPFLAGS="-DPD_FLOATSIZE=64" ## building externals for W64 (64-bit Windows) At the time of writing (2018-02) there is no official Pd that supports W64 yet. However, if you do get hold of an experimental W64 Pd, you can easily build your externals for this environment with make CPPFLAGS="-DPD_LONGINTTYPE=__int64" CC=x86_64-w64-mingw32-gcc To build a double-precision external for W64, use something like: make CPPFLAGS="-DPD_LONGINTTYPE=__int64 -DPD_FLOATSIZE=64" CC=x86_64-w64-mingw32-gcc ## TODO universal binaries on OSX # Project management In general it is advised to put the `Makefile.pdlibbuilder` into a separate subdirectory (e.g. `pd-lib-builder/`). This makes it much easier to update the `Makefile.pdlibbuilder` later You *should* also use a variable to the actual path of the Makefile.pdlibbuilder (even if you keep it in the root-directory), as this allows easy experimenting with newer (or older) (or site-specific) versions of the pd-lib-builder Makefile. ~~~make PDLIBBUILDER_DIR=pd-lib-builder/ include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder ~~~ ## Keeping pd-lib-builder up-to-date ### `git subtree` With git-subtrees, you make the pd-lib-builder repository (or any other repository for that matter) part of your own repository - with full history and everything - put nicely into a distinct subdirectory. Support for *manipulating* subtrees has been added with Git-v1.7.11 (May 2012). The nice thing however is, that from "outside" the subtree is part of your repository like any other directory. E.g. older versions of Git can clone your repository with the full subtree (and all it's history) just fine. You can also use git-archive to make a complete snapshot of your repository (including the subtree) - nice, if you e.g. want self-contained downloads of your project from git hosting platforms (like Github, Gitlab, Bitbucket,...) In short, `git subtree` is the better `git submodule`. So here's how to do it: #### Initial setup/check-out This will create a `pd-lib-builder/` directory containing the full history of the pd-lib-builder repository up to its release `v0.5.0` ~~~sh git subtree add --prefix=pd-lib-builder/ https://github.com/pure-data/pd-lib-builder v0.5.0 ~~~ This will automatically merge the `pd-lib-builder/` history into your current branch, so everything is ready to go. #### Cloning your repository with the subtree Nothing special, really. Just clone your repository as always: ~~~sh git clone https://git.example.org/pd/superbonk~.git ~~~ #### Updating the subtree Time passes and sooner or later you will find, that there is a shiny new pd-lib-builder with plenty of bugfixes and new features. To update your local copy to pd-lib-builder's current `master`, simply run: ~~~sh git subtree pull --prefix pd-lib-builder/ https://github.com/pure-data/pd-lib-builder master ~~~ #### Pulling the updated subtree into existing clones Again, nothing special. Just pull as always: ~~~sh git pull ~~~ #### Further reading More on the power of `git subtree` can be found online - https://medium.com/@v/git-subtrees-a-tutorial-6ff568381844 - https://www.atlassian.com/blog/git/alternatives-to-git-submodule-git-subtree - ... ### ~~`git submodule`~~ [DISCOURAGED] #### Initial setup/check-out To add a new submodule to your repository, just run `git submodule add` and commit the changes: ~~~sh git submodule add https://github.com/pure-data/pd-lib-builder git commit .gitmodules pd-lib-builder/ -m "Added pd-lib-builder as git-submodule" ~~~ #### Cloning your repository with the submodule When doing a fresh clone of your repository, pass the `--recursive` option to automatically fetch all submodules: ~~~sh git clone --recursive https://git.example.org/pd/superbonk~.git ~~~ If you've cloned non-recursively, you can initialize and update the submodules manually: ~~~sh git submodule init git submodule update ~~~ #### Updating the submodule Submodules are usually fixed to a given commit in their repository. To update the `pd-lib-builder` submodule to the current `master` do something like: ~~~sh cd pd-lib-builder git checkout master git pull cd .. git status pd-lib-builder git commit pd-lib-builder -m "Updated pd-lib-builder to current master" ~~~ #### Pulling the updated submodule into existing clones After you have pushed the submodule updates in your repository, other clones of the repository can be updated as follows: ~~~sh git pull ~~~ The above will make your repository aware, that the submodule is out-of-sync. ~~~sh $ LANG=C git status pd-lib-builder On branch master Your branch is up to date with 'origin/master'. Changes not staged for commit: (use "git add ..." to update what will be committed) (use "git checkout -- ..." to discard changes in working directory) modified: pd-lib-builder (new commits) $ ~~~ In order to sync the submodule to the correct commit, run the following: ~~~sh git submodule update ~~~ #### Drawbacks `git submodule` has a number of drawbacks: - it requires special commands to synchronize the submodules, in addition to synching your repository. - you must make sure to use an URL for the submodule that is accessible to your potential users. e.g. using `git@github.com:pure-data/pd-lib-builder` is bad, because it requires everybody who wants to checkout your sources to have a github-account - even if they could checkout *your* repository anonymously. - submodules will be excluded from `git archive`. This means, that if you use a mainstream git provider (like Github, GitLab, Bitbucket,...) and make releases by creating a `git tag`, the automatically generated zipfiles with the sources will lack the submodule - and your users will not be able to compile your source code. In general, I would suggest to **avoid** `git submodule`, and instead use the better `git subtree` (above). pd-fftease-3.0.1/pileup~.c000066400000000000000000000251211401707710000153670ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *pileup_class; #define OBJECT_NAME "pileup~" typedef struct _pileup { t_object x_obj; t_float x_f; t_fftease *fft; /* pileup vars */ t_float move_threshold; t_float *last_frame ; int *frames_left; t_float inverse_compensation_gain; // gain up inverse t_float persistence; // decay factor int mode; t_float tadv; short mute; t_float hi_freq; t_float lo_freq; } t_pileup; static void pileup_dsp(t_pileup *x, t_signal **sp); static t_int *pileup_perform(t_int *w); static void *pileup_new(t_symbol *s, int argc, t_atom *argv); static void pileup_mute(t_pileup *x, t_floatarg f); static void pileup_free( t_pileup *x ); static void pileup_clear( t_pileup *x ); static void pileup_init(t_pileup *x); static void pileup_mode(t_pileup *x, t_floatarg mode); static void pileup_inverse_gain(t_pileup *x, t_floatarg gain); static void pileup_persistence(t_pileup *x, t_floatarg persistence); static void pileup_transpose(t_pileup *x, t_floatarg tf); static void pileup_synthresh(t_pileup *x, t_floatarg thresh); static void pileup_oscbank(t_pileup *x, t_floatarg flag); static void pileup_highfreq(t_pileup *x, t_floatarg f); static void pileup_lowfreq(t_pileup *x, t_floatarg f); void pileup_tilde_setup(void) { t_class *c; c = class_new(gensym("pileup~"), (t_newmethod)pileup_new, (t_method)pileup_free,sizeof(t_pileup), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_pileup, x_f); class_addmethod(c,(t_method)pileup_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)pileup_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)pileup_oscbank,gensym("oscbank"),A_FLOAT,0); class_addmethod(c,(t_method)pileup_transpose,gensym("transpose"),A_FLOAT,0); class_addmethod(c,(t_method)pileup_synthresh,gensym("synthresh"),A_FLOAT,0); class_addmethod(c,(t_method)pileup_clear,gensym("clear"), 0); class_addmethod(c,(t_method)pileup_mode,gensym("mode"), A_FLOAT, 0); class_addmethod(c,(t_method)pileup_inverse_gain,gensym("inverse_gain"), A_FLOAT, 0); class_addmethod(c,(t_method)pileup_persistence,gensym("persistence"), A_FLOAT, 0); class_addmethod(c,(t_method)pileup_lowfreq,gensym("lowfreq"),A_FLOAT,0); class_addmethod(c,(t_method)pileup_highfreq,gensym("highfreq"),A_FLOAT,0); pileup_class = c; fftease_announce(OBJECT_NAME); } void pileup_highfreq(t_pileup *x, t_floatarg f) { t_float curfreq; t_fftease *fft = x->fft; if(f < x->lo_freq){ error("current minimum is %f",x->lo_freq); return; } if(f > fft->R/2 ){ f = fft->R/2; } x->hi_freq = f; fft->hi_bin = 1; curfreq = 0; while(curfreq < x->hi_freq) { ++(fft->hi_bin); curfreq += fft->c_fundamental; } } void pileup_lowfreq(t_pileup *x, t_floatarg f) { t_float curfreq; t_fftease *fft = x->fft; if(f > x->hi_freq){ error("current maximum is %f",x->lo_freq); return; } if(f < 0 ){ f = 0; } x->lo_freq = f; fft->lo_bin = 0; curfreq = 0; while( curfreq < x->lo_freq ) { ++(fft->lo_bin); curfreq += fft->c_fundamental ; } } void pileup_transpose(t_pileup *x, t_floatarg tf) { x->fft->P = tf; } void pileup_synthresh(t_pileup *x, t_floatarg thresh) { x->fft->synt = thresh; } void pileup_oscbank(t_pileup *x, t_floatarg flag) { x->fft->obank_flag = (short) flag; } void pileup_persistence(t_pileup *x, t_floatarg persistence) { x->persistence = persistence; } void pileup_clear(t_pileup *x) { x->last_frame = (t_float*)realloc(x->last_frame,(x->fft->N+2) * sizeof(t_float)); } void pileup_mode(t_pileup *x, t_floatarg mode) { if( mode >= 0 && mode <= 3) x->mode = (int) mode; } void pileup_inverse_gain(t_pileup *x, t_floatarg gain) { x->inverse_compensation_gain = gain; } void pileup_free(t_pileup *x){ if(x->fft->initialized){ free(x->last_frame); free(x->frames_left); } fftease_free(x->fft); free(x->fft); } void pileup_mute(t_pileup *x, t_floatarg f){ x->mute = (short)f; } void *pileup_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft; t_pileup *x = (t_pileup *)pd_new(pileup_class); outlet_new(&x->x_obj, gensym("signal")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft->initialized = 0; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void pileup_init(t_pileup *x) { t_fftease *fft = x->fft; short initialized = fft->initialized; fftease_init(fft); if(!initialized){ x->mode = 0; x->inverse_compensation_gain = 4.0; x->mute = 0; x->move_threshold = .00001 ; x->last_frame = (t_float *) calloc((fft->N+2), sizeof(t_float)); x->frames_left = (int *) calloc((fft->N+2), sizeof(int)); } else { x->last_frame = (t_float *) realloc(x->last_frame,(fft->N+2)*sizeof(t_float)); x->frames_left = (int *) realloc(x->frames_left, (fft->N+2) * sizeof(int)); x->fft->input = (t_float*) realloc(fft->input, fft->Nw * sizeof(t_float)); x->fft->output = (t_float*) realloc(fft->output, fft->Nw * sizeof(t_float)); x->fft->c_lastphase_in = (t_float*)realloc(fft->c_lastphase_in, (fft->N2+1) * sizeof(t_float)); x->fft->c_lastphase_out = (t_float*)realloc(fft->c_lastphase_out, (fft->N2+1) * sizeof(t_float)); } x->tadv = (t_float) fft->D / (t_float)fft->R ; } static void do_pileup(t_pileup *x) { int i; t_fftease *fft = x->fft; t_float *last_frame = x->last_frame; t_float persistence = x->persistence; // decay factor int N = fft->N; t_float *channel = fft->channel; fftease_fold(fft); fftease_rdft(fft,FFT_FORWARD); fftease_convert(fft); if( x->mode == 0 ){ for( i = 0; i < N; i += 2 ){ if( fabs( channel[i] ) < last_frame[i] ){ // fabs? channel[i] = last_frame[i]; channel[i + 1] = last_frame[i + 1]; } else { last_frame[i] = fabs( channel[i] ); last_frame[i + 1] = channel[i + 1]; } } } else if( x->mode == 1) { for( i = 0; i < N; i += 2 ){ if( fabs( channel[i] ) < last_frame[i] ){ // fabs? channel[i] = last_frame[i]; } else { last_frame[i] = fabs( channel[i] ); } } } else if( x->mode == 2 ){ for( i = 0; i < N; i += 2 ){ if( fabs( channel[i] ) > last_frame[i] ){ // fabs? // only preserve phase in this case // channel[i] = last_frame[i] * x->inverse_compensation_gain; channel[i + 1] = last_frame[i + 1]; } else { last_frame[i] = fabs( channel[i] ); last_frame[i + 1] = channel[i + 1]; } } } if( persistence < 1.0){ for( i = 0; i < N; i += 2 ){ last_frame[i] *= persistence; } } if(fft->obank_flag){ fftease_oscbank(fft); } else { fftease_unconvert(fft); fftease_rdft(fft,FFT_INVERSE); fftease_overlapadd(fft); } } t_int *pileup_perform(t_int *w) { int i,j; t_pileup *x = (t_pileup *) (w[1]); t_float *MSPInputVector = (t_float *)(w[2]); t_float *MSPOutputVector = (t_float *)(w[3]); t_fftease *fft = x->fft; int D = fft->D; int Nw = fft->Nw; t_float *input = fft->input; t_float *output = fft->output; t_float mult = fft->mult; int MSPVectorSize = fft->MSPVectorSize; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+4; } if( fft->obank_flag ) mult *= FFTEASE_OSCBANK_SCALAR; if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_pileup(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_pileup(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_pileup(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+4; } void pileup_dsp(t_pileup *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ pileup_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(pileup_perform, 3, x, sp[0]->s_vec, sp[1]->s_vec); } } pd-fftease-3.0.1/power_of_two.c000066400000000000000000000003411401707710000164010ustar00rootroot00000000000000 int fftease_power_of_two(int test) { int limit = 1048576; int compare = 1; do { if(test == compare){ return 1; } compare *= 2; } while (compare <= limit); return 0; } pd-fftease-3.0.1/pvcompand~.c000066400000000000000000000225231401707710000160630ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *pvcompand_class; #define OBJECT_NAME "pvcompand~" typedef struct _pvcompand { t_object x_obj; t_float x_f; t_fftease *fft; t_float rescale; t_float *curthresh; t_float *atten; t_float *thresh; int count; t_float thresh_interval; t_float max_atten; t_float atten_interval; t_float tstep; t_float gstep; t_float last_max_atten; short norml; short mute; } t_pvcompand; static void pvcompand_dsp(t_pvcompand *x, t_signal **sp); static t_int *pvcompand_perform(t_int *w); static void *pvcompand_new(t_symbol *s, int argc, t_atom *argv); static void update_thresholds(t_pvcompand *x); static void pvcompand_normalize(t_pvcompand *x, t_floatarg val); static void pvcompand_free(t_pvcompand *x); static float pvcompand_ampdb(float db); static void pvcompand_init(t_pvcompand *x); static void pvcompand_mute(t_pvcompand *x, t_floatarg f); void pvcompand_tilde_setup(void) { t_class *c; c = class_new(gensym("pvcompand~"), (t_newmethod)pvcompand_new, (t_method)pvcompand_free,sizeof(t_pvcompand), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_pvcompand, x_f); class_addmethod(c,(t_method)pvcompand_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)pvcompand_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)pvcompand_normalize,gensym("normalize"), A_FLOAT, 0); pvcompand_class = c; fftease_announce(OBJECT_NAME); } void pvcompand_mute(t_pvcompand *x, t_floatarg f) { x->mute = (short)f; } void pvcompand_free( t_pvcompand *x ){ if(x->fft->initialized){ free(x->curthresh); free(x->atten); free(x->thresh); } fftease_free(x->fft); free(x->fft); } void *pvcompand_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft; 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")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft->initialized = 0; x->max_atten = -6.0; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void pvcompand_init(t_pvcompand *x) { t_fftease *fft = x->fft; short initialized = x->fft->initialized; fftease_init(fft); if(!initialized){ x->norml = 0; x->mute = 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->thresh = (t_float *) calloc((fft->N), sizeof(t_float)); x->atten = (t_float *) calloc(fft->N, sizeof(t_float) ); x->curthresh = (t_float *) calloc(fft->N, sizeof(t_float) ); } else if(initialized == 1) { x->thresh = (t_float *) realloc(x->thresh, fft->N * sizeof(t_float)); x->atten = (t_float *) realloc(x->atten, fft->N * sizeof(t_float)); x->curthresh = (t_float *) realloc(x->curthresh, fft->N * sizeof(t_float)); } update_thresholds(x); } void update_thresholds( t_pvcompand *x ) { int i; t_float nowamp = x->max_atten ; t_float nowthresh = 0.0 ; int N = x->fft->N; 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 >= N){ error("count exceeds %d",N); x->count = 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 >= N){ error("count exceeds %d",N); x->count = N - 1; break; } } } for( i = 0; i < x->count; i++){ x->thresh[i] = pvcompand_ampdb( nowthresh ); nowthresh -= x->tstep ; } } void pvcompand_normalize(t_pvcompand *x, t_floatarg val) { x->norml = (short)val; } static void do_pvcompand(t_pvcompand *x) { t_fftease *fft = x->fft; t_float *channel = fft->channel; int N = fft->N; t_float *curthresh = x->curthresh; t_float *thresh = x->thresh; t_float *atten = x->atten; int count = x->count; t_float max_atten = x->max_atten; int i,j; t_float maxamp ; t_float cutoff; t_float avr, new_avr, rescale; fftease_fold(fft); fftease_rdft(fft,FFT_FORWARD); fftease_leanconvert(fft); 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] ; } if( x->norml ) { if( new_avr <= 0 ){ new_avr = .0001; } rescale = avr / new_avr ; } else { rescale = pvcompand_ampdb( max_atten * -.5); } for( i = 0; i < N; i += 2){ channel[i] *= rescale; } fftease_leanunconvert(fft); fftease_rdft(fft, FFT_INVERSE); fftease_overlapadd(fft); } t_int *pvcompand_perform(t_int *w) { int i,j; t_pvcompand *x = (t_pvcompand *) (w[1]); t_float *MSPInputVector = (t_float *)(w[2]); t_float *in2 = (t_float *)(w[3]); t_float *MSPOutputVector = (t_float *)(w[4]); t_fftease *fft = x->fft; int D = fft->D; int Nw = fft->Nw; t_float *input = fft->input; t_float *output = fft->output; t_float mult = fft->mult; int MSPVectorSize = fft->MSPVectorSize; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+5; } x->max_atten = *in2; if(x->max_atten != x->last_max_atten) { x->last_max_atten = x->max_atten; update_thresholds(x); } if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_pvcompand(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_pvcompand(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_pvcompand(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+5; } float pvcompand_ampdb(float db) { float amp; amp = pow((t_float)10.0, (t_float)(db/20.0)) ; return(amp); } void pvcompand_dsp(t_pvcompand *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ pvcompand_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(pvcompand_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); } } pd-fftease-3.0.1/pvgrain~.c000066400000000000000000000226271401707710000155470ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *pvgrain_class; #define OBJECT_NAME "pvgrain~" typedef struct _pvgrain { t_object x_obj; t_float x_f; t_fftease *fft; short *binsort; t_float topfreq; t_float bottomfreq; short bypass; int mute; t_float grain_probability; t_float sample_basefreq; int grains_per_frame; void *list_outlet; t_float *listdata; short list_count; void *m_clock; t_atom myList[2]; } t_pvgrain; static void pvgrain_dsp(t_pvgrain *x, t_signal **sp); static t_int *pvgrain_perform(t_int *w); static void *pvgrain_new(t_symbol *s, int argc, t_atom *argv); static void pvgrain_mute(t_pvgrain *x, t_floatarg state); static void pvgrain_tick(t_pvgrain *x); static void pvgrain_printchan(t_pvgrain *x); static void pvgrain_probability (t_pvgrain *x, t_floatarg prob); static void pvgrain_framegrains (t_pvgrain *x, t_floatarg grains); static void pvgrain_topfreq (t_pvgrain *x, t_floatarg top); static void pvgrain_bottomfreq (t_pvgrain *x, t_floatarg f); static void pvgrain_basefreq (t_pvgrain *x, t_floatarg base); static void pvgrain_init(t_pvgrain *x); static void pvgrain_free(t_pvgrain *x); void pvgrain_tilde_setup(void) { t_class *c; c = class_new(gensym("pvgrain~"), (t_newmethod)pvgrain_new, (t_method)pvgrain_free,sizeof(t_pvgrain), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_pvgrain, x_f); class_addmethod(c,(t_method)pvgrain_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)pvgrain_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)pvgrain_printchan,gensym("printchan"),A_DEFFLOAT,0); class_addmethod(c,(t_method)pvgrain_probability,gensym("probability"),A_DEFFLOAT,0); class_addmethod(c,(t_method)pvgrain_framegrains,gensym("framegrains"),A_DEFFLOAT,0); class_addmethod(c,(t_method)pvgrain_topfreq,gensym("topfreq"),A_FLOAT,0); class_addmethod(c,(t_method)pvgrain_bottomfreq,gensym("bottomfreq"),A_FLOAT,0); class_addmethod(c,(t_method)pvgrain_basefreq,gensym("basefreq"),A_FLOAT,0); pvgrain_class = c; fftease_announce(OBJECT_NAME); } void pvgrain_printchan(t_pvgrain *x) { int i; t_float *channel = x->fft->channel; post("***"); for( i = 0 ; i < 30; i+= 2 ){ post("amp %f freq %f", channel[i*2], channel[i*2 + 1]); } post("***"); } void pvgrain_basefreq (t_pvgrain *x, t_floatarg base) { int R = x->fft->R; if( base < 0.0 ) base = 0. ; if( base > R / 2 ) base = R / 2 ; x->sample_basefreq = base; } void pvgrain_topfreq (t_pvgrain *x, t_floatarg top) { int R = x->fft->R; t_fftease *fft = x->fft; if( top < 50. ){ top = 50.; } if(R > 0){ if( top > R / 2 ){ top = R / 2; } x->topfreq = top; fftease_oscbank_setbins(fft,x->bottomfreq, x->topfreq); } else { x->topfreq = top; } // post("topfreq set to %f",x->topfreq); } void pvgrain_bottomfreq (t_pvgrain *x, t_floatarg f) { int R = x->fft->R; t_fftease *fft = x->fft; if(R > 0){ if( f >= x->topfreq || f >= R/2){ post("pvgrain~: %f is too high a bottom freq",f); return; } x->bottomfreq = f; fftease_oscbank_setbins(fft,x->bottomfreq, x->topfreq); } else { x->bottomfreq = f; } } void pvgrain_probability (t_pvgrain *x, t_floatarg prob) { if( prob < 0. ) prob = 0.; if( prob > 1. ) prob = 1.; x->grain_probability = prob ; // post("probability set to %f",x->grain_probability); } void pvgrain_framegrains (t_pvgrain *x, t_floatarg grains) { int N2 = x->fft->N2; if( grains < 1 ){ grains = 1; } if(N2 > 0){ if( grains > N2 - 1 ){ grains = N2 - 1; } } x->grains_per_frame = grains; // post("grains-per-frame set to %d",x->grains_per_frame); } void pvgrain_tick(t_pvgrain *x) { t_atom *myList = x->myList; t_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,0,2,myList); } void *pvgrain_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft; t_pvgrain *x = (t_pvgrain *)pd_new(pvgrain_class); x->list_outlet = outlet_new(&x->x_obj, gensym("list")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft->initialized = 0; x->grain_probability = 0.0001; x->topfreq = 1000.0; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void pvgrain_init(t_pvgrain *x) { t_fftease *fft = x->fft; short initialized = fft->initialized; fftease_init(fft); if(!initialized){ x->m_clock = clock_new(x,(void *)pvgrain_tick); x->sample_basefreq = 261.0; x->bottomfreq = 0.0; x->mute = 0; x->binsort = (short *) calloc((fft->N2+1), sizeof(short) ); x->listdata = (t_float *) calloc(40, sizeof(t_float)); } else if(initialized == 1) { x->binsort = (short *) realloc(x->binsort,(fft->N2+1) * sizeof(short)); } fftease_oscbank_setbins(fft,x->bottomfreq, x->topfreq); } void pvgrain_free(t_pvgrain *x) { if(x->fft->initialized){ free(x->binsort); free(x->listdata); clock_free(x->m_clock); } fftease_free(x->fft); free(x->fft); } static void do_pvgrain(t_pvgrain *x) { int i,j; t_float tmp, dice; short print_grain; t_fftease *fft = x->fft; t_float *channel = fft->channel; short *binsort = x->binsort; int grains_per_frame = x->grains_per_frame ; t_float selection_probability = x->grain_probability; int hi_bin = fft->hi_bin; int lo_bin = fft->lo_bin; t_float *listdata = x->listdata; x->list_count = 0; fftease_fold(fft); fftease_rdft(fft,FFT_FORWARD); fftease_convert(fft); 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 = fftease_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 ){ listdata[ x->list_count * 2 ] = channel[ binsort[i]*2 ]; listdata[ (x->list_count * 2) + 1 ] = channel[(binsort[i]*2) + 1] ; ++(x->list_count); clock_delay(x->m_clock,0); } } } t_int *pvgrain_perform(t_int *w) { int i; t_pvgrain *x = (t_pvgrain *) (w[1]); t_float *MSPInputVector = (t_float *)(w[2]); t_fftease *fft = x->fft; int D = fft->D; int Nw = fft->Nw; t_float *input = fft->input; int MSPVectorSize = fft->MSPVectorSize; t_float *internalInputVector = fft->internalInputVector; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; if (x->mute) { return w+3; } if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_pvgrain(x); } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_pvgrain(x); } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_pvgrain(x); } fft->operationCount = operationCount; } return w+3; } void pvgrain_mute(t_pvgrain *x, t_floatarg state) { x->mute = (short)state; } void pvgrain_dsp(t_pvgrain *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ pvgrain_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(pvgrain_perform, 2, x, sp[0]->s_vec); } } pd-fftease-3.0.1/pvharm~.c000066400000000000000000000263731401707710000154000ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *pvharm_class; #define OBJECT_NAME "pvharm~" typedef struct _pvharm { t_object x_obj; t_float x_f; t_fftease *fft; t_fftease *fft2; short mute; short peakflag; t_float hifreq;/* highest frequency to synthesize */ t_float lofreq;/* lowest frequency to synthesize */ t_float framethresh; /* set lower limit for synth cutoff, to avoid noise */ int osclimit; int oscnt; t_float local_thresh; t_float framepeak; t_float *ampsort; /* sort amplitudes from highest to lowest */ short compressor; /* flag to compress */ t_float framestop; /* amplitude below which compressor is turned off */ } t_pvharm; static void pvharm_dsp(t_pvharm *x, t_signal **sp); static t_int *pvharm_perform(t_int *w); static void *pvharm_new(t_symbol *s, int argc, t_atom *argv); static void pvharm_mute(t_pvharm *x, t_floatarg f); static void pvharm_init(t_pvharm *x); static void pvharm_free(t_pvharm *x); static void pvharm_oscnt(t_pvharm *x); static void pvharm_osclimit(t_pvharm *x, t_floatarg f); static void pvharm_compressor(t_pvharm *x, t_floatarg state); static void pvharm_framestop(t_pvharm *x, t_floatarg state); static void pvharm_lowfreq(t_pvharm *x, t_floatarg f); static void pvharm_highfreq(t_pvharm *x, t_floatarg f); static void pvharm_rel2peak(t_pvharm *x, t_floatarg toggle); void pvharm_tilde_setup(void) { t_class *c; c = class_new(gensym("pvharm~"), (t_newmethod)pvharm_new, (t_method)pvharm_free,sizeof(t_pvharm), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_pvharm, x_f); class_addmethod(c,(t_method)pvharm_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)pvharm_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)pvharm_osclimit,gensym("osclimit"),A_FLOAT,0); class_addmethod(c,(t_method)pvharm_oscnt,gensym("oscnt"),0); class_addmethod(c,(t_method)pvharm_compressor,gensym("compressor"),A_FLOAT,0); class_addmethod(c,(t_method)pvharm_framestop,gensym("framestop"),A_FLOAT,0); class_addmethod(c,(t_method)pvharm_highfreq,gensym("highfreq"),A_FLOAT,0); class_addmethod(c,(t_method)pvharm_lowfreq,gensym("lowfreq"),A_FLOAT,0); pvharm_class = c; fftease_announce(OBJECT_NAME); } void pvharm_lowfreq(t_pvharm *x, t_floatarg f) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int R = x->fft->R; if(R > 0){ if(f > x->hifreq){ error("%s: minimum cannot exceed current maximum: %f",OBJECT_NAME,x->hifreq); return; } if(f < 0 ){ f = 0; } x->lofreq = f; fftease_oscbank_setbins(fft,x->lofreq, x->hifreq); fftease_oscbank_setbins(fft2,x->lofreq, x->hifreq); } else { x->lofreq = f; } } void pvharm_highfreq(t_pvharm *x, t_floatarg f) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int R = x->fft->R; if(R > 0){ if(f < x->lofreq){ error("%s: maximum cannot go below current minimum: %f",OBJECT_NAME,x->lofreq); return; } if(f > R/2 ){ f = R/2; } x->hifreq = f; fftease_oscbank_setbins(fft,x->lofreq, x->hifreq); fftease_oscbank_setbins(fft2,x->lofreq, x->hifreq); } else { x->hifreq = f; } } void pvharm_oscnt(t_pvharm *x) { post("%s: osc count: %d, local thresh: %f, frame peak: %f",OBJECT_NAME, x->oscnt, x->local_thresh, x->framepeak); } void pvharm_free(t_pvharm *x) { if(x->fft->initialized){ free(x->ampsort); } fftease_free(x->fft); fftease_free(x->fft2); free(x->fft); free(x->fft2); } void pvharm_rel2peak(t_pvharm *x, t_floatarg toggle) { x->peakflag = (short)toggle; } void *pvharm_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft, *fft2; 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")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); x->fft2 = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft2 = x->fft2; fft->initialized = 0; fft2->initialized = 0; x->lofreq = 0; x->hifreq = 15000; fft2->N = fft->N = FFTEASE_DEFAULT_FFTSIZE; fft2->overlap = fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft2->winfac = fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = fft2->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = fft2->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void pvharm_init(t_pvharm *x) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; short initialized = fft->initialized; fftease_init(fft); fftease_init(fft2); if(!initialized){ x->framethresh = 0.005; x->osclimit = fft->N2; fft->P = .5 ; // for testing purposes fft2->P = .6666666666 ; // for testing purposes x->mute = 0; x->compressor = 0; x->framestop = .001; x->ampsort = (t_float *) calloc((fft->N+1), sizeof(t_float)); } else if(initialized == 1){ x->ampsort = (t_float *) realloc(x->ampsort, (fft->N+1) * sizeof(t_float)); } fftease_oscbank_setbins(fft, x->lofreq, x->hifreq); fftease_oscbank_setbins(fft2, x->lofreq, x->hifreq); } static void do_pvharm(t_pvharm *x) { t_float framethresh = x->framethresh; int osclimit = x->osclimit; t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int i; int D = fft->D; int freq, amp,chan; t_float framesum, frame_rescale; t_float framestop = x->framestop; t_float *channel = fft->channel; t_float *channel2 = fft2->channel; t_float *output = fft->output; t_float *output2 = fft2->output; int lo_bin = fft->lo_bin; int hi_bin = fft->hi_bin; fftease_fold(fft); fftease_rdft(fft,FFT_FORWARD); fftease_convert(fft); if(x->compressor){ framesum = 0.0; for(chan = fft->lo_bin; chan < fft->hi_bin; chan++){ amp = chan << 1; framesum += channel[amp]; } if(framesum > framestop && framesum >= 0.0){ frame_rescale = 1.0 / framesum; for(chan = lo_bin; chan < hi_bin; chan++){ amp = chan << 1; channel[amp] *= frame_rescale; } } } // copy spectrum to second channel (yes it is inefficient) for(chan = lo_bin; chan < hi_bin; chan++){ amp = chan << 1; freq = amp + 1; channel2[amp] = channel[amp]; channel2[freq] = channel[freq]; } fftease_limited_oscbank(fft, osclimit, framethresh); fftease_limited_oscbank(fft2, osclimit, framethresh); for(i = 0; i < D; i++){ output[i] += output2[i]; } } t_int *pvharm_perform(t_int *w) { int i,j; t_pvharm *x = (t_pvharm *) (w[1]); t_float *MSPInputVector = (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 *MSPOutputVector = (t_float *)(w[6]); t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int D = fft->D; int Nw = fft->Nw; t_float *input = fft->input; t_float *output = fft->output; t_float *output2 = fft2->output; t_float mult = fft->mult; int MSPVectorSize = fft->MSPVectorSize; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; if(x->mute){ for( j = 0; j < MSPVectorSize; j++) { *MSPOutputVector++ = *MSPInputVector++ * FFTEASE_BYPASS_GAIN; } return w+7; } fft->P = *in2; fft2->P = *in3; fft->synt = fft2->synt = *in4; if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_pvharm(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } memcpy(output2, output2 + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output2[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_pvharm(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } memcpy(output2, output2 + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output2[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_pvharm( x ); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } memcpy(output2, output2 + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output2[j] = 0.0; } } fft->operationCount = operationCount; } return w+7; } void pvharm_compressor(t_pvharm *x, t_floatarg state) { x->compressor = (short)state; } void pvharm_framestop(t_pvharm *x, t_floatarg state) { x->framestop = state; } void pvharm_mute(t_pvharm *x, t_floatarg state) { x->mute = (short)state; } void pvharm_osclimit(t_pvharm *x, t_floatarg limit) { x->osclimit = (int)limit; } void pvharm_dsp(t_pvharm *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(!samplerate) return; if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); fft2->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft2); } if(fft->R != samplerate ){ fft->R = samplerate; fft2->R = samplerate; } if(reset_required){ pvharm_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(pvharm_perform, 6, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,sp[3]->s_vec, sp[4]->s_vec); } } pd-fftease-3.0.1/pvoc~.c000066400000000000000000000165761401707710000150560ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *pvoc_class; #define OBJECT_NAME "pvoc~" typedef struct _pvoc { t_object x_obj; float x_f; t_fftease *fft; t_float lofreq; t_float hifreq; t_float topfreq; short mute; } t_pvoc; static void *pvoc_new(t_symbol *s, int argc, t_atom *argv); static void pvoc_free(t_pvoc *x); static void pvoc_mute(t_pvoc *x, t_floatarg tog); static void pvoc_init(t_pvoc *x); static void pvoc_fftinfo(t_pvoc *x); static void pvoc_lowfreq(t_pvoc *x, t_floatarg f); static void pvoc_highfreq(t_pvoc *x, t_floatarg f); static void do_pvoc(t_pvoc *x ); static t_int *pvoc_perform(t_int *w); static void pvoc_dsp(t_pvoc *x, t_signal **sp); 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"), A_CANT, 0); class_addmethod(pvoc_class,(t_method)pvoc_mute,gensym("mute"),A_FLOAT,0); class_addmethod(pvoc_class,(t_method)pvoc_lowfreq,gensym("lowfreq"),A_FLOAT,0); class_addmethod(pvoc_class,(t_method)pvoc_highfreq,gensym("highfreq"),A_FLOAT,0); class_addmethod(pvoc_class,(t_method)pvoc_fftinfo,gensym("fftinfo"),0); fftease_announce(OBJECT_NAME); } void pvoc_lowfreq(t_pvoc *x, t_floatarg f) { if(!x->fft->initialized){ if(f >= 0 && f < 5000){ x->lofreq = f; } return; } if(f < 0 ){ f = 0; } x->lofreq = f; fftease_oscbank_setbins(x->fft,x->lofreq, x->hifreq); } void pvoc_highfreq(t_pvoc *x, t_floatarg f) { if(!x->fft->initialized){ if(f > 0 && f < 22050){ x->hifreq = f; } return; } if(f < 0 ){ f = 0; } if(f < x->lofreq){ error("%s: maximum cannot go below current minimum: %f",OBJECT_NAME,x->lofreq); return; } if(f > x->fft->R/2 ){ f = x->fft->R/2; } x->hifreq = f; fftease_oscbank_setbins(x->fft,x->lofreq, x->hifreq); } void pvoc_mute(t_pvoc *x, t_floatarg tog) { x->mute = (short)tog; } void pvoc_fftinfo(t_pvoc *x) { t_fftease *fft = x->fft; fftease_fftinfo( fft, OBJECT_NAME ); } void pvoc_free(t_pvoc *x ){ fftease_free(x->fft); free(x->fft); } void pvoc_init(t_pvoc *x) { float curfreq; t_fftease *fft = x->fft; if(fft->initialized == -1){ return; } fftease_init(fft); if( x->hifreq < fft->c_fundamental ) { post("default hi frequency of 18000 Hz"); x->hifreq = 18000.0 ; } x->fft->hi_bin = 1; curfreq = 0; while( curfreq < x->hifreq ) { ++(x->fft->hi_bin); curfreq += fft->c_fundamental ; } x->fft->lo_bin = 0; curfreq = 0; while( curfreq < x->lofreq ) { ++(x->fft->lo_bin); curfreq += fft->c_fundamental; } } void *pvoc_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft; 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")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; x->lofreq = 0; x->hifreq = 15000; x->mute = 0; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv);} if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv);} if(argc > 2){ x->lofreq = atom_getfloatarg(2, argc, argv);} if(argc > 3){ x->hifreq = atom_getfloatarg(3, argc, argv);} fft->initialized = 0;// prepare for init in DSP routine return x; } static void do_pvoc(t_pvoc *x) { t_fftease *fft = x->fft; fftease_fold(fft); fftease_rdft(fft, 1); fftease_convert(fft); fftease_oscbank(fft); } t_int *pvoc_perform(t_int *w) { t_pvoc *x = (t_pvoc *) (w[1]); t_float *MSPInputVector = (t_float *)(w[2]); t_float *transp = (t_float *)(w[3]); t_float *synth_thresh = (t_float *)(w[4]); t_float *MSPOutputVector = (t_float *)(w[5]); t_fftease *fft = x->fft; int i, j; int D = fft->D; int Nw = fft->Nw; t_float mult = fft->mult; t_float *input = fft->input; t_float *output = fft->output; int MSPVectorSize = fft->MSPVectorSize; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+6; } fft->P = *transp; fft->pitch_increment = fft->P*fft->L/fft->R; fft->synt = *synth_thresh; // HERE IS THE GOOD STUFF if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_pvoc( x ); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_pvoc( x ); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_pvoc( x ); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+6; } void pvoc_dsp(t_pvoc *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate ){ fft->R = samplerate; } if(reset_required){ pvoc_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(pvoc_perform, 5, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); } } pd-fftease-3.0.1/pvtuner~.c000066400000000000000000000725641401707710000156110ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *pvtuner_class; #define OBJECT_NAME "pvtuner~" #define MAXTONES (8192) #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 #define EQN 17 typedef struct { t_float *pitchgrid; int scale_steps; // total number of members short current_scale; } t_pvtuner_scale; typedef struct _pvtuner { t_object x_obj; t_float x_f; t_fftease *fft; int lo_bin; int hi_bin; int hi_tune_bin; t_float topfreq; t_float curfreq; // TUNING float *pitchgrid; float pbase; int scale_steps; short current_scale; short mute; t_float lofreq; t_float hifreq; t_float tabscale; int scale_len; short verbose; long fftsize_attr; long overlap_attr; long scale_interpolation; // interpolation flag, set to zero by default t_float interpolation_dur; // set to 1 second long interpolation_frames; // == duration / (D/R) long interpolation_countdown; // count frames for interpolation t_float ip; // interpolation point t_pvtuner_scale *this_scale; t_pvtuner_scale *last_scale; } t_pvtuner; static void pvtuner_dsp(t_pvtuner *x, t_signal **sp); static t_int *pvtuner_perform(t_int *w); static t_float closestf(t_float test, t_float *arr) ; static void pvtuner_diatonic( t_pvtuner *x ); static void pvtuner_eastern( t_pvtuner *x ); static void pvtuner_minor( t_pvtuner *x ); static void pvtuner_eq12( t_pvtuner *x ); static void pvtuner_pentatonic( t_pvtuner *x ); static void pvtuner_major_added_sixth( t_pvtuner *x ); static void pvtuner_minor_added_sixth( t_pvtuner *x ); static void pvtuner_major_seventh_chord( t_pvtuner *x ); static void pvtuner_minor_seventh_chord( t_pvtuner *x ); static void pvtuner_dominant_seventh_chord( t_pvtuner *x ); static void pvtuner_eq8( t_pvtuner *x ); static void pvtuner_pentaclust( t_pvtuner *x ); static void pvtuner_quarterclust( t_pvtuner *x ); static void pvtuner_eq5( t_pvtuner *x ); static void pvtuner_slendro( t_pvtuner *x ); static void pvtuner_pelog( t_pvtuner *x ); static void pvtuner_update_imported( t_pvtuner *x ); static void pvtuner_init(t_pvtuner *x); static void *pvtuner_new(t_symbol *s, int argc, t_atom *argv); static void pvtuner_list (t_pvtuner *x, t_symbol *msg, short argc, t_atom *argv); static void pvtuner_frequency_range(t_pvtuner *x, t_floatarg lo, t_floatarg hi); static void pvtuner_basefreq( t_pvtuner *x, t_floatarg bassfreq); static void pvtuner_free(t_pvtuner *x); static void pvtuner_mute(t_pvtuner *x, t_floatarg state); static void pvtuner_list (t_pvtuner *x, t_symbol *msg, short argc, t_atom *argv); static void pvtuner_eqn(t_pvtuner *x, t_floatarg steps); static void pvtuner_interpolation(t_pvtuner *x, t_floatarg state); static void pvtuner_binfo(t_pvtuner *x); static void pvtuner_copy_scale(t_pvtuner *x); static void pvtuner_toptune(t_pvtuner *x, t_floatarg f); void pvtuner_tilde_setup(void) { t_class *c; c = class_new(gensym("pvtuner~"), (t_newmethod)pvtuner_new, (t_method)pvtuner_free,sizeof(t_pvtuner), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_pvtuner, x_f); class_addmethod(c,(t_method)pvtuner_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)pvtuner_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)pvtuner_basefreq,gensym("basefreq"),A_DEFFLOAT,0); class_addmethod(c,(t_method)pvtuner_diatonic,gensym("diatonic"),0); class_addmethod(c,(t_method)pvtuner_eastern,gensym("eastern"),0); class_addmethod(c,(t_method)pvtuner_minor,gensym("minor"),0); class_addmethod(c,(t_method)pvtuner_eq12,gensym("eq12"),0); class_addmethod(c,(t_method)pvtuner_pentatonic,gensym("pentatonic"),0); class_addmethod(c,(t_method)pvtuner_major_added_sixth,gensym("added_sixth_major"),0); class_addmethod(c,(t_method)pvtuner_minor_added_sixth,gensym("added_sixth_minor"),0); class_addmethod(c,(t_method)pvtuner_major_seventh_chord,gensym("major_seventh_chord"),0); class_addmethod(c,(t_method)pvtuner_minor_seventh_chord,gensym("minor_seventh_chord"),0); class_addmethod(c,(t_method)pvtuner_dominant_seventh_chord,gensym("dominant_seventh_chord"),0); class_addmethod(c,(t_method)pvtuner_eq8,gensym("eq8"),0); class_addmethod(c,(t_method)pvtuner_pentaclust,gensym("pentaclust"),0); class_addmethod(c,(t_method)pvtuner_quarterclust,gensym("quarterclust"),0); class_addmethod(c,(t_method)pvtuner_eq5,gensym("eq5"),0); class_addmethod(c,(t_method)pvtuner_eqn,gensym("eqn"),A_FLOAT, 0); class_addmethod(c,(t_method)pvtuner_interpolation,gensym("interpolation"),A_FLOAT, 0); class_addmethod(c,(t_method)pvtuner_slendro,gensym("slendro"),0); class_addmethod(c,(t_method)pvtuner_pelog,gensym("pelog"),0); class_addmethod(c,(t_method)pvtuner_list,gensym("list"),A_GIMME,0); class_addmethod(c,(t_method)pvtuner_frequency_range,gensym("frequency_range"),A_FLOAT,A_FLOAT, 0); pvtuner_class = c; fftease_announce(OBJECT_NAME); } void *pvtuner_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft; 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")); inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal")); outlet_new(&x->x_obj, gensym("signal")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft->initialized = 0; x->verbose = 0; x->lofreq = 0; x->hifreq = 18000; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } /* Copies current scale (this_scale) to next scale (next_scale) */ void pvtuner_copy_scale(t_pvtuner *x) { int i; t_pvtuner_scale *this = x->this_scale; t_pvtuner_scale *last = x->last_scale; last->scale_steps = this->scale_steps; last->current_scale = this->current_scale; for(i = 0; i < last->scale_steps; i++){ last->pitchgrid[i] = this->pitchgrid[i]; } } void pvtuner_init(t_pvtuner *x) { int mem; t_fftease *fft = x->fft; if( fft->R <= 0.0 ){ post("%s: zero sample rate reported - initialization deferred", OBJECT_NAME); x->fft->initialized = 0; // failed initialization return; } if(!x->fft->initialized){ x->mute = 0; mem = (MAXTONES+1)*sizeof(float); x->pitchgrid = (float *) calloc(mem,1); x->pbase = BASE_FREQ; x->this_scale = (t_pvtuner_scale *) calloc(1,sizeof(t_pvtuner_scale)); x->last_scale = (t_pvtuner_scale *) calloc(1,sizeof(t_pvtuner_scale)); x->this_scale->pitchgrid = (t_float *) calloc(1,mem); x->last_scale->pitchgrid = (t_float *) calloc(1,mem); x->this_scale->scale_steps = 0; x->last_scale->scale_steps = 0; pvtuner_diatonic(x);// default scale (rebuilt for new scale structure) pvtuner_copy_scale(x); // now both this and next scale are diatonic } fftease_init(fft); if( x->fft->D && x->fft->R ){ /* x->interpolation_frames = x->interpolation_dur / ((float)x->fft->D / (float)x->fft->R); post("interpolation frames: %d", x->interpolation_frames); */ } else { post("pvtuner~: dire warning!"); return; // dire warning } fftease_oscbank_setbins(fft,x->lofreq, x->hifreq); x->hi_tune_bin = fft->hi_bin; } void pvtuner_toptune(t_pvtuner *x, t_floatarg f) { int tbin; t_float curfreq; t_float fundamental = x->fft->c_fundamental; t_fftease *fft = x->fft; tbin = 1; curfreq = 0; if( f < 0 || f > x->fft->R / 2.0 ){ error("frequency %f out of range", f); return; } while( curfreq < f ) { ++tbin; curfreq += fundamental ; } if( tbin > fft->lo_bin && tbin <= fft->hi_bin ){ x->hi_tune_bin = tbin; } else { error("pvtuner~: bin %d out of range", tbin); } } void pvtuner_list (t_pvtuner *x, t_symbol *msg, short argc, t_atom *argv) { t_float *pitchgrid = x->this_scale->pitchgrid; t_float dval; t_pvtuner_scale *s = x->this_scale; int i = 0; if( ! atom_getfloatarg(i,argc,argv) ){ error("either zero length scale or 0.0 (prohibited) is first value"); return; } pvtuner_copy_scale(x); /* first set every value to maximum */ for(i=0; i < MAXTONES; i++){ pitchgrid[i] = (t_float)x->fft->R / 2.0; } // now read scale for( i = 0; i < argc; i++ ){ dval = atom_getfloatarg(i,argc,argv); pitchgrid[ i ] = dval; } s->scale_steps = argc; s->current_scale = IMPORTED_SCALE; } void pvtuner_binfo(t_pvtuner *x) { t_fftease *fft = x->fft; post("%s: frequency targets: %f %f", OBJECT_NAME, x->lofreq, x->hifreq); post("synthesizing %d bins, from %d to %d",(fft->hi_bin - fft->lo_bin), fft->lo_bin, fft->hi_bin); } void pvtuner_frequency_range(t_pvtuner *x, t_floatarg lo, t_floatarg hi) { t_fftease *fft = x->fft; x->lofreq = lo ; x->hifreq = hi; if( lo >= hi ){ error("low frequency must be lower than high frequency"); return; } x->curfreq = 0; fft->hi_bin = 0; while( x->curfreq < x->hifreq ) { ++(fft->hi_bin); x->curfreq += x->fft->c_fundamental; } x->curfreq = 0; fft->lo_bin = 0; while( x->curfreq < x->lofreq ) { ++(fft->lo_bin); x->curfreq += x->fft->c_fundamental ; } } static void do_pvtuner(t_pvtuner *x) { t_fftease *fft = x->fft; int freq,chan; t_float *channel = fft->channel; t_float *this_pitchgrid = x->this_scale->pitchgrid; t_float *last_pitchgrid = x->last_scale->pitchgrid; int hi_bin = fft->hi_bin; int lo_bin = fft->lo_bin; int hi_tune_bin = x->hi_tune_bin; long scale_interpolation = x->scale_interpolation; t_float ip = x->ip; t_float freq_this, freq_last; fftease_fold(fft); fftease_rdft(fft, 1); fftease_convert(fft); // static case if( scale_interpolation == 0) { for ( chan = lo_bin; chan < hi_bin; chan++ ) { freq = (chan * 2) + 1; if(chan <= hi_tune_bin){ channel[freq] = closestf(channel[freq], this_pitchgrid); } } } // interpolated case else if( scale_interpolation == 1) { // clip if( ip < 0 ) ip = 0; if( ip > 1 ) ip = 1; // degenerate cases first if( ip == 0 ){ for ( chan = lo_bin; chan < hi_bin; chan++ ) { freq = (chan * 2) + 1; if(chan <= hi_tune_bin){ channel[freq] = closestf(channel[freq], last_pitchgrid); } } } else if ( ip == 1){ for ( chan = lo_bin; chan < hi_bin; chan++ ) { freq = (chan * 2) + 1; if(chan <= hi_tune_bin){ channel[freq] = closestf(channel[freq], this_pitchgrid); } } } else { for ( chan = lo_bin; chan < hi_bin; chan++ ) { freq = (chan * 2) + 1; if(chan <= hi_tune_bin){ freq_this = closestf(channel[freq], this_pitchgrid); freq_last = closestf(channel[freq], last_pitchgrid); channel[freq] = freq_last + (freq_this - freq_last) * ip; // linear interpolation } } } } fftease_oscbank(fft); } t_int *pvtuner_perform(t_int *w) { int i,j; t_pvtuner *x = (t_pvtuner *) (w[1]); t_float *MSPInputVector = (t_float *)(w[2]); t_float *pitchfac = (t_float *)(w[3]); t_float *synth_thresh = (t_float *)(w[4]); t_float *ip = (t_float *)(w[5]); t_float *MSPOutputVector = (t_float *)(w[6]); t_fftease *fft = x->fft; int D = fft->D; int Nw = fft->Nw; t_float mult = fft->mult; t_float *input = fft->input; t_float *output = fft->output; int MSPVectorSize = fft->MSPVectorSize; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; if (x->mute) { memset(MSPOutputVector, 0.0, MSPVectorSize * sizeof(float)); return w+7; } fft->P = *pitchfac; fft->synt = *synth_thresh ; x->ip = *ip; if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_pvtuner(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_pvtuner(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_pvtuner(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+7; } void pvtuner_basefreq( t_pvtuner *x, t_floatarg bassfreq) { if(! x->fft->initialized){ return; } if( bassfreq < 1 ){ bassfreq = 1; post("%s: base frequency may not go lower than 1 Hz", OBJECT_NAME); } if( bassfreq > 10000. ){ bassfreq = 10000.; post("%s: base frequency may not go higher than 10000 Hz", OBJECT_NAME); } 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(x->fft->initialized){ free(x->this_scale); free(x->last_scale); } fftease_free(x->fft); free(x->fft); } void pvtuner_update_imported( t_pvtuner *x ){ t_float *pitchgrid = x->this_scale->pitchgrid; t_float factor; int i; if( pitchgrid[0] <= 0.0){ error("%s: illegal first value of scale: %f",OBJECT_NAME,pitchgrid[0]); return; } factor = x->pbase / pitchgrid[0]; pvtuner_copy_scale(x); // copies this scale to next for( i = 0; i < x->scale_len; i++ ) pitchgrid[i] *= factor; } void pvtuner_diatonic( t_pvtuner *x ){ int i, j; int octsteps = 7; t_pvtuner_scale *s = x->this_scale; pvtuner_copy_scale(x); // copies this scale to next s->pitchgrid[0] = x->pbase; s->pitchgrid[1] = x->pbase * (9./8.); s->pitchgrid[2] = x->pbase * (5./4.); s->pitchgrid[3] = x->pbase * (4./3.); s->pitchgrid[4] = x->pbase * (3./2.); s->pitchgrid[5] = x->pbase * (27./16.); s->pitchgrid[6] = x->pbase * (15./8.); s->scale_steps = 7; for( i = 1; i < 10; i++ ){ for( j = 0; j < octsteps; j++ ){ s->pitchgrid[ i * octsteps + j] = s->pitchgrid[j] * pow(2.0,(float)i); } } s->current_scale = DIATONIC ; s->scale_steps = 70; // 10 * 7 } void pvtuner_minor( t_pvtuner *x ){ int i, j; int octsteps = 7; t_pvtuner_scale *s = x->this_scale; t_float *pitchgrid = x->this_scale->pitchgrid; pvtuner_copy_scale(x); // copies this scale to next pitchgrid[0] = x->pbase; pitchgrid[1] = x->pbase * (9./8.); pitchgrid[2] = x->pbase * (6./5.); pitchgrid[3] = x->pbase * (4./3.); pitchgrid[4] = x->pbase * (3./2.); pitchgrid[5] = x->pbase * (8./5.); pitchgrid[6] = x->pbase * (9./5.); for( i = 1; i < 10; i++ ){ for( j = 0; j < octsteps; j++ ){ pitchgrid[ i * octsteps + j] = pitchgrid[j] * pow(2.0,(float)i); } } s->current_scale = MINOR; s->scale_steps = 70; } void pvtuner_pentatonic( t_pvtuner *x ){ int i, j; t_pvtuner_scale *s = x->this_scale; t_float *pitchgrid = x->this_scale->pitchgrid; int octsteps = 5; pvtuner_copy_scale(x); pitchgrid[0] = x->pbase; pitchgrid[1] = x->pbase * (9./8.); pitchgrid[2] = x->pbase * (81./64.); pitchgrid[3] = x->pbase * (3./2.); pitchgrid[4] = x->pbase * (27./16.); for( i = 1; i < 10; i++ ){ for( j = 0; j < octsteps; j++ ){ pitchgrid[ i * octsteps + j] = pitchgrid[j] * pow(2.0,(float)i); } } s->current_scale = PENTATONIC; s->scale_steps = 50; } void pvtuner_eq12( t_pvtuner *x ){ int i, j; t_float expon; int octsteps = 12; t_float pbase = x->pbase; t_pvtuner_scale *s = x->this_scale; t_float *pitchgrid = x->this_scale->pitchgrid; pvtuner_copy_scale(x); // copies this scale to next // now refill this scale pitchgrid[0] = pbase; for( i = 0; i < octsteps; i++ ){ expon = (float) i / (float) octsteps; pitchgrid[i] = pbase * pow(2.0,expon); } for( i = 1; i < 10; i++ ){ for( j = 0; j < octsteps; j++ ){ pitchgrid[ i * octsteps + j] = pitchgrid[j] * pow(2.0,(float)i); } } s->current_scale = EQ12; s->scale_steps = 120; } void pvtuner_major_added_sixth( t_pvtuner *x ){ int i, j; t_pvtuner_scale *s = x->this_scale; t_float *pitchgrid = x->this_scale->pitchgrid; t_float pbase = x->pbase; int octsteps = 4; pvtuner_copy_scale(x); pitchgrid[0] = pbase; pitchgrid[1] = pbase * 1.259921; pitchgrid[2] = pbase * 1.498307; pitchgrid[3] = pbase * 1.681793; for( i = 1; i < 10; i++ ){ for( j = 0; j < octsteps; j++ ){ pitchgrid[ i * octsteps + j] = pitchgrid[j] * pow(2.0,(float)i); } } s->current_scale = MAJOR_ADDED_SIXTH; s->scale_steps = 40; } void pvtuner_minor_added_sixth( t_pvtuner *x ){ int i, j; // float *pitchgrid = x->pitchgrid; t_float pbase = x->pbase; t_pvtuner_scale *s = x->this_scale; t_float *pitchgrid = x->this_scale->pitchgrid; int octsteps = 4; pvtuner_copy_scale(x); 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 < octsteps; j++ ){ pitchgrid[ i * octsteps + j] = pitchgrid[j] * pow(2.0,(float)i); } } s->current_scale = MINOR_ADDED_SIXTH; s->scale_steps = 40; } void pvtuner_major_seventh_chord( t_pvtuner *x ){ int i, j; t_pvtuner_scale *s = x->this_scale; t_float *pitchgrid = s->pitchgrid; t_float pbase = x->pbase; int scale_steps; pvtuner_copy_scale(x); 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); } } s->current_scale = MAJOR_SEVENTH_CHORD; s->scale_steps = 40; } void pvtuner_minor_seventh_chord( t_pvtuner *x ){ int i, j; t_pvtuner_scale *s = x->this_scale; t_float *pitchgrid = s->pitchgrid; t_float pbase = x->pbase; int scale_steps; pvtuner_copy_scale(x); 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); } } s->current_scale = MINOR_SEVENTH_CHORD; s->scale_steps = 40; } void pvtuner_dominant_seventh_chord( t_pvtuner *x ){ int i, j; t_pvtuner_scale *s = x->this_scale; t_float *pitchgrid = s->pitchgrid; t_float pbase = x->pbase; int scale_steps; pvtuner_copy_scale(x); 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); } } s->current_scale = DOMINANT_SEVENTH_CHORD; s->scale_steps = 40; } void pvtuner_eqn( t_pvtuner *x, t_floatarg steps ) { int dexter = 0; if(steps <= 0.0){ return; } t_pvtuner_scale *s = x->this_scale; t_float *pitchgrid = x->this_scale->pitchgrid; float pbase = x->pbase; float factor = pow(2.0, (1.0/steps) ); pvtuner_copy_scale(x); while(pbase < (x->fft->R / 2.0) && dexter < MAXTONES ){ pitchgrid[dexter] = pbase; pbase = pbase * factor; dexter = dexter + 1; } s->scale_steps = dexter; s->current_scale = EQN; } void pvtuner_eq8( t_pvtuner *x ){ int i, j; t_pvtuner_scale *s = x->this_scale; t_float *pitchgrid = s->pitchgrid; t_float pbase = x->pbase; int octsteps = 8; pvtuner_copy_scale(x); 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; for( i = 1; i < 10; i++ ){ for( j = 0; j < octsteps; j++ ){ pitchgrid[ i * octsteps + j] = pitchgrid[j] * pow(2.0,(float)i); } } s->current_scale = EQ8; s->scale_steps = 80; } void pvtuner_pentaclust( t_pvtuner *x ){ int i, j; t_pvtuner_scale *s = x->this_scale; t_float *pitchgrid = s->pitchgrid; t_float pbase = x->pbase; int scale_steps; pvtuner_copy_scale(x); 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); } } s->current_scale = PENTACLUST; s->scale_steps = 50; } void pvtuner_quarterclust( t_pvtuner *x ){ int i, j; t_pvtuner_scale *s = x->this_scale; t_float *pitchgrid = s->pitchgrid; t_float pbase = x->pbase; int scale_steps; pvtuner_copy_scale(x); 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); } } s->current_scale = QUARTERCLUST; s->scale_steps = 80; } void pvtuner_eq5( t_pvtuner *x ){ int i, j; t_pvtuner_scale *s = x->this_scale; t_float *pitchgrid = s->pitchgrid; t_float pbase = x->pbase; int scale_steps; pvtuner_copy_scale(x); 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); } } s->current_scale = EQ5; s->scale_steps = 50; } void pvtuner_pelog( t_pvtuner *x ){ int i, j; t_float *pitchgrid = x->this_scale->pitchgrid; t_pvtuner_scale *s = x->this_scale; t_float pbase = x->pbase; int scale_steps; pvtuner_copy_scale(x); 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); } } s->current_scale = PELOG; s->scale_steps = 50; } void pvtuner_slendro( t_pvtuner *x ){ int i, j; t_float *pitchgrid = x->this_scale->pitchgrid; t_pvtuner_scale *s = x->this_scale; t_float pbase = x->pbase; int scale_steps; pvtuner_copy_scale(x); 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); } } s->current_scale = SLENDRO; s->scale_steps = 70; } void pvtuner_eastern( t_pvtuner *x ){ int i, j; t_pvtuner_scale *s = x->this_scale; t_float *pitchgrid = s->pitchgrid; pvtuner_copy_scale(x); int octsteps = 7; pitchgrid[0] = x->pbase; pitchgrid[1] = x->pbase * 1.059463; pitchgrid[2] = x->pbase * 1.259921; pitchgrid[3] = x->pbase * 1.334840; pitchgrid[4] = x->pbase * 1.498307; pitchgrid[5] = x->pbase * 1.587401; pitchgrid[6] = x->pbase * 1.887749; // scale_steps = 7 ; for( i = 1; i < 10; i++ ){ for( j = 0; j < x->scale_steps; j++ ){ pitchgrid[ i * octsteps + j] = pitchgrid[j] * pow(2.0,(float)i); } } s->current_scale = EASTERN ; s->scale_steps = 70; // post("eastern scale"); } t_float closestf(t_float test, t_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_interpolation(t_pvtuner *x, t_floatarg state) { x->scale_interpolation = (short)state; } void pvtuner_mute(t_pvtuner *x, t_floatarg state) { x->mute = (short)state; } void pvtuner_dsp(t_pvtuner *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ pvtuner_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(pvtuner_perform, 6, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[4]->s_vec); } } pd-fftease-3.0.1/pvwarpb~.c000066400000000000000000000360601401707710000155560ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *pvwarpb_class; #define OBJECT_NAME "pvwarpb~" typedef struct _pvwarpb { t_object x_obj; t_float x_f; t_symbol *buffername; t_float lofreq;/* user specified lowest synthfreq */ t_float hifreq;/* user specified highest synthfreq */ t_float topfreq; t_fftease *fft; short mute; short please_update; short always_update; t_float cf1; t_float bw1; t_float warpfac1; t_float cf2; t_float bw2; t_float warpfac2; int funcoff; short verbose; short automate; t_float *warpfunc; // workspace to create a new function short initialized; // state for object int b_errorstatus; // check if error msg has been sent due to a bad buffer int b_frames; t_word *b_samples; int b_valid; } t_pvwarpb; static void pvwarpb_dsp(t_pvwarpb *x, t_signal **sp); static t_int *pvwarpb_perform(t_int *w); static void *pvwarpb_new(t_symbol *s, int argc, t_atom *argv); static void pvwarpb_mute(t_pvwarpb *x, t_floatarg state); static void pvwarpb_autofunc(t_pvwarpb *x, t_floatarg minval, t_floatarg maxval); static void pvwarpb_free( t_pvwarpb *x ); t_float fftease_randf( t_float min, t_float max ); static int freq_to_bin(t_float target, t_float fundamental); static void pvwarpb_init(t_pvwarpb *x); static void pvwarpb_bottomfreq(t_pvwarpb *x, t_floatarg f); static void pvwarpb_topfreq(t_pvwarpb *x, t_floatarg f); static void pvwarpb_attachbuf(t_pvwarpb *x); static void pvwarpb_redraw(t_pvwarpb *x); //static void pvwarpb_automate(t_pvwarpb *x, t_floatarg state); //static void pvwarpb_setbuf(t_pvwarpb *x, t_symbol *wavename); //static void pvwarpb_verbose(t_pvwarpb *x, t_floatarg state); void pvwarpb_tilde_setup(void) { t_class *c; c = class_new(gensym("pvwarpb~"), (t_newmethod)pvwarpb_new, (t_method)pvwarpb_free,sizeof(t_pvwarpb), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_pvwarpb, x_f); class_addmethod(c,(t_method)pvwarpb_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)pvwarpb_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)pvwarpb_bottomfreq,gensym("bottomfreq"),A_FLOAT,0); class_addmethod(c,(t_method)pvwarpb_topfreq,gensym("topfreq"),A_FLOAT,0); class_addmethod(c,(t_method)pvwarpb_autofunc,gensym("autofunc"),A_DEFFLOAT, A_DEFFLOAT,0); pvwarpb_class = c; fftease_announce(OBJECT_NAME); } void pvwarpb_automate(t_pvwarpb *x, t_floatarg state) { x->automate = state; } void update_warp_function( t_pvwarpb *x ) { int i,j; int N2 = x->fft->N2; t_float warpfac1 = x->warpfac1; t_float warpfac2 = x->warpfac2; long b_frames; t_float *warpfunc = x->warpfunc; t_word *b_samples; t_float cf1 = x->cf1; t_float cf2 = x->cf2; t_float bw1 = x->bw1; t_float bw2 = x->bw2; t_float c_fundamental = x->fft->c_fundamental; t_float deviation; t_float diff; int midbin, lobin, hibin ; t_float hif, lof; int bin_extent; pvwarpb_attachbuf(x); b_frames = x->b_frames; if(b_frames < N2){ post("%s: table too small",OBJECT_NAME); return; } 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 * ((t_float)(bin_extent - j) / (t_float) bin_extent ); warpfunc[ i ] += deviation ; } bin_extent = midbin - lobin ; for( i = midbin, j = 0; i > lobin; i--, j++ ){ deviation = diff * ((t_float)(bin_extent - j) / (t_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 * ((t_float)(bin_extent - j) / (t_float) bin_extent ); warpfunc[ i ] += deviation ; } bin_extent = midbin - lobin ; for( i = midbin, j = 0; i > lobin; i--, j++ ){ deviation = diff * ((t_float)(bin_extent - j) / (t_float) bin_extent ); warpfunc[ i ] += deviation ; } // buffer stuffer b_samples = x->b_samples; for(i = 0; i < N2; i++){ b_samples[i].w_float = warpfunc[i]; } x->please_update = 0; pvwarpb_redraw(x); } void pvwarpb_redraw(t_pvwarpb *x) { t_garray *a; if (!(a = (t_garray *)pd_findbyclass(x->buffername, garray_class))) { if (*x->buffername->s_name) pd_error(x, "function~: %s: no such array", x->buffername->s_name); } else { garray_redraw(a); } } void pvwarpb_verbose(t_pvwarpb *x, t_floatarg state) { x->verbose = state; } void pvwarpb_autofunc(t_pvwarpb *x, t_floatarg minval, t_floatarg maxval) { int minpoints, maxpoints, segpoints, i; int pointcount = 0; t_float target, lastval; t_float m1, m2; int N2 = x->fft->N2; long b_frames; t_float *warpfunc = x->warpfunc; t_word *b_samples; pvwarpb_attachbuf(x); b_frames = x->b_frames; if(b_frames < N2){ post("%s: table too small or not mono",OBJECT_NAME); return; } minpoints = 0.05 * (t_float) N2; maxpoints = 0.25 * (t_float) N2; if( minval > 1000.0 || minval < .001 ){ minval = 0.5; } if( maxval < 0.01 || maxval > 1000.0 ){ minval = 2.0; } lastval = fftease_randf(minval, maxval); // post("automate: min %d max %d",minpoints, maxpoints); while( pointcount < N2 ){ target = fftease_randf(minval, maxval); segpoints = minpoints + (rand() % (maxpoints-minpoints)); if( pointcount + segpoints > N2 ){ segpoints = N2 - pointcount; } for( i = 0; i < segpoints; i++ ){ m2 = (t_float)i / (t_float) segpoints ; m1 = 1.0 - m2; warpfunc[ pointcount + i ] = m1 * lastval + m2 * target; } lastval = target; pointcount += segpoints; } // buffer stuffer b_samples = x->b_samples; for(i = 0; i < N2; i++){ b_samples[i].w_float = warpfunc[i]; } pvwarpb_redraw(x); } void pvwarpb_mute(t_pvwarpb *x, t_floatarg state) { x->mute = state; } void pvwarpb_free( t_pvwarpb *x ){ if(x->fft->initialized){ free(x->warpfunc); } fftease_free(x->fft); free(x->fft); } void *pvwarpb_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft; t_pvwarpb *x = (t_pvwarpb *)pd_new(pvwarpb_class); int i; for(i=0;i<3;i++){ inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal")); } outlet_new(&x->x_obj, gensym("signal")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft->initialized = 0; // for FFTease package x->initialized = 0; // for object x->b_errorstatus = 0; x->lofreq = 0.0; x->hifreq = 10000.0; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; x->warpfunc = (t_float *) calloc(8192, sizeof(t_float)); if(argc > 0){ x->buffername = atom_getsymbolarg(0, argc, argv); } else { post("%s: Must specify array name", OBJECT_NAME); return NULL; } if(argc > 1){ fft->N = (int) atom_getfloatarg(1, argc, argv); } if(argc > 2){ fft->overlap = (int) atom_getfloatarg(2, argc, argv); } return x; } void pvwarpb_init(t_pvwarpb *x) { t_fftease *fft = x->fft; fftease_init(fft); if(!x->initialized){ srand(clock()); x->please_update = 0; x->verbose = 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->initialized = 1; } if(fft->N2 > 8192){ x->warpfunc = (t_float *) realloc(x->warpfunc, fft->N2); } fftease_oscbank_setbins(fft,x->lofreq, x->hifreq); } void pvwarpb_bottomfreq(t_pvwarpb *x, t_floatarg f) { if(!x->fft->initialized){ if(f >= 0 && f < 5000){ x->lofreq = f; } return; } if( f < 0 || f > x->fft->R / 2.0 ){ error("%s: frequency %f out of range", OBJECT_NAME, f); return; } x->lofreq = f; fftease_oscbank_setbins(x->fft, x->lofreq, x->hifreq); } void pvwarpb_topfreq(t_pvwarpb *x, t_floatarg f) { if(!x->fft->initialized){ if(f > 0 && f < 22050){ x->hifreq = f; } return; } if( f < x->lofreq || f > x->fft->R / 2.0 ){ error("%s: frequency %f out of range", OBJECT_NAME, f); return; } x->hifreq = f; fftease_oscbank_setbins(x->fft, x->lofreq, x->hifreq); } static void do_pvwarpb(t_pvwarpb *x) { t_fftease *fft = x->fft; int lo_bin = fft->lo_bin; int hi_bin = fft->hi_bin; int chan, freq; int funcoff = x->funcoff; int N2 = fft->N2; t_float *channel = fft->channel; long b_frames; t_word *b_samples; fftease_fold(fft); fftease_rdft(fft,FFT_FORWARD); fftease_convert(fft); b_samples = x->b_samples; if(! b_samples){ goto panic2; } b_frames = x->b_frames; if(b_frames < N2){ post("%s: table too small",OBJECT_NAME); goto panic1; } for ( chan = lo_bin; chan < hi_bin; chan++ ) { freq = (chan << 1) + 1; channel[freq] *= b_samples[(chan + funcoff) % N2].w_float; } panic1: ; panic2: ; fftease_oscbank(fft); } t_int *pvwarpb_perform(t_int *w) { int i,j; t_float f; t_pvwarpb *x = (t_pvwarpb *) (w[1]); t_sample *MSPInputVector = (t_sample *)(w[2]); t_sample *in7 = (t_sample *)(w[3]); t_sample *in8 = (t_sample *)(w[4]); t_sample *in9 = (t_sample *)(w[5]); t_sample *MSPOutputVector = (t_sample *)(w[6]); t_fftease *fft = x->fft; int D = fft->D; int Nw = fft->Nw; int N2 = fft->N2; t_float *input = fft->input; t_float *output = fft->output; t_float mult = fft->mult; int MSPVectorSize = fft->MSPVectorSize; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; pvwarpb_attachbuf(x); if(x->mute || !x->b_valid || x->b_frames < N2){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+7; } f = *in7 ; if( f < 0 ) { f = 0.0; } else if (f > 1.0 ){ f = 1.0; } x->funcoff = (int) (f * (t_float) (N2 - 1)); fft->P = *in8 ; fft->synt = *in9; if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_pvwarpb(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_pvwarpb(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_pvwarpb(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+7; } int freq_to_bin( t_float target, t_float fundamental ){ t_float lastf = 0.0; t_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); } } void pvwarpb_attachbuf(t_pvwarpb *x) { int frames; t_symbol *buffername = x->buffername; t_garray *a; x->b_frames = 0; x->b_valid = 0; if (!(a = (t_garray *)pd_findbyclass(buffername, garray_class))) { if (*buffername->s_name) { if(x->b_errorstatus == 0) { pd_error(x, "pvwarpb~: %s: no such array", buffername->s_name); x->b_errorstatus = 1; } } } else if (!garray_getfloatwords(a, &frames, &x->b_samples)) { if(x->b_errorstatus == 0) { pd_error(x, "%s: bad template for pvwarpb~", buffername->s_name); x->b_errorstatus = 1; } } else { x->b_frames = frames; x->b_valid = 1; x->b_errorstatus = 0; garray_usedindsp(a); } } void pvwarpb_setbuf(t_pvwarpb *x, t_symbol *wavename) { x->buffername = wavename; } void pvwarpb_dsp(t_pvwarpb *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ pvwarpb_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(pvwarpb_perform, 6, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[4]->s_vec); } } pd-fftease-3.0.1/pvwarp~.c000066400000000000000000000320071401707710000154110ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *pvwarp_class; #define OBJECT_NAME "pvwarp~" typedef struct _pvwarp { t_object x_obj; t_float x_f; t_fftease *fft; t_float hifreq; // user specified highest synthfreq t_float lofreq;//user specified lowest synthfreq t_float topfreq; short *connections; short mute; short bypass; int pitch_connected; int synt_connected; t_float *warpfunc ; short please_update; short always_update; t_float cf1; t_float bw1; t_float warpfac1; t_float cf2; t_float bw2; t_float warpfac2; int funcoff; short verbose; short automate; long fftsize_attr; long overlap_attr; } t_pvwarp; static void pvwarp_dsp(t_pvwarp *x, t_signal **sp); static t_int *pvwarp_perform(t_int *w); static void *pvwarp_new(t_symbol *s, int argc, t_atom *argv); static void pvwarp_mute(t_pvwarp *x, t_floatarg state); static void pvwarp_autofunc(t_pvwarp *x, t_floatarg minval, t_floatarg maxval); static void pvwarp_free( t_pvwarp *x ); static int freq_to_bin( float target, float fundamental ); static void update_warp_function( t_pvwarp *x ) ; static void pvwarp_init(t_pvwarp *x); static void pvwarp_bottomfreq(t_pvwarp *x, t_floatarg f); static void pvwarp_topfreq(t_pvwarp *x, t_floatarg f); static void pvwarp_automate(t_pvwarp *x, t_floatarg state); void pvwarp_tilde_setup(void) { t_class *c; c = class_new(gensym("pvwarp~"), (t_newmethod)pvwarp_new, (t_method)pvwarp_free,sizeof(t_pvwarp), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_pvwarp, x_f); class_addmethod(c,(t_method)pvwarp_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)pvwarp_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)pvwarp_automate,gensym("automate"),A_FLOAT,0); class_addmethod(c,(t_method)pvwarp_bottomfreq,gensym("bottomfreq"),A_FLOAT,0); class_addmethod(c,(t_method)pvwarp_topfreq,gensym("topfreq"),A_FLOAT,0); class_addmethod(c,(t_method)pvwarp_autofunc,gensym("autofunc"),A_DEFFLOAT, A_DEFFLOAT,0); pvwarp_class = c; fftease_announce(OBJECT_NAME); } void pvwarp_automate(t_pvwarp *x, t_floatarg state) { x->automate = (short)state; } void update_warp_function( t_pvwarp *x ) { int i,j; int N2 = x->fft->N2; t_float *warpfunc = x->warpfunc; t_float warpfac1 = x->warpfac1; t_float warpfac2 = x->warpfac2; t_float cf1 = x->cf1; t_float cf2 = x->cf2; t_float bw1 = x->bw1; t_float bw2 = x->bw2; t_float c_fundamental = x->fft->c_fundamental; t_float deviation; t_float diff; int midbin, lobin, hibin ; t_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; } void pvwarp_autofunc(t_pvwarp *x, t_floatarg minval, t_floatarg maxval) { int minpoints, maxpoints, segpoints, i; int pointcount = 0; t_float target, lastval; t_float m1, m2; int N2 = x->fft->N2; t_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 = fftease_randf(minval, maxval); // post("automate: min %d max %d",minpoints, maxpoints); while( pointcount < N2 ){ target = fftease_randf(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; } x->automate = 1; } void pvwarp_mute(t_pvwarp *x, t_floatarg state) { x->mute = state; } void pvwarp_free( t_pvwarp *x ){ if(x->fft->initialized){ free(x->warpfunc); free(x->connections); } fftease_free(x->fft); free(x->fft); } void *pvwarp_new(t_symbol *s, int argc, t_atom *argv) { int i; t_fftease *fft; 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")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft->initialized = 0; x->lofreq = 0.0; x->hifreq = 18000.0; fft->R = sys_getsr(); fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv); } pvwarp_init(x); return x; } void pvwarp_init(t_pvwarp *x) { t_fftease *fft = x->fft; fftease_init(fft); srand(clock()); x->please_update = 0; x->verbose = 0; x->bypass = 0; x->mute = 0; 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->connections = (short *) calloc(16, sizeof(short)); x->warpfunc = (t_float *) calloc(fft->N2, sizeof(t_float)); fftease_oscbank_setbins(fft,x->lofreq, x->hifreq); update_warp_function(x); } void pvwarp_bottomfreq(t_pvwarp *x, t_floatarg f) { if(!x->fft->initialized){ if(f >= 0 && f < 5000){ x->lofreq = f; } return; } if( f < 0 || f > x->fft->R / 2.0 ){ error("%s: frequency %f out of range", OBJECT_NAME, f); return; } x->lofreq = f; fftease_oscbank_setbins(x->fft, x->lofreq, x->hifreq); } void pvwarp_topfreq(t_pvwarp *x, t_floatarg f) { if(!x->fft->initialized){ if(f > 0 && f < 22050){ x->hifreq = f; } return; } if( f < x->lofreq || f > x->fft->R / 2.0 ){ error("%s: frequency %f out of range", OBJECT_NAME, f); return; } x->hifreq = f; fftease_oscbank_setbins(x->fft, x->lofreq, x->hifreq); } static void do_pvwarp(t_pvwarp *x) { t_fftease *fft = x->fft; int lo_bin = fft->lo_bin; int hi_bin = fft->hi_bin; int chan, freq; int funcoff = x->funcoff; int N2 = fft->N2; t_float *channel = fft->channel; t_float *warpfunc = x->warpfunc; fftease_fold(fft); fftease_rdft(fft,FFT_FORWARD); fftease_convert(fft); for ( chan = lo_bin; chan < hi_bin; chan++ ) { freq = (chan << 1) + 1; channel[freq] *= warpfunc[(chan + funcoff) % N2]; } fftease_oscbank(fft); } t_int *pvwarp_perform(t_int *w) { int i,j; t_float f; t_pvwarp *x = (t_pvwarp *) (w[1]); t_sample *MSPInputVector = (t_sample *)(w[2]); t_sample *in1 = (t_sample *)(w[3]); t_sample *in2 = (t_sample *)(w[4]); t_sample *in3 = (t_sample *)(w[5]); t_sample *in4 = (t_sample *)(w[6]); t_sample *in5 = (t_sample *)(w[7]); t_sample *in6 = (t_sample *)(w[8]); t_sample *in7 = (t_sample *)(w[9]); t_sample *in8 = (t_sample *)(w[10]); t_sample *in9 = (t_sample *)(w[11]); t_sample *MSPOutputVector = (t_sample *)(w[12]); t_fftease *fft = x->fft; int D = fft->D; int Nw = fft->Nw; int N2 = fft->N2; t_float *input = fft->input; t_float *output = fft->output; t_float mult = fft->mult; int MSPVectorSize = fft->MSPVectorSize; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+13; } if(!x->automate) { x->cf1 = *in1; x->bw1 = *in2 ; x->warpfac1 = *in3; x->cf2 = *in4; x->bw2 = *in5; x->warpfac2 = *in6; } f = *in7 ; if( f < 0 ) { f = 0.0; } else if (f > 1.0 ){ f = 1.0; } x->funcoff = (int) (f * (float) (N2 - 1)); fft->P = *in8 ; fft->synt = *in9 ; /* if( (x->please_update || x->always_update) && ! x->automate){ update_warp_function(x); } */ if(!x->automate){ update_warp_function(x); } if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_pvwarp(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_pvwarp(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_pvwarp(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+13; } 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); } } void pvwarp_dsp(t_pvwarp *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ pvwarp_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(pvwarp_perform, 12, 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); } } pd-fftease-3.0.1/reanimator~.c000066400000000000000000000407001401707710000162320ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" #define THRESHOLD_MIN (.000001) static t_class *reanimator_class; #define OBJECT_NAME "reanimator~" typedef struct _reanimator { t_object x_obj; t_float x_f; t_fftease *fft; t_float **framebank; t_float *normalized_frame; t_float current_frame; int framecount; t_float frame_increment ; t_float last_frame ; t_float fpos; t_float last_fpos; t_float tadv; int readme; int total_frames; short mute; short initialized; t_float threshold; short inverse; int top_comparator_bin; short reanimator_mode; int matchframe; // current found frame t_float sample_len; /*duration of texture sample */ t_float sync; int megs; } t_reanimator; static void reanimator_dsp(t_reanimator *x, t_signal **sp); static t_int *reanimator_perform(t_int *w); static void *reanimator_new(t_symbol *msg, short argc, t_atom *argv); static void reanimator_analyze (t_reanimator *x); static void reanimator_mute(t_reanimator *x, t_floatarg flag); static void reanimator_inverse(t_reanimator *x, t_floatarg toggle); static void reanimator_topbin(t_reanimator *x, t_floatarg bin); static void reanimator_freeze_and_march(t_reanimator *x, t_floatarg f); static void reanimator_resume( t_reanimator *x ); static void reanimator_threshold(t_reanimator *x, t_floatarg threshold); static void reanimator_free( t_reanimator *x ); static void reanimator_framecount ( t_reanimator *x ); static void reanimator_init(t_reanimator *x); static void reanimator_transpose(t_reanimator *x, t_floatarg tf); static void reanimator_synthresh(t_reanimator *x, t_floatarg thresh); static void reanimator_oscbank(t_reanimator *x, t_floatarg flag); void reanimator_tilde_setup(void) { t_class *c; c = class_new(gensym("reanimator~"), (t_newmethod)reanimator_new, (t_method)reanimator_free,sizeof(t_reanimator), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_reanimator, x_f); class_addmethod(c,(t_method)reanimator_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)reanimator_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)reanimator_oscbank,gensym("oscbank"),A_FLOAT,0); class_addmethod(c,(t_method)reanimator_transpose,gensym("transpose"),A_FLOAT,0); class_addmethod(c,(t_method)reanimator_synthresh,gensym("synthresh"),A_FLOAT,0); class_addmethod(c,(t_method)reanimator_inverse,gensym("inverse"), A_FLOAT, 0); class_addmethod(c,(t_method)reanimator_topbin,gensym("topbin"), A_FLOAT, 0); class_addmethod(c,(t_method)reanimator_threshold,gensym("threshold"), A_FLOAT, 0); class_addmethod(c,(t_method)reanimator_analyze,gensym("analyze"), 0); class_addmethod(c,(t_method)reanimator_framecount,gensym("framecount"), 0); class_addmethod(c,(t_method)reanimator_freeze_and_march,gensym("freeze_and_march"), A_FLOAT, 0); class_addmethod(c,(t_method)reanimator_resume,gensym("resume"), 0); reanimator_class = c; fftease_announce(OBJECT_NAME); } void reanimator_transpose(t_reanimator *x, t_floatarg tf) { x->fft->P = (float) tf; } void reanimator_synthresh(t_reanimator *x, t_floatarg thresh) { x->fft->synt = (float) thresh; } void reanimator_oscbank(t_reanimator *x, t_floatarg flag) { x->fft->obank_flag = (short) flag; } 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->reanimator_mode = 1; } void reanimator_resume( t_reanimator *x ) { x->reanimator_mode = 0; } void reanimator_free( t_reanimator *x ){ int i; if(x->fft->initialized){ fftease_free(x->fft); for(i = 0; i < x->framecount; i++){ free(x->framebank[i]) ; } free((char**)x->framebank); free(x->normalized_frame); } } void *reanimator_new(t_symbol *msg, short argc, t_atom *argv) { t_fftease *fft; t_reanimator *x = (t_reanimator *)pd_new(reanimator_class); 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")); outlet_new(&x->x_obj, gensym("signal")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft->initialized = 0; x->sample_len = 1000.0; if(argc > 0){ x->sample_len = atom_getfloatarg(0, argc, argv); } else { post("%s: must include duration argument",OBJECT_NAME); return NULL; } x->sample_len *= .001; /* convert to seconds */ fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 1){ fft->N = (int) atom_getfloatarg(1, argc, argv); } if(argc > 2){ fft->overlap = (int) atom_getfloatarg(2, argc, argv); } return x; } void reanimator_init(t_reanimator *x ) { t_fftease *fft = x->fft; t_float **framebank = x->framebank; int framecount = x->framecount; short initialized = fft->initialized; fftease_init(fft); if(!fftease_msp_sanity_check(fft,OBJECT_NAME)){ return; } // sanity check here x->tadv = (float)fft->D/(float)fft->R; x->current_frame = framecount = 0; x->fpos = x->last_fpos = 0; x->total_frames = x->sample_len / x->tadv; if(!initialized){ x->sync = 0.0; x->inverse = 0; x->initialized = 0; // for perform x->threshold = .0001; x->top_comparator_bin = 10; x->reanimator_mode = 0; x->frame_increment = 1.0; x->mute = 0; x->readme = 0; x->total_frames = x->sample_len / x->tadv; x->framebank = (t_float **) calloc(x->total_frames, sizeof(t_float *)); while(framecount < x->total_frames ){ x->framebank[framecount] = (t_float *) calloc((fft->N+2),sizeof(t_float)); ++framecount; } } else if(initialized == 1){ // danger: could be more frames this time!!! while(framecount < x->total_frames ){ x->framebank[framecount] = (t_float *) realloc(framebank[framecount], (fft->N+2) * sizeof(t_float)); ++framecount; } } x->framecount = framecount; x->megs = sizeof(t_float) * x->framecount * (fft->N+2); } static void do_reanimator(t_reanimator *x) { t_float ampsum, new_ampsum, rescale; t_float min_difsum, difsum; int i,j; t_fftease *fft = x->fft; int framecount = x->framecount; int total_frames = x->total_frames; float threshold = x->threshold; int top_comparator_bin = x->top_comparator_bin ; t_float **framebank = x->framebank; // for reanimator mode t_float fframe = x->current_frame ; t_float last_fpos = x->last_fpos ; t_float fincr = x->frame_increment; t_float fpos = x->fpos ; t_float sync = x->sync; t_float *channel = fft->channel; t_float *output = fft->output; int matchframe = x->matchframe; int N = fft->N; int D = fft->D; float rescale_inv; /***********************************/ if(total_frames <= 0) return; /* SAMPLE MODE */ if( x->readme ) { if( framecount >= total_frames ){ sync = 1.0; x->readme = 0; post("reanimator~: data acquisition completed"); x->initialized = 1; // clear input buffer for( i = 0; i < fft->Nw; i++ ){ fft->input[i] = 0.0; } } else { fftease_fold(fft); fftease_rdft(fft,FFT_FORWARD); fftease_convert(fft); sync = (float) framecount / (float) total_frames; new_ampsum = ampsum = 0; for(i = 0; i < N; i += 2 ){ ampsum += channel[i]; } if( ampsum > .000001 ){ rescale = 1.0 / ampsum ; // use more efficient memcpy for(i = 0; i < N; i++){ framebank[framecount][i] = channel[i]; } for( i = 0; i < N; i += 2 ){ framebank[framecount][i] *= rescale; } ++framecount; } else { post("amplitude for frame %d is too low\n", framecount); } } } /* reanimator RESYNTHESIS */ else if(x->reanimator_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 ; } matchframe = (int) fframe; // use memcopy for(i = 0; i < N; i++){ channel[i] = framebank[matchframe][i]; } if(fft->obank_flag){ fftease_oscbank(fft); } else { fftease_unconvert(fft); fftease_rdft(fft,FFT_INVERSE); fftease_overlapadd(fft); } } /* REANIMATION HERE */ else { fftease_fold(fft); fftease_rdft(fft,FFT_FORWARD); fftease_convert(fft); ampsum = 0; // NORMALIZE INPUT FRAME for( i = 0; i < N; 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 (i = 0; i < D; i++ ){ output[i] = 0.0; } matchframe = 0; x->current_frame = fframe; x->frame_increment = fincr; x->fpos = fpos; x->sync = sync; x->framecount = framecount; x->matchframe = matchframe; return; } // 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 ){ matchframe = 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 ){ matchframe = j; min_difsum = difsum; } } } // use memcopy for(i = 0; i < N; i++){ channel[i] = framebank[matchframe][i]; } if(fft->obank_flag){ fftease_oscbank(fft); } else { fftease_unconvert(fft); fftease_rdft(fft,FFT_INVERSE); fftease_overlapadd(fft); } // scale back to match rescale_inv = 1.0 / rescale; for (i = 0; i < D; i++){ output[i] *= rescale_inv; } } /* restore state variables */ x->current_frame = fframe; x->frame_increment = fincr; x->fpos = fpos; x->sync = sync; x->framecount = framecount; x->matchframe = matchframe; } t_int *reanimator_perform(t_int *w) { int i,j; ////////////////////////////////////////////// t_reanimator *x = (t_reanimator *) (w[1]); t_float *driver = (t_float *)(w[2]); // was driver t_float *texture = (t_float *)(w[3]); t_float *MSPOutputVector = (t_float *)(w[4]); // was soundout t_float *matchout = (t_float *)(w[5]); t_float *sync_vec = (t_float *)(w[6]); t_fftease *fft = x->fft; int D = fft->D; int Nw = fft->Nw; t_float *input = fft->input; t_float *output = fft->output; t_float mult = fft->mult; int MSPVectorSize = fft->MSPVectorSize; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; /***********************************/ if(x->mute || ! x->initialized){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+7; } if( fft->obank_flag ) mult *= FFTEASE_OSCBANK_SCALAR; if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); if(x->readme){ memcpy(input + (Nw - D), texture, D * sizeof(t_float)); } else { memcpy(input + (Nw - D), driver, D * sizeof(t_float)); } do_reanimator(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); if(x->readme){ memcpy(input + (Nw - D), texture + (D * i), D * sizeof(float)); } else { memcpy(input + (Nw - D), driver + (D * i), D * sizeof(float)); } do_reanimator(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { if(x->readme){ memcpy(internalInputVector + (operationCount * MSPVectorSize), texture, MSPVectorSize * sizeof(float)); } else { memcpy(internalInputVector + (operationCount * MSPVectorSize), driver, MSPVectorSize * sizeof(float)); } memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize), MSPVectorSize * sizeof(float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_reanimator( x ); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } // now load other output buffers for(i = 0; i < MSPVectorSize; i++){ matchout[i] = x->matchframe; sync_vec[i] = x->sync; } return w+7; } void reanimator_analyze ( t_reanimator *x ) { x->readme = 1; x->initialized = 1; x->framecount = 0; post("reanimator: beginning spectral data acquisition"); return; } void reanimator_mute(t_reanimator *x, t_floatarg flag) { x->mute = (short)flag; } void reanimator_topbin(t_reanimator *x, t_floatarg bin) { if( bin > 1 && bin < x->fft->N2 ) x->top_comparator_bin = bin; } void reanimator_inverse(t_reanimator *x, t_floatarg toggle) { x->inverse = (short)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) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ reanimator_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(reanimator_perform, 6, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec,sp[4]->s_vec); } } pd-fftease-3.0.1/resent~.c000066400000000000000000000476051401707710000154040ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *resent_class; #define OBJECT_NAME "resent~" typedef struct _resent { t_object x_obj; t_float x_f; t_fftease *fft; t_float *frame_incr; t_float *store_incr; t_float *frame_phase; t_float frameloc; t_float **loveboat; t_float current_frame; long framecount; long last_framecount; t_float frame_increment ; t_float fpos; t_float last_fpos; t_float tadv; int read_me; long frames_read; short mute; void *m_clock; void *m_bang; short playthrough; short lock; t_float duration; t_float sync; long interpolation_attr; } t_resent; static void resent_dsp(t_resent *x, t_signal **sp); static t_int *resent_perform(t_int *w); static void *resent_new(t_symbol *msg, short argc, t_atom *argv); static void resent_acquire_sample (t_resent *x) ; static void resent_mute(t_resent *x, t_floatarg tog); static void resent_bin(t_resent *x, t_floatarg fbin, t_floatarg speed); static void resent_setphase(t_resent *x, t_floatarg phase); static void resent_addphase(t_resent *x, t_floatarg phase); static void resent_setspeed( t_resent *x, t_floatarg speed ); static void resent_addspeed( t_resent *x, t_floatarg speed ); static void resent_free( t_resent *x ); static void resent_store_incr( t_resent *x ); static void resent_setspeed_and_phase( t_resent *x, t_floatarg speed, t_floatarg phase ); static void resent_init(t_resent *x); static void resent_linephase(t_resent *x, t_symbol *msg, short argc, t_atom *argv); static void resent_linespeed(t_resent *x, t_symbol *msg, short argc, t_atom *argv); static void resent_randphase(t_resent *x, t_symbol *msg, short argc, t_atom *argv); static void resent_randspeed(t_resent *x, t_symbol *msg, short argc, t_atom *argv); static void resent_playthrough(t_resent *x, t_floatarg state); static void resent_interpolation(t_resent *x, t_floatarg tog); t_float fftease_randf(t_float min, t_float max); static void resent_transpose(t_resent *x, t_floatarg tf); static void resent_synthresh(t_resent *x, t_floatarg thresh); static void resent_oscbank(t_resent *x, t_floatarg flag); static void resent_assist (t_resent *x, void *b, long msg, long arg, char *dst); static void resent_tick(t_resent *x); void resent_tilde_setup(void) { t_class *c; c = class_new(gensym("resent~"), (t_newmethod)resent_new, (t_method)resent_free,sizeof(t_resent), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_resent, x_f); class_addmethod(c,(t_method)resent_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)resent_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)resent_oscbank,gensym("oscbank"),A_FLOAT,0); class_addmethod(c,(t_method)resent_transpose,gensym("transpose"),A_FLOAT,0); class_addmethod(c,(t_method)resent_synthresh,gensym("synthresh"),A_FLOAT,0); class_addmethod(c,(t_method)resent_acquire_sample,gensym("acquire_sample"), 0); class_addmethod(c,(t_method)resent_linespeed, gensym("linespeed"), A_GIMME, 0); class_addmethod(c,(t_method)resent_linephase, gensym("linephase"), A_GIMME, 0); class_addmethod(c,(t_method)resent_randspeed, gensym("randspeed"), A_GIMME, 0); class_addmethod(c,(t_method)resent_randphase, gensym("randphase"), A_GIMME, 0); class_addmethod(c,(t_method)resent_bin, gensym("bin"), A_FLOAT, A_FLOAT, 0); class_addmethod(c,(t_method)resent_setphase, gensym("setphase"), A_FLOAT, 0); class_addmethod(c,(t_method)resent_addphase, gensym("addphase"), A_FLOAT, 0); class_addmethod(c,(t_method)resent_setspeed, gensym("setspeed"), A_FLOAT, 0); class_addmethod(c,(t_method)resent_addspeed, gensym("addspeed"), A_FLOAT, 0); class_addmethod(c,(t_method)resent_playthrough, gensym("playthrough"), A_DEFFLOAT, 0); class_addmethod(c,(t_method)resent_store_incr, gensym("store_incr"),0); class_addmethod(c,(t_method)resent_setspeed_and_phase, gensym("setspeed_and_phase"), A_FLOAT, A_FLOAT, 0); class_addmethod(c,(t_method)resent_interpolation, gensym("interpolation"), A_FLOAT, 0); resent_class = c; fftease_announce(OBJECT_NAME); } void resent_transpose(t_resent *x, t_floatarg tf) { x->fft->P = tf; } void resent_synthresh(t_resent *x, t_floatarg thresh) { x->fft->synt = thresh; } void resent_oscbank(t_resent *x, t_floatarg flag) { x->fft->obank_flag = (short) flag; } void resent_store_incr(t_resent *x) { t_fftease *fft = x->fft; int i; t_float *store_incr = x->store_incr; t_float *frame_incr = x->frame_incr; for(i = 0; i < fft->N2; i++){ store_incr[i] = frame_incr[i]; } } void resent_free(t_resent *x){ int i ; if(x->fft->initialized){ for(i = 0; i < x->framecount; i++){ free(x->loveboat[i]) ; } free(x->loveboat); free(x->frame_phase); free(x->frame_incr); free(x->store_incr); } fftease_free(x->fft); free(x->fft); } void resent_bin(t_resent *x, t_floatarg fbin, t_floatarg speed) { t_fftease *fft = x->fft; int bin_num = (int) fbin; if(bin_num >= 0 && bin_num < fft->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) { t_fftease *fft = x->fft; t_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 < fft->N2; i++ ){ x->frame_phase[i] = scaled_phase ; } } void resent_addphase( t_resent *x, t_floatarg phase ) { t_fftease *fft = x->fft; t_float scaled_phase ; t_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 < fft->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 ) { t_fftease *fft = x->fft; if(! x->fft->init_status) return; int i; for( i = 0; i < fft->N2; i++ ){ x->frame_incr[i] = speed ; } // post("speed reset to %f",speed); } void resent_addspeed( t_resent *x, t_floatarg speed ) { t_fftease *fft = x->fft; int i; t_float *store_incr = x->store_incr; t_float *frame_incr = x->frame_incr; for( i = 0; i < fft->N2; i++ ){ frame_incr[i] = store_incr[i] + speed ; } } void resent_interpolation( t_resent *x, t_floatarg tog ) { x->interpolation_attr = (int) tog; } void resent_setspeed_and_phase( t_resent *x, t_floatarg speed, t_floatarg phase ) { t_fftease *fft = x->fft; t_float scaled_phase; int i; if( phase < 0. ) phase = 0. ; if( phase > 1. ) phase = 1.; scaled_phase = phase * (t_float) x->framecount ; for( i = 0; i < fft->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) { int i; short initialized = x->fft->initialized; t_fftease *fft = x->fft; fftease_init(fft); if(!fftease_msp_sanity_check(fft,OBJECT_NAME)){ return; } x->current_frame = x->framecount = 0; x->fpos = x->last_fpos = 0; x->tadv = (float)fft->D/(float)fft->R; if(x->duration < 0.1){ x->duration = 0.1; } 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->frame_incr = (t_float *) calloc(fft->N2, sizeof(t_float)); x->store_incr = (t_float *) calloc(fft->N2, sizeof(t_float)); x->frame_phase = (t_float *) calloc(fft->N2, sizeof(t_float)); x->loveboat = (t_float **) calloc(x->framecount, sizeof(t_float *)); for(i=0; i < x->framecount; i++){ x->loveboat[i] = (t_float *) calloc((fft->N+2), sizeof(t_float)); if(x->loveboat[i] == NULL){ error("%s: Insufficient Memory!",OBJECT_NAME); return; } } } else { /* this could fail or might not actually release memory - test it!! */ x->frame_incr = (t_float *) realloc(x->frame_incr, fft->N2 * sizeof(t_float)); x->store_incr = (t_float *) realloc(x->store_incr, fft->N2 * sizeof(t_float)); x->frame_phase = (t_float *) realloc(x->frame_phase, fft->N2 * sizeof(t_float)); for(i = 0; i < x->last_framecount; i++){ free(x->loveboat[i]) ; } x->loveboat = (t_float **)realloc(x->loveboat, x->framecount * sizeof(t_float*)); for(i=0; i < x->framecount; i++){ x->loveboat[i] = (t_float *) calloc((fft->N+2), sizeof(t_float)); if(x->loveboat[i] == NULL){ error("%s: Insufficient Memory!",OBJECT_NAME); return; } } } x->last_framecount = x->framecount; } void *resent_new(t_symbol *msg, short argc, t_atom *argv) { t_fftease *fft; t_resent *x = (t_resent *)pd_new(resent_class); outlet_new(&x->x_obj, gensym("signal")); outlet_new(&x->x_obj, gensym("signal")); x->fft = (t_fftease *) calloc(1, sizeof(t_fftease) ); fft = x->fft; fft->initialized = 0; srand(clock()); // needed ? x->interpolation_attr = 0; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ x->duration = atom_getfloatarg(0, argc, argv) / 1000.0; } else { post("%s: must give duration argument",OBJECT_NAME); return NULL; } if(argc > 1){ fft->N = (int) atom_getfloatarg(1, argc, argv); } if(argc > 2){ fft->overlap = (int) atom_getfloatarg(2, argc, argv); } return x; } static void do_resent(t_resent *x) { t_fftease *fft = x->fft; int iphase, amp, freq, i; int N = fft->N; int N2 = fft->N2; t_float fframe = x->current_frame ; t_float last_fpos = x->last_fpos ; int framecount = x->framecount; t_float *frame_incr = x->frame_incr; t_float *frame_phase = x->frame_phase; t_float *channel = fft->channel; t_float frak; long iphase1, iphase2; if(x->read_me && x->framecount > 0){ fftease_fold(fft); fftease_rdft(fft,FFT_FORWARD); fftease_convert(fft); // use memcopy for(i = 0; i < N; i++){ x->loveboat[x->frames_read][i] = channel[i]; } x->frames_read++; if(x->frames_read >= x->framecount){ x->read_me = 0; // post("sample acquisition completed"); } x->sync = (t_float) x->frames_read / (t_float) x->framecount; } else { if(x->interpolation_attr == 1){ for( i = 0 ; i < N2; i++ ){ amp = i<<1; freq = amp + 1; iphase1 = floor( frame_phase[i] ); frak = frame_phase[i] - iphase1; if( iphase1 < 0 ) iphase1 = 0; if( iphase1 > framecount - 1 ) iphase1 = framecount - 1; iphase2 = (iphase1 + 1) % framecount; channel[amp] = x->loveboat[iphase1][amp] + (frak * (x->loveboat[iphase2][amp] - x->loveboat[iphase1][amp])); channel[freq] = x->loveboat[iphase1][freq] + (frak * (x->loveboat[iphase2][freq] - x->loveboat[iphase1][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; } } 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; channel[amp] = x->loveboat[iphase][amp]; channel[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; } } if(fft->obank_flag){ fftease_oscbank(fft); } else { fftease_unconvert(fft); fftease_rdft(fft,FFT_INVERSE); fftease_overlapadd(fft); } } /* restore state variables */ x->current_frame = fframe; x->last_fpos = last_fpos; } t_int *resent_perform(t_int *w) { int i, j; ////////////////////////////////////////////// t_resent *x = (t_resent *) (w[1]); t_float *MSPInputVector = (t_float *)(w[2]); t_float *MSPOutputVector = (t_float *)(w[3]); t_float *sync_vec = (t_float *)(w[4]); /* dereference structure */ t_fftease *fft = x->fft; int D = fft->D; int Nw = fft->Nw; t_float *input = fft->input; t_float *output = fft->output; t_float mult = fft->mult; int MSPVectorSize = fft->MSPVectorSize; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } for(i=0; i < MSPVectorSize; i++){ sync_vec[i] = 0.0; } return w+5; } if( fft->obank_flag ) mult *= FFTEASE_OSCBANK_SCALAR; if(x->playthrough && x->read_me){ for (i = 0; i < MSPVectorSize; i++) { MSPOutputVector[i] = MSPInputVector[i] * 0.5; // scale down } for(i=0; i < MSPVectorSize; i++){ sync_vec[i] = 0.0; } return w+5; } if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_resent(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_resent(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_resent(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } for ( i = 0; i < MSPVectorSize; i++ ){ sync_vec[i] = x->sync; } return w+5; } 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) { t_fftease *fft = x->fft; 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 > fft->N2 || bin2 > fft->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) { t_fftease *fft = x->fft; 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 < fft->N2; i++ ){ x->frame_phase[i] = (int) (fftease_randf( minphase, maxphase ) * (float) (framecount - 1) ) ; } } void resent_randspeed(t_resent *x, t_symbol *msg, short argc, t_atom *argv) { t_fftease *fft = x->fft; float minspeed, maxspeed; int i; minspeed = atom_getfloatarg(0, argc, argv); maxspeed = atom_getfloatarg(1, argc, argv); for( i = 0; i < fft->N2; i++ ){ x->frame_incr[i] = fftease_randf(minspeed, maxspeed); } } void resent_linespeed(t_resent *x, t_symbol *msg, short argc, t_atom *argv) { t_fftease *fft = x->fft; 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 > fft->N2 || bin2 > fft->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) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ resent_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(resent_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); } } pd-fftease-3.0.1/residency_buffer~.c000066400000000000000000000360241401707710000174130ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *residency_buffer_class; #define OBJECT_NAME "residency_buffer~" typedef struct _residency_buffer { t_object x_obj; t_float x_f; t_fftease *fft; long b_frames; long b_valid; long b_errorstatus; t_word *b_samples; t_float current_frame; int framecount; // t_float frame_increment ; t_float fpos; t_float last_fpos; t_float tadv; long read_me; long frames_read; long MAXFRAMES; short mute; long buffer_frame_count; short initialized; short playthrough; t_float sync; short buffer_is_hosed; long interpolation_attr; t_symbol *buffername; void *size_outlet; // will send desired size in samples } t_residency_buffer; static void residency_buffer_dsp(t_residency_buffer *x, t_signal **sp); static t_int *residency_buffer_perform(t_int *w); static void *residency_buffer_new(t_symbol *msg, short argc, t_atom *argv); static void residency_buffer_acquire_sample ( t_residency_buffer *x ) ; static void residency_buffer_mute(t_residency_buffer *x, t_floatarg toggle); static void residency_buffer_interpolation(t_residency_buffer *x, t_floatarg toggle); static void residency_buffer_calcbuf(t_residency_buffer *x, t_floatarg desired_duration); static void residency_buffer_free( t_residency_buffer *x ); static void residency_buffer_playthrough(t_residency_buffer *x, t_floatarg f); static void residency_buffer_init(t_residency_buffer *x); static void residency_buffer_transpose(t_residency_buffer *x, t_floatarg tf); static void residency_buffer_synthresh(t_residency_buffer *x, t_floatarg thresh); static void residency_buffer_oscbank(t_residency_buffer *x, t_floatarg flag); static void residency_buffer_attachbuf(t_residency_buffer *x); static void residency_buffer_redraw(t_residency_buffer *x); void residency_buffer_tilde_setup(void) { t_class *c; c = class_new(gensym("residency_buffer~"), (t_newmethod)residency_buffer_new, (t_method)residency_buffer_free,sizeof(t_residency_buffer), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_residency_buffer, x_f); class_addmethod(c,(t_method)residency_buffer_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)residency_buffer_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)residency_buffer_interpolation,gensym("interpolation"),A_FLOAT,0); class_addmethod(c,(t_method)residency_buffer_oscbank,gensym("oscbank"),A_FLOAT,0); class_addmethod(c,(t_method)residency_buffer_transpose,gensym("transpose"),A_FLOAT,0); class_addmethod(c,(t_method)residency_buffer_synthresh,gensym("synthresh"),A_FLOAT,0); class_addmethod(c,(t_method)residency_buffer_calcbuf,gensym("calcbuf"), A_FLOAT, 0); class_addmethod(c,(t_method)residency_buffer_playthrough,gensym("playthrough"), A_FLOAT, 0); class_addmethod(c,(t_method)residency_buffer_acquire_sample,gensym("acquire_sample"), 0); residency_buffer_class = c; fftease_announce(OBJECT_NAME); } void residency_buffer_free( t_residency_buffer *x ) { fftease_free(x->fft); free(x->fft); } void residency_buffer_calcbuf(t_residency_buffer *x, t_floatarg desired_duration) { t_float ms_calc; t_float seconds; t_float frames; t_float samples; t_float tadv = x->tadv; t_fftease *fft = x->fft; if(tadv == 0){ post("zero tadv!"); return; } if(fft->R == 0){ post("zero sampling rate!"); return; } seconds = desired_duration / 1000.0; frames = seconds / tadv; samples = frames * (t_float) (fft->N + 2); ms_calc = (samples / fft->R) * 1000.0; post("desired duration in ms: %f",desired_duration); post("you need %.0f samples in buffer to get %.0f frames or %f secs", samples, frames, seconds); outlet_float(x->size_outlet, samples); } void *residency_buffer_new(t_symbol *msg, short argc, t_atom *argv) { t_residency_buffer *x = (t_residency_buffer *)pd_new(residency_buffer_class); t_fftease *fft; 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")); x->size_outlet = outlet_new(&x->x_obj, gensym("float")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft->initialized = 0; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; x->b_errorstatus = 0; if(argc > 0){ x->buffername = atom_getsymbolarg(0, argc, argv); } else { post("%s: Must specify array name", OBJECT_NAME); return NULL; } if(argc > 1){ fft->N = (int) atom_getfloatarg(1, argc, argv); } if(argc > 2){ fft->overlap = (int) atom_getfloatarg(2, argc, argv); } return x; } void residency_buffer_init(t_residency_buffer *x) { t_fftease *fft = x->fft; short initialized = x->fft->initialized; if( fft->R <= 0 ){ post("bad SR"); return; } if( fft->MSPVectorSize <= 0 ){ post("bad vectorsize"); return; } fftease_init(fft); x->tadv = (t_float)fft->D / (t_float)fft->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; } } static void do_residency_buffer(t_residency_buffer *x) { t_fftease *fft = x->fft; int N = x->fft->N; int i,j,k; t_float fframe = x->current_frame ; t_float fincr = x->frame_increment; t_float fpos = x->fpos; t_float last_fpos = x->last_fpos ; t_float *channel = fft->channel; t_word *b_samples; long b_frames = x->b_frames; long b_valid = x->b_valid; int frames_read = x->frames_read; long index_offset; long buffer_frame_count = x->buffer_frame_count; long index1, index2; t_float frak; residency_buffer_attachbuf(x); b_samples = x->b_samples; b_frames = x->b_frames; buffer_frame_count = (int)((t_float) b_frames / (t_float)(x->fft->N + 2)); if(b_frames < 1 || ! b_valid){ post("%s: table too small or not valid",OBJECT_NAME); return; } if( x->read_me ) { fftease_fold(fft); fftease_rdft(fft, FFT_FORWARD); fftease_convert(fft); index_offset = (N+2) * frames_read; for(i = index_offset, j = 0; i < index_offset + N + 2; i++, j++){ if(i >= b_frames){ post("hit end of buffer on frame %d", frames_read); goto escape; } b_samples[i].w_float = channel[j]; } ++frames_read; x->sync = (t_float)frames_read/(t_float)(buffer_frame_count); if( frames_read >= buffer_frame_count){ x->read_me = 0; fpos = 0.0; residency_buffer_redraw(x); } } else { if( fpos < 0 ) fpos = 0; if( fpos > 1 ) fpos = 1; if( fpos != last_fpos ){ fframe = fpos * (t_float) buffer_frame_count; last_fpos = fpos; } fframe += fincr; // post("fframe %f framecount %d", fframe, buffer_frame_count); while(fframe >= buffer_frame_count) { fframe -= buffer_frame_count; } while( fframe < 0. ) { fframe += buffer_frame_count; } // goto escape; if(x->interpolation_attr == 1){ long iframe = floor(fframe); index1 = (N+2) * iframe; index2 = (N+2) * ((iframe + 1) % buffer_frame_count); frak = fframe - iframe; for( i = index1, j = index2, k = 0; i < index1 + N + 2; i++, j++, k++){ if(i >= b_frames || j >= b_frames){ post("hit end of buffer on frame %d, index %d %d", index1,i,j); goto escape; } channel[k] = b_samples[i].w_float + frak * (b_samples[j].w_float - b_samples[i].w_float); } } else { index_offset = (N+2) * (long) fframe; for( i = index_offset, j = 0; i < index_offset + N + 2; i++, j++ ){ if(i >= b_frames){ post("hit end of buffer on frame %d, index %d", index_offset,i); goto escape; } channel[j] = b_samples[i].w_float; } } x->sync = fframe / (t_float) buffer_frame_count; // REPLACE loveboat with buffer if(fft->obank_flag){ fftease_oscbank(fft); } else { fftease_unconvert(fft); fftease_rdft(fft, FFT_INVERSE); fftease_overlapadd(fft); } } escape: ; /* restore state variables */ x->current_frame = fframe; x->frame_increment = fincr; x->fpos = fpos; x->last_fpos = last_fpos; x->frames_read = frames_read; } void residency_buffer_redraw(t_residency_buffer *x) { t_garray *a; if (!(a = (t_garray *)pd_findbyclass(x->buffername, garray_class))) { if (*x->buffername->s_name) pd_error(x, "function~: %s: no such array", x->buffername->s_name); } else { garray_redraw(a); } } void residency_buffer_attachbuf(t_residency_buffer *x) { int frames; t_symbol *buffername = x->buffername; t_garray *a; x->b_frames = 0; x->b_valid = 0; if (!(a = (t_garray *)pd_findbyclass(buffername, garray_class))) { if (*buffername->s_name) { if(x->b_errorstatus == 0) { pd_error(x, "residency_buffer~: %s: no such array", buffername->s_name); x->b_errorstatus = 1; } } } else if (!garray_getfloatwords(a, &frames, &x->b_samples)) { if(x->b_errorstatus == 0) { pd_error(x, "%s: bad template for residency_buffer~", buffername->s_name); x->b_errorstatus = 1; } } else { x->b_frames = frames; x->b_valid = 1; x->b_errorstatus = 0; garray_usedindsp(a); } } t_int *residency_buffer_perform(t_int *w) { int i, j; ////////////////////////////////////////////// t_residency_buffer *x = (t_residency_buffer *) (w[1]); t_float *MSPInputVector = (t_float *)(w[2]); t_float *increment = (t_float *)(w[3]); t_float *position = (t_float *)(w[4]); t_float *MSPOutputVector = (t_float *)(w[5]); t_float *vec_sync = (t_float *)(w[6]); t_fftease *fft = x->fft; int MSPVectorSize = fft->MSPVectorSize; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int D = fft->D; int Nw = fft->Nw; t_float *input = fft->input; t_float *output = fft->output; float mult = fft->mult; if( fft->obank_flag ) mult *= FFTEASE_OSCBANK_SCALAR; residency_buffer_attachbuf(x); /* quit before doing anything unless we're good to go */ if( x->mute || ! x->b_valid) { for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } for(i=0; i < MSPVectorSize; i++){ vec_sync[i] = 0.0; } return w+7; } x->frame_increment = *increment; x->fpos = *position; for ( i = 0; i < MSPVectorSize; i++ ){ vec_sync[i] = x->sync; } if(x->framecount > 0 && x->read_me ){ x->sync = (t_float)x->frames_read/(t_float)x->framecount; } if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_residency_buffer(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_residency_buffer(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_residency_buffer(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+7; } void residency_buffer_acquire_sample ( t_residency_buffer *x ) { residency_buffer_attachbuf(x); x->read_me = 1; x->frames_read = 0; x->buffer_frame_count = (int)((t_float) (x->b_frames) / (t_float)(x->fft->N + 2)); post("storing %d FFT frames", x->buffer_frame_count); post("%s: beginning spectral data acquisition",OBJECT_NAME); return; } void residency_buffer_mute(t_residency_buffer *x, t_floatarg toggle) { x->mute = (short)toggle; } void residency_buffer_interpolation(t_residency_buffer *x, t_floatarg toggle) { x->interpolation_attr = (short)toggle; } void residency_buffer_playthrough(t_residency_buffer *x, t_floatarg toggle) { x->playthrough = (short)toggle; } void residency_buffer_transpose(t_residency_buffer *x, t_floatarg tf) { x->fft->P = (float) tf; } void residency_buffer_synthresh(t_residency_buffer *x, t_floatarg thresh) { x->fft->synt = (float) thresh; } void residency_buffer_oscbank(t_residency_buffer *x, t_floatarg flag) { x->fft->obank_flag = (short) flag; } void residency_buffer_dsp(t_residency_buffer *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ residency_buffer_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(residency_buffer_perform, 6, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[4]->s_vec); } } pd-fftease-3.0.1/residency~.c000066400000000000000000000357131401707710000160660ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *residency_class; #define OBJECT_NAME "residency~" typedef struct _residency { t_object x_obj; t_float x_f; t_fftease *fft; t_float **loveboat; t_float current_frame; long framecount; long last_framecount; // t_float frame_increment; t_float fpos; t_float last_fpos; t_float tadv; short acquire_stop; // flag to stop recording immediately float force_pos; // force to this position on receiving message int read_me; int frames_read; short mute; short playthrough; t_float duration; short lock; short verbose; short override; t_float *input_vec; t_float sync; short failed_init; // flag to check if init failed due to bad data from Max t_float size_attr; short interpolation_attr; } t_residency; static void residency_dsp(t_residency *x, t_signal **sp); static t_int *residency_perform(t_int *w); static void *residency_new(t_symbol *s, int argc, t_atom *argv); static void residency_playthrough( t_residency *x, t_floatarg tog) ; static void residency_mute(t_residency *x, t_floatarg tog); static void residency_interpolation(t_residency *x, t_floatarg tog); static void residency_free(t_residency *x); static void residency_init(t_residency *x); static void residency_force_position(t_residency *x, t_floatarg position); static void residency_acquire_sample(t_residency *x); static void residency_acquire_stop(t_residency *x); static void residency_transpose(t_residency *x, t_floatarg tf); static void residency_synthresh(t_residency *x, t_floatarg thresh); static void residency_oscbank(t_residency *x, t_floatarg flag); static void residency_meminfo( t_residency *x ); static void residency_size( t_residency *x, t_floatarg newsize); static void residency_verbose( t_residency *x, t_floatarg t); static void do_residency(t_residency *x); void residency_tilde_setup(void) { t_class *c; c = class_new(gensym("residency~"), (t_newmethod)residency_new, (t_method)residency_free,sizeof(t_residency), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_residency, x_f); class_addmethod(c,(t_method)residency_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)residency_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)residency_interpolation,gensym("interpolation"),A_FLOAT,0); class_addmethod(c,(t_method)residency_oscbank,gensym("oscbank"),A_FLOAT,0); class_addmethod(c,(t_method)residency_transpose,gensym("transpose"),A_FLOAT,0); class_addmethod(c,(t_method)residency_synthresh,gensym("synthresh"),A_FLOAT,0); class_addmethod(c,(t_method)residency_acquire_sample,gensym("acquire_sample"), 0); class_addmethod(c,(t_method)residency_acquire_stop,gensym("acquire_stop"), 0); class_addmethod(c,(t_method)residency_playthrough,gensym("playthrough"), A_DEFFLOAT, 0); class_addmethod(c,(t_method)residency_force_position,gensym("force_position"), A_FLOAT, 0); residency_class = c; fftease_announce(OBJECT_NAME); } void residency_force_position(t_residency *x, t_floatarg position) { if( position >= 0.0 && position < 1.0 ){ x->force_pos = position; } } void residency_meminfo( t_residency *x ) { t_fftease *fft = x->fft; post("%d frames in buffer", x->framecount); post("frame_duration: %f, actual time in buffer: %f", x->tadv, (float)(x->framecount) * x->tadv); post("main storage chunk: %.2f MB", (x->framecount * (fft->N + 2) * sizeof(t_float)) / 1000000.0 ); } void residency_transpose(t_residency *x, t_floatarg tf) { x->fft->P = tf; } void residency_synthresh(t_residency *x, t_floatarg thresh) { x->fft->synt = thresh; } void residency_oscbank(t_residency *x, t_floatarg flag) { x->fft->obank_flag = (short) flag; } void residency_verbose(t_residency *x, t_floatarg t) { x->verbose = t; } void residency_size(t_residency *x, t_floatarg newsize) { if(newsize > 0.0){//could be horrendous size, but that's the user's problem x->duration = newsize/1000.0; residency_init(x); } } void residency_playthrough (t_residency *x, t_floatarg tog) { x->playthrough = tog; } void residency_acquire_stop(t_residency *x) { x->acquire_stop = 1; x->read_me = 0; } void residency_free(t_residency *x){ int i; if(x->fft->initialized){ for(i = 0; i < x->framecount; i++){ free(x->loveboat[i]) ; } free(x->loveboat); } fftease_free(x->fft); free(x->fft); } void *residency_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft; 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")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; x->fft->N = FFTEASE_DEFAULT_FFTSIZE; x->fft->overlap = FFTEASE_DEFAULT_OVERLAP; x->fft->winfac = FFTEASE_DEFAULT_WINFAC; x->last_framecount = x->framecount = 0; if(argc > 0){ x->duration = atom_getfloatarg(0, argc, argv) / 1000.0; } else { post("%s: must give duration argument",OBJECT_NAME); return NULL; } if(argc > 1){ fft->N = (int) atom_getfloatarg(1, argc, argv); } if(argc > 2){ fft->overlap = (int) atom_getfloatarg(2, argc, argv); } return x; } void residency_init(t_residency *x) { int i; t_fftease *fft = x->fft; if(!fft->R){ return; } if(fft->initialized == -1){ return; } fftease_init(x->fft); x->tadv = (t_float)fft->D/(t_float)fft->R; if( x->duration <= 0 ){ x->duration = 1.0; } if(!x->tadv){ return; } x->framecount = x->duration / x->tadv; x->read_me = 0; x->acquire_stop = 0; if(x->verbose){ post("%s: will allocate %d frames",OBJECT_NAME, x->framecount); } // could probably improve memory management here if(x->framecount <= 0){ // post("bad framecount:%s",x->framecount); return; } if(fft->initialized == 0){ // x->virgin = 1; x->force_pos = -1.0; x->current_frame = 0; x->fpos = x->last_fpos = 0; x->sync = 0; x->mute = 0; x->playthrough = 0; x->frame_increment = 0.0; // frozen by default x->verbose = 0; x->loveboat = (t_float **) calloc(x->framecount, sizeof(t_float *)); for(i=0;i < x->framecount; i++){ x->loveboat[i] = (t_float *) calloc((fft->N + 2), sizeof(t_float)); if(x->loveboat[i] == NULL){ error("%s: memory error",OBJECT_NAME); return; } } } else if((x->framecount == x->last_framecount) && (fft->initialized != 0)){ return; } else if(fft->initialized == 1) { if(x->framecount != x->last_framecount) { // free individual oldies for(i = 0; i < x->last_framecount; i++){ free(x->loveboat[i]); } x->loveboat = (t_float**)realloc(x->loveboat, x->framecount * sizeof(t_float *)); for(i=0;i < x->framecount; i++){ x->loveboat[i] = (t_float *) calloc((fft->N + 2), sizeof(t_float)); if(x->loveboat[i] == NULL){ error("%s: memory error",OBJECT_NAME); return; } } } } if(! fftease_msp_sanity_check(fft, OBJECT_NAME)){ // return 0; post("residency~ failed sanity test in Init"); x->failed_init = 1; } else { x->failed_init = 0; } if (fft->D <= 0.0 || fft->R <= 0.0){ error("%s: bad decimation size or bad sampling rate - cannot proceed",OBJECT_NAME); post("D: %d R: %d",fft->D, fft->R); return; } x->last_framecount = x->framecount; } static void do_residency(t_residency *x) { int i; t_float fframe = x->current_frame ; t_float last_fpos = x->last_fpos ; int framecount = x->framecount; t_float fincr = x->frame_increment; t_float fpos = x->fpos; t_float force_pos = x->force_pos; t_float frak; long index1, index2; t_fftease *fft = x->fft; if(x->acquire_stop){ x->acquire_stop = 0; fpos = (t_float) x->frames_read / (t_float) framecount; last_fpos = fpos; fframe = x->frames_read; if(x->verbose){ post("residency: data acquisition stopped"); } } else if(x->read_me) { // state for sampling to buffer if(x->frames_read >= framecount){ // termination condition x->read_me = 0; if(x->verbose){ post("residency: data acquisition completed"); } } else { // convert and store in one frame fftease_fold(fft); fftease_rdft(fft,1); fftease_convert(fft); for(i= 0; i < fft->N + 2; i++){ x->loveboat[x->frames_read][i] = fft->channel[i]; } ++(x->frames_read); } } else { // a sample is now in the buffer if(fpos < 0) fpos = 0; if(fpos > 1) fpos = 1; if(force_pos >= 0.0 && force_pos < 1.0){ // post("forcing frame to %f", force_pos); fframe = force_pos * (float) framecount; last_fpos = fpos = force_pos; x->force_pos = -1.0; } else if(fpos != last_fpos){ fframe = fpos * (float) framecount; last_fpos = fpos; } fframe += fincr; while(fframe >= framecount) { fframe -= framecount; } while( fframe < 0. ) { fframe += framecount; } if(x->framecount > 0) { x->sync = fframe/(float)x->framecount; } if(x->interpolation_attr == 1){ index1 = floor(fframe); index2 = (index1+1) % x->framecount; frak = fframe - (t_float)index1; for(i= 0; i < fft->N + 2; i++){ fft->channel[i] = x->loveboat[index1][i] + frak * (x->loveboat[index2][i] - x->loveboat[index1][i]); } } else { for(i= 0; i < fft->N + 2; i++){ fft->channel[i]= x->loveboat[(int)fframe][i]; } } if(fft->obank_flag){ fftease_oscbank(fft); } else { fftease_unconvert(fft); fftease_rdft(fft,FFT_INVERSE); fftease_overlapadd(fft); } } /* restore state variables */ x->current_frame = fframe; x->frame_increment = fincr; x->fpos = fpos; x->last_fpos = last_fpos; } t_int *residency_perform(t_int *w) { int i, j; ////////////////////////////////////////////// t_residency *x = (t_residency *) (w[1]); t_float *MSPInputVector = (t_float *)(w[2]); t_float *increment = (t_float *)(w[3]); t_float *position = (t_float *)(w[4]); t_float *MSPOutputVector = (t_float *)(w[5]); t_float *vec_sync = (t_float *)(w[6]); t_fftease *fft = x->fft; int MSPVectorSize = fft->MSPVectorSize; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int D = fft->D; int Nw = fft->Nw; t_float *input = fft->input; t_float *output = fft->output; t_float mult = fft->mult; x->frame_increment = *increment; x->fpos = *position; if( fft->obank_flag ) mult *= FFTEASE_OSCBANK_SCALAR; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } for(i=0; i < MSPVectorSize; i++){ vec_sync[i] = 0.0; } return w+7; } if(x->acquire_stop){ // will reset flag inside do_residency for(i=0; i < MSPVectorSize; i++){ output[i] = 0.0; } x->read_me = 0; } for ( i = 0; i < MSPVectorSize; i++ ){ vec_sync[i] = x->sync; } if(x->framecount > 0 && x->read_me ) x->sync = (t_float)x->frames_read/(t_float)x->framecount; if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_residency(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_residency(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_residency(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+7; } void residency_acquire_sample(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 = (short) tog; } void residency_interpolation(t_residency *x, t_floatarg tog) { x->interpolation_attr = (short) tog; } void residency_dsp(t_residency *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ residency_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(residency_perform, 6, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[4]->s_vec); } } pd-fftease-3.0.1/schmear~.c000066400000000000000000000215441401707710000155200ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *schmear_class; #define OBJECT_NAME "schmear~" #define MAXSCHMEAR (129) typedef struct _schmear { t_object x_obj; t_float x_f; t_fftease *fft; t_float schmearmult; short mute; t_float *spreader; t_float *newamps; int spreadlen; t_float threshold; short freakmode; int shift; } t_schmear; static void schmear_dsp(t_schmear *x, t_signal **sp); static t_int *schmear_perform(t_int *w); static void *schmear_new(t_symbol *s, int argc, t_atom *argv); static void schmear_mute(t_schmear *x, t_floatarg toggle); static void schmear_free(t_schmear *x); static void schmear_init(t_schmear *x); static void schmear_threshold(t_schmear *x, t_floatarg f); static void schmear_schmimp(t_schmear *x, t_symbol *msg, short argc, t_atom *argv); static void schmear_shift(t_schmear *x, t_floatarg f); static void schmear_oscbank(t_schmear *x, t_floatarg flag); static void do_schmear(t_schmear *x); void schmear_tilde_setup(void) { t_class *c; c = class_new(gensym("schmear~"), (t_newmethod)schmear_new, (t_method)schmear_free,sizeof(t_schmear), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_schmear, x_f); class_addmethod(c,(t_method)schmear_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)schmear_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)schmear_threshold,gensym("threshold"),A_FLOAT,0); class_addmethod(c,(t_method)schmear_shift,gensym("shift"),A_FLOAT,0); class_addmethod(c,(t_method)schmear_schmimp,gensym("schmimp"),A_GIMME,0); schmear_class = c; fftease_announce(OBJECT_NAME); } void schmear_oscbank(t_schmear *x, t_floatarg flag) { x->fft->obank_flag = (short) flag; } void schmear_mute(t_schmear *x, t_floatarg toggle) { x->mute = (short)toggle; } void schmear_shift(t_schmear *x, t_floatarg f) { x->shift = (int)f; } void schmear_schmimp(t_schmear *x, t_symbol *msg, short argc, t_atom *argv) { int i; if(argc > MAXSCHMEAR){ post("%d is too long for schmear", argc); return; } if(! (argc % 2) ){ post("%s: impulse length %d must be odd",OBJECT_NAME, argc); return; } for( i = 0; i < argc; i++ ){ x->spreader[i] = atom_getfloatarg(i,argc,argv); } x->spreadlen = argc; } void schmear_threshold(t_schmear *x, t_floatarg t) { x->threshold = (float)t; } void *schmear_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft; t_schmear *x = (t_schmear *)pd_new(schmear_class); outlet_new(&x->x_obj, gensym("signal")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft->initialized = 0; x->threshold = 0.1; x->schmearmult = 0.1; x->mute = 0; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void schmear_init(t_schmear *x) { t_fftease *fft = x->fft; fftease_init(fft); x->newamps = (t_float *) calloc((fft->N2+1), sizeof(t_float)); x->spreadlen = 7; x->spreader = (t_float *) calloc(MAXSCHMEAR, sizeof(t_float)); x->spreader[0] = 0.6; x->spreader[1] = 0.3; x->spreader[2] = 0.15; x->spreader[3] = 0.0; x->spreader[4] = 0.15; x->spreader[5] = 0.3; x->spreader[6] = 0.6; x->shift = 0; } void schmear_free(t_schmear *x) { if(x->fft->initialized){ free(x->newamps); free(x->spreader); } fftease_free(x->fft); free(x->fft); } static void do_schmear(t_schmear *x) { int i, j; t_fftease *fft = x->fft; t_float *channel = fft->channel; t_float frame_peak = 0.0, local_thresh; t_float threshold = x->threshold; int shift = x->shift; int N = fft->N; int N2 = fft->N2; t_float *newamps = x->newamps; t_float *spreader = x->spreader; t_float curamp; int spreadlen = x->spreadlen; int spread_center = (spreadlen - 1) / 2; int thisbin; fftease_fold(fft); fftease_rdft(fft,1); fftease_convert(fft); 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 < N2; i++){ newamps[i] = 0.0; } /* if( freakmode ){ // weird mistake version for(i = 0; i < N2; i++){ if(channel[i * 2] > local_thresh){ curamp = channel[i * 2]; for(j = i - spread_center; j <= i + spread_center; j++){ if(j >= 0 && j < N2){ newamps[j] += curamp * spreader[j + spread_center]; } } } } } */ // no spread for now for(i = 0; i < N2; i++){ curamp = channel[i * 2]; if(curamp > local_thresh){ for(j = 0; j < spreadlen; j++){ thisbin = i + j - spread_center; if(thisbin >= 0 && thisbin < N2){ newamps[thisbin] += curamp * spreader[j]; } } } else { newamps[i] = curamp; } } if( shift > 0 ){ for( i = 0; i < N2; i++){ channel[i * 2] = newamps[i]; } for( i = 0; i < N2; i++){ newamps[(i + shift) % N2] = channel[i * 2]; } } // move amps back where they belong for(i = 0; i < N2; i++){ channel[i * 2] = newamps[i]; } fftease_unconvert(fft); fftease_rdft(fft,-1); fftease_overlapadd(fft); } t_int *schmear_perform(t_int *w) { int i,j; t_schmear *x = (t_schmear *) (w[1]); t_float *MSPInputVector = (t_float *)(w[2]); t_float *MSPOutputVector = (t_float *)(w[3]); t_fftease *fft = x->fft; int D = fft->D; int Nw = fft->Nw; t_float *input = fft->input; t_float *output = fft->output; t_float mult = fft->mult; int MSPVectorSize = fft->MSPVectorSize; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; if(x->mute){ for( j = 0; j < MSPVectorSize; j++) { *MSPOutputVector++ = *MSPInputVector++ * FFTEASE_BYPASS_GAIN; } return w+4; } if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_schmear(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_schmear(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_schmear(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+4; } void schmear_dsp(t_schmear *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ schmear_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(schmear_perform, 3, x, sp[0]->s_vec, sp[1]->s_vec); } } pd-fftease-3.0.1/scrape~.c000066400000000000000000000207561401707710000153570ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *scrape_class; #define OBJECT_NAME "scrape~" typedef struct _scrape { t_object x_obj; t_float x_f; t_fftease *fft; t_float knee; t_float cutoff; t_float scrape_mult; t_float thresh1; t_float thresh2; t_float *threshfunc; short mute; } t_scrape; static void scrape_dsp(t_scrape *x, t_signal **sp); static t_int *scrape_perform(t_int *w); static void *scrape_new(t_symbol *msg, short argc, t_atom *argv); static void update_thresh_function( t_scrape *x ); static void scrape_mute(t_scrape *x, t_floatarg toggle); static void scrape_free( t_scrape *x ); static void update_thresh_function( t_scrape *x ); static void scrape_init(t_scrape *x); void scrape_tilde_setup(void) { t_class *c; c = class_new(gensym("scrape~"), (t_newmethod)scrape_new, (t_method)scrape_free,sizeof(t_scrape), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_scrape, x_f); class_addmethod(c,(t_method)scrape_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)scrape_mute,gensym("mute"),A_FLOAT,0); scrape_class = c; fftease_announce(OBJECT_NAME); } void scrape_free( t_scrape *x ) { if(x->fft->initialized){ free(x->threshfunc); } fftease_free(x->fft); free(x->fft); } void *scrape_new(t_symbol *msg, short argc, t_atom *argv) { t_fftease *fft; t_scrape *x = (t_scrape *)pd_new(scrape_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")); 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->fft = (t_fftease *) calloc(1, sizeof(t_fftease) ); fft = x->fft; fft->initialized = 0; x->knee = 1000.0; x->cutoff = 4000.0; x->thresh1 = 0.001; x->thresh2 = 0.09; x->scrape_mult = 0.1; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void scrape_init(t_scrape *x) { t_fftease *fft = x->fft; short initialized = fft->initialized; fftease_init(fft); if(!initialized){ x->mute = 0; x->threshfunc = (t_float *) calloc(fft->N2, sizeof(t_float)); update_thresh_function(x); } else if(initialized == 1){ x->threshfunc = (t_float *) realloc(x->threshfunc, fft->N2 * sizeof(t_float)); update_thresh_function(x); } } void update_thresh_function( t_scrape *x ) { t_float funda, curfreq, m1, m2; int i; int R = x->fft->R; int N = x->fft->N; int N2 = x->fft->N2; funda = (t_float) R / ((t_float)N); curfreq = funda ; for( i = 0; i < 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; } static void do_scrape(t_scrape *x) { int real, imag, amp, phase; t_float a, b; int i; t_float maxamp = 0.0; t_fftease *fft = x->fft; int N2 = fft->N2; t_float scrape_mult = x->scrape_mult; t_float *channel = fft->channel; t_float *buffer = fft->buffer; t_float *threshfunc = x->threshfunc; fftease_fold(fft); fftease_rdft(fft,FFT_FORWARD); for( i = 0; i <= N2; i++ ){ amp = i<<1; if( maxamp < channel[amp] ){ maxamp = channel[amp]; } } for ( i = 0; i <= N2; i++ ) { imag = phase = ( real = amp = i<<1 ) + 1; a = ( i == N2 ? buffer[1] : buffer[real] ); b = ( i == 0 || i == N2 ? 0. : buffer[imag] ); channel[amp] = hypot( a, b ); if ( (channel[amp]) < threshfunc[i] * maxamp ){ channel[amp] *= scrape_mult; } channel[phase] = -atan2( b, a ); } for ( i = 0; i <= N2; i++ ) { imag = phase = ( real = amp = i<<1 ) + 1; buffer[real] = *(channel+amp) * cos( *(channel+phase) ); if ( i != N2 ) buffer[imag] = -*(channel+amp) * sin( *(channel+phase) ); } fftease_rdft(fft, FFT_INVERSE); fftease_overlapadd(fft); } t_int *scrape_perform(t_int *w) { int i,j; t_float tmp ; t_scrape *x = (t_scrape *) (w[1]); t_float *MSPInputVector = (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 *MSPOutputVector = (t_float *)(w[8]); t_fftease *fft = x->fft; int D = fft->D; int Nw = fft->Nw; t_float *input = fft->input; t_float *output = fft->output; t_float mult = fft->mult; int MSPVectorSize = fft->MSPVectorSize; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+9; } tmp = *knee_freq++; if( tmp > 50 && tmp < 20000 ){ x->knee = tmp; } tmp = *cut_freq++; if( tmp > x->knee && tmp < 20000 ){ x->cutoff = *cut_freq++; } x->thresh1 = *thresh1; x->thresh2 = *thresh2; x->scrape_mult = *scrape_mult; update_thresh_function( x ); // if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_scrape(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_scrape(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_scrape(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+9; } void scrape_dsp(t_scrape *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ scrape_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(scrape_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[6]->s_vec); } } pd-fftease-3.0.1/shapee~.c000066400000000000000000000255521401707710000153460ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *shapee_class; #define OBJECT_NAME "shapee~" typedef struct _shapee { t_object x_obj; float x_f; t_fftease *fft,*fft2; int widthConnected; t_float shapeWidth; short mute; } t_shapee; /* msp function prototypes */ static void *shapee_new(t_symbol *s, int argc, t_atom *argv); static void shapee_init(t_shapee *x); static void shapee_mute(t_shapee *x, t_floatarg state); static void shapee_free(t_shapee *x); static void shapee_dsp(t_shapee *x, t_signal **sp); static t_int *shapee_perform(t_int *w); void shapee_tilde_setup(void) { t_class *c; c = class_new(gensym("shapee~"), (t_newmethod)shapee_new, (t_method)shapee_free,sizeof(t_shapee), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_shapee, x_f); class_addmethod(c,(t_method)shapee_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)shapee_mute,gensym("mute"),A_FLOAT,0); shapee_class = c; fftease_announce(OBJECT_NAME); } void *shapee_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft, *fft2; 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")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); x->fft2 = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft2 = x->fft2; fft->initialized = 0; fft2->initialized = 0; /* INITIALIZATIONS */ fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; fft2->N = FFTEASE_DEFAULT_FFTSIZE; fft2->overlap = FFTEASE_DEFAULT_OVERLAP; fft2->winfac = FFTEASE_DEFAULT_WINFAC; fft2->R = fft->R = sys_getsr(); fft2->MSPVectorSize = fft->MSPVectorSize = sys_getblksize(); x->shapeWidth = 2.0; if(argc > 0){ fft->N = fft2->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = fft2->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void shapee_init(t_shapee *x) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; short initialized = fft->initialized; fftease_init(fft); fftease_init(fft2); if(!initialized){ x->mute = 0; } } void shapee_mute(t_shapee *x, t_floatarg state) { x->mute = (short)state; } static void do_shapee(t_shapee *x) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int i,j, R, N, N2, D, Nw, remainingWidth, even, odd; t_float a1, b1, a2, b2, *bufferOne, *bufferTwo, *channelOne, *channelTwo; int shapeWidth = (int) x->shapeWidth; bufferOne = fft->buffer; bufferTwo = fft2->buffer; R = fft->R; N = fft->N; N2 = fft->N2; D = fft->D; Nw = fft->Nw; channelOne = fft->channel; channelTwo = fft2->channel; if(shapeWidth < 1 || shapeWidth > N2) shapeWidth = 1; /* apply hamming window and fold our window buffer into the fft buffer */ fftease_fold(fft); fftease_fold(fft2); /* do an fft */ fftease_rdft(fft,FFT_FORWARD); fftease_rdft(fft2,FFT_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) ); /* 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 ) { if( i+j >= N+2 ){ // post("shapee~: index out of range "); } else { 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 ){ if( i+j >= N+2 ){ // post("shapee~: index out of range "); } else { *(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 ) { if( bindex+j >= N+2 ){ // post("shapee~: index out of range ") } else { 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 ){ if( bindex+j >= N+2 ){ // post("shapee~: index out of range "); } else { *(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) ); } fftease_rdft(fft,FFT_INVERSE); fftease_overlapadd(fft); } t_int *shapee_perform(t_int *w) { int i,j; /* get our inlets and outlets */ t_shapee *x = (t_shapee *) (w[1]); t_float *MSPInputVector1 = (t_float *)(w[2]); t_float *MSPInputVector2 = (t_float *)(w[3]); t_float *inShape = (t_float *)(w[4]); t_float *MSPOutputVector = (t_float *)(w[5]); t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int MSPVectorSize = fft->MSPVectorSize; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; t_float *internalInputVector1 = fft->internalInputVector; t_float *internalInputVector2 = fft2->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; t_float *inputOne = fft->input; t_float *inputTwo = fft2->input; t_float *output = fft->output; int D = fft->D; int Nw = fft->Nw; t_float mult = fft->mult; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+6; } x->shapeWidth = *inShape; if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), MSPInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), MSPInputVector2, D * sizeof(t_float)); do_shapee(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw-D), MSPInputVector1 + (D*i), D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw-D), MSPInputVector2 + (D*i), D * sizeof(t_float)); do_shapee(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector1 + (operationCount * MSPVectorSize), MSPInputVector1, MSPVectorSize * sizeof(t_float)); memcpy(internalInputVector2 + (operationCount * MSPVectorSize), MSPInputVector2, MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize), MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), internalInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), internalInputVector2, D * sizeof(t_float)); do_shapee(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+6; } void shapee_free( t_shapee *x ) { fftease_free(x->fft); fftease_free(x->fft2); free(x->fft); free(x->fft2); } void shapee_dsp(t_shapee *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(!samplerate) return; if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); fft2->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft2); } if(fft->R != samplerate ){ fft->R = samplerate; fft2->R = samplerate; } if(reset_required){ shapee_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(shapee_perform, 5, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,sp[3]->s_vec); } } pd-fftease-3.0.1/smap.pd000066400000000000000000000011721401707710000150140ustar00rootroot00000000000000#N canvas 0 22 458 308 10; #X obj 88 84 inlet; #X obj 88 110 / 127; #X obj 265 144 - 0; #X obj 283 38 t b b; #X floatatom 128 161 5 0 0 0 - - -; #X obj 88 181 *; #X obj 88 210 +; #X floatatom 135 192 5 0 0 0 - - -; #X obj 88 237 outlet; #X obj 283 17 loadbang; #X floatatom 205 125 5 0 0 0 - - -; #X obj 227 66 float \$2; #X obj 304 67 float \$1; #X connect 0 0 1 0; #X connect 1 0 5 0; #X connect 2 0 4 0; #X connect 3 0 11 0; #X connect 3 1 12 0; #X connect 4 0 5 1; #X connect 5 0 6 0; #X connect 6 0 8 0; #X connect 7 0 6 1; #X connect 9 0 3 0; #X connect 10 0 2 0; #X connect 11 0 10 0; #X connect 12 0 2 1; #X connect 12 0 7 0; pd-fftease-3.0.1/sound/000077500000000000000000000000001401707710000146565ustar00rootroot00000000000000pd-fftease-3.0.1/sound/Piano.aif000066400000000000000000002652141401707710000164170ustar00rootroot00000000000000FORMjAIFFCOMM+@DSSNDj^{E@E ; K G I d  y z a  E  a 7 0 zG@ 4 x  d ' Vv  vBYzIaY A;ZJ 10 [ jae7@[J>(1Ў̯`{XS1INܓ V<#ae; G #p+>144f1.i,,.269:72m+%S  #(.v232.*'M%%'*-.V,)J$]Wm!G!+m7  U#Yd O725u~s)Ufr \MAGH!Kmn>;/T// P508ŐBC' V+kbÛFѰg(*dK Of!#+3:?@>:7[67:/<=>l=Z945.v**w-;2V8=A As=6n-%V=$B*1R5H4/&d &**-,-+& y<  n.ѺSk&r>ЎΚԥ9odyeަE4}$ t2j 0*S 2ǥ;ȕ2֫vR]I!]ߣu /SLn!%)u,-./2m7.LH0C>=5>RAFII/Dq<4-)&a##$P(/7=>:A0'M  '/6p:~94,&W"#C&+>/F1R0* dӛӆ~ -sڌ>[: C9;;!\GYPtn7)Cyk ͔٘t %AƐC׌wjШZr1Yɫˡ,գGq?܁ݰ*"%>vE \#k$%$$B#$6%(-5=F0L6MOIB8g/W){(*".366]3.)<%$$(E-38:8C3.,($"}"A#'.B6>A?85' k/su(l%Tr$_owoCX!+ wh$tiNZs:lۨчeᙼ&'tAõ]Ѧר%֡-;p'UHcdK/@ %31_%W1=HO/OKD?:=s?]CLGOJPKKJ4GB=L8559=?EKM>LH@7T-&$(j0z:ELNMJ+E@8/% d_xV'i5;ޙ^8zXU_5ӥڶG/c5_l3XAR^Rp~Hɼ) hn Hkv3, 2jz Da o o!+&4 ;*?A @???@CHMSWUOXE;G3S/|0l5N<4CIL5KH8B :3-K(&'+&0|6h;@bDF4F D@<73/+A%B>5 7`/%aQ}}~ߛ(dh5NwB/b\(X~9ɋϦ)͈%قTP4m(ⶵٵ#+ҏIW#ܻޢD,jFVa<n eZ!$>#""$(/6s=DHJ9HD>.73>0"./04 8k=+ACCf?8/('" 3t +#(-02345-4v1O,%u:/2D ;_ET<)Hcc: %a#@4cOOpذ: ѥ~}+7sKuqv׸+4؃Ցӑw6Z2/,m/5cBe2 #' .7@QFqI%GC>96B4 3N369>DCH~KKK3IEB*>;8C3M-(%_$'h-5=CLFvFED$BBwB0AAD@]?>;7(0-(V!=R[K_&x+K {*u?X`{Gm*tV - OhDIĂuQ7kM含ĹBA׽#F\R47(WP [#/'9AUFGHDA==;_;_BHqM5PQAORKdF5?6.u(@$#|$;&X(+./0r00/0w2#59f;y:6V/s'j ww h 9 Si ~T%U;P>IxcbͶct  2̍qXXXqޖdͨs] C,cʷbҺb|88KK"%z.5:><=:;"7C2/.0P4^:'@ EKPUW UrPInB>M;;;:9X6p2/3,-p0L5f;?bBDCB@?? >:<95/*%#u"" wo[Tbk5 itBQ3 -   #5  ;2 "QЀI9ឭ͝˞͠ ٞڴ|g\α };My=$-4;773.H)')-4:==ACcDyDDB?;5a/ *(),/2R3z3q2=248:>5a/*%#"$g&)9)&|!n :7D S/ 2?OshofQ  bf4>̝/ɱgߤ͟IyӞ&/t۪0"17έt΂סܿmO~I}p? $ 6 u`o !#%*198?_CEEoCA?f> =:8c5*1/.-]+)()P,2r7m;>o?@w?>;8k4a0.-.0600#-3(j"uT T$w()(#-pq S2 +7 [fr),xj pDc'1AQ}ՙśn,&1蜍 $z&Ě˒M{$XLh<ȝxxa~: ^&R#)17r;>@AOBD#ESEE4CB@@=95./+*N*-17=BDD@<76979q<~>?>:(4/,)%"R = 1!%+022-&z 2BvV \%*d f1)*a HGdFd 6&jĒGЭئ⡎ޛC2ڣ׭{f˫r<ǚİ>V" !r+P/p j!U%3(+.81H4u8C9t2A+%U"m"F#&),/1230.,'*K*g,05?8;G:7f1*|#Z @"'+G,M+o)&m!& c+<4D_ UW.Cxt v Oj5 |ŌMK޳W!雳uk̯gJřʢQSNHC|ӜL#E/Ke 2&-5{BEGGEB @d?:3+%"$',1Q4728:<>I?,><38u3/&*|&$$%'\*",/2 35 54}310{,x' 3wfk ~%g'M /gls0[`79V [p,) ѼǘMͬ@⣥ģɫG 3©RĕƤ ^8̂ʬwc ĠlQC pY .A yR1!'-3T7:};;/962/2+k(u&&3'7).(37O:$;<8;c985>2.+>(e%#!q #'k,03345,31 ,%"1 N n & _ +a|4Yu4N_1 <z 7FfG%IšγƬ?ٰ񱖲Wնzpuv ʗǺM#FFֻ/6"V x`# &,2699962-)}%$U$'L*m-q042Y4H6p79w: 9753{0-)%] +"g(07B<=<@7~0( =; v"9i  o `<p4Xِا޿.)i  s _  _! ,T۷ҩɟݹ۴± ǩ+Ѭq@<Ƅ̒%nll\̕3cҒ)pӺֻ٨lg&n,L1&+/2}44=20-*(m'F'=')e+-/"013N5y7:=L>>Q;5].(u"}.Ac  h 0  ?  {z6+ޝ=|~`h,E!  1 YE +0k?-_C˛ĒRxĸƥɡπbЦ %}Jߵ&&oj p$"*/2=22282*3<4431.,+g+-0j4Q8 &  6 Vm c[.ݭۙ۝Bn` < 5K KX X - ?nͨڱvѷ"I¯S“PIڿ&Ć^'Nɡ=BϷpV\ݘܸݭ]~TB Zo#K'*-//.3+(%#"'!"%*07pTždžʀѱSOڞ۶۳Y݋߁"9: ^=%k*.b0f10/.+"( %# "z#t'P-F4;BmG0HGiC>9"3/m,`*'%#""$k'+/3 5?678875Y1-(#r oxI9 A JJ EHNuU }Z9UpZA  ~"%$!E\~ KiߠEb͔ʾȳőúolƼW{ LĤ›fɵr ԡ q8fصح/ܶw: %v!'+-K+(#7~j!&**/49=@ByB^@=f95i1 -')S%#"|"3"#%A'*]-=036 66a542W0>-X)$;[ o='Z _Pp6F5|F ~,^KC*\i!$m$! ?V }Grɗ +QƋf$epũ]McͱlқmӶԫլEHDdnٜ9 +&V"<#,"! >vU!$)S.4{9GhCESE.BO<5<-%3!/1!Hu 9?:99(88:763F/*%!6  ~%,39/=>>B<8}3x-(X" 7Wk n 9  2 sw_E L5n Ubc"Qׂ ܆x  s*O +{g?xr)ǮŰ'`ËS=ý;l#ƌ̢XV]^8aĸ,$ S, v + \ s X f _iL|$Z(+.02r5 7:=@vAX@E=78-2#,&"\z"Q&Z+(059:62/\-#+B* )((q''(X),176:>@ @0>;'5/)#q Cf 4 >2`O]]ԆW` ܼy =[Q H@ 7BJiyiPg֘ҵʼ(ź_͗FSܒ~SHH56wc(à~DP_<SX v")058:|::X99z87c520,-F*3'&%&),l05[9=^@fBbBA?93[, $d{&<r(jE v G "Yu^gQKI8ԺԑxB܍5Iz Y0y /7s/*D`ގIfɜ–koBߺG+]ldO$ͮāŸaJͼ}N~eY5 lJ!%*f.2689)876J4B2x0-h*)'$#~$&*07T=mBDE2C?;6G1,(G$!vRf x  * 'D>Pڜ^ؓ}i} 4ORnz ?u70([ӽĺضצc(Ϭ8iW2{lCʬчJ=NZI "&*.25887C4L/+'w#! !$',247<8q41#-+Q)'$" #+v {!!!StWG B  EsםwMI;6jP kii* L%XNkD'ݦտ¯2M$}Ѐѱ>E=h;9*6C2.+3'$"w!e !-"-#X$%)$#h!)Rh:  d i p+w*ߓٰH -f0 ; T $  J d {*(ړa2͎ʀNjPK&DZfc/9{дqǗHX(NQ>Ϊv ړO5mo ^  #)-v..,*n(%$"!!"$|&)=,/3^7:=<=>Y=<96\2-)&%;$%A&4&'3'&J%$V" Tk54U [O I`ZG~ܠrG\ a k5 C _l p 30߳و.xrȅ$BϷӓQړ܀ۃ[u;Uge<4"i@7+8h!F?$l!%'X('&%m#""!! !#%)-26W9<>C>:<963I0.,*)((Q(P(A(R(('&% # {%iPeT`   0FIߧlե~vPU9 $ [ XQa :L : a/5d:xʈID3״nޓد>ѡ#÷«Zÿ)(|TӬRٗ?Sݖ;eN% "Z#$$" rQ!$(-9158I9:s:r98>64[1/q-+*p***+A+++*)x'p$!u@|7@=5{- %OEڠs٭Qݲ?s+QPq- V e m[ Ae }- .R`jٍhܜUچفHүż,+ʶ.MֆՕXp҂ҺՅ4i  j5 ! AY  #'+.i147r998742p0F.-,,},F,S,-r.(...1,*{'%l" .fOZ2b:771 !V v!zL&3߼SA#4 j (o e!  ,0sVՒwS_nڧ^%??ژعՐAxǚûh" 9!s˩kTT~ь)rnіӀjI55 { ,A#7T $(+/z264H555S4!20/2-W++S+V,/01f10.w,+*)(("&$"R^w `"#$$L" z/}Ur$ nF$Tc '=uPvt n 1!߁ڸNר؅:ިE/)B.`eGgƻQʐΗWͨPf`O$pE DKui7/,`"'+0A3'45,4#310/B..001K1,0d//^/r/0v01(1S0/.c+(U$! dWY H"%H'h(('%)  \voIqmm]_S j[Zk ?9} .IN_ 0B `_ܒʥ>¦-[G#̿͋ͷ̧lơƤ}ܡH5e -};%|"%(w*,\-//q///01001/S.l-a,,|,-.M/12F22Y1/,*U'$!a~!U$'w()&(&3#!U '4POYd)@ o-Op!AT Pdݝ0sr8?޻ ҅vǥŏ8WéxQ{˹LŏĀx|FlsQ\X  mI6 #W%(*q,/1211//--H,--C-m--R-!-G-.03/454^1-)^$>f~e\7%C 1;5ÚŦ}|. jm*j;"=` 9)3  """""z!!"v#%f'*,.0256366`4K1Y-(${!@ O"!i#%')+>,a,,+*($&#!wt ^ pJ|5`*mۼܸ*nyC\ , j:J1 ~Lp}22&TIp{9X$2ֈPׇdڌYټխuW쿪'=UáǛӀqޭ 9 | @cS  B !!"J#%H'+.257887641}.H*E&`" yA [ E > !$B')+,[+*)'m%$"!9knF:k J ' QOYZ {}5 )=$OO;FizI}ޑݪ݄D.ܰܘM؟֋ӷБ3Lr< 32āw̯ΩRِ)%:zX[ tb)\C".%*f.2455532P0g-*'$L!&@0 |!`"<#+#%6&e'(f(M'j&#!qJ"fV(C ~X0/s5x=޷ 9 vW92: Ek .g m;j!O 7 @ 4  dz.A 6:NtCZ`le_TQNl8Q.fę,84μLίC^ /QOSu D ~ 7k "&6)-j0B2313*20.*'%;#"#3$$%$$#G"##$&>'''m&&%\##R#$X%)&S'('&%"b ElUEe/  IYm^y   'a}[5[c] ,d |BluƱƇǬȐ*ɠɿ ~vIz6\dا}%jZa\ y J 'l$(,/M0f0C.-C+w)(((Q'&%$B"! !"#r$1%%%$w#[! z "$&j'b''X'&&'&%#0 \E~&$5J d   {j*Mi { i q G Tc7/}D 1/d΍}*jfabLʕFȋȋɦOրڶ$pJ,Q w\!v$&0')`*h++|+++[*Q(&$"!f!]"2#$%"$#"v!Q h !!!+ f V!L"$`&-')+<,k,,=*r'#AO RO$>;YzUO% 0  a Ye5Vr_`.>CԴ Gʤxʨƹ-=)>ʡz#ԇ}߳.3o@d}, <6  ,_#'*4+m+7)(U'6&%g$%% $$$_##=""o"H"(!!!!& BylM F"&7),.9.-,K*(K&8# ayDmN%#tnn%>  5 /a Tyt5c/ѪѠк]̹Q4w>Ʒ.šƚTpٰ;4 Kk;*)I sS!?#`$&3&&&&l&&&&&&Z%%$$$L$%&F&%9#> [z}!=#N% &')+,./P//S-*&!751`NK@~{4n  [  < / x  9,x\ 7oRESܵؿҗ,7%ѫn]v\`*MՋlmRa%il [ !#%%$m#a"!G !F"L#%&'-&^$" eg#3&k b"%'.)*,./0a06.,'!! GPTz3r)*",  3/7'O6!$HCֺհճmאӆ S4[Ɓ6huİCΰ5"S Z:YZ*UeM BKm "#$W$$$$##"!V +:t"K"%)3,$//19220-)#  k}oF%9rURf!+N5 :  1 ? "y\!N+f%x>x eWܠ۝.yvˢɃF,i8ЬԡU#uP6D  \F6R!z#8%&X' &&&%E${$)##""!` 82{"&j),.0W1x2*10-()=$vtW Od*)7/]d y:i2   TK@$M=k"h^: tHo*4ޒݓ܇C%۫^NЋk/ƪ)({&u# k{E ;^qO!O}u@v"_Fs&>Oqlh`d g 7!#%()k*+++b*))* *8*3)']#/ hl!YQ6<,/0/.,")h&# 9)<A Y,Pl9sGT`Y`;d.#ZiN$ h Aooߒ?9ԖJH̖ͱΩϦД?ۥ]B U@A<5  u=6 !"!" & !B!& Rt!!"%(u*,-.w..8--,*(]%#q u `IL ;*e%it!YAfhuA}ho+SE 65bi>@ёЗ>͌"QYԈ ܫG/# p Ii=|B !g!?! z B!#&X(*$+},-p.}/000".,)u&q#> 6\Oa j Hp@+u0*| 6k/;)o_N^n>F8ghm{xMcϷ#N^Ϗ$9R ~lj#fB8 R .@ETU b!f!r!] P=E= "$#'6*-0w12*1,/-+*e)))))x'[#BQ t iE! *af{$!OkD?Kc]=04:%Xzbe?܇قբҷ̻ɛAխׇ فOݍBb}f5)p &U. a !!!7CqP`#',*,g-!,+**)*v, ./1(0.+H&Z .T1 [ z VK( \ @ [^G .!""! %Q 2L ##%&G&N%$$%L&)M,$/'1221/,)|& "A& V{%pO~Yc-*tjA5 &,2Kszm_/k./@nNs$Ֆ (ͿbЁxl`֐_u-ROId]6X , !!7R@ w q \!#%(+l-/Q0V0p//M.%,*(w&Q#z!z8!f  ,z js^/gN 4 $Gzm_$*!q,zcjLh"tߥ ڍׇԓ=Y x.ҝl9<1t:G @ި)4i/X 7!Mu47%Hk+ "p$&J(K*+-./.-+* (o&%#"9 Gt/k; j o"IbP!FP /}4.inmQ՝=x҉Ϣg҆ԂӓҰҋ%ԡ׎e$I:A99 -jEg#  t(!S#& ')Z*u+v,K-L--- +s)7' %q$W##M# "! |'+W ^ <;Uw[L,2BEQb.pLHDV}*oB`~7 _|&ݾ۰^вХ{x հx^W<͚}չjwJ%Rb*z!T" J J= #aB a(()ew H"w$'3)^++,,,W++**r*!))a(8'E&%2$_"!S+* G A1nGKyxT& SH4Df>1KVu،Ӫlס3Հ-$ɰ%Ͷ:2N؟/X iY:mu 0A  k&YU` j"S#%z&|'b''(M()1)a))8((P'.&8%%l%%%$#, :A. [a{c; YB v5<*(UX:~#olZ^?T"QIMay.ٺЊϧ}=QЦKң զםjX!>3#tS K ;aB= IR Z!!]!j Q   3 !U"#"$&(+-//.,)V%" ,6   &  ? K \ D N^O^7:L3\ABNoQ80 [p_h-^XC 4mrcJQ}I͛Ѐ>GրX"۷b;S}jX+:H{! K  r & ~<\. , a MH!U$'*+,H,+++**)0'|%_" !z{ \ ?e'  n$aj'!e /+k:l!N~>fAL =qpnSP sqiجCqιgySJچ|s 9~=en;< ' / O !Viut "$%'(*.+s,--,+(s%  `| lq~V  iA}!KT[4lxgQ?mM" I7JhtIUR֡q(7ѨCq5AdۛVوݛ%I}y  0 8Hf&A@!$M'K*-/00\.,8($ xW/B @ 'ZN]dy02Ft!PhhAusfp.qD{,i: ]vҭ8b~aRBֻ ؽHgg}*Yܣm}sUx iB  7@(vRi"&*.-K./..,B)&b#. b0,&n% U3&:c,f\ v_iv~ZeZAu#%&0{C:m{PY9ܵ(ֶ:>Ԫ#բFWר.gٗGIְְ$؃2d^cU/#z-6vD: {A`sY% (H@ #0%'()})A(m&%c#q! ,jTP@NW`-jVz $xpK_e GS:6lK_VO0'1J9JܭٺسhֽMdٰ 3ڮvչԍ>տD߽^xyY>?*@X ofPdz SK%k.`!y"$Q%;%&0%%w$# !MB,w"o+3i _ZN|0SQ j1I{br X[F7IP6Yj N+rU٫ܣ߬d:٧׿)I}4nG$ +/  ~ Y*DG %!"!""#e#""J A`R0A`{&G, Ec@KN -QRxzi z7f*?`+$3~܀m؇_ْڋ!P$1c`"3 e c' / ayG7<q;, !""R! Ap'Ap` 2  ds%Y~ +Q-lVYb :N $V?SF/BO߫#ڋNڲQ*gNNj@n_r X _ } a E  6 P}{RF!7!!ZHo3!\oLTc/ `zsL% RYj~b})@? 6%;E8yejE4?!O6X,x$So%,|w܈ٰs޽(` AOSv!V6?,?{sK 5 81~?dVqd ?Q# HU6Y@;{P}/+vq*: )xrF*r ۅ={)D Hi,J{da{!s$ Y7LOwEZZ I G[L{ F p-D`qDo@aaEi?)s4_sG24>Sh[toi`)D`~3o݌4ۜۼW;tm?j,tmjM9plTn<@y2P  kdx  t ~UzW H_eU1@DKVvTDZES[byEy_xp[58n~m_`+u5k)&[ߺ{a޵=|}Uii ~6jy(6$ ' X '%: &p8ql7 A sS92 *9]oZ -t @y K(^WENN1RJcoV+}^%`7Kn1@ E>UJG z " \ ) O  i^3[K +L-KDsD,M^YnP` 9)G~*6y'v"_E7oT_V&)6tIPju@mUiJ9cjOxcfC~0K o 6KJ\?\   + ( U J$z<+ AQkY+yij%%- A{yB=|I=6y %_y!N~NsSi4ZmzbxsD"`y2VN _ /Q8a7_ _ t p + ) ~lE > D!A.<M3}s cc*q8e>(&K_\ S!Li jO&JJ:Q %sQ TJ7qZ'Z: @ %t + 9uj  1 Rni " fd0~hSBJ,JT /]o%0eQ*20Pemu2"ZZy7^K6bf04Dgg]:]I`@ibTaMc ` i e p^x Y { ay"Z iu$2&xj&+wj*@rEgVzDpjHt@F kTC@1[/,#*~Ofq)pItq[ Kz ' 4 OdS d z # < 5=-B  m xo{YOS%&[JW'jc;G_~4^! ikT  !.c:e>iYTA4tl[2U+Att;_& Z%h^ [ "m   UaAOs,@;u-GmOh YYkd9S9 O O J7Y57md?*$@  V x2p_y Dv!~ @#\cdaBPJ  & D  d7M YTK5EI1?/x!~JTht!sftT9eC\{$hw1syp!>}E'   Y A D?AcW+^fIUqN++TED" 2e8+E-#A_]yz  }u DEZ;Qh1tf.z6"16^*,DEN'?]  o U cD:b= ;fo hn-n,eOO:%+!F1_'kZ:v1A}  d   u u{A:Nn+&_1tJ_Zo-h,$]+ I4FbDWFc^8~ >]e@ 2 yLS1F"<*/TY_!6", #jpY&Nt[*] ~  tsc'==92F!+~OJU T;nFZs"{% :@{ ? _$Auk:b:sI L6UeDYek5e'"aI*<eg\tn}"0 / a  e U 9!+z~4 N0=/{[i@1dP,DO@}LA:jXmaNOSv 6GJ?/ =y/yRKZ  GKn'?P # @  ! D k/;Mkq4/&FhD iJ&F:}N 8A{%yKE7rjZ}E4 jae': /t\QkeY/k_d@0Ee! D j`VWnjAp9z,~6`ePS6TTt6bOE/=J4Ohc1??Qy+gVW{EQD'{ O^($1DQKvy=E/t y ~ a J9c!P"(` @!p U G+ Ls@49[2:`2nz<K ^e!!L1 :@<< V`k cY&jUET%KzJOGnZtaS#&  s D  !Hmr_O/@_U.{(z1 QT ,PEIXt J[ "TueKLMa Hd<yWd}Fh5VGst0uBL^&fDI 6&Ud5vh?l' ! o "~j)uD_*e~AU@ Qzc\'}`@UD`I Z>u?F{'[Y;JB|tgg=hf@3nN NoE7D 50,`*^s!is-jFT rKAxh|l!sN+vJ1yEZ:%4f\5{5`:/Z~I6?n>!J< u\ jD OUxnQs?&t1#Z_5x _m*VsN2GG*Aw`cf_RTQZd2v@\^6W0 P{A:F01?i}UTc:g%oG`,LnY;Tk:$cAoN<:#FYk"1tK~jP4[3 A\6t6t<vj\P1o'pCZY=2~''.  p<<Q?z_Jh;Y"~Jfayd1jP,@F{D?yk'> 0 Y { erKW::f k%9_?_DfQ:B_dej+pVs6jB\U^t5=+U0$@KYH(1'{Ioc/9yAC0<,u+K;  + 'sk;,Q"2#fGFTNa~xJtfa|txz<^Z vS_dL-ii"KX2 Y'B6?Y\QIAh_ZA<V z+@-zHS*~PSA+"-46elL1B^uh-07cfE iK FPTSZ Y"v?g:ByJf_+(vJE1ZEd_p6Lb"5^%~^U6piPeyurYpF/sk54h"_O[~pt[3PYGUUg!nW*y/+\E_vey^(:f%C%   :SEEYD2 MW^d ^x"'%P(ksP11/@/_n_;B{pLv (&iu+stY16cY}/ XyZ<p@W%L,y*AYsRe ca!x_K"*@9!;o$a[ \$",KU\FaV`:7 ,:N =9=JD+ZB2w6:io4^J@\20wCh* p+@"O6+ dZ#dJi&,'kl K%! SY&v"o&FfodQ/<p4jA<[ZfpCnQsSj!ihe^rh4V*sm<R D9vFy~KtnTVLszbaq}?`g1&" `M);Y>;h\nXh/77(Y Ev:+` 3 z&vW+ vLA'YLjopd[;WWhX{~TT/Gu Q?LR6 n%B1NW-TT'7D p=d@OY>1 >qPi K k@eIz%v^7Uk?4_s4KZQ* V5/H .TV$+ P@M(*dJkF|x v\i^ v"tFz (If&Ay fNFT"2Vpsa'TTG d.CNi>Pp1R5Tuo":-=PsFaT1[BG xuSQcBD4$ >n!#A)j&Jtj4@g/%Ge?oUh0J p"]N?d,dV'>cF*NQYJVo{; z@BfivFZ&^SVI U .P"9EpCOSfS=`iVk 9,Aye\_ma sK +xt?dJ4VuY!0T*kB WYAlj 4-tkJ4 dp?"91tJ[~@oY't\Qk^jA'lVT[Aps<K  Sp?g{YQt~)9dV 5j??K +L&yj6PekNt^ (K`Fu}{?<No'Wk9=kAJK%|ZBjo\2B,g7k`T fWQ_V 0, -C-[%%BV` Vhuh@ ?'ixr0en "G!~+BKY zTBqSd v4znVq>uJt/4"d6%&:V|T!y@?;D`x 5.NLk}n7:F6?tTQvyMLR:-6'p{{LJ & ,1. .1n%_D:*u,P\~5 jxmQ*Fuc LOHeRc8%vyP6u\ <P% lW?[B,L_ye&ee5Jf{yzoTB ?$$z uIFI5++?_;'?3:n-ZufxOmE'%+0Fs9b$AAWL/gY_BElJ8TMN; i{_f% 4j\Y*/V5nb",D<^4(:idut%"/4f(SI|lfvA jU>;?2UsZRxnecz'k^%ReTL?4YpP~IhiZ)"sx8_h`xZ6tWj0=Gk;_:,yF`L&c eoEBU"dp#9#PFc fQQh#6d^e y~yOi4J?Sy n@<T1eo KGl`sPzy6"#i_Kjl6`"Kv@+-%%B?WFe""!</+LE,"dT9UH2%OBQJB VW = 0t[:@I1 saJ7DZvVGq"B\o__EenzZk*$Uo2'eQ+1%qT6_"nyUgGWu<9<44(.T?Bjz*?47/f -K[;czn>jpj}V~'nBf_#O{<\ GvG kZ7q0;p1#f"Vi40 >D+`ZT + 9-KPjpV<i<c^O;tce{xKhSF`4}oNYJU:2={-_j!-kT tYl!FU:Bjnk%BQd_m{0GExk fQ_AuFJHV<'TeCb[\j!tZ*1}HO`B%gQN0'=y<|<"zo$ Ej+Py'et-KFB?+KjL" DNK_kNV "EH[6K*Tk>   E FJUNX"E,!pJtE1=" 9:F,q,6F$2!!QZn7 "Y# 'J&Z~*_!T^A@{N@HdSm{OiSe[?%* pGEUw(VK7,E&[8 ^ ?}_p$J(2":Pp0RJu_(WY<`YoZ$KcYmdisYVZmpr~ipbxt^<^+WkR}Wt]Kp"%Tj"?i'!jL;f_-?j`*V%Jd?;0"!@-am, Y%a 7/FKFjKKTE`zFeKJ6u&ak\ ?s}y<YA0lG16PUj@NO.W[p<5MdFe Dk;QB +jT\~B2;?,+@4J4DyrTu8,WdLR !@<\sBY_k"8es{16p1P3sB%se4%C#=MNvcNe'_(?duw{aZ}+?KE/pTn~{K4](\d?W0P DP:LxDyetF2`jQdv*j(E 2p0`Z12n%yD[TeYWYn;K(!KP%Kt^EnJ@:Np[ +bs5PxPB`?N{<VL<+HQ8 [ate# I >$vstAaJ_fu hxJp6J *u+@ !f0Nk-_o'@ 1-5;.4A!>"b1E *]d~N`N>6 2.YLI `~q  OE5/BF3Oug!k:OqP!XT*UdE1/08WnK@P: 8W4!T*;!L@@GR g m*Q'Ukp5LYh{Qeo& +Kf0%-xcL 9? B@:5@B:a[+M`z 8P *a:QR"kNHA%BaDHhP-;k D.;?%Py YG%p'TA^zGh_c1E*%(Tn}08|c#g`v7B#J XRGLaeVhV1R?!0(D2A'1:'8G1G1YZJnT!x7f sVkFAEjtVYB\UK&+: nZt|7}ENoR:YK@!s6Qsq%% <TJ1h;[Qoj}112KT;[JQ_-(!@8z8,a 'M"psPpT;#[@! B951@+G?eyyj=2E'"[&ST0QVI7q-2H&;cI^H  *%f^}k5F[(\c^hys4z=n+*1;; (?\T#sq??K#{q"'M  g[+- Gj"1_h@'~BvOM,jMlt@<=zlx&B L&m1L86T+-gyazv#%%1 L! YO*^{inqTgi:*7*e!Fyt&L ~eIS!mZ6 szzTJziz{ 6gs;O WS Q<E%1D6FvQYv_Vq*(4QOd=Ysen>HPch"tDp9!s2 Vgk?O^tJvt IfcG!Tg 7G{lujF7M99QY 4,(AKBywD?[=5sEV/4T"YDQM%Bz1 TG6a9F=hpm txl]f.8Mgl{Pk O|L+U"%4RUh 3*29X ,{a9<:  //'q~pl|bGQiA^x:z* e5AQn AXh-# \\Mm4cOcnNYb@$7Eaq CbiX0)8j.2)eX-/p!^O |[$R6P!!`<=j |t MCf C+C %) !:fWNWeQm]`]/pw ,g'*shd[n_$OywL-} Jc~kNpnCGqlyP.:{t\&p9<Yk83&&LBkM<>k\E2s3|DSdS7lgW7\eZs, >..I,16o~sCSzvy=V1$k@uAfuo}RBz}g760 Sttlsl .LPP3Zw)QrvcE&|4Xh4"D^m'`i]J(2I?s@E NuC{~\7 F?{ 8 Hy0:'P"'+$HDH5G[`i~;4##lzsqmvDiZQD5<;,qtdd=!/ >x_,MX^b -#) qX;\h >H@ ]E-:?,$9zH'?44:[oC'AxA!E:.]vCgd<7!X{twn -8Y@Tr++807QQriWT+OO?.fL\R\HZiniccxnP0HK8(T0e VVA/QVi,I67aN1"<\bu{9I`[xvq| PW[o`N+C'1:;HjLn} ^iP8gOO0#`*,;8:lgTaII9sHqkZJDeFlwb1H>hC&uC0B= R5='K%j*?Gl$DzO8lLJe1dJ"-86Hwcq:5(#9|*   4 FQU,C)5p?Q xO zYRT^\_GY++<"?:}77F+~sl$DL``:4Ob! *4 /5sJur}F9pCJL:=RKrRu# BxahqmC9 c&L+\=b- nshg~ps5 PV60G[}!YcpydUj['-iSFadqm^c/{k)* wyd!2:c]|'Vc+EN5ux(C JA\7LVC3"-_Lrwfsx%E[TYSF%{!coA cu)fU)"zC> =Ny4Jy.3?IUwX&Ygz 1HX$).''QC'b{}Ui|d@? jV-ytxp^a63[[_yQR=(H/s  lath(Kk+5AEb])=vsPWK 1!,ztmaeWid=w05gQ`[=4F80$mpPE\}%qnv{aSK9?`=" !I2Jx_Zvgb\#u6lt8|~4=$3(0_\73/zL"<nogC6n"e#|| {R oFro\dC^j*J{b]ng;n% & Epnpxk}haZa`/bDx (7sIQ4mvw^_Ojk&T,$>dN=hv A2 +P 'OW:Qvccd5;7a *v_Ze-(h]-x-  % !TV/w*7H3(f``s^j~;W)P_vik\@_d E-im$>jmF.D69eJwtSmweqT (gkKM8u~` {~NW#g>f[ /7DY_! -))=V?MkqlSwacV ]-#usQQcN8Qs>2)!69=/Q 55i$(*ARFAeW^#{[S;2.  rBVD$/ :6icxzz47cTg,-JTE/-QJ'N3 /Fjp+(5=FT\JdoMhF,([`RtH='.l[?1 |S~a| ?B$YhP '0 9$ T>5)#1(@pYW|. )GIHCeshtx  zqvH-tcE<%oQ=*ZQ{gLyb~[~yww 7=(3+5__p#&!. AJENv/C +(-GE?RRlx XW0o@4 f/;|-,E_E]ozd&  5+)1 0);9LUOqv %D`9-DQosVrviOZ@ a`^#}ns^ 8D6-Pqn($-;a~y &//73BJ$<3-$8cDc(.<;[`]JQ}ldzx}MB$sijsY.;%x@&(!.  3#%MHBA|^*1B'>B?I*BP70AKMCm >#(D>XNcgmwoI-.t^ssASHH9,~D<%#,%1K[H^v~x8!!9CCSM%-GE!2@)PEFagq!#"1=49Qzclw|VPB<<k_lnIG3rY^H2@/!"GF=Ked`vp(,7$  !2/$!)4_SZ} "$ 4/DFOehQLwbp4/*to^KTT/xeqc=>BE4?D'8-@iKTyjgbu Q;&H77;I$41@`Rbr '&%3O5ERo_]{ujssrp^B#  {O_uK62>#p}hcCYUXhihmyk -0N=X[SN9nS>hK>b`]RXvi  *5.K_Ucrket~lkW)!bis@/K3v\euzwjz "%%:83@M@FsN%0/5MPfgWii_}~ *(%HX^Yx|okkk|V8NN-_KWY73"{{{d 01HMGPaG@05=GTFI\wWTsy  $+3U^SVHr|}t]L77#_MVJJ>,%opp~ 53-$"%0;1N= ?V61VHHDUycslt ")*5<B?[iXl~`OL8&& ]b]O@"u% <).C4HI@:KkD:ERKNbf][mifwwTYCD`a[q{ysWV_I31$ {kcJMC. &;0,GH=PH@GEQPL==SG=CTaP_Psy &6F>UvjlhmvFMTE3&(Q\9%4  +9!1F>9IN95L`E@NCFMGP\_atz +$71QgjgWkmiysm{bGU4&;4% wdYQB,'."-928=B5LYJLRF?WRFOJF;DQOZ]qpw{ >=GMK`zu{xvmc[_6- rRL?6 99%)>A2DQLpubXkgKO_^LXSNXZih\WW{{a|~u /:C6GYlaodf~\gmfee\E7FNiqkD@5&9;11"){OXO5F6"$  '-,<@*-KLLJ`\Rkyoyvpv}jVsqbtugklY\{~f{)386FSnor~~k~txprtjQQIIHCF'&$  zv[`a]\I]R?QURPCKe[]dOboRPbogh{  ?1&3HR<Qg`urlgtz\G;I[,2H-)" wemhcj]Wccioeliaaideiml^glwtr 116CBI`_]vopsioykblaJQW:.76!zpz_`^PcWQ]VAKTWWTHNKRNU]LTHb[dt`kfi}|~|~z !2(=GHKeo]adhh`JK\^PU@1/-1  ywwvy}}ykxwlye *AEGZermr{{ywm]XcUDG;H2$2,/-, -74GOXo\Ws}snhXQQOFC58=0-"0<7+   +A;LNO_nimnr}hyvtz]bn`YRLCB9KG2<A/3<<*!.  !('0;ORUc_FXbebXibboaJNA;9'1#  |uvquzqtxxsxz~ #3)@% (&)qr}uvolrthdh]]jeetnr|ov~yw{y$/%+2$+11,<' }zxxoobfxklocoov|{w|xv~})40'/65?<@C655#  } '4-/ABHLHB?Q;)4)%,/#   !)/,@E<PSQZ^SUI:9:6,-+*!#*&)!"&  .4-5>JCGNNXVPFFLE>AB37>,5*$0*),&,)   +0)4?=LOOSQ]PMTCKK@H@=:732448;9/%%0*""  !(25:<;FMPWSVRUTORQFCOCBL;>9697=><:4,,,'2$      *3.3;CKRRJMRSPLNLGHL=AK=>H?@@=@=972)30 +"      !!(39<LRIJLORSIFLKMIFKLHNE@JBFI>?8>7191,1*,'   $.//<BIIJMKMMHJMGLPKIGFIJI?AD?EC?9933950--&#    %&,04=<>CCCA>?<BA;<@=A=;C<;46;56730',-&,( %      #,%.4.1:946:95@?><29>5:??>666274,,.(')!&!   #(++,(0).1).,..0)36/002.)-+-+)(#$# &"   !%(##))$(+++/1*.4/+-/--0&%1*#'&"" "     "# $ "" " %&$&!! "          !!!"%&$$'$&)'&$')%%""&##%!" $%# !           pd-fftease-3.0.1/swinger~.c000066400000000000000000000205231401707710000155500ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *swinger_class; #define OBJECT_NAME "swinger~" typedef struct _swinger { t_object x_obj; float x_f; t_fftease *fft; t_fftease *fft2; short mute; } t_swinger; static void swinger_dsp(t_swinger *x, t_signal **sp); static t_int *swinger_perform(t_int *w); static void *swinger_new(t_symbol *s, int argc, t_atom *argv); static void swinger_mute(t_swinger *x, t_floatarg state); static void swinger_init(t_swinger *x); static void swinger_free(t_swinger *x); void swinger_tilde_setup(void) { t_class *c; c = class_new(gensym("swinger~"), (t_newmethod)swinger_new, (t_method)swinger_free,sizeof(t_swinger), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_swinger, x_f); class_addmethod(c,(t_method)swinger_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)swinger_mute,gensym("mute"),A_FLOAT,0); swinger_class = c; fftease_announce(OBJECT_NAME); } void swinger_mute(t_swinger *x, t_floatarg state) { x->mute = state; } void *swinger_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft, *fft2; 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")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); x->fft2 = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft2 = x->fft2; fft->initialized = 0; fft2->initialized = 0; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; fft2->N = FFTEASE_DEFAULT_FFTSIZE; fft2->overlap = FFTEASE_DEFAULT_OVERLAP; fft2->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = fft2->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = fft2->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void swinger_init(t_swinger *x) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; if(!fft->initialized){ x->mute = 0; } fftease_init(fft); fftease_init(fft2); } static void do_swinger(t_swinger *x) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int i, R, N, N2, D, Nw, even, odd; t_float a1, b1, a2, b2, *bufferOne, *bufferTwo, *channelOne, *channelTwo; bufferOne = fft->buffer; bufferTwo = fft2->buffer; R = fft->R; N = fft->N; N2 = fft->N2; D = fft->D; Nw = fft->Nw; channelOne = fft->channel; channelTwo = fft2->channel; /* apply hamming window and fold our window buffer into the fft buffer */ fftease_fold(fft); fftease_fold(fft2); /* do an fft */ fftease_rdft(fft,FFT_FORWARD); fftease_rdft(fft2,FFT_FORWARD); /* 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 */ fftease_rdft(fft,FFT_INVERSE); /* dewindow our result */ fftease_overlapadd(fft); /* set our output and adjust our retaining output buffer */ } t_int *swinger_perform(t_int *w) { int i,j; t_swinger *x = (t_swinger *) (w[1]); t_float *MSPInputVector1 = (t_float *)(w[2]); t_float *MSPInputVector2 = (t_float *)(w[3]); t_float *MSPOutputVector = (t_float *)(w[4]); t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int MSPVectorSize = fft->MSPVectorSize; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; t_float *internalInputVector1 = fft->internalInputVector; t_float *internalInputVector2 = fft2->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; t_float *inputOne = fft->input; t_float *inputTwo = fft2->input; t_float *output = fft->output; int D = fft->D; int Nw = fft->Nw; t_float mult = fft->mult; /* no computation if muted */ if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+5; } if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), MSPInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), MSPInputVector2, D * sizeof(t_float)); do_swinger(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw-D), MSPInputVector1 + (D*i), D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw-D), MSPInputVector2 + (D*i), D * sizeof(t_float)); do_swinger(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector1 + (operationCount * MSPVectorSize), MSPInputVector1, MSPVectorSize * sizeof(t_float)); memcpy(internalInputVector2 + (operationCount * MSPVectorSize), MSPInputVector2, MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize), MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), internalInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), internalInputVector2, D * sizeof(t_float)); do_swinger(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+5; } void swinger_free( t_swinger *x ) { fftease_free(x->fft); fftease_free(x->fft2); free(x->fft); free(x->fft2); } void swinger_dsp(t_swinger *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(!samplerate) return; if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); fft2->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft2); } if(fft->R != samplerate ){ fft->R = samplerate; fft2->R = samplerate; } if(reset_required){ swinger_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(swinger_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); } } pd-fftease-3.0.1/taint~.c000066400000000000000000000262761401707710000152240ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *taint_class; #define OBJECT_NAME "taint~" typedef struct _taint { t_object x_obj; float x_f; t_fftease *fft; t_fftease *fft2; t_float mult; short mute; int invert; int invert_countdown; // delay onset of invert effect to avoid loud glitches int invert_nextstate; // next state for invert t_float invert_pad; t_float threshold; t_float exponent; } t_taint; /* msp function prototypes */ static void taint_dsp(t_taint *x, t_signal **sp); static t_int *taint_perform(t_int *w); static void *taint_new(t_symbol *s, int argc, t_atom *argv); static void taint_invert(t_taint *x, t_floatarg toggle); static void taint_free(t_taint *x); static void taint_mute(t_taint *x, t_floatarg toggle); static void taint_init(t_taint *x); static void taint_pad(t_taint *x, t_floatarg pad); void taint_tilde_setup(void) { t_class *c; c = class_new(gensym("taint~"), (t_newmethod)taint_new, (t_method)taint_free,sizeof(t_taint), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_taint, x_f); class_addmethod(c,(t_method)taint_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)taint_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)taint_invert,gensym("invert"), A_FLOAT, 0); class_addmethod(c,(t_method)taint_pad,gensym("pad"), A_FLOAT, 0); taint_class = c; fftease_announce(OBJECT_NAME); } void taint_mute(t_taint *x, t_floatarg toggle) { x->mute = (short)toggle; } void taint_free(t_taint *x) { fftease_free(x->fft); fftease_free(x->fft2); free(x->fft); free(x->fft2); } 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) { t_fftease *fft = x->fft; x->invert_nextstate = toggle; x->invert_countdown = fft->overlap; // delay effect for "overlap" vectors if(x->invert_nextstate){ // lower gain immediately; delay going to invert x->fft->mult = (1. / (t_float) x->fft->N) * x->invert_pad; } else { x->invert = 0; //immediately turn off invert; delay raising gain } } void *taint_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft, *fft2; t_taint *x = (t_taint *)pd_new(taint_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")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); x->fft2 = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft2 = x->fft2; fft->initialized = 0; fft2->initialized = 0; x->exponent = 0.25; x->threshold = 0.01; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; fft2->N = FFTEASE_DEFAULT_FFTSIZE; fft2->overlap = FFTEASE_DEFAULT_OVERLAP; fft2->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = fft2->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = fft2->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void taint_init(t_taint *x) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; short initialized = fft->initialized; fftease_init(fft); fftease_init(fft2); if(!initialized){ x->invert_pad = 0.025; // -32 dB x->invert_countdown = 0; x->mute = 0; x->invert = 0; } if(x->invert){ x->mult *= x->invert_pad; } } static void do_taint(t_taint *x) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int i; int odd,even; t_float a1,b1,a2,b2; t_float *bufferOne = fft->buffer; t_float *bufferTwo = fft2->buffer; int N2 = fft->N2; t_float *channelOne = fft->channel; t_float *channelTwo = fft2->channel; t_float threshold = x->threshold; t_float exponent = x->exponent; int invert = x->invert; /* apply hamming window and fold our window buffer into the fft buffer */ fftease_fold(fft); fftease_fold(fft2); /* do an fft */ fftease_rdft(fft,FFT_FORWARD); fftease_rdft(fft2,FFT_FORWARD); /* convert to polar coordinates from complex values */ if (invert) { for ( i = 0; i <= N2; i++ ) { t_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) ); } fftease_rdft(fft,FFT_INVERSE); fftease_overlapadd(fft); } t_int *taint_perform(t_int *w) { int i,j; /* get our inlets and outlets */ t_taint *x = (t_taint *) (w[1]); t_float *MSPInputVector1 = (t_float *)(w[2]); t_float *MSPInputVector2 = (t_float *)(w[3]); t_float *vec_exponent = (t_float *)(w[4]); t_float *vec_threshold = (t_float *)(w[5]); t_float *MSPOutputVector = (t_float *)(w[6]);; t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int MSPVectorSize = fft->MSPVectorSize; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; t_float *internalInputVector1 = fft->internalInputVector; t_float *internalInputVector2 = fft2->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; t_float *inputOne = fft->input; t_float *inputTwo = fft2->input; t_float *output = fft->output; int D = fft->D; int Nw = fft->Nw; t_float mult = fft->mult; //short *connected = x->connected; /* dereference structure */ x->exponent = *vec_exponent; x->threshold = *vec_threshold; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+7; } if(x->invert_countdown > 0){ --(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 mult = x->fft->mult = 1. / (t_float) x->fft->N; } } } // if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), MSPInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), MSPInputVector2, D * sizeof(t_float)); do_taint(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw-D), MSPInputVector1 + (D*i), D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw-D), MSPInputVector2 + (D*i), D * sizeof(t_float)); do_taint(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector1 + (operationCount * MSPVectorSize), MSPInputVector1, MSPVectorSize * sizeof(t_float)); memcpy(internalInputVector2 + (operationCount * MSPVectorSize), MSPInputVector2, MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize), MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), internalInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), internalInputVector2, D * sizeof(t_float)); do_taint(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+7; } void taint_dsp(t_taint *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(!samplerate) return; if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); fft2->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft2); } if(fft->R != samplerate ){ fft->R = samplerate; fft2->R = samplerate; } if(reset_required){ taint_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(taint_perform, 6, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,sp[3]->s_vec, sp[4]->s_vec); } } pd-fftease-3.0.1/thresher~.c000066400000000000000000000212201401707710000157110ustar00rootroot00000000000000/* Pd FFTease 3.0 */ #include "fftease.h" static t_class *thresher_class; #define OBJECT_NAME "thresher~" #define DEFAULT_HOLD (40.0) typedef struct _thresher { t_object x_obj; t_float x_f; t_fftease *fft; t_float move_threshold; t_float *composite_frame; int *frames_left; int max_hold_frames; t_float max_hold_time; int first_frame; t_float damping_factor; short thresh_connected; short damping_connected; short mute; t_float tadv; } t_thresher; static void thresher_dsp(t_thresher *x, t_signal **sp); static t_int *thresher_perform(t_int *w); static void *thresher_new(t_symbol *s, int argc, t_atom *argv); static void thresher_mute(t_thresher *x, t_floatarg f); static void thresher_free( t_thresher *x ); static void thresher_init(t_thresher *x); static void thresher_transpose(t_thresher *x, t_floatarg tf); static void thresher_synthresh(t_thresher *x, t_floatarg thresh); static void thresher_oscbank(t_thresher *x, t_floatarg flag); static void thresher_fftinfo(t_thresher *x); void thresher_tilde_setup(void) { t_class *c; c = class_new(gensym("thresher~"), (t_newmethod)thresher_new, (t_method)thresher_free,sizeof(t_thresher), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_thresher, x_f); class_addmethod(c,(t_method)thresher_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)thresher_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)thresher_oscbank,gensym("oscbank"),A_FLOAT,0); class_addmethod(c,(t_method)thresher_transpose,gensym("transpose"),A_FLOAT,0); class_addmethod(c,(t_method)thresher_synthresh,gensym("synthresh"),A_FLOAT,0); class_addmethod(c,(t_method)thresher_fftinfo,gensym("fftinfo"),0); thresher_class = c; fftease_announce(OBJECT_NAME); } void thresher_transpose(t_thresher *x, t_floatarg tf) { x->fft->P = tf; } void thresher_synthresh(t_thresher *x, t_floatarg thresh) { x->fft->synt = thresh; } void thresher_oscbank(t_thresher *x, t_floatarg flag) { x->fft->obank_flag = (short) flag; } void thresher_free(t_thresher *x){ if(x->fft->initialized){ free(x->composite_frame); } fftease_free(x->fft); free(x->fft); } void thresher_mute(t_thresher *x, t_floatarg f){ x->mute = (short)f; } void *thresher_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft; 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")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease) ); fft = x->fft; fft->initialized = 0; x->move_threshold = 0.001; x->damping_factor = 0.99; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void thresher_init(t_thresher *x) { t_fftease *fft = x->fft; short initialized = fft->initialized; fftease_init(fft); x->tadv = (t_float) fft->D / (t_float) fft->R ; if(!initialized){ x->mute = 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->composite_frame = (t_float *) calloc( (fft->N+2), sizeof(t_float)); x->frames_left = (int *) calloc( (fft->N+2), sizeof(int) ); } else if(initialized == 1){ x->composite_frame = (t_float *) realloc(x->composite_frame, (fft->N+2) * sizeof(t_float) ); x->frames_left = (int *) realloc(x->frames_left, (fft->N+2) * sizeof(int) ); } } void thresher_fftinfo( t_thresher *x ) { fftease_fftinfo(x->fft, OBJECT_NAME); } static void do_thresher(t_thresher *x) { int i; t_fftease *fft = x->fft; t_float *channel = fft->channel; t_float damping_factor = x->damping_factor; int max_hold_frames = x->max_hold_frames; int *frames_left = x->frames_left; t_float *composite_frame = x->composite_frame; int N = fft->N; t_float move_threshold = x->move_threshold; fftease_fold(fft); fftease_rdft(fft,FFT_FORWARD); fftease_convert(fft); 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; } } } // try memcpy here for ( i = 0; i < N+2; i++ ){ channel[i] = composite_frame[i]; } if(fft->obank_flag){ fftease_oscbank(fft); } else { fftease_unconvert(fft); fftease_rdft(fft,FFT_INVERSE); fftease_overlapadd(fft); } } t_int *thresher_perform(t_int *w) { int i,j; t_thresher *x = (t_thresher *) (w[1]); t_float *MSPInputVector = (t_float *)(w[2]); t_float *inthresh = (t_float *)(w[3]); t_float *damping = (t_float *)(w[4]); t_float *MSPOutputVector = (t_float *)(w[5]); t_fftease *fft = x->fft; int D = fft->D; int Nw = fft->Nw; t_float *input = fft->input; t_float *output = fft->output; t_float mult = fft->mult; int MSPVectorSize = fft->MSPVectorSize; t_float *internalInputVector = fft->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+6; } x->move_threshold = *inthresh; x->damping_factor = *damping; if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), MSPInputVector, D * sizeof(t_float)); do_thresher(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw-D), MSPInputVector + (D*i), D * sizeof(t_float)); do_thresher(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector + (operationCount * MSPVectorSize), MSPInputVector,MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize),MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(input, input + D, (Nw - D) * sizeof(t_float)); memcpy(input + (Nw - D), internalInputVector, D * sizeof(t_float)); do_thresher(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+6; } void thresher_dsp(t_thresher *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; if(!samplerate) return; t_fftease *fft = x->fft; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); } if(fft->R != samplerate){ fft->R = samplerate; } if(reset_required){ thresher_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(thresher_perform, 5, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); } } pd-fftease-3.0.1/unconvert.c000066400000000000000000000016601401707710000157200ustar00rootroot00000000000000#include "fftease.h" //void fftease_unconvert( t_float *C, t_float *S, int N2, t_float *lastphase, t_float fundamental, t_float factor ) // fftease_unconvert( channel, buffer, N2, c_lastphase_out, c_fundamental, c_factor_out ); void fftease_unconvert(t_fftease *fft) { t_float *channel = fft->channel; t_float *buffer = fft->buffer; int N2 = fft->N2; t_float *lastphase = fft->c_lastphase_out; t_float fundamental = fft->c_fundamental; t_float factor = fft->c_factor_out; int i, real, imag, amp, freq; t_float mag, phase; for ( i = 0; i <= N2; i++ ) { imag = freq = ( real = amp = i<<1 ) + 1; if ( i == N2 ) real = 1; mag = channel[amp]; lastphase[i] += channel[freq] - i*fundamental; phase = lastphase[i]*factor; buffer[real] = mag*cos( phase ); if ( i != N2 ) buffer[imag] = -mag*sin( phase ); } } pd-fftease-3.0.1/vacancy~.c000066400000000000000000000245171401707710000155250ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *vacancy_class; #define OBJECT_NAME "vacancy~" typedef struct _vacancy { t_object x_obj; t_float x_f; t_fftease *fft; t_fftease *fft2; int invert; int useRms; int swapPhase; short mute; t_float threshold; } t_vacancy; /* msp function prototypes */ static void vacancy_dsp(t_vacancy *x, t_signal **sp); static t_int *vacancy_perform(t_int *w); static void *vacancy_new(t_symbol *s, int argc, t_atom *argv); static void vacancy_rms(t_vacancy *x, t_floatarg f); static void vacancy_invert(t_vacancy *x, t_floatarg f); static void vacancy_swapphase(t_vacancy *x, t_floatarg f); static void vacancy_free(t_vacancy *x); static void vacancy_mute(t_vacancy *x, t_floatarg toggle); static void vacancy_init(t_vacancy *x); void vacancy_tilde_setup(void) { t_class *c; c = class_new(gensym("vacancy~"), (t_newmethod)vacancy_new, (t_method)vacancy_free,sizeof(t_vacancy), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_vacancy, x_f); class_addmethod(c,(t_method)vacancy_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)vacancy_mute,gensym("mute"),A_FLOAT,0); class_addmethod(c,(t_method)vacancy_rms,gensym("rms"), A_FLOAT, 0); class_addmethod(c,(t_method)vacancy_invert,gensym("invert"), A_FLOAT, 0); class_addmethod(c,(t_method)vacancy_swapphase,gensym("swapphase"), A_FLOAT, 0); vacancy_class = c; fftease_announce(OBJECT_NAME); } 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_mute(t_vacancy *x, t_floatarg toggle) { x->mute = (short)toggle; } void *vacancy_new(t_symbol *s, int argc, t_atom *argv) { t_fftease *fft, *fft2; 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")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); x->fft2 = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft2 = x->fft2; fft->initialized = 0; fft2->initialized = 0; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; fft2->N = FFTEASE_DEFAULT_FFTSIZE; fft2->overlap = FFTEASE_DEFAULT_OVERLAP; fft2->winfac = FFTEASE_DEFAULT_WINFAC; return x; } void vacancy_init(t_vacancy *x) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; short initialized = x->fft->initialized; fftease_init(fft); fftease_init(fft2); if(!initialized){ x->mute = 0; x->invert = 0; x->threshold = 0.01; x->useRms = 1; x->swapPhase = 0; } } void vacancy_free(t_vacancy *x) { fftease_free(x->fft); fftease_free(x->fft2); free(x->fft); free(x->fft2); } static void do_vacancy(t_vacancy *x) { t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int i, even, odd; float useme, rms = 0., a1, b1, a2, b2; /* dereference structure */ t_float *bufferOne = fft->buffer; t_float *bufferTwo = fft2->buffer; int N2 = fft->N2; int Nw = fft->Nw; t_float *channelOne = fft->channel; t_float *channelTwo = fft2->channel; t_float *inputOne = fft->input; int invert = x->invert; int useRms = x->useRms; int swapPhase = x->swapPhase; if (useRms) { rms = 0.; for ( i=0; i < Nw; i++ ) rms += *(inputOne+i) * *(inputOne+i); rms = sqrt( rms / Nw ); useme = rms * x->threshold; } else useme = x->threshold; fftease_fold(fft); fftease_fold(fft2); fftease_rdft(fft,FFT_FORWARD); fftease_rdft(fft2,FFT_FORWARD); 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 ); } 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); } } } } 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) ); } fftease_rdft(fft,FFT_INVERSE); fftease_overlapadd(fft); } t_int *vacancy_perform(t_int *w) { int i,j; /* get our inlets and outlets */ t_vacancy *x = (t_vacancy *) (w[1]); t_float *MSPInputVector1 = (t_float *)(w[2]); t_float *MSPInputVector2 = (t_float *)(w[3]); t_float *vec_threshold = (t_float *)(w[4]); t_float *MSPOutputVector = (t_float *)(w[5]); t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int MSPVectorSize = fft->MSPVectorSize; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; t_float *internalInputVector1 = fft->internalInputVector; t_float *internalInputVector2 = fft2->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; t_float *inputOne = fft->input; t_float *inputTwo = fft2->input; t_float *output = fft->output; int D = fft->D; int Nw = fft->Nw; t_float mult = fft->mult; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+6; } x->threshold = *vec_threshold; if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), MSPInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), MSPInputVector2, D * sizeof(t_float)); do_vacancy(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw-D), MSPInputVector1 + (D*i), D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw-D), MSPInputVector2 + (D*i), D * sizeof(t_float)); do_vacancy(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector1 + (operationCount * MSPVectorSize), MSPInputVector1, MSPVectorSize * sizeof(t_float)); memcpy(internalInputVector2 + (operationCount * MSPVectorSize), MSPInputVector2, MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize), MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), internalInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), internalInputVector2, D * sizeof(t_float)); do_vacancy(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+6; } void vacancy_dsp(t_vacancy *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(!samplerate) return; if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); fft2->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft2); } if(fft->R != samplerate ){ fft->R = samplerate; fft2->R = samplerate; } if(reset_required){ vacancy_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(vacancy_perform, 5, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,sp[3]->s_vec); } } pd-fftease-3.0.1/xsyn~.c000066400000000000000000000155771401707710000151100ustar00rootroot00000000000000/* FFTease for Pd */ #include "fftease.h" static t_class *xsyn_class; #define OBJECT_NAME "xsyn~" typedef struct _xsyn { t_object x_obj; t_float x_f; t_fftease *fft; t_fftease *fft2; short mute; } t_xsyn; static void xsyn_dsp(t_xsyn *x, t_signal **sp); static t_int *xsyn_perform(t_int *w); static void *xsyn_new(t_symbol *s, int argc, t_atom *argv); static void xsyn_free( t_xsyn *x ); static void xsyn_init(t_xsyn *x); static void xsyn_mute(t_xsyn *x, t_floatarg toggle); void xsyn_tilde_setup(void) { t_class *c; c = class_new(gensym("xsyn~"), (t_newmethod)xsyn_new, (t_method)xsyn_free,sizeof(t_xsyn), 0,A_GIMME,0); CLASS_MAINSIGNALIN(c, t_xsyn, x_f); class_addmethod(c,(t_method)xsyn_dsp,gensym("dsp"), A_CANT, 0); class_addmethod(c,(t_method)xsyn_mute,gensym("mute"),A_FLOAT,0); xsyn_class = c; fftease_announce(OBJECT_NAME); } void xsyn_free( t_xsyn *x ) { fftease_free(x->fft); free(x->fft); fftease_free(x->fft2); free(x->fft2); } void xsyn_mute(t_xsyn *x, t_floatarg toggle) { x->mute = (short)toggle; } void *xsyn_new(t_symbol *s, int argc, t_atom *argv) { t_xsyn *x = (t_xsyn *)pd_new(xsyn_class); t_fftease *fft, *fft2; inlet_new(&x->x_obj, &x->x_obj.ob_pd,gensym("signal"), gensym("signal")); outlet_new(&x->x_obj, gensym("signal")); x->fft = (t_fftease *) calloc(1,sizeof(t_fftease)); x->fft2 = (t_fftease *) calloc(1,sizeof(t_fftease)); fft = x->fft; fft2 = x->fft2; fft->initialized = 0; fft2->initialized = 0; fft->N = FFTEASE_DEFAULT_FFTSIZE; fft->overlap = FFTEASE_DEFAULT_OVERLAP; fft->winfac = FFTEASE_DEFAULT_WINFAC; fft2->N = FFTEASE_DEFAULT_FFTSIZE; fft2->overlap = FFTEASE_DEFAULT_OVERLAP; fft2->winfac = FFTEASE_DEFAULT_WINFAC; x->mute = 0; if(argc > 0){ fft->N = (int) atom_getfloatarg(0, argc, argv); } if(argc > 1){ fft->overlap = (int) atom_getfloatarg(1, argc, argv); } return x; } void xsyn_init(t_xsyn *x) { fftease_init(x->fft); fftease_init(x->fft2); } static void do_xsyn(t_xsyn *x) { int i; t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; t_float *channel1 = fft->channel; t_float *channel2 = fft2->channel; int N = fft->N; t_float maxamp; fftease_fold(fft); fftease_fold(fft2); fftease_rdft(fft,FFT_FORWARD); fftease_rdft(fft2,FFT_FORWARD); fftease_leanconvert(fft); fftease_leanconvert(fft2); maxamp = 0; for( i = 0; i < N; i+= 2 ) { if( channel2[i] > maxamp ) { maxamp = channel2[i]; } } if( maxamp > 0.000001 ){ for( i = 0; i < N; i+= 2 ) { channel1[i] *= (channel2[i] / maxamp ); } } fftease_leanunconvert(fft); fftease_rdft(fft,FFT_INVERSE); fftease_overlapadd(fft); } t_int *xsyn_perform(t_int *w) { int i,j; t_xsyn *x = (t_xsyn *) (w[1]); t_float *MSPInputVector1 = (t_float *)(w[2]); t_float *MSPInputVector2 = (t_float *)(w[3]); t_float *MSPOutputVector = (t_float *)(w[4]); t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; int MSPVectorSize = fft->MSPVectorSize; int operationRepeat = fft->operationRepeat; int operationCount = fft->operationCount; t_float *internalInputVector1 = fft->internalInputVector; t_float *internalInputVector2 = fft2->internalInputVector; t_float *internalOutputVector = fft->internalOutputVector; t_float *inputOne = fft->input; t_float *inputTwo = fft2->input; t_float *output = fft->output; int D = fft->D; int Nw = fft->Nw; t_float mult = fft->mult; if(x->mute){ for(i=0; i < MSPVectorSize; i++){ MSPOutputVector[i] = 0.0; } return w+5; } if( fft->bufferStatus == EQUAL_TO_MSP_VECTOR ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), MSPInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), MSPInputVector2, D * sizeof(t_float)); do_xsyn(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } else if( fft->bufferStatus == SMALLER_THAN_MSP_VECTOR ) { for( i = 0; i < operationRepeat; i++ ){ memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw-D), MSPInputVector1 + (D*i), D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw-D), MSPInputVector2 + (D*i), D * sizeof(t_float)); do_xsyn(x); for ( j = 0; j < D; j++ ){ *MSPOutputVector++ = output[j] * mult; } memcpy(output, output + D, (Nw-D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } } else if( fft->bufferStatus == BIGGER_THAN_MSP_VECTOR ) { memcpy(internalInputVector1 + (operationCount * MSPVectorSize), MSPInputVector1, MSPVectorSize * sizeof(t_float)); memcpy(internalInputVector2 + (operationCount * MSPVectorSize), MSPInputVector2, MSPVectorSize * sizeof(t_float)); memcpy(MSPOutputVector, internalOutputVector + (operationCount * MSPVectorSize), MSPVectorSize * sizeof(t_float)); operationCount = (operationCount + 1) % operationRepeat; if( operationCount == 0 ) { memcpy(inputOne, inputOne + D, (Nw - D) * sizeof(t_float)); memcpy(inputOne + (Nw - D), internalInputVector1, D * sizeof(t_float)); memcpy(inputTwo, inputTwo + D, (Nw - D) * sizeof(t_float)); memcpy(inputTwo + (Nw - D), internalInputVector2, D * sizeof(t_float)); do_xsyn(x); for ( j = 0; j < D; j++ ){ internalOutputVector[j] = output[j] * mult; } memcpy(output, output + D, (Nw - D) * sizeof(t_float)); for(j = (Nw-D); j < Nw; j++){ output[j] = 0.0; } } fft->operationCount = operationCount; } return w+5; } void xsyn_dsp(t_xsyn *x, t_signal **sp) { int reset_required = 0; int maxvectorsize = sp[0]->s_n; int samplerate = sp[0]->s_sr; t_fftease *fft = x->fft; t_fftease *fft2 = x->fft2; if(fft->R != samplerate || fft->MSPVectorSize != maxvectorsize || fft->initialized == 0){ reset_required = 1; } if(!samplerate) return; if(fft->MSPVectorSize != maxvectorsize){ fft->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft); fft2->MSPVectorSize = maxvectorsize; fftease_set_fft_buffers(fft2); } if(fft->R != samplerate ){ fft->R = samplerate; fft2->R = samplerate; } if(reset_required){ xsyn_init(x); } if(fftease_msp_sanity_check(fft,OBJECT_NAME)) { dsp_add(xsyn_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); } }