Përmbajtje:
2025 Autor: John Day | [email protected]. E modifikuara e fundit: 2025-01-13 06:58
Habitni miqtë dhe familjen tuaj me këtë projekt që zbulon notën e luajtur nga një instrument. Ky projekt do të shfaqë frekuencën e përafërt si dhe notën muzikore të luajtur në një tastierë elektronike, aplikacion pianoje ose ndonjë instrument tjetër.
Detajet
Për këtë projekt, dalja analoge nga detektori i modulit të zërit dërgohet në hyrjen analoge A0 të Arduino Uno. Sinjali analog merret mostra dhe kuantizohet (digjitalizohet). Kodi i autokorrelacionit, peshimit dhe akordimit përdoret për të gjetur frekuencën themelore duke përdorur 3 periudhat e para. Frekuenca e përafërt themelore krahasohet më pas me frekuencat në rangun e oktavave 3, 4 dhe 5 për të përcaktuar frekuencën më të afërt të notave muzikore. Më në fund shënimi i supozuar për frekuencën më të afërt shtypet në ekran.
Shënim: Ky udhëzues fokusohet vetëm në mënyrën e ndërtimit të projektit. Për më shumë informacion në lidhje me detajet dhe arsyetimet e projektimit, ju lutemi vizitoni këtë lidhje: Më shumë informacion
Furnizimet
- (1) Arduino Uno (ose Genuino Uno)
- (1) Sensori i mikrofonit DEVMO Moduli i zbulimit të tingullit me ndjeshmëri të lartë i pajtueshëm
- (1) Tabela e bukës pa saldim
- (1) Kabllo USB-A në B
- Telat e kërcyesit
- Burimi muzikor (piano, tastierë ose aplikacion për dhimbje me folës)
- (1) Kompjuter ose laptop
Hapi 1: Ndërtoni pajisjen për detektorin e shënimeve muzikore
Duke përdorur një Arduino Uno, telat e lidhjes, një tabelë pa saldim dhe një modul të zbulimit të tingullit me ndjeshmëri të lartë të sensorit të mikrofonit DEVMO (ose të ngjashme) ndërtoni qarkun e treguar në këtë imazh
Hapi 2: Programoni Detektorin e Shënimeve Muzikore
Në Arduino IDE, shtoni kodin e mëposhtëm.
gistfile1.txt
/* |
Emri i skedarit/skicës: MusicalNoteDetector |
Versioni Nr.: V1.0 Krijuar më 7 qershor, 2020 |
Autori origjinal: Clyde A. Lettsome, PhD, PE, MEM |
Përshkrimi: Ky kod/skicë tregon frekuencën e përafërt si dhe notën muzikore të luajtur në një tastierë elektronike ose aplikacion pianoje. Për këtë projekt, dalja analoge nga |
detektori i modulit të zërit dërgohet në hyrjen analoge A0 të Arduino Uno. Sinjali analog merret mostra dhe kuantizohet (digjitalizohet). Kodi i autokorrelacionit, peshimit dhe akordimit përdoret për |
gjeni frekuencën themelore duke përdorur 3 periudhat e para. Frekuenca e përafërt themelore krahasohet më pas me frekuencat në rangun e oktavave 3, 4 dhe 5 për të përcaktuar muzikën më të afërt |
frekuenca e shënimeve. Më në fund shënimi i supozuar për frekuencën më të afërt shtypet në ekran. |
Licenca: Ky program është softuer falas; mund ta rishpërndani dhe/ose modifikoni sipas kushteve të Licencës së Përgjithshme Publike GNU (GPL) versioni 3, ose ndonjë më vonë |
versioni i zgjedhjes suaj, siç është publikuar nga Fondacioni i Softuerit të Lirë. |
Shënime: E drejta e autorit (c) 2020 nga C. A. Lettsome Services, LLC |
Për më shumë informacion vizitoni |
*/ |
#përcakto SHEMBULL 128 // Maks 128 për Arduino Uno. |
#define SAMPLING_FREQUENCY 2048 // Fs = Bazuar në Nyquist, duhet të jetë 2 herë frekuenca më e lartë e pritshme. |
#përcaktoni OFFSETSAMPLE 40 // të përdorura për qëllime kalabruese |
#define TUNER -3 // Rregulloni derisa C3 të jetë 130.50 |
marrja e mostrave notuesePeriudha; |
mikro sekonda të gjata të panënshkruara; |
int X [Mostrat]; // krijoni vektor me madhësi SHEMBULL për të mbajtur vlera reale |
noton autoCorr [Mostrat]; // krijoni vektor me madhësi SHEMBULL për të mbajtur vlera imagjinare |
nota e ruajturNoteFreq [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]; // krijoni vektor të kompensuar |
int avgOffSet; // krijoni vektor të kompensuar |
int i, k, periodEnd, periodFillim, period, rregullues, shënimLokacioni, oktavaRange; |
float maxValue, minValue; |
shumë e gjatë; |
int thresh = 0; |
int numOfCycles = 0; |
sinjal notuesFrekuenca, sinjalFrekuenca2, sinjalFrekuenca3, sinjalFrekuencaGjestësia, gjithsej; |
byte gjendja_makina = 0; |
mostrat intPerPeriod = 0; |
void setup () |
{ |
Serial.filloj (115200); // 115200 Norma Baud për Monitor Serial |
} |
lak void () |
{ |
//***************************************************************** |
// Seksioni i Calabration |
//***************************************************************** |
Serial.println ("Calabrating. Ju lutemi mos luani asnjë shënim gjatë kalabracionit."); |
për (i = 0; i <OFFSETSAMPLES; i ++) |
{ |
offSet = analogRead (0); // Lexon vlerën nga kunja analoge 0 (A0), e kuantizon dhe e ruan si term real. |
//Serial.println(offSet sharedi]; // përdorni këtë për të rregulluar modulin e zbulimit të zërit në afërsisht gjysmën ose 512 kur nuk luhet zë. |
sumOffSet = sumOffSet + offSet ; |
} |
mostraPerPeriudha = 0; |
maxValue = 0; |
//***************************************************************** |
// Përgatituni për të pranuar të dhëna nga A0 |
//***************************************************************** |
avgOffSet = raund (sumOffSet / OFFSETSAMPLES); |
Serial.println ("Numërimi mbrapsht."); |
vonesa (1000); // pauzë për 1 sekonda |
Serial.println ("3"); |
vonesa (1000); // pauzë për 1 sekonda |
Serial.println ("2"); |
vonesa (1000); // pauzë për 1 |
Serial.println ("1"); |
vonesa (1000); // pauzë për 1 sekonda |
Serial.println ("Luani shënimin tuaj!"); |
vonesë (250); // pauzë për 1/4 sekondë për kohën e reagimit |
//***************************************************************** |
// Mblidhni mostrat e mostrave nga A0 me periudhën e mostrës së periudhës së kampionimit |
//***************************************************************** |
mostërPeriudha = 1.0 / SAMPLING_FREQUENCY; // Periudha në mikrosekonda |
për (i = 0; i <mostrat; i ++) |
{ |
mikro sekonda = mikros (); // Kthen numrin e mikrosekondave që kur bordi Arduino filloi të ekzekutojë skriptin aktual. |
X = analogRead (0); // Lexon vlerën nga kunja analoge 0 (A0), e kuantizon dhe e ruan si term real. |
/ *koha e mbetur e pritjes midis mostrave nëse është e nevojshme në sekonda */ |
ndërsa (micros () <(microSeconds + (samplingPeriod * 1000000))) |
{ |
// mos bëni asgjë vetëm prisni |
} |
} |
//***************************************************************** |
// Funksioni i autokorrelacionit |
//***************************************************************** |
për (i = 0; i <mostrat; i ++) // i = vonesë |
{ |
shuma = 0; |
për (k = 0; k <Mostrat - i; k ++) // Përputhja e sinjalit me sinjalin e vonuar |
{ |
shuma = shuma + ((((X [k]) - avgOffSet) * ((X [k + i]) - avgOffSet)); // X [k] është sinjali dhe X [k+i] është versioni i vonuar |
} |
autoCorr = shuma / SHEMBUJ; |
// Makina e parë e zbulimit të pikut të parë |
nëse (makina_shtetërore == 0 && i == 0) |
{ |
thresh = autoCorr * 0.5; |
makina e gjendjes = 1; |
} |
përndryshe nëse (state_machine == 1 && i> 0 && thresh 0) // state_machine = 1, gjeni 1 periudhë për përdorimin e ciklit të parë |
{ |
maxValue = autoCorr ; |
} |
përndryshe nëse (state_machine == 1 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0) |
{ |
periodBegin = i-1; |
makinë_shtetërore = 2; |
numOfCycles = 1; |
mostraPerPeriudha = (periudhaFillo - 0); |
periudhë = mostraPeriudhë; |
rregullues = TUNER+(50.04 * exp (-0.102 * samplePerPeriod)); |
sinjal Frekuenca = ((SAMPLING_FREQUENCY) / (samplePerPeriod))-rregullues; // f = fs/N |
} |
përndryshe nëse (state_machine == 2 && i> 0 && thresh 0) // state_machine = 2, gjeni 2 periudha për ciklin e parë dhe të dytë |
{ |
maxValue = autoCorr ; |
} |
përndryshe nëse (state_machine == 2 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0) |
{ |
periodEnd = i-1; |
makinë_shtetërore = 3; |
numOfCycles = 2; |
mostraPerPeriudha = (periudha Fundi - 0); |
signalFrequency2 = ((numOfCycles*SAMPLING_FREQUENCY) / (samplePerPeriod))-rregullues; // f = (2*fs)/(2*N) |
maxValue = 0; |
} |
përndryshe nëse (state_machine == 3 && i> 0 && thresh 0) // state_machine = 3, gjeni 3 periudha për ciklin e parë, të dytë dhe të tretë |
{ |
maxValue = autoCorr ; |
} |
përndryshe nëse (state_machine == 3 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0) |
{ |
periodEnd = i-1; |
makinë_shtetërore = 4; |
numOfCycles = 3; |
mostraPerPeriudha = (periudha Fundi - 0); |
signalFrequency3 = ((numOfCycles*SAMPLING_FREQUENCY) / (samplePerPeriod))-rregullues; // f = (3*fs)/(3*N) |
} |
} |
//***************************************************************** |
// Analiza e rezultateve |
//***************************************************************** |
nëse (mostratPerPeriudha == 0) |
{ |
Serial.println ("Hmm….. nuk jam i sigurt. Po përpiqesh të më mashtrosh?"); |
} |
tjeter |
{ |
// përgatit funksionin e peshimit |
gjithsej = 0; |
nëse (sinjal Frekuenca! = 0) |
{ |
gjithsej = 1; |
} |
nëse (sinjal Frekuenca2! = 0) |
{ |
total = total + 2; |
} |
nëse (sinjal Frekuenca3! = 0) |
{ |
total = total + 3; |
} |
// llogarit frekuencën duke përdorur funksionin e peshimit |
signalFrequencyGuess = ((1/total) * sinjal Frekuenca) + ((2/gjithsej) * sinjal Frekuenca2) + ((3/gjithsej) * sinjal Frekuenca3); // gjeni një frekuencë të ponderuar |
Serial.print ("Shënimi që keni luajtur është afërsisht"); |
Serial.print (signalFrequencyGuess); // Shtyp supozimin e frekuencës. |
Serial.println ("Hz."); |
// gjeni gamën e oktavës bazuar në supozimin |
varg oktava = 3; |
ndërsa (! (signalFrequencyGuess> = ruhetNoteFreq [0] -7 && signalFrequencyGuess <= ruhetNoteFreq [11] +7)) |
{ |
për (i = 0; i <12; i ++) |
{ |
ruhetNoteFreq = 2 * ruhetNoteFreq ; |
} |
octaveRange ++; |
} |
// Gjeni shënimin më të afërt |
minVlera = 10000000; |
shënimLokacioni = 0; |
për (i = 0; i <12; i ++) |
{ |
if (minVlera> abs (sinjal FrekuencaGuess-ruhetNoteFreq )) |
{ |
minValue = abs (sinjal FrekuencaGuess-ruajturNoteFreq ); |
shënimLokacioni = i; |
} |
} |
// Shtyp shënimin |
Serial.print ("Unë mendoj se keni luajtur"); |
nëse (shënimLokacioni == 0) |
{ |
Serial.print ("C"); |
} |
tjetër nëse (shënimLokacioni == 1) |
{ |
Serial.print ("C#"); |
} |
tjetër nëse (shënimLokacioni == 2) |
{ |
Serial.print ("D"); |
} |
tjetër nëse (shënimLokacioni == 3) |
{ |
Serial.print ("D#"); |
} |
tjetër nëse (shënimLokacioni == 4) |
{ |
Serial.print ("E"); |
} |
tjetër nëse (shënimLokacioni == 5) |
{ |
Serial.print ("F"); |
} |
tjetër nëse (shënimLokacioni == 6) |
{ |
Serial.print ("F#"); |
} |
tjetër nëse (shënimLokacioni == 7) |
{ |
Serial.print ("G"); |
} |
tjetër nëse (shënimLokacioni == 8) |
{ |
Serial.print ("G#"); |
} |
tjetër nëse (shënimLokacioni == 9) |
{ |
Serial.print ("A"); |
} |
tjetër nëse (shënimLokacioni == 10) |
{ |
Serial.print ("A#"); |
} |
tjetër nëse (shënimLokacioni == 11) |
{ |
Serial.print ("B"); |
} |
Serial.println (varg oktava); |
} |
//***************************************************************** |
//Ndalo ketu. Shtypni butonin e rivendosjes në Arduino për të rinisur |
//***************************************************************** |
ndërsa (1); |
} |
shikoni rawgistfile1.txt të pritur me ❤ nga GitHub
Hapi 3: Konfiguroni detektorin e shënimeve muzikore
Lidhni Arduino Uno me PC me kodin e shkruar ose të ngarkuar në Arduino IDE. Përpiloni dhe ngarkoni kodin në Arduino. Vendoseni qarkun pranë burimit të muzikës. Shënim: Në videon hyrëse, unë përdor një aplikacion të instaluar në tabletë në lidhje me altoparlantët e kompjuterit si burimi im i muzikës. Shtypni butonin e rivendosjes në Bordin Arduino dhe më pas luani një shënim në burimin e muzikës. Pas disa sekondash, Detektori i Shënimeve Muzikore do të shfaqë shënimin e luajtur dhe frekuencën e tij.