Proiectul constă într-un mini sintetizator, capabil să genereze și să înregistreze note muzicale simple.
Funcționalitățile dispozitivului:
Dispozitivul e însoțit de o aplicație pentru calculator, MiniSynth Recorder, cu următoarele funcționalități:
Scopul proiectului este de a oferi utilizatorilor un instrument intuitiv și portabil, pentru compunerea de linii melodice simple. Fișierele MIDI generate pot fi redate direct, sau importate în aplicații specializate, cum ar fi FL Studio, GarageBand sau Logic Pro, pentru editare avansată.
Dispozitivul are 8 butoane pentru note, fiecare produce o notă muzicală atunci când e apăsat. Sunetele sunt redate cu ajutorul buzzer-ului. Potențiometrul poate fi folosit pentru a ajusta frecvența notelor.
Butonul de record pornește/oprește înregistrarea. În timpul înregistrării, Arduino-ul trimite prin Bluetooth informații despre notele apăsate. Comunicarea între Arduino și PC este realizată prin intermediul modulului Bluetooth HC-05.
În modul record, aplicația de pe PC primește mesajele prin Bluetooth. La finalul înregistrării, generează un fișier MIDI și permite redarea și vizualizarea tuturor înregistrărilor.
Dispozitivul are 2 LED-uri care oferă feedback vizual despre starea lui:
Dispozitivul are două moduri de funcționare:
1. Modul normal
În modul normal (implicit), dispozitivul are următoarele funcționalități:
2. Modul record
Modul record este activat prin apăsarea butonului de înregistrare, atunci când dispozitivul e conectat la Bluetooth.
Dacă se apasă butonul de înregistrare fără conexiune Bluetooth, dispozitivul nu activează modul record și LED-ul albastru clipește de două ori pentru semnalizare.
Dacă în timpul înregistrării conexiunea Bluetooth se întrerupe (ex: aplicația este închisă):
Dispozitivul trimite către aplicație 4 tipuri de mesaje, separate prin '\n':
1 <timestamp> <frequency>
- note on (începerea unei note)0 <timestamp> 0
- note off (oprire notă)RECORD_ON
- transmis la activarea modului recordRECORD_OFF
- transmis la dezactivarea modului recordDacă o notă e întreruptă de apăsarea altei note, nu se mai trimite un mesaj “note off” pentru nota anterioară, care ar fi redundant. Aplicația Recorder tratează acest caz și introduce mesajele “note off” necesare.
Nume | Cantitate | Detalii | Link |
---|---|---|---|
Arduino Nano V3 Atmega328P-AU | 1 | compatibil, CH340, USB-C | link |
Modul Bluetooth HC-05 | 1 | compatibil | link |
Modul buzzer pasiv | 1 | cu amplificator integrat (9012) | link |
Modul potențiometru rotativ RV09 | 1 | + capac ergonomic/estetic | link |
Buton mini 6x6x5, 4 pini | 9 | ||
LED-uri | 2 | roșu, albastru | |
Rezistențe | 4 | 100Ω, 150Ω, 1kΩ, 2kΩ | |
Breadboard 830 puncte | 1 | ||
Fire jumper | set variat |
Componentă | Pin Arduino | Pin MCU | Detalii |
---|---|---|---|
Butoane note (8) | D2–D9 | PD2–PD7, PB0, PB1 | Pull-up activat, pinii sunt în linie continuă |
Buton record | A1 | PC1 | Pull-up activat |
LED albastru | A2 | PC2 | Conectat în serie cu rezistență de 100Ω |
LED roșu | A3 | PC3 | Conectat în serie cu rezistență de 150Ω |
Potențiometru | A0 | PC0 (ADC0) | Intrare analogică, folosește canalul ADC0 |
Buzzer | D10 | PB2 (OC1B) | Ieșire PWM pe Timer1 |
HC-05 STATE | D13 | PB5 | Indică starea conexiunii Bluetooth |
HC-05 RXD | TX0 | PD1 | Comunicare UART (USART0), Arduino→HC-05, conectat prin divizor de tensiune (2kΩ și 1kΩ), pentru că pinul RXD funcționează la 3.3V |
HC-05 TXD | RX0 | PD0 | Comunicare UART (USART0), HC-05→Arduino |
Inițial am conectat pinii RX și TX de pe HC-05 la D11 și D12, în ideea de a folosi SoftwareSerial. Ulterior i-am mutat pe TX1 și RX0 și am renunțat complet la bibliotecile Arduino.
<avr/io.h>
și <avr/interrupt.h>
)
Structura codului este modulară: fiecare header definește o interfață pentru o componentă hardware sau funcționalitate, iar main.cpp
folosește aceste interfețe pentru logica principală a aplicației. Ideea de la care am pornit a fost să implementez funcționalitățile necesare, asemănătoare cu funcțiile de bază din Arduino.
main.cpp
Fișierul principal conține funcția setup()
și bucla while(1)
, în care sunt apelate funcțiile de actualizare
update_bt_state()
: verifică dacă modulul HC-05 este conectat, controlează LED-ul albastru și dezactivează modul record în caz de deconectareupdate_notes()
: detectează apăsarea butoanelor, aplică pitch shift în funcție de potențiometru, redă nota pe buzzer și trimite mesaje seriale dacă înregistrarea e activăupdate_rec_mode()
: comută între modurile normal și record la apăsarea butonului de înregistrare, controlează LED-ul roșu și trimite serial mesaje de control
io_utils.h
Funcții pentru configurarea pinilor, folosind structura IOPin
, care conține toate registrele asociate unui pin
conf_input(IOPin)
: setează pinul ca intrareconf_input_pullup(IOPin)
: configurare ca intrare cu rezistor de pull-up activconf_output(IOPin)
: setează pinul ca ieșireread_pin(IOPin)
: returnează starea pinuluiset_pin_high(IOPin)
/set_pin_low(IOPin)
: controlează nivelul logic pe pin
buzzer.h
Controlul buzzer-ului prin PWM, folosind Timer1
buzzer_init()
: configurează Timer1 în modul Fast PWM, cu top în ICR1 și ieșire pe pinul OC1B (PB2)play_note(frequency)
: calculează valoarea pentru ICR1 în funcție de frecvența dată, activează pinul OC1B și configurează semnalul PWMstop_note()
: dezactivează PWM, setează pinul pe LOW și apoi pe input pentru a opri complet sunetul
adc_pot.h
Citirea valorii de la potențiometru prin ADC0
adc_init()
: inițializează perifericul ADCread_pot_value()
: returnează valoarea potențiometrului mapată în intervalul 0.0–12.0, folosită pentru calculul pitch shift
timer.h
Folosește Timer0 pentru funcții asemănătoare cu Arduino
timer0_init()
: configurează Timer0 în mod CTC, cu întrerupere pe compare match A_millis()
: returnează timpul scurs în milisecunde, folosit pentru debounce și timestamp-uri_delay(ms)
: întârziere software folosind _millis()
usart.h
Comunicare serială cu modulul HC-05
usart0_init(ubrr)
: inițializează USART0 cu baud 9600, format 8N1usart0_print(str)
: transmite un șir de caractere prin USART, folosește usart0_transmit(character)
, pentru a trasmite câte un caracterSoftware debounce pentru butoane
În loc de debounce hardware (cu condensator), am implementat debounce-ul în software, folosind _millis()
și _delay()
, cu o întârziere de 30 ms. Această variantă este mai flexibilă și mai ușor de ajustat, în plus spațiul pe breadboard era deja la limită.
Polling în loc de întreruperi
Butoanele sunt distribuite pe mai multe porturi, iar întreruperile externe sunt limitate. În plus, pinii D0 și D1 sunt rezervați pentru USART, deci nu puteau fi folosiți pentru întreruperi. Polling-ul permite control mai bun asupra logicii, în special pentru integrarea debounce-ului software.
Structura IOPin
pentru pinii digitali
struct IOPin { volatile uint8_t* pin; volatile uint8_t* ddr; volatile uint8_t* port; uint8_t bit; };
Structura grupează bitul asociat unui pin cu adresele registrelor sale, făcând codul mai lizibil și mai ușor de scris.
Câmpurile sunt declarate ca volatile
, asigurând că valorile registrelor sunt scrise și citite exact în momentul în care sunt accesate în cod.
Poate fi redată o singură notă la un moment dat
Deoarece buzzer-ul poate genera doar o singură frecvență la un moment dat, dispozitivul nu poate rada mai multe note simultan. Dacă sunt apăsate mai multe butoane simultan, este selectată prima notă (primul buton) detectată de loop-ul de polling (indexul cel mai mic).
for(int i = 0; i < 8; i++) { if (read_pin(note_btns[i]) == 0) { note = i; break; } }
Dezactivarea completă a buzzer-ului în stop_note()
Modulul buzzer folosit genera un sunet de fundal constant atunci când semnalul PWM era oprit. Sunetul nu a dispărut nici prin setarea pinului pe LOW, nici cu noTone()
din Arduino. Am încercat să rezolv problema prin hardware, dar fără succes. Am ales totuși să păstrez modulul, pentru că produce un volum semnificativ mai mare decât un buzzer simplu (datorită amplificatorului integrat).
Pentru a opri complet sunetul, pinul buzzer-ului este setat ca input in stop_note()
, apoi ca output în play_note()
.
Pitch shift
Valoarea citită este mapată în intervalul 0.0-12.0, (12 este numărul de semitonuri într-o octavă).
Frecvențele sunt ajustate conform formulei $f = f_0 \cdot 2^{n/12}$ (n = pitch_shift), care reflectă creșterea pe scara muzicală reală.
Ajustarea frecvenței este doar în sus, astfel la poziția minimă a potențiometrului sunt redate notele exacte din gama C4–C5, iar la poziția maximă gama C5-C6.
Am ales această variantă pentru a avea un punct de referință clar pentru gama centrală (la poziția minimă). La valoarea maximă, cea mai înaltă notă e C6, deoarece notele mai înalte generate prin buzzer pot deveni deranjante.
Mesaje seriale compacte
Evenimentele note_on
și note_off
sunt transmise într-un singur mesaj (ex: 1 1034 440\n
), pentru a evita fragmentarea și a simplifica parsarea în aplicația Recorder.
_millis()
și pentru PWMPentru înregistrarea și redarea melodiilor, am dezvoltat o aplicație companion în Python.
Biblioteci utilizate:
pyserial
– pentru comunicarea serială cu dispozitivulmido
– pentru crearea fișierelor MIDIpygame.midi
– pentru redarea fișierelor MIDIpygame_gui
– pentru interfața graficăAplicația funcționează pe Windows, Linux și macOS.
Aplicația are două taburi principale:
1. Record
Permite conectarea la dispozitiv prin port serial și înregistrarea notelor transmise în timp real.
COM11
, /dev/ttyUSB0
)RECORD_OFF
de la dispozitiv.mid
, în folderul recordings
2. View Recordings
Afișează toate melodiile înregistrate și permite redarea sau ștergerea acestora.
La selectarea unei înregistrări, sunt disponibile două butoane:
Am testat funcționalitățile incremental, pe măsură ce le-am implementat, prin observarea comportamentului așteptat sau prin afișarea valorilor prin serial monitor, unde era necesar.
note_off
, actualizarea interfeței la oprirea înregistrării de către dispozitiv (prin RECORD_OFF
) etc.Proiectul m-a ajutat să înțeleg mai bine conceptele studiate în cadrul laboratoarelor, prin aplicarea practică a noțiunilor de GPIO, UART, PWM, ADC și timere.
În plus, proiectul mi-a oferit ocazia să învăț noțiuni noi despre formatul MIDI și modul în care se procesează digital muzica, de la conversia frecvențelor în note până la generarea și redarea fișierelor MIDI.
Resurse hardware:
Resurse software:
Resurse aplicație Python: