// MidiVizDualHistory
// Lew Hill II
//
// storage for all midi and realtime audio information

#include "MidiVizDualHistory.h"

MidiVizDualHistory::MidiVizDualHistory(){

  history_index = 0;
  timed_event_index = 0;

  for (int k = 0; k < DUAL_HISTORY_LENGTH; k++){
   for (int i = 0; i < 128; i++){
      noteValues[i][k] = 0;
    }
    
    for (int j = 0; j < NUM_BANDS; j++){
      eqHistory[j][k] = 0;
      eqTotal[j][k] = 0;
    }
  }
  
  initAngles();
  initPhotisms();

}

void MidiVizDualHistory::initAngles(){

  float radians;
  float angle;
  float audio_angle_step = 90.0/16.0;
  int debug = 0;

  for (int k = 0; k < 16; k++){
    angle = k * audio_angle_step;
    radians = angle * MV_PI_RAD;
    mandalaAudioCdts[k][0] = cos(radians);
    mandalaAudioCdts[k][1] = sin(radians);

    if (debug){
      cout << "audio k = " << k << " " << angle << " " << radians << " "
	   << mandalaAudioCdts[k][0] << " " << mandalaAudioCdts[k][1] << endl;
    }
  }


  // init circle of fifths angles
  
  mandalaMidiCdts[0][2] = 0;    /* C  */
  mandalaMidiCdts[1][2] = 150;  /* Db */
  mandalaMidiCdts[2][2] = 300;  /* D  */
  mandalaMidiCdts[3][2] = 90;   /* Eb */
  mandalaMidiCdts[4][2] = 240;  /* E  */
  mandalaMidiCdts[5][2] = 30;   /* F  */
  mandalaMidiCdts[6][2] = 180;  /* Gb */
  mandalaMidiCdts[7][2] = 330;  /* G  */
  mandalaMidiCdts[8][2] = 120;  /* Ab */
  mandalaMidiCdts[9][2] = 270;  /* A  */
  mandalaMidiCdts[10][2] = 60;  /* Bb */
  mandalaMidiCdts[11][2] = 210; /* B  */

  for (int k = 0; k < 12; k++){
    angle = mandalaMidiCdts[k][2]; // angle
    radians = (angle +90) * MV_PI_RAD;
    mandalaMidiCdts[k][0] = cos(radians);
    mandalaMidiCdts[k][1] = sin(radians);
    
    if (debug) {
      cout << "midi k = " << k << " " << angle << " " << radians << " " 
	   << mandalaMidiCdts[k][0] << " " << mandalaMidiCdts[k][1] << endl;
    }
  }
}

void MidiVizDualHistory::storeSample(float *eq_vals){
  float tot = 0;

  for (int i = 0; i < NUM_BANDS; i++){
    eqHistory[i][history_index] = eq_vals[i];
    tot += eq_vals[i];
    eqTotal[i][history_index] = tot;

    // get time and store it.
    timeval time;
    gettimeofday(&time, NULL);
    unsigned long systemtime = time.tv_usec/1000 + time.tv_sec*1000;
    recvTimeMillis[history_index] = systemtime;
    //    cout << "simulation time = " << systemtime << endl;
  }

  nextFrame();  // must advance with each audio frame
}

void MidiVizDualHistory::processMidiEvent(MidiEvent event){

  int note = event.getNote() % 128;
  int velocity = event.getVelocity();

  //  cout << "event note %12 =  " << event.getNote() % 12 << endl;

  noteValues[note][history_index] = velocity;

  if (velocity != 0){
    noteAttacks[note][history_index] = velocity;
    timedEventIndex[note][history_index] = timed_event_index;

    // add timedEventQueueInformation
    // advance indices

    timedEventQueue[timed_event_index].copyEvent(event);
    timed_event_index++;
    if (timed_event_index > TIMED_EVENT_HISTORY_LENGTH){
      timed_event_index -= TIMED_EVENT_HISTORY_LENGTH;
    }

  }
    //  event.printData();
}

void MidiVizDualHistory::initPhotisms(){
  
  for (int i = 0; i < 16; i++){
    
    photismColor[i][0] = photismColor[i][1] =  photismColor[i][2] = 0.0;
    photismPosition[i][0] = photismPosition[i][1] = photismPosition[i][2] = 0;  
    photismScale[i] = 0;         
    photismType[i] = 0;           
  }
  
}

void MidiVizDualHistory::processCCEvent(MidiEvent event){
  
  // float photismColor[16][3];        // radium slider 1,2,3 = r,g,b
  // float photismPosition[16][3];     // radium slider 4,5,6 = x,y,z
  // float photismScale[16];           // radium slider 7 = scale
  // float photismType[16];            // radium slider 8 = type;

  int channel =  event.getChannel() % 16;
  int controllerValue = event.getControllerValue();

  // r g b
  if (event.isRadiumSlider1()){
    photismColor[channel][0] = controllerValue;
    
  } else if (event.isRadiumSlider2()){
    photismColor[channel][1] = controllerValue;
    
  } else if (event.isRadiumSlider3()){
    photismColor[channel][2] = controllerValue;
    
    // x y z
  } else if (event.isRadiumSlider4()){
    photismPosition[channel][0] = controllerValue;
    
  } else if (event.isRadiumSlider5()){
    photismPosition[channel][1] = controllerValue;

  } else if (event.isRadiumSlider6()){
    photismPosition[channel][2] = controllerValue;

    // scale 
  } else if (event.isRadiumSlider7()){
    photismScale[channel] = controllerValue;

    // type
  } else if (event.isRadiumSlider8()){
    photismType[channel] = controllerValue;
  }

  // print out photisms
}
 

void MidiVizDualHistory::printPhotisms(int channel){
  
 int  i = channel % 16;

  cout << "channel = " << i  << " r,g,b= " 
       << photismColor[i][0] << " " 
       << photismColor[i][1] << " " 
       << photismColor[i][2] 
       << " x,y,z= "      
       << photismPosition[i][0] << " "
       << photismPosition[i][1] << " "
       << photismPosition[i][2] 
       << " scale = " << photismScale[i]
       << " type = " << photismType[i] 
       << endl;
  
}


void MidiVizDualHistory::print(){
  //print last frame

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

    cout << "j = " << j << " ";
    cout << "midi: "; 
    for (int i = 0; i < 128; i++){
      cout << noteValues[i][j];
    }
    cout << endl;
    
    cout << "fft: ";
    for (int i = 0; i < 16; i++){
      cout << eqHistory[i][j] << " ";
    }
    cout << endl;
  }
}

void MidiVizDualHistory::nextFrame(){

  // copy ahead midi values to next frame
  int new_history_index = (history_index + 1) % DUAL_HISTORY_LENGTH;
  
    for (int i = 0; i < 127; i++) {
      noteValues[i][new_history_index] = noteValues[i][history_index];
      noteAttacks[i][new_history_index] = 0;
      timedEventIndex[i][history_index] = 0;
    }

  history_index = new_history_index;

  // clear old history setting... kill eq echoes
  for (int i = 0; i < 16; i++){
    eqHistory[i][history_index] = 0;
    eqTotal[i][history_index] = 0;
  }

  //  print();
}

