Table of Contents

Mini Synth

Introducere

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

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:

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:

2. Modul record

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

Feedback vizual (LED-uri)

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

Formatul datelor transmise prin Bluetooth

Dispozitivul trimite către aplicație 4 tipuri de mesaje, separate prin '\n':

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

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

io_utils.h

Funcții pentru configurarea pinilor, folosind structura IOPin, care conține toate registrele asociate unui pin

buzzer.h

Controlul buzzer-ului prin PWM, folosind Timer1

adc_pot.h

Citirea valorii de la potențiometru prin ADC0

timer.h

Folosește Timer0 pentru funcții asemănătoare cu Arduino

usart.h

Comunicare serială cu modulul HC-05

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

Aplicația MiniSynth Recorder

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

Biblioteci utilizate:

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.

2. View Recordings

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

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

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.

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: