MIDI Stop Controller V1.0 suitable for driving Hauptwerk digital organ software. Written for the KL25Z uses BusInOut and will drive up to 16 illuminated push buttons each switch uses a single I/O pin to both drive the LED and act as a switch input. Pressing a button will alternately send MIDI note on / off messages and turn the LED on or off. If corresponding MIDI note on/off messages are received these will be used to drive the LEDs in preference to the locally generated LED signals. The MIDI channel used to send can be selected by jumpers on 4 pins of the J2 header.
main.cpp@0:aac55e1fc12f, 2013-09-14 (annotated)
- Committer:
- djbottrill
- Date:
- Sat Sep 14 21:32:06 2013 +0000
- Revision:
- 0:aac55e1fc12f
V1.0 MIDI Stop Controller
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
djbottrill | 0:aac55e1fc12f | 1 | #include "mbed.h" |
djbottrill | 0:aac55e1fc12f | 2 | #include "USBMIDI.h" |
djbottrill | 0:aac55e1fc12f | 3 | // MIDI Stop Controller V1.0 |
djbottrill | 0:aac55e1fc12f | 4 | // USB MIDI Stop switch controller, suitable for driving stops and piston on PCs and MACs running Hauptwerk digital organ software. |
djbottrill | 0:aac55e1fc12f | 5 | // This code has been written for the KL25Z but should work on other MBED boards. |
djbottrill | 0:aac55e1fc12f | 6 | // Drives up to 16 illuminated pushbuttons using one bit for both the LED output and switch input. |
djbottrill | 0:aac55e1fc12f | 7 | // LED connected to +V via ballast resistor, switch shorts output to gnd which is read when the bus is in input mode. |
djbottrill | 0:aac55e1fc12f | 8 | // White LEDs need a 390ohm resistor to +5v other LEDs can be driven from 3.3V via 220 ohm resistor or 5V via 680 ohm. |
djbottrill | 0:aac55e1fc12f | 9 | // The above values provide the maximum current that a KL25Z can sink namely 4mA per output. |
djbottrill | 0:aac55e1fc12f | 10 | // Every 2ms the LED bus is switched to input in order to read the switch status then immediately switched back, |
djbottrill | 0:aac55e1fc12f | 11 | // this is not noticeable as a flicker on the LEDs. Buttons need to be pressed for 2 scans to de-bounce. |
djbottrill | 0:aac55e1fc12f | 12 | // The program will toggle the LEDs sending MIDI on/off messages, if Matching MIDI on / off data is received this data will be used |
djbottrill | 0:aac55e1fc12f | 13 | // instaed to drive the LEDs. |
djbottrill | 0:aac55e1fc12f | 14 | // The blue LED on the KL25Z will light while the USB port is initialing |
djbottrill | 0:aac55e1fc12f | 15 | // The green LED on the KL25Z will flash as MIDI messages are received. |
djbottrill | 0:aac55e1fc12f | 16 | |
djbottrill | 0:aac55e1fc12f | 17 | DigitalOut blueled (LED1); |
djbottrill | 0:aac55e1fc12f | 18 | DigitalOut greenled (LED2); |
djbottrill | 0:aac55e1fc12f | 19 | DigitalOut redled (LED3); |
djbottrill | 0:aac55e1fc12f | 20 | |
djbottrill | 0:aac55e1fc12f | 21 | //Pins allocated for stop switches J9 and J10 headers |
djbottrill | 0:aac55e1fc12f | 22 | BusInOut led(PTE5,PTE4,PTE3,PTE2,PTB11,PTB10,PTB9,PTB8,PTE30,PTE29,PTE23,PTE22,PTE21,PTE20,PTB1,PTB0); |
djbottrill | 0:aac55e1fc12f | 23 | //Alternative set of pins using J1 header |
djbottrill | 0:aac55e1fc12f | 24 | //BusInOut led(PTC7,PTC0,PTC3,PTC4,PTC5,PTC6,PTC10,PTC11,PTA1,PTA2,PTD4,PTA12,PTA4,PTA5,PTC8,PTC9); |
djbottrill | 0:aac55e1fc12f | 25 | |
djbottrill | 0:aac55e1fc12f | 26 | //Global variables |
djbottrill | 0:aac55e1fc12f | 27 | extern unsigned int rx_ledstate=0; //LED recieved status buffer |
djbottrill | 0:aac55e1fc12f | 28 | extern int rx_flag=0; //MIDI receive flag |
djbottrill | 0:aac55e1fc12f | 29 | |
djbottrill | 0:aac55e1fc12f | 30 | //Interrupt routine to receive MIDI on/off message and set LED status accordingly |
djbottrill | 0:aac55e1fc12f | 31 | void get_message(MIDIMessage msg) |
djbottrill | 0:aac55e1fc12f | 32 | { |
djbottrill | 0:aac55e1fc12f | 33 | rx_flag=1; //Set MIDI received status flag |
djbottrill | 0:aac55e1fc12f | 34 | greenled=0; //Green LED on |
djbottrill | 0:aac55e1fc12f | 35 | switch (msg.type()) { |
djbottrill | 0:aac55e1fc12f | 36 | case MIDIMessage::NoteOnType: //MIDI note on received |
djbottrill | 0:aac55e1fc12f | 37 | rx_ledstate |= 1 << (msg.key()-36); //Set interrupt LED status on |
djbottrill | 0:aac55e1fc12f | 38 | break; |
djbottrill | 0:aac55e1fc12f | 39 | case MIDIMessage::NoteOffType: //Midi note off received |
djbottrill | 0:aac55e1fc12f | 40 | rx_ledstate ^= 1 << (msg.key()-36); //Set received LED status off |
djbottrill | 0:aac55e1fc12f | 41 | break; |
djbottrill | 0:aac55e1fc12f | 42 | case MIDIMessage::AllNotesOffType: //Midi all notes off |
djbottrill | 0:aac55e1fc12f | 43 | rx_ledstate=0; //Set status for all LEDs to off |
djbottrill | 0:aac55e1fc12f | 44 | default: |
djbottrill | 0:aac55e1fc12f | 45 | rx_ledstate=0; //Any other midi command then clear all LEDs |
djbottrill | 0:aac55e1fc12f | 46 | } |
djbottrill | 0:aac55e1fc12f | 47 | } |
djbottrill | 0:aac55e1fc12f | 48 | |
djbottrill | 0:aac55e1fc12f | 49 | BusOut linksout (PTD0, PTC13); //Channel config links outputs |
djbottrill | 0:aac55e1fc12f | 50 | BusInOut linksin (PTC16, PTD5); //Channel config links inputs |
djbottrill | 0:aac55e1fc12f | 51 | BusOut matrixout (PTD3, PTC17); //Matrix config links outputs |
djbottrill | 0:aac55e1fc12f | 52 | BusInOut matrixin (PTA16, PTD2); //Matrix config links inputs |
djbottrill | 0:aac55e1fc12f | 53 | |
djbottrill | 0:aac55e1fc12f | 54 | |
djbottrill | 0:aac55e1fc12f | 55 | //Main Program |
djbottrill | 0:aac55e1fc12f | 56 | int main() |
djbottrill | 0:aac55e1fc12f | 57 | { |
djbottrill | 0:aac55e1fc12f | 58 | blueled=0; //Blue LED on |
djbottrill | 0:aac55e1fc12f | 59 | redled=1; //Red LED off |
djbottrill | 0:aac55e1fc12f | 60 | greenled=1; //Green LED off |
djbottrill | 0:aac55e1fc12f | 61 | USBMIDI midi; //Open USB MIDI |
djbottrill | 0:aac55e1fc12f | 62 | blueled=1; //Turn blue LED off when MIDI has initialised |
djbottrill | 0:aac55e1fc12f | 63 | |
djbottrill | 0:aac55e1fc12f | 64 | //Variables |
djbottrill | 0:aac55e1fc12f | 65 | unsigned int ledstate=0; //LED status buffer |
djbottrill | 0:aac55e1fc12f | 66 | unsigned int pins; //Button read buffer |
djbottrill | 0:aac55e1fc12f | 67 | unsigned int bit=0; //Button bitmask |
djbottrill | 0:aac55e1fc12f | 68 | unsigned int colidx=0; //Button index |
djbottrill | 0:aac55e1fc12f | 69 | int sw[16]= {}; //Switch status array |
djbottrill | 0:aac55e1fc12f | 70 | int velocity = 127; //Note velocity |
djbottrill | 0:aac55e1fc12f | 71 | int note = 0; //Midi note buffer |
djbottrill | 0:aac55e1fc12f | 72 | |
djbottrill | 0:aac55e1fc12f | 73 | //Read jumpers to set MIDI channel number |
djbottrill | 0:aac55e1fc12f | 74 | // 1 2 3 4 5 6 7 |
djbottrill | 0:aac55e1fc12f | 75 | // [PTC13] [PTC16] 0 0 0 0 0 0 0 0 0 0 0-0 0-0 |
djbottrill | 0:aac55e1fc12f | 76 | // | | | | |
djbottrill | 0:aac55e1fc12f | 77 | // [PTD5 ] [PTD0 ] 0 0 0 0 0 0 0 0 0-0 0 0 0-0 |
djbottrill | 0:aac55e1fc12f | 78 | |
djbottrill | 0:aac55e1fc12f | 79 | const unsigned char tjumpers[]= {0,1,4,0,5,0,6,0,2,3}; //Jumper settings mode translate table (0 to 6) |
djbottrill | 0:aac55e1fc12f | 80 | unsigned char jumpers[2]; //Status of the channel config jumper links |
djbottrill | 0:aac55e1fc12f | 81 | int chan = 0 ; //Base Midi channel |
djbottrill | 0:aac55e1fc12f | 82 | linksin.mode(PullUp); //Setup Pull Up for chan Jumpers input pins |
djbottrill | 0:aac55e1fc12f | 83 | linksout=2; //Set first jumper output pin low |
djbottrill | 0:aac55e1fc12f | 84 | jumpers[0]=3&(~linksin); //Read first jumper bits |
djbottrill | 0:aac55e1fc12f | 85 | linksout=1; //Set second jumper output pin low |
djbottrill | 0:aac55e1fc12f | 86 | jumpers[1]=3&(~linksin); //Read second jumper bits |
djbottrill | 0:aac55e1fc12f | 87 | jumpers[0]=jumpers[0]+(4*jumpers[1]); //Combine into a 4 bit code |
djbottrill | 0:aac55e1fc12f | 88 | chan=tjumpers[jumpers[0]]; //Set midi channel using the tjumpers translate table |
djbottrill | 0:aac55e1fc12f | 89 | |
djbottrill | 0:aac55e1fc12f | 90 | midi.attach(get_message); //call back for MIDI messages received |
djbottrill | 0:aac55e1fc12f | 91 | led.mode(PullUp); //Bus pullup mode |
djbottrill | 0:aac55e1fc12f | 92 | led.output(); //Set bus to output |
djbottrill | 0:aac55e1fc12f | 93 | |
djbottrill | 0:aac55e1fc12f | 94 | //Main loop |
djbottrill | 0:aac55e1fc12f | 95 | while(1) { |
djbottrill | 0:aac55e1fc12f | 96 | led.input(); //Set Bus to input |
djbottrill | 0:aac55e1fc12f | 97 | pins=~led; //Read buttons |
djbottrill | 0:aac55e1fc12f | 98 | led.output(); //Set Bus to output |
djbottrill | 0:aac55e1fc12f | 99 | //Process button status |
djbottrill | 0:aac55e1fc12f | 100 | bit=1; //Starting bitmask |
djbottrill | 0:aac55e1fc12f | 101 | for (colidx=1; colidx<17; colidx++) { //Scan 16 buttons |
djbottrill | 0:aac55e1fc12f | 102 | note=colidx+35; |
djbottrill | 0:aac55e1fc12f | 103 | if ((pins&bit)>0) { //Button pressed |
djbottrill | 0:aac55e1fc12f | 104 | if (sw[colidx]<3) { //De-bounce reached? |
djbottrill | 0:aac55e1fc12f | 105 | sw[colidx]++; //Inc De-bounce |
djbottrill | 0:aac55e1fc12f | 106 | if (sw[colidx]==2) { //De-Bounce reached? |
djbottrill | 0:aac55e1fc12f | 107 | sw[colidx]=3; //Set on status |
djbottrill | 0:aac55e1fc12f | 108 | if ((ledstate & bit)==0) { |
djbottrill | 0:aac55e1fc12f | 109 | midi.write(MIDIMessage::NoteOn(note,velocity,chan)); //Send midi on |
djbottrill | 0:aac55e1fc12f | 110 | ledstate |= 1 << (colidx-1); //Set LED on |
djbottrill | 0:aac55e1fc12f | 111 | } else { |
djbottrill | 0:aac55e1fc12f | 112 | midi.write(MIDIMessage::NoteOff(note,velocity,chan)); //Send midi off |
djbottrill | 0:aac55e1fc12f | 113 | ledstate ^= 1 << (colidx-1); //Set LED off |
djbottrill | 0:aac55e1fc12f | 114 | } |
djbottrill | 0:aac55e1fc12f | 115 | } |
djbottrill | 0:aac55e1fc12f | 116 | } |
djbottrill | 0:aac55e1fc12f | 117 | } |
djbottrill | 0:aac55e1fc12f | 118 | if ((pins&bit)==0) { //Is button released? |
djbottrill | 0:aac55e1fc12f | 119 | sw[colidx]=0; //Button released so reset de-bounce counter |
djbottrill | 0:aac55e1fc12f | 120 | } |
djbottrill | 0:aac55e1fc12f | 121 | bit=bit*2; //Shift bitmask |
djbottrill | 0:aac55e1fc12f | 122 | } //Next button |
djbottrill | 0:aac55e1fc12f | 123 | if (rx_flag==1) { //If midi received use receive buffer |
djbottrill | 0:aac55e1fc12f | 124 | ledstate=rx_ledstate; //instead of the switch status |
djbottrill | 0:aac55e1fc12f | 125 | rx_flag=0; //Reset MIDI receive flag |
djbottrill | 0:aac55e1fc12f | 126 | greenled=1; //Turn green LED off |
djbottrill | 0:aac55e1fc12f | 127 | } |
djbottrill | 0:aac55e1fc12f | 128 | led=~ledstate; //Update LEDs |
djbottrill | 0:aac55e1fc12f | 129 | wait(0.002); //De-bounce delay |
djbottrill | 0:aac55e1fc12f | 130 | } //end of main loop |
djbottrill | 0:aac55e1fc12f | 131 | } //End of program |