Bài viết
Máy chỉnh dây đàn guitar tự chế bằng Arduino
🎸
Máy chỉnh dây đàn guitar bán sẵn giá không đắt, nhưng tự làm một chiếc bằng Arduino là bài tập tuyệt vời để hiểu cách vi điều khiển “nghe” và phân tích âm thanh — biến sóng âm analog thành một con số tần số cụ thể rồi so sánh với nốt chuẩn. Nguyên lý ở đây (lấy mẫu âm thanh, phát hiện cao độ) cũng chính là nền tảng của nhận diện giọng nói, phân tích rung động máy móc và nhiều ứng dụng xử lý tín hiệu khác.
Nguyên lý hoạt động
- Micro electret thu âm thanh dây đàn đang rung, khuếch đại lên bằng một tầng op-amp đơn giản trước khi đưa vào chân ADC của Arduino.
- Arduino lấy mẫu tín hiệu âm thanh ở tần số đủ cao (khoảng 5-9kHz, đủ để bắt các nốt guitar tiêu chuẩn từ E2 ~82Hz đến E4 ~330Hz theo định lý lấy mẫu Nyquist).
- Thay vì dùng FFT tốn nhiều bộ nhớ, thuật toán tự tương quan (autocorrelation) đơn giản hơn được dùng để tìm chu kỳ lặp lại trong tín hiệu — từ chu kỳ đó suy ra tần số cơ bản của nốt nhạc.
- Tần số đo được so sánh với 6 tần số chuẩn của dây guitar tiêu chuẩn (E2, A2, D3, G3, B3, E4); độ lệch (tính bằng cent — đơn vị âm nhạc) được hiển thị qua dải đèn LED hoặc màn hình LCD để người chơi biết cần lên hay xuống dây.
Linh kiện
- Arduino Uno hoặc Nano
- Micro electret (loại 2 chân hoặc 3 chân, kèm mạch khuếch đại đơn giản dùng op-amp LM386 hoặc module micro có sẵn khuếch đại)
- Dải LED (5-7 đèn) hoặc màn hình LCD 16x2 để hiển thị mức lệch cao/thấp
- Điện trở và tụ điện cho tầng lọc/phân cực micro (theo datasheet module micro sử dụng)
- Vỏ hộp nhỏ để đóng gói gọn gàng, tiện mang theo khi chơi đàn
Code mẫu
const int MIC_PIN = A0;
const int SAMPLE_SIZE = 256;
const float SAMPLE_RATE_HZ = 9000.0;
int samples[SAMPLE_SIZE];
// Tan so chuan 6 day guitar (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; // tru offset DC
delayMicroseconds(intervalMicros);
}
// Tu tuong quan: tim do tre (lag) co tong tich luy lon nhat
int bestLag = -1;
long bestCorr = 0;
for (int lag = 20; lag < 200; lag++) { // tuong ung dai tan ~45-450Hz o 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; // ngoai dai guitar, bo qua nhieu
// Tim day guitar gan nhat
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(" - Tan so: ");
Serial.print(freq);
Serial.print("Hz - Lech: ");
Serial.print(cents);
Serial.println(" cent");
// cents > 0: dang cao hon chuan (can chinh xuong), cents < 0: dang thap hon (can chinh len)
}
Những lỗi thường gặp
- Không trừ offset DC trước khi tự tương quan khiến thuật toán luôn tìm ra độ trễ sai — micro electret thường có điện áp phân cực (bias) khoảng giữa dải ADC, cần trừ đi trước khi xử lý.
- Lấy mẫu quá thưa làm mất khả năng phân biệt các dây trầm (E2 ~82Hz) — tần số lấy mẫu cần ít nhất gấp đôi tần số cao nhất muốn bắt, nhưng thực tế nên cao hơn nhiều lần để độ chính xác tốt.
- Nhiễu từ tiếng ồn xung quanh khiến kết quả nhảy loạn — dùng vỏ bọc micro hướng thẳng vào lỗ thoát âm của đàn, hoặc chỉ chấp nhận kết quả khi biên độ tín hiệu đủ lớn.
delayMicrosecondskhông chính xác tuyệt đối trên vòng lặp dài làm lệch tần số lấy mẫu thực tế — với ứng dụng cần độ chính xác cao hơn, nên dùng ngắt Timer thay vì delay trong vòng lặp.
Mở rộng
Thêm màn hình OLED hiển thị kim đồng hồ ảo giống tuner chuyên nghiệp, hỗ trợ nhiều kiểu tuning khác (Drop D, DADGAD), hoặc tham khảo cách xử lý và hiển thị tín hiệu analog theo thời gian thực trong bài máy hiện sóng mini bằng Arduino để debug trực quan dạng sóng âm thanh thu được.
Thẻ:#arduino#audio#music
Bình luận