Final version of project

Dependencies:   FSR LSM9DS1_Library_cal USBMIDI mbed

Fork of LSM9DS1_Demo_wCal by jim hamblen

main.cpp

Committer:
KrissyHam
Date:
2016-04-29
Revision:
4:f0cd8d252c08
Parent:
3:de36d456f684

File content as of revision 4:f0cd8d252c08:

#include "mbed.h"
#include "USBMIDI.h"
#include "LSM9DS1.h"
#include "math.h" 
#include "FSR.h"

#define PI 3.14159
#define BUFFERSIZE 6

// FSR
FSR fsr_kick(p20, 10); // Pin 20 is used as the AnalogIn pin and a 10k resistor is used as a voltage divider
FSR fsr_hh(p19, 10); // Pin 19 is used as the AnalogIn pin and a 10k resistor is used as a voltage divider
bool hh_close = false;  // boolean to determine if hi-hat is closed or open
bool kicked = false;

// IMU
LSM9DS1 IMU(p9, p10, 0xD6, 0x3C);
LSM9DS1 IMU2(p28, p27, 0xD6, 0x3C);

USBMIDI midi;

Serial pc(USBTX, USBRX);
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

Timer t;
float t_prev = 0;
float t_prev2 = 0;
float t_curr = 0;
float t_curr2 = 0;
float t_gyroPrev = 0;
float t_gyroPrev2 = 0;
float t_gyroCurr = 0;
float t_gyroCurr2 = 0;
float delta_t = 0;

float y_accel = 0;
float y_accel2 = 0;

int resetIndex = BUFFERSIZE - 2;
float average[BUFFERSIZE] = {0};
int avg_index = 0;
float total = 0;
float avg_thresh = 20;

float average2[BUFFERSIZE] = {0};
int avg_index2 = 0;
float total2 = 0;
float avg_thresh2;

float prev_y_accel = 0;
float curr_y_accel = 0;
float y_accel_threshold = 0.8;
bool check_y_accel = false;
float t_prev_y_accel = 0;

float prev_y_accel2 = 0;
float curr_y_accel2 = 0;
bool check_y_accel2 = false;
float t_prev_y_accel2 = 0;

int count2 = 0;
int count = 0;

bool detectHit = 0;
bool detectHit2 = 0;
bool detectUp = 0;
bool detectUp2 = 0;

float runningAvg = 0;
float runningAvg2 = 0;

float interval = 0.20;
float hit_volume = 0;
float hit_volume2 = 0;

enum StateType {FRONT, SIDE, HIT};
enum StateType2 {FRONT2, SIDE2, HIT2};

StateType state = FRONT;   // Initial state is FRONT
StateType2 state2 = FRONT2;

void show_message(MIDIMessage msg) {
    switch (msg.type()) {
        case MIDIMessage::NoteOnType:
            printf("NoteOn key:%d, velocity: %d, channel: %d\n", msg.key(), msg.velocity(), msg.channel());
            break;
        case MIDIMessage::NoteOffType:
            printf("NoteOff key:%d, velocity: %d, channel: %d\n", msg.key(), msg.velocity(), msg.channel());
            break;
        case MIDIMessage::ControlChangeType:    
            printf("ControlChange controller: %d, data: %d\n", msg.controller(), msg.value());
            break;
        case MIDIMessage::PitchWheelType:
            printf("PitchWheel channel: %d, pitch: %d\n", msg.channel(), msg.pitch());
            break;
        default:
            printf("Another message\n");
    }    
}


