// MidiVizEQWatcher
// Lew Hill II

#include "MidiVizEQWatcher.h"

MidiVizEQWatcher::MidiVizEQWatcher(float* bands, int* rands){

  setBandsReference(bands, rands);

  init();

  //  setPosition(60, 10, -20);
  history_index = 0;
 
  for (int i = 0; i < NUM_BANDS; i++){

    discflip[i] = 1;
    eq_bands[i] = 0;
    eq_bands_avg[i] = 0;
    eq_bands_slow_avg[i] = 0;
    
    for (int j = 0; j < HISTORY_LENGTH; j++){
      eq_bands_history[i][j]=0;      
      }
  }
 
  float radians;
  for (int k = 0; k < 360; k++){
    radians = k * MV_PI_RAD;
    orbitCoordinates[k][0] = cos(radians);
    orbitCoordinates[k][1] = sin(radians);
  }
  
}

void MidiVizEQWatcher::init(){

  position[0] = 0;
  position[1] = 0;  
  position[2] = 0;

  rotation[0] = 0;
  rotation[1] = 0;  
  rotation[2] = 0;

  scale[0] = 1;
  scale[1] = 1;  
  scale[2] = 1;

  /*
  float radians;
  for (int i =0; i < 360; i+=1){
    radians = i * MV_PI_RAD;
    coordinates[i][0] = cos(radians);
    coordinates[i][1] = sin(radians);
    }*/
}

void MidiVizEQWatcher::frame(){
  //  cout << "History Index = " << history_index << endl;
  // use frame to do any decay functions

  // do normalized sum squares.

}

void MidiVizEQWatcher::storeSample(){
  
  for (int i = 0; i < NUM_BANDS; i++){
    eq_bands_slow_avg[i] = eq_bands_slow_avg[i] * .96 + eq_bands[i] * .03;
    eq_bands_avg[i] = eq_bands_avg[i] * .89 + eq_bands[i] * .09;
    eq_bands_diff[i] = eq_bands[i]-eq_bands_avg[i];
 }

  for (int i = 0; i < NUM_BANDS; i++){
    eq_bands_history[i][history_index] = eq_bands[i];
  }

  history_index++;
  history_index = history_index % HISTORY_LENGTH;
}

void MidiVizEQWatcher::drawWatcher(){

  // kitt-like voice box with rainbows and things

  glPushMatrix();
  glTranslatef(position[0], position[1], position[2]);
  glRotatef(rotation[2], 0.0, 0.0, 1.0); 
  glRotatef(rotation[1], 0.0, 1.0, 0.0); 
  glRotatef(rotation[0]-90, 1.0, 0.0, 0.0); 
  glScalef(scale[0], scale[1], scale[2]);
  
  float xStep = .7;
  float color[3];
  float* colorvec;

  float eq_val;
  float yheight;

  for (int i = 0; i< NUM_BANDS; i++){

    eq_val = eq_bands_avg[i];
    //eq_val = eq_bands[i];
    yheight = eq_val * 2.0;

    colorvec = rainbowLookup.getValue(eq_bands_avg[i]);
    color[0] = colorvec[0];
    color[1] = colorvec[1];
    color[2] = colorvec[2];

    //  glColor3f(eq_bands[i], 1-eq_val, 0.0);

    glColor3fv(color);

    glBegin(GL_POLYGON);
    glVertex3f(xStep*i, 0, yheight);
    glVertex3f(xStep*i, 0, -yheight);
    glVertex3f(xStep*(i+1), 0, -yheight);
    glVertex3f(xStep*(i+1), 0, yheight);
    glEnd();

    glBegin(GL_POLYGON);
    glVertex3f(-xStep*i, 0, yheight);
    glVertex3f(-xStep*i, 0, -yheight);
    glVertex3f(-xStep*(i+1), 0, -yheight);
    glVertex3f(-xStep*(i+1), 0, yheight);
    glEnd();
  }

  glPopMatrix();
  
}

