'jdl+cdk 12.07.05: mutliplexed play+menu for 18F252


'************************************************************************
'Setup
'************************************************************************
    DEFINE OSC 20

    ' Define ADCIN parameters
    DEFINE  ADC_BITS        10     ' Set number of bits in result
    DEFINE  ADC_CLOCK       3      ' Set clock source (3=rc)
    DEFINE  ADC_SAMPLEUS    15     ' Set sampling time in uS

    'Enable communication out to MIDI
    DEFINE HSER_RCSTA 90h ' enable the receive register
    DEFINE HSER_TXSTA 20h  ' enable the transmit register
    DEFINE HSER_BAUD 31250 ' set the baud rate

    TRISA = %00000001       ' Set PORTA.0 to input
    ADCON1 = %10000010      ' Set PORTA analog and right justify result
    
    TRISC = %10110000       'Set RC0-RC3 and RC6 to output    
    inhibitPin VAR PORTA.1
    inputPin CON 0
    
    GREENLEDpin VAR PORTB.6
    REDLEDpin VAR PORTB.7
    PLAYMENUpin VAR PORTB.5
'************************************************************************
'END Setup
'************************************************************************

'************************************************************************
'Declare Variables
'************************************************************************
    'Declare Size of Array CONSTANTS
        numinput CON 16
        numlibrary CON 35
    
    'Declare CONSTANTS AND COUNTER VARIABLEs
        locktime CON 300
        menuth CON 300
        threshold CON 125
        resetthreshold CON threshold*3/4
        volumemin CON 25
        i VAR BYTE
        timecount VAR WORD
    
    'Declare ADC VARIABLES
        ADCVar VAR WORD
        
        volume VAR BYTE
    
    'Declare ARRAYS
        hold VAR WORD[numinput]      
        impulsetoggle VAR BYTE[numinput]
        sounds VAR BYTE[numinput]  
        finger VAR BYTE[numinput] 
        mutetoggle VAR BYTE[numinput]
        soundlib VAR BYTE[numlibrary]
        lock VAR BIT[numinput]  '1 is open to change, 0 is locked
         
    'initialize volume and toggle ARRAYS:
        volume=50 'mid volume
        FOR i=0 TO numinput
            impulsetoggle[i] = 0 'means okay to go
            mutetoggle[i]=0 'means don't sound off
        NEXT
    
    'initialize soundlib ARRAY
        soundlib[0]=25  '!!real kick
        soundlib[1]=27  '!side kick
        soundlib[2]=31  '!!hard snare
        soundlib[3]=32  '!drum sticks together
        soundlib[4]=33  '!kick drum
        soundlib[5]=34  '!!hard sharp drum
        soundlib[6]=35  '!!Kick drum
        soundlib[7]=36  '!duller kick drum
        soundlib[8]=37  '!two sticks snare
        soundlib[9]=38  '!hard snare
        soundlib[10]=40  '!!nice snare
        soundlib[11]=41  '!!hollowish boong drum
        soundlib[12]=42  '!!tssst high hat
        soundlib[13]=43  '!kick drum
        soundlib[14]=44  '!tsst high hat
        soundlib[15]=45  '!hollowish bong drum
        soundlib[16]=46  '!!lounder cymbal
        soundlib[17]=47  '!hollowish bong drum
        soundlib[18]=48  '!higher hollowish bong drum
        soundlib[19]=49  '!!loud cymbal
        soundlib[20]=50  '!hollow shalllow boong
        soundlib[21]=51  '!!cymbal tap
        soundlib[22]=53  '!traingle like tap
        soundlib[23]=54  '!tamborunie shake
        soundlib[24]=55  '!lower tambourine shake
        soundlib[25]=56  '!tin can smack
        soundlib[26]=57  '!!louder cmybal crash
        soundlib[27]=59  '!soft cymbal hit
        soundlib[28]=60  '!hollow bongo
        soundlib[29]=61  '!lower hollow bongo
        soundlib[30]=62  '!muted bongo
        soundlib[31]=63  '!!nice bongo
        soundlib[32]=64  '!!nice2 bongo
        soundlib[33]=65  '!!steel drum
        soundlib[34]=66  '!!steel drum2
 
    'initialize the finger[] sound locator
        finger[0] = 10
        finger[1] = 12
        finger[2] = 16
        finger[3] = 19
        finger[4] = 0
        finger[8] = 10  
        finger[9] = 12
        finger[10] = 16
        finger[11] = 19
        finger[12] = 0
    'Load sounds[] using finger[] as reference to soundlib[]
        FOR i=0 TO (numinput-1)
    	   sounds[i] = soundlib[finger[i]]
        NEXT
        
    'intialize all elements of lock[] as locked
        FOR i=0 TO (numinput-1)
    	   lock[i]=0
        NEXT
        
    '*************************
    'Declare Play/Menu toggle variable
        playmenu VAR BIT  ' 0 play, 1 menu
        lastplaymenu VAR BIT 
    ' initialize playmenu
        playmenu=0

