Presentazione - Luca Andrea Ludovico

Lezione 20
Dispositivi MIDI in Java
Programmazione MIDI (Prof. Luca A. Ludovico)
Introduzione
• Nella lezione precedente è stata introdotta la logica di
descrizione di dati MIDI da parte del package
• Tipicamente i dati vengono scambiati tra dispositivi
– Ad esempio, un programma può generare messaggi MIDI da
zero, ma spesso questi vengono creati da un sequencer o
ricevuti su una porta MIDI In
– Di solito poi i messaggi vengono inviati a un altro dispositivo,
quale un sintetizzatore o una porta MIDI Out
• In Java si creano allo scopo oggetti software che
implementano l’interfaccia MidiDevice
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
Interfaccia MidiDevice
• Usata per definire oggetti software in grado di inviare
e/o ricevere messaggi MIDI
• Può presentare un’implementazione software pura o
fungere come interfaccia per le porte MIDI di una
scheda audio (hardware)
• Cos’è un’interfaccia Java? Un’interfaccia (interface)
ha una struttura simile a una classe, ma può
contenere solo metodi astratti e costanti (quindi non
può contenere costruttori, variabili statiche, variabili
di istanza e metodi statici).
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
Interfaccia MidiDevice
• L’interfaccia MidiDevice fornisce tutte le funzionalità
genericamente richieste da dispositivi di sequencing,
sintetizzatori, porte MIDI di ingresso e uscita
– Esistono sotto-interfacce più specifiche di MidiDevice, che
ereditano da tale interfaccia: Synthesizer e Sequencer
• L’interfaccia MidiDevice include metodi per “aprire” e
“chiudere” un dispositivo
• Include inoltre la classe interna MidiDevice.Info che
fornisce descrizioni in formato stringa del dispositivo,
tra cui il nome del modello, il produttore e la versione
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
Trasmettitori e ricevitori
• Un MidiDevice può essere un trasmettitore di eventi
MIDI, un ricevitore o entrambe le cose. Dunque
MidiDevice deve mettere a disposizione istanze delle
interfacce Transmitter o Receiver o entrambe.
• Tipicamente:
– le porte MIDI IN presentano trasmettitori (vedi slide succ.)
– le porte MIDI OUT e i sintetizzatori presentano ricevitori
– i sequencer mettono a disposizione trasmettitori per il
playback e ricevitori per le operazioni di registrazione
DeviceInfo.java
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
Porte e trasmettitori/ricevitori
Catena
MIDI
MIDI IN
•Riceve da
catena MIDI
e trasmette
al software
Software
•Riceve da
MIDI IN e
trasmette a
MIDI OUT
MIDI
OUT
•Riceve dal
software e
trasmette a
catena MIDI
Catena
MIDI
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
Paradigma di ricezione e trasmissione
• In che modo un dispositivo invia i dati MIDI? Tramite
uno o più trasmettitori
• In che modo un dispositivo riceve i dati MIDI? Tramite
uno o più ricevitori
• Ogni trasmettitore può essere connesso a un solo
ricevitore alla volta, ma non viceversa
– Se un dispositivo deve inviare messaggi MIDI a più dispositivi
contemporaneamente, deve avere più trasmettitori
– Se un dispositivo deve poter ricevere messaggi MIDI da più
mittenti simultaneamente, può (non deve) avere più ricevitori
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
Esempi
Porta MIDI In
Trasmettitore
Synth
Messaggio MIDI
Midi Out 1
Sequencer
Trasmettitore 1
Trasmetttitore 2
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
Ricevitore
Messaggio MIDI
Messaggio MIDI
Ricevit
Midi Out 2
Ricevitore
Esempio
Ricevitore
1
Ricevitore
2
Ricevitore
Ricevitore
3
Sintetizzatore
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
Sintetizzatore
Sequencer
public interface Sequencer extends MidiDevice
• Un sequencer è un dispositivo che cattura ed esegue
sequenze di eventi MIDI.
– Può ad esempio caricare una sequenza da un file MIDI,
interrogarne e impostarne il tempo e sincronizzare altri
dispositivi
• Possiede trasmettitori, in quanto è in grado di inviare i
messaggi salvati in una sequenza ad altri dispositivi
(synth, MIDI OUT).
• Possiede ricevitori in quanto è in grado di catturare
messaggi MIDI e salvarli in una sequenza.
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
Sintetizzatori
public interface Synthesizer extends MidiDevice
• I sintetizzatori sono gli unici oggetti nel
package javax.sound.midi in grado di produrre audio
• Ogni sintetizzatore controlla un insieme di 16 oggetti
“canale MIDI”, ciascuno istanza
dell’interfaccia MidiChannel
• Un’applicazione può generare suono invocando
direttamente i metodi degli oggetti “canale MIDI” di un
sintetizzatore. Il caso più comune però è che un
sintetizzatore generi suono in risposta ai messaggi inviati ai
suoi ricevitori (vedi più avanti).
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
Strumenti
• Il sintetizzatore valuta i messaggi che giungono ai suoi
ricevitori e quindi invia i comandi corrispondenti (ad es.
Note On o Control Change) a uno dei propri oggetti
MidiChannel sulla base del numero di canale specificato
nell’evento.
• Per generare audio però serve informazione aggiuntiva: lo
strumento associato al canale. Lo si fa tramite la classe
astratta Instrument.
• Il sintetizzatore deve caricare uno strumento e associarlo a
uno o più canali tramite un comando di Program Change. Da
quel momento le note inviate a quei canali verranno
sintetizzate con lo strumento.
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
SINTESI DEL SUONO IN JAVA
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
Introduzione
• Molti software Java che si avvalgono del package hanno
l’obiettivo di generare suono.
L’apparato fin qui descritto, composto da:
–
–
–
–
–
messaggi
eventi (messaggi temporizzati)
tracce (insiemi di eventi)
sequenze (insiemi di tracce)
sequencer (oggetti che manipolano tracce)
quasi sempre ha lo scopo di inviare dati musicali a un
sintetizzatore che li tradurrà in segnali audio.
• Esistono eccezioni: ad esempio, programmi che visualizzano dati
MIDI in formato testuale, o software che li convertono in
notazione musicale, o che li inviano a dispositivi esterni tramite
porte MIDI.
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
L’interfaccia Synthesizer
• In questa parte della lezione si mostrerà come gestire
un sintetizzatore per far suonare eventi MIDI.
• Esistono diversi approcci:
1. Utilizzare un sequencer per inviare dati MIDI al sintetizzatore,
eventualmente caricandoli da un file MIDI o generando direttamente
la sequenza (vedi lezione precedente);
2. Controllare il sintetizzatore in modo diretto, senza passare
attraverso sequencer;
3. Usare direttamente oggetti MidiMessage.
• I diversi approcci verranno trattati separatamente.
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
L’architettura per la sintesi del suono
• L’architettura include tre interfacce:
1. Synthesizer
2. MidiChannel
3. Soundbank: concetto introdotto dall’API Java come ulteriore livello
gerarchico. I soundbank possono contenere fino a 128 bank, ciascuno
contenente fino a 128 strumenti
e quattro classi:
1. Instrument: una specifica per sintetizzare un certo tipo di suono. In GM si
definiscono 128 strumenti standard
2. Patch
3. SoundbankResource
4. VoiceStatus: dà informazioni sullo stato corrente (attivo o inattivo) della
voce, sul canale MIDI, sul numero di bank e di programma associati, sul
numero di nota MIDI e sul volume
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
Synthesizer e sequencer di default
Sequencer mioSequencer = MidiSystem.getSequencer();
Synthesizer mioSynth = MidiSystem.getSynthesizer();
Per elencare tutti i dispositivi installati:
MidiDevice.Info[] devices = MidiSystem.getMidiDeviceInfo();
for (MidiDevice.Info info: devices)
{
...
}
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
Caricamento di strumenti
• Per conoscere gli strumenti attualmente caricati nel
sintetizzatore si può invocare il metodo di Synthesizer
Instrument[] getLoadedInstruments()
• Per conoscere gli strumenti caricabili dal soundbank corrente
Instrument[] getAvailableInstruments()
• Per conoscere il nome dei singoli strumenti, si utilizza il metodo
getName() di Instrument
• Il metodo di Synthesizer che restituisce il soundbank di default è
Soundbank getDefaultSoundbank()
• Anche in questo caso, l’interfaccia Soundbank include metodi per
recuperare il nome, il produttore, il numero di versione, ecc.
SynthInfo.java
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
Approccio 1: uso di sequencer
• In molti casi, un programma può utilizzare un oggetto
Synthesizer quasi senza invocare metodi per la sintesi
– E’ possibile creare una sequenza manualmente o caricarla da
un file MIDI all’interno di un oggetto Sequence. Tale oggetto
viene poi caricato da un sequencer, che manda i dati al
sintetizzatore di default.
• Come ottenere il sequencer di default? Usando un
metodo statico di MidiSystem:
static Sequencer getSequencer()
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
Approccio 1: uso di sequencer
• Ottenere il sequencer di default, acquisire le risorse di
sistema richieste e renderlo operativo:
Sequencer mioSequencer;
mioSequencer = MidiSystem.getSequencer();
if (mioSequencer == null)
{
// Errore - dispositivo sequencer non supportato
}
else
{
mioSequencer.open();
}
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
Approccio 1: uso di sequencer
• Leggere una sequenza da file: si usa il metodo getSequence
di MidiSystem, in grado (tramite overload) di caricare una
sequenza da InputStream, File, o URL. Il metodo restituisce un
oggetto Sequence che può essere caricato in un Sequencer
try
{
File mioMidiFile = new File("seq1.mid");
Sequence miaSeq = MidiSystem.getSequence(mioMidiFile);
mioSequencer.setSequence(miaSeq);
}
catch (Exception e)
{
// Gestione dell’errore
}
CaricaSequenzaDaFile.java
CaricaSequenzaDaUrl.java
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
Playback di una sequenza
• Metodi principali invocabili su oggetti Sequencer:
void start()
avvia l’esecuzione
void stop()
mette in pausa l’esecuzione
• Il metodo setSequence inizializza la posizione corrente
del sequencer all’inizio della sequenza
• Tra i metodi per il riposizionamento:
void setMicrosecondPosition(long microseconds)
void setTickPosition(long tick)
• Descrizione completa della classe Sequencer:
http://docs.oracle.com/javase/7/docs/api/javax/sound/midi/Sequencer.html
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java
Ulteriori esempi
• Nel file ZIP della lezione corrente sono state incluse delle varianti
agli esercizi sopra commentati
• SynthInfo2.java dà informazioni su tutti i sintetizzatori trovati nel
sistema, non solo su quello di default
– Per farlo, si cicla su tutti i MidiDevice e si filtrano i risultati tramite
l’istruzione if (device instanceof Synthesizer)
• CaricaSequenzaDaFile2.java permette di scegliere quale traccia
ascoltare tra quelle di un MIDI file
– Se il file è di tipo 1, di solito la 1a traccia è riservata ai metadati e
non contiene informazione audio
– Per farlo si accede alla struttura dati
Track[] tracks = miaSeq.getTracks();
e si eliminano tutte le tracce diverse da quella scelta
Programmazione MIDI (Prof. Luca A. Ludovico)
20. Dispositivi MIDI in Java