Cuprins:
2025 Autor: John Day | [email protected]. Modificat ultima dată: 2025-01-13 06:58
Uimiți-vă prietenii și familia cu acest proiect care detectează nota cântată de un instrument. Acest proiect va afișa frecvența aproximativă, precum și nota muzicală redată pe o tastatură electronică, o aplicație pentru pian sau orice alt instrument.
Detalii
Pentru acest proiect, ieșirea analogică de la detectorul modulului de sunet este trimisă la intrarea analogică A0 a Arduino Uno. Semnalul analogic este eșantionat și cuantificat (digitalizat). Codul de corelare automată, ponderare și reglare este utilizat pentru a găsi frecvența fundamentală folosind primele 3 perioade. Frecvența fundamentală aproximativă este apoi comparată cu frecvențele din intervalul octavelor 3, 4 și 5 pentru a determina cea mai apropiată frecvență a notelor muzicale. În cele din urmă, nota ghicită pentru cea mai apropiată frecvență este imprimată pe ecran.
Notă: Această instrucțiune se concentrează doar asupra modului de construire a proiectului. Pentru mai multe informații despre detalii și justificări de proiectare, vă rugăm să vizitați acest link: Mai multe informații
Provizii
- (1) Arduino Uno (sau Genuino Uno)
- (1) Modul de detectare a sunetului cu sensibilitate ridicată pentru senzorul de microfon DEVMO
- (1) Pânză fără sudură
- (1) Cablu USB-A la B
- Sârme de jumper
- Sursă muzicală (pian, tastatură sau aplicație paino cu difuzoare)
- (1) Computer sau laptop
Pasul 1: Construiți hardware-ul pentru detectorul de note muzicale
Folosind un Arduino Uno, cablurile de conectare, o placă fără sudură și un modul de detectare a sunetului cu sensibilitate ridicată (sau similar) DEVMO construiesc circuitul prezentat în această imagine
Pasul 2: Programați Detectorul de note muzicale
În IDE-ul Arduino, adăugați următorul cod.
gistfile1.txt
/* |
Nume fișier / schiță: MusicalNoteDetector |
Versiune nr.: v1.0 Creat 7 iunie 2020 |
Autor original: Clyde A. Lettsome, dr., PE, MEM |
Descriere: Acest cod / schiță afișează frecvența aproximativă, precum și nota muzicală redată pe o tastatură electronică sau o aplicație pentru pian. Pentru acest proiect, ieșirea analogică din |
detectorul modulului de sunet este trimis la intrarea analogică A0 a Arduino Uno. Semnalul analogic este eșantionat și cuantificat (digitalizat). Se utilizează codul de corelare automată, ponderare și reglare |
găsiți frecvența fundamentală folosind primele 3 perioade. Frecvența fundamentală aproximativă este apoi comparată cu frecvențele din intervalele de octave 3, 4 și 5 pentru a determina cel mai apropiat muzical |
frecvența notei. În cele din urmă, nota ghicită pentru cea mai apropiată frecvență este imprimată pe ecran. |
Licență: Acest program este software gratuit; îl puteți redistribui și / sau modifica în condițiile licenței GNU General Public License (GPL) versiunea 3 sau oricare ulterioară |
versiunea la alegere, publicată de Free Software Foundation. |
Note: Copyright (c) 2020 de C. A. Lettsome Services, LLC |
Pentru mai multe informații vizitați |
*/ |
#define SAMPLES 128 // Max 128 pentru Arduino Uno. |
#define SAMPLING_FREQUENCY 2048 // Fs = Bazat pe Nyquist, trebuie să fie de 2 ori cea mai mare frecvență așteptată. |
#define OFFSETSAMPLES 40 // utilizat în scopuri de calibrare |
#define TUNER -3 // Reglați până când C3 este 130,50 |
float samplingPeriod; |
microSecunde lungi nesemnate; |
int X [SAMPLES]; // creați vector de mărime EȘANTIOANE pentru a păstra valori reale |
float autoCorr [SAMPLES]; // creați vector de mărime EȘANTIOANE pentru a păstra valori imaginare |
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]; // creați offset vector |
int avgOffSet; // creați offset vector |
int i, k, periodEnd, periodBegin, period, ajuster, noteLocation, octaveRange; |
float maxValue, minValue; |
sumă lungă; |
int treier = 0; |
int numOfCycles = 0; |
float signalFrequency, signalFrequency2, signalFrequency3, signalFrequencyGuess, total; |
octet state_machine = 0; |
int samplesPerPeriod = 0; |
configurare nulă () |
{ |
Serial.begin (115200); // Rată de 115200 Baud pentru monitorul serial |
} |
bucla nulă () |
{ |
//***************************************************************** |
// Secțiunea Calabrație |
//***************************************************************** |
Serial.println ("Calabrating. Vă rugăm să nu cântați nicio notă în timpul calabrării."); |
pentru (i = 0; i <OFFSETSAMPLES; i ++) |
{ |
offSet = analogRead (0); // Citește valoarea de la pinul analogic 0 (A0), cuantificați-o și salvați-o ca termen real. |
//Serial.println(offSet); // utilizați acest lucru pentru a regla modulul de detectare a sunetului la aproximativ jumătate sau 512 când nu se redă sunet. |
sumOffSet = sumOffSet + offSet ; |
} |
samplesPerPeriod = 0; |
Valoare maximă = 0; |
//***************************************************************** |
// Pregătește-te să accepți intrarea din A0 |
//***************************************************************** |
avgOffSet = round (sumOffSet / OFFSETSAMPLES); |
Serial.println ("Numărătoarea inversă."); |
întârziere (1000); // pauză timp de 1 secundă |
Serial.println ("3"); |
întârziere (1000); // pauză timp de 1 secundă |
Serial.println ("2"); |
întârziere (1000); // pauză pentru 1 |
Serial.println („1”); |
întârziere (1000); // pauză timp de 1 secundă |
Serial.println („Joacă-ți nota!”); |
întârziere (250); // pauză timp de 1/4 de secundă pentru timpul de reacție |
//***************************************************************** |
// Colectați eșantioane de probe din A0 cu perioada de eșantionare a perioadei de eșantionare |
//***************************************************************** |
samplingPeriod = 1.0 / SAMPLING_FREQUENCY; // Perioada în microsecunde |
pentru (i = 0; i <SAMPLES; i ++) |
{ |
microSecunde = micros (); // Returnează numărul de microsecunde de când placa Arduino a început să ruleze scriptul curent. |
X = analogRead (0); // Citește valoarea de la pinul analogic 0 (A0), cuantificați-o și salvați-o ca termen real. |
/ * timpul de așteptare rămas între probe, dacă este necesar în câteva secunde * / |
while (micros () <(microSeconds + (samplingPeriod * 1000000))) |
{ |
// nu face nimic doar să aștepți |
} |
} |
//***************************************************************** |
// Funcția de autocorelare |
//***************************************************************** |
pentru (i = 0; i <SAMPLES; i ++) // i = întârziere |
{ |
suma = 0; |
for (k = 0; k <SAMPLES - i; k ++) // Semnal de potrivire cu semnal întârziat |
{ |
sum = sum + (((X [k]) - avgOffSet) * ((X [k + i]) - avgOffSet)); // X [k] este semnalul și X [k + i] este versiunea întârziată |
} |
autoCorr = sum / SAMPLES; |
// Prima mașină de detectare a vârfurilor |
if (state_machine == 0 && i == 0) |
{ |
treieră = autoCorr * 0,5; |
state_machine = 1; |
} |
altfel dacă (state_machine == 1 && i> 0 && merge 0) // state_machine = 1, găsiți 1 perioadă pentru utilizarea primului ciclu |
{ |
maxValue = autoCorr ; |
} |
else if (state_machine == 1 && i> 0 && treier <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0) |
{ |
periodBegin = i-1; |
state_machine = 2; |
numOfCycles = 1; |
samplesPerPeriod = (periodBegin - 0); |
period = samplesPerPeriod; |
reglator = TUNER + (50.04 * exp (-0.102 * samplesPerPeriod)); |
signalFrequency = ((SAMPLING_FREQUENCY) / (samplesPerPeriod)) - reglator; // f = fs / N |
} |
altfel dacă (state_machine == 2 && i> 0 && merge 0) // state_machine = 2, găsiți 2 perioade pentru ciclul 1 și 2 |
{ |
maxValue = autoCorr ; |
} |
else if (state_machine == 2 && i> 0 && treier <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0) |
{ |
periodEnd = i-1; |
state_machine = 3; |
numOfCycles = 2; |
samplesPerPeriod = (periodEnd - 0); |
signalFrequency2 = ((numOfCycles * SAMPLING_FREQUENCY) / (samplesPerPeriod)) - reglator; // f = (2 * fs) / (2 * N) |
Valoare maximă = 0; |
} |
altfel dacă (state_machine == 3 && i> 0 && merge 0) // state_machine = 3, găsiți 3 perioade pentru ciclul 1, 2 și 3 |
{ |
maxValue = autoCorr ; |
} |
else if (state_machine == 3 && i> 0 && treier <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0) |
{ |
periodEnd = i-1; |
state_machine = 4; |
numOfCycles = 3; |
samplesPerPeriod = (periodEnd - 0); |
signalFrequency3 = ((numOfCycles * SAMPLING_FREQUENCY) / (samplesPerPeriod)) - ajustator; // f = (3 * fs) / (3 * N) |
} |
} |
//***************************************************************** |
// Analiza rezultatelor |
//***************************************************************** |
if (samplesPerPeriod == 0) |
{ |
Serial.println ("Hmm ….. Nu sunt sigur. Încercați să mă păcăliți?"); |
} |
altceva |
{ |
// pregătește funcția de ponderare |
total = 0; |
if (signalFrequency! = 0) |
{ |
total = 1; |
} |
if (signalFrequency2! = 0) |
{ |
total = total + 2; |
} |
if (signalFrequency3! = 0) |
{ |
total = total + 3; |
} |
// calculați frecvența utilizând funcția de ponderare |
signalFrequencyGuess = ((1 / total) * signalFrequency) + ((2 / total) * signalFrequency2) + ((3 / total) * signalFrequency3); // găsiți o frecvență ponderată |
Serial.print („Nota pe care ați jucat-o este aproximativ”); |
Serial.print (signalFrequencyGuess); // Imprimați ghiciul de frecvență. |
Serial.println ("Hz."); |
// găsiți intervalul de octave pe baza ghiciului |
octaveRange = 3; |
while (! (signalFrequencyGuess> = storedNoteFreq [0] -7 && signalFrequencyGuess <= storedNoteFreq [11] +7)) |
{ |
pentru (i = 0; i <12; i ++) |
{ |
storedNoteFreq = 2 * storedNoteFreq ; |
} |
octaveRange ++; |
} |
// Găsiți nota cea mai apropiată |
MinValue = 10000000; |
noteLocation = 0; |
pentru (i = 0; i <12; i ++) |
{ |
if (minValue> abs (signalFrequencyGuess-storedNoteFreq )) |
{ |
MinValue = abs (signalFrequencyGuess-storedNoteFreq ); |
noteLocation = i; |
} |
} |
// Imprimați nota |
Serial.print („Cred că ai jucat”); |
if (noteLocation == 0) |
{ |
Serial.print ("C"); |
} |
altfel dacă (noteLocation == 1) |
{ |
Serial.print („C #”); |
} |
altfel dacă (noteLocation == 2) |
{ |
Serial.print („D”); |
} |
altfel dacă (noteLocation == 3) |
{ |
Serial.print ("D #"); |
} |
altfel dacă (noteLocation == 4) |
{ |
Serial.print („E”); |
} |
altfel dacă (noteLocation == 5) |
{ |
Serial.print („F”); |
} |
altfel dacă (noteLocation == 6) |
{ |
Serial.print ("F #"); |
} |
altfel dacă (noteLocation == 7) |
{ |
Serial.print („G”); |
} |
altfel dacă (noteLocation == 8) |
{ |
Serial.print ("G #"); |
} |
altfel dacă (noteLocation == 9) |
{ |
Serial.print ("A"); |
} |
altfel dacă (noteLocation == 10) |
{ |
Serial.print ("A #"); |
} |
altfel dacă (noteLocation == 11) |
{ |
Serial.print („B”); |
} |
Serial.println (octaveRange); |
} |
//***************************************************************** |
//Opreste aici. Apăsați butonul de resetare pe Arduino pentru a reporni |
//***************************************************************** |
în timp ce (1); |
} |
vizualizați rawgistfile1.txt găzduit cu ❤ de GitHub
Pasul 3: Configurați detectorul de note muzicale
Conectați Arduino Uno la computer cu codul scris sau încărcat în ID-ul Arduino. Compilați și încărcați codul pe Arduino. Plasați circuitul aproape de sursa de muzică. Notă: În videoclipul de introducere, folosesc ca sursă de muzică o aplicație instalată pe tabletă împreună cu difuzoare pentru PC. Apăsați butonul de resetare de pe placa Arduino și apoi redați o notă pe sursa de muzică. După câteva secunde, Detectorul de note muzicale va afișa nota redată și frecvența acesteia.