int main()
{
    midi.attach(show_message);         // call back for messages received 
    pc.baud(9600);
    pc.printf("Hello world!\n");
    
    // Initialize IMUs
    IMU.begin();
    if (!IMU.begin()) {
        pc.printf("Failed to communicate with LSM9DS1 - first.\n");
    }
    IMU.calibrate(1);
    
    IMU2.begin();
    if (!IMU2.begin()) {
        pc.printf("Failed to communicate with LSM9DS1 - second.\n");
    }
    IMU2.calibrate(1);    
    
    t.start(); // start timer
    
    while(1) {
        
        // Initialize acceleration and gyroscope data for both IMUs
        while(!IMU.accelAvailable());
        IMU.readAccel();
        while(!IMU.gyroAvailable());
        IMU.readGyro();
        
        while(!IMU2.accelAvailable());
        IMU2.readAccel();
        while(!IMU2.gyroAvailable());
        IMU2.readGyro();
        
        // Create variables for ease of use for acceleration
        y_accel = IMU.calcAccel(IMU.ay);
        y_accel2 = IMU2.calcAccel(IMU2.ay);
        
        // Initialize timer
        t_curr = t.read();
        t_curr2 = t_curr;
        
        
        /**
        * FSR detection
        */
        
        // Check if values from FSRs are above a threshold (to detect hit)
        if (fsr_kick.readRaw() > 0.3){
            // Sound will only play if foot is not on FSR (eliminates continuous noise playing if pedal is held down)
            if (kicked == false){
                midi.write(MIDIMessage::NoteOn(45, fsr_kick.readRaw() * 127 + 30, 10)); // Play a kick, map the volume and boost the amplitude, channel 10
                }
            kicked = true;
            }
        else {kicked = false;}
                
        if (fsr_hh.readRaw() > 0.3){
            if (hh_close == false){
                midi.write(MIDIMessage::NoteOn(42, fsr_hh.readRaw()*127, 10)); // Play a hi-hat pedal, map the volume, channel 10
            }           
            hh_close = true;
        }
        else {hh_close = false;} 
        
        
        /** 
        * Running average for hit detection
        */
        
        // First IMU
        total -= average[avg_index];
        average[avg_index] = IMU.calcGyro(IMU.gy);
        total += average[avg_index];
        if (avg_index > resetIndex) {
            avg_index = 0;
        } else {
            avg_index++;
        }
        
        // Second IMU
        total2 -= average2[avg_index2];
        average2[avg_index2] = IMU2.calcGyro(IMU2.gy);
        total2 += average2[avg_index2];
        if (avg_index2 > resetIndex) {
            avg_index2 = 0;
        } else {
            avg_index2++;
        }              
        
        /**
        * Hit detection
        */
        
        // Detect downward hit
         if (IMU.calcGyro(IMU.gy) > 35) {
            detectHit = 1; 
        }
        
        if (IMU2.calcGyro(IMU2.gy) > 35) {
            detectHit2 = 1; 
        }
        
        // Map gyroscope value ranges to volume ranges
        hit_volume = (runningAvg + 245) * (127) / (490);            
        hit_volume2 = (runningAvg2 + 245) * (127) / (490) + 15;
        
        // First IMU
        detectUp = IMU.calcGyro(IMU.gy) <= 0;
        runningAvg = total / BUFFERSIZE;
        
        // Check if drumstick is brought down and then brought back up (eliminates continous hit detection if drumstick is just held tilted down)
        // Then check if running average is greater than a threshold (to elimate noise)
        // Elimate debouncing by only allowing a hit to play if the time interval has passed   
        if (detectHit && detectUp && (runningAvg > avg_thresh) && (t_curr - t_prev) > interval) {
            // Depending on the state, play the corresponding instrument
            switch (state) {
                case (FRONT):
                    midi.write(MIDIMessage::NoteOn(46, hit_volume, 10)); // Play ride sound
                    break;
                case (SIDE):
                    if (hh_close) {
                        midi.write(MIDIMessage::NoteOn(40, hit_volume, 10)); // Play closed hi-hat sound
                    } else {
                        midi.write(MIDIMessage::NoteOn(41, hit_volume, 10)); // Play open hi-hat sound
                    }
                    break;
            }
            detectHit = 0;
            t_prev = t_curr;
            count = 0;
        }   
        
        // Second IMU
        detectUp2 = IMU2.calcGyro(IMU2.gy) <= 0;
        runningAvg2 = total2 / BUFFERSIZE;
        
        if (detectHit2 && detectUp2 && runningAvg2 > avg_thresh2  && (t_curr2 - t_prev2) > interval) {
            switch (state2) {
                case (FRONT2):
                    midi.write(MIDIMessage::NoteOn(47, hit_volume2, 10)); // Play snare sound
                    break;
                case (SIDE2):
                    midi.write(MIDIMessage::NoteOn(51, hit_volume2, 10)); // Play clap sound
                    break;
            }
            detectHit2 = 0;
            t_prev2 = t_curr2;
        }
        
        
        /**
        * Instrument switching detection
        */
        
        curr_y_accel = y_accel;
        curr_y_accel2 = y_accel2;
        
        check_y_accel = abs(curr_y_accel - prev_y_accel) >  y_accel_threshold;
        check_y_accel2 = abs(curr_y_accel2 - prev_y_accel2) >  y_accel_threshold;
        
        // Check that y accleration is above threshold; if it is, increase the count for the number of cycles it is above this threshold
        if (check_y_accel) {
            count++;
        }
        
        if (check_y_accel2) {
            count2++;
        }
            
        // First IMU
        switch (state) {
            case (FRONT):
                // Check that y_accleration is above the threshold for at least 3 cycles
                // Elimnate debouncing by only switching if a time interval has passed
                if (check_y_accel && (count >= 3) && (t_curr - t_prev_y_accel) > 0.3) {
                    count = 0;
                    state = SIDE;
                    led1 = 1;
                    led2 = 0;
                    t_prev_y_accel = t_curr;
                }      
                break;
            case (SIDE):
                if (check_y_accel && (count >= 3) && (t_curr - t_prev_y_accel) > 0.3) {
                    count = 0;
                    state = FRONT;
                    led1 = 0;
                    led2 = 1;
                    t_prev_y_accel = t_curr;
                }
                break;
        }
        prev_y_accel = curr_y_accel;
        
        //Second IMU
        switch (state2) {
            case (FRONT2):
                if (check_y_accel2 && (count2 >= 3) && (t_curr - t_prev_y_accel2) > 0.3){
                    state2 = SIDE2;
                    count2 = 0; 
                    led4 = 1;
                    led3 = 0;
                    t_prev_y_accel2 = t_curr;
                }       
                break;
            case (SIDE2):
                if (check_y_accel2 && (count2 >= 3) && (t_curr - t_prev_y_accel2) > 0.3){
                    state2 = FRONT2;
                    count2 = 0;
                    led4 = 0;
                    led3 = 1;
                    t_prev_y_accel2 = t_curr;
                }
                break;
        }
        prev_y_accel2 = curr_y_accel2;
    }
}