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

Dependencies:   FATFileSystem N5110_mod SDFileSystem USBDevice mbed

main.h

Committer:
el14pjgn
Date:
2016-05-09
Revision:
0:02a88f05d461

File content as of revision 0:02a88f05d461:

/**
@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