Detector de note muzicale: 3 pași
Detector de note muzicale: 3 pași
Anonim
Image
Image

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

Configurați detectorul de note muzicale
Configurați 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.