void MidiVizEQWatcher::drawBackground(){

  float incolor[3];
  float* incolor_vec;

  float outcolor[3];
  float* outcolor_vec;


  float xStep = 1;
  float diagonal;
  float next_diagonal;
  int blackAndWhite = 1;
  int rainbowColor = 0;
  int useaverage = 1;

  glPushMatrix();
  glTranslatef(position[0], position[1], position[2]);
  glRotatef(rotation[2], 0.0, 0.0, 1.0); 
  glRotatef(rotation[1], 0.0, 1.0, 0.0); 
  glRotatef(rotation[0]-90, 1.0, 0.0, 0.0); 
  glScalef(scale[0], scale[1], scale[2]);
  
  for (int i = 0; i< NUM_BANDS-1; i++){
    diagonal  = xStep * i + 4*xStep;
    next_diagonal = xStep * (i+1) + 4*xStep;
    
    if (rainbowColor == 1){
      
      if (useaverage){
	incolor_vec = rainbowLookup.getValue(eq_bands_avg[i]);
      } else {
	incolor_vec = rainbowLookup.getValue(eq_bands[i]);
      }
      incolor[0] = incolor_vec[0];
      incolor[1] = incolor_vec[1];
      incolor[2] = incolor_vec[2];
      
      if (useaverage){
	outcolor_vec = rainbowLookup.getValue(eq_bands_avg[i+1]);
      } else {
	outcolor_vec = rainbowLookup.getValue(eq_bands[i+1]);
      }

      outcolor[0] = outcolor_vec[0];
      outcolor[1] = outcolor_vec[1];
      outcolor[2] = outcolor_vec[2];
     
    } else if (blackAndWhite == 1){
      
      if (useaverage){
	incolor[0] = incolor[1] = incolor[2] = eq_bands_avg[i]*eq_bands_avg[i];
	outcolor[0] = outcolor[1] = outcolor[2] = eq_bands_avg[i+1]*eq_bands_avg[i+1];
      } else {
	incolor[0] = incolor[1] = incolor[2] = eq_bands[i] * eq_bands[i];
	outcolor[0] = outcolor[1] = outcolor[2] = eq_bands[i+1] * eq_bands[i+1];
      }      
    }
    
    glBegin(GL_QUAD_STRIP);
    glColor3fv(incolor);
    glVertex3f(diagonal, 0, diagonal);
    glColor3fv(outcolor);
    glVertex3f(next_diagonal, 0, next_diagonal);

    glColor3fv(incolor);
    glVertex3f(diagonal, 0, -diagonal);
    glColor3fv(outcolor);
    glVertex3f(next_diagonal, 0, -next_diagonal);

    glColor3fv(incolor);
    glVertex3f(-diagonal, 0, -diagonal);
    glColor3fv(outcolor);
    glVertex3f(-next_diagonal, 0, -next_diagonal);

    glColor3fv(incolor);
    glVertex3f(-diagonal, 0, diagonal);
    glColor3fv(outcolor);
    glVertex3f(-next_diagonal, 0, next_diagonal);

    glColor3fv(incolor);
    glVertex3f(diagonal, 0, diagonal);
    glColor3fv(outcolor);
    glVertex3f(next_diagonal, 0, next_diagonal);

    glEnd();
  }

  glPopMatrix();

}

