#import "MSPd.h"
#include "bashfest.h"
#include <string.h>

/* THIS IS PROBABLY THE LIMITING FACTOR FOR LARGE BUFFER SIZES
SO, MAKE THIS A PARAMETER, -OR- BUFFER THE INPUT TRIGGER ITSELF!!!
*/
#define DEFAULT_MAX_OVERLAP (8) // number of overlapping instances allowed
#define ACTIVE 0
#define INACTIVE 1
#define MAX_VEC 2048
#define DEFAULT_BUFFER_SIZE 4000.0 // 4 second default buffer size * 2
#define DEFAULT_LATENCY 8192 //latency in samples after a trigger for note to start
#define MAX_PARAMETERS 2048
#define PROCESS_COUNT 20
#define CYCLE_MAX 1024

#define OBJECT_NAME "bashfest~"

#if __MSP__
void *bashfest_class;
#endif
#if __PD__
static t_class *bashfest_class;
#endif




void *bashfest_new(t_symbol *msg, short argc, t_atom *argv);
t_int *bashfest_perform_hosed(t_int *w);
void bashfest_dsp(t_bashfest *x, t_signal **sp, short *count);
void bashfest_assist (t_bashfest *x, void *b, long msg, long arg, char *dst);
void bashfest_dsp_free(t_bashfest *x);
int bashfest_set_parameters(t_bashfest *x,float *params);
t_int *bashfest_perform(t_int *w);
void bashfest_deploy_dsp(t_bashfest *x);
void bashfest_copy_to_MSP_buffer(t_bashfest *x, int slot);
/*user messages*/
void bashfest_stop(t_bashfest *x);
void bashfest_info(t_bashfest *x);
void bashfest_dblclick(t_bashfest *x);
void bashfest_mute(t_bashfest *x, t_floatarg t);
void bashfest_maximum_process(t_bashfest *x, t_floatarg n);
void bashfest_minimum_process(t_bashfest *x, t_floatarg n);
void bashfest_setbuf(t_bashfest *x, t_symbol *wavename);
void bashfest_flatodds(t_bashfest *x);
void bashfest_killproc(t_bashfest *x, long p);
void bashfest_soloproc(t_bashfest *x, long p);
void bashfest_latency(t_bashfest *x, long n);
void bashfest_verbose(t_bashfest *x, long t);
void bashfest_block_dsp(t_bashfest *x, t_floatarg t);
void bashfest_gozero(t_bashfest *x);
void bashfest_grab(t_bashfest *x);
void bashfest_setodds(t_bashfest *x,t_symbol *msg, short argc, t_atom *argv);
void bashfest_tcycle(t_bashfest *x,t_symbol *msg, short argc, t_atom *argv);
/* function code */

void killdc( float *inbuf, int in_frames, int channels, t_bashfest *x);

void ringmod(t_bashfest *x, int slot, int *pcount);
void retrograde(t_bashfest *x, int slot, int *pcount);
void comber(t_bashfest *x, int slot, int *pcount);
void transpose(t_bashfest *x, int slot, int *pcount);
void flange(t_bashfest *x, int slot, int *pcount);
void butterme(t_bashfest *x, int slot, int *pcount);
void truncateme(t_bashfest *x, int slot, int *pcount);
void sweepreson(t_bashfest *x, int slot, int *pcount);
void slidecomb(t_bashfest *x, int slot, int *pcount);
void reverb1(t_bashfest *x, int slot, int *pcount);
void ellipseme(t_bashfest *x, int slot, int *pcount);
void feed1me(t_bashfest *x, int slot, int *pcount);
void flam1(t_bashfest *x, int slot, int *pcount);
void flam2(t_bashfest *x, int slot, int *pcount);
void expflam(t_bashfest *x, int slot, int *pcount);
void comb4(t_bashfest *x, int slot, int *pcount);
void ringfeed(t_bashfest *x, int slot, int *pcount);
void resonadsr(t_bashfest *x, int slot, int *pcount);
void stv(t_bashfest *x, int slot, int *pcount);
void compdist(t_bashfest *x, int slot, int *pcount);
	 
#if __PD__
void atom_arg_getfloat(float *c, long idx, long ac, t_atom *av);
void atom_arg_getsym(t_symbol **c, long idx, long ac, t_atom *av);
#endif

#if __MSP__
void main(void)
{
  setup((t_messlist **)&bashfest_class, (method)bashfest_new, (method)bashfest_dsp_free, 
    	(short)sizeof(t_bashfest), 0, A_GIMME, 0);
  addmess((method)bashfest_dsp,"dsp", A_CANT, 0);
  addmess((method)bashfest_assist,"assist", A_CANT, 0);
  addmess((method)bashfest_dblclick,"dblclick", A_CANT, 0);
  addmess((method)bashfest_setbuf,"setbuf", A_SYM, 0);
  addmess((method)bashfest_stop,"stop", 0);
  addmess((method)bashfest_flatodds,"flatodds", 0);
  addmess((method)bashfest_soloproc,"soloproc", A_FLOAT, 0);
  addmess((method)bashfest_killproc,"killproc", A_FLOAT, 0);
  addmess((method)bashfest_latency,"latency", A_FLOAT, 0);
  addmess((method)bashfest_mute,"mute", A_FLOAT, 0);
  addmess((method)bashfest_verbose,"verbose", A_LONG, 0);
  addmess((method)bashfest_setodds,"setodds", A_GIMME, 0);
  addmess((method)bashfest_tcycle,"tcycle", A_GIMME, 0);
  addmess((method)bashfest_gozero,"gozero", 0);
  addmess((method)bashfest_grab,"grab", 0);
  addmess((method)bashfest_maximum_process,"maximum_process", A_FLOAT, 0);
  addmess((method)bashfest_minimum_process,"minimum_process", A_FLOAT, 0);
  addmess((method)bashfest_block_dsp,"block_dsp", A_FLOAT, 0);
  post("%s %s",OBJECT_NAME, LYONPOTPOURRI_MSG);
  dsp_initclass();
}
#endif
#if __PD__

void bashfest_tilde_setup(void)
{
bashfest_class = class_new(gensym("bashfest~"),(t_newmethod)bashfest_new,(t_method)bashfest_dsp_free, sizeof(t_bashfest), 0, A_GIMME,0);
CLASS_MAINSIGNALIN(bashfest_class,t_bashfest, x_f );
class_addmethod(bashfest_class,(t_method)bashfest_dsp,gensym("dsp"),A_CANT,0);
class_addmethod(bashfest_class,(t_method)bashfest_assist,gensym("assist"),A_CANT,0);
class_addmethod(bashfest_class,(t_method)bashfest_dblclick,gensym("dblclick"),A_CANT,0);
class_addmethod(bashfest_class,(t_method)bashfest_setbuf,gensym("setbuf"),A_SYMBOL,0);
class_addmethod(bashfest_class,(t_method)bashfest_stop,gensym("stop"),0);
class_addmethod(bashfest_class,(t_method)bashfest_flatodds,gensym("flatodds"),0);
class_addmethod(bashfest_class,(t_method)bashfest_soloproc,gensym("soloproc"),A_FLOAT,0);
class_addmethod(bashfest_class,(t_method)bashfest_killproc,gensym("killproc"),A_FLOAT,0);
class_addmethod(bashfest_class,(t_method)bashfest_latency,gensym("latency"),A_FLOAT,0);
class_addmethod(bashfest_class,(t_method)bashfest_mute,gensym("mute"),A_FLOAT,0);
class_addmethod(bashfest_class,(t_method)bashfest_verbose,gensym("verbose"),A_FLOAT,0);
class_addmethod(bashfest_class,(t_method)bashfest_setodds,gensym("setodds"),A_GIMME,0);
class_addmethod(bashfest_class,(t_method)bashfest_tcycle,gensym("tcycle"),A_GIMME,0);
class_addmethod(bashfest_class,(t_method)bashfest_gozero,gensym("gozero"),0);
class_addmethod(bashfest_class,(t_method)bashfest_grab,gensym("grab"),0);
class_addmethod(bashfest_class,(t_method)bashfest_maximum_process,gensym("maximum_process"),A_FLOAT,0);
class_addmethod(bashfest_class,(t_method)bashfest_minimum_process,gensym("minimum_process"),A_FLOAT,0);
class_addmethod(bashfest_class,(t_method)bashfest_block_dsp,gensym("block_dsp"),A_FLOAT,0);
  post("%s %s",OBJECT_NAME, LYONPOTPOURRI_MSG);
//  dsp_initclass();
}

#endif

void bashfest_block_dsp(t_bashfest *x, t_floatarg t)
{

  x->block_dsp = (short)t;

}
void bashfest_maximum_process(t_bashfest *x, t_floatarg n)
{
  if(n < 0){
    error("illegal val to maximum_process");
    return;
  }
  x->max_process_per_note = (int)n;
}

void bashfest_minimum_process(t_bashfest *x, t_floatarg n)
{
  if(n < 0){
    error("illegal val to minimum_process");
    return;
  }
  x->min_process_per_note = (int)n;
}

void bashfest_verbose(t_bashfest *x, long t)
{
  x->verbose = t;
}
void bashfest_latency(t_bashfest *x, long n)
{
  if(n < x->vs){
    error("latency cannot be less than %d",x->vs);
    return;
  }
/*  if(n > x->latency_samples){
  	x->trigger_buffer = (float *) realloc(x->trigger_buffer, n * sizeof(float));
  }
	x->tb_inpt = 0;
  x->tb_outpt = x->latency_samples - x->vs;*/
  x->latency_samples = n;
}

void bashfest_stop(t_bashfest *x)
{
  int i;
	
  for(i = 0; i < x->overlap_max; i++){
    x->events[i].status = INACTIVE;
  }
}


void bashfest_mute(t_bashfest *x, t_floatarg t)
{
  x->mute = (short)t;
}


void bashfest_grab(t_bashfest *x)
{
  x->grab = 1;
}

void bashfest_tcycle(t_bashfest *x,t_symbol *msg, short argc, t_atom *argv)
{
  t_cycle tcycle = x->tcycle;
  int i;
  float data=1.0;
	
  if(argc < 1){
    error("no data for tcycle!");
    return;
  } else if(argc > CYCLE_MAX){
    error("%d is the maximum size tcycle",CYCLE_MAX);
    return;
  }
  x->tcycle.len = argc;
  x->tcycle.p = 0;
  for(i=0;i<argc;i++){
    atom_arg_getfloat(&data,i,argc,argv);
    if(data <= 0.0){
      error("bad data for tcycle:%f",data);
    } else {
      tcycle.data[i] = data;
    }
  }
}

void bashfest_gozero(t_bashfest *x)
{
  x->tcycle.p = 0;
}

void bashfest_setodds(t_bashfest *x,t_symbol *msg, short argc, t_atom *argv)
{
  int i;

  if(argc > PROCESS_COUNT){
    error("there are only %d processes",PROCESS_COUNT);
    return;
  }
  for(i=0;i<PROCESS_COUNT;i++){
    x->odds[i] = 0.0;
  }


  for(i=0;i<argc;i++){
    x->odds[i] = atom_getfloatarg(i,argc,argv);
  }

  setweights(x->odds,PROCESS_COUNT);
}

void bashfest_soloproc(t_bashfest *x, long p)
{
  int i;
  if(p < 0 || p >= PROCESS_COUNT){
    error("bad %d",p);
  }
  for(i=0;i<PROCESS_COUNT;i++){
    x->odds[i] = 0.0;
  }
  x->odds[p] = 1.0;
  setweights(x->odds,PROCESS_COUNT);
}

void bashfest_killproc(t_bashfest *x, long p)
{
  int i;
  if(p < 0 || p >= PROCESS_COUNT){
    error("bad %d",p);
  }
  for(i=0;i<PROCESS_COUNT;i++){
    x->odds[i] = 1.0;
  }
  x->odds[p] = 0.0;
  setweights(x->odds,PROCESS_COUNT);
}

void bashfest_flatodds(t_bashfest *x)
{
  int i;
  for(i=0;i<PROCESS_COUNT;i++){
    x->odds[i] = 1.0;
  }
  setweights(x->odds,PROCESS_COUNT);
}


