Sisällysluettelo:
2025 Kirjoittaja: John Day | [email protected]. Viimeksi muokattu: 2025-01-13 06:57
Yllätä ystäväsi ja perheesi tällä projektilla, joka havaitsee instrumentin soittaman nuotin. Tämä projekti näyttää likimääräisen taajuuden sekä nuotin, joka soitetaan elektronisella näppäimistöllä, pianosovelluksella tai muulla instrumentilla.
Yksityiskohdat
Tässä projektissa äänimoduulin ilmaisimen analoginen lähtö lähetetään Arduino Unon A0 -analogituloon. Analoginen signaali näytteistetään ja kvantisoidaan (digitoidaan). Autokorrelaatiota, painotusta ja virityskoodia käytetään perustaajuuden löytämiseen kolmen ensimmäisen jakson avulla. Likimääräistä perustaajuutta verrataan sitten oktaavien 3, 4 ja 5 taajuuksiin lähimmän nuotin taajuuden määrittämiseksi. Lopuksi lähimmälle taajuudelle arvattu muistiinpano tulostetaan näytölle.
Huomautus: Tässä ohjeessa keskitytään vain projektin rakentamiseen. Lisätietoja yksityiskohdista ja suunnittelun perusteluista löydät tästä linkistä: Lisätietoja
Tarvikkeet
- (1) Arduino Uno (tai Genuino Uno)
- (1) Yhteensopiva DEVMO -mikrofonianturin korkean herkkyyden äänentunnistusmoduulin kanssa
- (1) Juotamaton leipälevy
- (1) USB-A-B-kaapeli
- Hyppyjohdot
- Musiikkilähde (piano, näppäimistö tai paino -sovellus kaiuttimilla)
- (1) Tietokone tai kannettava tietokone
Vaihe 1: Rakenna nuotinilmaisimen laitteisto
Käytä Arduino Unoa, liitäntäjohtoja, juotonta leipälevyä ja DEVMO -mikrofonianturin korkean herkkyyden äänentunnistusmoduulia (tai vastaavaa) muodostamaan tässä kuvassa näkyvä piiri
Vaihe 2: Ohjelmoi nuotinilmaisin
Lisää seuraava koodi Arduino IDE: hen.
gistfile1.txt
/* |
Tiedoston/luonnoksen nimi: MusicalNoteDetector |
Versio nro: v1.0 Luotu 7. kesäkuuta 2020 |
Alkuperäinen kirjoittaja: Clyde A. Lettsome, tohtori, PE, MEM |
Kuvaus: Tämä koodi/luonnos näyttää likimääräisen taajuuden sekä nuotin, joka soitetaan elektronisella näppäimistöllä tai pianosovelluksella. Tässä projektissa analoginen lähtö |
äänimoduulin ilmaisin lähetetään Arduino Unon A0 -analogituloon. Analoginen signaali näytteistetään ja kvantisoidaan (digitoidaan). Autokorrelaatiota, painotusta ja virityskoodia käytetään |
löytää perustaajuus käyttämällä kolmea ensimmäistä jaksoa. Arvioitua perustaajuutta verrataan sitten oktaavien 3, 4 ja 5 taajuuksiin lähimmän musikaalin määrittämiseksi |
muistiinpanotaajuus. Lopuksi lähimmälle taajuudelle arvattu muistiinpano tulostetaan näytölle. |
Lisenssi: Tämä ohjelma on ilmainen ohjelmisto; voit jakaa sen uudelleen ja/tai muokata sitä GNU General Public License (GPL) -version 3 ehtojen mukaisesti tai myöhemmin |
valitsemasi version Free Software Foundationin julkaisemana. |
Huomautuksia: Tekijänoikeus (c) 2020, C. A. Lettsome Services, LLC |
Lisätietoja on osoitteessa |
*/ |
#define SAMPLES 128 // Enintään 128 Arduino Unolle. |
#define SAMPLING_FREQUENCY 2048 // Fs = Nyquistin perusteella sen on oltava kaksi kertaa korkein odotettu taajuus. |
#define OFFSETSAMPLES 40 // käytetään kalablaatiotarkoituksiin |
#define TUNER -3 // Säädä kunnes C3 on 130,50 |
kelluva näytteenottoAika; |
allekirjoittamattomat pitkät mikrosekunnit; |
int X [NÄYTTEET]; // Luo SAMPLES -kokoinen vektori todellisten arvojen säilyttämiseksi |
kelluva autoCorr [NÄYTTEET]; // luo vektori, jonka koko on SAMPLES pitämään kuvitteellisia arvoja |
float storageNoteFreq [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]; // luoda offset -vektori |
int avgOffSet; // luoda offset -vektori |
int i, k, periodEnd, periodBegin, period, Adjuster, noteLocation, oktaavialue; |
float maxValue, minValue; |
pitkä summa; |
int thresh = 0; |
int numOfCycles = 0; |
float signalFrequency, signalFrequency2, signalFrequency3, signalFrequencyGuess, yhteensä; |
tavu tila_kone = 0; |
int näytteetPerPeriod = 0; |
mitätön asennus () |
{ |
Sarja.alku (115200); // 115200 Sarjamonitorin siirtonopeus |
} |
tyhjä silmukka () |
{ |
//***************************************************************** |
// Calabration -osio |
//***************************************************************** |
Serial.println ("Calabrating. Älä toista mitään nuotteja calabration aikana."); |
for (i = 0; i <OFFSETSAMPLES; i ++) |
{ |
offSet = analoginen (0); // Lukee arvon analogisesta nastasta 0 (A0), kvantisoi sen ja tallentaa sen todellisena terminä. |
//Sarja.println(offSet); // käytä tätä säätääksesi äänentunnistusmoduulin noin puoleen tai 512, kun ääntä ei toisteta. |
sumOffSet = sumOffSet + offSet ; |
} |
samplePerPeriod = 0; |
maxValue = 0; |
//***************************************************************** |
// Valmistaudu syötteen vastaanottamiseen A0: sta |
//***************************************************************** |
avgOffSet = pyöreä (sumOffSet / OFFSETSAMPLES); |
Serial.println ("Laskenta alas."); |
viive (1000); // keskeytä 1 sekunti |
Serial.println ("3"); |
viive (1000); // keskeytä 1 sekunti |
Serial.println ("2"); |
viive (1000); // tauko 1 |
Serial.println ("1"); |
viive (1000); // keskeytä 1 sekunti |
Serial.println ("Toista muistiinpanosi!"); |
viive (250); // tauko 1/4 sekunniksi reaktioaikaksi |
//***************************************************************** |
// Kerää näytteitä näytteestä A0 näytteenottoajanjakson aikana |
//***************************************************************** |
samplingPeriod = 1.0 / SAMPLING_FREQUENCY; // Jakso mikrosekunneissa |
(i = 0; i <NÄYTTEET; i ++) |
{ |
mikrosekunnit = mikros (); // Palauttaa mikrosekuntien määrän siitä lähtien, kun Arduino -kortti aloitti nykyisen komentosarjan suorittamisen. |
X = analoginen (0); // Lukee arvon analogisesta nastasta 0 (A0), kvantisoi sen ja tallentaa sen todellisena terminä. |
/ *jäljellä oleva odotusaika näytteiden välillä tarvittaessa sekunneissa */ |
kun taas (micros () <(microSeconds + (samplingPeriod * 1000000))) |
{ |
// älä tee mitään vain odota |
} |
} |
//***************************************************************** |
// Automaattinen korrelaatiotoiminto |
//***************************************************************** |
for (i = 0; i <SAMPLES; i ++) // i = viive |
{ |
summa = 0; |
for (k = 0; k <SAMPLES - i; k ++) // Sovita signaali viivästetyn signaalin kanssa |
{ |
summa = summa + ((((X [k]) - avgOffSet) * ((X [k + i]) - avgOffSet)); // X [k] on signaali ja X [k+i] on viivästetty versio |
} |
autoCorr = summa / NÄYTTEET; |
// Ensimmäinen huipputunnistustilakone |
jos (tila_kone == 0 && i == 0) |
{ |
heitto = autoCorr * 0,5; |
tila_kone = 1; |
} |
else if (state_machine == 1 && i> 0 && thresh 0) // state_machine = 1, etsi 1 jakso ensimmäisen syklin käyttämistä varten |
{ |
maxValue = autoCorr ; |
} |
muuten jos (tila_kone == 1 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0) |
{ |
periodBegin = i-1; |
tila_kone = 2; |
numOfCycles = 1; |
samplePerPeriod = (periodBegin - 0); |
aika = näytteetPerPeriod; |
säädin = TUNER+(50,04 * exp (-0,102 * samplePerPeriod)); |
signalFrequency = ((SAMPLING_FREQUENCY) / (samplePerPeriod))-säädin; // f = fs/N |
} |
else if (state_machine == 2 && i> 0 && thresh 0) // state_machine = 2, etsi 2 jaksoa ensimmäiselle ja toiselle jaksolle |
{ |
maxValue = autoCorr ; |
} |
muuten jos (tila_kone == 2 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0) |
{ |
periodEnd = i-1; |
tila_kone = 3; |
numOfCycles = 2; |
samplePerPeriod = (periodEnd - 0); |
signalFrequency2 = (((numOfCycles*SAMPLING_FREQUENCY) / (samplePerPeriod))-säädin; // f = (2*fs)/(2*N) |
maxValue = 0; |
} |
else if (state_machine == 3 && i> 0 && thresh 0) // state_machine = 3, etsi 3 jaksoa 1., 2. ja 3. syklille |
{ |
maks.arvo = autoCorr ; |
} |
muuten jos (tila_kone == 3 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0) |
{ |
periodEnd = i-1; |
tila_kone = 4; |
numOfCycles = 3; |
samplePerPeriod = (periodEnd - 0); |
signalFrequency3 = (((numOfCycles*SAMPLING_FREQUENCY) / (samplePerPeriod))-säädin; // f = (3*fs)/(3*N) |
} |
} |
//***************************************************************** |
// Tulosanalyysi |
//***************************************************************** |
jos (samplePerPeriod == 0) |
{ |
Serial.println ("Hmm….. en ole varma. Yritätkö huijata minua?"); |
} |
muu |
{ |
// valmistele painotus |
yhteensä = 0; |
jos (signalFrequency! = 0) |
{ |
yhteensä = 1; |
} |
jos (signalFrequency2! = 0) |
{ |
yhteensä = yhteensä + 2; |
} |
jos (signalFrequency3! = 0) |
{ |
yhteensä = yhteensä + 3; |
} |
// laske taajuus painotusfunktion avulla |
signalFrequencyGuess = ((1/yhteensä) * signalFrequency) + ((2/total) * signalFrequency2) + ((3/total) * signalFrequency3); // löytää painotettu taajuus |
Serial.print ("Soittamasi nuotti on suunnilleen"); |
Serial.print (signalFrequencyGuess); // Tulosta taajuusarvaus. |
Sarja.println ("Hz"); |
// löytää oktaavialueen arvauksen perusteella |
oktaavialue = 3; |
kun taas (! (signalFrequencyGuess> = tallennettuNoteFreq [0] -7 && signalFrequencyGuess <= tallennettuNoteFreq [11] +7)) |
{ |
(i = 0; i <12; i ++) |
{ |
storageNoteFreq = 2 * tallennettuNoteFreq ; |
} |
oktaavialue ++; |
} |
// Etsi lähin nuotti |
minValue = 10000000; |
noteLocation = 0; |
(i = 0; i <12; i ++) |
{ |
if (minValue> abs (signalFrequencyGuess-storageNoteFreq )) |
{ |
minValue = abs (signalFrequencyGuess-storageNoteFreq ); |
noteLocation = i; |
} |
} |
// Tulosta muistiinpano |
Serial.print ("Luulen, että pelasit"); |
jos (noteLocation == 0) |
{ |
Serial.print ("C"); |
} |
muuten jos (noteLocation == 1) |
{ |
Serial.print ("C#"); |
} |
muuten jos (noteLocation == 2) |
{ |
Serial.print ("D"); |
} |
muuten jos (noteLocation == 3) |
{ |
Serial.print ("D#"); |
} |
muuten jos (noteLocation == 4) |
{ |
Serial.print ("E"); |
} |
muuten jos (noteLocation == 5) |
{ |
Serial.print ("F"); |
} |
muuten jos (noteLocation == 6) |
{ |
Serial.print ("F#"); |
} |
muuten jos (noteLocation == 7) |
{ |
Serial.print ("G"); |
} |
muuten jos (noteLocation == 8) |
{ |
Serial.print ("G#"); |
} |
muuten jos (noteLocation == 9) |
{ |
Serial.print ("A"); |
} |
muuten jos (noteLocation == 10) |
{ |
Serial.print ("A#"); |
} |
muuten jos (noteLocation == 11) |
{ |
Serial.print ("B"); |
} |
Sarja.println (oktaavialue); |
} |
//***************************************************************** |
//Pysähdy tähän. Käynnistä uudelleen painamalla Arduinon nollauspainiketta |
//***************************************************************** |
kun taas (1); |
} |
katso rawgistfile1.txt, jota isännöi GitHub
Vaihe 3: Asenna nuotinilmaisin
Liitä Arduino Uno tietokoneeseen koodilla, joka on kirjoitettu tai ladattu Arduino IDE: hen. Kokoa ja lähetä koodi Arduinolle. Aseta piiri lähelle musiikkilähdettä. Huomautus: Esittelyvideossa käytän musiikkilähteenä sovellusta, joka on asennettu tablettiin PC -kaiuttimien kanssa. Paina Arduino Boardin nollauspainiketta ja toista sitten nuotti musiikkilähteestä. Muutaman sekunnin kuluttua nuotti -ilmaisin näyttää soitetun nuotin ja sen taajuuden.