/* Nord Modular Midi Protocol 3.03 Library Copyright (C) 2003-2007 Marcus Andersson 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 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package net.sf.nmedit.jnmprotocol; import net.sf.nmedit.jnmprotocol.AckMessage; import net.sf.nmedit.jnmprotocol.ErrorMessage; import net.sf.nmedit.jnmprotocol.IAmMessage; import net.sf.nmedit.jnmprotocol.KnobAssignmentMessage; import net.sf.nmedit.jnmprotocol.LightMessage; import net.sf.nmedit.jnmprotocol.MeterMessage; import net.sf.nmedit.jnmprotocol.MidiException; import net.sf.nmedit.jnmprotocol.MidiMessage; import net.sf.nmedit.jnmprotocol.MorphAssignmentMessage; import net.sf.nmedit.jnmprotocol.MorphRangeChangeMessage; import net.sf.nmedit.jnmprotocol.NewPatchInSlotMessage; import net.sf.nmedit.jnmprotocol.NmProtocol; import net.sf.nmedit.jnmprotocol.NmProtocolListener; import net.sf.nmedit.jnmprotocol.NoteMessage; import net.sf.nmedit.jnmprotocol.ParameterMessage; import net.sf.nmedit.jnmprotocol.ParameterSelectMessage; import net.sf.nmedit.jnmprotocol.PatchListMessage; import net.sf.nmedit.jnmprotocol.PatchMessage; import net.sf.nmedit.jnmprotocol.SetPatchTitleMessage; import net.sf.nmedit.jnmprotocol.SlotActivatedMessage; import net.sf.nmedit.jnmprotocol.SlotsSelectedMessage; import net.sf.nmedit.jnmprotocol.SynthSettingsMessage; import net.sf.nmedit.jnmprotocol.VoiceCountMessage; /** * This class can be used to accept a specific midi message. * * Example: * * <code> * MessageMulticaster multicaster; * * // create the acceptor * NmMessageAcceptor<SynthSettingsMessage> acceptor = * new NmMessageAcceptor<SynthSettingsMessage>(SynthSettingsMessage.class); * * try * { * // install acceptor * multicaster.addProtocolListener(acceptor); * * // add request message to the send queue * protocol.send(new RequestSynthSettingsMessage()); * * long timeout = 3000; // 3000 milliseconds timeout * * // this will trigger the protocol.heartbeat() method * // and wait until the reply is received * // when a timeout occurs an exception is thrown * multicaster.waitForReply(timeout); * * SynthSettingsMessage reply = multicaster.getRecentMessage(); * * // do something with the reply message * doSomething(reply); * * } * finally * { * // uninstall acceptor * multicaster.removeProtocolListener(acceptor); * } * </code> * */ public class NmMessageAcceptor<M extends MidiMessage> extends NmProtocolListener { private Class<M> messageClass; private M firstMessage; private M recentMessage; private int acceptedCount; public NmMessageAcceptor(Class<M> messageClass) { this.messageClass = messageClass; this.firstMessage = null; this.recentMessage = null; this.acceptedCount = 0; } public void waitForReply(NmProtocol protocol, long timeout) throws MidiException { final long timeoutThreshold = System.currentTimeMillis()+timeout; while (!isMessageReceived()) { if (System.currentTimeMillis()>timeoutThreshold) { throw new MidiException("timeout: "+timeout+"ms ("+messageClass.getName()+")", 0); } protocol.heartbeat(); protocol.waitForActivity(100); } } public void accept(MidiMessage message) { if (messageClass.isInstance(message)) { M instance = messageClass.cast(message); if (!acceptsMessage(instance)) return; if (firstMessage == null) firstMessage = instance; recentMessage = instance; acceptedCount ++; } } protected boolean acceptsMessage(M message) { return true; } public int getAcceptedCount() { return acceptedCount; } public M getFirstMessage() { return firstMessage; } public M getRecentMessage() { return recentMessage; } public boolean isMessageReceived() { return firstMessage != null; } public void messageReceived(IAmMessage message) { accept(message); } public void messageReceived(LightMessage message) { accept(message); } public void messageReceived(MeterMessage message) { accept(message); } public void messageReceived(PatchMessage message) { accept(message); } public void messageReceived(AckMessage message) { accept(message); } public void messageReceived(PatchListMessage message) { accept(message); } public void messageReceived(NewPatchInSlotMessage message) { accept(message); } public void messageReceived(VoiceCountMessage message) { accept(message); } public void messageReceived(SlotsSelectedMessage message) { accept(message); } public void messageReceived(SlotActivatedMessage message) { accept(message); } public void messageReceived(ParameterMessage message) { accept(message); } public void messageReceived(ErrorMessage message) { accept(message); } public void messageReceived(SynthSettingsMessage message) { accept(message); } public void messageReceived(KnobAssignmentMessage message) { accept(message); } public void messageReceived(MorphAssignmentMessage message) { accept(message); } public void messageReceived(NoteMessage message) { accept(message); } public void messageReceived(MorphRangeChangeMessage message) { accept(message); } public void messageReceived(SetPatchTitleMessage message) { accept(message); } public void messageReceived(ParameterSelectMessage message) { accept(message); } }