gt:         MessageMulticaster multicaster = new MessageMulticaster();
context: package net.sf.nmedit.jnmprotocol;
  
  import java.util.Iterator;
  
  import javax.sound.midi.MidiDevice;
  import javax.sound.midi.MidiSystem;
  
  import junit.framework.Assert;
  import junit.framework.TestCase;
  import net.sf.nmedit.jnmprotocol.helper.GetPatchMessageReplyAcceptor;
  import net.sf.nmedit.jnmprotocol.AckMessage;
  import net.sf.nmedit.jnmprotocol.DeleteModuleMessage;
  import net.sf.nmedit.jnmprotocol.DeletePatchMessage;
  import net.sf.nmedit.jnmprotocol.ErrorMessage;
  import net.sf.nmedit.jnmprotocol.GetPatchListMessage;
  import net.sf.nmedit.jnmprotocol.GetPatchMessage;
  import net.sf.nmedit.jnmprotocol.IAmMessage;
  import net.sf.nmedit.jnmprotocol.LightMessage;
  import net.sf.nmedit.jnmprotocol.LoadPatchMessage;
  import net.sf.nmedit.jnmprotocol.MessageHandler;
  import net.sf.nmedit.jnmprotocol.MessageMulticaster;
  import net.sf.nmedit.jnmprotocol.MeterMessage;
  import net.sf.nmedit.jnmprotocol.MidiDriver;
  import net.sf.nmedit.jnmprotocol.MidiException;
  import net.sf.nmedit.jnmprotocol.MidiMessage;
  import net.sf.nmedit.jnmprotocol.MoveModuleMessage;
  import net.sf.nmedit.jnmprotocol.NewModuleMessage;
  import net.sf.nmedit.jnmprotocol.NewPatchInSlotMessage;
  import net.sf.nmedit.jnmprotocol.NmProtocol;
  import net.sf.nmedit.jnmprotocol.NmProtocolListener;
  import net.sf.nmedit.jnmprotocol.ParameterMessage;
  import net.sf.nmedit.jnmprotocol.PatchListEntry;
  import net.sf.nmedit.jnmprotocol.PatchListMessage;
  import net.sf.nmedit.jnmprotocol.PatchMessage;
  import net.sf.nmedit.jnmprotocol.RequestPatchMessage;
  import net.sf.nmedit.jnmprotocol.SlotActivatedMessage;
  import net.sf.nmedit.jnmprotocol.SlotsSelectedMessage;
  import net.sf.nmedit.jnmprotocol.StorePatchMessage;
  import net.sf.nmedit.jnmprotocol.VoiceCountMessage;
  import net.sf.nmedit.jnmprotocol.utils.NmLookup;
  import net.sf.nmedit.jpdl.BitStream;
  
  public class ProtocolTester extends TestCase
  {
      static private int pid0;
      
      MidiDevice.Info[] nmDevice = new MidiDevice.Info[0];
      static MidiDriver nmDriver = null; 
      
      protected void setUp()
      {
          if (nmDriver != null)
              return;
          
          nmDevice = NmLookup.lookup(NmLookup.getHardwareDevices(), 1,
                  1000 /* 1 second timeout for each midi device pair*/
                 );
          if (nmDevice.length != 2)
              throw new RuntimeException("Nord Modular device not available");
          
          nmDriver = new MidiDriver(nmDevice[0], nmDevice[1]);
      }
      
      private NmProtocol createProtocol(MidiDriver driver, MessageHandler messageHandler)
      {
          return configureProtocol(new NmProtocol(), driver, messageHandler);
      }
      
      private NmProtocol configureProtocol(NmProtocol protocol,
              MidiDriver driver, MessageHandler messageHandler)
      {
          protocol.getTransmitter().setReceiver(driver.getReceiver());
          driver.getTransmitter().setReceiver(protocol.getReceiver());
          protocol.setMessageHandler(messageHandler);
          return protocol;
      }
      
      public void testMidiDriver()
  	throws Exception
      {
  
  	MidiDevice.Info[] info = MidiSystem.getMidiDeviceInfo();
  	
  	System.out.println("");
  	System.out.println("MIDI devices:");
  	for (int i = 0; i < info.length; i++) {
  	    System.out.println(info[i].getName() + " "
  			       + info[i].getDescription() + " "
  			       + info[i].getVendor());
  	    System.out.println("Receivers: " + MidiSystem.getMidiDevice(info[i]).getMaxReceivers());
  	    System.out.println("Transmitters: " + MidiSystem.getMidiDevice(info[i]).getMaxTransmitters());
  	}
  
      nmDriver.connect();
      
      try
      {
          /*
      	for (int i = 0; i < 10; i++) {
      	    System.out.print("" + i + ":");
      	    byte[] data = md.receive();
      	    for (int j = 0; j < data.length; j++) {
      		System.out.print(" " + data[j]);
      	    }
      	    System.out.println("");
      	    Thread.sleep(100);
      	}
          */
      }
      finally
      {
          nmDriver.disconnect();
      }
      }
  
      public void testNewModuleMessage()
  	throws Exception
      {
  	int[] correctEncoding = {
  	    0xf0, 0x33, 0x7c, 0x06, 0x05, 0x18, 0x01, 0x60, 0x10, 0x50, 0x08,
  	    0x12, 0x4f, 0x39, 0x58, 0x68, 0x13, 0x10, 0x01, 0x25, 0x00, 0x00,
  	    0x13, 0x30, 0x11, 0x20, 0x78, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
  	    0x00, 0x00, 0x00, 0x5b, 0x40, 0x45, 0x00, 0x20, 0x02, 0x6a, 0x02,
  	    0x0a, 0x27, 0x5c, 0x6c, 0x34, 0x09, 0x48, 0x00, 0x1e, 0xf7
  	};
  	//NewModuleMessage.usePdlFile("/patch.pdl", new TestTracer());
  	//MidiMessage.usePdlFile("/midi.pdl", new TestTracer());
  	NewModuleMessage nm = new NewModuleMessage();
  	nm.set("pid", 5);
  	BitStream bitStream = null;
  	try {
  	    int[] parameterValues = {64, 64, 64, 64, 0, 0, 0, 0, 0, 0};
  	    int[] customValues = {0};
  	    nm.newModule(7, 1, 10, 2, 9, "OscA2", parameterValues, customValues);
  	    bitStream = (BitStream)nm.getBitStream().get(0);
  	} catch(Exception e) {
  	    e.printStackTrace();
  	}
  	int n = 0;
  	System.out.println("Size: " + bitStream.getSize());
  	while (bitStream.isAvailable(8)) {
  	    int data = bitStream.getInt(8);
  	    //System.out.println(" " + data + " " + correctEncoding[n]);
  	    Assert.assertEquals(data, correctEncoding[n]);
  	    n++;
  	}
      }
  
      public void testNoParameterNewModuleMessage()
  	throws Exception
      {
  	//NewModuleMessage.usePdlFile("/patch.pdl", new TestTracer());
  	//MidiMessage.usePdlFile("/midi.pdl", new TestTracer());
  	NewModuleMessage nm = new NewModuleMessage();
  	nm.set("pid", 5);
  	BitStream bitStream = null;
  	try {
  	    int[] parameterValues = {};
  	    int[] customValues = {};
  	    nm.newModule(1, 1, 9, 0, 28, "Some1", parameterValues, customValues);
  	    bitStream = (BitStream)nm.getBitStream().get(0);
  	} catch(Exception e) {
  	    e.printStackTrace();
  	}
  	int n = 0;
  	System.out.println("Size: " + bitStream.getSize());
  	while (bitStream.isAvailable(8)) {
  	    int data = bitStream.getInt(8);
  	    //System.out.println(" " + data + " " + correctEncoding[n]);
  	    n++;
  	}	
      }
  
      public void testProtocol()
  	throws Exception
      {
  	try {
          nmDriver.connect();
          MessageMulticaster multicaster = new MessageMulticaster();
  	    NmProtocol p = createProtocol(nmDriver, multicaster);
          multicaster.addProtocolListener(new Listener(p, multicaster));
  	    p.send(new IAmMessage());
  	    p.send(new RequestPatchMessage());
  	    int n = 0;
  	    while(n < 100) {
  		n++;
  		p.heartbeat();
  		Thread.sleep(10);
  	    }
  	    pid0 = multicaster.getActivePid(0);
  	}
  	catch (MidiException me) {
  	    me.printStackTrace();
  	    System.out.println("" + me.getError());
  	}
  	catch (Throwable e) {
  	    e.printStackTrace();
  	}
      finally
      {
          nmDriver.disconnect();
      }
      }
  
      public void testModuleMessages()
  	throws Exception
      {
  	System.out.println("testModuleMessages: " + pid0);
  	try {
          nmDriver.connect();
  