'************************************************************************
'END Declare Variables
'************************************************************************

'************************************************************************
'MAIN
'************************************************************************
    MAIN:
    	playmenu = PLAYMENUpin
    	   'Look for change to PLAY
    	   IF lastplaymenu ==1 AND playmenu ==0 THEN
                'set all lock[] to locked
                FOR i=0 TO (numinput-1)
    	           lock[i]=0
                NEXT
                SEROUT2 PORTA.2, 16468, [200,220,0,0]
            ENDIF
            'Look fro change to MENU
            IF lastplaymenu ==0 AND playmenu ==1 THEN
                SEROUT2 PORTA.2, 16468, [200,221,0,0]
            ENDIF
    	
    	lastplaymenu=playmenu
    	
    	IF playmenu == 0 THEN
    		GOTO PLAY
    	ELSE
    		GOTO MENU
    	ENDIF
    
    GOTO MAIN
'************************************************************************
'END MAIN
'************************************************************************

'************************************************************************
'PLAY
'************************************************************************
    PLAY:
        'SET STATUS LEDS
    	HIGH GREENLEDpin 'Turn on green LED indicate play mode on
        LOW REDLEDpin  'Turn off red LED
    	'code:
    	
        FOR i=0 TO (numinput-1)
        'Turn off inputs:
            HIGH inhibitPin
        'Set the address you want to read
            PORTC = i 'channelVar
        'Turn on inputs
            LOW inhibitPin
    
            'Get reading from FSR (assume 0-1000):
            ADCIN inputPin, ADCVar
            hold[i]=ADCVar'This is an extra step
         '    SEROUT2 PORTA.2, 16468, ["finger ",DEC i, "reading ", DEC ADCVar,10,13] 
            IF hold[i] > threshold AND impulsetoggle[i]=0 THEN
                'Here we look 6 more times to find peak
                 
                 FOR  timecount=0 TO 6
                      ADCIN inputPin, ADCVar
                      IF ADCVar > hold[i] THEN
                            hold[i]=ADCVar
                      ENDIF 
                 NEXT
                           
                'Convert hold to volume
                    volume=hold[i]/8
                    volume=volume+volumemin
                    IF volume>125 THEN
                        volume=125
                    ENDIF
                'noteon channel 1
                    HSEROUT [$90, sounds[i] ,volume]
                    SEROUT2 PORTA.2, 16468, [200,i,sounds[i],volume]
                'reset impulsetoggle
                    impulsetoggle[i]=1
                'set mutetoggle to trigger
                    mutetoggle[i]=1
            ENDIF
        NEXT
        
        'Reset Toggles and Noteoff Loop
        'NO NEED TO MULTIPLEX
        FOR i=0 TO (numinput-1)
            'Send Noteoff signal and reset mutetoggle
            IF hold[i]<threshold AND mutetoggle[i]==1 THEN
                 HSEROUT [$80, sounds[i], $00]
                 mutetoggle[i]=0
            ENDIF
            'RESET impulsetoggle
            IF hold[i]<resetthreshold THEN
                impulsetoggle[i]=0
            ENDIF
        NEXT
   	
    GOTO MAIN
'************************************************************************
'END PLAY
'************************************************************************

'************************************************************************
'MENU
'************************************************************************
    MENU:
    	'SET STATUS LEDS
        LOW GREENLEDpin  'Turn off green LED
    	HIGH REDLEDpin 'Turn on red LED indicate menu mode on
    	'code:
    	
        FOR i = 0  TO (numinput-1)
        'Turn off inputs:
            HIGH inhibitPin
        'Set the address you want to read
            PORTC = i 'channelVar
        'Turn on inputs
            LOW inhibitPin
    
        		timecount=0
        		'read input
        		ADCIN inputPin, ADCVar
        		IF ADCVar > menuth THEN
        			WHILE ADCVar > menuth
        				timecount=timecount+1
        				'pause
        				PAUSE 2
        				ADCIN inputPin, ADCVar
        			WEND
        			IF timecount > locktime THEN
        				lock[i]=lock[i] +1  'lock is a bit so this flips it
        				SEROUT2 PORTA.2, 16468, [200,i,210,0]
        			ELSE
        				IF lock[i]==1 THEN 'system open: change note
        					finger[i]=(finger[i]+1)//numlibrary
                            sounds[i]=soundlib[finger[i]]
        				ENDIF			
        	           	HSEROUT [$80, sounds[i-1] ,00] 'use constant volume
                		HSEROUT [$90, sounds[i] ,90] 'use constant volume
                        SEROUT2 PORTA.2, 16468, [200,i,sounds[i],0]	
        			ENDIF
        		ENDIF
          NEXT
    
           PAUSE 100 'Helps get rid of noise
   	
    GOTO MAIN
'************************************************************************
'END MENU
'************************************************************************

'/*
'  Serial Codes:
'     Inside Play Mode:  [startbit, finger, sound, velocity]
'     Inside Menu Mode:  [startbit, finger, sound, 0]
'         UNLOCK:        [startbit, finger, UNLOCK, 0]
'         LOCK:          [startbit, finger, LOCK, 0] 
     
'     Transfer Play Mode: [startbit, PLAY, 0, 0]
'     Transfer Menu Mode: [startbit, MENU, 0, 0]
     
'     Serial Codes:
'     Inside Play Mode:  [555, 0-9, 0-50, 0-127]
'     Inside Menu Mode:  [555, 0-9, 0-50, 0    ]
'         UNLOCK:        [555, 0-9, 210, 0]
'         LOCK:          [555, 0-9, 211, 0] 
     
'     Transfer Play Mode: [555, 220, 0, 0]
'     Transfer Menu Mode: [555, 221, 0, 0]

'*/

'import processing.serial.*;
'Serial myPort;  // The serial port

'Finger[] f= new Finger[10];
'PFont font;
'Smsg serialmsg;
'int initial=-1;
'boolean waiting;
'int count=0;

'//Global Variables
'  boolean Play; //true if in Play mode false if in Menu mode
'  int startbit=200;
'  int playmsg=220;
'  int menumsg=221;
 
'void setup()
'{
'  size(500,500);
'  background(0);
'  smooth();
  
'  //LOAD font
'    font = loadFont("ArialMT-48.vlw"); 
'    textFont(font, 12);    
'  //INITIALIZE Fingers
'    initializeF();
'  //INITIALIZE Variables  
'    serialmsg= new Smsg(0,0,0);
'    Play=true;
  
'  //DEAL with serial
'    println(Serial.list());
'    myPort = new Serial(this, Serial.list()[0], 9600);
  
'  //initialize getting to punctuation bit
'    while(initial != startbit)
'    {
'      if (myPort.available() > 0)
'      {
'        initial = myPort.read();
'        println(initial);
'      }
'    }
'    waiting = false;
'    count=0;
'} 

'void draw()
'{
'  background(0);
 
'  readPORT();
'  renderF();
'  //render mode
'  if(Play)
'  {
'    text("PLAY",20,20);
'  }
'  else
'  {
'    text("MENU",20,20);
'  }
'  resetFvel();
'}
'/////////////////////////////////////////PAGE2
'  void readPORT()
'  {
'    int code;    
'    if (myPort.available() > 0)
'    {
'      code = myPort.read();
      
'      if(code == startbit)
'        { count=0;}
'      else if(count==0)
'        { serialmsg.setMSG(0,code);
'          count=1;}
'       else if(count==1)
'         { serialmsg.setMSG(1,code);
'           count=2;}
'        else if(count==2)
'          { serialmsg.setMSG(2,code);
'            evalmsg(serialmsg);}
'    }
'  }
'///////////////////////////////////////////PAGE 3
' void evalmsg(Smsg SEmsg)
'  {
'    int[] msg= new int[3];
'   //parse message apart here, assume its a array
'     msg[0]=SEmsg.getMSG(0);
'     msg[1]=SEmsg.getMSG(1);
'     msg[2]=SEmsg.getMSG(2);
   
'   //EVALUATE HIT CODES
'   if(msg[0] >-1 && msg[0] <13)
'     {
     
'       if(msg[0]>=5)//Corrects for the fact one hand is 8-12
'       {
'         msg[0]=msg[0]-3;
'       }
'       if(Play)
'       {
'         f[msg[0]].setVELOCITY(2*msg[2]);
'       }
'       else if(Play==false && (msg[1]==210 || msg[1]==211) )//Unlock
'       {
'         f[msg[0]].setLOCKED(!f[msg[0]].getLOCKED());
'       }
'       else //MENU MODE
'       {
'         if(f[msg[0]].getLOCKED()==false)
'         {
'           f[msg[0]].setSOUND((f[msg[0]].getSOUND()+1)%15);
'         }
'         else
'         {
'           f[msg[0]].setVELOCITY(100);
'         }
'       }
'     }
     
'     //SWITCH TO PLAY 
'     if(msg[0] == playmsg)
'     {
'       Play=true;
'       lockF();
'     }
'     //SWITCH TO MENU
'     if(msg[0] == menumsg)
'     {
'       Play=false;
'     }
'  }
  
'  /////////////////////////////////////
  
'   void resetFvel()
'  {
'     for(int i=0; i < f.length; i++)
'     {
'       if(f[i].getVELOCITY() > 0)
'       {
'         f[i].setVELOCITY(f[i].getVELOCITY()-1);
'       }
'     }  
'  }

'  void lockF()
'  {
'     for(int i=0; i < f.length; i++)
'     {
'       f[i].setLOCKED(true);
'     }
'  }
  
'  void renderF()
'  {
'     for(int i=0; i < f.length; i++)
'     {
'       f[i].render();
'     }
'  }
  
'  void initializeF()
'  {
'     for(int i=0; i < f.length; i++)
'     {
'       f[i]= new Finger(100 + i*20, 100, i, 0, true);
'     }
'  }

'///////////////////////////////////////////////////PAGE 4
'class Finger
'{
'  float x, y;
'  int sound;
'  float velocity;
'  boolean locked;
'  String[] sounds= new String[15];
  
'  Finger(float x_, float y_, int sound_, float velocity_, boolean locked_)
'  {
'    x=x_;
'    y=y_;
'    sound=sound_;
'    velocity=velocity_;
'    locked=locked_;
    
'    sounds[0]="a";
'    sounds[1]="b";
'    sounds[2]="c";
'    sounds[3]="d";
'    sounds[4]="e";
'    sounds[5]="f";
'    sounds[6]="g";
'    sounds[7]="h";
'    sounds[8]="i";
'    sounds[9]="j";
'    sounds[10]="k";
'    sounds[11]="l";
'    sounds[12]="m";
'    sounds[13]="n";
'    sounds[14]="o";  
'  }//END Finger
  
'  int getSOUND() {return sound;}
'  void setSOUND(int sound_) {sound = sound_;}
'  float getVELOCITY() {return velocity;}
'  void setVELOCITY(float v_) {velocity=v_;}
'  boolean getLOCKED() {return locked;}
'  void setLOCKED(boolean l_) {locked=l_;}
  
'  void render()
'  {
'    noStroke();
'    fill(255-velocity);
    
'    ellipse(x,y,10+velocity/10,10+velocity/10);
'    text(sounds[sound], x, y-20);
   
'    if(locked==false)
'    {
'       for(int i=0; i<sounds.length; i++)
'       {
'         if(i==sound)
'           {fill(255,0,0);}
'         else
'           {fill(255);}
'         text(sounds[i],x,y+i*15+20);
'       }      
'      }   
'  }//END render


'}//END Finger
'/////////////////////////////////////////////////////PAGE 5

'class Smsg
'{
'  int[] b= new int[3];
  
'  Smsg(int b0, int b1, int b2)
'  {
'    b[0]=b0;
'    b[1]=b1;
'    b[2]=b2;
'  }

'  int getMSG(int i) {return b[i];}
'  void setMSG(int i, int bin) {b[i] = bin;}
'}