Dati MIDI in Java Lezione 22 Programmazione MIDI (Prof. Luca A. Ludovico)
Pic MIDI Documentation
Transcript of Pic MIDI Documentation
Progetto di un a tastiera
“MIDI Master Keyboard”
Progetto e realizzazione di un dispositivo per il polling temporizzato di una matrice di contatti e la
generazione conseguente di messaggi secondo lo standard musicale MIDI.
Corso:
Elettronica III
Studente:
Giancarlo Todone
Giancarlo Todone - Progetto e realizzazione di un controller master MIDI Pagina 1
Introduzione
Lo scopo del progetto era quello di trovare un campo
di utilizzo reale per il microcontrollore Microchip
PIC18F452 che pur dimostrandone la potenza e la
flessibilità, non necessitasse di molta circuiteria
esterna e fosse di facile ed economica costruzione per
chiunque volesse riprodurre il dispositivo. Per
motivazioni contingenti è stato scelto di usare il PIC in
campo musicale, e precisamente per costruire una
cosiddetta “master keyboard” MIDI, o “tastiera muta”,
e cioè un dispositivo che analizzi lo stato di un’insieme
di tasti e resistenze variabili disposti a foggia di
tastiera musicale e generi a partire da esso un
adeguato flusso di dati MIDI con cui comandare un
sintetizzatore, un campionatore o un altro strumento
MIDI “slave”. Per l’hardware dei tasti musicali si è
riciclata una vecchia tastiera che –per quanto non professionale- dispone della forma e dei contatti
appropriati a gestire le caratteristiche richieste. Il protocollo MIDI -riassunto di seguito- dimostra una certa
complessità quando ci si trovi a doverlo interpretare (poiché per questioni tecniche è necessario
decodificare anche molti dati ai quali non si è direttamente interessati) ma si rivela abbastanza semplice nel
momento in cui si debbano invece generare comandi di un insieme ristretto di tipologie. Per il progetto si è
deciso di implementare i comandi MIDI note-on e note-off per segnalare la pressione dei vari tasti, di
leggere la “pitch-wheel” o “controllo del portamento”, di inoltrare comandi relativi al pedale del sustain e
gestire il cosiddetto “active-sensing”: è comunque facile aggiungere a richiesta fino ad altri 7 comandi
analogici e diversi altri comandi discreti (il numero è dipendente da eventuali tecniche di multiplazione). In
particolare, un punto focale dell’intero progetto è la gestione della “velocity” o “dinamica”, cioè della
rapidità -con cui solitamente si approssima la forza- con la quale ogni tasto viene attivato, parametro che di
conseguenza viene usato per comandare l’espressione di ogni singolo suono prodotto. Per poter gestire
tutti gli aspetti discussi finora –in particolar modo la dinamica- è stato necessario progettare del semplice
hardware dedicato, incarnato da due de-multiplexer 74hc138 economici (circa 0,60 euro l’uno) e di
semplice utilizzo, ed è stato inoltre necessario “spremere” abbastanza la potenza del PIC utilizzando un
quarzo da 20 MHz direttamente connesso col microcontrollore. Il resto dei componenti è passivo (tranne il
classico regolatore di tensione 78ls05) e rappresenta il tipico setup per un PIC: alimentazione, clock, reset.
Nel prototipo –perfettamente funzionante- realizzato su piastra millefori, mancano alcune raffinatezze
come resistenze limitatrici di corrente o condensatori di de-bounce, che sono però stati aggiunti nel
progetto CAD sviluppato con il software gratuito EAGLE: grazie ad esso è quindi possibile generare semi-
automaticamente anche una PCB dedicata al circuito, da incidere con i soliti metodi.
Figura 1 - prototipo del dispositivo di polling e generazione
messaggi MIDI
Giancarlo Todone - Progetto e realizzazione di un controller master MIDI Pagina 2
Materiali ed attrezzature
Il Microchip PIC18F452 è un microcontrollore a basso consumo
dotato di una CPU RISC capace di eseguire fino a 10 milioni di
istruzioni al secondo, di 1,5 Kbyte di ram on-chip, 256 bytes di
eeprom gestibile con istruzioni dedicate, memoria programma
di 16 K istruzioni e di diverse periferiche come timers, un
USART e un convertitore AD multiplato su 8 ingressi. Esso
risulta molto comodo per la compatibilità –ottenibile con sforzi
limitati- verso molti altri dispositivi della stessa casa di
produzione, ormai molto diffusi e largamente utilizzati.
Durante questa esperienza è stato quindi possibile riutilizzare il
know-how accumulato con altre periferiche simili, ed
addirittura l’hardware di programmazione precedentemente
auto costruito.
L’altro integrato adottato nel progetto è il 74hc138, una semplice logica combinatoria
che implementa un de-multiplexer mantenendo alte o basse le diverse 8 uscite a
seconda della configurazione binaria presente su 3 ingressi e 3 linee di enable (in figura
pedinatura e tabella di verità). In particolare, quando abilitato, l’integrato –qui usato
nella sua versione invertente- pone a 0v una delle 8 linee di uscita normalmente a Vcc,
corrispondente al numero binario in ingresso sui tre input.
Figura 2 – caratteristiche e pedinatura del
PIC18F452
Figura 3 - pedinatura
dell'integrato
74hc138
Figura 4 - tabella di verità dell'integrato 74hc138, ripresa dal suo datasheet
Giancarlo Todone - Progetto e realizzazione di un controller master MIDI
permetta l’interazione con vari hardware
semplice ed economico programmatore JDM (in figura foto e schema elettrico), ricorrendo
all’uscita seriale hardware del PIC per le operazioni di debug.
utilizzato è l’ottimo PicPGM che vanta notevoli funzioni di auto
al quale sono stati dati in pasto direttamente i binari generati da MikroC.
ciclo di polling sono stati usati un’oscilloscopio (non strettamente necessario) e un frequenzimetro auto
costruito (in figura). Una volta terminato e fatto funzionare il prototipo, si è proceduto al disegno CAD dello
schema elettrico con la versione dimostrativa gratuita di EAGLE,
maniera assistita anche le PCB (nella versione dimostrativa limitate per dimensioni).
Figura 6
semplice
programmatore JDM
(autocostruito)
adattato a
funzionare con
packaging diversi
Figura 5 - schema elettrico del programmatore JDM, qui
dimostrato per l'uso con un diverso modello di PIC
Progetto e realizzazione di un controller master MIDI
Per questioni di comodità, e per permettere a chiunque
di costruire la sua versione del dispositivo, si sono usati
software gratuiti o versioni dimostrative gratuite d
software commerciali. Per la programmazione
C/assembler, è stato adottato MikroC, un ambiente
semplice e rapido in cui si produce codice riutilizzabile
anche nel’ufficiale C18 di Microchip (con minime
modifiche); il software permette di creare e ridistri
liberamente progetti, ma permette la compilazione
fino a 2000 parole di istruzione, dopo le quali è
necessario adottare la versione a pagamento (che costa
poco più di 100 euro). Nonostante l’ambiente MikroC
permetta l’interazione con vari hardware di programmazione/ICD, per questo progetto si è fatto uso del più
semplice ed economico programmatore JDM (in figura foto e schema elettrico), ricorrendo
del PIC per le operazioni di debug. Il software di programmazion
utilizzato è l’ottimo PicPGM che vanta notevoli funzioni di auto-detect di programmatori e microcontrollori,
al quale sono stati dati in pasto direttamente i binari generati da MikroC. Per verificare
usati un’oscilloscopio (non strettamente necessario) e un frequenzimetro auto
costruito (in figura). Una volta terminato e fatto funzionare il prototipo, si è proceduto al disegno CAD dello
schema elettrico con la versione dimostrativa gratuita di EAGLE, un software che permette di generare in
maniera assistita anche le PCB (nella versione dimostrativa limitate per dimensioni).
Figura 6 - foto di un
semplice
programmatore JDM
(autocostruito)
adattato a
funzionare con
packaging diversi
elettrico del programmatore JDM, qui
dimostrato per l'uso con un diverso modello di PIC
Figura 7 - utilizzo del frequenzimetro autocostruito
(con PIC16F84) per verificare la frequenza di polling di
circa 1 KHz
Pagina 3
Per questioni di comodità, e per permettere a chiunque
di costruire la sua versione del dispositivo, si sono usati
software gratuiti o versioni dimostrative gratuite di
software commerciali. Per la programmazione
C/assembler, è stato adottato MikroC, un ambiente
semplice e rapido in cui si produce codice riutilizzabile
anche nel’ufficiale C18 di Microchip (con minime
modifiche); il software permette di creare e ridistribuire
progetti, ma permette la compilazione di
fino a 2000 parole di istruzione, dopo le quali è
necessario adottare la versione a pagamento (che costa
poco più di 100 euro). Nonostante l’ambiente MikroC
di programmazione/ICD, per questo progetto si è fatto uso del più
semplice ed economico programmatore JDM (in figura foto e schema elettrico), ricorrendo talvolta
Il software di programmazione gratuito
detect di programmatori e microcontrollori,
verificare la regolarità del
usati un’oscilloscopio (non strettamente necessario) e un frequenzimetro auto
costruito (in figura). Una volta terminato e fatto funzionare il prototipo, si è proceduto al disegno CAD dello
un software che permette di generare in
maniera assistita anche le PCB (nella versione dimostrativa limitate per dimensioni).
utilizzo del frequenzimetro autocostruito
per verificare la frequenza di polling di
Giancarlo Todone - Progetto e realizzazione di un controller master MIDI Pagina 4
Lo schema elettrico
Per completezza, in primis riportiamo anche la
configurazione di base di un PIC. I condensatori C1
e C5 con il regolatore di tensione 78ls05
costituiscono una sorgente di tensione stabilizzata a
5 Vcc. Il valore del condensatore elettrolitico è
abbastanza elevato da garantire la continuità
dell’alimentazione anche durante un elevato
assorbimento da parte di un altro componente del
circuito o durante i possibili sbalzi nella tensione di
alimentazione non regolata (marcata 6-10v), ma
abbastanza basso da consentire un ridotto tempo di
start-up, che consente di polarizzare il piedino di
reset MCLR con una sola resistenza direttamente a
5Vcc, senza condensatori di temporizzazione
(solitamente si collega un condensatore tra MCLR e
GND per fare in modo che il PIC resti resettato
finchè l’alimentazione non si stabilizza). La base dei
tempi utilizza l’oscillatore interno (qui non facciamo
uso di PLL) che si basa sul quarzo esterno -in questo
caso da 20 MHz- stabilizzato dai due condensatori
da 15 pF.
Le linee RD0-RD2 del PIC sono connesse alle linee di ingresso di entrambi gli integrati 74hc138, mentre RD3
è collegata in modo da abilitare uno o l’altro integrato esclusivamente a seconda del suo livello logico;
questo in pratica ci consente di ottenere logicamente un unico de-multiplexer che accetta un numero
binario su 4 bit (quindi da 0 a 15) e pone a livello logico basso la linea corrispondente, lasciando a livello
alto tutte le altre. Per esempio, se RD0-RD3 vale 0, la sola linea “bank A” viene posta a 0v; se RD0-RD3 vale
1, la sola linea “bank B” viene posta a 0v; se RD0-RD3 vale 8, la sola linea “bank A’ ” viene posta a 0v.
Questo consente di effettuare la scansione delle note per banchi. Ognuno degli 8 banchi “A”, “B”, “C”, “D”,
“E”, “F”, “G”, “H” attiva un gruppo di otto note che vengono lette contemporaneamente dagli otto ingressi
Figura 8 - configurazione di base del PIC: alimentazione, clock,
reset.
Figura 9 - de-multiplexer
che gestisce i banchi
"before"; viene attivato
quando RD3 è posto a
livello logico basso
Figura 10 - de-
multiplexer che gestisce
i banchi "after"; viene
attivato quando RD3 è
posto a livello logico alto
Giancarlo Todone - Progetto e realizzazione di un controller master MIDI Pagina 5
RB0-RB7 del PIC. I corrispettivi banchi con l’apice servono per il rilevamento della dinamica; ogni nota
chiude in rapida sequenza due contatti: uno che potremmo chiamare “before” e successivamente un altro
che potremmo chiamare “after”. Da quanto ravvicinatamente i contatti “before” e “after” vengono chiusi,
dipende il parametro di dinamica di ogni pressione. Ad esempio, ponendo a 0 le linee RD0-RD3 attiviamo il
banco A e possiamo quindi leggere su RB0-RB7 lo stato degli switch ”before” delle prime 8 note della
tastiera; ponendo RD0-RD3 a 8 attiviamo il banco A’ e possiamo quindi leggere su RB0-RB7 lo stato degli
switch “after” delle prime 8 note. Abbiamo visto che “attivare” un banco significa porre la corrispondente
linea a 0 (stiamo quindi usando la logica negativa); ciò è dovuto a come è costruita la matrice di contatti (in
figura) e anche al fatto che in questo modo si possono sfruttare le resistenze di pull-up programmabili
interne della porta RB del PIC.
Figura 11 - costituzione della matrice di contatti della tastiera (semplificata a tre banchi da tre note per chiarezza). I diodi evitano
ritorni di corrente in caso di pressioni contemporanee e fungono inoltre da blande resistenze. Le resistenze di pull-up nel nostro
caso sono interne al microcontrollore.
Figura 12 - suddivisione della tastiera in banchi da 8 note. I banchi A, B, C,... permettono la lettura degli switch "before", mentre
A', B', C', ... permettono la lettura degli switch "after"
Giancarlo Todone - Progetto e realizzazione di un controller master MIDI Pagina 6
L’interfaccia MIDI è costituita da una semplice
resistenza connessa alla porta TX dell USART
integrato nel PIC. Come vedremo, infatti la
trasmissione MIDI è una trasmissione seriale su una
linea in “current-loop” per cui vengono fornite
anche le linee Vcc e Gnd. Lo standard MIDI prevede
l’utilizzo di un optoisolatore, ma esso è a carico del
dispositivo “slave”, e quindi non dobbiamo
preoccuparcene.
Di seguito vengono riportate le pedinature dei connettori utilizzati per collegare la matrice di contatti (e
pochi altri dispositivi) alla scheda del prototipo. Quello a 20 contatti “grigio” era già presente ed è stato
mantenuto non modificato per consentire l’utilizzo della matrice con altri progetti precedentemente
sviluppati: trasporta le linee relative ai banchi A, B, C, D, E, F, G, H e due contatti del pedale del sustain;
quello a 16 contatti “colorato” –collegato ex novo- trasporta le linee dedicate ai banchi A’, B’, C’, D’, E’, F’,
G’, H’ e delle linee dedicate a controller analogici (resistenze variabili) che sono poi collegate alle linee AN
(il convertitore ADC) del PIC.
La resistenza variabile da usare come pitch-bender va
semplicemente collegata con PB al comune, Vcc su uno dei
piedini rimanenti e Gnd sull’altro. Data la natura economica
della tastiera, essa dispone però di una “rotella” per il
controllo del portamento che non si basa su resistenza
variabile ma su una matrice di contatti mostrata in figura. Si è
ovviato collegando i contatti con delle resistenze, in modo da
emulare sommariamente un resistore variabile “a gradoni”, e
smussando poi le letture con un filtro software sul micro.
Figura 13 - interfaccia MIDI.
Figura 14 - connettore a 20 pin,
osservato "da sotto"
Figura 15 - connettore a 16 pin,
osservato "da sotto". PB = Pitch-
Bender
Figura 16 - collegamento della
resistenza variabile del Pitch-
Bender (controllo del
portamento)
Figura 17 - sulla destra la schematizzazione della
PCB della rotella del portamento, sulla sinistra la
rete di resistenze per emulare un resistore
variabile
Giancarlo Todone - Progetto e realizzazione di un controller master MIDI Pagina 7
Il protocollo MIDI
Il protocollo MIDI
rappresenta un ottimo
caso di studio perchè
abbastanza semplice da
essere comunque molto
comprensibile, ma
abbastanza complesso da
non risultare banale.
Inoltre, si tratta di una
comunicazione seriale
asincrona -e in quanto
tale facilmente simulabile.
I dati viaggiano su una linea a bassa tensione con una tecnica chiamata "current loop" per interfacciarsi con
la quale lo standard MIDI prevede l'uso di optoisolatori come il comune 6N138 e l'adozione di un baud-rate
non standard di 31250 (+/- 1%).
La pubblicazione delle prime specifiche risale al 1983, ma
lo standard è sopravvissuto fino ad oggi (e continua ad
imporsi) nonostante le pecche che ovviamente comincia a
dimostrare. Difetti sensibili risiedono sia nella logica del
protocollo, sia nelle specifiche di comunicazione elettrica,
originariamente pensati per comunicare da un singolo
master ad un singolo slave in maniera unidirezionale, poi
adattati a gestire loopbacks e catene di strumenti ed
effetti musicali grazie anche all'introduzione del MIDI-
THRU, una porta che replica in uscita i messaggi arrivati
alla porta MIDI-IN dello stesso strumento. In questo modo
-grazie anche alla suddivisione in canali virtuali di cui
parleremo- ogni strumento osserva l'intero flusso di dati
in ingresso, e filtra da esso quelli che è programmato per
recepire, passando poi i dati ad altri strumenti tramite la
porta THRU. Così facendo, però -non essendo tra l'altro il canale di comunicazione di banda molto larga e
non prevedendo il protocollo un sistema di rilevamento o correzione degli errori- si introducono effetti
indesiderati e latenze, cui si è cercato di ovviare migliorando nel tempo i dispositivi implementanti
Figura 18 - la rotella del controllo portamento disassemblata; la PCB a destra è autoesplicativa: il
trascinamento della rotella provoca la chiusura dei contatti in diversi modi.
Figura 19 - Connessione MIDI - lato ricevitore(slave); la resistenza di protezione
dell'optoisolatore è di 220Ω, mentre quella di pull-up di 1KΩ
Figura 20 - Connessione MIDI - lato trasmettitore
(master); si noti il pin collegato direttamente a Vcc e il
pin centrale (GND) che viene lasciato scollegato per
evitare oscillazioni nel potenziale di massa; entrambe le
resistenze sono da 220Ω
Giancarlo Todone - Progetto e realizzazione di un controller master MIDI Pagina 8
piuttosto che lo standard. Per questi motivi, da sempre gli strumenti MIDI professionali hanno richieste di
latenza molto bassa e capacità di interpretare "elasticamente" il protocollo.
Le informazioni che si possono ricavare da uno stream di comandi MIDI sono organizzate in messaggi, che
sono composti di "opcodes" (o "status bytes") seguiti da dati. Esistono poi degli opcodes particolari
indicanti messaggi di sistema.
Osservando un qualsiasi dato in transito durante una comunicazione, è possibile dire immediatamente di
che tipo si tratta: infatti qualsiasi byte con il bit 7 impostato a '1' rappresenta un opcode, altrimenti -se '0'- i
sette bit meno significativi rappresentano un dato, come il parametro di qualche comando (quindi parlando
di byte di dati, in realtà d'ora in poi intenderemo i 7 bits utili rimasti). Per interpretare correttamente una
comunicazione, quindi, bisogna tener conto del tipo di byte che si sta osservando e dell'evoluzione della
comunicazione. In dettaglio, ecco le tipologie di messaggi:
opcode nome descrizione e numero di bytes di parametri
Sta
tus
by
tes
rela
tiv
i a
d u
n c
an
ale
vir
tua
le
0x80-0x8f note off indica di silenziare una nota; è seguito da due byte di parametri (uno
per la nota, l'altro per l'intensità)
0x90-0x9f note on indica di suonare una nota (o silenziarla se l'intensità è 0)
0xa0-0xaf key pressure "after-touch"; è seguito da due byte di parametri (uno per la nota,
l'altro per la presenza di effetto)
0xb0-0xbf Cc parameter modifica di un parametro continuous controller; è seguito da due byte
(uno per il codice controller, l'altro per la nuova impostazione
parametro)
0xc0-0xcf Program change seleziona uno strumento; è seguito da un byte che indica il codice del
nuovo strumento da adottare
0xd0-0xdf chan. pressure effetto di pressione tasti che interessa l'intero canale (non
perfettamente specificato); è seguito da un byte indicante l'intensità di
effetto
0xe0-0xef pitch wheel indica la posizione assoluta della rotella che sposta finemente il tono; è
seguita da due bytes rappresentanti una parola di 14 bits (i 7 bits meno
significativi per primi)
Sy
ste
m M
ess
ag
es,
al
di
fuo
ri d
ell
a l
og
ica
de
i
can
ali
vir
tua
li
0xf0 system
exclusive
indica l'inizio di un messaggio di sistema seguito da un numero variabile
di bytes di parametri (va terminato con un EOX)
0xf1 undefined
0xf2 song position per i sequencers; indica la nuova posizione in una traccia; seguito da 2
bytes che costituiscono il valore di 14 bits indicante la posizione, i 7
meno significativi per primi
0xf3 song select per i sequencers; indica il codice della nuova traccia; è seguito da un
byte indicante il codice della nuova traccia
0xf4 undefined
0xf5 undefined
0xf6 tune request per i sintetizzatori analogici: indica la richiesta di risintonizzare gli
oscillatori. Non è seguito da alcun dato
0xf7 EOX
(terminator)
indicatore che termina una sequenza di parametri in un messaggio di
sistema a lunghezza variabile; anche altri messaggi come note-on o
note-off possono interrompere una sequenza. Non è seguito da alcun
dato.
Re
alt
ime
Me
ssa
ge
s
0xf8 timing clock usato per sincronizzare le macchine (specialmente le “drum-machines”)
0xf9 undefined
0xfa start per sequencers: indica di iniziare la riproduzione
0xfb continue per sequencers: indica di continuare la riproduzione
0xfc stop per sequencers: indica di fermare la riproduzione
0xfd undefined
0xfe active sensing viene mandato ogni 300 ms circa dal master quando questo non ha
niente da fare (per far capire che è ancora vivo); quando non viene
ricevuto alcun messaggio per più di 300 ms il master è da considerarsi
Giancarlo Todone - Progetto e realizzazione di un controller master MIDI Pagina 9
opcode nome descrizione e numero di bytes di parametri
disconnesso
0xff system reset reset di sistema
alcune precisazioni:
1. vale la regola del "running status byte": una volta che un messaggio viene ricevuto, non occorre
ripetere l'opcode prima di mandare i dati successivi, se questo non cambia (vedere esempi in
seguito)
2. una note-on con intensità posta a 0 è interpretata come un note-off; questo, insieme alla
convenzione del "running status byte" permette di inviare lunghe stringhe di eventi note-on/note-
off rapidamente
3. MIDI prevede la suddivisione in canali virtuali; i messaggi da 0x80 a 0xef sono raggruppati in gruppi
di 16: nel messaggio (nei 4 bits meno significativi) è insito il canale virtuale al quale ci si riferisce; ad
esempio 0x90 significa "note-on sul canale 0", mentre 0x91 vuol dire "note-on sul canale 1" e così
via
4. i messaggi "undefined" vanno semplicemente ignorati
5. gli ultimi 8 messaggi da 0xf8 a 0xff chiamati "realtime messages" (è più in generale i messaggi senza
parametri in coda) così come altri System Messages possono venire inframezzati ad altri comandi
ed è quindi necessario gestirli -in ricezione- anche se non interessa l'informazione veicolata
6. i messaggi "cc parameter" da 0xb0 a 0xbf indicano i valori di eventuali controllers (continui o
discreti) come manopole o sliders che possono venire associati ad effetti: solo il contoller continuo
di codice 0 è standardizzato ed è la cosiddetta "modulation wheel"; tutti gli altri codici di parametro
controller sono proprietari e tendenzialmente diversi da macchina a macchina. I messaggi
parameter possono contenere ulteriori comandi valevoli per l'intero canale al quale si riferiscono
(aggiunti con questo trucco a quelli già esistenti):
codice
controller
Nome secondo byte di parametro
Co
ntr
oll
ers
ve
ri
e p
rop
ri,
sta
nd
ard
o
qu
asi
0x00 Bank select il banco strumenti da selezionare (0 per “General MIDI”)
0x01 Modulation
Wheel
la nuova impostazione di modulazione
0x07 Volume l’intensità di volume da impostare
0x40 Sustain 0 per pedale sustain non premuto, 127 per pedale premuto, indefinito
per qualsiasi altro valore (da ignorare)
Co
ntr
oll
ers
fit
tizi
, u
sati
co
me
com
an
di
ag
giu
nti
vi
0x7a local control 0 = local control off, 0x7f = on
indica ad esempio se una tastiera deve suonare gli eventi locali o quelli
inviati da remoto
0x7b all notes off 0
0x7c omni mode
off
0
0x7d omni mode
on
0
0x7e monophonic
mode
numero di canali monofonici o 0 per indicare un numero pari ai
riceventi
0x7f polyphonic
mode
0
in più, oltre al controller 0x7b, anche quelli da 0x7c a 0x7f silenziano ogni nota.
7. per semplicità di discorso, chiameremo "comandi" gli opcodes riferiti ad un canale (da 0x80 a 0xef),
"System Messages" (o SM) quelli da 0xf0 a 0xff e "dati" tutti gli altri valori
Giancarlo Todone - Progetto e realizzazione di un controller master MIDI Pagina 10
Analizziamo per esempio la seguente sequenza:
0x91 0x40 0x41
• 0x91 significa "Note-on sul canale 1"
• 0x40 = la nota da "accendere" è la numero 64 (il DO centrale delle tastiere)
• 0x41 = la "velocity" (assimilabile con l'intensità con cui suonare la nota)
Vediamo ora un'altra sequenza:
0x91 0x40 0x41 0x4c 0x30 0x40 0x00
• i primi tre bytes hanno lo stesso significato che nel precedente esempio: suonare il DO centrale a
un'intensità media
• il quarto byte è ancora un dato, quindi vale l'ultimo status byte ricevuto, ovvero 0x91; i byte 4 e 5
vogliono quindi dire "suona il DO un'ottava sopra il DO centrale a un'intensità lieve sul canale 1"
• i bytes sei e sette sono ancora dati, quindi vale ancora lo status byte 0x91 (note-on sul canale 1);
l'intensità però stavolta è 0, quindi bisogna interpretare il messaggio come "spegni
immediatamente il DO centrale"
Ed ecco un ultimo esempio di sequenza valida:
0x91 0x40 0xfe 0x41 0x4c 0x30 0xf0 0x01 0x02 0x03 0xf7 0x40 0x00
• La sequenza di eventi relativi ai canali è identica a prima, ma la sequenza è stata inframezzata da
messaggi di sistema (un "realtime message" e un "system exclusive")
• i dati inframezzati alla sequenza originale sono
o 0xfe = realtime message chiamato "active sensing" (qui non ha molto senso, ma serve a
fabbricare l'esempio)
o 0xf0 0x01 0x02 0x03 0xf7 = sequenza "system exclusive" a lunghezza variabile che trasporta
in questo caso il payload 0x01 0x02 0x03 (anche qui i dati inseriti sono a puro titolo
d'esempio)
• Si noti che il realtime message è inserito addirittura tra il primo e il secondo parametro del primo
comando "note-on".
Il software
Si è optato per un loop while infinito, nel quale ad ogni ciclo viene effettuata una lettura completa di tutti i
dispositivi: tutti i banchi di note “before”, tutti i banchi di note “after”, ingressi discreti (pedale) e analogici
(pitch-wheel).
while (1)
{
scanBeforeAndAfter();
readOtherInputs();
sendMIDIMessageAccordingly();
handleActiveSensing();
}
Giancarlo Todone - Progetto e realizzazione di un controller master MIDI Pagina 11
In un sottociclo, una variabile viene incrementata da 0 a 15 e riportata in output sui primi bits della porta
RD; ad ogni sottociclo, sugli otto ingressi di RB si leggono (invertendoli) i bit corrispondenti allo stato delle
otto note del banco selezionato. Tenendo traccia dei vecchi valori è possibile sapere quali switch sono
appena stati premuti o rilasciati:
void scanBeforeAndAfter()
{
for (i = 0; I < 16; ++i )
{
oldData[i] =newData[i]; // each bit contains on/off status of a switch;
newData[i] = ~PORTB; // 1 byte = 1 bank = 8 switches
justPressed[i] = ~ oldData[i] & newData[i];
justReleased[i] = oldData[i] & ~ newData[i];
}
}
L’algoritmo per il rilevamento della dinamica è semplice: vi sono 64 possibili note, e di conseguenza 64
misure dei tempi tra “before” e “after”; dunque sono allocati nella ram interna 64 bytes ognuno dei quali
memorizza il valore della velocity della nota corrispondente. Ogni valore di velocity viene inizializzato a 127
(massima velocity nello standard MIDI). Ad ogni ciclo, se lo switch “before” di una nota risulta chiuso, allora
decrementiamo la corrispondente velocity; se lo switch “after” è appena stato premuto, allora procediamo
a spedire un messaggio MIDI di note-on in cui la velocity è quella memorizzata; se lo switch “before” è
appena stato rilasciato, provvediamo a fabbricare e inviare un messaggio MIDI note-off e resettiamo la
corrispondente velocity a 127.
for (i = 0; i < 64; ++i)
{
if (pressedBefore[i]) // for sake of simplicity here we omit the code that translates index
--velocity[i]; // from bit mask to linear array
If (justPressedAfter[i])
sendNoteOn(i, velocity[i]);
if (justReleasedBefore[i])
{
sendNoteOff(i);
velocity[i] = 127;
}
}
Il precedentemente menzionato algoritmo di smussamento dei valori del pitch-bender viene implementato
come un controllore PID elementare in cui la parte integrativa sia posta a 0.
filteredValue = filteredValue + (value - filteredValue)*k, 0<k<1 (in questi casi solitamente piccolo)
Giancarlo Todone - Progetto e realizzazione di un controller master MIDI Pagina 12
Ovviamente per evitare fenomeni di accumulo dell’errore e aliasing sarebbe necessario usare dei numeri
reali; inoltre è necessario adattare le diverse dimensioni in bit: si è deciso di implementare questa funzione
con la tecnica fixed-point. L’ADC del PIC fornisce un numero intero non segnato a 10 bits, mentre il
protocollo MIDI richiede per il parametro del pitch-bender un numero intero non segnato a 14 bits,
entrambi ovviamente gestiti poi con interi non segnati a 16 bits che lasciano quindi spazio ad almeno 2 bits
per la parte frazionaria.
La lettura dello stato del pedale viene effettuata direttamente su uno degli ingressi digitali della porta C del
PIC (attualmente senza multiplazione): un meccanismo logico permette di gestire pedali dai contatti sia
normalmente aperti che normalmente chiusi (una lettura effettuata allo start-up prima di entrare nel ciclo
principale stabilisce la norma)
Come spiegato in precedenza, parte dei meccanismi del protocollo MIDI sono dedicati alla minimizzazione
del traffico di dati. La già descritta convenzione del “running status byte” prevede di evitare di reinviare due
comandi uguali che siano inframezzati solo da dati. A questo proposito, si è adottato un semplice
meccanismo che ricorda l’ultimo status byte inviato:
void sendCommand(cmd)
{
if (lastSB != cmd)
{
lastSB = cmd;
send(cmd);
}
activeSensingTimeout = 0
}
Nell’ultima riga si può notare l’azzeramento di una variabile che (contando semplicemente il numero di
cicli) permette di stabilire se è il caso o meno di inviare un “active-sense”, utile a segnalare la presenza e il
funzionamento del dispositivo quando non ci sono altri comandi da inviare per un certo tempo. Come
ultima operazione del nostro ciclo principale, infatti abbiamo:
++ activesensingTimeout;
if (activeSensingTimeout>300)
{
activesensingTimeout = 0;
send(activeSensingToken);
}
Giancarlo Todone - Progetto e realizzazione di un controller master MIDI Pagina 13
Conclusioni e possibili sviluppi
Collegando il dispositivo a degli analizzatori di protocollo MIDI (come per esempio un semplice terminale
che supporti il baudrate MIDI, o il progetto “FPGA_MIDI” sviluppato per il corso di elettronica II su board
Altera) si è proceduto a verificare che i messaggi vengono inviati correttamente.
Il dispositivo si comporta bene anche nelle prove pratiche, nelle quali si procede semplicemente a suonare
la tastiera e a far attenzione alle eventuali inesattezze di riproduzione del suono, come ritardi o veri e
propri errori. Per completare tale prova si è provveduto a collegare il circuito alla porta MIDI standard di un
PC (nel nostro caso tramite una scheda sonora Creative Sound Blaster Audigy Platinum) e ad eseguire un
semplice programma che traduca messaggi MIDI in suoni. Le latenze non sono avvertibili anche in casi
critici per il protocollo, come quello di molte pressioni simultanee e la risposta appare immediata,
dimostrando la semi-professionalità del dispositivo costruito; nonostante ciò, la pulsione al miglioramento
ci suggerisce eventuali modifiche apportabili al progetto. Una delle prime migliorie possibili sarebbe quella
di aumentare la velocità con la quale le scansioni si succedono: una prima idea potrebbe essere –date le
attuali ridotte dimensioni del codice eseguibile- quella di usare la tecnica dei loops “srotolati”. Il PIC 18F452
riesce a sostenere clock fino a 40 MHz, che sarebbe il doppio di quello attualmente in uso: ciò
permetterebbe di ravvicinare ulteriormente tra loro le scansioni e quindi migliorare la risposta della
dinamica. A tal proposito, la risposta dinamica del circuito è attualmente lineare, mentre è facile intuire che
allo scopo di simulare la forza di pressione, la velocity andrebbe distorta prima dell’invio, tramite -ad
esempio- una look-up table. La rotella del portamento andrebbe modificata in modo da azionare
direttamente un potenziometro, permettendo così di eliminare dal software il filtro, che è abbastanza time-
consuming. Al circuito andrebbero aggiunti pochi componenti passivi come resistenze limitatrici e un
condensatore di anti-bounce al fine di ridurre i –già minimi- consumi e garantire l’affidabilità. L’unico errore
non gestito del dispositivo, al momento, riguarda l’operatività in condizioni di alimentazione insufficiente
(es: batteria scarica): invece di smettere semplicemente di funzionare, il circuito comincia a commettere
errori di scansione, inviando messaggi pseudo-casuali. La cosa è eventualmente ovviabile con un minimo di
circuiteria esterna. Un ultima raffinatezza potrebbe essere quella di misurare la dimensione -in numero di
istruzioni- di ogni blocco condizionale, in modo da riempire di un numero adeguato di NOP uno dei due
rami di ogni istruzione condizionale, per fare in modo da avere cicli di tempo di esecuzione sempre
esattamente identico a se stesso (adesso sono presenti minime oscillazioni). Lo sviluppo di una board
dedicata permetterebbe di effettuare tests più seri ed eventualmente portare ad una produzione su medio-
piccola scala.
NB: progetti, schemi, immagini, foto, informazioni e codici sorgenti di Giancarlo Todone vengono rilasciati
con licenza Apache 2.0, a parte le informazioni sul protocollo MIDI 1.1 dedotte dall’ottimo documento “The
Usenet MIDI Primer” di Bob McQueer, facilmente reperibile in rete.
Giancarlo Todone - Progetto e realizzazione di un controller master MIDI Pagina 14