net.abumarkub.midi.MIDISequencer.java Source code

Java tutorial

Introduction

Here is the source code for net.abumarkub.midi.MIDISequencer.java

Source

/*!
 *  copyright 2012 abudaan http://abumarkub.net
 *  code licensed under MIT 
 *  http://abumarkub.net/midibridge/license
 * 
 *  
 *  Wrapper around the javax.sound.midi.Sequencer class 
 *  
 */
package net.abumarkub.midi;

import java.applet.AppletContext;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.net.MalformedURLException;
import java.net.URL;
import javax.sound.midi.*;
import netscape.javascript.JSObject;
import org.apache.commons.codec.binary.Base64;

public class MIDISequencer implements Receiver, MetaEventListener {

    private Sequence _sequence;
    private Sequencer _sequencer;
    private Transmitter _transmitter;
    private Transmitter _transmitter2;
    private Receiver _receiver;
    private AppletContext _context;
    private JSObject _jsMIDIEventListener;
    private JSObject _jsMetaEventListener;
    private boolean _hasMetaEventListener;

    public MIDISequencer(AppletContext context) {
        _context = context;

        try {
            _sequencer = javax.sound.midi.MidiSystem.getSequencer(false);

        } catch (MidiUnavailableException e) {
            System.out.println(e);
        }

        _receiver = null;
        _transmitter = null;
        _transmitter2 = null;
    }

