Introduction: Guitar Tuner for the Blind (using an Arduino)
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:
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
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
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
// 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
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
http://lushprojects.com/guitartuner/