void MidiVizDualHistory::drawDualHistoryVolume(int mode){

  if (mode == 0) {
    drawEqVsMidi();

  } else if (mode == 1){
    drawPitchVSTime();
 
  } else if (mode == 2){
    drawEqMidiBlocks();
  
  } else if (mode == 3){
    drawSMET();
  
  } else if (mode == 4){
    drawCaptain();

  } else if (mode == 5){
    drawCentralRadiation();

  } else if (mode == 6){
    drawRiver();

  } else if (mode == 7){
    //    drawPhotisms();
    drawMandala();
  }

}

void MidiVizDualHistory::drawEqVsMidi(){ 
// matrix blocks

  int beginhistory;
  float eqval;
  int midival;
  float color[3];
  float* colorvec;

  float xscale, yscale, zscale;
  float xpos, ypos, zpos;
  float colorAttenuation;

  drawbox(.2, -.2, .2, -.2, .2, -.2, GL_QUADS);

  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]);
  
  drawAxes();

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

    beginhistory = history_index - j ;

    if ( beginhistory < 0){
      beginhistory += DUAL_HISTORY_LENGTH;
    }
    
    colorAttenuation = 1-j/((float) DUAL_HISTORY_LENGTH);

    for(int k  =0; k < 127; k++){
      midival = noteValues[k][beginhistory]; 
      
      if (midival > 0){
	
	//	cout << " history index , midi note, val " 
	//     << " " << j << " " << k << " " << midival <<  endl;  
	
	for(int i  = 0; i < NUM_BANDS; i++){
	  
	  eqval = eqHistory[i][beginhistory];        
	  
	  if (eqval > .15){
	    
	    // width by eq value
	    xscale =  eqval;
	  // vertical size by midi strength
	    yscale = midival / 127.0;
	    // unused
	    zscale = 1.0;
	    
	    // horiz spacing by eq band
	    xpos = (i+1)*2;                                 
	    // vertical spacing by midi note
	    ypos = k *.4;                
	    // depth by history index
	    zpos = -j*.5 ;
	   	 
	    colorvec = rainbowLookup.getValue(eqval);
	    color[0] = colorvec[0] * colorAttenuation;
	    color[1] = colorvec[1] * colorAttenuation;
	    color[2] = colorvec[2] * colorAttenuation;
	    glColor3fv(color);
	    
	    glPushMatrix();
	    glTranslatef(xpos, ypos, zpos);
	    glBegin(GL_POLYGON);
	    glVertex3f(-xscale, -yscale, 0);
	    glVertex3f(xscale, -yscale, 0);  
	    glVertex3f(xscale, yscale, 0);  
	    glVertex3f(-xscale,yscale, 0);
	    glEnd();
	    
	    glPopMatrix();
	    
	    // invert A
	    glPushMatrix();
	    glTranslatef(-xpos, ypos, zpos );
	    glBegin(GL_POLYGON);
	    glVertex3f(-xscale, -yscale, 0);
	    glVertex3f(xscale, -yscale, 0);  
	    glVertex3f(xscale, yscale, 0);  
	    glVertex3f(-xscale,yscale, 0);
	    glEnd();
	    glPopMatrix();
	    
	    // invert B
	    glPushMatrix();
	    glTranslatef(-xpos, -ypos, zpos );
	    glBegin(GL_POLYGON);
	    glVertex3f(-xscale, -yscale, 0);
	    glVertex3f(xscale, -yscale, 0);  
	    glVertex3f(xscale, yscale, 0);  
	    glVertex3f(-xscale,yscale, 0);
	    glEnd();
	    glPopMatrix();
	    
	    // invert C
	    glPushMatrix();
	    glTranslatef(xpos, -ypos, zpos );
	    glBegin(GL_POLYGON);
	    glVertex3f(-xscale, -yscale, 0);
	    glVertex3f(xscale, -yscale, 0);  
	    glVertex3f(xscale, yscale, 0);  
	    glVertex3f(-xscale,yscale, 0);
	    glEnd();
	    glPopMatrix();
	    
	  }  //if eq val
	} //i
      } //if midi
    } //k
  } // j
  
  glPopMatrix();   // placement transform

}

void MidiVizDualHistory::drawPitchVSTime(){
 
  // colored horse shoes man...

  int beginhistory;
  float eqval;
  int midival;
  float color[3]  = {0,0,0};
  float* colorvec;

  float xscale, yscale, zscale;
  float xpos, ypos, zpos;
  float colorAttenuation;
  float eqtot;

  drawbox(.2, -.2, .2, -.2, .2, -.2, GL_QUADS);

  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]);

  drawAxes();

  for (int j = 0; j < DUAL_HISTORY_LENGTH; j++){
    beginhistory = history_index - j ;

    if ( beginhistory < 0){
      beginhistory += DUAL_HISTORY_LENGTH;
    }

    for(int k = 0; k < 127; k++){

      midival = noteValues[k][beginhistory];

      if (midival > 0){

        //      cout << " history index , midi note, val "
        //     << " " << j << " " << k << " " << midival <<  endl;

	color[0] = color[1] = color[2] = 0;
	eqtot = .01;

        for(int i  = 0; i < NUM_BANDS; i++){
	  // iterate over all eq entries and compute the color for the blocks.

          eqval = eqHistory[i][beginhistory];
	  eqval *= eqval;
	  eqtot += eqval;
          colorAttenuation = eqval;
          colorvec = eqLookup.getValue(i);

          color[0] += (colorvec[0] * colorAttenuation);
          color[1] += (colorvec[1] * colorAttenuation);
          color[2] += (colorvec[2] * colorAttenuation);

	}	 

	
	color[0] = color[0] / ((float) NUM_BANDS/2);
	color[1] = color[1] / ((float) NUM_BANDS/2);
	color[2] = color[2] / ((float) NUM_BANDS/2);
	

	// width by eq value
	xscale =  1;
	// vertical size by midi strength
	yscale = midival *.025;
	// unused
	zscale = 1.0;
	
	// horiz spacing by eq band
	xpos = j;
	// vertical spacing by midi note
	ypos = k *.6;
	// depth by history index
	zpos = ((j*j)*.04 - DUAL_HISTORY_LENGTH *.5);
	
	/*	cout << " j= " << j << " k= "<< k <<
	  " xpos= " << xpos << " ypos= " << ypos << " zpos= " << zpos << 
	  " color = " << color[0] << " " <<  color[1] << " " << color[2] << endl;
	*/

	glColor3fv(color);
	
	glPushMatrix();
	glTranslatef(xpos, ypos, zpos);
	glBegin(GL_POLYGON);
	glVertex3f(-xscale, -yscale, 0);
	glVertex3f(xscale, -yscale, 0);
	glVertex3f(xscale, yscale, 0);
	glVertex3f(-xscale,yscale, 0);
	glEnd();
	glPopMatrix();
	
	// invert A
	glPushMatrix();
	glTranslatef(-xpos, ypos, zpos );
	glBegin(GL_POLYGON);
	glVertex3f(-xscale, -yscale, 0);
	glVertex3f(xscale, -yscale, 0);
	glVertex3f(xscale, yscale, 0);
	glVertex3f(-xscale,yscale, 0);
	glEnd();
	glPopMatrix();

	// invert B
	glPushMatrix();
	glTranslatef(-xpos, -ypos, zpos );
	glBegin(GL_POLYGON);
	glVertex3f(-xscale, -yscale, 0);
	glVertex3f(xscale, -yscale, 0);
	glVertex3f(xscale, yscale, 0);
	glVertex3f(-xscale,yscale, 0);
	glEnd();
	glPopMatrix();

	// invert C
	glPushMatrix();
	glTranslatef(xpos, -ypos, zpos );
	glBegin(GL_POLYGON);
	glVertex3f(-xscale, -yscale, 0);
	glVertex3f(xscale, -yscale, 0);
	glVertex3f(xscale, yscale, 0);
	glVertex3f(-xscale,yscale, 0);
	glEnd();
	glPopMatrix();


	// transpose invert x/y

	glPushMatrix();
	glTranslatef(ypos, xpos, zpos);
	glBegin(GL_POLYGON);
	glVertex3f(-xscale, -yscale, 0);
	glVertex3f(xscale, -yscale, 0);
	glVertex3f(xscale, yscale, 0);
	glVertex3f(-xscale,yscale, 0);
	glEnd();
	glPopMatrix();
	
	// transpose invert A
	glPushMatrix();
	glTranslatef(-ypos, xpos, zpos );
	glBegin(GL_POLYGON);
	glVertex3f(-xscale, -yscale, 0);
	glVertex3f(xscale, -yscale, 0);
	glVertex3f(xscale, yscale, 0);
	glVertex3f(-xscale,yscale, 0);
	glEnd();
	glPopMatrix();

	// transpose invert B
	glPushMatrix();
	glTranslatef(-ypos, -xpos, zpos );
	glBegin(GL_POLYGON);
	glVertex3f(-xscale, -yscale, 0);
	glVertex3f(xscale, -yscale, 0);
	glVertex3f(xscale, yscale, 0);
	glVertex3f(-xscale,yscale, 0);
	glEnd();
	glPopMatrix();

	// transpose invert C
	glPushMatrix();
	glTranslatef(ypos, -xpos, zpos );
	glBegin(GL_POLYGON);
	glVertex3f(-xscale, -yscale, 0);
	glVertex3f(xscale, -yscale, 0);
	glVertex3f(xscale, yscale, 0);
	glVertex3f(-xscale,yscale, 0);
	glEnd();
	glPopMatrix();
	
	
      } // k
    }
  } // j
  
  glPopMatrix();
}

