Isi kandungan:

Pengesan Nota Muzik: 3 Langkah
Pengesan Nota Muzik: 3 Langkah

Video: Pengesan Nota Muzik: 3 Langkah

Video: Pengesan Nota Muzik: 3 Langkah
Video: MEMBINA ATURCARA DALAM APLIKASI MBLOCK DENGAN ARDUINO UNO SHIELD 9 IN 1 ASCO EDUTECH 2024, November
Anonim
Image
Image

Kagumi rakan dan keluarga anda dengan projek ini yang mengesan nota yang dimainkan oleh instrumen. Projek ini akan memperlihatkan frekuensi perkiraan serta nota muzik yang dimainkan pada papan kekunci elektronik, aplikasi piano atau instrumen lain.

Perincian

Untuk projek ini, output analog dari pengesan modul bunyi dihantar ke input analog A0 dari Arduino Uno. Isyarat analog diambil dan dihitung (didigitalkan). Kod autokorelasi, pemberat dan penalaan digunakan untuk mencari frekuensi asas menggunakan 3 tempoh pertama. Kekerapan mendasar mendekati kemudian dibandingkan dengan frekuensi dalam jarak oktaf 3, 4, dan 5 untuk menentukan frekuensi nota muzik terdekat. Akhirnya nota yang ditebak untuk frekuensi terdekat dicetak ke skrin.

Catatan: Instruksional ini hanya tertumpu pada bagaimana membina projek. Untuk maklumat lebih lanjut mengenai perincian dan justifikasi reka bentuk, sila lawati pautan ini: Maklumat Lanjut

Bekalan

  • (1) Arduino Uno (atau Genuino Uno)
  • (1) Modul Pengesanan Suara Sensitiviti Tinggi Sensor Tinggi Mikrofon DEVMO Sesuai
  • (1) Papan Roti Solderless
  • (1) Kabel USB-A hingga B
  • Wayar pelompat
  • Sumber muzik (piano, papan kekunci atau aplikasi paino dengan pembesar suara)
  • (1) Komputer atau komputer riba

Langkah 1: Bina Perkakasan untuk Pengesan Nota Muzik

Sediakan Pengesan Nota Muzik
Sediakan Pengesan Nota Muzik

Dengan menggunakan Arduino Uno, wayar sambungan, papan roti tanpa solder dan Modul Pengesanan Suara Sensitiviti Tinggi Sensor Tinggi Mikrofon DEVMO (atau yang serupa) membina litar yang ditunjukkan dalam gambar ini

Langkah 2: Programkan Pengesan Nota Muzik

Dalam Arduino IDE, tambahkan kod berikut.

gistfile1.txt

