Introduction: Guitar Tuner for the Blind (using an Arduino)

About: A charity that builds custom equipment to help people with disabilities.
How to modify a guitar tuner so it can be used by a blind person
This build uses an Arduino Pro mini microcontroller, (all code is provided).
This project was undertaken for the charity Remap, which provides custom-made equipment for people with disabilities.




Summary
Begin with an LED electronic guitar tuner. I used a Cherub Guitar Mate (WST-550), which cost about £10 from eBay. It was a good choice for this project as it worked well and, as it uses through-hole LEDs, it was quite easy to solder to.

Use a microcontroller (Arduino) to read the LED's then output the information as a series of tones through a headphone.


Using the tuner

When it is turned on, the tuner will play a scale to let you know it’s on.
If the tuner is set to semitone tuning mode it will play 4 low-frequency flat tones.

When a guitar string is sounded, the tuner will play the note it believes the string is playing before either playing three sharp or three flat tones, depending on whether the string is sharp or flat.

The duration of these three tones will depend on how sharp or flat the string is (long tones if the sounded string is very out of tune, short tones if it is nearly correct).

If the string is in tune, the tone associated with the string will be repeated.

A specific string can be selected by pressing the button on the back of the tuner, the tuner will cycle through the strings to be tuned. It will then only give feedback tones (as in default mode, above) once the correct string is played.







Step 1: Dismantle the Guitar Tuner

To dismantle the guitar tuner remove the battery and battery holder.

Undo the two screws on the back of the tuner and gently prise the two halves of the case apart (I used my fingernails).









Step 2: Make Some Space

In order to make some space in the guitar tuner, you’ll need to do the following:
 

Modify the plastic case

I used a knife, some small files and some wire cutters to clear space for the Arduino in the back of the guitar tuner.
One of the screw holes in the case will need to be removed, as well as some of the plastic that holds the battery in place.


Modify the circuit board

Remove the black foam battery pad and de-solder the battery contacts. Some of the through-hole components may have wires sticking quite far out of the back of the board, so tidy them up and clip them down to make as much space as possible. 


Step 3: The Circuit

In order to use slightly fewer Arduino input pins, some of the very high and very low tuner signals were combined with diodes.

See the picture for how to construct the circuit...

The other additional components (headphone, button etc.) will be discussed in step 5.

Step 4: Add the Arduino

Solder the arduino to the back of the guitar tuner circuit

To insulate the Arduino from the guitar tuner circuit, I used a piece of plastic from some packaging and held it in place with a sticky foam pad.

This build uses up most of the Arduino IO pins (even the analogue inputs have to be used as digital inputs).

I found that fairly thick enamel copper wire was the easiest to use for this job; its insulation can be melted off using a soldering iron. However, it’s best to use plenty of fresh solder. Starting from the open (cut) end of the wire also seems to help.

Step 5: Add the Backpack

Some of the components won’t fit inside the tuner casing. So I put the battery, button, power-smoothing capacitor and headphone on the back of the tuner.

I made the backpack arrangement detachable from the main circuit so that I would still be able to open the tuner for re-programming if required.
 

Feedback problems

A resistor has been put in series with the headphone; it can't be seen on these pictures as it is surface mounted and located under the circuit board. Use the highest value resistor you can that will still give loud enough tones.

Using a large-value resistor and a big power capacitor helps prevent the output tones from interfering with the tuner; if this happens, it can cause it to interfere with itself and go a bit mad.

I used a 470uF 16V capacitor and a 470Ohm resistor. However, you may need to experiment in order to find what works for you.


Capacitor placement

If the capacitor remains permanently charged (that is, if it is in the circuit before the power switch) it may be bad for battery life as it will have a leakage current.

Step 6: Programe - Arduino Code

// Written in Arduino 1.0.1, for Pro Mini 3.3v ATmega328
// December 2012
// Code written for REMAP: www.remap.org.uk A charity that produces custom made equipment for people with disabilities.
// Code designed to use an Arduino to make a guitar tuner suitable for use by the blind
// The guitar tuner modified was a Cherub WST-550
// Use, copy, modify, improve the code all you like, no guarantees though....Good luck / have fun....


