Mục lục:

Bộ dò nốt nhạc Arduino: 3 bước
Bộ dò nốt nhạc Arduino: 3 bước

Video: Bộ dò nốt nhạc Arduino: 3 bước

Video: Bộ dò nốt nhạc Arduino: 3 bước
Video: Học lập trình Arduino KHÔNG HỀ KHÓ - Bộ KIT học tập Arduino Uno R3 BLK 2024, Tháng mười một
Anonim
Image
Image

Việc phát hiện các nốt nhạc từ tín hiệu âm thanh rất khó thực hiện, đặc biệt là trên Arduino do bộ nhớ và sức mạnh xử lý có hạn. Nói chung, nốt nhạc không phải là một sóng hình sin thuần túy khiến việc phát hiện khó khăn. Nếu chúng ta lấy sự biến đổi tần số của các nhạc cụ khác nhau, nó có thể chứa nhiều hài âm dựa trên nốt nhạc đang được chơi. Mỗi nhạc cụ đều có sự kết hợp đặc trưng của các sóng hài khác nhau. Trong đoạn mã này, tôi đã cố gắng tạo ra một chương trình có thể bao gồm nhiều nhạc cụ nhất có thể. Bạn có thể tham khảo video đính kèm trong đó tôi đã thử kiểm tra nhiều loại nhạc cụ khác nhau, nhiều loại âm do bàn phím tạo ra và thậm chí cả âm thanh của giọng hát cũng được kiểm tra. Độ chính xác của phát hiện thay đổi tùy theo thiết bị. Đối với một số nhạc cụ (tức là piano) trong một phạm vi giới hạn (200-500Hz), nó chính xác, trong khi một số nhạc cụ có độ chính xác thấp (tức là Harmonica).

Mã này sử dụng mã FFT được phát triển trước đó có tên là EasyFFT.

Việc trình diễn mã được hiển thị trong video trên với nhiều loại âm thanh nhạc cụ cũng như giọng hát.

Quân nhu

- Arduino Nano / Uno trở lên

- Mô-đun micrô cho Arduino

Bước 1: Thuật toán phát hiện ghi chú

Như đã đề cập ở bước trước, việc phát hiện rất khó khăn do sự hiện diện của nhiều tần số trong các mẫu âm thanh.

Chương trình hoạt động theo quy trình sau:

1. Thu thập dữ liệu:

- phần này lấy 128 mẫu từ dữ liệu âm thanh, sự tách biệt giữa hai mẫu (tần số lấy mẫu) tùy thuộc vào tần số quan tâm. Trong trường hợp này, chúng tôi đang sử dụng khoảng cách giữa hai mẫu được sử dụng để áp dụng chức năng cửa sổ Hann cũng như tính toán biên độ / RMS. Mã này cũng thực hiện việc làm 0 thô bằng cách trừ đi 500 từ giá trị đọc tương tự. Giá trị này có thể được thay đổi nếu được yêu cầu. Đối với một trường hợp điển hình, các giá trị này hoạt động tốt. Hơn nữa, một số độ trễ cần được thêm vào để có tần số lấy mẫu khoảng 1200Hz. trong trường hợp tần số lấy mẫu 1200Hz, tần số lấy mẫu tối đa là 600 HZ có thể được phát hiện.