void MidiVizDualHistory::drawEqMidiBlocks(){
  
  int beginhistory;
  float eqval;
  int midival;
  float color[3]  = {0,0,0};
  float *colorvechigh, *colorveclow;
  float colorAttenuation;
  float maxeqindex;
  float maxeq;

  float xscale, yscale, zscale;
  float xpos, ypos, zpos;

  float eqtot = 0;
  float eqwttot = 0; // tally of eqband*i...
  float eqwtavg = 0; // sum of eqband*i   divided by 16 bands

  drawbox(.2, -.2, .2, -.2, .2, -.2, GL_QUADS);

  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]);

  drawAxes();

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

    beginhistory = history_index - j ;

    if ( beginhistory < 0){
      beginhistory += DUAL_HISTORY_LENGTH;
    }

    for(int k = 0; k < 127; k++){

      eqtot = .01;
      eqwttot = 0;
      midival = noteValues[k][beginhistory];
      
      if (midival > 0){
	
	//	cout << " history index , midi note, val "
	//  << " " << j << " " << k << " " << midival <<  endl;

	maxeq = 0;
	maxeqindex = 0;

	for(int i  = 0; i < NUM_BANDS; i++){
          // iterate over all eq entries 
	  // compute the weighted average center positon
	  // and the total eq value
	  
	  eqval = eqHistory[i][beginhistory];
	  eqtot += eqval;
	  eqwttot += i * eqval;

	  if (maxeq < eqval){
	    maxeqindex = i;
	    maxeq = eqval;
	  }
        }
	
	eqwtavg = (eqwttot)/(eqtot);
	
	colorvechigh = eqLookup.getValue((int) (floorf( eqwtavg)));
	colorveclow = eqLookup.getValue((int) (ceilf( eqwtavg)));

	float t = eqwtavg - floor(eqwtavg);
	colorAttenuation =  1- j/((float) DUAL_HISTORY_LENGTH);       

	color[0] = (colorveclow[0] * t) + (colorvechigh[0] * (1-t));
	color[1] = (colorveclow[1] * t) + (colorvechigh[1] * (1-t));
	color[2] = (colorveclow[2] * t) + (colorvechigh[2] * (1-t));
	
	color[0] *= colorAttenuation;
	color[1] *= colorAttenuation;
	color[2] *= colorAttenuation;

	// width by eq value
        xscale =  eqtot/2.0;
        // vertical size by midi strength
        yscale = midival *.02;
        // unused
        zscale = 1.0;
	
        // horiz spacing by eq band
        xpos = (maxeqindex *1.5)  + j*.004;
        // vertical spacing by midi note
        ypos = k*.4;
        // depth by history index
        zpos = -j*.5;
	
        /*
	  cout << " j= " << j << " k= "<< k <<
	  " xpos= " << xpos << " ypos= " << ypos << " zpos= " << zpos <<
	  " color = " << color[0] << " " <<  color[1] << " " << color[2] <<
	  endl;
	*/
	
        glColor3fv(color);
		
        glPushMatrix();
        glTranslatef(xpos, ypos, zpos);
        glBegin(GL_POLYGON);
        glVertex3f(-xscale, -yscale, 0);
        glVertex3f(xscale, -yscale, 0);
        glVertex3f(xscale, yscale, 0);
        glVertex3f(-xscale,yscale, 0);
        glEnd();
	
        glPopMatrix();
	
        // invert A
        glPushMatrix();
        glTranslatef(-xpos, ypos, zpos );
        glBegin(GL_POLYGON);
        glVertex3f(-xscale, -yscale, 0);
        glVertex3f(xscale, -yscale, 0);
        glVertex3f(xscale, yscale, 0);
        glVertex3f(-xscale,yscale, 0);
        glEnd();
        glPopMatrix();

        // invert B
        glPushMatrix();
        glTranslatef(-xpos, -ypos, zpos );
        glBegin(GL_POLYGON);
        glVertex3f(-xscale, -yscale, 0);
        glVertex3f(xscale, -yscale, 0);
        glVertex3f(xscale, yscale, 0);
        glVertex3f(-xscale,yscale, 0);
        glEnd();
        glPopMatrix();

        // invert C
        glPushMatrix();
        glTranslatef(xpos, -ypos, zpos );
        glBegin(GL_POLYGON);
        glVertex3f(-xscale, -yscale, 0);
        glVertex3f(xscale, -yscale, 0);
        glVertex3f(xscale, yscale, 0);
        glVertex3f(-xscale,yscale, 0);
        glEnd();
        glPopMatrix();




	
      } // k
    }
  } // j
  
  glPopMatrix();
}