// This sets the properties of the feedback tones.
#define NOTE_FLAT 93       // The tone played when a flat note is detected: G Flat
#define NOTE_SHARP 887     // The tone played when a sharp note is detected: D Sharp
#define NOTE_6E  105       // The tone played when an 6E is detected (but the tone is actually E4)
#define NOTE_5A  157       // The tone played when an 5A is detected (but the tone is actually A3)
#define NOTE_4D 235        // The tone played when an 4D is detected (but the tone is actually D3)
#define NOTE_3G  352       // The tone played when an 3G is detected (but the tone is actually G2)
#define NOTE_2B 559        // The tone played when an 2B is detected (but the tone is actually B1)
#define NOTE_1E  837       // The tone played when an 1E is detected (but the tone is actually E1)
#define NOTE_DURATION  300 // All times in milliseconds The duration of tone played on startup or when selecting a string
#define NOTE_DELAY1 200    // Time in-between feedback beeps
#define NOTE_DUR2 400      // The duration of tone played when an in tune string is detected

// Input pins for reading from the note LEDs
int p6E = 7;    // Pin connected to the 6E LED
int p5A = 6;    // Pin connected to the 5A LED
int p4D = 5;    // Pin connected to the 4D LED
int p3G = 4;    // Pin connected to the 3G LED
int p2B = 3;    // Pin connected to the 2B LED
int p1E = 2;    // Pin connected to the 1E LED

// Input pins for reading from the tune LEDs
int p40 = 11;  // Pin connected to the diodes which combine the +50 and +40 LEDs
int p30 = 12;  // Pin connected to the +30 LED
int p20 = 13;  // Pin connected to the +20 LED
int p10 = 14;  // (Analogue pin 0) Pin connected to the +10 LED
int tune = 15; // (Analogue pin 1) Pin connected to the 0 LED
int n10 = 16;  // (Analogue pin 2) Pin connected to the -10 LED
int n20 = 18;  // (Analogue pin 4) Pin connected to the -20 LED
int n30 = 17;  // (Analogue pin 3) Pin connected to the -30 LED
int n40 = 19;  // (Analogue pin 5) Pin connected to the diodes which combine the -40 and -50 LEDs

// Other pins
int spkr = 10;  // Output Pin that connects to the headphone via a resistor (Highest value that still gives a loud enough output).
int button = 9; // Input Pin that connects to the string select button.
int flat = 8;   // Input Pin that senses if the tuner is in semitone mode?

// Variables
int offset = 0;      // How far out of tune the string is, eg if LED -30 is lit the value of this variable will be -40.
int note = 0;        // Variable to record which note was detected 1 = 1E , 2 = 2B, 3 = 3G, 4 = 4D, 5 = 5A, 6 = 6E.
int noteSelect = 0;  // This stores which string has been selected if the specific string mode is in use 0 = off.
int lastOffset = 0;  // Previous offset seen.
int lastNote = 0;    // Previous note seen.


void setup(){

  Serial.begin(9600);  // For fault finding
 
  //Set pin modes
  pinMode(p6E,INPUT);
  pinMode(p5A,INPUT);
  pinMode(p4D,INPUT);
  pinMode(p3G,INPUT);
  pinMode(p2B,INPUT);
  pinMode(p1E,INPUT);

  pinMode(p40,INPUT);
  pinMode(p30,INPUT);
  pinMode(p20,INPUT);
  pinMode(p10,INPUT);
  pinMode(tune,INPUT);
  pinMode(n10,INPUT);
  pinMode(n20,INPUT);
  pinMode(n30,INPUT);
  pinMode(n40,INPUT);

  pinMode(flat,INPUT);
  pinMode(spkr,OUTPUT);
  pinMode(button,INPUT);
  digitalWrite(button,HIGH);


  // Play some tones on start up to let the user know the tuner is working.
  tone(spkr, NOTE_1E, NOTE_DURATION);
  delay(NOTE_DELAY1);
  tone(spkr, NOTE_2B, NOTE_DURATION);
  delay(NOTE_DELAY1);
  tone(spkr, NOTE_3G, NOTE_DURATION);
  delay(NOTE_DELAY1);
  tone(spkr, NOTE_4D, NOTE_DURATION);
  delay(NOTE_DELAY1);
  tone(spkr, NOTE_5A, NOTE_DURATION);
  delay(NOTE_DELAY1);
  tone(spkr, NOTE_6E, NOTE_DURATION);
  delay(800);


  //Check if the tuner is in semitone tuning mode. If it is, play some more tones
  if(digitalRead(flat) == 0){
    Serial.println("Semitone mode is on");
    tone(spkr, NOTE_FLAT, 500);
    delay(800);
    tone(spkr, NOTE_FLAT, 500);
    delay(800);
    tone(spkr, NOTE_FLAT, 500);
    delay(800);
    tone(spkr, NOTE_FLAT, 500);
    delay(800);
  }

}


