Post on 07-Apr-2016
O Pacote Java MIDI
Roteiro Principais Classes e Interfaces do Pacote MIDI
Acessando Recursos MIDI
Carregando Seqüências MIDI
Transmitindo e Recebendo Mensagens MIDI
Gravando e Editando Seqüências MIDI
Recursos Avançados de Sequencer
Sintetizando Som
Principais Classes e Interfaces do Pacote MIDI
Classe MidiMessage MidiMessage é uma classe abstrata que representa
uma mensagem MIDI pura;
Possui três subclasses: ShortMessages : tipo mais comum, possui um byte de
status e no máximo dois de dados (Ex.: Note On);
SysexMessages: podem possuir muito bytes e contém instruções especificas do fabricante;
MetaMessages: ocorre apenas em arquivos MIDI, contem, por exemplo, configurações de tempo;
Classe MidiEvent MidiEvent é uma classe que engloba mensagens
MIDI puras junto com informação de tempo;
A classe MidiEvent possui métodos para especificar e também obter informação de timestamp:
long getTick () void setTick (long tick)
Classe Sequence
Sequence representa uma composição musical que pode ser lida de um arquivo ou criada em tempo real;
É composto por uma coleção de Tracks onde estão armazenados os MidiEvents;
SequenceTracks
MidiEvents
Interface MidiDevice
Objetos que implementem a interface MidiDevice são capazes de enviar e receber mensagens MIDI;
Possui métodos para abrir e fechar um dispositivo;
Inclui uma classe interna, MidiDevice.Info, que fornece uma descrição textual do dispositivo;
Interfaces Transmitter e Receiver
Dispositivos MIDI possuem objetos transmissores e objetos receptores;
Objetos transmissores implementam a interface Transmitter e objetos receptores implementam a interface Receiver;
Interface Sequencer Um sequenciador é um dispositivo para
captura e execução de seqüências de eventos MIDI;
Normalmente, possui tanto transmissores quanto receptores;
Sequenciadores implementam a interface Sequencer que é uma subinterface de MidiDevice;
Interface Synthesizer Sintetizadores implementam a interface
Synthesizer (subinterface de MidiDevice);
Um sintetizador possui canais, representados por objetos que implementem a interface MidiChannel;
Normalmente um sintetizador gera sons em resposta a mensagens enviadas aos seus receptores;
Acessando Recursos MIDI
Classe MidiSystem Assim como a classe AudioSystem, permite
descobrir e acessar os dispositivos instalados no sistema;
Permite obter os seguintes recursos: Sequenciadores; Sintetizadores; Transmissores; Receptores; Dados a partir de arquivos MIDI; Dados a partir de arquivos de soundbank;
Obtendo Dispositivos Padrões
Uma aplicação típica inicia obtendo os dispositivos necessários (sequenciadores, sintetizadores, etc.);
A classe MidiSystem inclui métodos para obter dispositivos padrão:
static Sequencer getSequencer (); static Synthesizer getSynthesizer (); static Receiver getReceiver (); static Transmitter getTransmitter ();
Obtendo Dispositivos Instalados
A classe MidiSystem possui um método para obter informações sobre os dispositivos instalados:static MidiDevice.Info[] getMidiDeviceInfo ()
Para obter um dispositivo deve-se utilizar o método:static MidiDevice getMidiDevice (MidiDevice.Info
info)
Exemplo 1: Obtendo os sintetizadores instalados
Vector synthInfo;MidiDevice device;MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo ();
for (int i = 0; i < infos.length; i++) {try {
device = MidiSystem.getMidiDevice (infos[i]);} catch (MidiUnavailableException e) {
// tratar ou throw a exceção}if (device instanceof Synthesizer) {
synthInfos.add (infos[i]);}
}
Abrindo Dispositivos
Para reservar um dispositivo : método open() da interface MidiDevice:
if (!device.isOpen ()) {try { device.open ();} catch (MidiUnavailableException e) { // tratar ou throw a exceção}
}
Carregando Seqüências MIDI
Carregando um Arquivo MIDI Duas maneiras:
Carregar um arquivo MIDI em um InputStream e depois usar:Sequencer.setSequence (InputStream stream)
Criar, explicitamente, um objeto Sequence e depois carregá-lo em um Sequencer (Necessário quando se deseja editar uma seqüência MIDI)
Exemplo 2: Criando e Carregando um Objeto Sequence
try {File midiFile = new File (“seq1.mid”);Sequence seq = MidiSystem.getSequence (midiFile);sequencer.setSequence (seq);
} catch (Exception e) {// tratar ou throw a exceção
}
Transmitindo e Recebendo Mensagens MIDI
Dispositivos, Receptores e Transmissores
Diferentes MidiDevice podem ser interconectados possibilitando que dados fluam entre eles;
MidiDevice possui um ou mais objetos auxiliares que implementam as interfaces Transmitter ou Receiver;
Cada transmissor só pode ser conectado a um receptor e vice-versa;
Conectando-se a um Dispositivo
A interface Transmitter possui um método que permite estabelecer a conexão com o Receiver para o qual serão enviadas as mensagens:void setReceiver (Receiver receiver)
Após terminada a conexão deve-se invocar o método close() de Transmitter e Receiver para que os mesmos sejam liberados;
Exemplo 2: Conectando um Sequenciador a um Sintetizador
Sequencer seq;Transmitter seqTrans;Synthesizer synth;Receiver synthRcvr;
try {seq = MidiSystem.getSequencer ();seqTrans = seq.getTransmitter ();synth = MidiSystem.getSynthesizer ();synthRcvr = synth.getReceiver ();seqTrans.setReceiver (synthRcvr);
} catch (MidiUnavailableException e) {// tratar ou throw a exceção
}
Exercício 1 Abrir e tocar um arquivo MIDI;
Como enviar a mesma mensagem para diferentes dispositivos ?
Basta usar mais de um transmissor e mais de um receptor;
MidiDevice possui métodos para descobrir quantos transmissores e receptores um dispositivo suporta:int getMaxTransmitters ()int getMaxReceivers ()
Exemplo 3: Conectando um Porta de Entrada a um Sequenciador e a um Sintetizador
Sequencer seq;Synthesizer synth;MidiDevice inputPort;// Obter e abrir os três dispositivosTransmitter inPortTrans1, inPortTrans2;Receiver synthRcvr, seqReceiver;
try {inPortTrans = inputPort.getTransmitter ();synthRcvr = synth.getReceiver ();inPortTrans1.setReceiver (synthRcvr);inPortTrans2 = inputPort.getTransmitter ();seqRcvr = seq.getReceiver (); inPortTrans2.setReceiver (seqRcvr);
} catch (MidiUnavailableException e) {// tratar ou throw a exceção
}
Quando Usar um Sequenciador É possível enviar mensagens MIDI diretamente
para um dispositivo sem usar um sequenciador;
Essa técnica pode ser utilizada quando o próprio programa cria as mensagens em tempo real;
Ex.: Programa que simula um piano
Sequenciadores são utilizados para lidar com dados lidos de um arquivo MIDI e também para gravar dados MIDI;
Enviando Mensagem para um Receptor sem Usar um Transmissor
A interface Receiver contém um método que envia mensagens para o receptor:void send (MidiMessage message, long timeStamp)
Criar um objeto ShortMessage e usar o método:Void setMessage (int command, int channel,
int data1, int data2)
Exemplo 4: Enviando uma Mensagem sem Usar um Transmissor
ShortMessage msg = new ShortMessage ();// Tocar a nota Middle C (60) com velocidade = 93
msg.setMessage (ShortMessage.NOTE_ON, 0, 60, 93);long timeStamp = -1;Receiver rcvr = MidiSystem.getReceiver ();Rcvr.send (msg, timeStamp);
Exercício 2 Enviar mensagens MIDI
diretamente para um sintetizador sem usar um Sequenciador
Roteiro Principais Classes e Interfaces do Pacote MIDIPrincipais Classes e Interfaces do Pacote MIDI
Acessando Recursos MIDIAcessando Recursos MIDI
Carregando Seqüências MIDICarregando Seqüências MIDI
Transmitindo e Recebendo Mensagens MIDITransmitindo e Recebendo Mensagens MIDI
Gravando e Editando Seqüências MIDI
Recursos Avançados de Sequencer
Sintetizando Som
Gravando e Editando Seqüências MIDI
Tracks Arquivos MIDI são organizados em tracks;
Normalmente cada track contem as notas de um único instrumento (não é obrigado pelo padrão);
Arquivos MIDI são organizados em uma hierarquia de três níveis:
Sequence; Track; MidiEvents;
SequenceTracks
MidiEvents
MidiEvents e Ticks Em um MidiEvent o tempo é expresso tendo como base
o conceito de tick;
A duração de um tick varia de acordo com a sequência MIDI e seu valor é armazenado no cabeçalho de um arquivo MIDI;
O tamanho de um tick pode ser dado em duas unidades: Pulsos por quarto de nota (PPQ) Ticks por frame (SMPTE)
Na API Java os valores de tick medem tempo cumulativo;
Gravando e Salvando Sequences (1/2)1. Obtenha um Sequencer através de MidiSystem;
2. Estabeleça a conexão entre o Sequencer e o objeto que transmitirá as mensagens MIDI;
3. Crie um novo objeto Sequence:Sequence (float divisionType, int resolution )Sequence (float divisionType, int resolution,
int numTracks )
4. Crie um objeto Track caso isso não seja feito no construtor:
Sequence.createTrack();
Gravando e Salvando Sequences (2/2)
5. Relacione o objeto Sequence criado com o Sequencer usado:Sequencer.setSequence(Sequence sequence)
6. Chame o método Sequencer.recordEnable ();
7. Chame o método Sequence.startRecording ();
8. Quando terminar, chame Sequencer.stop () ou Sequencer.stopRecording ();
9. Salve o objeto Sequence gravado usando MididSystem.write();
Editando uma Seqüência
Objetos do tipo Sequence permitem que sejam adicionados ou removidos Tracks:
Track createTrack () Boolean deleteTrack (Track track)
As Tracks são armazenadas em um objeto Sequence através de um Vector;
Editando uma Seqüência Os MidiEvents contidos em uma Track também
são armazenados em um Vector;
Os métodos de Track são: boolean add (MidiEvent event) MidiEvent get (int index) boolean remove (MidiEvent event) int size () long ticks ()
Exercício 3 Criar alguns eventos MIDI, com
mensagens Note On e Note Off, e gravá-los em um SMF (Usar PPQ com, por exemplo, resolução 12;
Recursos Avançados de Sequencer
Posição de uma Sequence Obtendo a posição corrente do Sequencer em
um Sequence: Long getTickPosition () Long getMicrosecondPosition ()
Movendo para um ponto arbitrário em um objeto Sequence:
void setTickPosition (long Tick) void setMicrosecondPosition (long
microsecond)
Mudando a Velocidade de Execução
A velocidade de uma seqüência é indicada pelo seu tempo;
Pode-se mudar o tempo de uma seqüência através de eventos MIDI ou através da chamada de métodos de Sequencer:
void setTempoInBPM (float bpm) void setTempoInMPQ (float mpq) void setTempoFactor (float factor)
Mute e Solo em Tracks Pode-se escolher que Tracks irão contribuir para o
stream de mensagens MIDI gerados pelo Sequencer;void setTrackMute (int track, boolean mute)void setTrackSolo (int track, boolean solo)
Para verificar o status de uma Track: boolean getTrackMute (int track) boolean getTrackSolo (int track)
Sincronizando com Outros Dispositivos
Sequencer possui uma classe interna Sequencer.SyncMode que representa os modos como um Sequencer pode ser sincronizado;
Um Sequencer pode ser sincronizado como Master e/ou Slave:
void setMasterSyncMode (Sequencer.SyncMode sync) void setSlaveSyncMode (Sequencer.SyncMode sync)
Listeners par Eventos Especiais Especificando Listeners para eventos especiais:
Int[] addControllerEventListener (ControllerEventListener listener, int[]
controllers)
Boolean addMetaEventListener (MetaEventListener listener)
Exercício 4 Alterar o tocador MIDI de modo que seja
possível executar Mute e Solo em Tracks especificas;
Sintetizando Som
A Síntese de Sons em Java A arquitetura para síntese de sons em Java é
composta de três interfaces Synthesizer MidiChannel Soundbank
E quatro classes: Instrument Patch SoundbankResource VoiceStatus
Verificando Quais Instrumentos Estão Carregados
Para carregar o Soundbank padrão deve-se usar o seguinte método de Synthesizer:
Soundbank getDefaultSoundbank ()
Para descobrir quais instrumentos estão atualmente carregados deve-se usar o seguinte método de Synthesizer:
Instrument[] getLoadedInstruments()
Carregando Instrumentos Para descobrir quais instrumentos pertencem
ao Sintetizador:Instrument[] getAvailableInstruments ()
Um instrumento pode ser carregado usando:boolean loadInstrument (Intrument instrument)
O instrumento será carregado na posição especificada pelo seu objeto Patch;
Carregando Instrumentos Cada objeto do tipo Instrument possui um objeto Patch que
especifica onde o instrumento deverá ser carregado;
Esse local é definido pelo número do banco e número do programa;
É possível carregar o instrumento em um outro local através do seguinte método de Synthesizer:
boolean remapIntrument (Intrument from, Instrument to)
Descarregando Instrumentos
Existem três métodos para descarregar instrumentos:
void unloadAllInstruments (Soundbank soundbank)
void unloadInstrument(Instrument instrument)
void unloadInstruments(Soundbank soundbank, Patch[] patchList)
Acessando Canais Existem 2 maneiras para controlar o
sintetizador sem usar um sequenciador:
Como já foi visto, pode-se enviar uma mensagem diretamente a um receptor do sintetizador através do método send ();
Outra opção seria interagir diretamente com objetos MidiChannel;
Exemplo 6: Exemplo 4 Usando Canais
Synthesizer synth = MidiSystem.getSynthesizer ();// Obtem todos os canais do sintetizadorMidiChannel chan[] = synth.getChannels ();
// Checa se o canal existeif (chan[4] != null) {
chan[4].noteOn (60, 93);}
Mute e Solo em Canais A API Java Sound adiciona a noção de Solo e
Mute por canais;
Essa operação é similar as de Mute e Solo para Tracks;
São fornecidos quatro métodos: boolean getMute () boolean getSolo () void setMute (boolean muteState) void setSolo (boolean soloState)
Alterando o Instrumento de um Canal
Para descobrir qual o instrumento atualmente alocado a um canal deve-se usar:int getProgram ()
Para modificar o instrumento associado:void programChange (int program)
OBS.: Instrumento deve estar carregado no sintetizador !
Exercício 5 Enviar mensagens Note On e Note Off
diretamente para o canal de um sintetizador (sem usar MidiMessages). Permitir também a mudança de Instrumentos;