void MidiVizDualHistory::drawSMET(){

  int beginhistory;
  float eqval;
  int midival;
  float color[3]  = {0,0,0};
  float* colorvec;

  float xscale, yscale, zscale;
  float xpos, ypos, zpos;

  drawbox(.2, -.2, .2, -.2, .2, -.2, GL_QUADS);

  glLineWidth(1.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]/2.0, scale[1]/2.0, scale[2]/2.0);
  
  drawAxes();
  
  // piano

  glPushMatrix();
  glScalef(1.15, 2.1, 1);
  glTranslatef(-43.5, 5.2, 0);
  drawPiano();
  glPopMatrix();

  glPushMatrix();
  glScalef(-3.3, 3.5, 1);
  glTranslatef(-15,0,0);
  drawBass();
  glPopMatrix();

  // draw line guides
  double line_length = DUAL_HISTORY_LENGTH/2.0; 
  
  for(int k = 21; k < 108; k++){ // over midi range
    colorvec = note_color_table.getValue(k%12);
    color[0] = colorvec[0];
    color[1] = colorvec[1];
    color[2] = colorvec[2];
    
    glColor3fv(color);
    glBegin(GL_LINES);
    glVertex3f(-line_length, k, -0.1);
    glVertex3f(line_length, k, -0.1);
    glEnd();
  }

  for (int j = 0; j < DUAL_HISTORY_LENGTH; j++){
    beginhistory = history_index - j ;

    if ( beginhistory < 0){
      beginhistory += DUAL_HISTORY_LENGTH;
    }

    // draw eq data
    for(int i  = 0; i < NUM_BANDS; i++){
    
      eqval = eqHistory[i][beginhistory];
  
      if (eqval > .05){

	color[0] = 1-eqval;
	color[1] = 1-eqval;
	color[2] = 1-eqval;
	
	xscale = .5;
	yscale = .5;
	zscale = 1;
	
	xpos = DUAL_HISTORY_LENGTH/2 - j;
	ypos = i*0.5-16;
	zpos = 0;
	
	glColor3fv(color);
	glPushMatrix();
	glTranslatef(xpos, ypos, zpos);
	glBegin(GL_POLYGON);
	glVertex3f(xscale, yscale, 0);
	glVertex3f(xscale, -yscale, 0);
	glVertex3f(-xscale, -yscale, 0);
	glVertex3f(-xscale, yscale, 0);
	glEnd();
	glPopMatrix();
      }
    }
    
      // draw midi data
    for(int k = 0; k < 127; k++){ // over midi range

      midival = noteValues[k][beginhistory];

      if (midival == 0){
	midival = noteAttacks[k][beginhistory];
      }	
	
      if (midival > 0){

	  colorvec = note_color_table.getValue(k%12);

	  color[0] = colorvec[0];
	  color[1] = colorvec[1];
	  color[2] = colorvec[2];

	  // uniform size
	  xscale =  .5;
	  yscale = .5 * (float) midival/128.0;
	  zscale = 1;

	  // boxes scroll outward with time
	  // height = pitch
	  xpos = DUAL_HISTORY_LENGTH/2 - j;
	  ypos = k;
	  zpos = 0;

	  glColor3fv(color);

	  if (noteAttacks[k][beginhistory] > 0){
	    glBegin(GL_LINES);
	    glVertex3f(xpos, ypos+5, 0);
	    glVertex3f(xpos, ypos-5, 0);
	    glEnd();
	  }	    

	  glPushMatrix();
	  glTranslatef(xpos, ypos, zpos);
	  glBegin(GL_POLYGON);
	  glVertex3f(xscale, yscale, 0);
	  glVertex3f(xscale, -yscale, 0);
	  glVertex3f(-xscale, -yscale, 0);
	  glVertex3f(-xscale, yscale, 0);
	  glEnd();
	  glPopMatrix();
      }
    }
  }
}


void MidiVizDualHistory::drawCaptain(){

  int beginhistory;
  float eqval;
  int midival;
  float color[3]  = {0,0,0};
  float* colorvec;

  float xscale, yscale, zscale;
  float xpos, ypos, zpos;

  drawbox(.2, -.2, .2, -.2, .2, -.2, GL_QUADS);

  glLineWidth(1.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]/2.0, scale[1]/2.0, scale[2]/2.0);

  drawAxes();

    // draw line guides
  
  double line_length = DUAL_HISTORY_LENGTH/2.0; 

  for(int k = 0; k < 12; k++){ // only 12 for percussion sim
    
    color[0] = color[1] = color[2] = .5;   // grey
    
    glColor3fv(color);
    glBegin(GL_LINES);
    glVertex3f(-line_length, k*5.0, -0.1);
    glVertex3f(line_length, k*5.0, -0.1);
    glEnd();
  }


  // calculate system time.
  float history_window_length; // this calculates the system time in the window

  int last_frame = history_index;
  int first_frame = (history_index -1);
  if (first_frame < 0){
    first_frame += DUAL_HISTORY_LENGTH;
  }

  unsigned long last_frame_ms = recvTimeMillis[last_frame];
  unsigned long first_frame_ms = recvTimeMillis[first_frame];
  history_window_length = first_frame_ms - last_frame_ms;

  /*
 cout << "window first, last, width " << first_frame_ms 
       << " " <<  last_frame_ms 
       << " " << history_window_length << endl;
  */

  // end calculate system time.

  for (int j = 0; j < DUAL_HISTORY_LENGTH; j++){
    beginhistory = history_index - j ;

    if ( beginhistory < 0){
      beginhistory += DUAL_HISTORY_LENGTH;
    }

    // draw eq data
    for(int i  = 0; i < NUM_BANDS; i++){

      eqval = eqHistory[i][beginhistory];
  
      if (eqval > .02){

	color[0] = 1-eqval;
	color[1] = 1-eqval;
	color[2] = 1-eqval;
	
	xscale = .5;
	yscale = .5;
	zscale = 1;
	
	xpos = DUAL_HISTORY_LENGTH/2 - j;
	ypos = i*0.5-11;
	zpos = 0;
	
	glColor3fv(color);
	glPushMatrix();
	glTranslatef(xpos, ypos, zpos);
	glBegin(GL_POLYGON);
	glVertex3f(xscale, yscale, 0);
	glVertex3f(xscale, -yscale, 0);
	glVertex3f(-xscale, -yscale, 0);
	glVertex3f(-xscale, yscale, 0);
	glEnd();
	glPopMatrix();
      }
    }
    
    // draw midi data
    for(int k = 0; k < 127; k++){ // over midi range
      
      midival = noteValues[k][beginhistory];

      if (midival == 0){   // check for short short notes
	midival = noteAttacks[k][beginhistory];
      }

      int timedindex = timedEventIndex[k][beginhistory];
      if (timedindex != 0){
	timedEventQueue[timedindex].printData();
	cout << "systime = " << recvTimeMillis[beginhistory] << " t-bulk = " << timedEventQueue[timedindex].getBulkTime() << endl;
      }	
      
      if (midival > 0){

	colorvec = note_color_table.getValue(k%12);

	  color[0] = colorvec[0];
	  color[1] = colorvec[1];
	  color[2] = colorvec[2];

	  // uniform size
	  xscale =  .5;
	  yscale = 2.5 * (float) midival/128.0;
	  zscale = 1;

	  // boxes scroll outward with time
	  // height = pitch
	  xpos = DUAL_HISTORY_LENGTH/2 - j;
	  ypos = (k % 12) * 5;
	  zpos = 0;

	  glColor3fv(color);

	  if (noteAttacks[k][beginhistory] > 0){
	    glBegin(GL_LINES);
	    glVertex3f(xpos, 0, 0);
	    glVertex3f(xpos, 60, 0);
	    glEnd();
	  }	    

	  glPushMatrix();
	  glTranslatef(xpos, ypos, zpos);
	  glBegin(GL_POLYGON);
	  glVertex3f(xscale, yscale, 0);
	  glVertex3f(xscale, -yscale, 0);
	  glVertex3f(-xscale, -yscale, 0);
	  glVertex3f(-xscale, yscale, 0);
	  glEnd();
	  glPopMatrix();
      }
    }
  }
}