void MidiVizEQWatcher::drawLollipop(){

  float incolor[3];
  float* incolor_vec;
  float inverse_incolor[3];

  float outcolor[3];
  float* outcolor_vec;
  float inverse_outcolor[3];

  float xpos=0, ypos=0;
  float lastx, lasty;

  glPushMatrix();
  glTranslatef(position[0], position[1], position[2]);
  glRotatef(rotation[2], 0.0, 0.0, 1.0); 
  glRotatef(rotation[1], 0.0, 1.0, 0.0); 
  glRotatef(rotation[0]-90, 1.0, 0.0, 0.0); 
  glScalef(scale[0], scale[1], scale[2]);
  
  for (int i = 0; i< NUM_BANDS-1; i++){
    lastx = xpos;
    lasty = ypos;
    ypos += eq_bands_avg[i] + 1;
    xpos += 1-eq_bands_avg[i] + 1;

    //    midxpos = (xpos + lastx) * .5;
    //midypos = (ypos + lasty) * .5;
    
    incolor_vec = rainbowLookup.getValue(eq_bands_avg[i]);
    incolor[0] = incolor_vec[0];
    incolor[1] = incolor_vec[1];
    incolor[2] = incolor_vec[2];
    inverse_incolor[0] = 1-incolor[0];
    inverse_incolor[1] = 1-incolor[1];
    inverse_incolor[2] = 1-incolor[2];

    outcolor_vec = rainbowLookup.getValue(eq_bands_avg[i+1]);
    outcolor[0] = outcolor_vec[0];
    outcolor[1] = outcolor_vec[1];
    outcolor[2] = outcolor_vec[2];
    inverse_outcolor[0] = 1-outcolor[0];
    inverse_outcolor[1] = 1-outcolor[1];
    inverse_outcolor[2] = 1-outcolor[2];

    glLineWidth(2.0);  

    glNormal3f(0,1,0);

    glBegin(GL_LINES);  
    glColor3fv(inverse_outcolor);
    glVertex3f(xpos, 0, ypos);
    glColor3fv(inverse_incolor);
    glVertex3f(lastx, 0, lasty);
    glEnd();

    glBegin(GL_LINES);  
    glColor3fv(inverse_outcolor);
    glVertex3f(xpos, 0, -ypos);
    glColor3fv(inverse_incolor);
    glVertex3f(lastx, 0, -lasty);
    glEnd();

    glBegin(GL_LINES);  
    glColor3fv(inverse_outcolor);
    glVertex3f(-xpos, 0, -ypos);
    glColor3fv(inverse_incolor);
    glVertex3f(-lastx, 0, -lasty);
    glEnd();

    glBegin(GL_LINES);  
    glColor3fv(inverse_outcolor);
    glVertex3f(-xpos, 0, ypos);
    glColor3fv(inverse_incolor);
    glVertex3f(-lastx, 0, lasty);
    glEnd();

    // draw interconnects

    glBegin(GL_QUAD_STRIP);
    glColor3fv(outcolor);
    glVertex3f(xpos, 0, ypos);
    glColor3fv(incolor);
    glVertex3f(lastx, 0, lasty);

    glColor3fv(outcolor);
    glVertex3f(xpos, 0, -ypos);
    glColor3fv(incolor);
    glVertex3f(lastx, 0, -lasty);

    glColor3fv(outcolor);
    glVertex3f(-xpos, 0, -ypos);
    glColor3fv(incolor);
    glVertex3f(-lastx, 0, -lasty);

    glColor3fv(outcolor);
    glVertex3f(-xpos, 0, ypos);
    glColor3fv(incolor);
    glVertex3f(-lastx, 0, lasty);

    glColor3fv(outcolor);
    glVertex3f(xpos, 0, ypos);
    glColor3fv(incolor);
    glVertex3f(lastx, 0, lasty);

    glEnd();

  }

  glPopMatrix();    
}

void MidiVizEQWatcher::drawHistory(){
  
  int beginhistory;
  float zstep = .2;  float yval;
  float eqval;
  float color[3];
  float* colorvec;
  glLineWidth(2.0);
  
  glPushMatrix();
  glTranslatef(position[0], position[1], position[2]);
  glRotatef(rotation[2], 0.0, 0.0, 1.0);
  glRotatef(rotation[1], 0.0, 1.0, 0.0);
  glRotatef(rotation[0], 1.0, 0.0, 0.0);
  glScalef(scale[0], scale[1], scale[2]);
  
  float xconverge;

  for (int j = 0; j < HISTORY_LENGTH; j++){
    beginhistory = j + history_index;
    if ( beginhistory > HISTORY_LENGTH) beginhistory -= HISTORY_LENGTH;
    
    glBegin(GL_LINE_STRIP);
      for(int i  = 0; i < NUM_BANDS; i++){
	eqval = eq_bands_history[i][beginhistory];	  
	eqval *= eqval;
	yval = eqval *5;
	xconverge = (HISTORY_LENGTH-j)/(float) HISTORY_LENGTH;

	colorvec = rainbowLookup.getValue(eqval);
	color[0] = colorvec[0];
	color[1] = colorvec[1];
	color[2] = colorvec[2];
	glColor3fv(color);
	glVertex3f(31 - yval - 30*xconverge, i*4 - 16,  zstep*j - HISTORY_LENGTH * zstep);
      }
      glEnd();
  }

  for (int j = 0; j < HISTORY_LENGTH; j++){
    beginhistory = j + history_index;
    if ( beginhistory > HISTORY_LENGTH) beginhistory -= HISTORY_LENGTH;
    
    glBegin(GL_LINE_STRIP);
      for(int i  = 0; i < NUM_BANDS; i++){
	eqval = eq_bands_history[i][beginhistory];	  
	eqval *= eqval;

	yval = eqval *5;
	xconverge = ((HISTORY_LENGTH-j)/(float) HISTORY_LENGTH);

	colorvec = rainbowLookup.getValue(eqval);
	color[0] = colorvec[0];
	color[1] = colorvec[1];
	color[2] = colorvec[2];
	glColor3fv(color);
	glVertex3f(yval - 31 + 30*xconverge, i*4 - 16,  zstep*j - HISTORY_LENGTH * zstep);
      }
      glEnd();
  }

  // top line  
  // bottom lines

  glBegin(GL_LINES);
  
  for (int j = 0; j < HISTORY_LENGTH; j++){
    beginhistory = j + history_index;
    if ( beginhistory > HISTORY_LENGTH) beginhistory -= HISTORY_LENGTH;
       
    eqval = eq_bands_history[0][beginhistory];	  
    eqval *= eqval;
    yval = eqval *5;
    xconverge = ((HISTORY_LENGTH-j)/(float) HISTORY_LENGTH);
    colorvec = rainbowLookup.getValue(eqval);
    color[0] = colorvec[0];
    color[1] = colorvec[1];
    color[2] = colorvec[2];
    glColor3fv(color);
    glVertex3f(31 - yval - 30*xconverge, -16,  zstep*j - HISTORY_LENGTH * zstep);
    glVertex3f(yval - 31 + 30*xconverge, -16,  zstep*j - HISTORY_LENGTH * zstep);

    eqval = eq_bands_history[NUM_BANDS-1][beginhistory];	  
    eqval *= eqval;
    yval = eqval *5;
    xconverge = ((HISTORY_LENGTH-j)/(float) HISTORY_LENGTH);
    colorvec = rainbowLookup.getValue(eqval);
    color[0] = colorvec[0];
    color[1] = colorvec[1];
    color[2] = colorvec[2];
    glColor3fv(color);
    glVertex3f(31 - yval - 30*xconverge, (NUM_BANDS-1)*4-16,  zstep*j - HISTORY_LENGTH * zstep);
    glVertex3f(yval - 31 + 30*xconverge, (NUM_BANDS-1)*4-16,  zstep*j - HISTORY_LENGTH * zstep);
  }
  
  glEnd();
  
  glPopMatrix();

}

void MidiVizEQWatcher::setBandsReference(float* bands, int* rands){
  eq_bands = bands;
  mRandomNumbers = rands;
}

void MidiVizEQWatcher::animateDiscs(){
  
  for(int i = 0; i < NUM_BANDS; i++){
    if (eq_bands[i] > .96){
      discAngles[i] = eq_bands[i];
      discAccel[i] = eq_bands[i];
      discColor[i] = eq_bands[i];
      discflip[i] *= -1;
    }
    
    discAngles[i] += discAccel[i]*15.0*discflip[i];

    if (discAccel[i] > .02){
      discAccel[i] *= .995;
    }

    if (discAngles[i] > .02){ 
      discAngles[i] *= .90;
    }

    if (discColor[i] > .02){
      discColor[i] *= .90;
    }
   
  }
}

