
com.github.trilarion.share.midi.TMidiDevice Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vorbis-support Show documentation
Show all versions of vorbis-support Show documentation
Vorbis SPI support. Combination of JOrbis, JavaSPI and Tritonus-Share.
/*
* TMidiDevice.java
*
* This file is part of Tritonus: http://www.tritonus.org/
*/
/*
* Copyright (c) 1999 - 2006 by Matthias Pfisterer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
|<--- this code is formatted to fit into 80 columns --->|
*/
package com.github.trilarion.share.midi;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MetaMessage;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiMessage;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Receiver;
import javax.sound.midi.Transmitter;
import com.github.trilarion.share.TDebug;
/** Base class for MidiDevice implementations.
* The goal of this class is to supply the common functionality for
* classes that implement the interface MidiDevice.
*/
public abstract class TMidiDevice
implements MidiDevice
{
/** The Info object for a certain instance of MidiDevice.
*/
private MidiDevice.Info m_info;
/** A flag to store whether the device is "open".
*/
private boolean m_bDeviceOpen;
/** Whether to handle input from the physical port
and to allow Transmitters.
*/
private boolean m_bUseTransmitter;
/** Whether to handle output to the physical port
and to allow Receivers.
*/
private boolean m_bUseReceiver;
/** The list of Receiver objects that belong to this
* MidiDevice.
*
* @see #addReceiver
* @see #removeReceiver
*/
private List m_receivers;
/** The list of Transmitter objects that belong to this
* MidiDevice.
*
* @see #addTransmitter
* @see #removeTransmitter
*/
private List m_transmitters;
/** Initialize this class.
* This sets the info from the passed one, sets the open status
* to false, the number of Receivers to zero and the collection
* of Transmitters to be empty.
*
* @param info The info object that describes this instance.
*/
public TMidiDevice(MidiDevice.Info info)
{
this(info, true, true);
}
/** Initialize this class.
* This sets the info from the passed one, sets the open status
* to false, the number of Receivers to zero and the collection
* of Transmitters to be empty.
*
* @param info The info object that describes this instance.
*/
public TMidiDevice(MidiDevice.Info info,
boolean bUseTransmitter,
boolean bUseReceiver)
{
m_info = info;
m_bUseTransmitter = bUseTransmitter;
m_bUseReceiver = bUseReceiver;
m_bDeviceOpen = false;
m_receivers = new ArrayList();
m_transmitters = new ArrayList();
}
/** Retrieves a description of this instance.
* This returns the info object passed to the constructor.
*
* @return the description
*
* @see #TMidiDevice
*/
public MidiDevice.Info getDeviceInfo()
{
return m_info;
}
public synchronized void open()
throws MidiUnavailableException
{
if (TDebug.TraceMidiDevice) { TDebug.out("TMidiDevice.open(): begin"); }
if (! isOpen())
{
openImpl();
/* If openImpl() throws a MidiUnavailableException, m_bDeviceOpen
* remains false.
*/
m_bDeviceOpen = true;
}
if (TDebug.TraceMidiDevice) { TDebug.out("TMidiDevice.open(): end"); }
}
/**
* Subclasses have to override this method to be notified of
* opening.
*/
protected void openImpl()
throws MidiUnavailableException
{
if (TDebug.TraceMidiDevice) TDebug.out("TMidiDevice.openImpl(): begin");
if (TDebug.TraceMidiDevice) TDebug.out("TMidiDevice.openImpl(): end");
}
public synchronized void close()
{
if (TDebug.TraceMidiDevice) { TDebug.out("TMidiDevice.close(): begin"); }
if (isOpen())
{
closeImpl();
// TODO: close all Receivers and Transmitters
m_bDeviceOpen = false;
}
if (TDebug.TraceMidiDevice) { TDebug.out("TMidiDevice.close(): end"); }
}
/**
* Subclasses have to override this method to be notified of
* closeing.
*/
protected void closeImpl()
{
if (TDebug.TraceMidiDevice) TDebug.out("TMidiDevice.closeImpl(): begin");
if (TDebug.TraceMidiDevice) TDebug.out("TMidiDevice.closeImpl(): end");
}
public boolean isOpen()
{
return m_bDeviceOpen;
}
/** Returns whether to handle input.
If this is true, retrieving Transmitters is possible
and input from the physical port is passed to them.
@see #getUseOut
*/
protected boolean getUseTransmitter()
{
return m_bUseTransmitter;
}
/** Returns whether to handle output.
If this is true, retrieving Receivers is possible
and output to them is passed to the physical port.
@see #getUseTransmitter
*/
protected boolean getUseReceiver()
{
return m_bUseReceiver;
}
/** Returns the device time in microseconds.
This is a default implementation, telling the application
program that the device doesn't track time. If a device wants
to give timing information, it has to override this method.
*/
public long getMicrosecondPosition()
{
return -1;
}
public int getMaxReceivers()
{
int nMaxReceivers = 0;
if (getUseReceiver())
{
/*
* The value -1 means unlimited.
*/
nMaxReceivers = -1;
}
return nMaxReceivers;
}
public int getMaxTransmitters()
{
int nMaxTransmitters = 0;
if (getUseTransmitter())
{
/*
* The value -1 means unlimited.
*/
nMaxTransmitters = -1;
}
return nMaxTransmitters;
}
/** Creates a new Receiver object associated with this instance.
* In this implementation, an unlimited number of Receivers
* per MidiDevice can be created.
*/
public Receiver getReceiver()
throws MidiUnavailableException
{
if (! getUseReceiver())
{
throw new MidiUnavailableException("Receivers are not supported by this device");
}
return new TReceiver();
}
/** Creates a new Transmitter object associated with this instance.
* In this implementation, an unlimited number of Transmitters
* per MidiDevice can be created.
*/
public Transmitter getTransmitter()
throws MidiUnavailableException
{
if (! getUseTransmitter())
{
throw new MidiUnavailableException("Transmitters are not supported by this device");
}
return new TTransmitter();
}
public List getReceivers()
{
return Collections.unmodifiableList(m_receivers);
}
public List getTransmitters()
{
return Collections.unmodifiableList(m_transmitters);
}
/*
* Intended for overriding by subclasses to receive messages.
* This method is called by TMidiDevice.Receiver object on
* receipt of a MidiMessage.
*/
protected void receive(MidiMessage message, long lTimeStamp)
{
if (TDebug.TraceMidiDevice) { TDebug.out("### [should be overridden] TMidiDevice.receive(): message " + message); }
}
protected void addReceiver(Receiver receiver)
{
synchronized (m_receivers)
{
m_receivers.add(receiver);
}
}
protected void removeReceiver(Receiver receiver)
{
synchronized (m_receivers)
{
m_receivers.remove(receiver);
}
}
protected void addTransmitter(Transmitter transmitter)
{
synchronized (m_transmitters)
{
m_transmitters.add(transmitter);
}
}
protected void removeTransmitter(Transmitter transmitter)
{
synchronized (m_transmitters)
{
m_transmitters.remove(transmitter);
}
}
/** Send a MidiMessage to all Transmitters.
* This method should be called by subclasses when they get a
* message from a physical MIDI port.
*/
protected void sendImpl(MidiMessage message, long lTimeStamp)
{
if (TDebug.TraceMidiDevice) { TDebug.out("TMidiDevice.sendImpl(): begin"); }
Iterator transmitters = m_transmitters.iterator();
while (transmitters.hasNext())
{
TTransmitter transmitter = (TTransmitter) transmitters.next();
/* due to a bug in the Sun jdk1.3, we cannot use
clone() for MetaMessages. So we have to do the
equivalent ourselves.
*/
// MidiMessage copiedMessage = (MidiMessage) message.clone();
MidiMessage copiedMessage = null;
if (message instanceof MetaMessage)
{
MetaMessage origMessage = (MetaMessage) message;
MetaMessage metaMessage = new MetaMessage();
try
{
metaMessage.setMessage(origMessage.getType(), origMessage.getData(), origMessage.getData().length);
}
catch (InvalidMidiDataException e)
{
if (TDebug.TraceAllExceptions) { TDebug.out(e); }
}
copiedMessage = metaMessage;
}
else
{
copiedMessage = (MidiMessage) message.clone();
}
if (message instanceof MetaMessage)
{
if (TDebug.TraceMidiDevice) { TDebug.out("TMidiDevice.sendImpl(): MetaMessage.getData().length (original): " + ((MetaMessage) message).getData().length); }
if (TDebug.TraceMidiDevice) { TDebug.out("TMidiDevice.sendImpl(): MetaMessage.getData().length (cloned): " + ((MetaMessage) copiedMessage).getData().length); }
}
transmitter.send(copiedMessage, lTimeStamp);
}
if (TDebug.TraceMidiDevice) { TDebug.out("TMidiDevice.sendImpl(): end"); }
}
/////////////////// INNER CLASSES //////////////////////////////////////
/** Receiver proxy class.
* This class' objects are handed out on calls to
* TMidiDevice.getReceiver().
*/
public class TReceiver
implements Receiver
{
private boolean m_bOpen;
public TReceiver()
{
TMidiDevice.this.addReceiver(this);
m_bOpen = true;
}
protected boolean isOpen()
{
return m_bOpen;
}
/** Receive a MidiMessage.
*
*/
public void send(MidiMessage message, long lTimeStamp)
{
if (TDebug.TraceMidiDevice) { TDebug.out("TMidiDevice.TReceiver.send(): message " + message); }
if (m_bOpen)
{
TMidiDevice.this.receive(message, lTimeStamp);
}
else
{
throw new IllegalStateException("receiver is not open");
}
}
/** Closes the receiver.
* After a receiver has been closed, it does no longer
* propagate MidiMessages to its associated MidiDevice.
*/
public void close()
{
TMidiDevice.this.removeReceiver(this);
m_bOpen = false;
}
}
public class TTransmitter
implements Transmitter
{
private boolean m_bOpen;
private Receiver m_receiver;
public TTransmitter()
{
m_bOpen = true;
TMidiDevice.this.addTransmitter(this);
}
public void setReceiver(Receiver receiver)
{
synchronized (this)
{
m_receiver = receiver;
}
}
public Receiver getReceiver()
{
return m_receiver;
}
public void send(MidiMessage message, long lTimeStamp)
{
if (getReceiver() != null && m_bOpen)
{
getReceiver().send(message, lTimeStamp);
}
}
/** Closes the transmitter.
* After a transmitter has been closed, it no longer
* passes MidiMessages to a Receiver previously set for
* it.
*/
public void close()
{
TMidiDevice.this.removeTransmitter(this);
m_bOpen = false;
/* Previously, this method just set m_receiver to null
instead of maintaining an open flag. This allows to exploit
the behaviour of calling close(), the setReceiver() again,
and the Transmitter is "reopened". TODO: write a test case
for this scenario.
*/
}
}
/*
* This is needed only because MidiDevice.Info's
* constructor is protected (in the Sun jdk1.3).
*/
public static class Info
extends MidiDevice.Info
{
public Info(String a, String b, String c, String d)
{
super(a, b, c, d);
}
}
}
/*** TMidiDevice.java ***/
© 2015 - 2025 Weber Informatics LLC | Privacy Policy