void loop(){
  lastOffset = offset;
  lastNote = note;
  ButtonV(); // Check if the button is being pressed
  NotesV();  // Check if any strings can be heard
  OffsetsV();// See how out of tune the strings are
  if(note != 0){ // If a string has been detected
    if(noteSelect == 0 || noteSelect == note){ // Check if a specific string is being tuned
      if(note == lastNote){    // Make sure the reading has stabilised for a while (i.e. two repeat readings)
        if(offset == lastOffset){  // Check reading has stabilised
          Output();  // Give audio feedback
        }
      }


    }
  }

  delay(200);

}





void Output(){ // A note has been detected so time to give some feedback
  delay(100);
 
  // Tone to show which note
  if(note == 1){
    tone(spkr, NOTE_1E, NOTE_DUR2);
  }
  if(note == 2){
    tone(spkr, NOTE_2B, NOTE_DUR2);
  }
  if(note == 3){
    tone(spkr, NOTE_3G, NOTE_DUR2);
  }
  if(note == 4){
    tone(spkr, NOTE_4D, NOTE_DUR2);
  }
  if(note == 5){
    tone(spkr, NOTE_5A, NOTE_DUR2);
  }
  if(note == 6){
    tone(spkr, NOTE_6E, NOTE_DUR2);
  }
  delay(100);

  // Tone to give feedback on how sharp or flat.
  if(offset > 1 || offset < 0){
    offset = offset * 5;
    if(offset < 0){
      offset = offset*-1;
      tone(spkr, NOTE_FLAT, offset);
      delay(250);
      tone(spkr, NOTE_FLAT, offset);
      delay(250);
      tone(spkr, NOTE_FLAT, offset);
      delay(250);
    }
    else{
      tone(spkr, NOTE_SHARP, offset);
      delay(250);
      tone(spkr, NOTE_SHARP, offset);
      delay(250);
      tone(spkr, NOTE_SHARP, offset);
      delay(250);
    }
  }
  else{ // What to play if the string is in tune
    if(note == 1){
      tone(spkr, NOTE_1E, NOTE_DUR2);
    }
    if(note == 2){
      tone(spkr, NOTE_2B, NOTE_DUR2);
    }
    if(note == 3){
      tone(spkr, NOTE_3G, NOTE_DUR2);
    }
    if(note == 4){
      tone(spkr, NOTE_4D, NOTE_DUR2);
    }
    if(note == 5){
      tone(spkr, NOTE_5A, NOTE_DUR2);
    }
    if(note == 6){
      tone(spkr, NOTE_6E, NOTE_DUR2);
    }
    delay(400);
  }

}