void *bashfest_new(t_symbol *msg, short argc, t_atom *argv)
{
#if __MSP__
  t_bashfest *x = (t_bashfest *)newobject(bashfest_class);
#endif
#if __PD__
  t_bashfest *x = (t_bashfest *)pd_new(bashfest_class);
//  outlet_new(&x->x_obj, gensym("signal"));
#endif
    
  int i;
  long membytes = 0;
float tmpfloat;
  srand(time(0));

  x->sr = sys_getsr();
  x->vs = sys_getblksize();
  if(! x->sr)
    x->sr = 44100;


  x->work_buffer_size = DEFAULT_BUFFER_SIZE;
//  x->latency_samples = DEFAULT_LATENCY;
//  x->overlap_max = DEFAULT_MAX_OVERLAP;
	
  /* argument list: buffer name, work buffer duration, latency in samples, number of overlaps */	
  atom_arg_getsym(&x->wavename,0,argc,argv);
  atom_arg_getfloat(&x->work_buffer_size,1,argc,argv);
  tmpfloat = DEFAULT_LATENCY;
  atom_arg_getfloat(&tmpfloat,2,argc,argv);
  x->latency_samples = tmpfloat;
  tmpfloat = DEFAULT_MAX_OVERLAP;
  atom_arg_getfloat(&tmpfloat,3,argc,argv);
  x->overlap_max = tmpfloat;
  
  
  /*
  atom_arg_getlong((long *)&x->latency_samples,2,argc,argv);
  atom_arg_getlong((long *)&x->overlap_max,3,argc,argv);
  */

#if __MSP__
  dsp_setup((t_pxobject *)x,1);
  outlet_new((t_pxobject *)x, "signal");
  outlet_new((t_pxobject *)x, "signal");
  x->x_obj.z_misc |= Z_NO_INPLACE;
#endif
#if __PD__
outlet_new(&x->x_obj, gensym("signal"));
outlet_new(&x->x_obj, gensym("signal"));
#endif

  x->sinelen = 8192;
		
  x->verbose = 0;
  x->most_recent_event = 0;
  x->active_events = 0;
  x->increment = 1.0;
  x->block_dsp = 0;
  x->grab = 0;
  /*
  x->tb_inpt = 0;
  if(x->latency_samples < x->vs){
  	x->latency_samples = x->vs;//might need x->vs * 2 here
  	error("latency forced to %d samples",x->vs);
  }
  x->tb_outpt = x->latency_samples - x->vs;
  */
  /* buffer contains space for both input and output, thus factor of 2 */
  x->buf_frames = 2 * x->work_buffer_size * .001 * x->sr;

  x->buf_samps = x->buf_frames * 2;
  x->halfbuffer = x->buf_samps / 2;
	
  x->maxdelay = 1.0; // in seconds
  /*memory allocation */
  x->events = (t_event *) t_getbytes(x->overlap_max * sizeof(t_event));
  x->trigger_vec = (float *) t_getbytes(MAX_VEC * sizeof(float));
  x->sinewave = t_getbytes(x->sinelen * sizeof(float));
  x->params = t_getbytes(MAX_PARAMETERS * sizeof(float));
  x->odds = t_getbytes(64 * sizeof(float));
//  x->trigger_buffer = calloc(x->latency_samples, sizeof(float));
  
  for(i=0;i<64;i++)
    x->odds[i] = 0;
  putsine(x->sinewave, x->sinelen);
  for(i=0;i<x->overlap_max;i++){
    x->events[i].workbuffer = (float *) t_getbytes(x->buf_samps * sizeof(float));
  }
  x->delayline1 = (float *) t_getbytes(x->maxdelay * x->sr * sizeof(float));
  x->delayline2 = (float *) t_getbytes(x->maxdelay * x->sr * sizeof(float));
  x->max_mini_delay = .25;
  x->eel = (LSTRUCT *) t_getbytes(MAXSECTS * sizeof(LSTRUCT));
  for( i = 0; i < 4 ; i++ ){
    x->mini_delay[i] = 
      (float *) t_getbytes(((int)(x->sr * x->max_mini_delay) + 1)  * sizeof(float));
  }
  x->reverb_ellipse_data = (float *) t_getbytes(16 * sizeof(float));

  x->ellipse_data = (float **) t_getbytes(MAXFILTER * sizeof(float *));
  for(i=0;i<MAXFILTER;i++){
    x->ellipse_data[i] = (float *) t_getbytes(MAX_COEF * sizeof(float));
  }
  x->tf_len = 1;
  x->tf_len <<= 16;
  x->transfer_function = (float *) t_getbytes(x->tf_len * sizeof(float) );
  x->feedfunclen = 8192 ;
  x->feedfunc1 = (float *) t_getbytes( x->feedfunclen * sizeof(float) );
  x->feedfunc2 = (float *) t_getbytes( x->feedfunclen * sizeof(float) );
  x->feedfunc3 = (float *) t_getbytes( x->feedfunclen * sizeof(float) );
  x->feedfunc4 = (float *) t_getbytes( x->feedfunclen * sizeof(float) );
  x->flamfunc1len = 8192 ;
  x->flamfunc1 = (float *) t_getbytes( x->flamfunc1len * sizeof(float));
  setflamfunc1(x->flamfunc1,x->flamfunc1len);
  x->max_comb_lpt = 0.15 ;// watch out here
  x->combies = (CMIXCOMB *) t_getbytes(4 * sizeof(CMIXCOMB));
  for( i = 0; i < 4; i++ ){
    x->combies[i].len = x->sr * x->max_comb_lpt + 2;
    x->combies[i].arr = (float *) t_getbytes(x->combies[i].len * sizeof(float));
  }
  x->adsr = (CMIXADSR *) t_getbytes(1 * sizeof(CMIXADSR));
  x->adsr->len = 32768 ;
  x->adsr->func = (float *) t_getbytes(x->adsr->len * sizeof(float) );
  x->dcflt = (float *) t_getbytes(16 * sizeof(float));
  x->tcycle.data = (float *) t_getbytes(CYCLE_MAX * sizeof(float));
  x->tcycle.len = 0;
  for(i=0;i<x->overlap_max;i++){
  	x->events[i].phasef = x->events[i].phase = 0.0;
  }

  membytes = x->overlap_max * sizeof(t_event);
  membytes += x->sinelen * sizeof(float);
  membytes += MAX_PARAMETERS * sizeof(float);
  membytes += 64 * sizeof(float);
  membytes += x->buf_samps * sizeof(float) * x->overlap_max;
  membytes += x->maxdelay * x->sr * sizeof(float) * 2;
  membytes += MAXSECTS * sizeof(LSTRUCT);
  membytes += ((int)(x->sr * x->max_mini_delay) + 1)  * sizeof(float) * 4;
  membytes += 16 * sizeof(float);
  membytes += MAXFILTER * sizeof(float *);
  membytes += MAX_COEF * sizeof(float) * MAXFILTER;
  membytes += x->tf_len * sizeof(float);
  membytes += x->feedfunclen * sizeof(float) * 4;
  membytes += x->flamfunc1len * sizeof(float);
  membytes += 4 * sizeof(CMIXCOMB);
  membytes += x->combies[0].len * sizeof(float) * 4;
  membytes += sizeof(CMIXADSR);
  membytes += x->adsr->len * sizeof(float);
  membytes += 16 * sizeof(float);
  membytes += CYCLE_MAX * sizeof(float);

  post("total memory for this bashfest %.2f MBytes",(float)membytes/1000000.);
    
  /* be sure to finish clearing memory */
  set_dcflt(x->dcflt);
  init_reverb_data(x->reverb_ellipse_data);
  init_ellipse_data(x->ellipse_data);

  for(i=0;i<PROCESS_COUNT;i++){
    x->odds[i] = 1;
  }	

															
  x->max_process_per_note = 2;
  setweights(x->odds,PROCESS_COUNT);


  x->mute = 0;
	
  for(i = 0; i < x->overlap_max; i++){
    x->events[i].status = INACTIVE;
  }


  return (x);
}


void bashfest_dblclick(t_bashfest *x)
{
#if __MSP__
  t_buffer *b;
  t_symbol *wavename = x->wavename;
	
  if ((b = (t_buffer *)(wavename->s_thing)) && ob_sym(b) == gensym("buffer~"))
    mess0((t_object *)b,gensym("dblclick"));
#endif
}


#if __MSP__
void bashfest_setbuf(t_bashfest *x, t_symbol *wavename)
{
  t_buffer *b;

  x->hosed = 0;
		
  if ((b = (t_buffer *)(wavename->s_thing)) && ob_sym(b) == gensym("buffer~")) {
    if( b->b_nchans > 2 ){
      error("too many channels (> 2) in buffer %s", wavename->s_name);
      x->hosed = 1;
    } else {
	/* valid buffer found */

	x->b_samples = b->b_samples;
	x->b_nchans = b->b_nchans;
	x->b_valid = b->b_valid;
	x->b_frames = b->b_frames;
 //     x->wavebuf = b;
    }		
  } else {
    error("bashfest~: no such buffer~ %s", wavename->s_name);
    x->hosed = 1;
  }

  x->wavename = wavename;
  strcpy(x->sound_name, x->wavename->s_name);

}
#endif
#if __PD__
void bashfest_setbuf(t_bashfest *x, t_symbol *wavename)
{
  t_garray *a;
	x->hosed = 0;
  x->b_frames = 0;
  x->b_nchans = 1;
  x->b_valid = 0;
  int b_frames;
  if (!(a = (t_garray *)pd_findbyclass(wavename, garray_class))) {
      if (*wavename->s_name) pd_error(x, "bashfest~: %s: no such array",
				      wavename->s_name);
      x->b_samples = 0;
      x->hosed = 1;
    }
  else if (!garray_getfloatarray(a, &b_frames, &x->b_samples)) {
      pd_error(x, "%s: bad array for bashfest~", wavename->s_name);
      x->b_samples = 0;
      x->hosed = 1;
    }
  else  {
    x->b_frames = (long)b_frames;
    // post("%d frames in buffer %s",x->b_frames, wavename->s_name);
    garray_usedindsp(a);
	x->b_valid = 1;
  }

}

#endif


t_int *bashfest_perform_hosed(t_int *w)
{

//  t_bashfest *x = (t_bashfest *) (w[1]);
//  float *trigger = (t_float *)(w[2]);
  float *outchanL = (t_float *)(w[3]);
  float *outchanR = (t_float *)(w[4]);
  int n = w[5];

// try bzero 
//  while(n--) *outchanL++ = *outchanR++ = 0.0;
  memset((char *)outchanL, 0, sizeof(float) * n);
  memset((char *)outchanR, 0, sizeof(float) * n);
  return(w+6);

}

/* modified for dsp turnoff*/

t_int *bashfest_perform(t_int *w)
{
  t_bashfest *x = (t_bashfest *) (w[1]);
  float *t_vec = (t_float *)(w[2]);
  float *outchanL = (t_float *)(w[3]);
  float *outchanR = (t_float *)(w[4]);
  int n = w[5];

/*
  float *b_samples = x->wavebuf->b_samples;
  long b_nchans = x->wavebuf->b_nchans;
  */
  float *b_samples;
  long b_nchans;
  long b_valid;
  long b_frames;
  
  t_event *events = x->events;
//  int active_events = x->active_events;
  float increment = x->increment;
  int overlap_max = x->overlap_max;
  int iphase;
  int flimit;
  short insert_success;
  int new_insert;
  int i,j,k;
  t_cycle tcycle = x->tcycle;
  float gain;
//  short bail;
  float frac;
  float samp1, samp2;
  float maxphase;
  int theft_candidate;
  int out_channels;
  float *processed_drum;
  char *sound_name = x->sound_name;

  int latency_samples = x->latency_samples;
  float *trigger_vec = x->trigger_vec;
#if __MSP__
	trigger_vec = t_vec;
#endif
#if __PD__
	for(i = 0; i < n; i++)
		trigger_vec[i] = t_vec[i];
#endif
  
  if(x->mute || x->hosed){
    while(n--) {
      *outchanL++ = *outchanR++ = 0.0;
    }
    return(w+6);
  }
  bashfest_setbuf(x, x->wavename);
	
  if(! x->b_valid) {
    while(n--) {
      *outchanL++ = *outchanR++ = 0.0;
    }
    return(w+6);		
  }
  
  b_samples = x->b_samples;
  b_frames = x->b_frames;
  b_nchans = x->b_nchans;
  
  if(x->block_dsp){
    /* computation savings if processing is blocked */


    /* preliminary transposition will be set here */
    
    if(tcycle.len > 0){
      increment = tcycle.data[tcycle.p];
      // post("position %d, increment %f",tcycle.p,increment );
    } else {
      increment = 1.0;
      //error("increment default, len is zero");
    }
    // initial cleaning
    for(i=0; i<n; i++){
      outchanL[i] = outchanR[i] = 0.0;
    }
    flimit = (b_frames - 1) * 2;
    for(i = 0; i < overlap_max; i++){
	  if(events[i].status == ACTIVE){
		gain = events[i].gain;

		if(b_nchans == 1){ /* mono */

			flimit = (b_frames - 1);
			for(j = 0; j < n; j++){
			  if(events[i].countdown > 0){
			    --events[i].countdown;
			  } else {

			    iphase = events[i].phasef;
			    frac = events[i].phasef - iphase;

			    if(increment > 0){
			      if(iphase == flimit || increment == 1.0){
							outchanL[j] += b_samples[iphase] * gain;
							outchanR[j] += b_samples[iphase] * gain;
			      } else {
							samp1 = b_samples[iphase];
							samp2 = b_samples[iphase+1];
							samp1 = gain * (samp1 + frac * (samp2-samp1));
							outchanL[j] += samp1;
							outchanR[j] += samp1;
			      }
			    } else { /*negative increment case (currently unused but might be useful)*/
			      if(iphase == 0.0 || increment == -1.0 ){
							outchanL[j] += b_samples[iphase] * gain;
							outchanR[j] += b_samples[iphase] * gain;
			      } else {
							samp2 = b_samples[iphase];
							samp1 = b_samples[iphase-1];
							samp1 = gain * (samp1 + frac * (samp2-samp1));
							outchanL[j] += samp1;
							outchanR[j] += samp1;
			      }
			    }
			    events[i].phasef += increment;

			    if( events[i].phasef < 0.0 || events[i].phasef >= b_frames){
			      events[i].status = INACTIVE;
			      events[i].phasef = 0;
			      // post("valid exit mono note");
			      break;
			    }
			  }
			}
		} else if(b_nchans == 2){
		/* stereo */

			for(j = 0; j < n; j++){
			  if(events[i].countdown > 0){
			    --events[i].countdown;
			  } else {
			    iphase = events[i].phasef;
			    frac = events[i].phasef - iphase;
			    iphase *= 2;
			    if(increment > 0){
			      if(iphase == flimit || increment == 1.0){
					outchanL[j] += b_samples[iphase] * gain;
					outchanR[j] += b_samples[iphase+1] * gain;
			      } else {
					samp1 = b_samples[iphase];
					samp2 = b_samples[iphase+2];
					outchanL[j] += gain * (samp1 + frac * (samp2-samp1));
					samp1 = b_samples[iphase+1];
					samp2 = b_samples[iphase+3];
					outchanR[j] += gain * (samp1 + frac * (samp2-samp1));
			      }
			    } else { /*negative increment case (currently unused but might be useful)*/
			      if(iphase == 0.0 || increment == -1.0 ){
					outchanL[j] += b_samples[iphase] * gain;
					outchanR[j] += b_samples[iphase+1] * gain;
			      } else {
					samp2 = b_samples[iphase];
					samp1 = b_samples[iphase-2];
					outchanL[j] += gain * (samp1 + frac * (samp2-samp1));
					samp2 = b_samples[iphase+1];
					samp1 = b_samples[iphase-1];
					outchanR[j] += gain * (samp1 + frac * (samp2-samp1));
			      }
			    }
			    events[i].phasef += increment;

			    if( events[i].phasef < 0.0 || events[i].phasef >= b_frames){
			      events[i].status = INACTIVE;
			      break;
			    }
			  }
			}
		}
	  }
    }

    for(i=0; i<n; i++){
	  if(trigger_vec[i]){
		gain = trigger_vec[i];

		insert_success = 0;
		for(j=0; j<overlap_max; j++){
		  if(events[j].status == INACTIVE){
		    events[j].status = ACTIVE;
		    events[j].gain = gain;
		    if(increment > 0){
		      events[j].phasef = 0.0;
		    } else {
		      events[j].phasef = b_frames - 1;
		    }
		    insert_success = 1;
		    new_insert = j;
		    break;
		  }
		}	
				
		if(!insert_success){ // steal a note
			
		  maxphase = 0;
		  theft_candidate = 0;
		  for(k = 0; k < overlap_max; k++){
		    if(events[k].phasef > maxphase){
		      maxphase = events[k].phasef;
		      theft_candidate = k;
		    }
		  }
		  new_insert = theft_candidate;
		  events[new_insert].gain = gain;
		  if(increment > 0){
		    events[new_insert].phasef = 0.0;
		  } else {
		    events[new_insert].phasef = b_frames - 1;
		  }
		  insert_success = 1;
		  post("stealing a note at %d for buffer %s", new_insert, sound_name);
		}
		events[new_insert].countdown = latency_samples;
		events[new_insert].status = ACTIVE;
		x->new_slot = new_insert;
		x->new_gain = gain;
		// post("new note at slot %d",new_insert);
		if(tcycle.len > 0){
		  increment = tcycle.data[tcycle.p++];
		  if(tcycle.p >= tcycle.len){
		    tcycle.p = 0;
		  }
		  x->tcycle.p = tcycle.p;
		} else {
		  increment = 1.0;
		}

		for(k=i; k<n; k++){
		  //roll out for remaining portion of vector
		  if(events[new_insert].countdown > 0){
		    --events[new_insert].countdown;
		  } else {
			if(b_nchans == 1){

			    iphase = events[new_insert].phasef;
			    frac = events[new_insert].phasef - iphase;
				if(iphase < 0 || iphase >= b_frames){
					error("aborting on phase %f",events[new_insert].phasef);
					break;
				}
			    if(increment > 0){
			      if(iphase == flimit || increment == 1.0){
					outchanL[k] += b_samples[iphase] * gain;
					outchanR[k] += b_samples[iphase] * gain;
			      } else {
					samp1 = b_samples[iphase];
					samp2 = b_samples[iphase+1];
					samp1 = gain * (samp1 + frac * (samp2-samp1));
					outchanL[k] += samp1;
					outchanR[k] += samp1;
			      }
			    } else { /*negative increment case (currently unused but might be useful)*/
			      if(iphase == 0.0 || increment == -1.0 ){
					outchanL[k] += b_samples[iphase] * gain;
					outchanR[k] += b_samples[iphase] * gain;
			      } else {
					samp2 = b_samples[iphase];
					samp1 = b_samples[iphase-2];
					samp1 = gain * (samp1 + frac * (samp2-samp1));
					outchanL[k] += samp1;
					outchanR[k] += samp1;
			      }
			    }
			    events[new_insert].phasef += increment;

			    if( events[new_insert].phasef < 0.0 || events[new_insert].phasef >= b_frames){
			      events[new_insert].status = INACTIVE;
			      break;
			    }
			} else if(b_nchans == 2)
			{
			    iphase = events[new_insert].phasef;
			    frac = events[new_insert].phasef - iphase;
			    iphase *= 2;
			    if(increment > 0){
			      if(iphase == flimit || increment == 1.0){
					outchanL[k] += b_samples[iphase] * gain;
					outchanR[k] += b_samples[iphase+1] * gain;
			      } else {
					samp1 = b_samples[iphase];
					samp2 = b_samples[iphase+2];
					outchanL[k] += gain * (samp1 + frac * (samp2-samp1));
					samp1 = b_samples[iphase+1];
					samp2 = b_samples[iphase+3];
					outchanR[k] += gain * (samp1 + frac * (samp2-samp1));
			      }
			    } else { /*negative increment case (currently unused but might be useful)*/
			      if(iphase == 0.0 || increment == -1.0 ){
					outchanL[k] += b_samples[iphase] * gain;
					outchanR[k] += b_samples[iphase+1] * gain;
			      } else {
					samp2 = b_samples[iphase];
					samp1 = b_samples[iphase-2];
					outchanL[k] += gain * (samp1 + frac * (samp2-samp1));
					samp2 = b_samples[iphase+1];
					samp1 = b_samples[iphase-1];
					outchanR[k] += gain * (samp1 + frac * (samp2-samp1));
			      }
			    }
			    events[new_insert].phasef += increment;

			    if( events[new_insert].phasef < 0.0 || events[new_insert].phasef >= b_frames){
			      events[new_insert].status = INACTIVE;
			      break;
			    }
		    }
		  }					
		}
	  }
    }
    x->increment = increment;
/*    x->tb_inpt = tb_inpt;
    x->tb_outpt = tb_outpt;*/
    return(w+6);		
    /* end of block_dsp contingecy code */
  }

  /* main body of bashfest processing */	


  for(i=0; i<n; i++){ /* pre-clean buffers*/
    outchanL[i] = outchanR[i] = 0.0;
  }

  /* add output from all active buffers into global outlet buffers */
	
	
  for(i = 0; i < overlap_max; i++){
    if( events[i].status == ACTIVE){
      out_channels = events[i].out_channels;
      /* assign the output part of work buffer to the local float buffer */

      processed_drum = events[i].workbuffer + events[i].in_start;
     
      for(j = 0; j < n; j++){
        if(x->grab){
        	x->grab = 0;
        	// if too slow, defend with defer_low()
        	bashfest_copy_to_MSP_buffer(x,i);
        }
		if(events[i].countdown > 0){
		  --events[i].countdown;
		} else {
				  if(out_channels == 1){
				    outchanL[j] += processed_drum[events[i].phase] * events[i].gainL;
				    outchanR[j] += processed_drum[events[i].phase] * events[i].gainR;
				  } else if(out_channels == 2){
				    iphase = events[i].phase * 2;
				    outchanL[j] += processed_drum[iphase] * events[i].gainL;
				    outchanR[j] += processed_drum[iphase+1] * events[i].gainR;
				  }

				  events[i].phase++;

				  if(events[i].phase >= events[i].sample_frames){
				    events[i].status = INACTIVE;
				    break;
				  }
				}
      }
    }
  }
	
  /* now check for initiation click. If found,
     add to list. If necessary, steal a note 
  */
  for(i=0; i<n; i++){
    if(trigger_vec[i]){
      gain = trigger_vec[i];

      /*look for an open slot*/
      insert_success = 0;
      for(j=0; j<overlap_max; j++){
		if(events[j].status == INACTIVE){
		  events[j].status = ACTIVE;
		  events[j].gain = gain;
		  insert_success = 1;
		  new_insert = j;
		  break;
		}
      }	
			
      if(!insert_success){ /* steal a note if necessary*/
		maxphase = 0;
		theft_candidate = 0;
		for(k = 0; k < overlap_max; k++){
		  if(events[k].phase > maxphase){
		    maxphase = events[k].phase;
		    theft_candidate = k;
		  }
		}
		if(x->verbose){
		  post("stealing note at slot %d", theft_candidate);
		}
		post("stealing a note at %d for buffer %s", theft_candidate, sound_name);
		new_insert = theft_candidate;
		events[new_insert].gain = gain;
		insert_success = 1;
      }

      events[new_insert].countdown = x->latency_samples;
      x->new_slot = new_insert;
      x->new_gain = gain;
#if __MSP__
      defer_low(x,(void *)bashfest_deploy_dsp,0,0,0);
#endif

#if __PD__
	bashfest_deploy_dsp(x); 
#endif

      /* now begin output from the new note */

      out_channels = events[new_insert].out_channels;
      processed_drum = events[new_insert].workbuffer + events[new_insert].in_start;
 			
      /* processed_drum = events[new_insert].workbuffer;	*/		
      for(j = i; j < n; j++){ 
		if(events[new_insert].countdown > 0){
		  --events[new_insert].countdown;
		} else{
		  iphase = events[new_insert].phase;
		  if(x->grab){
        	x->grab = 0;
        	// if too slow, defend with defer_low()
        	bashfest_copy_to_MSP_buffer(x,i);
      }
		  if(out_channels == 1){
		    outchanL[j] += processed_drum[iphase] * events[new_insert].gainL;
		    outchanR[j] += processed_drum[iphase] * events[new_insert].gainR;
		  } else if(out_channels == 2){
		    iphase = events[i].phase * 2;
		    outchanL[j] += processed_drum[iphase] * events[new_insert].gainL;
		    outchanR[j] += processed_drum[iphase+1] * events[new_insert].gainR;
		  }

		  events[new_insert].phase++;

		  if(events[new_insert].phase >= events[new_insert].sample_frames){
		    events[new_insert].status = INACTIVE;
		    break;
		  }
		}
      } 
    }
  }
  return (w+6);
}

void bashfest_copy_to_MSP_buffer(t_bashfest *x, int slot)
{
	int i; //,j;
	t_event *events = x->events;
	long b_nchans = x->b_nchans;
	long b_frames = x->b_frames;
	float *b_samples = x->b_samples;
	float *processed_drum;

	processed_drum = events[slot].workbuffer + events[slot].in_start;

	if(events[slot].out_channels == b_nchans){
		if(b_nchans == 1){
			for(i=0;i<b_frames;i++){
				b_samples[i] = processed_drum[i];
			}
		} else if(b_nchans == 2){
			for(i=0;i<b_frames*2;i+=2){
				b_samples[i] = processed_drum[i];
				b_samples[i+1] = processed_drum[i+1];
			}
		}else{
			error("bashfest copy: channel mismatch");
			//fixable but first let's try these
		}
	}
}
void bashfest_deploy_dsp(t_bashfest *x)
{
  float *b_samples = x->b_samples;
  long b_nchans = x->b_nchans;
  long b_frames = x->b_frames;
  t_event *events = x->events;
  float pan;
  int i; //,j;
  float *params = x->params;
  int pcount;
  int buf_samps = x->buf_samps;
  int curarg = 0;
  float maxamp;
  float rescale;
  float *inbuf;
  int slot = x->new_slot;
  float gain = x->new_gain;
	
  events[slot].completed = 1;// for testing only
	
  if(b_nchans <1 || b_nchans > 2){
    error("illegal channels in buffer:%d",b_nchans);
    return;
    x->hosed = 1;
  }
  if(b_frames > x->buf_frames / 2){
    error("sample in buffer %s is to large for work buffer",x->sound_name);
    return;
    x->hosed = 1;
  }

  pan = boundrand(0.1, 0.9);
  events[slot].gainL = cos(PIOVERTWO * pan) * gain;
  events[slot].gainR = sin(PIOVERTWO * pan) * gain;
  events[slot].phase = 0;
  events[slot].status = ACTIVE;
  /*  if(x->verbose)
      post("initiating note at slot %d, gain %f, pan %f,inchans %d",slot,gain,pan,b_nchans);
  */
  if(x->sound_lock){
    return;// of course should finally copy good stuff to MSP buffer
  }
  events[slot].out_channels = b_nchans;
  events[slot].sample_frames = b_frames;
  for(i=0; i<b_frames*b_nchans; i++){
    events[slot].workbuffer[i] = b_samples[i];
  }

  // clean rest of work buffer
  for(i=b_frames*b_nchans; i<buf_samps; i++){
    events[slot].workbuffer[i] = 0.0;
  }
  events[slot].in_start = 0;
  events[slot].out_start = x->halfbuffer;
  pcount = bashfest_set_parameters(x, params);
	
  while(curarg < pcount){
    if(params[curarg] == TRANSPOSE){
      transpose(x, slot, &curarg);
    }
    else if(params[curarg] == RINGMOD){
      ringmod(x, slot, &curarg);
    } 
    else if(params[curarg] == RETRO){
      retrograde(x, slot, &curarg);
    } 
    else if(params[curarg] == COMB){
      comber(x, slot, &curarg);
    }
    else if(params[curarg] == FLANGE){
      flange(x, slot, &curarg);
    }
    else if(params[curarg] == BUTTER){
      butterme(x, slot, &curarg);
    }
    else if(params[curarg] == TRUNCATE){
      truncateme(x, slot, &curarg);
    }
    else if(params[curarg] == SWEEPRESON){
      sweepreson(x, slot, &curarg);
    } 
    else if(params[curarg] == SLIDECOMB){
      slidecomb(x, slot, &curarg);
    } 
    else if(params[curarg] == REVERB1){
      reverb1(x, slot, &curarg);
    } 
    else if(params[curarg] == ELLIPSE){
      ellipseme(x, slot, &curarg);
    } 
    else if(params[curarg] == FEED1){
      feed1me(x, slot, &curarg);
    } 
    else if(params[curarg] == FLAM1){
      flam1(x, slot, &curarg);
    }     	
    else if(params[curarg] == FLAM2){
      flam2(x, slot, &curarg);
    } 
    else if(params[curarg] == EXPFLAM){
      expflam(x, slot, &curarg);
    }
    else if(params[curarg] == COMB4){
      comb4(x, slot, &curarg);
    }
    else if(params[curarg] == COMPDIST){
      compdist(x, slot, &curarg);
    }
    else if(params[curarg] == RINGFEED){
      ringfeed(x, slot, &curarg);
    }
    else if(params[curarg] == RESONADSR){
      resonadsr(x, slot, &curarg);
    }
    else if(params[curarg] == STV){
      stv(x, slot, &curarg);
    }
    else {
      error("deploy missing branch");
    }
  }
	
  maxamp = 0.0;
  inbuf = events[slot].workbuffer + events[slot].in_start;
  b_nchans = events[slot].out_channels;
  b_frames = events[slot].sample_frames;
  for(i=0; i< b_frames * b_nchans; i++){
    if(maxamp < fabs(inbuf[i])){
      maxamp = fabs(inbuf[i]);
    }
  }
  if(maxamp>0){
    rescale = 1.0/maxamp;
    for(i=0; i< b_frames * b_nchans; i++){
      inbuf[i] *= rescale;
    }
  }
  else{
    if(x->verbose)
      error("zero maxamp detected");
  }
	
  if(events[slot].countdown <= 0)
    error("deploy_dsp: failed to conclude in time; need more latency");
}

int bashfest_set_parameters(t_bashfest *x,float *params)
{
  float rval;
  int pcount = 0;
  int events;
  int i, j;
  int type;
  float cf;//, bw;
  float *odds = x->odds;
  int maxproc  = x->max_process_per_note;
  int minproc = x->min_process_per_note;
  float tval;
  t_cycle tcycle = x->tcycle;

  /* preliminary transposition will be set here */
  
  if(tcycle.len > 0){
    params[pcount++] = TRANSPOSE;
    params[pcount++] = tcycle.data[tcycle.p++];
    if(tcycle.p >= tcycle.len){
      tcycle.p = 0;
    }
    x->tcycle.p = tcycle.p;
  }

  
  if(maxproc <= 0){
    return pcount;
  }

  events = minproc + rand() % (1+(maxproc-minproc));
	
  for(i = 0; i < events; i++){
    rval = boundrand(0.0,1.0);
    j = 0;
    while(rval > odds[j]){
      j++;
    }
		

    if(j == RETRO){
      params[pcount++] = RETRO;
    } 
    else if(j == COMB){
      params[pcount++] = COMB;
      params[pcount++] = boundrand(.001,.035);// delaytime
      params[pcount++] = boundrand(.25,.98);//feedback
      params[pcount++] = boundrand(.05,.5);//hangtime
    } 
    else if(j == RINGMOD) {
      params[pcount++] = RINGMOD;
      params[pcount++] = boundrand(100.0,2000.0); //need a log version
    } 
    else if(j == TRANSPOSE){
      params[pcount++] = TRANSPOSE;
      params[pcount++] = boundrand(0.25,3.0);
    } 
    else if(j == FLANGE){
      params[pcount++] = FLANGE;
      params[pcount++] = boundrand(100.0,400.0);
      params[pcount++] = boundrand(600.0,4000.0);
      params[pcount++] = boundrand(0.1,2.0);
      params[pcount++] = boundrand(0.1,0.95);
      params[pcount++] = boundrand(0.0,0.9);
    } 	
    else if(j == BUTTER){
      params[pcount++] = BUTTER;
      type = rand() % 3;
      params[pcount++] = type;
      cf = boundrand(70.0,3000.0);
      params[pcount++] = cf;
      if(type == BANDPASS){
	params[pcount++] = cf * boundrand(0.05,0.6);
      }		
    }	
    else if(j == TRUNCATE){
      params[pcount++] = TRUNCATE;
      params[pcount++] = boundrand(.05,.15);
      params[pcount++] = boundrand(.01,.05);
    }
    else if(j == SWEEPRESON){
      params[pcount++] = SWEEPRESON;
      params[pcount++] = boundrand(100.0,300.0);
      params[pcount++] = boundrand(600.0,6000.0);
      params[pcount++] = boundrand(0.01,0.2);
      params[pcount++] = boundrand(0.05,2.0);
      params[pcount++] = boundrand(0.0,1.0);
    }
    else if(j == SLIDECOMB){
      params[pcount++] = SLIDECOMB;
      params[pcount++] = boundrand(.001,.03);
      params[pcount++] = boundrand(.001,.03);
      params[pcount++] = boundrand(0.05,0.95);
      params[pcount++] = boundrand(0.05,0.5);
    }
    else if(j == REVERB1){
      params[pcount++] = REVERB1;
      params[pcount++] = boundrand(0.25,0.99);
      params[pcount++] = boundrand(0.1,1.0);
      params[pcount++] = boundrand(0.2,0.8);
    }
    else if(j == ELLIPSE){
      params[pcount++] = ELLIPSE;
      params[pcount++] = rand() % ELLIPSE_FILTER_COUNT;
    }
    else if(j == FEED1){
      params[pcount++] = FEED1;
      tval = boundrand(.001,0.1);
      params[pcount++] = tval;
      params[pcount++] = boundrand(tval,0.1);
      tval = boundrand(.01,0.5);
      params[pcount++] = tval;
      params[pcount++] = boundrand(tval,0.5);
      params[pcount++] = boundrand(.05,1.0);
    }
    else if(j == FLAM1){
      params[pcount++] = FLAM1;
      params[pcount++] = 4 + (rand() % 20);
      params[pcount++] = boundrand(0.3,0.8);
      params[pcount++] = boundrand(0.5,1.2);
      params[pcount++] = boundrand(.025,0.15);
    }
    else if(j == FLAM2){
      params[pcount++] = FLAM2;
      params[pcount++] = 4 + (rand() % 20);
      params[pcount++] = boundrand(0.1,0.9);
      params[pcount++] = boundrand(0.2,1.2);
      params[pcount++] = boundrand(.025,0.15);
      params[pcount++] = boundrand(.025,0.15);
    }
    else if(j == EXPFLAM){
      params[pcount++] = EXPFLAM;
      params[pcount++] = 4 + (rand() % 20);
      params[pcount++] = boundrand(0.1,0.9);
      params[pcount++] = boundrand(0.2,1.2);
      params[pcount++] = boundrand(.025,0.15);
      params[pcount++] = boundrand(.025,0.15);
      params[pcount++] = boundrand(-5.0,5.0);
    }
    else if(j == COMB4){
      params[pcount++] = COMB4;
      params[pcount++] = boundrand(100.0,900.0);
      params[pcount++] = boundrand(100.0,900.0);
      params[pcount++] = boundrand(100.0,900.0);
      params[pcount++] = boundrand(100.0,900.0);
      tval = boundrand(.5,0.99);
      params[pcount++] = tval;
      params[pcount++] = tval;
    }
    else if(j == COMPDIST){
      params[pcount++] = COMPDIST;
      params[pcount++] = tval = boundrand(.01,.25);
      params[pcount++] = boundrand(tval,.9);
      params[pcount++] = 1;
    }
    else if(j == RINGFEED){
      params[pcount++] = RINGFEED;
      params[pcount++] = boundrand(90.0,1500.0);
      params[pcount++] = boundrand(90.0,1500.0);
      params[pcount++] = boundrand(0.2,0.95);
      params[pcount++] = boundrand(90.0,1500.0);
      params[pcount++] = boundrand(.01,.4);
      params[pcount++] = boundrand(.05,1.0);
    }
    else if(j == RESONADSR){
      params[pcount++] = RESONADSR;
      params[pcount++] = boundrand(.01,.1);
      params[pcount++] = boundrand(.01,.05);
      params[pcount++] = boundrand(.05,.5);
      params[pcount++] = boundrand(150.0,4000.0);
      params[pcount++] = boundrand(150.0,4000.0);
      params[pcount++] = boundrand(150.0,4000.0);
      params[pcount++] = boundrand(150.0,4000.0);
      params[pcount++] = boundrand(.03,.7);
    }
    else if(j == STV){
      params[pcount++] = STV;
      params[pcount++] = boundrand(.025,0.5);
      params[pcount++] = boundrand(.025,0.5);
      params[pcount++] = boundrand(.001,.01);
    }
    else {
      error("could not find a process for %d",j);
      return 0;
    }
  }
  return pcount;
}

