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.

Dependencies:   mbed

main.cpp

Committer:
djbottrill
Date:
2013-09-14
Revision:
0:aac55e1fc12f

File content as of revision 0:aac55e1fc12f:

#include "mbed.h"
#include "USBMIDI.h"
// MIDI Stop Controller V1.0
// USB MIDI Stop switch controller, suitable for driving stops and piston on PCs and MACs running Hauptwerk digital organ software.
// This code has been written for the KL25Z but should work on other MBED boards.
// Drives up to 16 illuminated pushbuttons using one bit for both the LED output and switch input.
// LED connected to +V via ballast resistor, switch shorts output to gnd which is read when the bus is in input mode.
// 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.
// The above values provide the maximum current that a KL25Z can sink namely 4mA per output.
// Every 2ms the LED bus is switched to input in order to read the switch status then immediately switched back,
// this is not noticeable as a flicker on the LEDs. Buttons need to be pressed for 2 scans to de-bounce.
// The program will toggle the LEDs sending MIDI on/off messages, if Matching MIDI on / off data is received this data will be used 
// instaed to drive the LEDs.
// The blue LED on the KL25Z will light while the USB port is initialing
// The green LED on the KL25Z will flash as MIDI messages are received.

DigitalOut blueled  (LED1);
DigitalOut greenled (LED2);
DigitalOut redled   (LED3);

//Pins allocated for stop switches J9 and J10 headers
BusInOut led(PTE5,PTE4,PTE3,PTE2,PTB11,PTB10,PTB9,PTB8,PTE30,PTE29,PTE23,PTE22,PTE21,PTE20,PTB1,PTB0);
//Alternative set of pins using J1 header
//BusInOut led(PTC7,PTC0,PTC3,PTC4,PTC5,PTC6,PTC10,PTC11,PTA1,PTA2,PTD4,PTA12,PTA4,PTA5,PTC8,PTC9);

//Global variables
extern unsigned int rx_ledstate=0;                                                      //LED recieved status buffer
extern int rx_flag=0;                                                                   //MIDI receive flag

//Interrupt routine to receive MIDI on/off message and set LED status accordingly
void get_message(MIDIMessage msg)
{
    rx_flag=1;                                                                          //Set MIDI received status flag
    greenled=0;                                                                         //Green LED on
    switch (msg.type()) {
        case MIDIMessage::NoteOnType:                                                   //MIDI note on received
            rx_ledstate |= 1 << (msg.key()-36);                                         //Set interrupt LED status on
            break;
        case MIDIMessage::NoteOffType:                                                  //Midi note off received
            rx_ledstate ^= 1 << (msg.key()-36);                                         //Set received LED status off
            break;
        case MIDIMessage::AllNotesOffType:                                              //Midi all notes off
            rx_ledstate=0;                                                              //Set status for all LEDs to off
        default:
            rx_ledstate=0;                                                              //Any other midi command then clear all LEDs
    }
}

BusOut linksout     (PTD0,  PTC13);                                                     //Channel config links outputs
BusInOut linksin    (PTC16, PTD5);                                                      //Channel config links inputs
BusOut matrixout    (PTD3,  PTC17);                                                     //Matrix config links outputs
BusInOut matrixin   (PTA16, PTD2);                                                      //Matrix config links inputs


//Main Program
int main()
{
    blueled=0;                                                                          //Blue LED on
    redled=1;                                                                           //Red LED off
    greenled=1;                                                                         //Green LED off
    USBMIDI midi;                                                                       //Open USB MIDI
    blueled=1;                                                                          //Turn blue LED off when MIDI has initialised

//Variables
    unsigned int ledstate=0;                                                            //LED status buffer
    unsigned int pins;                                                                  //Button read buffer
    unsigned int bit=0;                                                                 //Button bitmask
    unsigned int colidx=0;                                                              //Button index
    int sw[16]= {};                                                                     //Switch status array
    int velocity = 127;                                                                 //Note velocity
    int note = 0;                                                                       //Midi note buffer

//Read jumpers to set MIDI channel number
//                   1    2    3    4    5    6    7
// [PTC13] [PTC16]  0 0  0 0  0 0  0 0  0 0  0-0  0-0
//                         |  |    | |
// [PTD5 ] [PTD0 ]  0 0  0 0  0 0  0 0  0-0  0 0  0-0

    const unsigned char tjumpers[]= {0,1,4,0,5,0,6,0,2,3};                              //Jumper settings mode translate table (0 to 6)
    unsigned char jumpers[2];                                                           //Status of the channel config jumper links
    int chan = 0 ;                                                                      //Base Midi channel
    linksin.mode(PullUp);                                                               //Setup Pull Up for chan Jumpers input pins
    linksout=2;                                                                         //Set first jumper output pin low
    jumpers[0]=3&(~linksin);                                                            //Read first jumper bits
    linksout=1;                                                                         //Set second jumper output pin low
    jumpers[1]=3&(~linksin);                                                            //Read second jumper bits
    jumpers[0]=jumpers[0]+(4*jumpers[1]);                                               //Combine into a 4 bit code
    chan=tjumpers[jumpers[0]];                                                          //Set midi channel using the tjumpers translate table

    midi.attach(get_message);                                                           //call back for MIDI messages received
    led.mode(PullUp);                                                                   //Bus pullup mode
    led.output();                                                                       //Set bus to output

//Main loop
    while(1) {
        led.input();                                                                    //Set Bus to input
        pins=~led;                                                                      //Read buttons
        led.output();                                                                   //Set Bus to output
//Process button status
        bit=1;                                                                          //Starting bitmask
        for (colidx=1; colidx<17; colidx++) {                                           //Scan 16 buttons
            note=colidx+35;
            if ((pins&bit)>0) {                                                         //Button pressed
                if (sw[colidx]<3) {                                                     //De-bounce reached?
                    sw[colidx]++;                                                       //Inc De-bounce
                    if (sw[colidx]==2) {                                                //De-Bounce reached?
                        sw[colidx]=3;                                                   //Set on status
                        if ((ledstate & bit)==0) {
                            midi.write(MIDIMessage::NoteOn(note,velocity,chan));        //Send midi on
                            ledstate |= 1 << (colidx-1);                                //Set LED on
                        } else {
                            midi.write(MIDIMessage::NoteOff(note,velocity,chan));       //Send midi off
                            ledstate ^= 1 << (colidx-1);                                //Set LED off
                        }
                    }
                }
            }
            if ((pins&bit)==0) {                                                        //Is button released?
                sw[colidx]=0;                                                           //Button released so reset de-bounce counter
            }
            bit=bit*2;                                                                  //Shift bitmask
        }                                                                               //Next button
        if (rx_flag==1) {                                                               //If midi received use receive buffer
            ledstate=rx_ledstate;                                                       //instead of the switch status
            rx_flag=0;                                                                  //Reset MIDI receive flag
            greenled=1;                                                                 //Turn green LED off
        }
        led=~ledstate;                                                                  //Update LEDs
        wait(0.002);                                                                    //De-bounce delay
    }                                                                                   //end of main loop
}                                                                                       //End of program