K64F drum machine, with RAW WAV sample playback, and USB midi functionality

Dependencies:   FATFileSystem N5110_mod SDFileSystem USBDevice mbed

Files at this revision

API Documentation at this revision

Comitter:
el14pjgn
Date:
Mon May 09 14:20:16 2016 +0000
Commit message:
K64F drum machine, with sample playback and USB midi functionality

Changed in this revision

FATFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
N5110_mod.lib Show annotated file Show diff for this revision Revisions of this file
SDFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
USBDevice.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
main.h Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 02a88f05d461 FATFileSystem.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FATFileSystem.lib	Mon May 09 14:20:16 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/FATFileSystem/#e960e2b81a3c
diff -r 000000000000 -r 02a88f05d461 N5110_mod.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/N5110_mod.lib	Mon May 09 14:20:16 2016 +0000
@@ -0,0 +1,1 @@
+https://developer.mbed.org/teams/ELEC2645-201516/code/N5110_mod/#d2140be00144
diff -r 000000000000 -r 02a88f05d461 SDFileSystem.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem.lib	Mon May 09 14:20:16 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/SDFileSystem/#7b35d1709458
diff -r 000000000000 -r 02a88f05d461 USBDevice.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice.lib	Mon May 09 14:20:16 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/USBDevice/#01321bd6ff89
diff -r 000000000000 -r 02a88f05d461 main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon May 09 14:20:16 2016 +0000
@@ -0,0 +1,706 @@
+# include "main.h"
+int main()
+{
+    init();   /// calls initialisation routine
+    while(1) {
+        if(USB_mode == 2) {   /// prints display output for speaker mode
+            lcd.clear();
+            lcd.printString("USB audio",0,2);
+            lcd.printString("to exit,",0,3);
+            lcd.printString("press back",0,4);
+        }
+        while(USB_mode == 2) {    ///loop for while within speaker mode
+            audio->read((uint8_t *)USBaudio_buffer); ///reads audio stream
+            USBaudio_packet_available = true; ///sets flag to indicate presence of data
+            if(buttons.back) {    ///withdraw from speaker mode
+                USB_mode = 3;   ///set USB mode to none
+                audio_tkr.detach();   ///detatch audio ticker
+                LED_scan_tkr.attach(&LED_scan_ISR,0.005);   ///re-attach tickers
+                Sequence_increment_tkr.attach(&Sequence_increment_ISR,30/tempo);
+                buttons.back = 0; ///re-set back button flag
+                USB_init(); ///re-initialise USB
+                lcd.clear();  ///set display to normal
+                LCD_printMain();
+            }
+        }
+        check_flags();  ///check for button presses
+        sleep();  ///return to sleep mode, to save power
+    }
+}
+
+/* General functions */
+
+void init()
+{
+    LCD_init();
+    USB_init();
+    Button_init();
+    LED_init();
+    IO_init();
+    tempo_init();
+    Sequence_init();
+}
+
+void IO_init()
+{
+    for (int i = 0; i < 7; i++) {
+        trigOut[i]->write(1); /// test trigger outputs
+        wait(0.1);
+        trigOut[i]->write(0);
+    }
+}
+
+int bool_to_int(bool *array, int shifter)
+{
+    switch(shifter) {
+        case 0: /// 1:1 mapping
+            return array[15]+(array[14]*0x2)+(array[13]*0x4)+(array[12]*0x8)+(array[11]*0x10)+(array[10]*0x20)+(array[9]*0x40)+(array[8]*0x80)+(array[7]*0x100)+(array[6]*0x200)+(array[5]*0x400)+(array[4]*0x800)+(array[3]*0x1000)+(array[2]*0x2000)+(array[1]*0x4000)+(array[0]*0x8000);
+        case 1 : /// even mapping
+            return (array[7]*0x2)+(array[6]*0x8)+(array[5]*0x20)+(array[4]*0x80)+(array[3]*0x200)+(array[2]*0x800)+(array[1]*0x2000)+(array[0]*0x8000);
+        case 2: /// odd mapping
+            return array[7]+(array[6]*0x4)+(array[5]*0x10)+(array[4]*0x40)+(array[3]*0x100)+(array[2]*0x400)+(array[1]*0x1000)+(array[0]*0x4000);
+    }
+    return;
+}
+
+void selector(bool *flag, int *variable)
+{
+    for(int i=0; i<8; i++) {      /// scans through input button values
+        if(buttons.steps[i]) {    /// sets value if button is pressed
+            *variable = i;
+            buttons.steps[i] = 0;
+            *flag = 0;
+            lcd.clear();          ///set display to normal
+            LCD_printMain();
+        }
+    }
+}
+
+void check_flags()
+{
+    if(Seq_flag) Sequence_increment();  /// increments sequencer if flag is set
+    if(decay_flag) {
+        for(int i = 0; i<8; i++) {      /// clears midi messages if decay flag is set
+            if(USB_mode == 0) midi->write(MIDIMessage::NoteOff(Seq_array[Seq_current_seq].structure.MIDI_note[i]));
+        }
+        for(int i = 0; i<7; i++) {      /// clears trigger outputs if decay flag is set
+            trigOut[i]->write(0);
+        }
+        decay_tkr.detach();             /// detatches decay ticker
+        decay_flag = 0;                 /// clears decay flag
+    }
+    if(ButtonFlag_press) {              /// run if any input buttons are pressed
+        /// prints button values over serial if available, for debugging
+        if(USB_mode == 1) pc->printf("step_0:%d step_1:%d step_2:%d step_3:%d step_4:%d step_5:%d step_6:%d step_7:%d \n",buttons.steps[0],buttons.steps[1],buttons.steps[2],buttons.steps[3],buttons.steps[4],buttons.steps[5],buttons.steps[6],buttons.steps[7]);
+        if(USB_mode == 1) pc->printf("start:%d skip:%d edit:%d pattern:%d inst:%d save:%d shift:%d load:%d back:%d down:%d enter:%d up:%d \n",buttons.start,buttons.skip,buttons.edit,buttons.pattern,buttons.inst,buttons.save,buttons.shift,buttons.load,buttons.back,buttons.down,buttons.enter,buttons.up);
+        if(buttons.shift) shift_LED = !shift_LED; /// toggles shift LED
+        buttons.shift = 0;                        /// clears shift button flag
+        //if(buttons.up)      buttons.up = 0;       /// clears unused button flags
+        //if(buttons.down)    buttons.down = 0;
+        if(buttons.back)    buttons.back = 0;
+        if(buttons.inst) {
+            pattern_flag = 0;
+            inst_flag = !inst_flag;               /// toggles instrument selection, and updates LCD & serial
+            if(inst_flag) {
+                if(USB_mode == 1) pc->printf("instrument_select\n");
+                lcd.printString("select inst.",0,5);
+            } else {
+                lcd.clear();
+                LCD_printMain();
+            }
+            buttons.inst = 0;
+        }
+        if(buttons.pattern) {                     /// toggles pattern selection, and updates LCD & serial
+            inst_flag = 0;
+            pattern_flag = !pattern_flag;
+            if(pattern_flag) {
+                if(USB_mode == 1) pc->printf("pattern_select\n");
+                lcd.printString("select patrn.",0,5);
+            } else {
+                lcd.clear();
+                LCD_printMain();
+            }
+            buttons.pattern = 0;
+        }
+        if(inst_flag) selector(&inst_flag,&Seq_current_inst); /// selects current instrument if inst_flag is set
+        else if(pattern_flag) selector(&pattern_flag,&Seq_current_seq); /// selects current pattern if pattern_flag is set
+        else Sequence_write(); /// otherwise, updates sequence data
+        LED_write((Seq_array[Seq_current_seq].structure.gate[Seq_current_inst])|(0x8000>>Seq_current_step)); ///writes sequence data & position indicator to matrix
+        if(buttons.skip) {
+            if(skip_flag == 0) {
+                if(USB_mode == 1) pc->printf("skip...\n");
+                Seq_prev_inst = Seq_current_inst;   /// stores current instrument, in order to return once skip setting is complete
+                Seq_current_inst = 8;               /// sets sequencer channel to skip channel
+            } else {
+                if(USB_mode == 1) pc->printf("Done skip\n");
+                Seq_current_inst = Seq_prev_inst;   /// returns to previous instrument
+            }
+            buttons.skip = 0;
+            skip_flag = !skip_flag;
+            LED_write((Seq_array[Seq_current_seq].structure.gate[Seq_current_inst])|(0x8000>>Seq_current_step));  ///updates LED output
+            lcd.clear();      ///re-draws display
+            LCD_printMain();
+        }
+        if(buttons.start) {   ///toggles sequencer ticker
+            running? Sequence_increment_tkr.detach() : Sequence_increment_tkr.attach(&Sequence_increment_ISR,30/tempo);
+            lcd.printString(running? "Paused":"       ",0,2);
+            running = !running;
+            if(running) Sequence_increment_ISR();
+            buttons.start = 0;
+        }
+        if(buttons.enter) {     ///draws main menu
+            buttons.enter = 0;
+            mainMenu_draw();
+        }
+        if(buttons.edit) {      ///draws edit menu
+            buttons.edit = 0;
+            if(skip_flag == 0) editMenu_draw();
+        }
+        if(buttons.load) {      ///loads sequence from SD card
+            load();
+            buttons.load = 0;
+        }
+        if(buttons.save) {      ///saves sequence to SD card
+            save();
+            buttons.save = 0;
+        }
+        ButtonFlag_press = 0;   ///clears button press flag
+    }
+    if(tempo_flag) {            ///runs tempo_set routine if button is pressed
+        tempo_set();
+        tempo_flag = 0;
+    }
+}
+void null() {} /// no function
+
+void USB_init()   /// initialises USB mode, dependent on USB_mode value
+{
+    switch (USB_mode) {
+        case 0:
+            if(pc!=0) pc->disconnect();   /// disconnects serial, if connected
+            if(audio!=0) audio->disconnect(); /// disconnects audio, if connected
+            midi = new USBMIDI; /// connects midi
+            break;
+        case 1:
+            if(midi!=0)  midi->disconnect(); /// disconnects midi, if connected
+            if(audio!=0) audio->disconnect(); /// disconnects audio, if connected
+            pc = new USBSerial; /// connects serial
+            break;
+        case 2:
+            if(pc!=0) pc->disconnect();   /// disconnects serial, if connected
+            if(midi!=0) midi->disconnect(); /// disconnects midi, if connected
+            audio = new USBAudio; /// connects audio
+            Sequence_increment_tkr.detach();  /// detatches all tickers, to maximise efficiency
+            LED_scan_tkr.detach();
+            audio_tkr.attach_us(audio_tkr_ISR, 1000000.0/(float)48000);
+            break;
+        case 3:
+            if(pc!=0) pc->disconnect(); /// disconnects serial, if connected
+            if(midi!=0) midi->disconnect(); /// disconnects midi, if connected
+            break;
+    }
+}
+void decay_ISR()  /// sets decay flag if called by decay ticker
+{
+    decay_flag = 1;
+}
+
+/* Button functions */
+void Button_init()  /// initialises button matrix
+{
+    Button_scan_tkr.attach(&Button_scan_ISR,0.02); ///attaches button ticker
+    ButtonIn_A.fall(&ButtonIn_A_ISR); ///connects button to ISR
+    ButtonIn_A.mode(PullUp);          ///sets pullup
+    ButtonIn_B.fall(&ButtonIn_B_ISR);
+    ButtonIn_B.mode(PullUp);
+    ButtonIn_C.fall(&ButtonIn_C_ISR);
+    ButtonIn_C.mode(PullUp);
+    ButtonIn_D.fall(&ButtonIn_D_ISR);
+    ButtonIn_D.mode(PullUp);
+    ButtonIn_E.fall(&ButtonIn_E_ISR);
+    ButtonIn_E.mode(PullUp);
+}
+void Button_scan_ISR()
+{
+    if(ButtonFlag_zero == 0) ButtonFlag_cols[ButtonOut_pos] = 0;  /// updates repeat flags
+    ButtonFlag_zero = 0;
+    ButtonOut_pos++;  /// increments button scan position
+    if(ButtonOut_pos>3) ButtonOut_pos = 0;  /// limits scan range
+    ButtonOut = ButtonOut_val[ButtonOut_pos]; /// writes to output
+}
+void ButtonIn_A_ISR()
+{
+    Button_update(0);   /// updates button flags
+}
+void ButtonIn_B_ISR()
+{
+    Button_update(1);   /// updates button flags
+}
+void ButtonIn_C_ISR()
+{
+    Button_update(2);   /// updates button flags
+}
+void ButtonIn_D_ISR()
+{
+    Button_update(3);   /// updates button flags
+}
+void ButtonIn_E_ISR()
+{
+    Button_update(4);   /// updates button flags
+}
+void Button_update(int row)
+{
+    ButtonFlag_zero = 1;  /// sets button flags
+    ButtonFlag_press = 1;
+    if(ButtonFlag_cols[ButtonOut_pos] == 0) {
+        *(keyMap_point[row][ButtonOut_pos]) = 1;  ///sets flag pointed to by position within matrix
+        ButtonFlag_cols[ButtonOut_pos] = 1;
+    }
+}
+
+/* LED functions */
+void LED_init() ///initialises LEDs
+{
+    LED_scan_tkr.attach(&LED_scan_ISR,0.005); ///Setup matrix scan ticker
+    int LED_test[] {  ///output values for test
+        0x0,0x180,0x3c0,0x7e0,0xff0,0x1ff8,0x3ffc,0x7ffe,0xFFFF,~0x180,~0x3c0,~0x7e0,~0xff0,~0x1ff8,~0x3ffc,~0x7ffe,0x0
+    };
+    for(int j=0; j!=17; j++) {  ///scan through output test values
+        LED_write(LED_test[j]);
+        wait(0.04);
+    }
+    shift_LED = 0;  /// clear shift LED
+}
+void LED_scan_ISR()                    ///Scan ISR
+{
+    LED_bus = LED_buffer[LED_pos];     ///Sends buffer value to bus output
+    LED_pos++;                         ///Increment scan position
+    if(LED_pos==4) LED_pos = 0;        ///limit range
+}
+void LED_write(uint16_t value)         ///Matrix refresh routine
+{
+    uint8_t  LED_scan_row = 0x1;
+    uint16_t LED_loadBuffer = ((value<<4) | (value>>(16-4)));              ///initialise LED_loadBuffer
+    for(int i=0; i<4; i++) {                                               ///Run loop 4 times
+        LED_buffer[i] = (~LED_loadBuffer)&0xF0|(LED_scan_row)&0xf;         ///write LED_loadBuffer nibble to FSM
+        LED_scan_row=((LED_scan_row>>1) | (LED_scan_row<<(4-1)));          ///Rotate row
+        LED_loadBuffer=((LED_loadBuffer<<4) | (LED_loadBuffer>>(16-4)));   ///rotate LED_loadBuffer
+    };
+}
+
+/* LCD functions */
+void LCD_init()   /// initialise LCD
+{
+    lcd.init();
+    LCD_set();
+    lcd.refresh();
+    lcd.printString("Drumulator",1,1);    /// display bootscreen
+    lcd.printString("Ver 2.5PI",25,3);
+    wait(1);
+    lcd.clear();
+    LCD_printMain();
+}
+void LCD_set()
+{
+    lcd.setPwmFreq(PWM_freq);             /// set PWM frequency (new function added to library)
+    lcd.setBrightness(brightness);        /// set brightness (new function added to library)
+}
+void LCD_printMain()
+{
+    lcd.drawRect(0,0,84,16,2);          /// clear upper section of the screen
+    char buffer[14];                    /// set up buffer for variable printing
+    int length = sprintf(buffer,"%d bpm",int(tempo)); /// print tempo
+    if (length <= 14) {
+        lcd.printString(buffer,0,0);
+    }
+    length = sprintf(buffer,"Seq_%d",int(Seq_current_seq)); /// print sequence position
+    if (length <= 14) {
+        lcd.printString(buffer,55,0);
+    }
+    lcd.printString(inst_names[Seq_current_inst],55,1);   /// print current instrument
+    length = sprintf(buffer,"Stp %d",(Seq_current_step/2)+1); /// print current step
+    if (length <= 14) {
+        lcd.printString(buffer,0,1);
+    }
+}
+
+/* Sequencer functions */
+void Sequence_init()  /// initialise sequencer
+{
+    Sequence_increment_tkr.attach(&Sequence_increment_ISR,30/tempo);
+}
+void Sequence_increment_ISR()    ///Increment sequencer position
+{
+    Seq_current_step++;
+    Seq_flag = 1;
+}
+void Sequence_increment()       /// output sequence data
+{
+    if(Seq_current_step>15) Seq_current_step = 0;
+    LED_write((Seq_array[Seq_current_seq].structure.gate[Seq_current_inst])|(0x8000>>Seq_current_step));  /// update LED matrix
+    while((Seq_array[Seq_current_seq].structure.gate[8]&(0x8000>>(Seq_current_step==15? 0 : Seq_current_step+1)) )!=0) {
+        Seq_current_step++;
+        if(Seq_current_step>15) Seq_current_step = 0;
+    }
+    for(int i = 0; i<8; i++) {
+        if((Seq_array[Seq_current_seq].structure.gate[i]&(0x8000>>Seq_current_step) )!=0) {
+            switch (Seq_array[Seq_current_seq].structure.Output_type[i]) {  /// update outputs
+                case 0: /// midi output
+                    if(USB_mode == 0) midi->write(MIDIMessage::NoteOn(int(Seq_array[Seq_current_seq].structure.MIDI_note[i])));
+                    decay_tkr.attach(&decay_ISR,0.1);
+                    break;
+                case 1: /// audio output
+                    audio_pos[i] = 0;
+                    audio_flag[i] = 1;
+                    if(USB_mode == 1) pc->printf("audio_flag %d = %d\n",i,audio_flag[i]);
+                    break;
+                case 2: /// trigger output
+                    trigOut[int(Seq_array[Seq_current_seq].structure.Trig_chan[i])]->write(1);
+                    decay_tkr.attach(&decay_ISR,0.1);
+                    break;
+                case 3: /// no output
+                    break;
+            };
+        }
+    }
+    char buffer[14];
+    int length = sprintf(buffer,"Stp %d",(Seq_current_step/2)+1); /// update step position display
+    if (length <= 14) {
+        lcd.printString(buffer,0,1);
+    }
+    if(tempo_update_flag) {   /// set tempo
+        Sequence_increment_tkr.detach();    ///detach increment ticker
+        Sequence_increment_tkr.attach(&Sequence_increment_ISR,30/tempo);
+        tempo_update_flag = 0;
+    }
+    Seq_flag = 0;
+}
+void Sequence_write() /// write button value to gate channel
+{
+    Seq_array[Seq_current_seq].structure.gate[Seq_current_inst] = Seq_array[Seq_current_seq].structure.gate[Seq_current_inst]^bool_to_int(buttons.steps,(shift_LED+1));
+    for(int i = 0; i!=8; i++) {
+        buttons.steps[i] = 0;
+    }
+}
+
+/* Tap tempo functions */
+void tempo_init() /// initialise tap tempo
+{
+    tempo_tapIn.rise(&tempo_ISR); /// attach tap input to ISR
+    tempo_time.start(); /// start timer
+}
+void tempo_ISR()                                                                          //Tap tempo ISR
+{
+    tempo_flag = 1;
+}
+void tempo_set()
+{
+    if(USB_mode == 1) pc->printf("tapped...");
+    if(tempo_time.read()>(8*(tempo_timerState+1))) tempo_timerState = 0;
+    switch(tempo_timerState) {
+        case 0: ///First press (timer start)
+            if(tempo_time.read()>DEBOUNCE) {  /// to prevent false triggers
+                if(USB_mode == 1) pc->printf("first tap\n");
+                tempo_time.stop();    /// reset and restart timer
+                tempo_time.reset();
+                tempo_time.start();
+                tempo_timerState++;   /// Increment state variable
+                if(USB_mode == 1) pc->printf("tap tempo started!\n");
+                lcd.printString("Set tempo.",0,5);
+            }
+            break;
+        case 1:                              ///Second press (count)
+            if(tempo_time.read()>DEBOUNCE) { /// to prevent false triggers
+                tempo_timerState++;          ///Increment state variable
+                if(USB_mode == 1) pc->printf("second tap\n");
+                tempo_debounce = tempo_time.read();
+                lcd.printString(".",59,5);
+            }
+            break;
+        case 2:                                               ///Third press (count)
+            if((tempo_time.read()-tempo_debounce)>DEBOUNCE) { /// to prevent false triggers
+                tempo_timerState++;                           ///Increment state variable
+                if(USB_mode == 1) pc->printf("third tap\n");
+                tempo_debounce = tempo_time.read();
+                lcd.printString(".",64,5);
+            }
+            break;
+        case 3:                                               ///Fourth press (Stop timer & set tempo)
+            if((tempo_time.read()-tempo_debounce)>DEBOUNCE) { /// to prevent false triggers
+                tempo_time.stop();                            ///Stop timer
+                if(USB_mode == 1) pc->printf("timer stopped...");
+                tempo = (180/tempo_time.read());
+                tempo_update(); /// update tempo
+                Seq_current_step = 15;
+                LCD_printMain();
+                if(USB_mode == 1) pc->printf("tempo updated!\n");
+                tempo_time.reset();
+                tempo_time.start();  ///reset tempo timer
+                tempo_timerState = 0; ///Reset state variable
+                tempo_debounce = 0;
+                lcd.clear();
+                LCD_printMain();
+            }
+    }
+}
+void tempo_update() /// set update flag
+{
+    if(USB_mode == 1) pc->printf("tempo set...");
+    tempo_update_flag = 1;
+}
+
+/* Menu functions */
+void mainMenu_draw()
+{
+    switch(drawMenu(mainMenu)) { /// draw main menu
+        case 0:
+            drawVariable("Tempo",&tempo,5,500,1,&tempo_update); ///set tempo
+            break;
+        case 1:
+            switch(drawMenu(displayMenu)) {  /// draw display menu
+                case 0:
+                    drawVariable("Brightness", &brightness,0.05,1,0,&LCD_set);  /// set brightness
+                    break;
+                case 1:
+                    drawVariable("PWM frequency", &PWM_freq,10,600,0,&LCD_set); /// set PWM frequency
+                    break;
+                case 2:
+                    inverse=!inverse; /// toggle screen inversion
+                    if(inverse) {
+                        lcd.inverseMode();  /// inverted display
+                    } else {
+                        lcd.normalMode(); /// normal display
+                    }
+                    lcd.clear();  /// reset display
+                    LCD_printMain();
+                    break;
+                case 3:
+                    mainMenu_draw();  /// return to main menu when back button is pressed
+            };
+            break;
+        case 2:
+            USB_mode = drawMenu(usbMenu); /// select USB mode
+            USB_init();
+            break;
+        case 3:
+            break;
+    }
+    lcd.clear();  /// reset display
+    LCD_printMain();
+}
+void editMenu_draw()
+{
+    switch (drawMenu(editMenu)) { /// draw editmenu
+        case 0: /// set output type
+            Seq_array[Seq_current_seq].structure.Output_type[Seq_current_inst] = drawMenu(outputMenu);
+            break;
+        case 1: /// set note value
+            drawVariable("Note Value",&Seq_array[Seq_current_seq].structure.MIDI_note[Seq_current_inst],1,127,0,&null);
+            break;
+        case 2: /// set trigger channel
+            drawVariable("trig chan",&Seq_array[Seq_current_seq].structure.Trig_chan[Seq_current_inst],1,6,0,&null);
+            break;
+        case 3:
+            Audio_init(); /// call wave file load procedure
+            break;
+        case 4:
+            break;
+    }
+    lcd.clear(); /// reset screen
+    LCD_printMain();
+}
+int drawMenu(const char* array[]) ///draws single level menu on screen
+{
+    int size=0;
+    int pos_s=0;
+    bool data=true;
+    int menuPos=0;
+    while(data==true) { /// checks size of array
+        size++;
+        if(array[pos_s]==0) {
+            size--;
+            data = false;
+        }
+        pos_s++;
+    }
+    lcd.clear(); /// reset display
+    LCD_printMain();
+    for (int pos=0; pos<size; pos++) { ///loops through menu entries
+        lcd.printString(array[pos],0,pos+2); ///plots menu entries
+    }
+    while(1) { /// scans input flags
+        if(buttons.up) {
+            lcd.printString(" ",79,menuPos+2);  /// clears menu indicator
+            (menuPos==0)? menuPos = size-1 : menuPos--; /// increments menu position
+            if(USB_mode == 1) pc->printf("menuPos %d\n",menuPos);
+            buttons.up = 0;
+        }
+        if(buttons.down) {
+            lcd.printString(" ",79,menuPos+2);  /// clears menu indicator
+            (menuPos==size-1)? menuPos = 0 : menuPos++; /// decrements menu position
+            if(USB_mode == 1) pc->printf("menuPos %d\n",menuPos);
+            buttons.down = 0;
+        }
+        lcd.printString("<",79,menuPos+2);  /// draw menu indicator
+        if(buttons.enter|buttons.back) {  /// return
+            buttons.enter = 0;
+            buttons.back = 0;
+            lcd.clear();
+            LCD_printMain();
+            return menuPos;
+        }
+        check_flags();
+        sleep(); /// sleeps until output
+    }
+}
+
+void drawVariable(const char* variableName,float *variable, float step_size, float max, float min, void (*function)())
+{
+    char numberbuffer[14];
+    lcd.clear();
+    LCD_printMain();
+    while(1) {
+        lcd.printString(variableName,0,3);  /// print variable name
+        if(buttons.up) {  /// increment variable
+            *variable=*variable+step_size;
+            buttons.up = 0;
+        }
+        if(buttons.down) { /// decrement variable
+            *variable=*variable-step_size;
+            buttons.down = 0;
+        }
+        if (*variable>max) *variable = max; /// limit range
+        if (*variable<min) *variable = min;
+        int length = sprintf(numberbuffer,((*variable<0.1)&&(*variable>-0.1))? ((*variable<0)?"-%d.0%d":"%d.0%d"):((*variable<0)?"-%d.%d":"%d.%d"),abs(int(*variable)),abs(int(*variable*100-(int(*variable)*100))));
+        if (length <= 14) { /// print variable
+            lcd.printString("              ",0,4);
+            lcd.printString(numberbuffer,2,4);
+        }
+        if(buttons.enter|buttons.back) { /// return
+            buttons.enter = 0;
+            buttons.back = 0;
+            lcd.clear();
+            LCD_printMain();
+            return;
+        }
+        (*function)();
+        check_flags();
+        sleep();
+    }
+}
+
+/* File Functions */
+
+void save()
+{
+    lcd.clear(); /// reset display
+    LCD_printMain();
+    lcd.printString("saving...",0,5);
+    if(USB_mode == 1) pc->printf("saving sequence...\n");
+    Seq_array[Seq_current_seq].sequence = new char [sizeof(Seq_array[Seq_current_seq].structure)];
+    std::ofstream outfile ("/sd/sequence.mdrum",std::ofstream::binary); /// create file stream
+    outfile.seekp(0);   /// set file position to zero
+    if(USB_mode == 1) pc->printf("sequence = %d\n",Seq_array[Seq_current_seq].sequence); /// output file data for debugging
+    outfile.write(Seq_array[Seq_current_seq].sequence,sizeof(Seq_array[Seq_current_seq].sequence)); /// write data to filestream
+    outfile.close();  /// close file
+    if(USB_mode == 1) pc->printf("file closed\n");
+    lcd.clear();  /// reset display
+    LCD_printMain();
+    buttons.save = 0;
+}
+
+void load()
+{
+    lcd.clear();  /// reset display
+    LCD_printMain();
+    lcd.printString("loading...",0,5);
+    if(USB_mode == 1) pc->printf("saving sequence...\n");
+    Seq_array[Seq_current_seq].sequence = new char [sizeof(Seq_array[Seq_current_seq].structure)];
+    std::ifstream infile ("/sd/sequence.mdrum",std::ifstream::binary); /// setup filestream
+    infile.seekg(0);  /// set to start of file
+    infile.read(Seq_array[Seq_current_seq].sequence,sizeof(Seq_array[Seq_current_seq].sequence)); /// read file
+    infile.close(); /// close file
+    if(USB_mode == 1) pc->printf("file closed\n");
+    lcd.clear();  /// reset display
+    LCD_printMain();
+    buttons.load = 0;
+}
+
+/* USB audio functions */
+void audio_tkr_ISR()  /// ticker to update USB audio output
+{
+    float speaker_value;  /// speaker value
+    if (USBaudio_packet_available) { /// checks if packet is available
+        speaker_value = (float)(USBaudio_buffer[USBaudio_index_buffer]); /// converts value to float
+        speaker_value = speaker_value + 32768.0; /// ofsets speaker value
+        speaker_value *= audio->getVolume(); /// adjusts output level
+        USBaudio_index_buffer++; /// increment buffer position
+        if (USBaudio_index_buffer == 96/2) { /// checks if buffer is empty
+            USBaudio_index_buffer = 0;
+            USBaudio_packet_available = false;
+        }
+    } else {
+        speaker_value = audio_prev_val; /// sets speaker value to previous available value
+    }
+    audio_prev_val = speaker_value;
+    SOUND_OUT_1.write_u16((uint16_t)speaker_value); /// writes speaker value to analog output
+}
+
+/* audio functions */
+void Audio_init()
+{
+    if(USB_mode == 1) pc->printf("Initialising Audio file\n");
+    audio_tkr.detach();
+    lcd.clear();
+    LCD_printMain();
+    lcd.printString("loading WAVs...",0,5);
+    std::ifstream is (audioFile_map[Seq_current_inst], std::ifstream::binary);
+    if(is) {  /// checks if file is present
+        if(USB_mode == 1) pc->printf("loading %s\n",audioFile_map[Seq_current_inst]);
+        is.seekg (0, is.end);
+        audio_length[Seq_current_inst] = is.tellg(); /// finds length of file
+        audio_buffer[Seq_current_inst] = new char [(audio_length[Seq_current_inst])]; /// sets buffer size
+        if(USB_mode == 1) pc->printf("length %d\n",audio_length[Seq_current_inst]);
+        is.seekg (0, is.beg);
+        is.read (audio_buffer[Seq_current_inst],audio_length[Seq_current_inst]);  /// loads file into buffer
+        is.close(); /// closes file
+    }
+    if(USB_mode == 1) pc->printf("WAVs loaded\n");
+    lcd.clear();
+    LCD_printMain();
+    if(USB_mode == 1){
+        for(int i=0;i<audio_length[Seq_current_inst];i++)
+        {
+            pc->printf("%d",audio_buffer[Seq_current_inst][i]);
+        }
+    }
+    for(int i=0;i<audio_length[Seq_current_inst];i++)
+    {
+      SOUND_OUT_1 = float(int(audio_buffer[Seq_current_inst][i]))/255;
+      wait(0.00002267573);
+    }
+    audio_tkr.attach(Audio_ISR,0.00002267573);/// attaches audio update ticker
+}
+void Audio_ISR(){
+    /*if(audio_pos[Seq_current_inst]<audio_length[Seq_current_inst]){
+        SOUND_OUT_1 = float(int(audio_buffer[Seq_current_inst][audio_pos[Seq_current_inst]]))/1800;
+        audio_pos[Seq_current_inst]++;
+    }else{
+        audio_pos[Seq_current_inst] = 0;
+    }*/
+    float speaker_value;  /// speaker value
+    for(int i = 0; i<8; i++){
+        if(audio_flag[i]==1) audio_pos[i]++;
+        if(audio_pos[i]>=audio_length[i]){
+            audio_pos[i] = 0;
+            audio_flag[i] = 0;
+        }
+    }
+    speaker_value = float(int(audio_buffer[0][audio_pos[0]])+int(audio_buffer[1][audio_pos[1]])+int(audio_buffer[2][audio_pos[2]])+int(audio_buffer[3][audio_pos[3]])+int(audio_buffer[4][audio_pos[4]])+int(audio_buffer[5][audio_pos[5]])+int(audio_buffer[6][audio_pos[6]])+int(audio_buffer[7][audio_pos[7]]))/1800;
+    if(speaker_value==0){
+        speaker_value = audio_prev_val;
+    }else{
+        SOUND_OUT_1 = speaker_value;
+        audio_prev_val = speaker_value;
+    }
+}
\ No newline at end of file
diff -r 000000000000 -r 02a88f05d461 main.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.h	Mon May 09 14:20:16 2016 +0000
@@ -0,0 +1,604 @@
+/**
+@file main.h
+@brief Header file containing functions prototypes, defines, and global variables
+@brief K64F drum machine project, for ELEC2645
+@author Peter J.G. Nye
+@date May 2016
+*/
+
+#ifndef MAIN_H
+#define MAIN_H
+
+#define     DEBOUNCE   0.2 /*!<  Debounce time for tap tempo */
+
+#include    "mbed.h"
+#include    "N5110.h"
+#include    "USBMIDI.h"
+#include    "USBSerial.h"
+#include    "USBAudio.h"
+#include    "SDFileSystem.h"
+#include    <fstream>
+
+/** @defgroup group1 Button matrix
+ *  used for the scanning of the UI buttons
+ *  @{
+ */
+
+
+/** # IO & interrupts */
+
+/** @brief Output bus used for scanning button matrix */
+BusOut      ButtonOut(PTE26,PTE25,PTD3,PTC8);
+
+/** @brief  interrupt pins connected to button matrix outputs */
+InterruptIn ButtonIn_A(PTB11);
+InterruptIn ButtonIn_B(PTB3);
+InterruptIn ButtonIn_C(PTB2);
+InterruptIn ButtonIn_D(PTB10);
+InterruptIn ButtonIn_E(PTB20);
+
+/** @brief ticker to rotate ButtonOut bus */
+Ticker      Button_scan_tkr;
+
+/** # Flags, maps & variables */
+
+/** @brief generates boolean flags for the matrix buttons */
+struct      buttons_struct {
+    bool    steps[8];
+    bool    start;
+    bool    skip;
+    bool    edit;
+    bool    pattern;
+    bool    inst;
+    bool    save;
+    bool    shift;
+    bool    load;
+    bool    back;
+    bool    down;
+    bool    enter;
+    bool    up;
+};
+buttons_struct buttons;
+
+/**
+@namespace keyMap
+@brief indicates name of button pressed
+@brief used for serial debugging
+*/
+char        *keyMap[][4] {
+    {"Step 7",  "Step 6",   "Step 5",   "Step 4"    },
+    {"Step 3",  "Step 2",   "Step 1",   "Step 0"    },
+    {"Load",    "save",     "Edit",     "Instrument"},
+    {"Pattern", "Skip",     "Shift",    "Start",    },
+    {"Back",    "Enter",    "Down",     "Up"        }
+};
+
+/** @brief used to map the button presses on to the boolean flags */
+bool        *keyMap_point[][4] {
+    {&buttons.steps[7], &buttons.steps[6],  &buttons.steps[5],  &buttons.steps[4] },
+    {&buttons.steps[3], &buttons.steps[2],  &buttons.steps[1],  &buttons.steps[0] },
+    {&buttons.load,     &buttons.save,      &buttons.edit,      &buttons.inst     },
+    {&buttons.pattern,  &buttons.skip,      &buttons.shift,     &buttons.start    },
+    {&buttons.back,     &buttons.enter,     &buttons.down,      &buttons.up       }
+};
+
+/**
+@namespace ButtonOut_val
+@brief Used to set the value of the ButtonOut bus
+@brief When scanned through, sets a different value low each cycle
+*/
+uint8_t     ButtonOut_val[]= {
+    0xE,
+    0xD,
+    0xB,
+    0x7
+};
+
+/**
+@namespace ButtonOut_pos
+@brief stores the current position of the ButtonOut scan, in order to select the correct value for the output from the ButtonOut_val array
+@brief increments upwards from 0 to 3, and then resets
+*/
+uint8_t     ButtonOut_pos = 0;
+
+/** @brief used to indicate if any button has been pressed */
+bool        ButtonFlag_zero = 0;
+
+/** @brief used to indicate if the input on the column during the last scan was equal to zero */
+bool        ButtonFlag_cols[4] = {0,0,0,0};
+bool        ButtonFlag_press = 0;
+
+/** # Functions */
+
+/**
+@namespace Button_init
+@brief function used to initialise the button matrix
+*/
+void        Button_init();
+
+/**
+@namespace Button_scan_ISR
+@brief function called by Button_scan_tkr
+@brief rotates the output of ButtonOut
+*/
+void        Button_scan_ISR();
+
+/**
+@namespace Button_update
+@brief Used to update the boolean flags within Buttons_struct
+@brief called by ButtonIn_*_ISR
+@param row - Used to indicate which ButtonIn interrupt it was called by
+*/
+void        Button_update(int row);
+
+/** @brief interrupt subroutines for ButtonIn_* input */
+void        ButtonIn_A_ISR();
+void        ButtonIn_B_ISR();
+void        ButtonIn_C_ISR();
+void        ButtonIn_D_ISR();
+void        ButtonIn_E_ISR();
+
+/** @} */ // end of group1
+
+/** @defgroup group2 LED matrix
+ *  Variables and functions used to adress the step LEDs
+ *  @{
+ */
+
+/** # IO & interrupts */
+
+/** @brief bus used to adress the LED matrix */
+BusOut      LED_bus(PTC0,PTC9,PTC5,PTC7 , PTC2,PTA2,PTB23,PTA1);
+
+/** @brief ticker used to scan through the LED matrix values */
+Ticker      LED_scan_tkr;
+
+/**
+@namespace shift_LED
+@brief LED above the shift button on the PCB
+@brief not connected to the LED matrix
+*/
+DigitalOut  shift_LED(PTE24);
+
+/** # Flags, maps & variables */
+
+/**
+@namespace LED_buffer
+@brief array used to store the requred ouput values for LED_bus
+@brief used to reduce the amount of functions to be run within the LED_scan_ISR
+*/
+int         LED_buffer[4] = {0x7,0xB,0xD,0xE};
+
+//uint16_t    LED_loadBuffer = 0;
+
+/**
+@namespace LED_pos
+@brief stores the current position of the LED_bus scan, in order to select the correct value for the output from the LED_buffer array
+@brief increments upwards from 0 to 3, and then resets
+*/
+int         LED_pos = 0;
+
+/** @brief */
+//uint8_t     LED_scan_row = 0x1;
+
+/** # LED functions */
+
+/** @brief ISR for LED matrix scan */
+void        LED_scan_ISR();
+
+/**
+@namespace LED_write
+@brief updates the values within LED_buffer to those required for the current output
+@param value - data to be written to the LED matrix
+*/
+void        LED_write(uint16_t value);                                                                          //Loads buffer
+void        LED_init();
+
+/** @} */ // end of group2
+
+/** @defgroup group3 LCD
+ *  Variables and functions used to adress the nokia 5110 LCD
+ *  @{
+ */
+
+/** # IO */
+
+/** @brief defines LCD pins */
+N5110       lcd (PTE26 , PTA0 , PTC4 , PTD0 , PTD2 , PTD1 , PTC3);
+
+/** # LCD variables */
+
+/** @brief current backlight brightness */
+float       brightness = 0.32;
+
+/** @brief current backlight PWM frequency */
+float       PWM_freq = 50;
+
+/** @brief boolean to keep track of screen colour inversion */
+bool        inverse = false;
+
+/** # LCD functions */
+
+/** @brief function to initialise screen */
+void        LCD_init();
+
+/** @brief function to set brightness and PWM frequency values */
+void        LCD_set();
+/** @brief function to print main screen to display */
+void        LCD_printMain();
+
+/** @} */ // end of group3
+
+/** @defgroup group4 Sequencing
+ *  Variables and functions used to adress the step sequencer
+ *  @{
+ */
+
+/** # Sequence data */
+
+/** @brief channel names (to be displayed to LCD) */
+char        *inst_names[]= {
+    "Kick",
+    "Snare",
+    "Crash",
+    "HH Cl",
+    "HH Op",
+    "Clap",
+    "Ride",
+    "Cowbl",
+    "Skip"
+};
+
+/**
+@namespace Sequence_struct
+@brief generates the variables requred for a sequence
+@brief Output_type indicates the type of output set for each channel
+@brief Midi_note indicates the note ouput via midi for each channel
+@brief Trig_chan indicates the hardware trigger output for each channel
+@brief gate contains the sequence data for each channel
+@brief final channel of the gate array contains step skip points
+@brief the data for each part of these arrays had to be set individually, due to limitations of the MBed IDE
+*/
+union       Sequence_struct {
+    struct  structure {
+        char        Output_type[8];
+        float       MIDI_note[8];
+        float       Trig_chan[8];
+        uint16_t    gate[9];
+    } structure;
+    char*   sequence;
+    Sequence_struct::Sequence_struct() {
+            structure.Output_type[0] = 0;
+            structure.Output_type[1] = 0;
+            structure.Output_type[2] = 0;
+            structure.Output_type[3] = 0;
+            structure.Output_type[4] = 0;
+            structure.Output_type[5] = 0;
+            structure.Output_type[6] = 0;
+            structure.Output_type[7] = 0;
+            structure.MIDI_note[0] = 36;
+            structure.MIDI_note[1] = 38;
+            structure.MIDI_note[2] = 49;
+            structure.MIDI_note[3] = 42;
+            structure.MIDI_note[4] = 56;
+            structure.MIDI_note[5] = 39;
+            structure.MIDI_note[6] = 37;
+            structure.MIDI_note[7] = 51;
+            structure.Trig_chan[0] = 0;
+            structure.Trig_chan[1] = 1;
+            structure.Trig_chan[2] = 2;
+            structure.Trig_chan[3] = 3;
+            structure.Trig_chan[4] = 3;
+            structure.Trig_chan[5] = 4;
+            structure.Trig_chan[6] = 5;
+            structure.Trig_chan[7] = 6;
+    };
+} Seq_array[8];
+
+/** # Sequence IO & interrupts */
+
+/** @brief ticker to increment sequence position */
+Ticker      Sequence_increment_tkr;
+
+/** # flags & variables */
+
+/** @brief currently selected instrument channel */
+int         Seq_current_inst = 0;
+/** @brief currently selected sequence */
+int         Seq_current_seq = 0;
+/** @brief previously selected instrument channel (used when skip button is pressed) */
+int         Seq_prev_inst = 0;
+/** @brief current sequence step */
+int         Seq_current_step = 15;
+/** @brief flag to indicate step increment */
+volatile int Seq_flag = 0;
+/** @brief current tempo value */
+float       tempo = 60;
+/** @brief flag to indicate if the sequence is currently running */
+bool        running = 1;
+/** @brief indicates whether system is waiting for instrument channel selection */
+bool        inst_flag = 0;
+/** @brief indicates whether system is waiting for sequence pattern selection */
+bool        pattern_flag = 0;
+/** @brief indicates whether in skip setup mode */
+bool        skip_flag = 0;
+
+/** # Sequence functions */
+
+/** @brief initialises sequencer */
+void        Sequence_init();
+
+/** @brief writes input data to sequence gate */
+void        Sequence_write();
+/** @brief interrupt call for sequence increment */
+void        Sequence_increment_ISR();
+/** @brief increments sequencer */
+void        Sequence_increment();
+
+/** @} */ // end of group4
+
+/** @defgroup group5 Tap tempo
+ *  Variables and functions used to control the tap-tempo
+ *  @{
+ */
+
+/** # IO & interrupts */
+
+/** @brief timer to keep track of time between button presses */
+Timer       tempo_time;
+/** @brief interrupt for tap tempo button */
+InterruptIn tempo_tapIn(PTB9);
+
+/** # flags & variables */
+
+/** @brief set when tap tempo button is pressed */
+volatile int tempo_flag;
+/** @brief indicates how many times tap tempo button has been pressed */
+int         tempo_timerState;
+/** @brief keeps track of button bounces */
+float       tempo_debounce = 0;
+/** @brief indicates that tempo has been changed */
+volatile int tempo_update_flag = 0;
+
+/** # functions */
+
+/** @brief initialises tap tempo */
+void        tempo_init();
+/** @brief interrupt called by tap tempo input */
+void        tempo_ISR();
+/** @brief tempo set routine */
+void        tempo_set();
+/** @brief Indicates tempo to be updated (used when tempo is set via menu) */
+void        tempo_update();
+
+/** @} */ // end of group5
+
+/** @defgroup group6 Audio output
+ *  Variables and functions used in the playback of wav files (not currently functional)
+ *  @{
+ */
+
+/** # flags & variables */
+
+/** @brief buffer to contain audio file data */
+char *      audio_buffer[8];
+
+/** @brief map to indicate positions of RAW WAV files on SD card */
+char*       audioFile_map[8] {
+    "/sd/samples/808/Bass.wav",
+    "/sd/samples/808/Snare.wav",
+    "/sd/samples/808/Crash.wav",
+    "/sd/samples/808/HiHat_closed.wav",
+    "/sd/samples/808/HiHat_open.wav",
+    "/sd/samples/808/Clap.wav",
+    "/sd/samples/808/Ride.wav",
+    "/sd/samples/808/CowBell.wav"
+};
+/** @brief indicates whether file is currently playing */
+bool        audio_flag[8]   {0,0,0,0,0,0,0,0};
+/** @brief indicates file length */
+int         audio_length[8] {0,0,0,0,0,0,0,0};
+/** @brief indicates current position within file */
+int         audio_pos[8]    {0,0,0,0,0,0,0,0};
+
+/** # functions */
+/** @brief loads file data into buffers */
+void        Audio_init();
+/** @brief updates speaker output */
+void        Audio_ISR();
+
+/** @} */ // end of group6
+
+/** @defgroup group7 USB
+ *  Variables and functions used to control the USB interfacing
+ *  @{
+ */
+
+/** # flags & variables */
+/** @brief keeps track of current USB mode (0 = midi, 1 = serial, 2 = speaker, 3 = none) */
+int         USB_mode = 3;
+/** @brief indicates whether the output needs clearing */
+volatile int decay_flag = 0;
+
+/** # IO & interrupts */
+
+/** @brief pointer to midi function */
+USBMIDI     *midi = 0;
+/** @brief pointer to serial function */
+USBSerial   *pc = 0;
+/** @brief pointer to audio function */
+USBAudio    *audio = 0;
+/** @brief ticker for note decay */
+Ticker      decay_tkr;
+
+
+/** # functions */
+
+/** @brief initialises USB */
+void        USB_init();
+/** @brief called by decay ticker */
+void        decay_ISR();
+
+/** @} */ // end of group7
+
+/** @defgroup group8 USB audio
+ *  Variables and functions used to act as a USB soundcard
+ *  (heavily based on existing code, [see here](https://developer.mbed.org/users/samux/code/USBAUDIO_speaker/))
+ *  @{
+ */
+
+/** # flags & variables */
+
+/** @brief ticker for audio output */
+Ticker      audio_tkr;
+/** @brief buffer to contain incoming audio packets */
+int16_t     USBaudio_buffer[96/2];
+/** @brief indicates availability of audio data */
+volatile bool USBaudio_packet_available = false;
+/** @brief indicates current position within USBaudio_buffer */
+int         USBaudio_index_buffer = 0;
+/** @brief maintains previous speaker value until more data is available */
+uint16_t    audio_prev_val = 0;
+
+/** # USB audio functions */
+/** @brief ISR for audio ouput */
+void        audio_tkr_ISR();
+
+/** @} */ // end of group8
+
+/** @defgroup group9 Menu system
+ *  Variables and functions used to control menus
+ *  based on menu system from first-year project
+ *  @{
+ */
+
+/** # Menu maps */
+
+/** @brief map for Main menu */
+const char  *mainMenu[]= {
+    "Tempo",
+    "Display",
+    "USB mode",0
+};
+/** @brief map for display submenu */
+const char  *displayMenu[]= {
+    "Brightness",
+    "PWM frequency",
+    "Invert",0
+};
+/** @brief map for USB mode submenu */
+const char  *usbMenu[]= {
+    "MIDI",
+    "Serial",
+    "Speaker",
+    "None",0
+};
+/** @brief map for output mode submenu */
+const char  *outputMenu[] = {
+    "Midi",
+    "WAV",
+    "Trigger",
+    "Muted",0
+};
+/** @brief map for edit menu */
+const char  *editMenu[] = {
+    "Output type",
+    "Midi Note",
+    "Trig chan",
+    "WAV load",0
+};
+
+/** # functions */
+
+/** @brief function to control main menu navigation */
+void        mainMenu_draw();
+/** @brief function to control edit menu navigation */
+void        editMenu_draw();
+/**
+@namespace drawMenu
+@brief draws menu to LCD, and returns selected value
+@param array[] - menu map to be drawn
+ */
+int         drawMenu(const char* array[]);
+/**
+@namespace drawVariable
+@brief draws variable to LCD
+@param variableName - name of variable being edited
+@param variable  - pointer to variable being edited
+@param step_size - amount to increment variable per buttonpress
+@param max - maximum value of variable
+@param min - minimum value of variable
+@param function - function to be called to update variables
+ */
+void        drawVariable(const char* variableName,float *variable, float step_size, float max, float min, void (*function)());
+
+/** @} */ // end of group9
+
+/** @defgroup group10 Filesystem
+ *  Variables and functions used to control file management
+ *  (only partially functional)
+ *  @{
+ */
+/** # IO */
+
+/** @brief IO for SD card interfacting */
+SDFileSystem sd(PTE3, PTE1, PTE2, PTE4, "sd"); //SD card
+
+/** # Functions */
+
+/** @brief loads current sequence data from SD card */
+void        load();
+/** @brief saves current sequence data to SD card */
+void        save();
+
+/** @} */ // end of group10
+
+/** @defgroup group11 general
+ *  General purpose variables and functions
+ *  @{
+ */
+
+/** # IO */
+
+/** @brief speaker output */
+AnalogOut   SOUND_OUT_1(DAC0_OUT);
+/** @brief trigger channels */
+DigitalOut  *trigOut[7] {
+    new     DigitalOut(PTC10),
+    new     DigitalOut(PTC11),
+    new     DigitalOut(PTC1),
+    new     DigitalOut(PTC19),
+    new     DigitalOut(PTC18),
+    new     DigitalOut(PTC17),
+    new     DigitalOut(PTC16)
+};
+
+/** # functions */
+
+/** @brief initialises system */
+void        init();
+/** @brief initialises general IO*/
+void        IO_init();
+/**
+@namespace bool_to_int
+@brief converts boolean array to integer
+@param array - boolean input
+@param shifter - integer output
+ */
+int         bool_to_int(bool *array, int shifter);
+/**
+@namespace selector
+@brief selects value between 0 and 7 based on step button press
+@param flag - flag to reset after selection is made
+@param shifter - variable to be changed
+ */
+void        selector(bool *flag, int *variable);
+
+/** @brief checks interrupt flags */
+void        check_flags();
+/** @brief null function; used to pad drawVariable when no repeated function call is needed
+void        null();
+
+/** @} */ // end of group11
+
+#endif
diff -r 000000000000 -r 02a88f05d461 mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon May 09 14:20:16 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/aae6fcc7d9bb
\ No newline at end of file