Muzieknootdetector: 3 stappen
Muzieknootdetector: 3 stappen
Anonim
Image
Image

Verbaas je vrienden en familie met dit project dat de door een instrument gespeelde noot detecteert. Dit project zal de geschatte frequentie weergeven, evenals de muzieknoot die wordt gespeeld op een elektronisch toetsenbord, piano-app of een ander instrument.

Details

Voor dit project wordt de analoge uitgang van de geluidsmodule-detector naar de A0 analoge ingang van de Arduino Uno gestuurd. Het analoge signaal wordt gesampled en gekwantiseerd (gedigitaliseerd). Autocorrelatie, weging en afstemmingscode wordt gebruikt om de grondfrequentie te vinden met behulp van de eerste 3 perioden. De geschatte grondfrequentie wordt vervolgens vergeleken met frequenties in het bereik van de octaven 3, 4 en 5 om de dichtstbijzijnde muzieknootfrequentie te bepalen. Ten slotte wordt de geraden noot voor de dichtstbijzijnde frequentie op het scherm afgedrukt.

Opmerking: deze instructable richt zich alleen op het bouwen van het project. Ga voor meer informatie over de details en ontwerprechtvaardigingen naar deze link: Meer informatie

Benodigdheden

  • (1) Arduino Uno (of Genuino Uno)
  • (1) DEVMO-microfoonsensor Compatibel met geluidsdetectiemodule met hoge gevoeligheid
  • (1) Soldeerloze Breadboard
  • (1) USB-A naar B-kabel
  • Doorverbindingsdraden
  • Muzikale bron (piano, keyboard of paino app met speakers)
  • (1) Computer of laptop

Stap 1: Construeer de hardware voor de muzieknootdetector

Stel de muzieknootdetector in
Stel de muzieknootdetector in

Gebruik een Arduino Uno, verbindingsdraden, een soldeerloze breadboard en een DEVMO-microfoonsensor High Sensitivity Sound Detection Module (of vergelijkbaar) om het circuit te bouwen dat in deze afbeelding wordt getoond

Stap 2: Programmeer de muzieknootdetector

Voeg in de Arduino IDE de volgende code toe.

gistfile1.txt

/*
Bestands-/schetsnaam: MusicalNoteDetector
Versie nr.: v1.0 Gemaakt op 7 juni 2020
Oorspronkelijke auteur: Clyde A. Lettsome, PhD, PE, MEM
Beschrijving: deze code/schets geeft de frequentie bij benadering weer, evenals de muzieknoot die wordt gespeeld op een elektronisch toetsenbord of piano-app. Voor dit project is de analoge uitgang van de
geluidsmodule detector wordt verzonden naar de A0 analoge ingang van de Arduino Uno. Het analoge signaal wordt gesampled en gekwantiseerd (gedigitaliseerd). Autocorrelatie, weging en afstemmingscode wordt gebruikt om:
vind de grondfrequentie met behulp van de eerste 3 perioden. De geschatte grondfrequentie wordt vervolgens vergeleken met frequenties in het bereik van octaven 3, 4 en 5 om de dichtstbijzijnde musical te bepalen
noot frequentie. Ten slotte wordt de geraden noot voor de dichtstbijzijnde frequentie op het scherm afgedrukt.
Licentie: Dit programma is gratis software; u kunt het opnieuw distribueren en/of wijzigen onder de voorwaarden van de GNU General Public License (GPL) versie 3, of een latere
versie van uw keuze, zoals gepubliceerd door de Free Software Foundation.
Opmerkingen: Copyright (c) 2020 door C. A. Lettsome Services, LLC
Ga voor meer informatie naar
*/
#define MONSTERS 128 //Max 128 voor Arduino Uno.
#define SAMPLING_FREQUENCY 2048 //Fs = Gebaseerd op Nyquist, moet 2 keer de hoogst verwachte frequentie zijn.
#define OFFSETSAMPLES 40 //gebruikt voor kalibratiedoeleinden
#define TUNER -3 //Aanpassen tot C3 130.50. is
float bemonsteringPeriode;
niet-ondertekende lange microSeconden;
int X[VOORBEELDEN]; // maak een vector met de grootte SAMPLES om echte waarden vast te houden
float autoCorr[VOORBEELDEN]; // maak een vector met de grootte SAMPLES om denkbeeldige waarden vast te houden
float opgeslagenNoteFreq [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]; // maak offset vector
int avgOffSet; // maak offset vector
int i, k, periodEnd, periodBegin, period, adjuster, noteLocation, octaveRange;
float maxValue, minValue;
lange som;
int drempel = 0;
int aantalCycles = 0;
float signaalFrequentie, signaalFrequentie2, signaalFrequentie3, signaalFrequentieGuess, totaal;
byte state_machine = 0;
int samplesPerPeriode = 0;
ongeldige setup()
{
Serieel.begin(115200); //115200 Baudrate voor de seriële monitor
}
lege lus()
{
//*****************************************************************
// Kalibratie Sectie
//*****************************************************************
Serial.println("Kalaberen. Speel geen noten tijdens het kalibreren.");
voor (i = 0; i < OFFSETSAMPLES; i++)
{
offSet = analoogRead(0); // Leest de waarde van analoge pin 0 (A0), kwantiseert deze en slaat deze op als een echte term.
//Serial.println(offSet); // gebruik dit om de geluidsdetectiemodule in te stellen op ongeveer de helft of 512 als er geen geluid wordt afgespeeld.
sumOffSet = sumOffSet + offSet;
}
samplesPerPeriode = 0;
maxWaarde = 0;
//*****************************************************************
// Bereid je voor om invoer van A0. te accepteren
//*****************************************************************
avgOffSet = round(sumOffSet / OFFSETSAMPLES);
Serial.println("Aftellen.");
vertraging (1000); // pauze voor 1 seconden
Serieel.println("3");
vertraging (1000); // pauze voor 1 seconden
Serieel.println("2");
vertraging (1000); // pauze voor 1
Serieel.println("1");
vertraging (1000); // pauze voor 1 seconden
Serial.println("Speel je notitie af!");
vertraging (250); // pauzeer 1/4 seconde voor reactietijd
//*****************************************************************
// Verzamel SAMPLES-samples van A0 met sampleperiode van samplingPeriod
//*****************************************************************
samplingPeriod = 1.0 / SAMPLING_FREQUENCY; //Periode in microseconden
voor (i = 0; i < MONSTERS; i++)
{
microSeconden = micros(); // Geeft het aantal microseconden terug sinds het Arduino-bord het huidige script begon uit te voeren.
X = analoog lezen(0); // Leest de waarde van analoge pin 0 (A0), kwantiseert deze en slaat deze op als een echte term.
/* resterende wachttijd tussen samples indien nodig in seconden */
while (micros() < (microSeconden + (samplingPeriod * 1000000)))
{
//niets doen, gewoon wachten
}
}
//*****************************************************************
// Autocorrelatiefunctie
//*****************************************************************
voor (i = 0; i < MONSTERS; i++) //i=vertraging
{
som = 0;
for (k = 0; k <SAMPLES - i; k++) // Match signaal met vertraagd signaal
{
som = som + (((X[k]) - avgOffSet) * ((X[k + i]) - avgOffSet)); //X[k] is het signaal en X[k+i] is de vertraagde versie
}
autoCorr = som / MONSTERS;
// First Peak Detect State Machine
if (state_machine==0 && i == 0)
{
thresh = autoCorr * 0,5;
staat_machine = 1;
}
else if (state_machine == 1 && i>0 && thresh 0) //state_machine=1, zoek 1 periode voor het gebruik van de eerste cyclus
{
maxValue = autoCorr;
}
else if (state_machine == 1&& i>0 && thresh < autoCorr[i-1] && maxValue == autoCorr[i-1] && (autoCorr-autoCorr[i-1])<=0)
{
periodeBegin = i-1;
staat_machine = 2;
aantalCycles = 1;
samplesPerPeriod = (periodeBegin - 0);
periode = samplesPerPeriode;
regelaar = TUNER+(50.04 * exp(-0.102 * samplesPerPeriod));
signalFrequency = ((SAMPLING_FREQUENCY) / (samplesPerPeriod))-regelaar; // f = fs/N
}
else if (state_machine == 2 && i>0 && thresh 0) //state_machine=2, zoek 2 perioden voor de 1e en 2e cyclus
{
maxValue = autoCorr;
}
else if (state_machine == 2&& i>0 && thresh < autoCorr[i-1] && maxValue == autoCorr[i-1] && (autoCorr-autoCorr[i-1])<=0)
{
periodeEnd = i-1;
staat_machine = 3;
aantalCycles = 2;
samplesPerPeriod = (periodEnd - 0);
signalFrequency2 = ((numOfCycles*SAMPLING_FREQUENCY) / (samplesPerPeriod))-aanpasser; // f = (2*fs)/(2*N)
maxWaarde = 0;
}
else if (state_machine == 3 && i>0 && thresh 0) //state_machine=3, zoek 3 perioden voor de 1e, 2e en 3e cyclus
{
maxValue = autoCorr;
}
else if (state_machine == 3&& i>0 && thresh < autoCorr[i-1] && maxValue == autoCorr[i-1] && (autoCorr-autoCorr[i-1])<=0)
{
periodeEnd = i-1;
staat_machine = 4;
aantalCycles = 3;
samplesPerPeriod = (periodEnd - 0);
signalFrequency3 = ((numOfCycles*SAMPLING_FREQUENCY) / (samplesPerPeriod))-aanpasser; // f = (3*fs)/(3*N)
}
}
//*****************************************************************
//Resultaatanalyse
//*****************************************************************
if (steekproevenPerPeriode == 0)
{
Serial.println("Hmm… ik weet het niet zeker. Probeer je me te misleiden?");
}
anders
{
// bereid de weegfunctie voor
totaal = 0;
if (signaalfrequentie !=0)
{
totaal = 1;
}
if (signaalfrequentie2 !=0)
{
totaal = totaal + 2;
}
if (signaalfrequentie3 !=0)
{
totaal = totaal + 3;
}
// bereken de frequentie met behulp van de weegfunctie
signaalfrequentieGuess = ((1/totaal) * signaalfrequentie) + ((2/totaal) * signaalfrequentie2) + ((3/totaal) * signaalfrequentie3); // zoek een gewogen frequentie
Serial.print("De noot die je speelde is ongeveer ");
Serial.print(signaalFrequencyGuess); // Druk de schatting van de frequentie af.
Serial.println ("Hz.");
// vind octaafbereik op basis van de gok
octaafBereik=3;
while (!(signalFrequencyGuess >= opgeslagenNoteFreq[0]-7 && signalFrequencyGuess <= opgeslagenNoteFreq[11]+7))
{
voor(i = 0; ik < 12; i++)
{
opgeslagenNoteFreq = 2 * opgeslagenNoteFreq;
}
octaveRange++;
}
// Vind de dichtstbijzijnde notitie
minWaarde = 10000000;
opmerkingLocatie = 0;
voor (i = 0; ik < 12; i++)
{
if(minValue> abs(signalFrequencyGuess-storedNoteFreq))
{
minValue = abs(signaalFrequencyGuess-storedNoteFreq);
opmerkingLocatie = ik;
}
}
// Druk de notitie af
Serial.print("Ik denk dat je gespeeld hebt ");
if(noteLocation==0)
{
Serial.print("C");
}
anders if(noteLocation==1)
{
Serieel.print("C#");
}
anders if(noteLocation==2)
{
Serial.print("D");
}
anders if(noteLocation==3)
{
Serieel.print("D#");
}
anders if(noteLocation==4)
{
Serial.print("E");
}
anders if(noteLocation==5)
{
Serieel.print("F");
}
anders if(noteLocation==6)
{
Serieel.print("F#");
}
anders if(noteLocation==7)
{
Serial.print("G");
}
anders if(noteLocation==8)
{
Serial.print("G#");
}
anders if(noteLocation==9)
{
Serial.print("A");
}
anders if(noteLocation==10)
{
Serial.print("A#");
}
anders if(noteLocation==11)
{
Serial.print("B");
}
Serial.println(octaafbereik);
}
//*****************************************************************
//Stop hier. Druk op de reset-knop op Arduino om opnieuw op te starten
//*****************************************************************
terwijl (1);
}

bekijk rawgistfile1.txt gehost met ❤ door GitHub

Stap 3: Stel de muzieknootdetector in

Verbind de Arduino Uno met de pc met de code geschreven of geladen in de Arduino IDE. Compileer en upload de code naar de Arduino. Plaats het circuit dicht bij de muziekbron. Opmerking: in de introductievideo gebruik ik een app die op een tablet is geïnstalleerd in combinatie met pc-luidsprekers als mijn muziekbron. Druk op de resetknop op het Arduino-bord en speel vervolgens een notitie op de muziekbron. Na een paar seconden geeft de muzieknootdetector de gespeelde noot en de frequentie ervan weer.