Cuprins:

Detector de note muzicale Arduino: 3 pași
Detector de note muzicale Arduino: 3 pași

Video: Detector de note muzicale Arduino: 3 pași

Video: Detector de note muzicale Arduino: 3 pași
Video: Instalare Arduino IDE | Sectiunea 3. Lectia 10 2024, Noiembrie
Anonim
Image
Image

Detectarea notelor muzicale din semnalul audio este dificil de realizat în special pe Arduino datorită memoriei limitate și a puterii de procesare. În general, nota nu este o undă sinusoidală pură care face dificilă detectarea. Dacă luăm transformarea de frecvență a diferitelor instrumente muzicale, aceasta poate conține mai multe armonici pe baza notei redate. Fiecare instrument are propria sa combinație de semnături din diferite armonici. În acest cod, am încercat să realizez un program care să acopere cât mai multe instrumente posibil. Puteți consulta videoclipul atașat în care am încercat să testez diferitele tipuri de instrumente, diferite tipuri de tonuri generate de tastatură și chiar sunetul vocii sunt verificate. Precizia detecției variază de la instrument la instrument. Pentru un anumit instrument (de exemplu, pian) într-o gamă limitată (200-500Hz) este precis, în timp ce pentru unele instrumente are o precizie redusă (de exemplu, Harmonica).

Acest cod folosește un cod FFT dezvoltat anterior numit EasyFFT.

Demonstrația codului este prezentată în videoclipul de mai sus, cu diferite tipuri de sunet de instrument, precum și vocal.

Provizii

- Arduino Nano / Uno sau mai mare

- Modul de microfon pentru Arduino

Pasul 1: Algoritm pentru detectarea notelor

După cum sa menționat în pasul anterior, detectarea este dificilă din cauza prezenței mai multor frecvențe în probele audio.

Programul funcționează în următorul flux:

1. Achiziționarea datelor:

- această secțiune preia 128 de eșantioane din date audio, separarea dintre două eșantioane (frecvența de eșantionare) în funcție de frecvența de interes. În acest caz, folosim spațiere între două eșantioane pentru a aplica funcția ferestrei Hann, precum și calculul amplitudinii / RMS. Acest cod face, de asemenea, reducerea la zero, scăzând 500 din valoarea de citire analogică. Această valoare poate fi modificată dacă este necesar. Pentru un caz tipic, aceste valori funcționează bine. Mai mult, trebuie adăugată o anumită întârziere pentru a avea o frecvență de eșantionare de aproximativ 1200Hz. în cazul frecvenței de eșantionare de 1200Hz se poate detecta frecvența maximă de 600 HZ.

for (int i = 0; i <128; i ++) {a = analogRead (Mic_pin) -500; // zero zero shift sum1 = sum1 + a; // la valoarea medie sum2 = sum2 + a * a; // la valoarea RMS a = a * (sin (i * 3.14 / 128) * sin (i * 3.14 / 128)); // fereastra Hann din = 4 * a; // scalare pentru float to int întârziere conversie Microsecunde (195); // pe baza frecvenței de funcționare}

2. FFT:

Odată ce datele sunt gata, FFT se efectuează folosind EasyFFT. Această funcție EasyFFT este modificată pentru a repara FFT pentru 128 de probe. Codul este, de asemenea, modificat pentru a reduce consumul de memorie. Funcția originală EasyFFT concepută pentru a avea până la 1028 probe (cu placa compatibilă), în timp ce avem nevoie doar de 128 de probe. acest cod reduce consumul de memorie de aproximativ 20% comparativ cu funcția originală EasyFFT.

Odată ce FFT este realizat, codul returnează primele 5 vârfuri de frecvență cele mai dominante pentru o analiză ulterioară. Această frecvență este aranjată în ordinea descrescătoare a amplitudinii.

3. Pentru fiecare vârf, codul detectează posibile note asociate cu acesta. acest cod scanează numai până la 1200 Hz. Nu este necesar să aveți nota la fel ca frecvența cu amplitudine maximă.

Toate frecvențele sunt mapate între 0 și 255, aici este detectată prima octavă, de exemplu, 65,4 Hz la 130,8 reprezintă o octavă, 130,8 Hz la 261,6 Hz reprezintă alta. Pentru fiecare octavă, frecvențele sunt mapate de la 0 la 255. aici mapare începând de la C la 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);}

