Taula de continguts:
2025 Autora: John Day | [email protected]. Última modificació: 2025-01-13 06:57
Sorprèn als teus amics i familiars amb aquest projecte que detecta la nota que toca un instrument. Aquest projecte mostrarà la freqüència aproximada, així com la nota musical reproduïda en un teclat electrònic, una aplicació de piano o qualsevol altre instrument.
Detalls
Per a aquest projecte, la sortida analògica del detector del mòdul de so s’envia a l’entrada analògica A0 de l’Arduino Uno. El senyal analògic es mostra i es quantifica (digitalitza). El codi d’autocorrelació, ponderació i afinació s’utilitza per trobar la freqüència fonamental mitjançant els primers 3 períodes. A continuació, es compara la freqüència fonamental aproximada amb les freqüències del rang de les octaves 3, 4 i 5 per determinar la freqüència de notes musicals més propera. Finalment, la nota endevinada de la freqüència més propera s’imprimeix a la pantalla.
Nota: aquesta instrucció només es centra en com construir el projecte. Per obtenir més informació sobre els detalls i les justificacions de disseny, visiteu aquest enllaç: Més informació
Subministraments
- (1) Arduino Uno (o Genuino Uno)
- (1) Compatible amb mòdul de detecció de so d'alta sensibilitat del sensor de micròfon DEVMO
- (1) Taula de pa sense soldadura
- (1) Cable USB-A a B.
- Filferros de pont
- Font musical (piano, teclat o aplicació paino amb altaveus)
- (1) Ordinador o ordinador portàtil
Pas 1: construïu el maquinari per al detector de notes musicals
Mitjançant un Arduino Uno, els cables de connexió, una placa sense soldar i un mòdul de detecció de so d'alta sensibilitat (o similar) del sensor de micròfon DEVMO construeixen el circuit que es mostra en aquesta imatge
Pas 2: programa el Detector de notes musicals
A l’IDE Arduino, afegiu el codi següent.
gistfile1.txt
/* |
Nom del fitxer / esbós: MusicalNoteDetector |
Número de versió: v1.0 Creat el 7 de juny de 2020 |
Autor original: Clyde A. Lettsome, PhD, PE, MEM |
Descripció: aquest codi / esbós mostra la freqüència aproximada i la nota musical reproduïda en un teclat electrònic o una aplicació de piano. Per a aquest projecte, la sortida analògica del fitxer |
El detector de mòduls de so s’envia a l’entrada analògica A0 de l’Arduino Uno. El senyal analògic es mostra i es quantifica (digitalitza). S’utilitza el codi d’autocorrelació, ponderació i afinació |
trobar freqüència fonamental utilitzant els primers 3 períodes. La freqüència fonamental aproximada es compara amb les freqüències de les octaves 3, 4 i 5 per determinar el musical més proper |
freqüència de notes. Finalment, la nota endevinada de la freqüència més propera s’imprimeix a la pantalla. |
Llicència: aquest programa és programari lliure; podeu redistribuir-lo i / o modificar-lo segons els termes de la Llicència Pública General GNU (GPL) versió 3, o qualsevol altra versió posterior |
versió que trieu, publicada per la Free Software Foundation. |
Notes: Copyright (c) 2020 de C. A. Lettsome Services, LLC |
Per obtenir més informació, visiteu |
*/ |
#define SAMPLES 128 // Max 128 per a Arduino Uno. |
#define SAMPLING_FREQUENCY 2048 // Fs = Basat en Nyquist, ha de ser 2 vegades la freqüència més alta esperada. |
#define OFFSETSAMPLES 40 // s’utilitza amb finalitats calabradores |
#define TUNER -3 // Ajusta fins que C3 sigui 130,50 |
període de mostreig flotant; |
microSegons llargs sense signar; |
int X [MOSTRES]; // Creeu vector de MOSTRES de mida per contenir valors reals |
float autoCorr [MOSTRES]; // Creeu vector de MOSTRES de mida per mantenir valors imaginaris |
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]; // crear vector de desplaçament |
int avgOffSet; // crear vector de desplaçament |
int i, k, periodEnd, periodBegin, period, ajust, noteLocation, octaveRange; |
float maxValue, minValue; |
suma llarga; |
int batre = 0; |
int numOfCycles = 0; |
float signalFrequency, signalFrequency2, signalFrequency3, signalFrequencyGuess, total; |
byte state_machine = 0; |
int samplesPerPeriod = 0; |
configuració nul·la () |
{ |
Serial.begin (115200); // 115200 Baud rate per al monitor de sèrie |
} |
bucle buit () |
{ |
//***************************************************************** |
// Secció de calabració |
//***************************************************************** |
Serial.println ("Calabrating. Si us plau, no toqueu cap nota durant la calabració."); |
per a (i = 0; i <OFFSETSAMPLES; i ++) |
{ |
offSet = analogRead (0); // Llegeix el valor del pin analògic 0 (A0), quantifiqueu-lo i deseu-lo com a terme real. |
//Serial.println(offSet); // utilitzeu això per ajustar el mòdul de detecció de so a aproximadament la meitat o 512 quan no es reprodueixi cap so. |
sumOffSet = sumOffSet + offSet ; |
} |
samplesPerPeriod = 0; |
Valor màxim = 0; |
//***************************************************************** |
// Prepareu-vos per acceptar l'entrada d'A0 |
//***************************************************************** |
avgOffSet = round (sumOffSet / OFFSETSAMPLES); |
Serial.println ("Compte enrere"); |
retard (1000); // pausa durant 1 segon |
Serial.println ("3"); |
retard (1000); // pausa durant 1 segon |
Serial.println ("2"); |
retard (1000); // pausa per a 1 |
Serial.println ("1"); |
retard (1000); // pausa durant 1 segon |
Serial.println ("Reprodueix la teva nota!"); |
retard (250); // Pausa durant 1/4 de segon durant el temps de reacció |
//***************************************************************** |
// Recolliu mostres de MOSTRES d'A0 amb el període de mostra del període de mostreig |
//***************************************************************** |
samplingPeriod = 1.0 / SAMPLING_FREQUENCY; // Període en microsegons |
per a (i = 0; i <SAMPLES; i ++) |
{ |
microSegons = micros (); // Retorna el nombre de microsegons des que la placa Arduino va començar a executar l'script actual. |
X = analogRead (0); // Llegeix el valor del pin analògic 0 (A0), quantifiqueu-lo i deseu-lo com a terme real. |
/ * temps d'espera restant entre mostres si és necessari en segons * / |
while (micros () <(microSeconds + (samplingPeriod * 1000000))) |
{ |
// no fer res només esperar |
} |
} |
//***************************************************************** |
// Funció d’autocorrelació |
//***************************************************************** |
for (i = 0; i <SAMPLES; i ++) // i = delay |
{ |
suma = 0; |
for (k = 0; k <SAMPLES - i; k ++) // Coincideix el senyal amb el senyal retardat |
{ |
suma = suma + (((X [k]) - avgOffSet) * ((X [k + i]) - avgOffSet)); // X [k] és el senyal i X [k + i] és la versió retardada |
} |
autoCorr = suma / MOSTRES; |
// Primera màquina d'estat de detecció de pics |
if (state_machine == 0 && i == 0) |
{ |
batre = autoCorr * 0,5; |
màquina_estat = 1; |
} |
altrament si (state_machine == 1 && i> 0 && beat 0) // state_machine = 1, trobeu 1 període per utilitzar el primer cicle |
{ |
Valor màxim = autoCorr ; |
} |
else if (state_machine == 1 && i> 0 && batre <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0) |
{ |
periodBegin = i-1; |
màquina_estat = 2; |
numOfCycles = 1; |
samplesPerPeriod = (períodeBegin - 0); |
període = samplesPerPeriod; |
ajustador = TUNER + (50,04 * exp (-0,102 * samplesPerPeriod)); |
signalFrequency = ((SAMPLING_FREQUENCY) / (samplesPerPeriod)) - ajustador; // f = fs / N |
} |
altrament si (state_machine == 2 && i> 0 && batre 0) // state_machine = 2, trobeu 2 períodes per al 1r i 2n cicle |
{ |
Valor màxim = autoCorr ; |
} |
else if (state_machine == 2 && i> 0 && batre <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0) |
{ |
periodEnd = i-1; |
màquina_estat = 3; |
numOfCycles = 2; |
samplesPerPeriod = (periodEnd - 0); |
signalFrequency2 = ((numOfCycles * SAMPLING_FREQUENCY) / (samplesPerPeriod)) - ajustador; // f = (2 * fs) / (2 * N) |
Valor màxim = 0; |
} |
altrament si (state_machine == 3 && i> 0 && batre 0) // state_machine = 3, trobeu 3 períodes per al 1r, 2n i 3r cicle |
{ |
Valor màxim = autoCorr ; |
} |
else if (màquina_estat == 3 && i> 0 && batre <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0) |
{ |
periodEnd = i-1; |
màquina_estat = 4; |
numOfCycles = 3; |
samplesPerPeriod = (PeriodEnd - 0); |
signalFrequency3 = ((numOfCycles * SAMPLING_FREQUENCY) / (samplesPerPeriod)) - ajustador; // f = (3 * fs) / (3 * N) |
} |
} |
//***************************************************************** |
// Anàlisi de resultats |
//***************************************************************** |
if (samplesPerPeriod == 0) |
{ |
Serial.println ("Hmm ….. No estic segur. Esteu intentant enganyar-me?"); |
} |
en cas contrari |
{ |
// prepara la funció de ponderació |
total = 0; |
if (freqüència del senyal! = 0) |
{ |
total = 1; |
} |
if (freqüència del senyal2! = 0) |
{ |
total = total + 2; |
} |
if (signalFrequency3! = 0) |
{ |
total = total + 3; |
} |
// calcular la freqüència mitjançant la funció de ponderació |
signalFrequencyGuess = ((1 / total) * signalFrequency) + ((2 / total) * signalFrequency2) + ((3 / total) * signalFrequency3); // trobar una freqüència ponderada |
Serial.print ("La nota que heu interpretat és aproximadament"); |
Serial.print (signalFrequencyGuess); // Imprimiu la suposició de freqüència. |
Serial.println ("Hz."); |
// trobar el rang d'octava basat en la suposició |
rang d’octava = 3; |
while (! (signalFrequencyGuess> = storageNoteFreq [0] -7 && signalFrequencyGuess <= storedNoteFreq [11] +7)) |
{ |
per a (i = 0; i <12; i ++) |
{ |
storageNoteFreq = 2 * storageNoteFreq ; |
} |
octaveRange ++; |
} |
// Cerqueu la nota més propera |
Valor mínim = 10000000; |
notaLocalització = 0; |
per a (i = 0; i <12; i ++) |
{ |
if (MinValue> abs (signalFrequencyGuess-storedNoteFreq ))) |
{ |
MinValue = abs (signalFrequencyGuess-storedNoteFreq ); |
notaLocalització = i; |
} |
} |
// Imprimeix la nota |
Serial.print ("Crec que has jugat"); |
if (noteLocation == 0) |
{ |
Serial.print ("C"); |
} |
else if (noteLocation == 1) |
{ |
Serial.print ("C #"); |
} |
else if (noteLocation == 2) |
{ |
Serial.print ("D"); |
} |
else if (noteLocation == 3) |
{ |
Serial.print ("D #"); |
} |
else if (noteLocation == 4) |
{ |
Serial.print ("E"); |
} |
else if (noteLocation == 5) |
{ |
Serial.print ("F"); |
} |
else if (noteLocation == 6) |
{ |
Serial.print ("F #"); |
} |
else if (noteLocation == 7) |
{ |
Serial.print ("G"); |
} |
else if (noteLocation == 8) |
{ |
Serial.print ("G #"); |
} |
else if (noteLocation == 9) |
{ |
Serial.print ("A"); |
} |
else if (noteLocation == 10) |
{ |
Serial.print ("A #"); |
} |
else if (noteLocation == 11) |
{ |
Serial.print ("B"); |
} |
Serial.println (octaveRange); |
} |
//***************************************************************** |
//Atura't aquí. Feu clic al botó de reinici d'Arduino per reiniciar-lo |
//***************************************************************** |
mentre que (1); |
} |
visualitza rawgistfile1.txt allotjat amb ❤ per GitHub
Pas 3: configureu el detector de notes musicals
Connecteu l'Arduino Uno al PC amb el codi escrit o carregat a l'IDE Arduino. Compileu i pengeu el codi a Arduino. Col·loqueu el circuit a prop de la font de música. Nota: Al vídeo de presentació, faig servir una aplicació instal·lada a la tauleta juntament amb altaveus de PC com a font de música. Feu clic al botó de restabliment de la placa Arduino i, a continuació, reproduïu una nota a la font de música. Al cap d’uns segons, el Detector de notes musicals mostrarà la nota reproduïda i la seva freqüència.