void ButtonV(){  // Check if a specific string is being selected
  if(digitalRead(button) == 0){ // Read the button
    noteSelect++;  // Increment note selected every button press

    if(noteSelect == 7){ // Tones to play if all the notes have been cycled through i.e. return to normal mode
      noteSelect = 0;
      tone(spkr, NOTE_6E, NOTE_DURATION);
      delay(NOTE_DELAY1);
      tone(spkr, NOTE_5A, NOTE_DURATION);
      delay(NOTE_DELAY1);
      tone(spkr, NOTE_4D, NOTE_DURATION);
      delay(NOTE_DELAY1);
      tone(spkr, NOTE_3G, NOTE_DURATION);
      delay(NOTE_DELAY1);
      tone(spkr, NOTE_2B, NOTE_DURATION);
      delay(NOTE_DELAY1);
      tone(spkr, NOTE_1E, NOTE_DURATION);
      delay(NOTE_DELAY1);
    }

    if(noteSelect > 0){ // Tones to play as the notes are cycled through
      tone(spkr, NOTE_1E, NOTE_DURATION);
      delay(NOTE_DELAY1);
    }
    if(noteSelect > 1){
      tone(spkr, NOTE_2B, NOTE_DURATION);
      delay(NOTE_DELAY1);
    }
    if(noteSelect > 2){
      tone(spkr, NOTE_3G, NOTE_DURATION);
      delay(NOTE_DELAY1);
    }
    if(noteSelect > 3){
      tone(spkr, NOTE_4D, NOTE_DURATION);
      delay(NOTE_DELAY1);
    }
    if(noteSelect > 4){
      tone(spkr, NOTE_5A, NOTE_DURATION);
      delay(NOTE_DELAY1);
    }
    if(noteSelect > 5){
      tone(spkr, NOTE_6E, NOTE_DURATION);
      delay(NOTE_DELAY1);
    }
  }
}





void OffsetsV(){ // Reads the tune LEDs and puts the reading in the variable offset
  offset = 0;
  if(digitalRead(p40) == 0){
    Serial.println("p40");
    offset = 40;
  }
  if(digitalRead(p30) == 0){
    Serial.println("p30");
    offset = 30;
  }
  if(digitalRead(p20) == 0){
    Serial.println("p20");
    offset = 20;
  }
  if(digitalRead(p10) == 0){
    Serial.println("p10");
    offset = 10;
  }
  if(digitalRead(tune) == 0){
    Serial.println("tune");
    offset = 1;
  }
  if(digitalRead(n40) == 0){
    Serial.println("n40");
    offset = -40;
  }
  if(digitalRead(n30) == 0){
    Serial.println("n30");
    offset = -30;
  }
  if(digitalRead(n20) == 0){
    Serial.println("n20");
    offset = -20;
  }
  if(digitalRead(n10) == 0){
    Serial.println("n10");
    offset = -10;
  }
}





void NotesV(){ //Reads the note LEDs and stores the results in the note variable
  note = 0;
  if(digitalRead(p6E) == 0){
    Serial.println("p6E");
    note = 6;
  }
  if(digitalRead(p5A) == 0){
    Serial.println("p5A");
    note = 5;
  }
  if(digitalRead(p4D) == 0){
    Serial.println("p4D");
    note = 4;
  }
  if(digitalRead(p3G) == 0){
    Serial.println("p3G");
    note = 3;
  }
  if(digitalRead(p2B) == 0){
    Serial.println("p2B");
    note = 2;
  }
  if(digitalRead(p1E) == 0){
    Serial.println("p1E");
    note = 1;
  }
}







Step 7: Tidy Up

To protect the external components I covered them in Sugru; it's an awesome self-setting rubber that starts off a lot like plasticine.

It didn't work out quite as neatly as I had hoped, but is certainly functional and tough. If I did the project again I would probably try to get a new back case 3D-printed, or I would use different (more interesting) colours of Sugru.

Step 8: Lessons Learnt and Notes

Here are a few lessons I learnt along the way:

The giant capacitor

I had to upgrade the capacitor as I was getting feedback issues; The Arduino would output a tone and the noise it would put on the power supply would be picked up by the tuner, causing it to give false readings.

Analogue inputs

My original plan for this build was to put resistors between all the LEDs, thereby building a basic digital-to-analogue converter. I could have then used an ATtiny (basically, a mini Arduino) to read the analogue voltages.

This would have been a more efficient and cheaper system. The problem was, however, that even after a lot of modifications and very careful soldering of surface-mount resistors, I could not get this method to work reliably.

Other things I might change:

·         redesign the back case (possibly 3D-print it)

·         use a bigger button on the back
 

A very similar project has been pointed out to me:
http://lushprojects.com/guitartuner/