A program to automatically tune a guitar. Written by Justin Reidhead and Steven Swenson

Dependencies:   FFT FrequencyFinder Motor NewTextLCD PinDetect mbed strings

main.cpp

Committer:
melangeaddict
Date:
2012-04-17
Revision:
5:c0fd99f07536
Parent:
4:e370f322a697
Child:
6:46fb12f6ace1

File content as of revision 5:c0fd99f07536:

#include "mbed.h"
#include "Motor.h"
#include "FrequencyFinder.h"
#include "NewTextLCD.h"
#include "PinDetect.h"
#include "strings.h"
//#include "vector"

//using namespace std;
//***************************************************
//***************Globals*****************************
PinDetect string_but(p11);
PinDetect pitch_but(p12);//These are the buttons the user will interface with
PinDetect start_but(p13);
PinDetect mode_but(p14);

//DigitalOut led1(LED1);//For diagnostic purposes
//DigitalOut led2(LED2);

TextLCD lcd(p10,p9,p8,p7,p6,p5);//Our method of communication with LCD screen (rs e d4 d5 d6 d7)
Motor motor(p19,p20,p21);//Setup for the motor (enable, direction, step)
FrequencyFinder guitar(p18);//Interface to get data from guitar (input pin)

short selected_string;//Holds on to the selected string
bool current_mode;//Tuning mode or winding mode
bool start_tuning;//Bool to tell whether to start the tuning process or not
bool wind_up;//Bool for winding mode - turn motor up
bool wind_down;//Bool for winding mode - turn motor down
bool up, down;//To move the motor up or down

//vector<strings> strings_array;//Holds strings objects - basically the frequency data for each string
strings strings_array[6];

//***************************************************
//*****************constants*************************
const bool tuning_mode=false;//For setting the mode to tuning or winding
const bool winding_mode=true;

//***************************************************
//******************prototypes***********************
void device_init();

void string_sel();
void pitch_sel();
void start();
void stop();
void mode();
void do_nothing();
void wind_up_start();
void wind_down_start();
void wind_up_stop();
void wind_down_stop();

void button_init();
void setup_buttons();
void output_menu();
void motor_calibration();
bool check_threshold(float);
//*************************************************
//*********************main************************
int main() {
    lcd.cls();//Clear the LCD
    lcd.printf("Perfect\n      Pitch");//Modify to whatever we want to name this thing

    wait(.5);

    device_init();//Setup buttons and set global variables

    int state=0,next_state=0;
    //float old_freq=0;
    float new_freq=0;
    float desired_freq=0;
    strings *temp=&strings_array[0];

    output_menu();

    while (1) {
        state=next_state;

        switch (state) {
                //------------------------------------
            case 0://Stay here till the user selects the string and pitch
                if (start_tuning==true) {
                    next_state=1;
                } else {
                    next_state=0;
                    //output_menu();
                }
                break;
                //----------------------------------------
            case 1://motor calibration state
                motor_calibration();//determine which direction is up and down for the motor
                next_state=2;
                break;
                //-----------------------------------------
            case 2://begin the actual tuning
                temp=&strings_array[selected_string];
                desired_freq=temp->get_freq();//Get the desired frequency for the string selected

                next_state=3;
                break;
                //-----------------------------------------
            case 3://Do the dirty work of tuning
                new_freq=guitar.find_frequency();//Get the current frequency of the string
                if (check_threshold(new_freq)) {//The check_threshold function makes sure the frequency is valid (less than 500 Hz)
                    if ((desired_freq-.5)<new_freq && (desired_freq+.5)>new_freq) {//We are within .5Hz of the desired frequency
                        lcd.cls();
                        lcd.printf("String %d\ntuned",selected_string+1);
                        wait(.5);

                        start_tuning=false;
                        output_menu();
                        setup_buttons();
                        next_state=0;
                    } else if ((desired_freq-.5)>new_freq) {//We are too low, and need to turn the string tigher
                        motor.motor_turn(up,10);//TODO:Adjust # of steps
                        next_state=3;
                    } else {//We are too high, and need to loosen the string
                        motor.motor_turn(down,10);
                        next_state=3;
                    }
                } else {
                    next_state=3;
                }

                //TODO:Determine number of steps per frequency change
                //old_freq=new_freq;
                break;
                //-----------------------------------------
            case 4://Winding mode
                if (current_mode==winding_mode) {
                    if (wind_up) {
                        motor.motor_turn(up,5);//TODO:Adjust number of turns
                    }

                    if (wind_down) {
                        motor.motor_turn(down,5);//TODO:Adjust number of turns
                    }
                    next_state=4;
                } else {
                    next_state=0;
                }
                break;
            default:
                break;
        }//end switch
        wait_ms(5);

        if (start_tuning==false) {//If the stop button is pressed, the state machine returns to user input
            next_state=0;
            //setup_buttons();
            //output_menu();
        }

        if (current_mode==winding_mode) {//TODO:Debug this
            next_state=4;
        }

        if (start_tuning) {
            lcd.cls();
            lcd.printf("Detected %f ",new_freq);
            lcd.locate(0,1);
            lcd.printf("Desired %f",desired_freq);
        }

    }//end while

    //   return 0;
}

//***************************************************
//******************functions************************
//Display the string and pitch selection menu
void output_menu() {
    lcd.cls();
    lcd.printf("Select String: %d",selected_string+1);

    lcd.locate(0,1);
    strings *temp=&strings_array[selected_string];
    lcd.printf("Select Pitch: ");
    lcd.printf("%s",temp->get_note());
    //wait(.5);
}

//***************************************************
//Initialize the buttons
void button_init() {
    string_but.mode( PullDown );
    string_but.setSampleFrequency();

    pitch_but.mode( PullDown );
    pitch_but.setSampleFrequency();

    start_but.mode( PullDown );
    start_but.setSampleFrequency();

    mode_but.mode( PullDown );
    mode_but.setSampleFrequency();

    setup_buttons();
}

//***************************************************
//Depending on the current mode, the buttons do different things
void setup_buttons() {
    if (current_mode==tuning_mode) {//Tuning mode
        string_but.attach_asserted(&string_sel);
        string_but.attach_deasserted(&do_nothing);
        pitch_but.attach_asserted(&pitch_sel);
        pitch_but.attach_deasserted(&do_nothing);
        start_but.attach_asserted(&start);
        mode_but.attach_asserted(&mode);
    } else {//Winding mode
        string_but.attach_asserted(&wind_up_start);
        string_but.attach_deasserted(&wind_up_stop);
        pitch_but.attach_asserted(&wind_down_start);
        pitch_but.attach_deasserted(&wind_down_stop);
        start_but.attach_asserted(&do_nothing);
        mode_but.attach_asserted(&mode);
    }
}
//***************************************************
//Change the selected string - there are only six strings
void string_sel() {
    selected_string++;
    if (selected_string>5)
        selected_string=0;

    strings *temp=&strings_array[selected_string];
    temp->reset_index();

    output_menu();
}
//***************************************************
//Change the pitch of the selected string
void pitch_sel() {
    strings *temp=&strings_array[selected_string];
    temp->inc_index();

    output_menu();
}
//***************************************************
//Start the tuning process
void start() {
    start_tuning=true;

    string_but.attach_asserted(&do_nothing);//Disable the other buttons
    string_but.attach_deasserted(&do_nothing);
    pitch_but.attach_asserted(&do_nothing);
    pitch_but.attach_deasserted(&do_nothing);
    start_but.attach_asserted(&stop);       //except for the start/stop button
    mode_but.attach_asserted(&do_nothing);
}
//***************************************************
void mode() {
    if (current_mode==tuning_mode) {
        current_mode=winding_mode;
        lcd.cls();
        lcd.printf("Winding Mode");
        wait(1);
        lcd.cls();
        lcd.printf("String for up\nPitch for down");
    } else {
        current_mode=tuning_mode;
        lcd.cls();
        lcd.printf("Tuning Mode");
        wait(.5);
        output_menu();
    }
    setup_buttons();//Change the functions the buttons connect to
}
//***************************************************
void stop() {
    start_tuning=false;
}
//***************************************************
void do_nothing() {
    return;
}
//***************************************************
void wind_up_start() {
    wind_up=true;
}
//***************************************************
void wind_up_stop() {
    wind_up=false;
}
//***************************************************
void wind_down_start() {
    wind_down=true;
}
//***************************************************
void wind_down_stop() {
    wind_down=false;
}
//***************************************************
void device_init() {

    strings string1(1);
    strings string2(2);
    strings string3(3);
    strings string4(4);
    strings string5(5);
    strings string6(6);

    strings_array[0]=string1;
    strings_array[1]=string2;
    strings_array[2]=string3;
    strings_array[3]=string4;
    strings_array[4]=string5;
    strings_array[5]=string6;

    selected_string=5;
    current_mode=tuning_mode;
    start_tuning=false;
    up=true;
    down=false;
    wind_up=true;

    button_init();

    output_menu();

}
//***************************************************
void motor_calibration() {
    lcd.cls();
    lcd.printf("Calibrate Motor");
    wait(.5);

    float freq=0, freq_up=0, freq_down=0;
    bool done=false;
    lcd.cls();
    lcd.printf("Please pluck\nstring");
    wait(1);

    //motor.motor_turn(up,25)//TODO: Adjust the number of steps here
    //On second thought, we don't need to tune up and down for this, we can find the current frequency
    //and then turn the peg for the two frequencies!
    while (!done) {
        freq=guitar.find_frequency();

        if (check_threshold(freq)) {
            lcd.cls();
            freq_up=freq;
            done=true;
        }

        if (start_tuning==false)
            break;
    }
    motor.motor_turn(down,25);//TODO: Adjust the number of steps here
    done=false;
    while (!done) {
        freq=guitar.find_frequency();

        if (check_threshold(freq)) {
            lcd.cls();
            freq_down=freq;
            done=true;
        }
        if (start_tuning==false)
            break;
    }

    if (freq_up<freq_down) {
        down=true;
        up=false;
    }

    lcd.cls();
    lcd.printf("Calibration Done");

    if (start_tuning==false) {
        output_menu();
        setup_buttons();
    }
}
//**********************************************
bool check_threshold(float freq) {
    if (freq>500) {
        lcd.cls();
        lcd.printf("Pluck string \nagain");
        return false;
    } else
        return true;
}