Valorile matricei NoteV sunt utilizate pentru a atribui nota frecvențelor detectate.

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

4. După calcularea notei pentru fiecare frecvență, este posibil să existe mai multe frecvențe care sugerează aceeași notă. Pentru a avea un cod de ieșire precis, se iau în considerare și repetări. Codul adună toate valorile de frecvență pe baza ordinii amplitudinii și a repetițiilor și atinge nota cu amplitudinea maximă.

Pasul 2: aplicație

Utilizarea codului este simplă, cu toate acestea, există, de asemenea, multiple limitări care trebuie ținute cont în timp ce acesta. Codul poate fi copiat deoarece este utilizat pentru detectarea notelor. Punctele de mai jos trebuie luate în considerare în timpul utilizării acestuia.

1. Alocarea pinului:

Pe baza atribuirii Pin atașate trebuie modificată. Pentru experimentul meu, l-am păstrat la pinul analogic 7, void setup () {Serial.begin (250000); Mic_pin = A7; }

2. Sensibilitatea microfonului:

Sensibilitatea microfonului trebuie modificată, astfel încât forma de undă poate fi generată cu o amplitudine bună. În general, modulul Microfon vine cu o setare de sensibilitate. sensibilitatea adecvată să fie selectată astfel încât semnalul să nu fie nici prea mic și, de asemenea, să nu se decupeze din cauza amplitudinii mai mari.

3. Pragul amplitudinii:

Acest cod se activează numai dacă amplitudinea semnalului este suficient de mare. această setare trebuie setată manual de către utilizator. această valoare depinde de sensibilitatea microfonului, precum și de aplicație.

if (sum2-sum1> 5) {

..

în codul de mai sus, suma2 dă valoare RMS în timp ce suma 1 dă valoare medie. deci diferența dintre aceste două valori dă amplitudinea semnalului sonor. în cazul meu, funcționează corect cu o valoare a amplitudinii de aproximativ 5.

4. În mod implicit, acest cod va imprima nota detectată. cu toate acestea, dacă intenționați să utilizați nota în alte scopuri, ar trebui utilizat numărul atribuit direct. de exemplu C = 0; C # = 1, D = 2, D # = 3 și mai departe.

5. Dacă instrumentul are o frecvență mai mare, codul poate da o ieșire falsă. frecvența maximă este limitată de frecvența de eșantionare. deci puteți juca sub valorile de întârziere pentru a obține o ieșire optimă. în mai jos cod întârziere de 195 microsecunde. care poate fi modificat pentru a obține o ieșire optimă. Acest lucru va afecta timpul total de execuție.

{a = analogRead (Mic_pin) -500; // zero zero shift

sum1 = sum1 + a; // la valoarea medie sum2 = sum2 + a * a; // la valoarea RMS a = a * (sin (i * 3.14 / 128) * sin (i * 3.14 / 128)); // fereastra Hann din = 4 * a; // scalarea pentru float to int întârziere conversie Microsecunde (195); // pe baza frecvenței de funcționare}

6. acest cod va funcționa doar până la frecvența de 2000Hz. prin eliminarea întârzierii dintre eșantionare în jurul a 3-4 kHz de frecvențe de eșantionare se poate obține.

Precauții:

  • După cum sa menționat în tutorialul EasyFFT, FFT consumă o cantitate imensă de memorie de Arduino. Deci, dacă aveți un program care trebuie să stocheze unele valori, este recomandat să utilizați o placă cu memorie mai mare.
  • Acest cod poate funcționa bine pentru un instrument / vocalist și rău pentru altul. Detectarea exactă în timp real nu este posibilă din cauza limitărilor de calcul.

Pasul 3: Vara

Detectarea notelor este o muncă intensă din punct de vedere al calculului, obținerea unei ieșiri în timp real este foarte dificilă mai ales pe Arduino. Acest cod poate da aproximativ 6,6 eșantioane / secundă (pentru 195 de microsecunde de întârziere adăugată). acest cod funcționează bine cu pianul și alte instrumente.

Sper că acest cod și tutorial să vă fie de ajutor în proiectul dvs. legat de muzică. în caz de îndoială sau sugestie, nu ezitați să comentați sau să trimiteți un mesaj.

În următorul tutorial, voi modifica acest cod pentru detectarea acordurilor muzicale. deci stați la curent.

Recomandat: