
// Lew Hill 
// MidiVizBellTree.h

// this class creates an
// upward spiraling bell tree
// of musical notes.

#include "MidiVizBellTree.h"


MidiVizBellTree::MidiVizBellTree(/*midiLew* in_music*/){

  //  music = in_music;

  rootNote = 0;
  channel = 0;
  noteVelocity = 100;
  verticalGap = .100;
  angleGap = 30;
  radialNoteDistance = 3.0;

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

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

  // this num_vizNotes and the size of the vizNotes array
  // could be handled in a more dynamic fasion

  NUM_VIZ_NOTES = 60;
}


void MidiVizBellTree::draw(){

  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_VIZ_NOTES; i++){
    vizNotes[i].draw();
  }

  glPopMatrix();

}

void MidiVizBellTree::frame(double time){

  for(int i = 0; i < NUM_VIZ_NOTES; i++){
    vizNotes[i].frame(time);
  }
  
}

void MidiVizBellTree::processMidiEvent(MidiEvent event){

  if (event.getChannel() == channel){
    
    for(int i = 0; i < NUM_VIZ_NOTES; i++){
      if (vizNotes[i].getNote()== event.getNote()){
	vizNotes[i].startAnimation(&event);
	if (event.getVelocity() > 0){
	  //music->playSound(&event);
	}
      }
    } 

  }
  
}

void MidiVizBellTree::intersect(float in_position[], int button){
  // perform intersection test against
  // the bell tree 

  // we determine the button that was pressed and then play an interval
  // upward from the root...
  // so button 1
  int button_note_offset =0;

  switch(button){

  case 0:
    button_note_offset = 0; // root
    break;
  case 1:
    button_note_offset = 3; // min 3rd
    break;
  case 2:
    button_note_offset = 4; // maj 3rd
    break;
  case 3:
    button_note_offset = 5; // 4th
    break;
  case 4:
    button_note_offset = 7; // 5th
    break;
  case 5:
    button_note_offset = 10; // min 7th
    break;
  default:
    button_note_offset = 0; // nothing
    break;
  }
  
  int note_to_play; // temp variable used to store the computed
                    // viz note midi note + the button_note_offset

  int velocity = 100;  // change velocity to use wand distance from viz note.
  
  bool intersect;
  
  MidiEvent event;

  for(int i = 0; i < NUM_VIZ_NOTES; i++){
    intersect = vizNotes[i].intersect(in_position);

    if (intersect){ 
      
      if (!vizNotes[i].isAnimating()){
	note_to_play = vizNotes[i].getNote() + button_note_offset;
	
	event.setData(0, vizNotes[i].getChannel(), 
					 note_to_play, velocity);
	//music->playSound(&event);
      }
      vizNotes[i].startAnimation(&event);
    }
  }
}

void MidiVizBellTree::setRootNote(int note){
  // this is the midi note of the lowest node in the tree
  rootNote = note;
}

void MidiVizBellTree::setChannel(int in_channel){
// this is the midi channel that a note will be transmitted on
  channel = in_channel;
}

void MidiVizBellTree:: setVelocity(int note_velocity){
  // how loud should the note be
  noteVelocity = note_velocity;
}

void MidiVizBellTree::setVerticalNoteGap(float vertical_gap){
  // how much higher should one note be from the next in the
  // stair case
  
  verticalGap = vertical_gap;
}

void MidiVizBellTree::setAngularNoteGap(float in_anglegap){
  // what angle (degrees) should there be between tree nodes.
  
  angleGap = in_anglegap;
}

void MidiVizBellTree::setRadialNoteDistance(float distance){
  radialNoteDistance = distance;
}

void MidiVizBellTree::assignColors(){

  
  NoteColorLookupTable noteColorTable;

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

    float* value = noteColorTable.getValue(vizNotes[i].getNote() % 12);
    vizNotes[i].setColor(value[0], value[1], value[2]);
    
  }

}

void MidiVizBellTree::assignNotes(){
  
  for(int i = 0; i < NUM_VIZ_NOTES; i++){
    vizNotes[i].setChannel(channel);
    vizNotes[i].setNote(rootNote+i);
  }
}

void MidiVizBellTree::adjustTreeLeafAngles(){
  // this note applies all tree parameters
  // do some math

  float iter_pos[3];
  iter_pos[0] = position[0];
  iter_pos[1] = position[1];
  iter_pos[2] = position[2];

  float iter_rotation[3];
  iter_rotation[0] = 0;
  iter_rotation[1] = 0;  
  iter_rotation[2] = 0;
  
  float iter_angle = 0;

   for(int i = 0; i < NUM_VIZ_NOTES; i++){
    
    iter_pos[0] = position[0] + (cos(iter_angle * 3.1428571/180.0) * (float)radialNoteDistance);   
    iter_pos[1] += verticalGap; 
    // raise height by one small amount
    // from the last position;
    iter_pos[2] = position[2] + (sin(iter_angle * 3.1428571/180.0) * (float)radialNoteDistance);   

    /*    
    cout << i << "\t"  << iter_pos[0] <<  "\t "
	 << iter_pos[2] << "\t"  << iter_angle << endl;
    */    

    iter_rotation[0] = 0;
    iter_rotation[1] = 270-iter_angle;
    iter_rotation[2] = 0;

    vizNotes[i].setPosition(iter_pos[0], 
			    iter_pos[1], 
			    iter_pos[2]);
    vizNotes[i].setRotation(iter_rotation[0], 
			    iter_rotation[1], 
			    iter_rotation[2]);
    vizNotes[i].setScale(.5, .5, .5); // half scale the notes

    iter_angle += angleGap; 
    if (iter_angle >= 360){
      iter_angle -= 360;
    }

  }

}

