/**
 * grab_pipe.c
 *
 * Written by Evan Raskob 2002-2003
 * :: devices [at] lowfrequency [dot] org ::
 *
 * pipe-based dj/saxophone audio/video controller
 *
 * Platform: PIC16F877
 * Uses 4 momentary switches on (top to bottom) RB7,RB6,RB5,RB4
 * Uses 2 ADC channels for a crossfader potentiometer RA0,RA1
 * Uses 2 ADC channels for an accelerometer (y,x) RA2,RA3
 * Uses 1 ADC channel for rotary pot RA4
 * 
 *
 * Not for use without permission of the author.
 */


/* Standard Include for 16F876 Chip */
#include <16F877.h>

#device PIC16F877 ADC=10



/* library of midi functions (expanded in midi.c) */
#include "midi.h"

#FUSES HS,NOWDT,NOPROTECT,NOBROWNOUT

/* Delay for 20 mhz crystal */
#use delay (clock=20000000)

/* Setup buit-in RS232 serial ports to work work at MIDI speeds */
#use rs232(baud=MIDI_BAUD_RATE, xmit=PIN_C6,rcv=PIN_C7)

int sendByte (char byteToSend) {
        printf("%c", byteToSend);
        return 0;
}

/** DEBUG **/
//Setup buit-in RS232 serial ports to work work at serial port speeds
#use rs232(baud=9600, xmit=PIN_C4,rcv=PIN_C5)
/** END DEBUG **/

#use standard_io(B)

#define HIGH 1
#define LOW  0

// send a midi NOTE ON message from the uart of the form [0x9n, note, vel]
// where n is the midi channel from 0-F, note and vel are 7-bit numbers
int midiNoteOn(char channel, char note, char vel) {
        sendByte(MIDI_NOTE_ON | (channel & MIDI_CHANNEL_MASK));
        sendByte(MIDI_DATA_MASK & note);
        sendByte(MIDI_DATA_MASK & vel);
        return 0;
}

// send a midi NOTE ON message from the uart of the form [0x9n, note, velocity]
// where n is the midi channel from 0-F, note is a 7-bit number and velocity is 0
int midiNoteOFF(char channel, char note) {
        sendByte(MIDI_NOTE_ON | (channel & MIDI_CHANNEL_MASK));
        sendByte(MIDI_DATA_MASK & note);
        sendByte(MIDI_DATA_MASK & 0);
        return 0;
        return 0;
}       

// send a midi POLYPHONIC AFTERTOUCH message from the uart of the form [0xCn, controller, value]
// where n is the midi channel from 0-F, note and pressure are 7-bit numbers
int midiControlChange(char channel, char controller, char value) {
        sendByte(MIDI_CONTROL_CHANGE | (channel & MIDI_CHANNEL_MASK));
        sendByte(MIDI_DATA_MASK & controller);
        sendByte(MIDI_DATA_MASK & value);
        return 0;
}

int midiPolyTouch(char channel, char note, char pressure) {
        sendByte(MIDI_POLY_TOUCH | (channel & MIDI_CHANNEL_MASK));
        sendByte(MIDI_DATA_MASK & note); 
        sendByte(MIDI_DATA_MASK & pressure); 
        return 0;
}       
        
// send a midi CHANNEL AFTERTOUCH message from the uart of the form [0xDn, pressure]
// where n is the midi channel from 0-F, and pressure is a 7-bit number
int midiChannelTouch(char channel, char pressure) { 
        sendByte(MIDI_CHANNEL_TOUCH | (channel & MIDI_CHANNEL_MASK));        sendByte(MIDI_DATA_MASK & pressure);
        return 0;
}      


// send a midi PITCH BEND message from the uart of the form [0xEn, bendLSB, bendMSB ]
// where n is the midi channel from 0-F, and bendLSB and bendMSB are 7-bit numbers
// note that MIDI devices normally pack together bendLSB and bendMSB to make a 14-bit number
int midiPitchBend(char channel, char bendLSB, char bendMSB) {
        sendByte(MIDI_PITCH_BEND | (channel & MIDI_CHANNEL_MASK));
        sendByte(MIDI_DATA_MASK & bendLSB);
        sendByte(MIDI_DATA_MASK & bendMSB);
        return 0;
}


void setStatusLED(int state) {
   output_bit(PIN_B0, state);
}

main()
{

   // 4 magnetic momentary switches
   // hooked up to pin B7
   int switch1   = 0;
   int note1 = 67;
   // hooked up to pins B6
   int switch2   = 0;
   int note2 = 68;
   // hooked up to pins B5
   int switch3   = 0;
   int note3 = 69;
   // hooked up to pins B4
   int switch4   = 0;
   int note4 = 70;

   int tempSwitch= 0;

   long adcval    = 0;   

   int midiPitchMultiplier = 1;


   // Flash what yo momma gave ya
   setStatusLED(HIGH);
   delay_ms(150);
   setStatusLED(LOW);
   delay_ms(150);
   setStatusLED(HIGH);
   delay_ms(150);
   setStatusLED(LOW);
   delay_ms(150);
   setStatusLED(HIGH);
   delay_ms(150);
   setStatusLED(LOW);
   delay_ms(10);



   setup_adc_ports( ALL_ANALOG );
   setup_adc(ADC_CLOCK_INTERNAL );




   // DEBUG: print to console
   //printf("Started.");
   while (TRUE)
   {  
   
      //footswitches
      tempSwitch = input(PIN_B7);
      if (tempSwitch != switch1) {
        switch1 = tempSwitch;

        //switch state has changed
        if (tempSwitch ==1) {
          note1 = 67 + midiPitchMultiplier;
          midiNoteOn(0, note1, 80);
          setStatusLED(HIGH);
        } else {
          midiNoteOff(0, note1);
          setStatusLED(LOW);
        }
      }
   

      tempSwitch = input(PIN_B6);
      if (tempSwitch != switch2) {
        switch2 = tempSwitch;

        //switch state has changed
        if (switch2 ==1) {
          note2 = 68 + midiPitchMultiplier;
          midiNoteOn(0, note2, 80);
          setStatusLED(HIGH);
        } else {
          midiNoteOff(0, note2);
          setStatusLED(LOW);
        }
      }


      tempSwitch = input(PIN_B5);
      if (tempSwitch != switch3) {
        switch3 = tempSwitch;

        //switch state has changed
        if (switch3 ==1) {
          note3 = 69 + midiPitchMultiplier;
          midiNoteOn(0, note3, 80);
          setStatusLED(HIGH);
        } else {
          midiNoteOff(0, note3);
          setStatusLED(LOW);
        }
      }


      tempSwitch = input(PIN_B4);
      if (tempSwitch != switch4) {
        switch4 = tempSwitch;

        //switch state has changed
        if (switch4 ==1) {
          note4 = 70 + midiPitchMultiplier;
          midiNoteOn(0, note4, 80);
          setStatusLED(HIGH);
        } else {
          midiNoteOff(0, note4);
          setStatusLED(LOW);
        }
      }


      set_adc_channel(0);
      delay_us(50);
      adcval = read_adc();
      midiPitchBend(0, adcval >> 7, adcval << 7);


      set_adc_channel(1);
      delay_us(50);
      adcval = read_adc();
      midiPitchBend(1, adcval >> 7, adcval << 7);

      set_adc_channel(2);
      delay_us(50);
      adcval = read_adc();
      midiPitchBend(2, adcval >> 7, adcval << 7);   

      set_adc_channel(3);
      delay_us(50);
      adcval = read_adc();
      midiPitchBend(3, adcval >> 7, adcval << 7);   

      set_adc_channel(4);
      delay_us(50);
      adcval = read_adc();
      midiPitchMultiplier = adcval >> 3;

   }
 }
