Mündəricat:
2025 Müəllif: John Day | [email protected]. Son dəyişdirildi: 2025-01-13 06:56
Bir alətin çaldığı notu algılayan bu layihə ilə dostlarınızı və ailənizi heyrətləndirin. Bu layihə, elektron klaviatura, fortepiano tətbiqi və ya hər hansı digər alətdə çalınan musiqili notun təxminən təxmini tezliyini göstərəcək.
Detallar
Bu layihə üçün səs modulu detektorundan analoq çıxış Arduino Uno -nun A0 analoq girişinə göndərilir. Analoq siqnal nümunə götürülür və kvantlaşdırılır (rəqəmləşdirilir). Avtokorrelyasiya, çəki və tənzimləmə kodu ilk 3 dövrdən istifadə edərək əsas tezliyi tapmaq üçün istifadə olunur. Təxmini əsas tezlik daha sonra ən yaxın musiqi notunun tezliyini təyin etmək üçün 3, 4 və 5 oktavalardakı tezliklər ilə müqayisə olunur. Nəhayət, ən yaxın tezlik üçün təxmin edilən qeyd ekranda çap olunur.
Qeyd: Bu təlimat yalnız layihənin necə qurulacağına yönəlmişdir. Detallar və dizayn əsaslandırmaları haqqında daha çox məlumat üçün bu linkə daxil olun: Ətraflı Məlumat
Təchizat
- (1) Arduino Uno (və ya Genuino Uno)
- (1) DEVMO Mikrofon Sensoru Yüksək Həssaslıq Səs Algılama Modulu Uyğundur
- (1) Lehimsiz Çörək Paneli
- (1) USB-A-B Kabeli
- Jumper telləri
- Musiqi mənbəyi (fortepiano, klaviatura və ya dinamikləri olan paino proqramı)
- (1) Kompüter və ya dizüstü kompüter
Addım 1: Musiqili Not Detektoru üçün Avadanlıq qurun
Bir Arduino Uno, əlaqə telləri, lehimsiz çörək taxtası və DEVMO Mikrofon Sensoru Yüksək Həssaslıq Səs Algılama Modulu (və ya bənzəri) istifadə edərək bu şəkildə göstərilən dövrə qurun.
Addım 2: Musiqili Not Detektorunu proqramlaşdırın
Arduino IDE -də aşağıdakı kodu əlavə edin.
gistfile1.txt
/* |
Fayl/Eskiz Adı: MusicalNoteDetector |
Versiya No.: v1.0 7 İyun 2020 tarixində yaradılmışdır |
Orijinal Müəllif: Clyde A. Lettsome, PhD, PE, MEM |
Təsvir: Bu kod/eskiz, elektron klaviatura və ya fortepiano tətbiqində çalınan musiqi notunun təxmini tezliyini göstərir. Bu layihə üçün |
səs modulu detektoru Arduino Uno'nun A0 analog girişinə göndərilir. Analoq siqnal nümunə götürülür və kvantlaşdırılır (rəqəmləşdirilir). Avtokorrelyasiya, çəki və tənzimləmə kodu istifadə olunur |
ilk 3 dövrdən istifadə edərək əsas tezliyi tapın. Təxmini əsas tezlik daha sonra ən yaxın musiqini təyin etmək üçün 3, 4 və 5 oktavalı tezliklər ilə müqayisə olunur. |
tezliyi qeyd edin. Nəhayət, ən yaxın tezlik üçün təxmin edilən qeyd ekranda çap olunur. |
Lisenziya: Bu proqram pulsuz proqramdır; GNU General Public License (GPL) 3 -cü versiya və ya daha sonra onu yenidən paylaya və/və ya dəyişdirə bilərsiniz. |
Pulsuz Proqram Vəqfi tərəfindən nəşr olunduğu kimi, seçdiyiniz versiyadır. |
Qeydlər: Müəlliflik hüququ (c) 2020 tərəfindən C. A. Lettsome Services, LLC |
Ətraflı məlumat üçün https://clydelettsome.com/blog/2020/06/07/my-weekend-project-musical-note-detector-using-an-arduino/ saytına daxil olun. |
*/ |
#define NÜMUNƏLƏR 128 // Arduino Uno üçün Max 128. |
#define SAMPLING_FREQUENCY 2048 // Fs = Nyquist əsasında, gözlənilən ən yüksək tezliyin 2 qatını təşkil etməlidir. |
#define OFFSETSAMPLES 40 // kalabrasiya məqsədləri üçün istifadə olunur |
#define TUNER -3 // C3 130.50 olana qədər tənzimləyin |
float nümunə götürmə müddəti; |
imzasız uzun microSeconds; |
int X [NÜMUNƏLƏR]; // həqiqi dəyərləri saxlamaq üçün NÜMUNƏ ölçüsündə vektor yaradın |
float autoCorr [NÜMUNƏLƏR]; // xəyali dəyərləri saxlamaq üçün SAMPLES ölçülü vektor yaradın |
float storageNoteFreq [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]; // ofset vektoru yaradın |
int avgOffSet; // ofset vektoru yaradın |
int i, k, periodEnd, periodBegin, period, ayarlayıcı, noteLocation, octaveRange; |
float maxValue, minValue; |
uzun məbləğ; |
int thresh = 0; |
int numOfCycles = 0; |
float siqnalıFrequency, signalFrequency2, signalFrequency3, signalFrequencyGuess, total; |
bayt state_machine = 0; |
int nümunələriPerPeriod = 0; |
boş quraşdırma () |
{ |
Serial.begin (115200); // Serial Monitor üçün 115200 Baud dərəcəsi |
} |
boşluq döngəsi () |
{ |
//***************************************************************** |
// Kalabrasiya Bölməsi |
//***************************************************************** |
Serial.println ("Calabrating. Zəhmət olmasa kalabrasiya zamanı heç bir qeyd oynamayın."); |
üçün (i = 0; i <OFFSETSAMPLES; i ++) |
{ |
offSet = analogRead (0); // Dəyəri analoq pin 0 -dan (A0) oxuyur, kəmiyyətləndirir və real termin kimi saxlayır. |
//Serial.println(offSet ); // heç bir səs çalınmadıqda səs aşkarlama modulunu təxminən yarısına və ya 512 -ə uyğunlaşdırmaq üçün istifadə edin. |
sumOffSet = sumOffSet + offSet ; |
} |
nümunələrPerPeriod = 0; |
maxValue = 0; |
//***************************************************************** |
// A0 girişini qəbul etməyə hazırlaşın |
//***************************************************************** |
avgOffSet = yuvarlaq (sumOffSet / OFFSETSAMPLES); |
Serial.println ("Geri saymaq."); |
gecikmə (1000); // 1 saniyə ara verin |
Serial.println ("3"); |
gecikmə (1000); // 1 saniyə ara verin |
Serial.println ("2"); |
gecikmə (1000); // 1 dayan |
Serial.println ("1"); |
gecikmə (1000); // 1 saniyə ara verin |
Serial.println ("Qeydinizi oxuyun!"); |
gecikmə (250); // reaksiya müddəti üçün 1/4 saniyə ara verin |
//***************************************************************** |
// A0 -dan NÜMUNƏ nümunələri götürün, nümunə götürmə müddəti ilə |
//***************************************************************** |
samplingPeriod = 1.0 / SAMPLING_FREQUENCY; // Dövr mikrosaniyələrdə |
üçün (i = 0; i <NÜMUNƏLƏR; i ++) |
{ |
microSeconds = micros (); // Arduino lövhəsi cari skriptin işə salınmasından bəri mikrosaniyələrin sayını qaytarır. |
X = analogRead (0); // Dəyəri analoq pin 0 -dan (A0) oxuyur, kəmiyyətləndirir və real termin kimi saxlayır. |
/ *lazım gələrsə saniyələr ərzində nümunələr arasında qalan gözləmə müddəti */ |
while (micros () <(microSeconds + (samplePreiod * 1000000))) |
{ |
// heç nə etmə, sadəcə gözlə |
} |
} |
//***************************************************************** |
// Avtokorrelyasiya funksiyası |
//***************************************************************** |
for (i = 0; i <NÜMUNƏLƏR; i ++) // i = gecikmə |
{ |
cəmi = 0; |
for (k = 0; k <NÜMUNƏLƏR - i; k ++) // Gecikmiş siqnalla uyğun siqnal |
{ |
cəmi = cəmi + ((((X [k]) - avgOffSet) * ((X [k + i]) - avgOffSet)); // X [k] siqnaldır və X [k+i] gecikmiş versiyadır |
} |
autoCorr = cəmi / NÜMUNƏLƏR; |
// First Peak Detect State Machine |
əgər (state_machine == 0 && i == 0) |
{ |
harman = autoCorr * 0.5; |
dövlət_maşın = 1; |
} |
başqa halda (state_machine == 1 && i> 0 && thresh 0) // state_machine = 1, birinci dövrənin istifadəsi üçün 1 dövr tapın |
{ |
maxValue = autoCorr ; |
} |
başqa halda (state_machine == 1 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0) |
{ |
periodBegin = i-1; |
dövlət_maşın = 2; |
numOfCycles = 1; |
samplePerPeriod = (periodBegin - 0); |
dövr = nümunələrPerPeriod; |
tənzimləyici = TUNER+(50.04 * exp (-0.102 * samplePerPeriod)); |
signalFrequency = ((SAMPLING_FREQUENCY) / (samplePerPeriod))-tənzimləyici; // f = fs/N |
} |
başqa halda (state_machine == 2 && i> 0 && thresh 0) // state_machine = 2, 1 -ci və 2 -ci dövr üçün 2 dövr tapın |
{ |
maxValue = autoCorr ; |
} |
başqa halda (state_machine == 2 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0) |
{ |
periodEnd = i-1; |
dövlət_maşın = 3; |
numOfCycles = 2; |
samplePerPeriod = (periodEnd - 0); |
signalFrequency2 = ((numOfCycles*SAMPLING_FREQUENCY) / (samplePerPeriod))-tənzimləyici; // f = (2*fs)/(2*N) |
maxValue = 0; |
} |
başqa halda (state_machine == 3 && i> 0 && thresh 0) // state_machine = 3, 1, 2 və 3 -cü dövr üçün 3 dövr tapın |
{ |
maxValue = autoCorr ; |
} |
başqa halda (state_machine == 3 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0) |
{ |
periodEnd = i-1; |
dövlət_maşın = 4; |
numOfCycles = 3; |
samplePerPeriod = (periodEnd - 0); |
signalFrequency3 = ((numOfCycles*SAMPLING_FREQUENCY) / (samplePerPeriod))-tənzimləyici; // f = (3*fs)/(3*N) |
} |
} |
//***************************************************************** |
// Nəticələrin təhlili |
//***************************************************************** |
əgər (samplePerPeriod == 0) |
{ |
Serial.println ("Hmm….. Mən əmin deyiləm. Məni aldatmaq istəyirsən?"); |
} |
başqa |
{ |
// ağırlıq funksiyasını hazırlayın |
cəmi = 0; |
əgər (siqnal Tezliyi! = 0) |
{ |
cəmi = 1; |
} |
əgər (siqnalFrequency2! = 0) |
{ |
cəmi = cəmi + 2; |
} |
if (signalFrequency3! = 0) |
{ |
cəmi = cəmi + 3; |
} |
// ağırlıq funksiyasından istifadə edərək tezliyi hesablayın |
signalFrequencyGuess = ((1/total) * signalFrequency) + ((2/total) * signalFrequency2) + ((3/total) * signalFrequency3); // ağırlıqlı bir tezlik tapın |
Serial.print ("Oynadığınız not təxminəndir"); |
Serial. çap (signalFrequencyGuess); // Tezlik təxminini çap edin. |
Serial.println ("Hz."); |
// təxmin əsasında oktava aralığını tapın |
oktav aralığı = 3; |
isə (! (signalFrequencyGuess> = storageNoteFreq [0] -7 && signalFrequencyGuess <= saxlanılanNoteFreq [11] +7)) |
{ |
üçün (i = 0; i <12; i ++) |
{ |
storageNoteFreq = 2 * storageNoteFreq ; |
} |
octaveRange ++; |
} |
// Ən yaxın notu tapın |
minValue = 10000000; |
noteLocation = 0; |
üçün (i = 0; i <12; i ++) |
{ |
if (minValue> abs (signalFrequencyGuess-storedNoteFreq )) |
{ |
minValue = abs (signalFrequencyGuess-storedNoteFreq ); |
noteLocation = i; |
} |
} |
// Qeyd yazdırın |
Serial.print ("Məncə sən oynamısan"); |
əgər (noteLocation == 0) |
{ |
Serial.print ("C"); |
} |
başqa halda (noteLocation == 1) |
{ |
Serial.print ("C#"); |
} |
başqa halda (noteLocation == 2) |
{ |
Serial.print ("D"); |
} |
başqa halda (noteLocation == 3) |
{ |
Serial.print ("D#"); |
} |
başqa halda (noteLocation == 4) |
{ |
Serial.print ("E"); |
} |
başqa halda (noteLocation == 5) |
{ |
Serial.print ("F"); |
} |
başqa halda (noteLocation == 6) |
{ |
Serial.print ("F#"); |
} |
başqa halda (noteLocation == 7) |
{ |
Serial.print ("G"); |
} |
başqa halda (noteLocation == 8) |
{ |
Serial.print ("G#"); |
} |
başqa halda (noteLocation == 9) |
{ |
Serial.print ("A"); |
} |
başqa halda (noteLocation == 10) |
{ |
Serial.print ("A#"); |
} |
başqa halda (noteLocation == 11) |
{ |
Serial.print ("B"); |
} |
Serial.println (octaveRange); |
} |
//***************************************************************** |
//Burada dayan. Yenidən başlatmaq üçün Arduino -da sıfırlama düyməsini vurun |
//***************************************************************** |
isə (1); |
} |
GitHub tərəfindən ❤ ilə evlənən rawgistfile1.txt -ə baxın
Addım 3: Musiqili Not Detektorunu qurun
Arduino Une -ni Arduino IDE -də yazılmış və ya yüklənmiş kodla PC -yə qoşun. Kodu tərtib edin və Arduinoya yükləyin. Dövrəni musiqi mənbəyinə yaxın qoyun. Qeyd: Giriş videosunda, musiqi mənbəyim olaraq PC hoparlörləri ilə birlikdə tabletə quraşdırılmış bir tətbiqdən istifadə edirəm. Arduino lövhəsindəki sıfırlama düyməsini vurun və sonra musiqi mənbəyində qeyd edin. Bir neçə saniyə sonra Musiqili Not Detektoru çalınan notu və onun tezliyini göstərəcək.