void MidiVizEQWatcher::drawDiscRoom(){

  int roomsize = 30;
  float currenty = 0, lasty = 0;
  float ystep = (float) roomsize/(float) NUM_BANDS;

  animateDiscs();

  float incolor[3];
  float outcolor[3];

  glPushMatrix();
  glTranslatef(position[0], position[1], position[2]);
  glRotatef(rotation[2], 0.0, 0.0, 1.0);
  glRotatef(rotation[1], 0.0, 1.0, 0.0);
  glRotatef(rotation[0], 1.0, 0.0, 0.0);
  glScalef(scale[0], scale[1], scale[2]);

  for (int i = 0; i < NUM_BANDS-1; i++){
    lasty = currenty;
    currenty += ystep;
    
    incolor[0] = incolor[1] = incolor[2] = (eq_bands_slow_avg[i] *.98 + .02);
    outcolor[0] = outcolor[1] = outcolor[2] = (eq_bands_slow_avg[i+1]*.98 + .02);
    
    // draw three walls

    glBegin(GL_QUAD_STRIP);
    //    glNormal3f(-1,eq_bands[i],eq_bands[i]);
    glColor3fv(outcolor);
    glVertex3f(roomsize, currenty, 0);
    //glNormal3f(-1,eq_bands[i+1],eq_bands[i+1]);
    glColor3fv(incolor);
    glVertex3f(roomsize, lasty, 0);

    //glNormal3f(-1,eq_bands[i],-1);
    glColor3fv(outcolor);
    glVertex3f(roomsize, currenty, -roomsize);
    //glNormal3f(-1,eq_bands[i+1],-1);
    glColor3fv(incolor);
    glVertex3f(roomsize, lasty, -roomsize);

    //glNormal3f(1,eq_bands[i],-1);
    glColor3fv(outcolor);
    glVertex3f(-roomsize, currenty, -roomsize);
    //glNormal3f(1,eq_bands[i+1],-1);
    glColor3fv(incolor);    
    glVertex3f(-roomsize, lasty, -roomsize);
    
    //glNormal3f(1,eq_bands[i],eq_bands[i]);
    glColor3fv(outcolor);
    glVertex3f(-roomsize, currenty, 0);
    //glNormal3f(1,eq_bands[i+1],eq_bands[i+1]);
    glColor3fv(incolor);
    glVertex3f(-roomsize, lasty, 0);

    glEnd();

    // ceiling

    glBegin(GL_POLYGON);
    glColor3fv(outcolor);
    //glNormal3f(eq_bands[i],-1,eq_bands[i]);
    glVertex3f(roomsize, -ystep, -currenty);
    glVertex3f(-roomsize, -ystep, -currenty);
    glColor3fv(incolor);
    //glNormal3f(eq_bands[i+1],-1,eq_bands[i+1]);
    glVertex3f(-roomsize, -ystep, -lasty);
    glVertex3f(roomsize, -ystep, -lasty);
    glEnd();

    //    floor
    glBegin(GL_POLYGON);
    glColor3fv(outcolor);
    //glNormal3f(eq_bands[i],1,eq_bands[i]);
    glVertex3f(roomsize, roomsize, -currenty);
    glVertex3f(-roomsize, roomsize, -currenty);
    glColor3fv(incolor);
    //glNormal3f(eq_bands[i+1],-1,eq_bands[i+1]);
    glVertex3f(-roomsize, roomsize, -lasty);
    glVertex3f(roomsize, roomsize, -lasty);
    glEnd();
  }

 // draw large disc
  
  float discScale;

  float xdiscpos;

  for (int i  = 0; i < NUM_BANDS; i++){

    xdiscpos = -(float)i*1.6;

    if (i%2 == 0){ // even odd placement
      xdiscpos *= -1;
    }
    
    discScale = 2.0/(sqrt((float)i));

    glPushMatrix();
    glColor3f(discColor[i], discColor[i], discColor[i]);
    glTranslatef(xdiscpos, roomsize*0.4-i*.2, -roomsize*.5+i*.5);
    glScalef(discScale,discScale,discScale);
    glRotatef(discAngles[i], 0,1,0);
    drawDisc();
    glPopMatrix();

  }


  glPopMatrix(); // scene transformation
}

void MidiVizEQWatcher::contextInit(){

  contextData->diskQuadric = gluNewQuadric();

  // --- Allocate context specific data --- //
  contextData->displayList = glGenLists(1);

  glNewList(contextData->displayList, GL_COMPILE);
  gluDisk(contextData->diskQuadric, .25, 1,  24 /* slices */, 24 /*stacks*/);
  glEndList();

}

void MidiVizEQWatcher::drawDisc(){
  glCallList(contextData->displayList);
}


void MidiVizEQWatcher::drawWaterFountain(){


  float height = 16;
  float ystep = height/(float) NUM_BANDS;
  float currenty = 0;
  float lasty = currenty;

  float width = 25;
  float widthstep = width / (float) NUM_BANDS;
  float currentwidth = width;
  float lastwidth = currentwidth;

  float incolor[3];
  float* incolor_vec;

  for (int j = 0; j < NUM_BANDS; j++){

    lasty = currenty;
    currenty +=ystep;

    lastwidth = currentwidth;
    currentwidth -= widthstep;
    //    float tempcolor;

    incolor_vec = waterfallLookup.getValue(eq_bands_slow_avg[j]);
    incolor[0] = incolor_vec[0];
    incolor[1] = incolor_vec[1];
    incolor[2] = incolor_vec[2];

    //   incolor[0] = incolor_vec[0];
    //    tempcolor = incolor_vec[1];
    //    incolor[1] = incolor_vec[2]/2.0;
    //    incolor[2] = tempcolor;

    //
    glBegin(GL_QUAD_STRIP);
    glNormal3f(eq_bands[j],1,eq_bands[j]);
    glColor3fv(incolor);
    for (int i =0; i < 360; i+=2){
      glVertex3f(orbitCoordinates[i][0]*currentwidth,  currenty, 
		 orbitCoordinates[i][1]*currentwidth);
      glVertex3f(orbitCoordinates[i][0]*lastwidth,  currenty, 
		 orbitCoordinates[i][1]*lastwidth);
    }
    glVertex3f(orbitCoordinates[0][0]*currentwidth,  currenty, 
	       orbitCoordinates[0][1]*currentwidth);
    glVertex3f(orbitCoordinates[0][0]*lastwidth,  currenty, 
	       orbitCoordinates[0][1]*lastwidth);
    
    glEnd();

    // innerstrip
    glBegin(GL_QUAD_STRIP);
    glColor3fv(incolor);

    for (int i =0; i < 360; i+=2){
      glNormal3f(-orbitCoordinates[i][0], 0, -orbitCoordinates[i][1]);
      glVertex3f(orbitCoordinates[i][0]*currentwidth, currenty, 
		 orbitCoordinates[i][1]*currentwidth);
      glVertex3f(orbitCoordinates[i][0]*currentwidth, lasty, 
		 orbitCoordinates[i][1]*currentwidth);
    }
    glNormal3f(-orbitCoordinates[0][0], 0, -orbitCoordinates[0][1]);
    glVertex3f(orbitCoordinates[0][0]*currentwidth, currenty, 
	       orbitCoordinates[0][1]*currentwidth);
    glVertex3f(orbitCoordinates[0][0]*currentwidth, lasty, 
	       orbitCoordinates[0][1]*currentwidth);
    glEnd();
    
    // innerstrip
    glBegin(GL_QUAD_STRIP);
    glColor3fv(incolor);
    for (int i =0; i < 360; i+=2){
      glNormal3f(orbitCoordinates[i][0], 0, orbitCoordinates[i][1]);
      glVertex3f(orbitCoordinates[i][0]*lastwidth, currenty, orbitCoordinates[i][1]*lastwidth);
      glVertex3f(orbitCoordinates[i][0]*lastwidth, lasty, orbitCoordinates[i][1]*lastwidth);
    }
    glNormal3f(orbitCoordinates[0][0], 0, orbitCoordinates[0][1]);
    glVertex3f(orbitCoordinates[0][0]*lastwidth, currenty, orbitCoordinates[0][1]*lastwidth);
    glVertex3f(orbitCoordinates[0][0]*lastwidth, lasty, orbitCoordinates[0][1]*lastwidth);

    glEnd();
  }
  
  
  // animate particles
  float* test_pos;  
  float* test_vel;
  float distance;
  float floorlevel;
  float bounce  = .5;
  
  for (int i = 0; i < NUM_BANDS; i++){
    for (int j = 0; j < NUM_PARTICLES; j++){
      if (waterParticles[i][j].isMoving()){
	waterParticles[i][j].step(.3);
	
	test_pos=waterParticles[i][j].getPosition();
	test_vel = waterParticles[i][j].getVelocity();
	// if below the ground then stop
	
	distance = (sqrt(test_pos[0] * test_pos[0] + test_pos[2] * test_pos[2]));	
	floorlevel = height+1 - (ceil(ystep * distance/widthstep));
	
	if ((test_pos[1] < floorlevel)){
	  waterParticles[i][j].setPosition(test_pos[0], floorlevel, test_pos[2]);
	  waterParticles[i][j].setVelocity(test_vel[0]*1.1, 
					   -1* bounce * test_vel[1], 
					   test_vel[2]*1.1);
	} 

	if (distance >  width + widthstep){
	  waterParticles[i][j].stop();
	}
      }
    }
  }
  
  int startangle;
  float startpos[3];

  // start new  particles
  for(int i = 0; i < NUM_BANDS; i++){

    if (eq_bands_avg[i] > .50){ // issue the next particle
     
      startangle = rand()%360;
      startpos[0] = (width-((float) i)*widthstep) * orbitCoordinates[startangle][0];
      startpos[1] = ((float)i)*ystep;
      startpos[2] = (width-((float) i)*widthstep) * orbitCoordinates[startangle][1];

      //      cout << "Start pos = " << startpos[0] << " " <<  startpos[1] << " " <<  startpos[2] << endl;

      waterParticles[i][nextParticle[i]].setPosition(startpos[0], startpos[1],  startpos[2]);
      waterParticles[i][nextParticle[i]].setVelocity(orbitCoordinates[startangle][0]/3.0, 
						     eq_bands_avg[i]*20, 
						     orbitCoordinates[startangle][1]/3.0);
      waterParticles[i][nextParticle[i]].setAcceleration(0, -9.8, 0);
      
      incolor_vec = waterfallLookup.getValue(eq_bands[i]);

      incolor[0] = incolor_vec[0];
      incolor[1] = incolor_vec[1];
      incolor[2] = incolor_vec[2];

      waterParticles[i][nextParticle[i]].setColor(incolor[0], incolor[1], incolor[2]);
      waterParticles[i][nextParticle[i]].start();
      
      // advance ot the next particle in line

      nextParticle[i]++;
      if (nextParticle[i] >= NUM_PARTICLES){
	nextParticle[i] = 0;
      }
    }
  }
  
  // draw particles
  for (int i = 0; i < NUM_BANDS; i++){
    for (int j = 0; j < NUM_PARTICLES; j++){
      if (waterParticles[i][j].isMoving()){
	waterParticles[i][j].draw(1);
      }
    }
  } 
}

