Automatic Guitar Tuner

13,620

30

35

Introduction: Automatic Guitar Tuner

Two things that I really like to do are: play guitar and tinker with my Arduino. I was very interested at the thought of this project, so I decided to do it. I am new to programming, so this was a real challenge to me!

This machine works with an electric guitar. It takes the electrical signal transmitted from the guitar and analyzes the code. It all starts with the Op Amp circuit. The circuit itself and the code was designed by amandaghassaei, and I want to thank her for helping me get a running start on my project. 

Here is the list of processes in a nutshell:
1. The string is picked, and the electrical signal is sent through the stereo cable, which carries the sound waves.
2. The female stereo adapter receives the sound waves and puts it into the Op Amp circuit.
3. The Op Amp circuit takes the sound waves and increases the amplitude, so that the Arduino can read it easily. It then sends the signal into the Arduino to be sampled.
4. The Arduino samples the frequency of the sound waves, and records it on the serial port so the user can see.
5. The Arduino looks at which direction the 6-way rotary switch is in, so that it can determine which string it is tuning.
6. The position of the rotary switch determines what the desired frequency is for the string to be at (with a margin of error of 2Hz)
7. If the String is not in tune, then the motor moves accordingly.
8. This process repeats until the string is tuned, then the user moves on to the next string.

