Article
Build a DIY Guitar Tuner with Arduino
🎸
Store-bought guitar tuners are cheap, but building one with an Arduino is a great exercise in understanding how a microcontroller “listens” and analyzes sound — turning an analog sound wave into a concrete frequency number and comparing it to a reference note. The principle here (sampling audio, detecting pitch) is also the foundation behind voice recognition, machine vibration analysis, and plenty of other signal processing applications.
How it works
- An electret microphone picks up the vibrating string’s sound, amplified through a simple op-amp stage before reaching the Arduino’s ADC pin.
- The Arduino samples the audio signal at a high enough rate (around 5-9kHz, enough to capture standard guitar notes from E2 (~82Hz) to E4 (~330Hz) per the Nyquist sampling theorem).
- Instead of a memory-hungry FFT, a simpler autocorrelation algorithm finds the repeating period in the signal — from that period, the fundamental frequency of the note is derived.
- The measured frequency is compared against the 6 standard guitar string frequencies (E2, A2, D3, G3, B3, E4); the deviation (measured in cents — a musical unit) is shown via an LED strip or LCD so the player knows whether to tune up or down.
Parts list
- Arduino Uno or Nano
- An electret microphone (2-pin or 3-pin, with a simple amplifier stage using an LM386 op-amp, or a pre-amplified mic module)
- An LED strip (5-7 LEDs) or a 16x2 LCD to show the sharp/flat deviation
- Resistors and capacitors for the mic’s filter/bias stage (per the mic module’s datasheet)
- A small enclosure to package it neatly for carrying along while playing
Sample code
const int MIC_PIN = A0;
const int SAMPLE_SIZE = 256;
const float SAMPLE_RATE_HZ = 9000.0;
int samples[SAMPLE_SIZE];
// Standard frequencies of the 6 guitar strings (E2 A2 D3 G3 B3 E4)
const float STRING_FREQS[] = {82.41, 110.00, 146.83, 196.00, 246.94, 329.63};
const char* STRING_NAMES[] = {"E2", "A2", "D3", "G3", "B3", "E4"};
void setup() {
Serial.begin(115200);
}
float detectFrequency() {
unsigned long intervalMicros = 1000000.0 / SAMPLE_RATE_HZ;
for (int i = 0; i < SAMPLE_SIZE; i++) {
samples[i] = analogRead(MIC_PIN) - 512; // remove DC offset
delayMicroseconds(intervalMicros);
}
// Autocorrelation: find the lag with the largest accumulated product
int bestLag = -1;
long bestCorr = 0;
for (int lag = 20; lag < 200; lag++) { // roughly the ~45-450Hz range at 9kHz
long corr = 0;
for (int i = 0; i < SAMPLE_SIZE - lag; i++) {
corr += (long)samples[i] * samples[i + lag];
}
if (corr > bestCorr) {
bestCorr = corr;
bestLag = lag;
}
}
if (bestLag <= 0) return 0;
return SAMPLE_RATE_HZ / bestLag;
}
void loop() {
float freq = detectFrequency();
if (freq < 60 || freq > 400) return; // outside the guitar range, likely noise
// Find the closest guitar string
int closest = 0;
float minDiff = 9999;
for (int i = 0; i < 6; i++) {
float diff = abs(freq - STRING_FREQS[i]);
if (diff < minDiff) {
minDiff = diff;
closest = i;
}
}
float cents = 1200.0 * log(freq / STRING_FREQS[closest]) / log(2.0);
Serial.print(STRING_NAMES[closest]);
Serial.print(" - Frequency: ");
Serial.print(freq);
Serial.print("Hz - Deviation: ");
Serial.print(cents);
Serial.println(" cents");
// cents > 0: sharp (tune down), cents < 0: flat (tune up)
}
Common pitfalls
- Not removing the DC offset before autocorrelating causes the algorithm to consistently find the wrong lag — electret mics usually output a bias voltage around the middle of the ADC range, which needs subtracting before processing.
- Sampling too sparsely loses the ability to distinguish the low strings (E2 ~82Hz) — the sample rate needs to be at least double the highest frequency you want to catch, but in practice much higher for good accuracy.
- Ambient noise makes results jump around erratically — shield the mic and point it directly at the guitar’s sound hole, or only accept a reading when the signal amplitude is large enough.
delayMicrosecondsisn’t perfectly precise across a long loop, skewing the actual sample rate — for applications needing tighter accuracy, use a Timer interrupt instead of a delay inside the loop.
Extensions
Add an OLED display with a virtual needle like a professional tuner, support alternate tunings (Drop D, DADGAD), or check out the DIY mini oscilloscope with Arduino post for real-time analog signal processing and display to visually debug the captured audio waveform.
Tags:#arduino#audio#music
Comments