void MidiVizEQWatcher::drawWaterfall(){
 
  float incolor[3];
  float* incolor_vec;

  float outcolor[3];
  float* outcolor_vec;

  int beginhistory;
  float zstep = .2;
  float zval = -4;
  float lastz= zval;
  
  float ineqval, outeqval;


  glPushMatrix();
  glTranslatef(position[0], position[1], position[2]);
  glRotatef(rotation[2], 0.0, 0.0, 1.0); 
  glRotatef(rotation[1], 0.0, 1.0, 0.0); 
  glRotatef(rotation[0], 1.0, 0.0, 0.0); 
  glScalef(scale[0], scale[1], scale[2]);
 
  
  for (int j = 0; j < HISTORY_LENGTH; j++){
    lastz = zval;
    zval += zstep;
    
    beginhistory = j + history_index;
    if ( beginhistory > HISTORY_LENGTH) beginhistory -= HISTORY_LENGTH;
    
    glBegin(GL_QUAD_STRIP);
    
    for(int i  = 0; i < NUM_BANDS; i++){
      ineqval = eq_bands_history[i][beginhistory];	  
      outeqval = eq_bands_history[i][beginhistory];	  
      
      incolor_vec = waterfallLookup.getValue(ineqval);
      incolor[0] = incolor_vec[0];
      incolor[1] = incolor_vec[1];
      incolor[2] = incolor_vec[2];
      
      outcolor_vec = waterfallLookup.getValue(outeqval);
      outcolor[0] = outcolor_vec[0];
      outcolor[1] = outcolor_vec[1];
      outcolor[2] = outcolor_vec[2];
      
      glColor3fv(incolor);
      glVertex3f(i*2.5 - 20,  0, zval);
      glColor3fv(outcolor);
      glVertex3f(i*2.5 - 20, 0, lastz);
    }
    glEnd();
  }
}

void MidiVizEQWatcher::drawInverse(){
  

  float incolor[3];
  float* incolor_vec;

  glPushMatrix();
  
  glTranslatef(position[0], position[1], position[2]);
  glRotatef(rotation[2], 0.0, 0.0, 1.0);
  glRotatef(rotation[1], 0.0, 1.0, 0.0);
  glRotatef(rotation[0], 1.0, 0.0, 0.0);
  glScalef(scale[0], scale[1], scale[2]);    
 
  for (int i = 0; i < NUM_BANDS; i++){

  glBegin(GL_LINE_STRIP); 

  incolor_vec = waterfallLookup.getValue(eq_bands_diff[i]);
  incolor[0] = incolor_vec[0];
  incolor[1] = incolor_vec[1];
  incolor[2] = incolor_vec[2];

  glColor3f(incolor[0], incolor[1], incolor[2]);
  glEnd();
  }

  glPopMatrix();




}

