İçindekiler:
2025 Yazar: John Day | [email protected]. Son düzenleme: 2025-01-13 06:58
Bir enstrümanın çaldığı notayı algılayan bu proje ile arkadaşlarınızı ve ailenizi şaşırtın. Bu proje, bir elektronik klavyede, piyano uygulamasında veya başka herhangi bir enstrümanda çalınan notaların yanı sıra yaklaşık frekansı da gösterecektir.
Detaylar
Bu proje için, ses modülü dedektöründen gelen analog çıkış, Arduino Uno'nun A0 analog girişine gönderilir. Analog sinyal örneklenir ve nicelenir (sayısallaştırılır). İlk 3 periyodu kullanarak temel frekansı bulmak için otokorelasyon, ağırlıklandırma ve ayar kodu kullanılır. Yaklaşık temel frekans daha sonra en yakın nota frekansını belirlemek için oktav 3, 4 ve 5 aralığındaki frekanslarla karşılaştırılır. Son olarak en yakın frekans için tahmin edilen not ekrana yazdırılır.
Not: Bu talimat yalnızca projenin nasıl oluşturulacağına odaklanır. Ayrıntılar ve tasarım gerekçeleri hakkında daha fazla bilgi için lütfen şu bağlantıyı ziyaret edin: Daha Fazla Bilgi
Gereçler
- (1) Arduino Uno (veya Genuino Uno)
- (1) DEVMO Mikrofon Sensörü Yüksek Hassasiyetli Ses Algılama Modülü Uyumlu
- (1) Lehimsiz Breadboard
- (1) USB-A - B Kablosu
- Atlama telleri
- Müzik kaynağı (hoparlörlü piyano, klavye veya ağrılı uygulama)
- (1) Bilgisayar veya dizüstü bilgisayar
Adım 1: Nota Dedektörü Donanımını Oluşturun
Arduino Uno, bağlantı kabloları, lehimsiz devre tahtası ve DEVMO Mikrofon Sensörü Yüksek Hassasiyetli Ses Algılama Modülü (veya benzeri) kullanarak bu resimde gösterilen devreyi oluşturun.
Adım 2: Nota Dedektörünü Programlayın
Arduino IDE'de aşağıdaki kodu ekleyin.
gistfile1.txt
/* |
Dosya/Çizim Adı: MusicalNoteDetector |
Sürüm No.: v1.0 7 Haziran 2020'de düzenlendi |
Orijinal Yazar: Clyde A. Lettsome, PhD, PE, MEM |
Açıklama: Bu kod/çizim, bir elektronik klavyede veya piyano uygulamasında çalınan notanın yanı sıra yaklaşık frekansı da görüntüler. Bu proje için, analog çıkış |
ses modülü dedektörü Arduino Uno'nun A0 analog girişine gönderilir. Analog sinyal örneklenir ve nicelenir (sayısallaştırılır). Otokorelasyon, ağırlıklandırma ve ayar kodu, |
İlk 3 periyodu kullanarak temel frekansı bulun. Yaklaşık temel frekans daha sonra en yakın müzikal frekansı belirlemek için oktav 3, 4 ve 5 aralığındaki frekanslarla karşılaştırılır. |
not sıklığı. Son olarak en yakın frekans için tahmin edilen not ekrana yazdırılır. |
Lisans: Bu program ücretsiz bir yazılımdır; GNU Genel Kamu Lisansı (GPL) sürüm 3 veya daha sonraki herhangi bir şart altında yeniden dağıtabilir ve/veya değiştirebilirsiniz. |
Özgür Yazılım Vakfı tarafından yayınlandığı şekliyle seçtiğiniz sürümü. |
Notlar: Telif hakkı (c) 2020 by C. A. Lettsome Services, LLC |
Daha fazla bilgi için https://clydelettsome.com/blog/2020/06/07/my-weekend-project-musical-note-detector-using-an-arduino/ adresini ziyaret edin. |
*/ |
#define SAMPLES 128 //Arduino Uno için maksimum 128. |
#define SAMPLING_FREQUENCY 2048 //Fs = Nyquist'e göre, beklenen en yüksek frekansın 2 katı olmalıdır. |
#define OFSETSAMPLES 40 //kalibrasyon amacıyla kullanılır |
#define TUNER -3 //C3 130.50 olana kadar ayarlayın |
yüzer örneklemePeriod; |
imzasız uzun microSeconds; |
int X[ÖRNEKLER]; //gerçek değerleri tutmak için SAMPLES boyutunda vektör oluştur |
float autoCorr[ÖRNEKLER]; //sanal değerleri tutmak için SAMPLES boyutunda vektör oluştur |
float depolanmışNotFreq[12] = {130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185, 196, 207.65, 220, 233.08, 246.94}; |
int toplamOffSet = 0; |
int ofset[OFFSETSAMPLES]; // offset vektörü oluştur |
int avgOffSet; // offset vektörü oluştur |
int i, k, periodEnd, periodBegin, period, ayarlayıcı, noteLocation, octaveRange; |
float maxValue, minValue; |
uzun toplam; |
int eşik = 0; |
int numOfCycles = 0; |
kayan sinyalFrekans, sinyalFrekans2, sinyalFrekans3, sinyalFrekansTahmin, toplam; |
bayt durum_makinesi = 0; |
int samplePeriod = 0; |
geçersiz kurulum() |
{ |
Seri.başla(115200); //115200 Seri Monitör için Baud hızı |
} |
boşluk döngüsü() |
{ |
//***************************************************************** |
//Kalibrasyon Bölümü |
//***************************************************************** |
Serial.println("Kalibrasyon yapılıyor. Lütfen kalibrasyon sırasında nota çalmayınız."); |
için (i = 0; i < OFFSETSAMPLES; i++) |
{ |
offSet = analogRead(0); //Analog pin 0'dan (A0) değeri okur, kuantize eder ve gerçek terim olarak kaydeder. |
//Serial.println(offSet); //hiç ses çalınmadığında ses algılama modülünü yaklaşık olarak yarıya veya 512'ye ayarlamak için bunu kullanın. |
sumOffSet = toplamOffSet + ofset; |
} |
samplePeriod = 0; |
maxValue = 0; |
//***************************************************************** |
// A0'dan gelen girişi kabul etmeye hazırlanın |
//***************************************************************** |
avgOffSet = round(sumOffSet / OFFSETSAMPLES); |
Serial.println("Geri sayım yapılıyor."); |
gecikme(1000); // 1 saniye duraklat |
Seri.println("3"); |
gecikme(1000); // 1 saniye duraklat |
Seri.println("2"); |
gecikme(1000); // 1 için duraklat |
Seri.println("1"); |
gecikme(1000); // 1 saniye duraklat |
Serial.println("Notunuzu çalın!"); |
gecikme(250); //reaksiyon süresi için 1/4 saniye duraklat |
//***************************************************************** |
// SamplePeriod örnekleme periyodu ile A0'dan SAMPLES örnekleri toplayın |
//***************************************************************** |
samplePeriod = 1.0 / SAMPLING_FREQUENCY; //Mikrosaniye cinsinden süre |
için (i = 0; i < ÖRNEKLER; i++) |
{ |
mikroSaniye = mikros(); //Arduino kurulu mevcut betiği çalıştırmaya başladığından beri geçen mikrosaniye sayısını döndürür. |
X = analogRead(0); //Analog pin 0'dan (A0) değeri okur, kuantize eder ve gerçek terim olarak kaydeder. |
/*gerekirse örnekler arasında saniye cinsinden kalan bekleme süresi */ |
while (micros() < (microSeconds + (samplingPeriod * 1000000))) |
{ |
//hiçbir şey yapma sadece bekle |
} |
} |
//***************************************************************** |
//Otokorelasyon Fonksiyonu |
//***************************************************************** |
for (i = 0; i < ÖRNEK; i++) //i=gecikme |
{ |
toplam = 0; |
for (k = 0; k < ÖRNEKLER - i; k++) // Sinyali gecikmeli sinyalle eşleştirin |
{ |
toplam = toplam + (((X[k]) - avgOffSet) * ((X[k + i]) - avgOffSet)); //X[k] sinyaldir ve X[k+i] gecikmeli versiyondur |
} |
autoCorr = toplam / ÖRNEKLER; |
// İlk Tepe Algılama Durum Makinesi |
if (durum_makinesi==0 && i == 0) |
{ |
harman = autoCorr * 0,5; |
durum_makinesi = 1; |
} |
else if (state_machine == 1 && i>0 && thresh 0) //state_machine=1, birinci döngüyü kullanmak için 1 nokta bulun |
{ |
maxValue = autoCorr; |
} |
else if (state_machine == 1&& i>0 && thresh < autoCorr[i-1] && maxValue == autoCorr[i-1] && (autoCorr-autoCorr[i-1])<=0) |
{ |
periodBaşlangıç = i-1; |
durum_makinesi = 2; |
numOfCycles = 1; |
samplePerPeriod = (periodBegin - 0); |
periyot = samplePeriod; |
ayarlayıcı = TUNER+(50.04 * exp(-0.102 * samplePeriod)); |
sinyalFrekans = ((SAMPLING_FREQUENCY) / (samplesPerPeriod))-ayarlayıcı; // f = fs/N |
} |
else if (state_machine == 2 && i>0 && thresh 0) //state_machine=2, 1. ve 2. döngü için 2 periyot bulun |
{ |
maxValue = autoCorr; |
} |
else if (state_machine == 2&& i>0 && thresh < autoCorr[i-1] && maxValue == autoCorr[i-1] && (autoCorr-autoCorr[i-1])<=0) |
{ |
periyotBitiş = i-1; |
durum_makinesi = 3; |
numOfCycles = 2; |
samplePerPeriod = (periodEnd - 0); |
sinyalFrequency2 = ((numOfCycles*SAMPLING_FREQUENCY) / (samplesPerPeriod))-ayarlayıcı; // f = (2*fs)/(2*N) |
maxValue = 0; |
} |
else if (state_machine == 3 && i>0 && thresh 0) //state_machine=3, 1., 2. ve 3. döngü için 3 periyot bulun |
{ |
maxValue = autoCorr; |
} |
else if (state_machine == 3&& i>0 && thresh < autoCorr[i-1] && maxValue == autoCorr[i-1] && (autoCorr-autoCorr[i-1])<=0) |
{ |
periyotBitiş = i-1; |
durum_makinesi = 4; |
numOfCycles = 3; |
samplePerPeriod = (periodEnd - 0); |
sinyalFrequency3 = ((numOfCycles*SAMPLING_FREQUENCY) / (samplesPerPeriod))-ayarlayıcı; // f = (3*fs)/(3*N) |
} |
} |
//***************************************************************** |
//Sonuç Analizi |
//***************************************************************** |
if (samplesPeriod == 0) |
{ |
Serial.println("Hmm….. Emin değilim. Beni kandırmaya mı çalışıyorsun?"); |
} |
Başka |
{ |
// ağırlıklandırma fonksiyonunu hazırla |
toplam = 0; |
if (sinyal Frekansı !=0) |
{ |
toplam = 1; |
} |
if(sinyalFrekans2 !=0) |
{ |
toplam = toplam + 2; |
} |
if (signalFrequency3 !=0) |
{ |
toplam = toplam + 3; |
} |
//ağırlık fonksiyonunu kullanarak frekansı hesaplayın |
sinyalFrekansTahmin = ((1/toplam) * sinyalFrekans) + ((2/toplam) * sinyalFrekans2) + ((3/toplam) * sinyalFrekans3; // ağırlıklı bir frekans bul |
Serial.print("Çaldığınız nota yaklaşık olarak "); |
Serial.print(signalFrequencyGuess); // Frekans tahminini yazdır. |
Serial.println("Hz."); |
// tahmine göre oktav aralığını bul |
oktavaralığı=3; |
while (!(signalFrequencyGuess >= depolanmışNoteFreq[0]-7 && signalFrequencyGuess <= depolanmışNoteFreq[11]+7)) |
{ |
for(i = 0; ben < 12; ben++) |
{ |
depolananNotFreq = 2 * depolananNotFreq; |
} |
oktavaralığı++; |
} |
//En yakın notu bul |
minDeğer = 10000000; |
notKonum = 0; |
için (i = 0; i < 12; i++) |
{ |
if(minValue> abs(signalFrequencyGuess-storedNoteFreq)) |
{ |
minValue = abs(signalFrequencyGuess-storedNoteFreq); |
notKonum = i; |
} |
} |
//Notu yazdır |
Serial.print("Sanırım oynadınız"); |
if(noteLocation==0) |
{ |
Seri.print("C"); |
} |
else if(noteLocation==1) |
{ |
Serial.print("C#"); |
} |
else if(noteLocation==2) |
{ |
Seri.print("D"); |
} |
else if(noteLocation==3) |
{ |
Seri.print("D#"); |
} |
else if(noteLocation==4) |
{ |
Seri.print("E"); |
} |
else if(noteLocation==5) |
{ |
Seri.print("F"); |
} |
else if(noteLocation==6) |
{ |
Seri.print("F#"); |
} |
else if(noteLocation==7) |
{ |
Seri.print("G"); |
} |
else if(noteLocation==8) |
{ |
Serial.print("G#"); |
} |
else if(noteLocation==9) |
{ |
Seri.print("A"); |
} |
else if(noteLocation==10) |
{ |
Serial.print("A#"); |
} |
else if(noteLocation==11) |
{ |
Seri.print("B"); |
} |
Serial.println(octaveRange); |
} |
//***************************************************************** |
//Burada durun. Yeniden başlatmak için Arduino'daki sıfırlama düğmesine basın |
//***************************************************************** |
iken (1); |
} |
GitHub tarafından ❤ ile barındırılan rawgistfile1.txt dosyasını görüntüle
Adım 3: Müzik Notası Dedektörünü Kurun
Arduino IDE'ye yazılan veya yüklenen kod ile Arduino Uno'yu PC'ye bağlayın. Kodu derleyin ve Arduino'ya yükleyin. Devreyi müzik kaynağına yakın yerleştirin. Not: Tanıtım videosunda, müzik kaynağım olarak PC hoparlörleri ile birlikte tablette kurulu bir uygulama kullanıyorum. Arduino Board üzerindeki sıfırlama düğmesine basın ve ardından müzik kaynağında bir not çalın. Birkaç saniye sonra Müzik Nota Dedektörü çalınan notayı ve frekansını görüntüleyecektir.