    //sending messages from Java to Javascript is faster via AppletContext then via Live Connect
    private void sendMessageViaContext(String url) {
        try {
            _context.showDocument(new URL(url));
        } catch (MalformedURLException me) {
            System.out.println(me);
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    public boolean addEventListener(String id) {
        if (id.equals("midimessage")) {
            if (_transmitter == null) {
                try {
                    _transmitter = _sequencer.getTransmitter();
                } catch (MidiUnavailableException e) {
                    System.out.println("Sequencer could not open a transmitter " + e);
                    return false;
                }
            }
            _transmitter.setReceiver(this);
            return true;
        } else if (id.equals("metamessage")) {
            if (!_hasMetaEventListener) {
                _hasMetaEventListener = _sequencer.addMetaEventListener(this);
            }
            return true;
        }
        return false;
    }

    //@TODO: currently you can connect only 1 eventlistener!
    public boolean addEventListener(String id, JSObject eventListener) {

        if (id.equals("midimessage")) {
            if (_transmitter == null) {
                try {
                    _transmitter = _sequencer.getTransmitter();
                } catch (MidiUnavailableException e) {
                    System.out.println("Sequencer could not open a transmitter " + e);
                    return false;
                }
            }
            _jsMIDIEventListener = eventListener;
            _transmitter.setReceiver(this);
            return true;
        } else if (id.equals("metamessage")) {
            if (!_hasMetaEventListener) {
                _hasMetaEventListener = _sequencer.addMetaEventListener(this);
            }
            _jsMetaEventListener = eventListener;
            return true;
        }
        return false;
    }

    public Sequence loadBase64String(String data) {
        _sequence = null;
        byte[] decoded = Base64.decodeBase64(data);
        ByteArrayInputStream input = new ByteArrayInputStream(decoded);
        try {
            _sequence = javax.sound.midi.MidiSystem.getSequence(input);
            loadSequence(_sequence);

        } catch (Exception e) {
            System.out.println("loading: " + e);
        }
        return _sequence;
    }

    public Sequence playBase64String(String data) {
        loadBase64String(data);
        play();
        return _sequence;
    }

    public Sequence loadMidiFile(String url) {
        FileInputStream is = null;
        _sequence = null;

        try {
            //System.out.println("loadMidiFile: " + url);
            is = new FileInputStream(url);
            //} catch (FileNotFoundException e) {
        } catch (Exception e) {
            System.out.println(e);
        }
        try {
            _sequence = javax.sound.midi.MidiSystem.getSequence(is);
            loadSequence(_sequence);

        } catch (Exception e) {
            System.out.println(e);
        }
        return _sequence;
    }

    public Sequence playMidiFile(String url) {
        loadMidiFile(url);
        play();
        return _sequence;
    }

    public void close() {
        if (_sequencer.isOpen()) {
            _sequencer.stop();
            _sequencer.close();
        }
        if (_transmitter != null) {
            _transmitter.close();
        }
        if (_transmitter2 != null) {
            _transmitter2.close();
        }
        if (_receiver != null) {
            _receiver.close();
        }
    }

    private void loadSequence(Sequence seq) {
        try {
            _sequencer.open();
        } catch (MidiUnavailableException e) {
            System.out.println(e);
        }
        try {
            _sequencer.setSequence(seq);
        } catch (InvalidMidiDataException e) {
            System.out.println(e);
        }
    }

    public void send(MidiMessage message, long timeStamp) {
        //System.out.println("MidiMessage: " + message + " " + timeStamp);
        timeStamp = _sequencer.getMicrosecondPosition();
        if (message instanceof ShortMessage) {

            ShortMessage tmp = (ShortMessage) message;
            MIDIMessage msg = new MIDIMessage(tmp, timeStamp);

            //@TODO: loop over all event listeners, check if they want to be updated via AppletContext or Live Connect, and dispatch to all

            if (1 == 2) {//just a way of ignoring the AppletContext send method
                String jsMsg = msg.command + "," + msg.channel + "," + msg.data1 + "," + msg.data2 + "," + timeStamp
                        + ",'" + msg.toString() + "'";
                sendMessageViaContext("javascript:midiBridge.onSequencerMIDIData(" + jsMsg + ")");
            } else {//currently sending via Live Connect is preferred
                Object[] args = { msg };
                _jsMIDIEventListener.call("listener", args);
            }
        }
    }

    //@TODO: loop over all event listeners, check if they want to be updated via AppletContext or Live Connect, and dispatch to all
    public void meta(MetaMessage meta) {
        if (1 == 2) {//just a way of ignoring the AppletContext send method
            StringBuilder jsMsg = new StringBuilder();
            jsMsg.append(meta.getType());
            jsMsg.append(",");
            jsMsg.append(meta.getStatus());

            byte[] message = meta.getMessage();
            for (int i = 0, maxi = message.length; i < maxi; i++) {
                jsMsg.append(",");
                jsMsg.append(message[i]);
            }

            sendMessageViaContext("javascript:midiBridge.sequencerMetaData(" + jsMsg.toString() + ")");
        } else {//currently sending via Live Connect is preferred
            Object[] args = { meta };
            _jsMetaEventListener.call("listener", args);
        }

    }

    public Sequence getSequence() {
        return _sequence;
    }

    public boolean setDirectOutput(MIDIDevice device) {

        System.out.println("setDirectOutput: " + device.deviceName);

        if (_receiver != null) {
            _receiver.close();
        }

        _receiver = device.getReceiver();
        if (_receiver == null) {
            return false;
        }

        if (_transmitter2 == null) {
            try {
                _transmitter2 = _sequencer.getTransmitter();
            } catch (MidiUnavailableException e) {
                System.out.println("Sequencer could not open a transmitter " + e);
                return false;
            }
        }
        _transmitter2.setReceiver(_receiver);

        return true;
    }

    public void removeDirectOutput() {
        if (_transmitter2 != null) {
            _transmitter2.close();
        }
        if (_receiver != null) {
            _receiver.close();
        }
        _transmitter2 = null;
        _receiver = null;
    }

    public boolean hasDirectOutput() {
        return _receiver != null;
    }

    //composition:
    public void play() {
        if (_sequencer.isOpen()) {
            _sequencer.start();
        }
    }

    public void pause() {
        if (_sequencer.isOpen()) {
            _sequencer.stop();
        }
    }

    public void stop() {
        if (_sequencer.isOpen()) {
            _sequencer.setMicrosecondPosition(0L);
            _sequencer.stop();
        }
    }

    public Long getMicrosecondPosition() {
        return _sequencer.getMicrosecondPosition();
    }

    public void setMicrosecondPosition(int pos) {
        _sequencer.setMicrosecondPosition(Long.parseLong("" + pos));
    }

    public float getTempoInBPM() {
        return _sequencer.getTempoInBPM();
    }

    public void setTempoInBPM(int bpm) {
        _sequencer.setTempoInBPM(Float.parseFloat("" + bpm));
    }

    public float getTempoFactor() {
        return _sequencer.getTempoFactor();
    }

    public void setTempoFactor(float factor) {
        _sequencer.setTempoFactor(factor);
    }

    public void muteTrack(int index) {
        _sequencer.setTrackMute(index, true);
    }

    public void unmuteTrack(int index) {
        _sequencer.setTrackMute(index, false);
    }

    //@TODO: implemented this
    public void createNewSequence() {
        //_sequence = new Sequence();
        _sequence.getMicrosecondLength();
        _sequence.getTickLength();
    }
}