Share

    Recommendations

    • Water Contest

      Water Contest
    • Fix It! Contest

      Fix It! Contest
    • Metalworking Contest

      Metalworking Contest

    35 Discussions

    Can I get Schematic please?

    I am currently working on the schematic. I will post it as soon as possible. As far as the audio input circuit, go to amandaghassaei's arduino audio input instructable. Thank you for your interest!

    1 reply

    can i know what the component that u use in this project?..

    The below code compiled

    #include <Servo.h>

    Servo Servo1; //declaration of servo object

    int angleStill = 90; //stores servo position

    int angle = 90; //stores servo position

    int trim = 0; //trim adjustment to zero position

    int servoPin = 8; //Arduino pin assigned to servo

    int clockwisespeed = 120; //the speed to go in the clockwise direction

    int countclockwisespeed = 60; //the speed to go in the counter clockwise direction

    boolean clipping = 0; //clipping indicator variables

    //data storage variables

    byte newData = 0;

    byte prevData = 0;

    unsigned int time = 0;//keeps time and sends values to store in timer[] occasionally

    int timer[10];//sstorage for timing of events

    int slope[10];//storage fro slope of events

    unsigned int totalTimer;//used to calculate period

    unsigned int period;//storage for period of wave

    byte index = 0;//current storage index

    float frequency;//storage for frequency calculations

    int maxSlope = 0;//used to calculate max slope as trigger point

    int newSlope;//storage for incoming slope data

    int minfreq; //it will be changed according to its string

    int maxfreq; //it will be hanged according to to its string

    int basefreq = 0; //define baseline noise to ignore any frequency less than this value

    //int highstring;//says if you are tuning high string or not

    //variables for decided whether you have a match

    byte noMatch = 0;//counts how many non-matches you've received to reset variables if it's been too long

    byte slopeTol = 3;//slope tolerance- adjust this if you need

    int timerTol = 10;//timer tolerance- adjust this if you need

    int notenum = 0; //set the guitar string number I want to tune

    int notenumPrior = 0; //holds the previously selected guitar string

    //-------------------------------------------------------------------------------------------------------------

    //all Arduino programs must have a setup routine

    //Starts Setup routine

    void setup(){

    Serial.begin(9600); //begins sampling the serial port for monitoring purposes

    pinMode(13, OUTPUT); //clipping indicator

    pinMode(12, OUTPUT); //wave period indicator

    pinMode(11, OUTPUT); //freq too low

    pinMode(10, OUTPUT); //freq spot on

    pinMode(9, OUTPUT); //freq too high

    //sets all three pitch indicator lights off

    digitalWrite(11, LOW);

    digitalWrite(10, LOW);

    digitalWrite(9, LOW);

    pinMode(7, INPUT);// different paths from dip switch indicating the notenum value (output)

    pinMode(2, INPUT);

    pinMode(3, INPUT);

    pinMode(4, INPUT);

    pinMode(5, INPUT);

    pinMode(6, INPUT);

    digitalWrite(7, HIGH);// making sure the input pins are set high, so when pressed they will be on low

    digitalWrite(2, HIGH);

    digitalWrite(3, HIGH);

    digitalWrite(4, HIGH);

    digitalWrite(5, HIGH);

    digitalWrite(6, HIGH);

    Servo1.attach(servoPin); //attaches servo on pin x to servo object

    //ADC - Handle Analog to Digital Conversion of Guitar Signal

    cli(); //disables interrupts

    //set up continuous sampling of analog pin 0 at 38.5kHz

    //clear ADCSRA and ADCSRB registers

    ADCSRA = 0;

    ADCSRB = 0;

    ADMUX |= (1 << REFS0); //set reference voltage

    ADMUX |= (1 << ADLAR); //left align the ADC value- so we can read highest 8 bits from ADCH register only

    ADCSRA |= (1 << ADPS2) | (1 << ADPS0); //set ADC clock with 32 prescaler- 16mHz/32=500kHz

    ADCSRA |= (1 << ADATE); //enabble auto trigger

    ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete

    ADCSRA |= (1 << ADEN); //enable ADC

    ADCSRA |= (1 << ADSC); //start ADC measurements

    sei();//enable interrupts

    }

    void reset()

    {//clea out some variables

    index = 0;//reset index

    noMatch = 0;//reset match couner

    maxSlope = 0;//reset slope

    }

    //Launch Continuous Interupt Service Routine (ISR) for Sampling Analog to Digital Conversion of Guitar Audio Input

    ISR(ADC_vect)

    {//when new ADC value ready

    PORTB &= B11101111;//set pin 12 low

    prevData = newData;//store previous value

    newData = ADCH;//get value from A0

    if (prevData < 127 && newData >=127){//if increasing and crossing midpoint

    newSlope = newData - prevData;//calculate slope

    if (abs(newSlope-maxSlope)) //record new data and reset time

    slope[index] = newSlope;

    timer[index] = time;

    time = 0;

    if (index == 0)

    {//new max slope just reset

    PORTB |= B00010000;//set pin 12 high

    noMatch = 0;

    index++;//increment index

    }

    else if ( abs(timer[0]-timer[index]) ) //sum timer values

    totalTimer = 0 ;

    for (byte i=0;i= totalTimer+=timer[i];)

    {

    period = totalTimer;//set period

    //reset new zero index values to compare with

    timer[0] = timer[index];

    slope[0] = slope[index];

    index = 1;//set index to 1

    PORTB |= B00010000;//set pin 12 high

    noMatch = 0;

    }

    }

    else{//crossing midpoint but not match

    index++;//increment index

    if (index > 9)

    {

    reset();

    }

    else if (newSlope>maxSlope)

    {//if new slope is much larger than max slope

    maxSlope = newSlope;

    time = 0;//reset clock

    noMatch = 0;

    index = 0;//reset index

    }

    else{ //slope not steep enough

    noMatch++;//increment no match counter

    }

    }

    if (noMatch>9){

    reset();

    }

    if (newData == 0 || newData == 1023){//if clipping

    PORTB |= B00100000;//set pin 13 high- turn on clipping indicator led

    clipping = 1;//currently clipping

    }

    time++;//increment timer at rate of 38.5kHz

    }

    //---------------------------------------------------------------------------------------------------

    //---------------------------------------------------------------------------------------------------

    void checkClipping(){//manage clipping indicator LED

    if (clipping){//if currently clipping

    PORTB &= B11011111;//turn off clipping indicator led

    clipping = 0;

    }

    }

    //----------------------------------------------------------------------------------------------

    //Start of Main Arduino Loop

    void loop() // loop

    {

    //highstring = 0;

    frequency = 38462/float(period); //calculate frequency timer rate/period

    // added for debugging and visualizing data

    Serial.print(frequency);

    Serial.println(" hz");

    Serial.println(" ");

    Serial.println("string picked: ");

    Serial.print(notenum);

    notenum_val(); //call function to determine value of note/string we want to tune

    freq_range_identify(); //set frequency threshold ranges for string previously selected

    checkClipping(); //frequency determining and led indicator loop

    set_indicator_lights(); //checks value of current frequency and lights correct indicator light. Then moves servo accordingly

    //Serial.println(angle);

    move_motor(); //move tuning servo motor

    //delay(1000); //turn on to control debouncing

    notenumPrior = notenum;

    } //end of main loop

    //-----------------------------------------------------------------------------------------------

    //Determine String selected from rotary switch and voltage values on designated arduino pins

    void notenum_val()

    {

    int val_1 = digitalRead(2); //read the value of rotary switch pins

    int val_2 = digitalRead(3);

    int val_3 = digitalRead(4);

    int val_4 = digitalRead(5);

    int val_5 = digitalRead(6);

    int val_6 = digitalRead(7);

    if (val_1 == LOW && val_2 == HIGH && val_3 == HIGH && val_4 == HIGH && val_5 == HIGH && val_6 == HIGH) //switch set on pressed, then notenum = 1

    {

    if (notenumPrior != 1)

    {

    delay(5000);

    notenum = 1;

    }

    else

    {

    notenum = 1;

    }

    }

    else if (val_1 == HIGH && val_2 == LOW && val_3 == HIGH && val_4 == HIGH && val_5 == HIGH && val_6 == HIGH) //Switch 3 pressed, noenum = 2

    {

    if (notenumPrior != 2 )

    {

    delay(5000);

    notenum = 2;

    }

    else

    {

    notenum = 2;

    }

    }

    else if (val_1 == HIGH && val_2 == HIGH && val_3 == LOW && val_4 == HIGH && val_5 == HIGH && val_6 == HIGH) //switch 4 pressed, notenum = 3

    {

    if (notenumPrior != 3)

    {

    delay(5000);

    notenum = 3;

    }

    else

    {

    notenum = 3;

    }

    }

    else if (val_1 == HIGH && val_2 == HIGH && val_3 == HIGH && val_4 == LOW && val_5 == HIGH && val_6 == HIGH) //switch 5 pressed, notenum = 4

    {

    if (notenumPrior != 4)

    {

    delay(5000);

    notenum = 4;

    }

    else

    {

    notenum = 4;

    }

    }

    else if (val_1 == HIGH && val_2 == HIGH && val_3 == HIGH && val_4 == HIGH && val_5 == LOW && val_6 == HIGH) //switch 6 pressed, notenum = 5

    {

    if (notenumPrior != 5)

    {

    delay(5000);

    notenum = 5;

    }

    else

    {

    notenum = 5;

    }

    }

    else if (val_1 == HIGH && val_2 == HIGH && val_3 == HIGH && val_4 == HIGH && val_5 == HIGH && val_6 == LOW) //switch 7 pressed, notenum = 6

    {

    if (notenumPrior != 6)

    {

    delay(5000);

    notenum = 6;

    }

    else

    {

    notenum = 6;

    }

    }

    else

    {

    notenum == 0;

    //sets all three pitch indicator lights off

    digitalWrite(11, LOW);

    digitalWrite(10, LOW);

    digitalWrite(9, LOW);

    }

    }

    //---------------------------------------------------------------------------------------------------

    // Sets the flat, sharp and spot on frequency thresholds depending on the string we're trying to tune

    void freq_range_identify()

    {

    switch (notenum)

    {

    case 1://desired frequency=80-84 -- ideal value is 82

    minfreq = 80;

    maxfreq = 84;

    break;

    case 2://desired frequency between 108-112 ideal=110

    minfreq = 108;

    maxfreq = 112;

    break;

    case 3://desired frequency between 145-149 ideal= 147

    minfreq = 145;

    maxfreq = 149;

    break;

    case 4://desired frequency between 194-198 ideal=196

    minfreq = 194;

    maxfreq = 198;

    break;

    case 5://desired frequency= 245-249 -- ideal value is 247

    minfreq = 245;

    maxfreq = 249;

    break;

    case 6: //desired frequency between 328-332 ideal=330

    minfreq = 328;

    maxfreq = 332;

    //highstring = 1;//stating high string is one being tuned

    break;

    }

    }

    //---------------------------------------------------------------------------------------------------

    //Sets the 3 appropriate pitch indicator lights and sets the direction and speed of the tuning motor

    void set_indicator_lights()

    {

    // if (highstring = 1)

    //{

    // checkfreq();

    //}

    if (frequency <= basefreq)

    {

    digitalWrite (11, LOW);

    digitalWrite (10, LOW);

    digitalWrite (9, LOW);

    angle = 90;

    }

    else if (frequency < minfreq && frequency > basefreq)

    {

    digitalWrite (11, HIGH);

    digitalWrite (10, LOW);

    digitalWrite (9, LOW);

    angle = countclockwisespeed;

    }

    else if (frequency > maxfreq)

    {

    digitalWrite (11, LOW);

    digitalWrite (10, LOW);

    digitalWrite (9, HIGH);

    angle = clockwisespeed;

    }

    else

    {

    digitalWrite (11, LOW);

    digitalWrite (10, HIGH);

    digitalWrite (9, LOW);

    angle = 90;

    delay(1000);

    checkfreq();

    }

    }

    //---------------------------------------------------------------------------------------------------

    void checkfreq()

    {

    frequency = 38462/float(period); //calculate frequency timer rate/period

    Serial.println("doublecheck");

    Serial.print(frequency);

    Serial.println(" hz");

    Serial.println(" ");

    if (frequency <= basefreq)

    {

    digitalWrite (11, LOW);

    digitalWrite (10, LOW);

    digitalWrite (9, LOW);

    angle = 90;

    }

    else if (frequency < minfreq && frequency > basefreq)

    {

    digitalWrite (11, HIGH);

    digitalWrite (10, LOW);

    digitalWrite (9, LOW);

    angle = countclockwisespeed;

    }

    else if (frequency > maxfreq)

    {

    digitalWrite (11, LOW);

    digitalWrite (10, LOW);

    digitalWrite (9, HIGH);

    angle = clockwisespeed;

    }

    else

    {

    digitalWrite (11, LOW);

    digitalWrite (10, HIGH);

    digitalWrite (9, LOW);

    angle = 90;

    Serial.println("String is tuned! Please move on!");

    Serial.println(" ");

    delay(5000);

    }

    }

    //Turns the tuning motor appropriately

    void move_motor()

    {

    Servo1.write(angle+trim);

    delay(50);

    Servo1.write(angleStill+trim);

    }

    Last time I checked it compiled correctly and worked with the circuit. I will work on cleaning up the code and making a schematic so you can hopefully make your own!

    what kind of microphone did you use?

    Can anyone link Amanda's stuff on here for me? I'm having trouble finding it

    The low E on a guitar is 82.41 Hz. If you go low by 2 Hz (your margin of error) then you end up about halfway to Eb. That quarter tone is *very* noticeable.

    I'm not saying this to discourage you, or discount your work. On the contrary, I think this is a fantastic idea and great work. I just want to see it get even better!

    Has anyone been able to replicate this, and if so, how did you wire the 2 pol 6 way switch with the arduino?

    Owhhh..hmmm, let say i do exactly your project like on the picture and take your code. Will the project works? Or i need to refer to amandaghassaei's project too?

    1 reply

    The audio input and frequency detection I used are identical to amandaghassaei's. I reccommend you follow her instructables to make them, simply because I am working on cleaning up the code and making a schematic so you can make your own. Thanks.

    I will get on it. Sorry I have been absent, I have been rather busy recently. I will do whatever I can to help! I do not have a schematic, but I will make one. Thanks for your interest!