Mini Synth

Introducere

Proiectul constă într-un mini sintetizator, capabil să genereze și să înregistreze note muzicale simple.

Funcționalitățile dispozitivului:

  • 8 butoane pentru note
  • Redarea sunetelor în timp real (buzzer)
  • Ajustarea frecvenței (potențiometru)
  • Conectare prin Bluetooth la calculator, pentru a înregistra melodii

Dispozitivul e însoțit de o aplicație pentru calculator, MiniSynth Recorder, cu următoarele funcționalități:

  • Înregistrarea melodiilor
  • Transformarea datelor de la dispozitiv în format MIDI standand
  • Vizualizarea și redarea înregistrărilor salvate

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ă.

Descriere generală

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:

  • Albastru - conexiune Bluetooth activă
  • Roșu - înregistrare în curs

Detalii de funcționare

Moduri de funcționare

Dispozitivul are două moduri de funcționare:

1. Modul normal

În modul normal (implicit), dispozitivul are următoarele funcționalități:

  • Apăsarea celor 8 butoane pentru a reda note muzicale, folosind buzzer-ul pasiv
  • Ajustarea frecvenței notelor prin rotirea potențiometrului
    • În poziția minimă a potențiometrului, sunt redate notele din gama C4-C5, iar prin rotirea acestuia spre dreapta, frecvențele cresc gradual, până la C5-C6

2. Modul record

Modul record este activat prin apăsarea butonului de înregistrare, atunci când dispozitivul e conectat la Bluetooth.

  • Pe lângă redarea sunetului, fiecare notă este transmisă în timp real prin Bluetooth
  • Acest mod se poate folosi împreună cu aplicația MiniSynth Recorder, care înregistrează datele și le salvează în format MIDI

Feedback vizual (LED-uri)

  • LED albastru (Bluetooth):
    • Aprins continuu: conexiune Bluetooth activă
    • Clipire de 2 ori: atenționare - s-a încercat înregistrarea fără conexiune, sau s-a pierdut conexiunea în timpul înregistrării
  • LED roșu (record):
    • Aprins: mod record activ

Comportamente speciale

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ă):

  • se dezactivează modul record
  • se stinge LED-ul roșu
  • LED-ul albastru clipește de 2 ori

Formatul datelor transmise prin Bluetooth

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 record
    • În aplicație, acest mesaj golește datele primite anterior și marchează începutul înregistrării. În practică nu sunt transmise date înainte de acest mesaj, e mai mult un safety measure și o formă de logging
  • RECORD_OFF - transmis la dezactivarea modului record
    • Oprește automat înregistrarea în aplicație, fără a mai fi nevoie să se apese “Stop recording”

Dacă 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.

Hardware Design

Diagrama hardware

Lista de componente

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

Conexiuni hardware

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

Imagini

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.

Software Design

Mediu de dezvoltare

  • Visual Studio Code + PlatformIO
  • Cod scris în C++
  • Folosește doar biblioteci standard AVR (<avr/io.h> și <avr/interrupt.h>)
  • Nu am folosit biblioteci externe

Organizarea codului

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 deconectare
  • update_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 intrare
  • conf_input_pullup(IOPin): configurare ca intrare cu rezistor de pull-up activ
  • conf_output(IOPin): setează pinul ca ieșire
  • read_pin(IOPin): returnează starea pinului
  • set_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 PWM
  • stop_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 ADC
  • read_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 8N1
  • usart0_print(str): transmite un șir de caractere prin USART, folosește usart0_transmit(character), pentru a trasmite câte un caracter

Decizii și detalii de implementare

Software 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.

Concepte din laborator

  • GPIO - configurarea pinilor pentru butoane și LED-uri
  • UART - comunicare serială cu modulul HC-05 pentru transmiterea mesajelor către aplicație
  • Timer - pentru temporizarea cu _millis() și pentru PWM
  • PWM - generarea semnalului pentru buzzer
  • ADC - citirea valorii potențiometrului

Aplicația MiniSynth Recorder

Pentru înregistrarea și redarea melodiilor, am dezvoltat o aplicație companion în Python.

Biblioteci utilizate:

  • pyserial – pentru comunicarea serială cu dispozitivul
  • mido – pentru crearea fișierelor MIDI
  • pygame.midi – pentru redarea fișierelor MIDI
  • pygame_gui – pentru interfața grafică

Aplicația funcționează pe Windows, Linux și macOS.

Interfață și funcționalitate

Aplicația are două taburi principale:

1. Record

Permite conectarea la dispozitiv prin port serial și înregistrarea notelor transmise în timp real.

  • Port name – câmp text pentru introducerea portului serial (ex: COM11, /dev/ttyUSB0)
  • Status – afișează starea conexiunii (connected / disconnected)
  • Connect/Disconnect – deschid și închid conexiunea serială
    • La connect, conexiunea se încearcă timp de 10 secunde. Dacă nu reușește, se afișează “Connection failed”
  • Start Recording/Stop Recording – pornește sau oprește înregistrarea
    • Înregistrarea se oprește automat și la primirea mesajului RECORD_OFF de la dispozitiv
    • După oprirea înregistrării, aplicația procesează datele și le salvează într-un fișier .mid, în folderul recordings

2. View Recordings

Afișează toate melodiile înregistrate și permite redarea sau ștergerea acestora.

  • Listă de înregistrări – scrollable, afișează toate fișierele MIDI salvate

La selectarea unei înregistrări, sunt disponibile două butoane:

  • Play/Stop – redă melodia selectată sau oprește redarea
  • Delete – șterge fișierul selectat

Testare

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.

  • Apăsare butoane - afișarea frecvenței corespunzătoare
  • Debounce - se afișează un singur mesaj la fiecare apăsare
  • Buzzer - redarea corectă a frecvențelor
  • Pitch shift - afișarea valorii citite de la potențiometru, apoi afișarea frecvențelor ajustate și redarea acestora
    • am verificat că frecvențele calculate corespund cu tabelul de frecvențe ale notelor (de exemplu, la poziția maximă, am verificat că frecvențele corespund gamei C5-C6)
  • Activare/dezactivare mod record - testat vizual (LED) și prin verificarea mesajelor trimise
  • Comunicația Bluetooth - testată inițial cu un script care doar citește și afișează mesajele în terminal, ulterior cu aplicația implementată
    • am testat apoi cazurile speciale: se încearcă înregistrarea fără conexiune, se întrerupe conexiunea în timpul înregistrării
  • Aplicația Python - am implementat și testat pe rând conectarea, citirea mesajelor (prin afișare în terminal), crearea fișierelor MIDI (testate prin redare cu un player și prin analiza notelor într-un software dedicat), redarea înregistrărilor
    • am testat cazurile speciale, ex: note fără note_off, actualizarea interfeței la oprirea înregistrării de către dispozitiv (prin RECORD_OFF) etc.

Rezultate Obţinute

Demo:

Concluzii

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.

Download

Cod microcontroller: mini-synth-firmware.zip

Recorder Python: mini-synth-recorder.zip

GitHub

Planificare

Bibliografie/Resurse

Resurse hardware:

Resurse software:

Resurse aplicație Python:

pm/prj2025/ccristi/agavrilut.txt · Last modified: 2025/05/28 02:34 by agavrilut
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0