Inhaltsverzeichnis:
- Lieferungen
- Schritt 1: Konstruieren Sie die Hardware für den Musiknotendetektor
- Schritt 2: Programmieren Sie den Musiknotendetektor
- Schritt 3: Einrichten des Musiknotendetektors
Video: Musiknoten-Detektor - Gunook
2024 Autor: John Day | [email protected]. Zuletzt bearbeitet: 2024-01-30 07:15
Überraschen Sie Ihre Freunde und Familie mit diesem Projekt, das die von einem Instrument gespielte Note erkennt. Dieses Projekt zeigt die ungefähre Frequenz sowie die Musiknote an, die auf einer elektronischen Tastatur, einer Klavier-App oder einem anderen Instrument gespielt wird.
Einzelheiten
Für dieses Projekt wird der analoge Ausgang des Soundmodul-Detektors an den A0-Analogeingang des Arduino Uno gesendet. Das analoge Signal wird abgetastet und quantisiert (digitalisiert). Autokorrelation, Gewichtung und Abstimmungscode werden verwendet, um die Grundfrequenz unter Verwendung der ersten 3 Perioden zu finden. Die ungefähre Grundfrequenz wird dann mit Frequenzen in den Oktaven 3, 4 und 5 verglichen, um die nächste Musiktonfrequenz zu bestimmen. Schließlich wird die erratene Note für die nächste Frequenz auf dem Bildschirm gedruckt.
Hinweis: Dieses anweisbare konzentriert sich nur darauf, wie das Projekt erstellt wird. Für weitere Informationen zu den Details und Design-Begründungen besuchen Sie bitte diesen Link: Weitere Informationen
Lieferungen
- (1) Arduino Uno (oder Genuino Uno)
- (1) Kompatibel mit DEVMO-Mikrofonsensor mit hochempfindlichem Schallerkennungsmodul
- (1) lötfreies Steckbrett
- (1) USB-A-zu-B-Kabel
- Überbrückungsdrähte
- Musikquelle (Klavier, Keyboard oder Paino-App mit Lautsprechern)
- (1) Computer oder Laptop
Schritt 1: Konstruieren Sie die Hardware für den Musiknotendetektor
Mit einem Arduino Uno, Verbindungsdrähten, einem lötfreien Steckbrett und einem DEVMO-Mikrofonsensor-Sounderkennungsmodul (oder ähnlichem) bauen Sie die in diesem Bild gezeigte Schaltung auf
Schritt 2: Programmieren Sie den Musiknotendetektor
Fügen Sie in der Arduino-IDE den folgenden Code hinzu.
gistfile1.txt
/* |
Datei-/Skizzenname: MusicalNoteDetector |
Versions-Nr.: v1.0 Erstellt am 7. Juni 2020 |
Originalautor: Clyde A. Lettsome, PhD, PE, MEM |
Beschreibung: Dieser Code/diese Skizze zeigt die ungefähre Frequenz sowie die Musiknote an, die auf einer elektronischen Tastatur oder einer Klavier-App gespielt wird. Für dieses Projekt ist der Analogausgang des |
Der Soundmodul-Detektor wird an den A0-Analogeingang des Arduino Uno gesendet. Das analoge Signal wird abgetastet und quantisiert (digitalisiert). Autokorrelation, Gewichtung und Tuning-Code wird verwendet, um |
Finden Sie die Grundfrequenz mit den ersten 3 Perioden. Die ungefähre Grundfrequenz wird dann mit Frequenzen in den Oktaven 3, 4 und 5 verglichen, um das nächste musikalische |
Frequenz beachten. Schließlich wird die erratene Note für die nächste Frequenz auf dem Bildschirm gedruckt. |
Lizenz: Dieses Programm ist freie Software; Sie können es unter den Bedingungen der GNU General Public License (GPL) Version 3 oder einer späteren Version weitergeben und/oder ändern |
Version Ihrer Wahl, wie von der Free Software Foundation veröffentlicht. |
Hinweise: Copyright (c) 2020 von C. A. Lettsome Services, LLC |
Weitere Informationen finden Sie unter |
*/ |
#define SAMPLES 128 // Max 128 für Arduino Uno. |
#define SAMPLING_FREQUENCY 2048 //Fs = Basierend auf Nyquist, muss das Doppelte der höchsten erwarteten Frequenz sein. |
#define OFFSETSAMPLES 40 //zu Kalibrierzwecken verwendet |
#define TUNER -3 //Anpassen bis C3 130,50. beträgt |
Float-Sampling-Periode; |
lange Mikrosekunden ohne Vorzeichen; |
int X[MUSTER]; // Vektor der Größe SAMPLES erstellen, um reale Werte zu halten |
float autoCorr[SAMPLES]; //Erzeuge einen Vektor der Größe SAMPLES, um imaginäre Werte zu halten |
float StoredNoteFreq[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]; // Offset-Vektor erstellen |
int avgOffSet; // Offset-Vektor erstellen |
int i, k, periodEnd, periodBegin, period, adjuster, noteLocation, octaveRange; |
float maxValue, minValue; |
lange Summe; |
int-Schwellwert = 0; |
int numOfCycles = 0; |
float signalFrequency, signalFrequency2, signalFrequency3, signalFrequencyGuess, total; |
Byte state_machine = 0; |
int samplePeriod = 0; |
Void-Setup () |
{ |
Serial.begin(115200); //115200 Baudrate für den seriellen Monitor |
} |
Leere Schleife () |
{ |
//***************************************************************** |
//Kalibrierungsabschnitt |
//***************************************************************** |
Serial.println ("Kalibrieren. Bitte spielen Sie während der Kalibrierung keine Noten."); |
für (i = 0; i < OFFSETSAMPLES; i++) |
{ |
offSet = analogRead(0); // Liest den Wert vom analogen Pin 0 (A0), quantisiere ihn und speichere ihn als realen Ausdruck. |
//Seriell.println(offSet); // Verwenden Sie dies, um das Tonerkennungsmodul auf ungefähr die Hälfte oder 512 einzustellen, wenn kein Ton wiedergegeben wird. |
sumOffSet = sumOffSet + offSet; |
} |
SamplePeriode = 0; |
maxWert = 0; |
//***************************************************************** |
// Bereiten Sie sich darauf vor, die Eingabe von A0 zu akzeptieren |
//***************************************************************** |
avgOffSet = round(sumOffSet / OFFSETSAMPLES); |
Serial.println ("Countdown."); |
Verzögerung (1000); // 1 Sekunde pausieren |
Serial.println("3"); |
Verzögerung (1000); // 1 Sekunde pausieren |
Serial.println("2"); |
Verzögerung (1000); // Pause für 1 |
Serial.println("1"); |
Verzögerung (1000); // 1 Sekunde pausieren |
Serial.println ("Spielen Sie Ihre Notiz ab!"); |
Verzögerung (250); // Pause für 1/4 Sekunde für Reaktionszeit |
//***************************************************************** |
// Sammle SAMPLES-Samples von A0 mit der Sample-Periode von SamplingPeriod |
//***************************************************************** |
SamplingPeriod = 1.0 / SAMPLING_FREQUENCY; //Zeitraum in Mikrosekunden |
für (i = 0; i < PROBEN; i++) |
{ |
microSekunden = micros(); // Gibt die Anzahl der Mikrosekunden zurück, seit das Arduino-Board mit der Ausführung des aktuellen Skripts begonnen hat. |
X = analogRead(0); // Liest den Wert vom analogen Pin 0 (A0), quantisiere ihn und speichere ihn als realen Ausdruck. |
/*verbleibende Wartezeit zwischen den Proben ggf. in Sekunden */ |
while (micros() < (microSeconds + (samplingPeriod * 1000000))) |
{ |
// Nichts tun, nur warten |
} |
} |
//***************************************************************** |
//Autokorrelationsfunktion |
//***************************************************************** |
für (i = 0; i < SAMPLES; i++) //i=Verzögerung |
{ |
Summe = 0; |
for (k = 0; k < SAMPLES - i; k++) // Match-Signal mit verzögertem Signal |
{ |
Summe = Summe + (((X[k]) – avgOffSet) * ((X[k + i]) – avgOffSet)); //X[k] ist das Signal und X[k+i] ist die verzögerte Version |
} |
autoCorr = Summe / SAMPLES; |
// Erste Peak-Erkennungs-Zustandsmaschine |
if (state_machine==0 && i == 0) |
{ |
Schwelle = autoCorr * 0,5; |
Zustandsmaschine = 1; |
} |
else if (state_machine == 1 && i>0 && thresh 0) //state_machine=1, finde 1 Periode für die Verwendung des ersten Zyklus |
{ |
maxValue = autoCorr; |
} |
else if (state_machine == 1&& i>0 && thresh < autoCorr[i-1] && maxValue == autoCorr[i-1] && (autoCorr-autoCorr[i-1])<=0) |
{ |
periodBegin = i-1; |
Zustandsmaschine = 2; |
AnzahlZyklen = 1; |
SamplesPeriod = (PeriodeBegin - 0); |
Periode = SamplePeriod; |
Einsteller = TUNER + (50,04 * exp(-0,102 * SamplesPerPeriod)); |
signalFrequency = ((SAMPLING_FREQUENCY) / (samplesPeriod))-Einsteller; // f = fs/N |
} |
else if (state_machine == 2 && i>0 && thresh 0) //state_machine=2, finde 2 Perioden für den 1. und 2. Zyklus |
{ |
maxValue = autoCorr; |
} |
else if (state_machine == 2&& i>0 && thresh < autoCorr[i-1] && maxValue == autoCorr[i-1] && (autoCorr-autoCorr[i-1])<=0) |
{ |
periodEnd = i-1; |
Zustandsmaschine = 3; |
AnzahlZyklen = 2; |
SamplesPeriod = (PeriodeEnde - 0); |
signalFrequency2 = ((numOfCycles*SAMPLING_FREQUENCY) / (samplesPerPeriod))-Einsteller; // f = (2*fs)/(2*N) |
maxWert = 0; |
} |
else if (state_machine == 3 && i>0 && thresh 0) //state_machine=3, finde 3 Perioden für den 1., 2. und 3. Zyklus |
{ |
maxValue = autoCorr; |
} |
else if (state_machine == 3&& i>0 && thresh < autoCorr[i-1] && maxValue == autoCorr[i-1] && (autoCorr-autoCorr[i-1])<=0) |
{ |
periodEnd = i-1; |
Zustandsmaschine = 4; |
AnzahlZyklen = 3; |
SamplesPeriod = (PeriodeEnde - 0); |
signalFrequency3 = ((numOfCycles*SAMPLING_FREQUENCY) / (samplesPerPeriod))-Einsteller; // f = (3*fs)/(3*N) |
} |
} |
//***************************************************************** |
//Ergebnisanalyse |
//***************************************************************** |
if (samplesPerPeriod == 0) |
{ |
Serial.println("Hmm….. Ich bin mir nicht sicher. Versuchst du mich auszutricksen?"); |
} |
anders |
{ |
// Bereiten Sie die Gewichtungsfunktion vor |
gesamt = 0; |
if (signalFrequenz !=0) |
{ |
gesamt = 1; |
} |
if(signalFrequenz2 !=0) |
{ |
gesamt = gesamt + 2; |
} |
if (signalFrequenz3 !=0) |
{ |
gesamt = gesamt + 3; |
} |
// Berechnen Sie die Frequenz mit der Gewichtungsfunktion |
SignalFrequencyGuess = ((1/Gesamt) * SignalFrequenz) + ((2/Gesamt) * SignalFrequenz2) + ((3/Gesamt) * SignalFrequenz3); // eine gewichtete Frequenz finden |
Serial.print ("Die Note, die Sie gespielt haben, ist ungefähr"); |
Serial.print (signalFrequencyGuess); //Drucken Sie die Frequenzschätzung. |
Serial.println("Hz."); |
// Finden Sie den Oktavbereich basierend auf der Schätzung |
Oktavbereich=3; |
while (!(signalFrequencyGuess >= savedNoteFreq[0]-7 && signalFrequencyGuess <= savedNoteFreq[11]+7)) |
{ |
für(i = 0; i < 12; i++) |
{ |
gespeicherteNotizFreq = 2 * gespeicherteNotizFreq; |
} |
octaveRange++; |
} |
//Finde die nächste Notiz |
minWert = 10000000; |
noteLocation = 0; |
für (i = 0; i < 12; i++) |
{ |
if(minValue> abs(signalFrequencyGuess-storedNoteFreq)) |
{ |
minValue = abs(signalFrequencyGuess-storedNoteFreq); |
noteLocation = i; |
} |
} |
//Drucken Sie die Notiz |
Serial.print ("Ich glaube, du hast gespielt"); |
if(AnmerkungStandort==0) |
{ |
Serial.print ("C"); |
} |
sonst if(noteLocation==1) |
{ |
Serial.print("C#"); |
} |
sonst if(noteLocation==2) |
{ |
Serial.print ("D"); |
} |
sonst if(noteLocation==3) |
{ |
Serial.print ("D #"); |
} |
sonst if(noteLocation==4) |
{ |
Serial.print ("E"); |
} |
sonst if(noteLocation==5) |
{ |
Serial.print ("F"); |
} |
sonst if(noteLocation==6) |
{ |
Serial.print ("F #"); |
} |
sonst if(noteLocation==7) |
{ |
Serial.print ("G"); |
} |
sonst if(noteLocation==8) |
{ |
Serial.print ("G #"); |
} |
sonst if(noteLocation==9) |
{ |
Serial.print ("A"); |
} |
sonst if(noteLocation==10) |
{ |
Serial.print ("A #"); |
} |
sonst if(noteLocation==11) |
{ |
Serial.print ("B"); |
} |
Serial.println (OktaveRange); |
} |
//***************************************************************** |
//Stoppe hier. Drücken Sie die Reset-Taste auf Arduino, um neu zu starten |
//***************************************************************** |
während (1); |
} |
rawgistfile1.txt anzeigen, gehostet mit ❤ von GitHub
Schritt 3: Einrichten des Musiknotendetektors
Verbinden Sie das Arduino Uno mit dem PC mit dem in der Arduino IDE geschriebenen oder geladenen Code. Kompilieren Sie den Code und laden Sie ihn auf den Arduino hoch. Platzieren Sie den Stromkreis in der Nähe der Musikquelle. Hinweis: Im Einführungsvideo verwende ich als Musikquelle eine auf dem Tablet installierte App in Verbindung mit PC-Lautsprechern. Drücken Sie die Reset-Taste auf dem Arduino Board und spielen Sie dann eine Note auf der Musikquelle. Nach einigen Sekunden zeigt der Musiknotendetektor die gespielte Note und ihre Frequenz an.