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-25
- Revision:
- 12:03c189de6e2e
- Parent:
- 11:bdad1acccdad
- Child:
- 13:948c7d19acb9
File content as of revision 12:03c189de6e2e:
#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(p5,p6,p7,p8,p9,p10);//Our method of communication with LCD screen (rs e d4 d5 d6 d7) Motor motor(p24,p19,p21);//Setup for the motor (enable, direction, step) FrequencyFinder guitar(p20);//Interface to get data from guitar (input pin) AnalogOut bias(p18);//1.6v DC offset DigitalOut ledBlue(p27); DigitalOut ledGreen(p28); DigitalOut ledRed(p29); 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 short 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]; LocalFileSystem local("local"); //*************************************************** //*****************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();//string select void pitch_sel();//pitch select void start();//start tuning void stop();//stop tuning void mode();//change mode void do_nothing();//does nothing void wind_up_start();//start motor winding up void wind_down_start();//start motor winding down void wind_up_stop();//stop motor winding up void wind_down_stop();//stop motor winding down void button_init();//Set sampling period etc... for buttons void setup_buttons();//set function calls for buttons void output_menu();//Output the main menu void motor_calibration();//Calibrate the motor's direction bool check_threshold(float);//check to make sure the frequency is valid (frequency to check) void LED_initialize();//Initialization sequence for LEDs, called at start-up void set_LED(int led, int value);//sets or clears an LED: Blue=1(in tune), Red=2(flat), Green=3(sharp). Value=1(off), 0(on); int get_steps(float desired, float current); //************************************************* //*********************main************************ int main() { lcd.cls();//Clear the LCD lcd.printf("Perfect\n Pitch");//Modify to whatever we want to name this thing LED_initialize(); // wait(.5); device_init();//Setup buttons and set global variables int state=0,next_state=0; int num_steps=0; //float old_freq=0; short current_direction=up; float new_freq=0; float desired_freq=0; strings *temp=&strings_array[0]; wait(.5); 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 //old_freq=desired_freq;//We have to initalize it to something... 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 (desired_freq*2.2>new_freq && desired_freq*1.8<new_freq) { new_freq=new_freq/2; } if (check_threshold(new_freq)) {//The check_threshold function makes sure the frequency is valid (less than 500 Hz) num_steps=get_steps(desired_freq, new_freq); if ((desired_freq-.5)<new_freq && (desired_freq+.5)>new_freq) {//We are within .5Hz of the desired frequency new_freq=guitar.find_frequency(); if ((desired_freq-.5)>new_freq || (desired_freq+.5)<new_freq) {//This checks the frequency again to make sure we are close next_state=3; break; } lcd.cls(); lcd.printf("String %d\ntuned",selected_string+1); set_LED(1,0);//blue on set_LED(2,1);//red off; set_LED(3,1);//green off wait(1); 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 if (current_direction==down) { num_steps+=18;//For deadband current_direction=up; } lcd.cls(); lcd.printf("Tuning up"); set_LED(1,1);//blue off set_LED(2,0);//red on; set_LED(3,1);//green off //found_frequency=0; //wait(.5); motor.motor_turn(up,num_steps);//TODO:Adjust # of steps next_state=3; } else {//We are too high, and need to loosen the string if (current_direction==up) { num_steps+=18;//For deadband current_direction=down; } lcd.cls(); lcd.printf("Tuning down"); set_LED(1,1);//blue off set_LED(2,1);//red off; set_LED(3,0);//green on //found_frequency=0; //wait(.5); motor.motor_turn(down,num_steps); next_state=3; } } else { next_state=3; } if (start_tuning==false) {//If the stop button is pressed, the state machine returns to user input next_state=0; setup_buttons(); output_menu(); } //TODO:Determine number of steps per frequency change 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 { output_menu(); wind_up=false; wind_down=false; setup_buttons(); //set_LED(1,0); 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) { if (check_threshold(new_freq)) { lcd.cls(); lcd.locate(9,0); lcd.printf("%f",new_freq); lcd.locate(9,1); lcd.printf("%f",desired_freq); lcd.locate(0,1); lcd.printf("Desired"); lcd.locate(0,0); lcd.printf("Detected"); } } }//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); set_LED(1,0);//Turn blue LED on set_LED(2,1); set_LED(3,1); } //*************************************************** //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<0) selected_string=5; 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; output_menu(); setup_buttons(); } //*************************************************** 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=1; down=0; wind_up=false; wind_down=false; bias=.5; 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=0; //up=1; } else { //down=0; //up=1; } lcd.cls(); lcd.printf("Calibration Done"); if (start_tuning==false) { output_menu(); setup_buttons(); } } //********************************************** bool check_threshold(float freq) { strings *temp=&strings_array[selected_string]; float desired_freq=temp->get_freq();//Get the desired frequency for the string selected int hertz=0; switch (selected_string) { case 0: hertz=85; break; case 1: hertz=66; break; case 2: hertz=53; break; case 3: hertz=42; break; case 4: hertz=29; break; case 5: hertz=22; break; default: break; } if (freq>(desired_freq+hertz) || freq<(desired_freq-hertz) || freq>500) {//new_freq>(desired_freq+50) || new_freq<(desired_freq-50) lcd.cls(); lcd.printf("Pluck string %d\nagain",selected_string+1); set_LED(1,1); set_LED(2,1); set_LED(3,1);//Turn led off set_LED(2,0); set_LED(3,0);//Make the LED turn yellow //wait(.5); return false; } else return true; } void LED_initialize() { float wait_time=0.3; /* ledBlue=1;//red ledGreen=1; ledRed=0; wait(wait_time); ledRed=1;//green ledGreen=0; wait(wait_time); ledGreen=1; ledBlue=0;//blue wait(wait_time); for (int a=0; a<3; a++) { ledRed=0;//all ledGreen=0; ledBlue=0; wait(wait_time); ledRed=1; ledGreen=1; ledBlue=1; wait(wait_time); } ledBlue=0; ledRed=1;//blue ledGreen=1; */ set_LED(1,1); set_LED(2,1); set_LED(3,1); for (int b=1; b<4; b++) { for (int a=1; a<4; a++) { set_LED(a, 0); wait(wait_time); set_LED(a,1); wait(0.001); } } set_LED(1,0); set_LED(2,1); set_LED(3,1); return; } void set_LED(int led, int value) { //ledBlue=1; //ledRed=2; //ledGreen=3; //value must be an int: 0(on) or 1(off) if (value==0 || value==1) switch (led) { case(1): ledBlue=value; break; case(2): ledRed=value; break; case(3): ledGreen=value; break; default: break; } return; } //*********************************** //********get_steps***************** int get_steps(float desired, float current) { float difference=abs(desired-current); switch (selected_string) { case 5: if (difference>10) { return 60; } else if (difference>3) { return 35; } else if (difference>1) { return 15; } else { return 10; } case 4: if (difference>10) { return 60; } else if (difference>3) { return 40; } else if (difference>1) { return 23; } else { return 10; } case 3: if (difference>10) { return 40; } else if (difference>3) { return 25; } else if (difference>1) { return 15; } else { return 10; } case 2: if (difference>10) { return 33; } else if (difference>3) { return 20; } else if (difference>1) { return 15; } else { return 10; } case 1: if (difference>10) { return 30; } else if (difference>3) { return 20; } else if (difference>1) { return 10; } else { return 7; } case 0: if (difference>10) { return 20; } else if (difference>3) { return 15; } else if (difference>1) { return 8; } else { return 4; } default: return 0; break; }//end switch }