/*
Nama Fail / Lakaran: MusicalNoteDetector
Versi No.: v1.0 Dibuat 7 Jun, 2020
Pengarang Asal: Clyde A. Lettsome, PhD, PE, MEM
Penerangan: Kod / lakaran ini memaparkan frekuensi anggaran dan nota muzik yang dimainkan pada papan kekunci elektronik atau aplikasi piano. Untuk projek ini, output analog dari
pengesan modul bunyi dihantar ke input analog A0 dari Arduino Uno. Isyarat analog diambil sampel dan dihitung (didigitalkan). Kod autokorelasi, pemberat dan penalaan terbiasa
cari frekuensi asas menggunakan 3 tempoh pertama. Kekerapan mendasar mendekati kemudian dibandingkan dengan frekuensi dalam jarak oktaf 3, 4, dan 5 untuk menentukan muzik terdekat
kekerapan nota. Akhirnya nota yang ditebak untuk frekuensi terdekat dicetak ke skrin.
Lesen: Program ini adalah perisian percuma; anda boleh mengagihkannya dan / atau mengubahnya mengikut syarat-syarat Lesen Awam Umum GNU (GPL) versi 3, atau kemudian
versi pilihan anda, seperti yang diterbitkan oleh Yayasan Perisian Percuma.
Catatan: Hak Cipta (c) 2020 oleh C. A. Lettsome Services, LLC
Untuk maklumat lebih lanjut layari
*/
#tentukan CONTOH 128 // Maksimum 128 untuk Arduino Uno.
#definisi SAMPLING_FREQUENCY 2048 // Fs = Berdasarkan Nyquist, mestilah 2 kali ganda frekuensi yang dijangkakan tertinggi.
#definisi OFFSETSAMPLES 40 // digunakan untuk tujuan penentukuran
#define TUNER -3 // Laraskan sehingga C3 130.50
persampelan apunganPeriod;
mikroSeconds panjang yang tidak ditandatangani;
int X [CONTOH]; // buat vektor ukuran CONTOH untuk menyimpan nilai sebenar
float autoCorr [CONTOH]; // buat vektor ukuran CONTOH untuk menyimpan nilai khayalan
apungan disimpanNoteFreq [12] = {130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185, 196, 207.65, 220, 233.08, 246.94};
int sumOffSet = 0;
int offSet [OFFSETSAMPLES]; // buat vektor mengimbangi
int avgOffSet; // buat vektor mengimbangi
int i, k, periodEnd, periodBegin, period, adjuster, noteLocation, octaveRange;
float maxValue, minValue;
jumlah yang panjang;
int ambang = 0;
int numOfCycles = 0;
isyarat apunganFrequency, signalFrequency2, signalFrequency3, signalFrequencyGuess, total;
byte state_machine = 0;
int samplesPerPeriod = 0;
persediaan tidak sah ()
{
Serial.begin (115200); // 115200 Baud rate untuk Serial Monitor
}
gelung kosong ()
{
//*****************************************************************
// Bahagian Kalibrasi
//*****************************************************************
Serial.println ("Calabrating. Jangan memainkan nota semasa calabration.");
untuk (i = 0; i <OFFSETSAMPLES; i ++)
{
offSet = analogRead (0); // Membaca nilai dari pin analog 0 (A0), menghitungnya dan menyimpannya sebagai istilah sebenar.
//Serial.println(offSet); // gunakan ini untuk menyesuaikan modul pengesanan suara menjadi kira-kira separuh atau 512 ketika tidak ada suara yang dimainkan.
sumOffSet = sumOffSet + offSet ;
}
sampelPerPeriod = 0;
nilai maksimum = 0;
//*****************************************************************
// Bersedia untuk menerima input dari A0
//*****************************************************************
avgOffSet = bulat (sumOffSet / OFFSETSAMPLES);
Serial.println ("Mengira.");
kelewatan (1000); // berhenti sebentar selama 1 saat
Serial.println ("3");
kelewatan (1000); // berhenti sebentar selama 1 saat
Serial.println ("2");
kelewatan (1000); // berhenti sebentar untuk 1
Serial.println ("1");
kelewatan (1000); // berhenti sebentar selama 1 saat
Serial.println ("Mainkan nota anda!");
kelewatan (250); // berhenti sebentar selama 1/4 saat untuk masa reaksi
//*****************************************************************
// Kumpulkan sampel SAMBUNGAN dari A0 dengan jangka masa pengambilan sampelPeriod
//*****************************************************************
samplingPeriod = 1.0 / SAMPLING_FREQUENCY; // Tempoh dalam mikrodetik
untuk (i = 0; i <CONTOH; i ++)
{
mikroSeconds = mikro (); // Mengembalikan bilangan mikrodetik sejak papan Arduino mula menjalankan skrip semasa.
X = analogRead (0); // Membaca nilai dari pin analog 0 (A0), menghitungnya dan menyimpannya sebagai istilah sebenar.
/ * baki masa menunggu antara sampel jika perlu dalam beberapa saat * /
sementara (mikro () <(microSeconds + (samplingPeriod * 1000000)))
{
// jangan buat apa-apa tunggu sahaja
}
}
//*****************************************************************
// Fungsi Autokorelasi
//*****************************************************************
untuk (i = 0; i <CONTOH; i ++) // i = kelewatan
{
jumlah = 0;
untuk (k = 0; k <CONTOH - i; k ++) // Padankan isyarat dengan isyarat tertunda
{
jumlah = jumlah + (((X [k]) - avgOffSet) * ((X [k + i]) - avgOffSet)); // X [k] adalah isyarat dan X [k + i] adalah versi tertunda
}
autoCorr = jumlah / CONTOH;
// Mesin Pengesan Puncak Puncak Pertama
jika (state_machine == 0 && i == 0)
{
ambang = autoCorr * 0.5;
state_machine = 1;
}
lain jika (state_machine == 1 && i> 0 && ambang 0) // state_machine = 1, cari 1 tempoh untuk menggunakan kitaran pertama
{
maxValue = autoCorr ;
}
lain jika (state_machine == 1 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0)
{
periodBegin = i-1;
state_machine = 2;
numOfCycles = 1;
sampelPerPeriod = (periodBegin - 0);
tempoh = sampelPerPeriod;
pelaras = TUNER + (50.04 * exp (-0.102 * samplesPerPeriod));
signalFrequency = ((SAMPLING_FREQUENCY) / (samplesPerPeriod)) - pelaras; // f = fs / N
}
jika tidak (state_machine == 2 && i> 0 && thresh 0) // state_machine = 2, cari 2 tempoh untuk kitar 1 dan 2
{
maxValue = autoCorr ;
}
lain jika (state_machine == 2 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0)
{
periodEnd = i-1;
state_machine = 3;
numOfCycles = 2;
sampelPerPeriod = (periodEnd - 0);
signalFrequency2 = ((numOfCycles * SAMPLING_FREQUENCY) / (samplesPerPeriod)) - pelaras; // f = (2 * fs) / (2 * N)
nilai maksimum = 0;
}
jika tidak (state_machine == 3 &&> 0 && thresh 0) // state_machine = 3, cari 3 tempoh untuk kitaran 1, 2 dan 3
{
maxValue = autoCorr ;
}
lain jika (state_machine == 3 &&> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0)
{
periodEnd = i-1;
state_machine = 4;
numOfCycles = 3;
sampelPerPeriod = (periodEnd - 0);
signalFrequency3 = ((numOfCycles * SAMPLING_FREQUENCY) / (samplesPerPeriod)) - pelaras; // f = (3 * fs) / (3 * N)
}
}
//*****************************************************************
// Analisis Hasil
//*****************************************************************
jika (samplesPerPeriod == 0)
{
Serial.println ("Hmm….. Saya tidak pasti. Adakah anda cuba menipu saya?");
}
yang lain
{
// sediakan fungsi pemberat
jumlah = 0;
jika (signalFrequency! = 0)
{
jumlah = 1;
}
jika (signalFrequency2! = 0)
{
jumlah = jumlah + 2;
}
jika (signalFrequency3! = 0)
{
jumlah = jumlah + 3;
}
// hitung frekuensi menggunakan fungsi pemberat
signalFrequencyGuess = ((1 / total) * signalFrequency) + ((2 / total) * signalFrequency2) + ((3 / total) * signalFrequency3); // cari frekuensi berwajaran
Serial.print ("Nota yang anda mainkan kira-kira");
Serial.print (signalFrequencyGuess); // Cetak tekaan frekuensi.
Serial.println ("Hz.");
// cari julat oktaf berdasarkan tekaan
octaveRange = 3;
sementara (! (signalFrequencyGuess> = disimpanNoteFreq [0] -7 && signalFrequencyGuess <= disimpanNoteFreq [11] +7))
{
untuk (i = 0; i <12; i ++)
{
disimpanNoteFreq = 2 * disimpanNoteFreq ;
}
octaveRange ++;
}
// Cari nota terdekat
nilai min = 10000000;
noteLocation = 0;
untuk (i = 0; i <12; i ++)
{
jika (minValue> abs (signalFrequencyGuess-storeNoteFreq ))
{
minValue = abs (signalFrequencyGuess-disimpanNoteFreq );
noteLocation = i;
}
}
// Cetak nota
Serial.print ("Saya rasa anda bermain");
jika (noteLocation == 0)
{
Cetakan bersiri ("C");
}
lain jika (noteLocation == 1)
{
Cetakan bersiri ("C #");
}
lain jika (noteLocation == 2)
{
Cetakan bersiri ("D");
}
lain jika (noteLocation == 3)
{
Cetakan bersiri ("D #");
}
lain jika (noteLocation == 4)
{
Cetakan bersiri ("E");
}
lain jika (noteLocation == 5)
{
Cetakan bersiri ("F");
}
lain jika (noteLocation == 6)
{
Serial.print ("F #");
}
lain jika (noteLocation == 7)
{
Cetakan bersiri ("G");
}
lain jika (noteLocation == 8)
{
Cetakan bersiri ("G #");
}
lain jika (noteLocation == 9)
{
Cetakan bersiri ("A");
}
lain jika (noteLocation == 10)
{
Cetakan bersiri ("A #");
}
lain jika (noteLocation == 11)
{
Cetakan bersiri ("B");
}
Serial.println (octaveRange);
}
//*****************************************************************
//Berhenti di sini. Tekan butang reset pada Arduino untuk memulakan semula
//*****************************************************************
sementara (1);
}

lihat rawgistfile1.txt dihoskan dengan ❤ oleh GitHub

Langkah 3: Siapkan Pengesan Nota Muzik

Sambungkan Arduino Uno ke PC dengan kod yang ditulis atau dimuatkan di Arduino IDE. Susun dan muat naik kod ke Arduino. Letakkan litar dekat dengan sumber muzik. Catatan: Dalam video pengenalan, saya menggunakan aplikasi yang dipasang pada tablet bersama dengan pembesar suara PC sebagai sumber muzik saya. Tekan butang reset pada Arduino Board dan kemudian mainkan nota pada sumber muzik. Selepas beberapa saat, Musical Note Detector akan memaparkan nota yang dimainkan dan kekerapannya.

Disyorkan: