Πίνακας περιεχομένων:
2025 Συγγραφέας: John Day | [email protected]. Τελευταία τροποποίηση: 2025-01-13 06:57
Καταπλήξτε τους φίλους και την οικογένειά σας με αυτό το έργο που ανιχνεύει τη νότα που παίζει ένα όργανο. Αυτό το έργο θα εμφανίσει την κατά προσέγγιση συχνότητα καθώς και τη μουσική νότα που παίζεται σε ηλεκτρονικό πληκτρολόγιο, εφαρμογή πιάνου ή οποιοδήποτε άλλο όργανο.
Λεπτομέριες
Για αυτό το έργο, η αναλογική έξοδος από τον ανιχνευτή μονάδας ήχου αποστέλλεται στην αναλογική είσοδο Α0 του Arduino Uno. Το αναλογικό σήμα λαμβάνεται δείγμα και κβαντίζεται (ψηφιοποιείται). Ο κωδικός αυτόματης συσχέτισης, στάθμισης και συντονισμού χρησιμοποιείται για τον εντοπισμό της θεμελιώδους συχνότητας χρησιμοποιώντας τις 3 πρώτες περιόδους. Στη συνέχεια, η κατά προσέγγιση θεμελιώδης συχνότητα συγκρίνεται με τις συχνότητες στο εύρος οκτάβων 3, 4 και 5 για να προσδιοριστεί η πλησιέστερη συχνότητα μουσικής νότας. Τέλος, η υποτιθέμενη σημείωση για την πλησιέστερη συχνότητα εκτυπώνεται στην οθόνη.
Σημείωση: Αυτό το εκπαιδευτικό πρόγραμμα εστιάζει μόνο στον τρόπο κατασκευής του έργου. Για περισσότερες πληροφορίες σχετικά με τις λεπτομέρειες και τις δικαιολογίες σχεδιασμού, επισκεφθείτε αυτόν τον σύνδεσμο: Περισσότερες πληροφορίες
Προμήθειες
- (1) Arduino Uno (ή Genuino Uno)
- (1) Μονάδα ανίχνευσης ήχου υψηλής ευαισθησίας DEVMO Microphone Sensor Συμβατή
- (1) Χωρίς συγκόλληση Breadboard
- (1) Καλώδιο USB-A έως B
- Καλώδια βραχυκυκλωτήρων
- Μουσική πηγή (πιάνο, πληκτρολόγιο ή εφαρμογή Paino με ηχεία)
- (1) Υπολογιστής ή φορητός υπολογιστής
Βήμα 1: Κατασκευάστε το υλικό για τον ανιχνευτή μουσικής σημείωσης
Χρησιμοποιώντας ένα Arduino Uno, τα καλώδια σύνδεσης, μια σανίδα χωρίς κόλληση και μια μονάδα ανίχνευσης ήχου υψηλής ευαισθησίας αισθητήρα μικροφώνου DEVMO (ή παρόμοια) κατασκευάζουν το κύκλωμα που φαίνεται σε αυτήν την εικόνα
Βήμα 2: Προγραμματίστε τον ανιχνευτή μουσικής σημείωσης
Στο Arduino IDE, προσθέστε τον ακόλουθο κώδικα.
gistfile1.txt
/* |
Όνομα αρχείου/σκίτσου: MusicalNoteDetector |
Έκδοση αριθ.: v1.0 Δημιουργήθηκε στις 7 Ιουνίου 2020 |
Πρωτότυπος συγγραφέας: Clyde A. Lettsome, PhD, PE, MEM |
Περιγραφή: Αυτός ο κώδικας/σκίτσο εμφανίζει την κατά προσέγγιση συχνότητα καθώς και τη μουσική νότα που παίζεται σε ηλεκτρονικό πληκτρολόγιο ή εφαρμογή πιάνου. Για αυτό το έργο, η αναλογική έξοδος από το |
ο ανιχνευτής μονάδας ήχου αποστέλλεται στην αναλογική είσοδο A0 του Arduino Uno. Το αναλογικό σήμα λαμβάνεται δείγμα και κβαντίζεται (ψηφιοποιείται). Ο κωδικός αυτοσυσχέτισης, στάθμισης και συντονισμού χρησιμοποιείται για |
βρείτε βασική συχνότητα χρησιμοποιώντας τις 3 πρώτες περιόδους. Η κατά προσέγγιση θεμελιώδης συχνότητα συγκρίνεται στη συνέχεια με τις συχνότητες στο εύρος των οκτάβων 3, 4 και 5 για να προσδιοριστεί το πλησιέστερο μουσικό |
συχνότητα σημειώσεων. Τέλος, η υποτιθέμενη σημείωση για την πλησιέστερη συχνότητα εκτυπώνεται στην οθόνη. |
Άδεια: Αυτό το πρόγραμμα είναι δωρεάν λογισμικό. μπορείτε να το αναδιανείμετε και/ή να το τροποποιήσετε σύμφωνα με τους όρους της έκδοσης 3 της GNU General Public License (GPL) ή κάποια νεότερη έκδοση |
έκδοση της επιλογής σας, όπως δημοσιεύτηκε από το Softwareδρυμα Ελεύθερου Λογισμικού. |
Σημειώσεις: Πνευματικά δικαιώματα (γ) 2020 από την C. A. Lettsome Services, LLC |
Για περισσότερες πληροφορίες επισκεφθείτε τη διεύθυνση |
*/ |
#define SAMPLES 128 // Max 128 για Arduino Uno. |
#define SAMPLING_FREQUENCY 2048 // Fs = Με βάση το Nyquist, πρέπει να είναι 2 φορές η υψηλότερη αναμενόμενη συχνότητα. |
#define OFFSETSAMPLES 40 // που χρησιμοποιούνται για σκοπούς καταστροφής |
#define TUNER -3 // Προσαρμόστε έως ότου το C3 είναι 130,50 |
δειγματοληψία επίπλευσης Περίοδος. |
ανυπόγραφα μεγάλα microSeconds. |
int X [ΔΕΙΓΜΑΤΑ]; // δημιουργία διανύσματος ΔΕΙΓΜΑΤΩΝ μεγέθους για τη διατήρηση πραγματικών τιμών |
float autoCorr [ΔΕΙΓΜΑΤΑ]; // δημιουργία διανύσματος μεγέθους ΔΕΙΓΜΑΤΑ για να κρατήσει φανταστικές τιμές |
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]; // δημιουργία διανύσματος μετατόπισης |
int avgOffSet; // δημιουργία διανύσματος μετατόπισης |
int i, k, periodEnd, periodBegin, period, ρυθμιστής, noteLocation, octaveRange; |
float maxValue, minValue? |
μεγάλο ποσό? |
int thresh = 0; |
int numOfCycles = 0; |
float signalFrequence, signalFrequency2, signalFrequency3, signalFrequencyGuess, total? |
byte state_machine = 0; |
int δείγματαPerPeriod = 0; |
void setup () |
{ |
Serial.begin (115200); // 115200 Ποσοστό Baud για το Serial Monitor |
} |
κενός βρόχος () |
{ |
//***************************************************************** |
// Ενότητα Καλαμπράρισμα |
//***************************************************************** |
Serial.println ("Calabrating. Please not play any notes during calabration."); |
για (i = 0; i <OFFSETSAMPLES; i ++) |
{ |
offSet = analogRead (0); // Διαβάζει την τιμή από την αναλογική ακίδα 0 (A0), την ποσοτικοποιεί και την αποθηκεύει ως πραγματικό όρο. |
//Serial.println(offSet ); // χρησιμοποιήστε αυτό για να ρυθμίσετε τη μονάδα ανίχνευσης ήχου στο μισό περίπου ή 512 όταν δεν αναπαράγεται ήχος. |
sumOffSet = sumOffSet + offSet ; |
} |
samplePerPeriod = 0; |
maxValue = 0; |
//***************************************************************** |
// Προετοιμαστείτε για αποδοχή εισόδου από το A0 |
//***************************************************************** |
avgOffSet = γύρος (sumOffSet / OFFSETSAMPLES); |
Serial.println ("Αντίστροφη μέτρηση."); |
καθυστέρηση (1000)? // παύση για 1 δευτερόλεπτο |
Serial.println ("3"); |
καθυστέρηση (1000)? // παύση για 1 δευτερόλεπτο |
Serial.println ("2"); |
καθυστέρηση (1000)? // παύση για 1 |
Serial.println ("1"); |
καθυστέρηση (1000)? // παύση για 1 δευτερόλεπτο |
Serial.println ("Παίξτε τη σημείωσή σας!"); |
καθυστέρηση (250)? // παύση για 1/4 δευτερόλεπτο για χρόνο αντίδρασης |
//***************************************************************** |
// Συλλέξτε ΔΕΙΓΜΑΤΑ δείγματα από το Α0 με περίοδο δειγματοληψίας περιόδου δειγματοληψίας |
//***************************************************************** |
samplingPeriod = 1.0 / SAMPLING_FREQUENCY; // Περίοδος σε μικροδευτερόλεπτα |
για (i = 0; i <ΔΕΙΓΜΑΤΑ; i ++) |
{ |
microSeconds = micros (); // Επιστρέφει τον αριθμό των δευτερολέπτων από τότε που ο πίνακας Arduino άρχισε να τρέχει το τρέχον σενάριο. |
X = analogRead (0); // Διαβάζει την τιμή από την αναλογική ακίδα 0 (A0), την ποσοτικοποιεί και την αποθηκεύει ως πραγματικό όρο. |
/ *υπολειπόμενος χρόνος αναμονής μεταξύ δειγμάτων εάν είναι απαραίτητο σε δευτερόλεπτα */ |
ενώ (micros () <(microSeconds + (samplingPeriod * 1000000))) |
{ |
// μην κάνεις τίποτα απλά περίμενε |
} |
} |
//***************************************************************** |
// Λειτουργία αυτοσυσχέτισης |
//***************************************************************** |
για (i = 0; i <ΔΕΙΓΜΑΤΑ; i ++) // i = καθυστέρηση |
{ |
άθροισμα = 0; |
για (k = 0; k <ΔΕΙΓΜΑΤΑ - i; k ++) // Αντιστοιχίστε το σήμα με καθυστερημένο σήμα |
{ |
άθροισμα = άθροισμα + (((X [k]) - avgOffSet) * ((X [k + i]) - avgOffSet)); // X [k] είναι το σήμα και X [k+i] είναι η καθυστερημένη έκδοση |
} |
autoCorr = άθροισμα / ΔΕΙΓΜΑΤΑ; |
// First Peak Detect State Machine |
αν (state_machine == 0 && i == 0) |
{ |
thresh = autoCorr * 0,5; |
state_machine = 1; |
} |
αλλιώς εάν (state_machine == 1 && i> 0 && thresh 0) // state_machine = 1, βρείτε 1 περίοδο για τη χρήση του πρώτου κύκλου |
{ |
maxValue = autoCorr ; |
} |
αλλιώς εάν (state_machine == 1 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0) |
{ |
periodBegin = i-1; |
state_machine = 2; |
numOfCycles = 1; |
samplePerPeriod = (periodBegin - 0); |
περίοδος = δείγματαPerPeriod; |
ρυθμιστής = TUNER+(50,04 * exp (-0,102 * samplePerPeriod)); |
signalFrequency = ((SAMPLING_FREQUENCY) / (samplePerPeriod))-ρυθμιστής; // f = fs/N |
} |
αλλιώς αν (state_machine == 2 && i> 0 && thresh 0) // state_machine = 2, βρείτε 2 περιόδους για τον 1ο και 2ο κύκλο |
{ |
maxValue = autoCorr ; |
} |
αλλιώς εάν (state_machine == 2 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0) |
{ |
periodEnd = i-1; |
state_machine = 3; |
numOfCycles = 2; |
samplePerPeriod = (periodEnd - 0); |
signalFrequency2 = ((numOfCycles*SAMPLING_FREQUENCY) / (samplePerPeriod))-ρυθμιστής; // f = (2*fs)/(2*N) |
maxValue = 0; |
} |
αλλιώς εάν (state_machine == 3 && i> 0 && thresh 0) // state_machine = 3, βρείτε 3 περιόδους για τον 1ο, 2ο και 3ο κύκλο |
{ |
maxValue = autoCorr ; |
} |
αλλιώς εάν (state_machine == 3 && i> 0 && thresh <autoCorr [i-1] && maxValue == autoCorr [i-1] && (autoCorr -autoCorr [i-1]) <= 0) |
{ |
periodEnd = i-1; |
state_machine = 4; |
numOfCycles = 3; |
samplePerPeriod = (periodEnd - 0); |
signalFrequency3 = ((numOfCycles*SAMPLING_FREQUENCY) / (samplePerPeriod))-ρυθμιστής; // f = (3*fs)/(3*N) |
} |
} |
//***************************************************************** |
// Ανάλυση αποτελεσμάτων |
//***************************************************************** |
εάν (δείγματαPerPeriod == 0) |
{ |
Serial.println ("Χμμ….. δεν είμαι σίγουρος. Προσπαθείς να με ξεγελάσεις;"); |
} |
αλλού |
{ |
// προετοιμάστε τη συνάρτηση στάθμισης |
σύνολο = 0; |
αν (signalFrequency! = 0) |
{ |
σύνολο = 1; |
} |
εάν (signalFrequency2! = 0) |
{ |
σύνολο = σύνολο + 2; |
} |
εάν (signalFrequency3! = 0) |
{ |
σύνολο = σύνολο + 3; |
} |
// Υπολογίστε τη συχνότητα χρησιμοποιώντας τη συνάρτηση στάθμισης |
signalFrequencyGuess = ((1/σύνολο) * signalFrequency) + ((2/σύνολο) * signalFrequency2) + ((3/σύνολο) * signalFrequency3); // βρείτε μια σταθμισμένη συχνότητα |
Serial.print ("Η νότα που παίξατε είναι περίπου"); |
Serial.print (signalFrequencyGuess); // Εκτυπώστε την εικασία συχνότητας. |
Serial.println ("Hz."); |
// βρείτε εύρος οκτάβας με βάση την εικασία |
octaveRange = 3; |
ενώ (! (signalFrequencyGuess> = storageNoteFreq [0] -7 && signalFrequencyGuess <= αποθηκευμένοςΣημείωσηFreq [11] +7)) |
{ |
για (i = 0; i <12; i ++) |
{ |
storageNoteFreq = 2 * storageNoteFreq ; |
} |
octaveRange ++; |
} |
// Βρείτε την πλησιέστερη σημείωση |
minValue = 10000000; |
noteLocation = 0; |
για (i = 0; i <12; i ++) |
{ |
if (minValue> abs (signalFrequencyGuess-storageNoteFreq )) |
{ |
minValue = abs (signalFrequencyGuess-storageNoteFreq ); |
noteLocation = i; |
} |
} |
// Εκτυπώστε τη σημείωση |
Serial.print ("Νομίζω ότι έπαιξες"); |
εάν (noteLocation == 0) |
{ |
Serial.print ("C"); |
} |
else if (noteLocation == 1) |
{ |
Serial.print ("C#"); |
} |
αλλιώς αν (noteLocation == 2) |
{ |
Serial.print ("D"); |
} |
αλλιώς αν (noteLocation == 3) |
{ |
Serial.print ("D#"); |
} |
αλλιώς αν (noteLocation == 4) |
{ |
Serial.print ("E"); |
} |
αλλιώς αν (noteLocation == 5) |
{ |
Serial.print ("F"); |
} |
αλλιώς αν (noteLocation == 6) |
{ |
Serial.print ("F#"); |
} |
αλλιώς αν (noteLocation == 7) |
{ |
Serial.print ("G"); |
} |
αλλιώς αν (noteLocation == 8) |
{ |
Serial.print ("G#"); |
} |
αλλιώς αν (noteLocation == 9) |
{ |
Serial.print ("A"); |
} |
αλλιώς αν (noteLocation == 10) |
{ |
Serial.print ("A#"); |
} |
αλλιώς αν (noteLocation == 11) |
{ |
Serial.print ("B"); |
} |
Serial.println (octaveRange); |
} |
//***************************************************************** |
//Σταμάτα εδώ. Πατήστε το κουμπί επαναφοράς στο Arduino για επανεκκίνηση |
//***************************************************************** |
ενώ (1)? |
} |
προβολή rawgistfile1.txt που φιλοξενείται με ❤ από το GitHub
Βήμα 3: Ρυθμίστε τον ανιχνευτή μουσικής σημείωσης
Συνδέστε το Arduino Uno στον υπολογιστή με τον κωδικό γραμμένο ή φορτωμένο στο Arduino IDE. Συγκεντρώστε και ανεβάστε τον κώδικα στο Arduino. Τοποθετήστε το κύκλωμα κοντά στην πηγή μουσικής. Σημείωση: Στο εισαγωγικό βίντεο, χρησιμοποιώ μια εφαρμογή εγκατεστημένη στο tablet σε συνδυασμό με ηχεία υπολογιστή ως πηγή μουσικής. Πατήστε το κουμπί επαναφοράς στον πίνακα Arduino και, στη συνέχεια, παίξτε μια σημείωση στην πηγή μουσικής. Μετά από μερικά δευτερόλεπτα, ο ανιχνευτής μουσικής σημείωσης θα εμφανίσει τη νότα που παίχτηκε και τη συχνότητά της.