/*
* Musical Skill Coach - An interactive midi device friendly program to help music students improve their skills
* Copyright (C) 2011 Paul-Emile Gaudet
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package music.midi;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Iterator;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Receiver;
import javax.sound.midi.ShortMessage;
import javax.swing.Timer;
public class MidiTransmitter
{
protected Receiver midiReceiver;
protected Timer t;
protected ArrayList<Note> noteSequence;
protected long millis;
protected ShortMessage message;
protected ArrayList<ActionListener> listeners;
public MidiTransmitter()
{
midiReceiver = null;
noteSequence = new ArrayList<Note>();
millis = System.currentTimeMillis();
listeners = new ArrayList<ActionListener>();
t = new Timer(10, new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
millis = System.currentTimeMillis();
//System.out.println("timer");
if (midiReceiver == null)
{
noteSequence.clear();
return;
}
if (noteSequence.size() < 1)
return;
// System.out.println("TIMER: " + noteSequence.size());
Note n = noteSequence.get(0);
while ((n != null) && (n.eventTime <= millis))
{
noteSequence.remove(n);
//System.out.println("FYI: " + n.channel + ", " + n.note + ", " + n.pressure);
message = MidiController.getNoteEvent(n.channel, n.note, n.pressure);
if (message != null)
midiReceiver.send(message, n.eventTime);
actionKey(n.note, n.pressure);
if (noteSequence.size() > 0)
n = noteSequence.get(0);
else
n = null;
}
}
});
t.start();
}
public void addActionListener(ActionListener listener)
{
Iterator<ActionListener> iterator = listeners.iterator();
ActionListener existingListener;
while (iterator.hasNext())
{
existingListener = iterator.next();
if (existingListener.equals(listener) == true)
return;
}
listeners.add(listener);
}
public void clearMidiDevice()
{
midiReceiver = null;
}
public void setDevice(MidiDevice device)
{
try
{
if (device != null)
midiReceiver = device.getReceiver();
}
catch (MidiUnavailableException e1)
{
midiReceiver = null;
}
}
public boolean hasDevice()
{
return ((midiReceiver == null) ? false : true);
}
public void removeNotes()
{
noteSequence.clear();
}
public void addNote(int channel, int note, int pressure, int duration)
{
addNote(System.currentTimeMillis(), channel, note, pressure, duration, true, false);
}
public void addNote(int channel, int note, int pressure, int duration, boolean queueOffEvent)
{
addNote(System.currentTimeMillis(), channel, note, pressure, duration, queueOffEvent, false);
}
public void addNote(long millis, int channel, int note, int pressure, int duration, boolean queueOffEvent, boolean showNote)
{
if (duration < 1)
return;
// System.out.println("QUEUE: " + channel + ", " + note + ", " + pressure + ", " + duration);
Note noteOn = new Note();
noteOn.channel = channel;
noteOn.eventTime = millis;
noteOn.note = note;
noteOn.pressure = pressure;
noteOn.showNote = showNote;
int s = noteSequence.size();
for (int i = 0; i < s; i++)
{
Note currentNote = noteSequence.get(i);
if (noteOn.eventTime < currentNote.eventTime)
{
noteSequence.add(i, noteOn);
noteOn = null;
break;
}
}
if (noteOn != null)
{
noteSequence.add(noteOn);
}
if ((duration > 0) && (queueOffEvent))
{
Note noteOff = new Note();
noteOff.channel = channel;
noteOff.eventTime = millis + duration;
noteOff.note = note;
noteOff.pressure = 0;
noteOff.showNote = showNote;
s = noteSequence.size();
for (int i = 0; i < s; i++)
{
Note currentNote = noteSequence.get(i);
if (noteOff.eventTime < currentNote.eventTime)
{
noteSequence.add(i, noteOff);
noteOff = null;
break;
}
}
if (noteOff != null)
{
noteSequence.add(noteOff);
}
}
}
public void setProgramChange(int channel, int instrument)
{
if (midiReceiver != null)
{
ShortMessage message = MidiController.getProgramChange(channel, instrument);
midiReceiver.send(message, 0);
}
}
protected void actionKey(int midiKey, int pressure)
{
if (listeners.size() < 1)
return;
ActionEvent e = new ActionEvent(this, midiKey, Integer.toString(pressure));
Iterator<ActionListener> iterator = listeners.iterator();
ActionListener listener;
while (iterator.hasNext())
{
listener = iterator.next();
listener.actionPerformed(e);
}
}
}