void MidiVizDualHistory::drawScintillation(){
  // draw what?? who thinks up this stuff?
  // ok, well.. I think it looks like this...?
  
  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]);

  


  glPopMatrix();
}

void MidiVizDualHistory::drawCentralRadiation(){

  glPushMatrix();

  drawbox(.2, -.2, .2, -.2, .2, -.2, GL_QUADS);

  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 eqval;
  float angle;

  float xwidth;
  float yheight;
  float zdepth;

  float color[3]  = {0,0,0};
  float* colorvec;
  int beginhistory;

  float colorAttenuation;


  glPushMatrix();
  
  for (int j = 0; j < 30; j++){ // draw last 30 frames for photism
    
    beginhistory = history_index - j ;
    if ( beginhistory < 0){
      beginhistory += DUAL_HISTORY_LENGTH;
    }
    
    for (int i = 0; i < NUM_BANDS; i++){
      
      eqval = eqHistory[i][beginhistory];  // looks only at current values         eqval *= eqval;

      xwidth = eqval*10.0;
      yheight = eqval*.3;
      zdepth = -(j +(i/NUM_BANDS))/2.0;

      colorAttenuation = 1-j/((float) 30);
      
      colorvec = eqLookup.getValue(i);
      color[0] = colorvec[0] * colorAttenuation;
      color[1] = colorvec[1] * colorAttenuation;
      color[2] = colorvec[2] * colorAttenuation;
      
      glPushMatrix();
      
      angle = (float)i/(float)(NUM_BANDS) * 360.0;

      glRotatef(angle, 0,0,1);
      glTranslatef(eqval*10.0,0,0); 
           
      glColor3fv(color);
      //      glRotatef(angle, 0.0, 0.0, 1.0);
      glBegin(GL_POLYGON);
      glVertex3f(xwidth, yheight, zdepth);
      glVertex3f(xwidth, -yheight, zdepth);
      glVertex3f(-xwidth, -yheight, zdepth);
      glVertex3f(-xwidth, yheight, zdepth);
      glEnd();

      glBegin(GL_POLYGON);
      glVertex3f(yheight, xwidth, zdepth);
      glVertex3f(yheight, -xwidth, zdepth);
      glVertex3f(-yheight, -xwidth, zdepth);
      glVertex3f(-yheight, xwidth, zdepth);
      glEnd();

      glPopMatrix();

    }
  }
  glPopMatrix();
  
  glPopMatrix();
}

void MidiVizDualHistory::drawMandala(){
  
  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(.3*scale[0], .3*scale[1], scale[2]);

  drawBoundaryQuadrant(1);
  drawBoundaryQuadrant(2);
  drawBoundaryQuadrant(3);
  drawBoundaryQuadrant(4);

  drawEQMandalaQuadrant(1);
  drawEQMandalaQuadrant(2);
  drawEQMandalaQuadrant(3);
  drawEQMandalaQuadrant(4);

  drawMidiMandala();

  drawEQTree();

}

void MidiVizDualHistory::drawEQTree(){
  
  // considers the weighted average position of the eq values..
  // draws lines there
  // these are the peaks in the mandala

  int beginhistory;
  float eq;
  float max_eq;
  int max_index = 8;
  int last_max_index = 8;

  float color[3];
  float* colorvec;
  float in_color[3];
  float* in_colorvec;
  
  glLineWidth(2.0);

  glBegin(GL_LINES);
  
  for (int j = 0; j < DUAL_HISTORY_LENGTH; j++){
    
    beginhistory = history_index - j ;
    if ( beginhistory < 0){
      beginhistory += DUAL_HISTORY_LENGTH;
    }
    
    last_max_index= max_index;
    max_eq = 0;

    for (int i = 0; i < NUM_BANDS; i++){
      eq = eqHistory[i][beginhistory];
      
      if (eq > max_eq) {
	max_eq = eq;
	max_index = i;
      }
    }
    
    colorvec = eqLookup.getValue(last_max_index);
    color[0] = colorvec[0];
    color[1] = colorvec[1];
    color[2] = colorvec[2];

    in_colorvec = eqLookup.getValue(max_index);
    in_color[0] = in_colorvec[0];
    in_color[1] = in_colorvec[1];
    in_color[2] = in_colorvec[2];
 
    float xpos = mandalaAudioCdts[last_max_index][0] * (DUAL_HISTORY_LENGTH -j);
    float ypos = mandalaAudioCdts[last_max_index][1] * (DUAL_HISTORY_LENGTH -j);
  
    float in_xpos = mandalaAudioCdts[max_index][0] * (DUAL_HISTORY_LENGTH -j - 1);
    float in_ypos = mandalaAudioCdts[max_index][1] * (DUAL_HISTORY_LENGTH -j - 1);
    
    if ((j > 1) && (max_eq > .1)){
      
      glColor3fv(color);
      glVertex3f(xpos, ypos, .1);
      glColor3fv(in_color);
      glVertex3f(in_xpos, in_ypos, .1);
      
      glColor3fv(color);
      glVertex3f(xpos, -ypos, .1);
      glColor3fv(in_color);    
      glVertex3f(in_xpos, -in_ypos, .1);
      
      glColor3fv(color);
      glVertex3f(-xpos, -ypos, .1);
      glColor3fv(in_color);
      glVertex3f(-in_xpos, -in_ypos, .1);
      
      glColor3fv(color);
      glVertex3f(-xpos, ypos, .1);
      glColor3fv(in_color);
      glVertex3f(-in_xpos, in_ypos, .1);
      
    }
    
  }
  
  glEnd();
  
}

void MidiVizDualHistory::drawBoundaryQuadrant(int quadrant){
  
  float eq;
  float inner_xpos = 0, inner_ypos = 0;
  float outer_xpos = 0, outer_ypos = 0;
  float color[3];
  float* colorvec;
  int beginhistory;

  beginhistory = history_index - 1; // most recent time slot
  if ( beginhistory < 0){
    beginhistory += DUAL_HISTORY_LENGTH;
  }
  
  glBegin(GL_QUAD_STRIP);
 
  for (int i = 0; i < NUM_BANDS; i++){
    eq = eqHistory[i][beginhistory];
    eq = eq*eq;

        colorvec = eqLookup.getValue(i);
    color[0] = colorvec[0]*eq;
    color[1] = colorvec[1]*eq;
    color[2] = colorvec[2]*eq;
    
    inner_xpos = (DUAL_HISTORY_LENGTH + 5 + (-5*eq)) * mandalaAudioCdts[i][0];
    inner_ypos = (DUAL_HISTORY_LENGTH + 5 + (-5*eq)) * mandalaAudioCdts[i][1];

    outer_xpos = (DUAL_HISTORY_LENGTH + 5 + (5*eq)) * mandalaAudioCdts[i][0];
    outer_ypos = (DUAL_HISTORY_LENGTH + 5 + (5*eq)) * mandalaAudioCdts[i][1];

    glColor3fv(color);

    if ((quadrant == 2) || (quadrant == 3)){ // -y
      outer_ypos *= -1;
      inner_ypos *= -1;
    }

    if ((quadrant == 3) || (quadrant == 4)){ //-x
      outer_xpos *= -1;
      inner_xpos *= -1;
    }

    glVertex3f(inner_xpos, inner_ypos, 0);
    glVertex3f(outer_xpos, outer_ypos, 0);

  }

  // close the loop
  outer_xpos = 0;
  inner_xpos = 0;
  inner_ypos = (DUAL_HISTORY_LENGTH + 5 + (-5*eq));
  outer_ypos = (DUAL_HISTORY_LENGTH + 5 + (5*eq));
  
  if ((quadrant == 2) || (quadrant == 3)){ // -y
    outer_ypos *= -1;
    inner_ypos *= -1;
  }
  
  if ((quadrant == 3) || (quadrant == 4)){ //-x
    outer_xpos *= -1;
    inner_xpos *= -1;
  }
  
  glVertex3f(inner_xpos, inner_ypos, 0);
  glVertex3f(outer_xpos, outer_ypos, 0);  
  
  glEnd();
  
} // end  boundary

void MidiVizDualHistory::drawMidiMandala(){
  
  int beginhistory;
  float color[3]  ={0,0,0};
  float* colorvec;
  float colorAttenuation;
  float midival;
    float xpos, ypos;

    glLineWidth(1.0);

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

    beginhistory = history_index - j ;

    if ( beginhistory < 0){
      beginhistory += DUAL_HISTORY_LENGTH;
    }
    
    for(int k  =0; k < 127; k++){
      midival = noteValues[k][beginhistory];
      
      int note = k % 12;
      
      if (midival > 0){
	
	colorAttenuation = (float) midival/127.0;
	colorvec = note_color_table.getValue(note);
	color[0] = colorvec[0] * colorAttenuation;
	color[1] = colorvec[1] * colorAttenuation;
	color[2] = colorvec[2] * colorAttenuation;	 
	
	xpos = (DUAL_HISTORY_LENGTH + j/2.0) * mandalaMidiCdts[note][0];
	ypos = (DUAL_HISTORY_LENGTH + j/2.0) * mandalaMidiCdts[note][1];
	float width = 5 * colorAttenuation;
	float height = midival * .2;
	
	glBegin(GL_POLYGON);
	glColor3fv(color);
	glVertex3f(xpos+width, ypos+width, .3);
	glVertex3f(xpos+width, ypos-width, .3);
	glVertex3f(xpos-width, ypos-width, .3);
	glVertex3f(xpos-width, ypos+width, .3);
	glEnd();
	
      }
      
      if (midival > 0){
	
	colorAttenuation = (float) midival/127.0;
	colorvec = note_color_table.getValue(k%12);
	color[0] = colorvec[0] * colorAttenuation;
	color[1] = colorvec[1] * colorAttenuation;
	color[2] = colorvec[2] * colorAttenuation;
	
	xpos = DUAL_HISTORY_LENGTH * 1.3;
	ypos = (DUAL_HISTORY_LENGTH -(j+1)) + ((float) note/12.0);
	ypos *= 1.1;
 		
	glBegin(GL_LINES);
	glColor3fv(color);
	glVertex3f(xpos, ypos, -.1);
	glVertex3f(-xpos, ypos, -.1);
	glVertex3f(-xpos, -ypos, -.1);
	glVertex3f(xpos, -ypos, -.1);
	glEnd();

      }
    }
  } 
}

void MidiVizDualHistory::drawEQMandalaQuadrant(int quadrant){
  
  // quadrant 1 = ++
  // quadrant 2 = +-
  // quadrant 3 = --
  // quadrant 4 = -+

  int beginhistory;
  int lastindex;
  float eq = 0;
  //  float band_eq_tot = 0;

  float color[3]  = {0,0,0};
  float* colorvec;

  float outer_xpos, outer_ypos, inner_xpos, inner_ypos;

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

    beginhistory = history_index - j ;
    if ( beginhistory < 0){
      beginhistory += DUAL_HISTORY_LENGTH;
    }

    if ( j  == 0){
      lastindex = history_index;
    }

    glBegin(GL_QUAD_STRIP);

    for (int i = 0; i < NUM_BANDS; i++){
      eq = eqHistory[i][beginhistory];  
      eq = eq*eq;

      colorvec = eqLookup.getValue(i);
      color[0] = colorvec[0]*eq;
      color[1] = colorvec[1]*eq;
      color[2] = colorvec[2]*eq;

      outer_xpos = (DUAL_HISTORY_LENGTH -(j+1)) * mandalaAudioCdts[i][0];
      outer_ypos = (DUAL_HISTORY_LENGTH -(j+1)) * mandalaAudioCdts[i][1];      
      inner_xpos = (DUAL_HISTORY_LENGTH -j) * mandalaAudioCdts[i][0]; 
      inner_ypos = (DUAL_HISTORY_LENGTH -j) * mandalaAudioCdts[i][1];

      glColor3fv(color);

      if ((quadrant == 2) || (quadrant == 3)){ // -y
	outer_ypos *= -1;
	inner_ypos *= -1;
      }
      
      if ((quadrant == 3) || (quadrant == 4)){ //-x 
	outer_xpos *= -1;
	inner_xpos *= -1;
      }
      
      glVertex3f(outer_xpos, outer_ypos, 0);
      glVertex3f(inner_xpos, inner_ypos, 0);
            
    }
    
    // end case
    outer_xpos = 0;
    outer_ypos = (DUAL_HISTORY_LENGTH -(j+1));
    inner_xpos = 0;
    inner_ypos = (DUAL_HISTORY_LENGTH -j);
    
    if ((quadrant == 2) || (quadrant == 3)){ // -y
      outer_ypos *= -1;
      inner_ypos *= -1;
    }
    
    if ((quadrant == 3) || (quadrant == 4)){ //-x 
      outer_xpos *= -1;
      inner_xpos *= -1;
    }
    
    glVertex3f(outer_xpos, outer_ypos, 0);
    glVertex3f(inner_xpos, inner_ypos, 0);
    
    glEnd();


  }
  
}


void MidiVizDualHistory::drawPhotisms(){

  // float photismColor[16][3];        // radium slider 1,2,3 = r,g,b
  // float photismPosition[16][3];     // radium slider 4,5,6 = x,y,z
  // float photismScale[16];           // radium slider 7 = scale
  // float photismType[16];            // radium slider 8 = type;

  int midival;

  int beginhistory;
  
  float x, y, z; 
  float scale;
  float color[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, scale, scale);

  for (int j = 0; j < DUAL_HISTORY_LENGTH; j++){
    
    beginhistory = history_index -j;
    if ( beginhistory < 0){
      beginhistory += DUAL_HISTORY_LENGTH;
    }
    
    for (int itrchannel = 0; itrchannel < 2; itrchannel++){
      for(int k = 0; k < 127; k++){
	
	midival = noteValues[k][beginhistory];
	
	if (midival > 0){
	  
	  x = ((float) (photismPosition[itrchannel][0]-64.0))/12.7;
	  y = ((float) (photismPosition[itrchannel][1]-64.0))/12.7 
	    + k/12.7;
	  z = ((float) (photismPosition[itrchannel][2]-64.0))/12.7;
	  scale = ((float) (photismScale[itrchannel]-64.0))/12.7;
	  color[0] = ((float) photismColor[itrchannel][0])/127.0;
	  color[1] = ((float) photismColor[itrchannel][1])/127.0;
	  color[2] = ((float) photismColor[itrchannel][2])/127.0;
	  
	  printPhotisms(itrchannel);
	  
	  cout << "x,y,z " << x << " " << y << " " << z
	       << " color " << color[0] << " " 
	       << color[1] << " " << color[2] << 
	    " scale " << scale << endl;
	
	  glColor3fv(color);
	  glPushMatrix();
	  glTranslatef(x,y,z);
	  glScalef(scale, scale, scale);
	  drawbox(.5, -.5, .5, -.5, .5, -.5, GL_QUADS);
	  glPopMatrix();
	}
      }
    }
  }
  
  glPopMatrix();
  
}

void MidiVizDualHistory::drawRiver(){

  int beginhistory;
  int lastindex;
  float eq;
  float oldeq;
  float inner_x = 0, outer_x=0, old_inner_x=0, old_outer_x= 0;
  float color[3]  = {0,0,0};
  float* colorvec;
  float old_color[3]  = {0,0,0};
  float* old_colorvec;

  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(1.5*scale[0], 2*scale[1], scale[2]);

  for (int j = 0; j < DUAL_HISTORY_LENGTH; j++){
    
    beginhistory = history_index - j ;
    if ( beginhistory < 0){
      beginhistory += DUAL_HISTORY_LENGTH;
    }
    
    if ( j  == 0){
      lastindex = history_index;
    }
    
    for (int i = 0; i < NUM_BANDS-1; i++){
      
 	eq = eqHistory[i][beginhistory]; 
	oldeq = eqHistory[i][beginhistory];



	if (i == 0){
	  inner_x = 0;
	  old_inner_x = 0;
	} else {
	  inner_x = eqTotal[i][beginhistory];
	  old_inner_x= eqTotal[i][lastindex];
	}

	outer_x = eqTotal[i+1][beginhistory];
	old_outer_x= eqTotal[i+1][lastindex];

	// square and amplify the band widths postions
	inner_x = inner_x * inner_x + i;
	outer_x = outer_x * outer_x + i;
	old_inner_x  = old_inner_x * old_inner_x + i;
	old_outer_x = old_outer_x * old_outer_x + i;  
	
	colorvec = eqLookup.getValue(i);
	color[0] = colorvec[0]*eq;
	color[1] = colorvec[1]*eq;
	color[2] = colorvec[2]*eq;

	old_colorvec = eqLookup.getValue(i);
	old_color[0] = old_colorvec[0]*oldeq;
	old_color[1] = old_colorvec[1]*oldeq;
	old_color[2] = old_colorvec[2]*oldeq;
	

	glBegin(GL_POLYGON);
	glColor3fv(color);
	glVertex3f(j, inner_x, 0);
	glVertex3f(j, outer_x, 0);
	glColor3fv(old_color);
	glVertex3f(j-1, old_outer_x,  0);
	glVertex3f(j-1, old_inner_x, 0);
	glEnd();

	glBegin(GL_POLYGON);
	glColor3fv(color);
	glVertex3f(j, -inner_x, 0);
	glVertex3f(j, -outer_x, 0);
	glColor3fv(old_color);
	glVertex3f(j-1, -old_outer_x,  0);
	glVertex3f(j-1, -old_inner_x, 0);
	glEnd();

	glBegin(GL_POLYGON);
	glColor3fv(color);
	glVertex3f(-j, inner_x, 0);
	glVertex3f(-j, outer_x, 0);
	glColor3fv(old_color);
	glVertex3f(-j+1, old_outer_x,  0);
	glVertex3f(-j+1, old_inner_x, 0);
	glEnd();

	glBegin(GL_POLYGON);
	glColor3fv(color);
	glVertex3f(-j, -inner_x, 0);
	glVertex3f(-j, -outer_x, 0);
	glColor3fv(old_color);
	glVertex3f(-j+1, -old_outer_x,  0);
	glVertex3f(-j+1, -old_inner_x, 0);
	glEnd();

    }
    
    lastindex = beginhistory;
  }  

  glPopMatrix();
}
  
void MidiVizDualHistory::drawAxes(){

  glColor3f(1.0, 1.0, 1.0);
  glBegin(GL_LINES);
  glVertex3f(0,.2,0);
  glVertex3f(0,-.2,0);
  glEnd();

  glBegin(GL_LINES);
  glVertex3f(.2,0,0);
  glVertex3f(-.2,0,0);
  glEnd();

}

void MidiVizDualHistory::drawPiano(){

  float xpos, ypos, zpos;
  float xscale = 1, yscale = 4;
  float keyxscale = .8, keyyscale = 3.6;
  
  float color[3]  = {0,0,0};
  float* colorvec;

  ypos = 0;
  zpos = 0;
  int imodtwelve;
  
  for (int i = 21; i < 108; i++){
    
    xpos = i-21;
    
    imodtwelve = i % 12;

    if ((imodtwelve == 1) ||
	(imodtwelve == 3) ||
	(imodtwelve == 6) ||
	(imodtwelve == 8) ||
	(imodtwelve == 10)){

      glColor3f(0.3, 0.3, 0.3);
    } else {
      glColor3f(1.0, 1.0, 1.0);
    }
    
    glBegin(GL_POLYGON);
    glVertex3f(xpos, yscale, 0);
    glVertex3f(xpos, 0, 0);
    glVertex3f(xpos+xscale, 0, 0);
    glVertex3f(xpos+xscale, yscale, 0);
    glEnd();
    
    glColor3f(1, 1, 1);
    glBegin(GL_LINES);
    glVertex3f(xpos, 0,.02);
    glVertex3f(xpos, yscale, .02);
    glEnd();

    if (noteValues[i][history_index] > 0){ 
      // if the note is played, draw a glyph overlaying

      colorvec = note_color_table.getValue(i%12);
      color[0] = colorvec[0];
      color[1] = colorvec[1];
      color[2] = colorvec[2];
      glColor3fv(color);

      glBegin(GL_POLYGON);
      glVertex3f(xpos+.1, keyyscale, .1);
      glVertex3f(xpos+.1, .2, .1);
      glVertex3f(xpos+.1+keyxscale, .2, .1);
      glVertex3f(xpos+.1+keyxscale, keyyscale, .1);
      glEnd();

    }  

  }

}