for (int i = 0; i <128; i ++) {a = analogRead (Mic_pin) -500; // dịch chuyển số không thô sum1 = sum1 + a; // đến giá trị trung bình sum2 = sum2 + a * a; // đến giá trị RMS a = a * (sin (i * 3,14 / 128) * sin (i * 3,14 / 128)); // Cửa sổ Hann trong = 4 * a; // chia tỷ lệ cho chuyển đổi float thành int delayMicroseconds (195); // dựa trên dải tần hoạt động}

2. FFT:

Khi dữ liệu đã sẵn sàng, FFT được thực hiện bằng EasyFFT. Chức năng EasyFFT này được sửa đổi để sửa FFT cho 128 mẫu. Mã cũng được sửa đổi để giảm tiêu thụ bộ nhớ. Chức năng EasyFFT ban đầu được thiết kế để có tới 1028 mẫu (với bo mạch tương thích), trong khi chúng tôi chỉ cần 128 mẫu. mã này giảm mức tiêu thụ bộ nhớ khoảng 20% so với chức năng EasyFFT ban đầu.

Sau khi FFT được thực hiện, mã sẽ trả về 5 đỉnh tần số phổ biến nhất để phân tích thêm. Tần số này được sắp xếp theo thứ tự biên độ giảm dần.

3. Đối với mỗi đỉnh, mã phát hiện các ghi chú có thể liên kết với nó. mã này chỉ quét tối đa 1200 Hz. Không nhất thiết phải có nốt giống như tần số với biên độ tối đa.

Tất cả các tần số được ánh xạ từ 0 đến 255, ở đây quãng tám đầu tiên được phát hiện, ví dụ: 65,4 Hz đến 130,8 đại diện cho một quãng tám, 130,8 Hz đến 261,6 Hz đại diện cho một quãng tám khác. Đối với mỗi quãng tám, các tần số được ánh xạ từ 0 đến 255. ở đây ánh xạ bắt đầu từ C đến C '.

if (f_peaks > 1040) {f_peaks = 0;} if (f_peaks > = 65,4 && f_peaks = 130,8 && f_peaks = 261,6 && f_peaks = 523,25 && f_peaks = 1046 && f_peaks <= 2093) {f_peaks = 255 * ((f_peaks / 1046) -1);}

Các giá trị mảng NoteV được sử dụng để gán nốt cho các tần số được phát hiện.

byte NoteV [13] = {8, 23, 40, 57, 76, 96, 116, 138, 162, 187, 213, 241, 255};

4. Sau khi tính toán nốt cho mọi tần số, có thể xảy ra trường hợp có nhiều tần số tồn tại gợi ý cùng một nốt. Để có một mã đầu ra chính xác cũng cần xem xét các lần lặp lại. Mã cộng tất cả các giá trị tần số dựa trên thứ tự biên độ và số lần lặp lại và tạo đỉnh nốt với biên độ tối đa.

Bước 2: Ứng dụng

Tuy nhiên, việc sử dụng mã là điều dễ hiểu, tuy nhiên, cũng có nhiều hạn chế cần được lưu ý khi sử dụng. Mã có thể được sao chép vì nó được sử dụng để phát hiện ghi chú. Những điểm dưới đây cần được xem xét khi sử dụng nó.

1. Phân công ghim:

Dựa trên việc chỉ định Pin đính kèm cần được sửa đổi. Đối với thử nghiệm của tôi, tôi giữ nó ở chân Analog 7, void setup () {Serial.begin (250000); Mic_pin = A7; }

2. Độ nhạy của micrô:

Độ nhạy của micrô cần được sửa đổi để dạng sóng có thể được tạo ra với biên độ tốt. Hầu hết, mô-đun Micrô đi kèm với cài đặt độ nhạy. độ nhạy thích hợp được chọn sao cho tín hiệu không quá nhỏ và cũng không bị ngắt do biên độ cao hơn.

3. Ngưỡng biên độ:

Mã này chỉ kích hoạt nếu biên độ tín hiệu đủ cao. cài đặt này cần được người dùng đặt theo cách thủ công. giá trị này phụ thuộc vào độ nhạy của micrô cũng như ứng dụng.

if (sum2-sum1> 5) {

..

trong đoạn mã trên, sum2 cho giá trị RMS trong khi tổng 1 cho giá trị trung bình. vì vậy sự khác biệt giữa hai giá trị này cho biết biên độ của tín hiệu âm thanh. trong trường hợp của tôi, nó hoạt động bình thường với giá trị biên độ khoảng 5.

4. Theo mặc định, mã này sẽ in ghi chú được phát hiện. tuy nhiên, nếu bạn định sử dụng ghi chú cho một số mục đích khác, thì nên sử dụng số được chỉ định trực tiếp. ví dụ C = 0; C # = 1, D = 2, D # = 3 và trở đi.

5. Nếu thiết bị có tần số cao hơn, mã có thể cho đầu ra sai. tần số tối đa bị giới hạn bởi tần số lấy mẫu. vì vậy bạn có thể chơi xung quanh các giá trị độ trễ thấp hơn để có được sản lượng tối ưu. trong độ trễ mã dưới đây là 195 micro giây. có thể được điều chỉnh để có được đầu ra tối ưu. Điều này sẽ ảnh hưởng đến thời gian thực hiện chung.

{a = analogRead (Mic_pin) -500; // chuyển số 0 thô

sum1 = sum1 + a; // đến giá trị trung bình sum2 = sum2 + a * a; // đến giá trị RMS a = a * (sin (i * 3,14 / 128) * sin (i * 3,14 / 128)); // Cửa sổ Hann trong = 4 * a; // chia tỷ lệ cho chuyển đổi float thành int delayMicroseconds (195); // dựa trên dải tần hoạt động}

6. mã này sẽ chỉ hoạt động cho đến tần số 2000Hz. bằng cách loại bỏ độ trễ giữa các tần số lấy mẫu khoảng 3-4 kHz có thể thu được.

Các biện pháp phòng ngừa:

  • Như đã đề cập trong hướng dẫn EasyFFT, FFT ngốn một lượng lớn bộ nhớ của Arduino. Vì vậy, nếu bạn có một chương trình cần lưu trữ một số giá trị, bạn nên sử dụng bảng có bộ nhớ cao hơn.
  • Mã này có thể hoạt động tốt cho một nhạc cụ / ca sĩ và không tốt cho một nhạc cụ / ca sĩ khác. Thời gian thực Không thể phát hiện chính xác do các hạn chế về tính toán.

Bước 3: Truy vấn

Việc phát hiện ghi chú là công việc đòi hỏi nhiều tính toán, việc nhận đầu ra theo thời gian thực là rất khó, đặc biệt là trên Arduino. Mã này có thể cung cấp khoảng 6,6 mẫu / giây (thêm vào độ trễ 195 micro giây). mã này hoạt động tốt với piano và một số nhạc cụ khác.

Tôi hy vọng mã và hướng dẫn này sẽ hữu ích trong dự án của bạn liên quan đến âm nhạc. trong trường hợp có bất kỳ nghi ngờ hoặc đề xuất, vui lòng bình luận hoặc nhắn tin.

Trong hướng dẫn sắp tới, tôi sẽ sửa đổi mã này để phát hiện hợp âm trong âm nhạc. Vậy nên hãy chờ trong giây lát.

Đề xuất: