//
// Programmer:    Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Thu Oct 15 12:40:15 PDT 1998
// Last Modified: Thu Oct 15 13:07:01 PDT 1998
// Filename:      ...sig/doc/examples/improv/synthImprov/yekyek/yekyek.cpp
// Syntax:        C++; synthImprov 2.0
//  
// Description: Does the opposite of the keykey program
//     you input a text file and the program will play
//     the synthesizer according to the specified letters
//     You can control the interword time and the speed of 
//     the transmission of the characters.  Try extending
//     the program by assigning pitch patterns to the
//     10 transmission keys, and using different rhythmic
//     patterns.
//

#include "synthImprov.h" 

#define INTERFACE_FUNCTION   /* just a label so you can see req. functions */
#define LOCAL_FUNCTION       /* defined just for this program */

/*----------------- beginning of improvization algorithms ---------------*/

int lastNoteTime = 0;   // time at which to play next note pair.
int notePeriod = 100;   // duration of each note
int restPeriod = 300;   // duration of a non-letter character
int duration = 100;     // duration of the current note.

Voice leftHand;         // Voice for left hand notes.
Voice rightHand;        // Voice for right hand notes.

fstream infile;         // input file stream for characters
int source = 0;         // 0 = keyboard; 1 = file
int sounding = 0;       // 0 = rest, 1 = note on.
int character = 0;      // character to send
int volume = 127;       // volume of MIDI

int note[10] = {48, 50, 52, 53, 55, 60, 62, 64, 65, 67}; // notes to play


// function declarations:
void playNotes(int left, int right);
void playCharacter(int aCharacter);
int getCharacter(void);


/*--------------------- maintenance algorithms --------------------------*/

INTERFACE_FUNCTION void description(void) {
   cout << "\nKeykey:  (Craig Stuart Sapp <craig@ccrma.stanford.edu>)"
           "15 Oct 1998\n"
        << "Use the white midi keys C-G below middle C for the left hand\n"
        << "and middle C-G white keys for the right hand\n"
        << "left hand: C=5, D=4, E=3, F=2, G=1\n"
        << "right hand: C=1, D=4, E=3, F=4, G=5\n"
        << "Here are the key combinations (LH col, RH row):\n\n"
        << "     5 E J O T Y\n"
        << "     4 D I N S X        For example:\n"
        << "     3 C H M R W           LH3+RH2 = F\n"
        << "     2 B G L Q V           LH5+RH3 = O\n"
        << "     1 A F K P U           LH1+RH1 = A\n"
        << "       1 2 3 4 5"
        << " Commands:\n"
        << " 1 = keyboard control, 2 = file control\n"
        << " - = speed up,         = = slow down\n"
        << endl;
} 

INTERFACE_FUNCTION void initialization(void) { 
   leftHand.setPort(synth.getOutputPort());
   rightHand.setPort(synth.getOutputPort());
}

INTERFACE_FUNCTION void finishup(void) { 
   leftHand.off();
   rightHand.off();
}


/*-------------------- main loop algorithms -----------------------------*/

INTERFACE_FUNCTION void mainloopalgorithms(void) { 
   if (source && lastNoteTime + duration <= t_time) {
      character = getCharacter();
      if (character >= 0) {
         lastNoteTime = t_time;
         playCharacter(character);
         if (sounding) {
            duration = notePeriod;
         } else {
            duration = restPeriod;
         }
      }
   }
}


LOCAL_FUNCTION int getCharacter(void) {
   int output;
   if (source == 0) {    
      // keyboard characters are handled elsewhere
      return -1;
   } else {
      output = interfaceKeyboard.getch();
      if (infile.eof()) {
         source = 0;
      }
   }

   if (isalpha(output) || output == '\n') {
      cout << tolower(output) << flush;
   }

   return output;
}



LOCAL_FUNCTION void playCharacter(int aCharacter) {
   switch (tolower(aCharacter)) {
      case 'a':   playNotes(1, 1);   sounding = 1; break;
      case 'b':   playNotes(2, 1);   sounding = 1; break;
      case 'c':   playNotes(3, 1);   sounding = 1; break;
      case 'd':   playNotes(4, 1);   sounding = 1; break;
      case 'e':   playNotes(5, 1);   sounding = 1; break;
      case 'f':   playNotes(1, 2);   sounding = 1; break;
      case 'g':   playNotes(2, 2);   sounding = 1; break;
      case 'h':   playNotes(3, 2);   sounding = 1; break;
      case 'i':   playNotes(4, 2);   sounding = 1; break;
      case 'j':   playNotes(5, 2);   sounding = 1; break;
      case 'k':   playNotes(1, 3);   sounding = 1; break;
      case 'l':   playNotes(2, 3);   sounding = 1; break;
      case 'm':   playNotes(3, 3);   sounding = 1; break;
      case 'n':   playNotes(4, 3);   sounding = 1; break;
      case 'o':   playNotes(5, 3);   sounding = 1; break;
      case 'p':   playNotes(1, 4);   sounding = 1; break;
      case 'q':   playNotes(2, 4);   sounding = 1; break;
      case 'r':   playNotes(3, 4);   sounding = 1; break;
      case 's':   playNotes(4, 4);   sounding = 1; break;
      case 't':   playNotes(5, 4);   sounding = 1; break;
      case 'u':   playNotes(1, 5);   sounding = 1; break;
      case 'v':   playNotes(2, 5);   sounding = 1; break;
      case 'w':   playNotes(3, 5);   sounding = 1; break;
      case 'x':   playNotes(4, 5);   sounding = 1; break;
      case 'y':   playNotes(5, 5);   sounding = 1; break;
      default:    playNotes(0, 0);   sounding = 0; break;
   }
}


LOCAL_FUNCTION void playNotes(int left, int right) {
   switch (left) {
      case 0:   leftHand.off();
      case 1:   leftHand.play(note[0], volume);
      case 2:   leftHand.play(note[1], volume);
      case 3:   leftHand.play(note[2], volume);
      case 4:   leftHand.play(note[3], volume);
      case 5:   leftHand.play(note[4], volume);
   }
   switch (right) {
      case 0:   rightHand.off();
      case 1:   rightHand.play(note[0+5], volume);
      case 2:   rightHand.play(note[1+5], volume);
      case 3:   rightHand.play(note[2+5], volume);
      case 4:   rightHand.play(note[3+5], volume);
      case 5:   rightHand.play(note[4+5], volume);
   }
}



/*-------------------- triggered algorithms -----------------------------*/

INTERFACE_FUNCTION void keyboardchar(int key) { 
   cout << tolower(key) << flush;
   playCharacter(key);
}


/*------------------ end improvization algorithms -----------------------*/


// md5sum: 2141ce2c943938b97a28ebc36319f9cd yekyek.cpp [20050403]