void MidiVizDualHistory::drawBass(){

  // draw fretboard with notes placed on it.
  
  int numstrings = 4;
  int numfrets = 24;
  float boardlength =30;
  float dotradius = .1;
  float markerradius = .3;
  float xpos;
  float ypos;
  float y2pos;

  float color[3]  = {0,0,0};
  float* colorvec;

  int activenotes[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; // if a note is active set val to 1

  glColor3f(1.0, 1.0, 1.0);
  
  // draw strings
  for (int i = 0; i < numstrings; i++){    
    glBegin(GL_LINES);
    glVertex3f(0, i, 0);
    glVertex3f(boardlength, i, 0);
    glEnd();
  }    

  // draw frets / two octaves
  for (int i = 0; i < numfrets; i++){ //  two octaves
    xpos = boardlength/fretRatios.getRatio(i);
    glBegin(GL_LINES);
    glVertex3f(xpos, 0, 0);
    glVertex3f(xpos, (numstrings-1), 0);
    glEnd();
  }

  int imodtwelve;
  
  // draw dots
  for (int i = 0 ; i < numfrets; i++){
    imodtwelve = i % 12;
    
    if ((imodtwelve == 2) ||
	(imodtwelve == 4) ||
	(imodtwelve == 6) ||
	(imodtwelve == 8)) {
      
      // place dot between nth and n+1th fret
      xpos = (boardlength/fretRatios.getRatio(i) + 
	      boardlength/fretRatios.getRatio(i+1))/2.0;
      
      ypos = (numstrings -1)/2.0;
      
      glBegin(GL_POLYGON);
      glVertex3f(xpos + dotradius, ypos + dotradius, 0);
      glVertex3f(xpos + dotradius, ypos - dotradius, 0);
      glVertex3f(xpos - dotradius, ypos - dotradius, 0);
      glVertex3f(xpos - dotradius, ypos + dotradius, 0);
      glEnd();
    }

    if (imodtwelve == 11){
      
      xpos = (boardlength/fretRatios.getRatio(i) +
              boardlength/fretRatios.getRatio(i+1))/2.0;

      ypos = .5;
      y2pos = 2.5; 
      
      glBegin(GL_POLYGON);
      glVertex3f(xpos + dotradius, ypos + dotradius, 0);
      glVertex3f(xpos + dotradius, ypos - dotradius, 0);
      glVertex3f(xpos - dotradius, ypos - dotradius, 0);
      glVertex3f(xpos - dotradius, ypos + dotradius, 0);
      glEnd();

      glBegin(GL_POLYGON);
      glVertex3f(xpos + dotradius, y2pos + dotradius, 0);
      glVertex3f(xpos + dotradius, y2pos - dotradius, 0);
      glVertex3f(xpos - dotradius, y2pos - dotradius, 0);
      glVertex3f(xpos - dotradius, y2pos + dotradius, 0);
      glEnd();

    }  // double dot test

  } // end dot iteration


  // draw midi notes on strings


  
  /// iterate over each string and find a place 
  // show all possible placements for each active midi note
  // E A D G
  
  // E = 4
  // A = 9
  // D = 2
  // G = 7

  int stringpitchoffset[4];
  stringpitchoffset[0] = 4; // low string is E
  stringpitchoffset[1] = 9; // next A
  stringpitchoffset[2] = 2; // next D
  stringpitchoffset[3] = 7; // highest G
  
  int activeindex;

  // find active notes this frame...
  // place marker in active notes array
  for ( int i = 0; i < 127; i++){
    if (noteValues[i][history_index] > 0){
      activeindex = i%12;
      activenotes[activeindex] = 1;
    }      
  }

  // the pitch at the actual string/fret index
  int fretpitch;
  
  for (int j = 0; j < 24; j++){
    for (int k = 0; k < numstrings; k++){
      
      fretpitch = (j-stringpitchoffset[k])%12;

      if (fretpitch < 0 ){ 
	fretpitch += 12;
      }
   
      /*      cout << " fretpitch, j,k " << fretpitch 
	   << " j " << j << " k " << k << endl;
      */

      // draw glyph
      if (activenotes[fretpitch] == 1){
	colorvec = note_color_table.getValue(fretpitch);
	color[0] = colorvec[0];
	color[1] = colorvec[1];
	color[2] = colorvec[2];
	
	glColor3fv(color);

	xpos = (boardlength/fretRatios.getRatio(j) + 
		boardlength/fretRatios.getRatio(j+1))/2.0;

	ypos = 3-k;
	
	glBegin(GL_POLYGON);
	glVertex3f(xpos + markerradius, ypos + markerradius, 0);
	glVertex3f(xpos + markerradius, ypos - markerradius, 0);
	glVertex3f(xpos - markerradius, ypos - markerradius, 0);
	glVertex3f(xpos - markerradius, ypos + markerradius, 0);
	glEnd();
	
      }
    }
  }

  // add on makers for open notes..
  int index;

  for (int i=0; i < 4; i++){
    index = stringpitchoffset[i];

    if (activenotes[index] == 1){
      colorvec = note_color_table.getValue(index);
      color[0] = colorvec[0];
      color[1] = colorvec[1];
      color[2] = colorvec[2];
      glColor3fv(color);
      
      xpos = boardlength;
      ypos = i;
      
      glBegin(GL_POLYGON);
      glVertex3f(xpos + markerradius, ypos + markerradius, 0);
      glVertex3f(xpos + markerradius, ypos - markerradius, 0);
      glVertex3f(xpos - markerradius, ypos - markerradius, 0);
      glVertex3f(xpos - markerradius, ypos + markerradius, 0);
      glEnd();
    }
  }
  
}  


void MidiVizDualHistory::drawbox(GLdouble x0, GLdouble x1, GLdouble y0, GLdouble y1,
				 GLdouble z0, GLdouble z1, GLenum type)
{
  static GLdouble n[6][3] = {
    {-1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 0.0, 0.0},
    {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0}
  };
  static GLint faces[6][4] = {
    { 0, 1, 2, 3}, { 3, 2, 6, 7}, { 7, 6, 5, 4},
    { 4, 5, 1, 0}, { 5, 6, 2, 1}, { 7, 4, 0, 3}
  };
  GLdouble v[8][3], tmp;
  GLint i;
  
  if (x0 > x1)
    {
      tmp = x0; x0 = x1; x1 = tmp;
    }
  if (y0 > y1)
    {
      tmp = y0; y0 = y1; y1 = tmp;
    }
  if (z0 > z1)
    {
      tmp = z0; z0 = z1; z1 = tmp;
    }
  v[0][0] = v[1][0] = v[2][0] = v[3][0] = x0;
  v[4][0] = v[5][0] = v[6][0] = v[7][0] = x1;
  v[0][1] = v[1][1] = v[4][1] = v[5][1] = y0;
  v[2][1] = v[3][1] = v[6][1] = v[7][1] = y1;
  v[0][2] = v[3][2] = v[4][2] = v[7][2] = z0;
  v[1][2] = v[2][2] = v[5][2] = v[6][2] = z1;
  
  for (i = 0; i < 6; i++)
    {
      glBegin(type);
      glNormal3dv(&n[i][0]);
      glVertex3dv(&v[faces[i][0]][0]);
      glNormal3dv(&n[i][0]);
      glVertex3dv(&v[faces[i][1]][0]);
      glNormal3dv(&n[i][0]);
      glVertex3dv(&v[faces[i][2]][0]);
      glNormal3dv(&n[i][0]);
      glVertex3dv(&v[faces[i][3]][0]);
      glEnd();
    }
}