void bashfest_dsp_free(t_bashfest *x)
{
  int i;
#if __MSP__
  dsp_free((t_pxobject *)x);
#endif	
  t_freebytes(x->sinewave, x->sinelen * sizeof(float));
  t_freebytes(x->params, MAX_PARAMETERS * sizeof(float));
  t_freebytes(x->odds, 64 * sizeof(float));
  t_freebytes(x->delayline1, x->maxdelay * x->sr * sizeof(float));
  t_freebytes(x->delayline2, x->maxdelay * x->sr * sizeof(float));

  for(i=0;i<x->overlap_max;i++){
    t_freebytes(x->events[i].workbuffer, x->buf_samps * sizeof(float));
  }
  t_freebytes(x->events, x->overlap_max * sizeof(t_event));
	
  t_freebytes(x->eel,MAXSECTS * sizeof(LSTRUCT));
  for( i = 0; i < 4 ; i++ ){
    t_freebytes(x->mini_delay[i], ((int)(x->sr * x->max_mini_delay) + 1) * sizeof(float));
  }
  t_freebytes(x->reverb_ellipse_data, 16 * sizeof(float));
  for(i=0;i<MAXFILTER;i++){
    t_freebytes(x->ellipse_data[i], MAX_COEF * sizeof(float));
  } 	
  t_freebytes(x->ellipse_data, MAXFILTER * sizeof(float *));
  t_freebytes(x->transfer_function,x->tf_len * sizeof(float));
  t_freebytes(x->feedfunc1, x->feedfunclen * sizeof(float));
  t_freebytes(x->feedfunc2, x->feedfunclen * sizeof(float));
  t_freebytes(x->feedfunc3, x->feedfunclen * sizeof(float));
  t_freebytes(x->feedfunc4, x->feedfunclen * sizeof(float));
  t_freebytes(x->flamfunc1, x->flamfunc1len * sizeof(float));
  for( i = 0; i < 4; i++ ){
    t_freebytes(x->combies[i].arr, x->combies[i].len * sizeof(float));
  }
  t_freebytes(x->combies,4 * sizeof(CMIXCOMB));
  t_freebytes(x->adsr->func, x->adsr->len * sizeof(float));
  t_freebytes(x->adsr,sizeof(CMIXADSR));
  t_freebytes(x->tcycle.data,CYCLE_MAX * sizeof(float));
  t_freebytes(x->trigger_vec, MAX_VEC * sizeof(float));
}

void bashfest_dsp(t_bashfest *x, t_signal **sp, short *count)
{
  bashfest_setbuf(x, x->wavename);
	
  if( x->hosed ){
    error("bashfest~ needs a valid buffer");
  }
  /* if vector size changes, we also need to deal, thanks to
	the trigger buffer inter-delay
  */
  if(x->sr != sp[0]->s_sr){
    x->sr = sp[0]->s_sr;
    if(!x->sr){
      post("warning: zero sampling rate!");
      x->sr = 44100;
    }
  } 
  if(x->b_frames <= 0){
    post("empty buffer, hosing down");
    x->hosed = 1;
  }
	
  if(x->hosed){
    dsp_add(bashfest_perform_hosed, 5, x, 
	    sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);	
  } else {
    dsp_add(bashfest_perform, 5, x, 
	    sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);		
  }
}

void bashfest_assist (t_bashfest *x, void *b, long msg, long arg, char *dst)
{
  if (msg==1) {
    switch (arg) {
    case 0: sprintf(dst,"(signal) Click Trigger"); break;
    }
  } 
  else if (msg==2) {
    switch(arg){
    case 0: sprintf(dst,"(signal) Channel 1 Output"); break;
    case 1: sprintf(dst,"(signal) Channel 2 Output"); break;
    }
  }
}


/*** MSP helper function s **/
#if __PD__


void atom_arg_getfloat(float *c, long idx, long ac, t_atom *av) 
{
		if (c&&ac&&av&&(idx<ac)) {
			*c = atom_getfloat(av+idx);
		}
}

void atom_arg_getsym(t_symbol **c, long idx, long ac, t_atom *av)
{
	if (c&&ac&&av&&(idx<ac)) {
		*c = atom_getsymbol(av+idx);
	} 
}
#endif


