<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Recent changes to Programmer's Guide</title><link>https://sourceforge.net/p/jsynthlib/wiki/Programmer%2527s%2520Guide/</link><description>Recent changes to Programmer's Guide</description><atom:link href="https://sourceforge.net/p/jsynthlib/wiki/Programmer's%20Guide/feed" rel="self"/><language>en</language><lastBuildDate>Tue, 21 Oct 2014 10:09:48 -0000</lastBuildDate><atom:link href="https://sourceforge.net/p/jsynthlib/wiki/Programmer's%20Guide/feed" rel="self" type="application/rss+xml"/><item><title>Programmer's Guide modified by &lt;REDACTED&gt;</title><link>https://sourceforge.net/p/jsynthlib/wiki/Programmer%2527s%2520Guide/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v10
+++ v11
@@ -436,136 +436,117 @@

 ###Param Model and Sender###

-Param Model (Parameter Model) and Sender are objects which communicate data between the synth and the SysexWidgets. For example every time a SysexWidget moves, its Param Model ({@link core.SysexWidget.IParamModel#set}) gets told and then Sender ({@link core.SysexWidget.ISender#send}) does. 
-
-We want to keep track of the changes to the patch so that when we next call up this patch the changes are there. We also want to be able to set the SysexWidgets to the correct values for a particular patch when the Single Editor is opened. This is what the **Param Model (Parameter Model)** is for.
-
-Param Model is a class object which implements {@link core.SysexWidget.IParamModel} interface. The interface provides two method, {@link core.SysexWidget.IParamModel#set} and {@link core.SysexWidget.IParamModel#get}. They just read (get) and write (set) a parameter value.
-
-The default Param Model (constructor *ParamModel(Patch patch, int offset)*) is used by the YamahaTX81z editor. Its constructor takes two parameters, the *patch* being edited and the *offset* into the patch of the value.
-
-Sometimes the default Param Model can be used, other times it is either necessary or more convenient to subclass ParamModel to make your own Model. Here is a simple example from the KawaiK5000 Editor:
-
-~~~~~~
-  class K5kSrcModel extends ParamModel {
-    public K5kSrcModel(Patch patch, int src, int offset) {
-      super(patch, 91 - 1 + offset + 86 * (src - 1));
+Param Model (Parameter Model) and Sender are objects which communicate data between the synth and the Sysex controls. For example every time a sysex control moves, its Param Model ({@link core.SysexWidget.IParamModel#set}) gets told and then Sender ({@link core.SysexWidget.ISender#send}) does. 
+
+We want to keep track of the changes to the patch so that when we next call up this patch the changes are there. We also want to be able to set the sysex controls to the correct values for a particular patch when the Single Editor is opened. This is what the **Param Model (Parameter Model)** is for.
+
+Param Model is a class object which implements {@link org.jsynthlib.device.model.IParamModel} interface. The interface provides two method, {@link org.jsynthlib.device.model.IParamModel#set} and {@link org.jsynthlib.device.model.IParamModel#get}. They just read (get) and write (set) a parameter value.
+
+All Param Model objects must comply with the Java Beans standard i.e. provide a default constructor and have public getters and setters for all of its fields.
+
+Sometimes the default Param Model can be used, other times it is either necessary or more convenient to subclass ParamModel to make your own Model. Here is a simple example from the EmuProteus2 Editor:
+
+~~~~~~
+public class EmuParamModel extends ParamModel {
+
+    public static final int ADDRESS_SIZE = 2;
+
+    @Override
+    public void set(int i) {
+        if (i &amp;lt; 0) {
+            patch.sysex[offset + 1] = (byte) 0x7F;
+        }
+
+        patch.sysex[offset] = (byte) (i % 128);
     }
-  }
-~~~~~~
-
-This overrides only constructor to make the calculation of offset easier.
-
-Here is a more complex example from the KawaiK4 Editor:
-
-~~~~~~
-  class K4Model extends ParamModel {
-    private int bitmask;
-    private int mult;
-    ...
-    public K4Model(Patch p, int offset, int bitmask) {
-      super(p, offset + 8);
-      this.bitmask = bitmask;
-      if ((bitmask &amp;amp; 1) == 1)
-        mult = 1;
-      else if ((bitmask &amp;amp; 2) == 2)
-        mult = 2;
-      else if ((bitmask &amp;amp; 4) == 4)
-        mult = 4;
-      else if ((bitmask &amp;amp; 8) == 8)
-        mult = 8;
-      else if ((bitmask &amp;amp; 16) == 16)
-        mult = 16;
-      else if ((bitmask &amp;amp; 32) == 32)
-        mult = 32;
-      else if ((bitmask &amp;amp; 64) == 64)
-        mult = 64;
-      else if ((bitmask &amp;amp; 128) == 128)
-        mult = 128;
+
+    @Override
+    public int get() {
+        if ((patch.sysex[offset + 1] &amp;amp; 0xFF) == 0x7F) {
+            return patch.sysex[offset] - 128;
+        } else if ((patch.sysex[offset + 1] &amp;amp; 0xFF) != 0) {
+            return patch.sysex[offset + 1] * 128 + patch.sysex[offset];
+        } else {
+            return patch.sysex[offset] &amp;amp; 0xFF;
+        }
     }
-  
-    public void set(int i) {
-      patch.sysex[ofs] = (byte) ((i * mult) + (patch.sysex[ofs] &amp;amp; (~bitmask)));
+}
+~~~~~~
+
+This overrides the default get and set method to set the patch bytes correctly as this synth model uses two bytes for each parameter value.
+
+You can also implement org.jsynthlib.device.model.IParamModel directly if you don't need *patch* or *ofs* field. See AlesisDMProModel as an exmaple. 
+
+A **Sender** sends a Sysex message generated by Param Model to the synth informing it of the change. It is a class object which implements {@link org.jsynthlib.device.model.ISender} interface. The interface has only one method, {@link org.jsynthlib.device.model.ISender#send}.
+
+All Sender objects must comply with the Java Beans standard i.e. provide a default constructor and have public getters and setters for all of its fields.
+
+Here's an example of a Sender from the Roland D50 Editor. It extends {@link org.jsynthlib.device.model.AbstractSender} class which implements {@link org.jsynthlib.device.model.ISender}:
+
+~~~~~~
+public class D50Sender extends AbstractSender {
+
+    private static final int DEVICE_ID_OFFSET = 2;
+    public static final int VALUE_OFFSET = 8;
+    public static final int ADDRESS_OFFSET = 5;
+    public static final int ADDRESS_SIZE = 3;
+
+    // Base message containing one value
+    public static final byte[] BASE_MESSAGE = new byte[] {
+            (byte) 0xF0, 0x41, 0x00, 0x14, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
+            (byte) 0xF7 };
+    private static final int CS_START = D50Constants.SYSEX_HEADER_SIZE - 3;
+    private static final int CS_END = BASE_MESSAGE.length
+            - D50Constants.SYSEX_FOOTER_SIZE;
+    private static final int CS_OFS = BASE_MESSAGE.length - 2;
+    private final byte[] message;
+
+    private final transient Logger log = Logger.getLogger(getClass());
+
+    public D50Sender() {
+        message = new byte[BASE_MESSAGE.length];
+        System.arraycopy(BASE_MESSAGE, 0, message, 0, BASE_MESSAGE.length);
     }
-  
-    public int get() {
-      return ((patch.sysex[ofs] &amp;amp; bitmask) / mult);
+
+    @Override
+    public void setOffset(int offset) {
+        super.setOffset(offset);
+        int value = offset;
+        for (int index = 2; index &amp;gt;= 0; index--) {
+            message[ADDRESS_OFFSET + index] = (byte) (value &amp;amp; 0x7f);
+            value &amp;gt;&amp;gt;= 7;
+        }
     }
-  }
-~~~~~~
-
-In the case of the KawaiK4, we couldn't just use the default ParamModel class, because some Kawai K4 parameters are bitmasks stored in the same byte as other parameters. The above class K4Model takes care of deciphering the bitmasks. *MIDIboxFMModel.java* is another example which uses bitmasks.
-
-You can also implement SysexWidget.IParamModel directly if you don't need *patch* or *ofs* field. See AlesisDMProModel as an exmaple. 
-
-A **Sender** sends a Sysex message generated by Param Model to the synth informing it of the change. It is a class object which implements {@link core.SysexWidget.ISender} interface. The interface has only one method, {@link core.SysexWidget.ISender#send}.
-
-Here's an example of a Sender from the Kawai K4 Editor. It extends {@link core.SysexSender} class which implements {@link core.SysexWidget.ISender}:
-
-~~~~~~
-  class K4Sender extends SysexSender {
-    private int source;
-  
-    private byte[] b = {
-        (byte) 0xF0, 0x40, 0, 0x10, 0x00,
-        0x04, 0, 0, 0, (byte) 0xF7
-    };
-  
-    public K4Sender(int parameter, int source) {
-      this.source = source;
-      b[6] = (byte) parameter;
+
+    void setMessage(int value) {
+        message[VALUE_OFFSET] = (byte) value;
     }
-  
-    public K4Sender(int parameter) {
-      this.source = 0;
-      b[6] = (byte) parameter;
+
+    @Override
+    public void send(IDriver driver, int value) {
+        byte channel = (byte) driver.getDevice().getDeviceID();
+        message[DEVICE_ID_OFFSET] = (byte) (channel - 1);
+        SysexMessage m = new SysexMessage();
+        try {
+            setMessage(value);
+            driver.calculateChecksum(message, CS_START, CS_END, CS_OFS);
+            m.setMessage(message, message.length);
+            driver.send(m);
+        } catch (InvalidMidiDataException e) {
+            log.warn(e.getMessage(), e);
+        }
     }
-  
-    public byte[] generate(int value) {
-      b[2] = (byte) (channel - 1);
-      b[7] = (byte) ((value / 128) + (source * 2));
-      b[8] = (byte) (value &amp;amp; 127);
-      return b;
+
+    byte[] getMessage() {
+        return message;
     }
-  }
-~~~~~~
-
-This sender has two constructors. One has a parameter *source* and the other does not.
-
-Here is another example of RolandJV80SystemSetupEditor which uses {@link core.SysexSender#SysexSender(String)} constructor.
-
-~~~~~~
-  static class JVSender extends SysexSender {
-    int offset;
-
-    // retrieve default from patch
-    public JVSender(int offset) {
-      super("F041@@461200000000**00F7");
-      this.offset = offset;
-    }
-
-    protected byte[] generate(int value) {
-      byte[] data = super.generate(value);
-      data[JV80Constants.ADDR4_IDX] = (byte) offset;
-      JV80Constants.calculateChecksum(data, 1);
-      return data;
-    }
-  }
-~~~~~~
-
-The constructor for a SysexSender takes a String parameter representing which parameter a particular instance of the Sender should control and creates a sysex message containing all necessary information except for the data value to be transmitted and the channel (Device ID) to transmit on. When the SysexWidget attached to this instance of the SysexSender moves, the *generate* method of the SysexSender gets called with the value to send. The generate function simply puts the value and channel into the message and returns it.
-
-RolandTD6.RolandDT1Sender is an example which implements {@link core.SysexWidget.ISender} directly without extending {@link core.SysexSender}. It is little complexed to support generic Roland DT1 (Data Transfer) message.
-
-Often a Single Editor will have one or more Param Model and/or Sender. Sometimes more than one is used because a synth may use more than one method to transfer the data.
-
-Note how the Param Models and Senders are used in the various editors. A SysexWidget doesn't care if you use the default Param Model or if you implement your own. This makes the SysexWidgets much more extensible. They can be used without needing to know how exactly the data is supposed to be accessed. The Param Model and Sender takes care of that.
-
-This all probably sounds more complex than it really is, just take a look at the editors for various other synths, try changing some things maybe to see how they work. It shouldn't be too  hard to figure out, but I'm not too good at explaining.
-
-###Action Listener###
-
-Swing provides a construct known as an action listener which allows you to write a routine which is called whenever a SysexWidget is moved. You never need to use these for dealing with built in JSynthLib SysexWidgets because they take care of it themselves. It is useful however if you want to have a SysexWidget do something more than control the synth. the Yamaha TX81x editor, for example, uses one to change the picture of the algorithm every time the 'algorithm' slider is moved.
+
+}
+~~~~~~
+
+Often a Single Editor will have one or more Param Model and/or Sender class. Sometimes more than one is used because a synth may use more than one method to transfer the data.
+
+This all probably sounds more complex than it really is, just take a look at the editors for various other synths, try changing some things maybe to see how they work. It shouldn't be too  hard to figure out.

 ###Writing a Converter###

&lt;/pre&gt;
&lt;/div&gt;</description><pubDate>Tue, 21 Oct 2014 10:09:48 -0000</pubDate><guid>https://sourceforge.net54f68cdec916631cb402dcba103d3bf3a1577507</guid></item><item><title>Programmer's Guide modified by &lt;REDACTED&gt;</title><link>https://sourceforge.net/p/jsynthlib/wiki/Programmer%2527s%2520Guide/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v9
+++ v10
@@ -392,7 +392,7 @@
 * The next step is when the script generates your FXML file
 * Finally it will ask you if it should move the generated FXMl file into your code structure or not

-When the FXML file is generated and moved inside your code tree you can now edit it using Oracle's Scene Builder tool. See [Opening FXML files in Scene Builder] for how to configure the application to display all custom controls.
+When the FXML file is generated and moved inside your code tree you can now edit it using Oracle's Scene Builder tool. See [Opening FXML files in Scene Builder](https://sourceforge.net/p/jsynthlib/wiki/Programmer's%20Guide/#opening-fxml-files-in-scene-builder) for how to configure the application to display all custom controls.

 Note that all controls have unique IDs that also map them to their corresponding label (prefixed with lbl). This fx:id is used to map the GUI control to the parameters you specified in the XML file and must never be changed! 

&lt;/pre&gt;
&lt;/div&gt;</description><pubDate>Mon, 20 Oct 2014 20:27:14 -0000</pubDate><guid>https://sourceforge.net48f9b01260b89d150629e1da187dd1bbbe4820e5</guid></item><item><title>Programmer's Guide modified by &lt;REDACTED&gt;</title><link>https://sourceforge.net/p/jsynthlib/wiki/Programmer%2527s%2520Guide/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v8
+++ v9
@@ -330,11 +330,13 @@
 The XML file will contain static data about the driver and the patches it can handle. It can also contain the full list of parameters for patches managed by the driver. This parameter list is later used to generate a GUI stub for the patch editor. 
 The java file will contain a few methods for getting/setting patch data. These methods are descried in more detail below.

+![Patch Driver Editor](http://jsynthlib.sourceforge.net/img/PatchEditor.jpg "Patch Driver Editor")
+
 ###Write the damn thing###

-Your Single Driver will be a subclass of the {@link core.Driver} class. Take a look at the API document and open up the file *Driver.java*. All of the variables and functions are documented as to their purpose. Also look at your Single Driver code (which you copied from another synthesizer) Between these two files you should be able to figure out what to do.
-
-First, you change your constructor to provide the correct information to the driver. This information is used by the functions in Driver class to manipulate the data. If your synthesizer were very simple, that would be just about all there was to writing the driver. However, most synths have their unique quirks and features that are impossible to describe using just data. Therefore you will probably have to override some of the functions in Driver class to perform for your synth.
+Your Single Driver will be a subclass of the {@link core.Driver} class. Take a look at the API document and open up the file *Driver.xml*. All of the variables and functions are documented as to their purpose. Also look at your Single Driver code (which you copied from another synthesizer) Between these two files you should be able to figure out what to do.
+
+Most synths have their unique quirks and features that are impossible to describe using just data. Therefore you will probably have to override some of the functions in Driver class to perform for your synth.

 ###Implement *calculateChecksum* Method###

@@ -381,155 +383,56 @@

 All right, so you've written a Single Driver and maybe a Bank Driver and now have Librarian support for your synthesizer. JSynthLib can load, save and play patches. Pretty neat. But the real trick is to add editing support for your synth.

-Writing an editor is a little bit harder than writing a driver. It is harder because you have to write a Java Swing interface. Swing is the default graphical toolkit that comes with Java. It is the graphical interface which all of JSynthLib uses. If you don't know Swing at all you might want to get a Java book, but you can get away with just the Tutorial on java.sun.com and the API guide that you can download when you download the JDK.
-
-The job of your Single Editor class is to set up the interface for your editor by using a number of functions and widgets provided by JSynthLib and a number of Swing features. It is invoked by {@link org.jsynthlib.patch.model.impl.Patch#edit()} method. It returns a {@link core.JSLFrame} object. What you have to do is create a class extending {@link org.jsynthlib.patch.model.impl.PatchEditorFrame} class which extends {@link core.JSLFrame} class. (You don't have to extend {@link org.jsynthlib.patch.model.impl.PatchEditorFrame}, if you want to create a JSLFrame object from scratch.)
-
-I like to set up all my sliders and CheckBoxes and figure out where they go and what there ranges are first, get a nice pretty GUI on screen and then go back and put in the numbers to make it actually work. Basically you are going to create a number of JPanes and place controls inside them using the {@link org.jsynthlib.patch.model.impl.PatchEditorFrame#addWidget} method. Then you insert these JPanes onto *scrollPane* (the background of the window). *scrollPane* is created by JSynthLib for you convenience.
-
-If you want Tabs and such, you can implement them the same way the other editors do using the Swing feature. For a simple synth, you can get away with just putting all the JPanes directly onto *scrollPane*.
-
-You can do like with the Single Driver and start out by copying an existing editor over and renaming the file, classes, constructor, etc. I recommend the YamahaTX81z Editor since it is one of the simplest Single Editor.
-
-Make sure you've taken a look at how all the other Single Editors are set up, the code contained within them explains all better than I could cope with mere words.
-
-###How to Add SysexWidgets:###
-
-JSynthLib comes with several SysexWidgets I've created which automatically deal with sending sysex and whatnot. A SysexWidget subclasses {@link core.SysexWidget} class. All you have to do is tell them where to go and what values to send out. You create and layout them by using {@link org.jsynthlib.patch.model.impl.PatchEditorFrame#addWidget} method like this:
-
-~~~~~~
-  // example from the TX81z Editor
-  addWidget(cmnPane, // pane to put the SysexWidget on
-       new ScrollBarWidget("Feedback", patch, 0, 7, 0,
-                 new ParamModel(patch, 100),
-                 new VcedSender(53)),
-       1, 1,   // horizontal/vertical location
-       3, 1,   // horizontal/vertical size
-       18);   // fader number
-~~~~~~
-
-The first parameter is the JComponent (pane) you wish to put the SysexWidget on. You would have created this pane previously as a JPane. Usually I use panes to break the interface into functional sections (such as LFO parameters, filter parameters, etc.).
-
-The second parameter is the SysexWidget to create, in this case a {@link core.ScrollBarWidget}. Notice that the widget itself takes a few parameters, we'll get to that in a moment.
-
-The next four parameters represent the location and size of the SysexWidget within the Pane (Read up on gridbaglayout in Sun's Java tutorial). They are (in order) the horizontal location, the vertical location, the horizontal size, and the vertical size).
-
-The last parameter is the fader number. Each SysexWidget needs to have a unique fader number and they should go in order. label all SysexWidgets with positive numbers except for CheckBoxes which get negative numbers (buttons). So the sliders etc. would go 1, 2, 3, 4, 5.. and the CheckBoxes would go -1, -2, -3, -4, -5... etc.
-
-###The Provided SysexWidgets:###
-
-This section describes some of SysexWidgets provided. See API documents for other SysexWidgets and more details.
-
-**{@link core.ScrollBarWidget}** contain a label, a slider, and a numeric readout of the value of the slider. They are the most common SysexWidgets. The first parameter to the SysexWidget should be its label. the second one will always be *patch*. The next two values are the minimum and maximum values on the slider. The fifth value is a value offset for the slider. This is usually zero, but gets used if the parameter in the synthesizer is (for example) 0 through 127, but should be displayed as -63 to +63). The last two parameters are a Param Model and Sender for this fader (we'll get to those after we deal with some other SysexWidgets.).
-
-**{@link core.ScrollBarLookupWidget}** are just like ScrollBarWidget but they let the numeric readout contain values other than numbers. They are used rarely. For example if a parameter can take the values of OFF, 1,2,3,4,5,6 or 7, you might use one. You wouldn't want to use a ScrollBarWidget because the first value should be OFF, not zero. You could also use a ComboBoxWidget in this situation. The constructor is about the same as for a combo box.
-
-**{@link core.ComboBoxWidget}** are drop-down list of choices that are best used for non-numeric data (such as LFO shape). Here's an example of setting up a ComboBoxWidget:
-
-~~~~~~
-  addWidget(panel,
-       new ComboBoxWidget("EG Shift", patch,
-                 new ParamModel(patch, 20 + i*5),
-                 new AcedSender(i*5 + 4),
-                 new String[] {"96db", "48db", "24db", "12db"}),
-       0, 4, 1, 1, 5);
-~~~~~~
-
-Parameters to the constructor are 1) a Label, 2) *patch*, 3) a Param Model, 4) a Sender, and 5) an array of all the values that it can contain.
-
-**{@link core.CheckBoxWidget}** are used for parameters that can be either on or off. Heres an example:
-
-~~~~~~
-  addWidget(lfoPane,
-       new CheckBoxWidget("1", patch,
-                 new ParamModel(patch, 55 + 3*13),
-                 new VcedSender(3*13 + 8)),
-       3, 6, 1, 1, -19);
-~~~~~~
-
-Parameters to the Constructor are 1) a Label, 2) *patch*, 3) a Param Model, and 4) a Sender.
-
-**{@link core.EnvelopeWidget}**, the final SysexWidget type, are vastly more complex than the others.They represent several parameters on the synth, such as the attack, decay, sustain, and release of a VCA envelope.
-
-Note that the fader number you give to an envelope widget represents is its first fader number, and it will take as many as it needs starting at that one to represent all of it's parameters.
-
-The constructor for an envelope widget takes a list of {@link core.EnvelopeWidget.Node}s. Each Node is one of the movable squares on the envelope. Some of these nodes are stationary, some contain two parameters on the synth and can be moved vertically and horizontally, and others contain only one parameter and can therefore be moved in only one direction. Here is an example:
-
-~~~~~~
-  EnvelopeWidget.Node[] nodes = new EnvelopeWidget.Node[] {
-    // origin
-   new EnvelopeWidget.Node(0, 0, null, 0, 0, null, 0, false, null, null, null, null),
-    // delay time
-   new EnvelopeWidget.Node(0, 100, new K4Model(patch, 30 + i),
-               0, 0, null,
-               0, false, new K4Sender(34, i), null, "Dly", null),
-    // atack time
-   new EnvelopeWidget.Node(0, 100, new K4Model(patch, 62 + i),
-               100, 100, null,
-               25, false, new K4Sender(45, i), null, "A", null),
-    // decay time and sustain level
-   new EnvelopeWidget.Node(0, 100, new K4Model(patch, 66 + i),
-               0, 100, new K4Model(patch, 70 + i),
-               25, false, new K4Sender(46, i), new K4Sender(47, i), "D", "S"),
-    // null node for constant length horizontal line
-   new EnvelopeWidget.Node(100, 100, null,
-               EnvelopeWidget.Node.SAME, 0, null,
-               0, false, null, null, null, null),
-    // release time
-   new EnvelopeWidget.Node(0, 100, new K4Model(patch, 74 + i),
-               0, 0, null,
-               0, false, new K4Sender(48, i), null, "R", null),
-  };
-  addWidget(panel,
-       new EnvelopeWidget("DCA Envelope", patch, nodes),
-       0, 0, 3, 5, 33);
-~~~~~~
-
-As you see, the Envelope Widget takes a label, followed by *patch* and then an array of EnvelopeWidget.Node objects. The parameters given to the EnvelopeWidget.Node constructor have the following meaning:
-
-~~~~~~
-  public Node(int minx, int maxx, ParamModel pmodelx,
-        int miny, int maxy, ParamModel pmodely,
-        int basey,
-        boolean invertx,
-        SysexSender senderx, SysexSender sendery,
-        String namex, String namey)
-~~~~~~
-
-* minx, maxx, miny, maxy
+Once you have finished your driver XML file you can generate the FXML file using the scripts/generate_xml_files.bat script: 
+
+* Launch the script
+* Answer 'n' to the first question
+* Enter the full java package name where you have saved the XML file for your new driver
+* As file name prefix you should give the same name as your XML file without the ending '.xml'. This way the script will name your FXML the same as your XML file which will make them easy to group.
+* The next step is when the script generates your FXML file
+* Finally it will ask you if it should move the generated FXMl file into your code structure or not
+
+When the FXML file is generated and moved inside your code tree you can now edit it using Oracle's Scene Builder tool. See [Opening FXML files in Scene Builder] for how to configure the application to display all custom controls.
+
+Note that all controls have unique IDs that also map them to their corresponding label (prefixed with lbl). This fx:id is used to map the GUI control to the parameters you specified in the XML file and must never be changed! 
+
+When you have opened the FXML in Scene Builder you can now move around all your GUI components and layout your editor in what ever way you want. You can move your controls into new containers, delete the generated containers and so on.
+
+**The only important thing you mustn't forget is to leave the fx:ids intact**.
+
+###The Supported Sysex Controls:###
+
+This section describes the supported Sysex controls that can be used in your FXMl file. 
+
+* Slider
+* ComboBox are drop-down list of choices that are best used for non-numeric data (such as LFO shape). 
+* CheckBox are used for parameters that can be either on or off. *Note that checkboxes don't get a corresponding label generated for them. Instead the checkbox has its own label*.
+
+* Envelope vastly more complex than the others. They represent several parameters on the synth, such as the attack, decay, sustain, and release of a VCA envelope.
+
+As you see, the Envelope XML element takes a label, followed an array of envelopeNodeSpec elements. The parameters given to the envelopeNodeSpec have the following meaning:
+
+- minx, maxx, miny, maxy
     * The minimum/maximum value permitted by the synth parameter which rides the X/Y axis of the node.
-
-* pmodelx, pmodely
+- pmodelx, pmodely
     * The Param Model which provides reading/writing abilities to the sysex data representing the parameter.
-
-* basey
+- basey
     * Sometimes you don't want zero on a Y-axis-riding-parameter to be all the way down at the bottom. This gives it a little bit of rise. *basey* will be added to all Y values. (This doesn't change the function of the EnvelopeWidget, but makes it look nicer and possibly be more intuitive to use.)
-
-* invertx
+- invertx
     * Sometimes on an X-axis-riding attribute 0 is the fastest, other times it is the slowest. This allows you to choose.
-
-* senderx, sendery
+- senderx, sendery
     * The Senders which send sysex messages to the synths when the Node is moved.
-
-* namex, namey
+- namex, namey
     * The names of the parameters riding each access.

-
-**Using *null*s for the Param Models and Senders and setting min to max means that a node is stationary on that axis and has no related parameter.
-
-**Using EnvelopeWidget.Node.SAME for miny means that the height remains at whatever the previous node was at.
+Using *null*s for the Param Models and Senders and setting min to max means that a node is stationary on that axis and has no related parameter.
+
+Using EnvelopeWidget.Node.SAME for miny means that the height remains at whatever the previous node was at.

 I hope that made sense, if not, just take a look at the way EnvelopeWidget are used by various single editors.

-**{@link core.CheckBoxWidget}**,
-**{@link core.KnobWidget}**,
-**{@link core.KnobLookupWidget}**,
-**{@link core.LabelWidget}**,
-**{@link org.jsynthlib.patch.model.impl.PatchNameWidget}**,
-**{@link core.ScrollBarLookupWidget}**,
-**{@link core.VertScrollBarWidget}**,
-**{@link core.SpinnerWidget}**,
-and **{@link core.TreeWidget}** are also provided.
+* Knob
+* TextField

 ###Param Model and Sender###

&lt;/pre&gt;
&lt;/div&gt;</description><pubDate>Mon, 20 Oct 2014 20:24:24 -0000</pubDate><guid>https://sourceforge.net574ff8b7c6423479bd47b472ccde2aab02e869d4</guid></item><item><title>Programmer's Guide modified by &lt;REDACTED&gt;</title><link>https://sourceforge.net/p/jsynthlib/wiki/Programmer%2527s%2520Guide/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v7
+++ v8
@@ -156,17 +156,8 @@
 * Today you have A LOT of freedom when implementing new devices. This is good in some cases but I would say that most of the time it’s better to have strict boundaries on how to implement a ”mainstream” device. This is what I am trying to accomplish with the XML format. 
 * When you look at different drivers you can see that actually quite a lot of code has been copied over and over again to different drivers. One of my goals with the XML format is that drivers should reference implementations of certain interfaces e.g. ParamModel and ISender. I am also thinking of expand this to checksums and some other driver methods. By doing this several drivers can potentially use the same pieces of code to perform tasks that are today coded into each specific driver
 * I am also trying to build a stronger bond between the corresponding single and bank drivers. This is because naturally a lot of functionality is shared between them. This will as well decrease the amount of code the developer has to design and implement. Today there are multiple solutions implemented by different people. I will try to create a best practice that can be used in most cases.
-* If the developer still wants his/her freedom as before this is still possible. The design looks like this (simplified!):
-
-~~~~~~
-        Driver
-       /    \
-    XMLDriver   AllLegacyDrivers
-     /
- AllNewConcreteXMLDrivers
-~~~~~~
-
-Thus you can still implement devices and drivers ”old style” but the methods that are discouraged to use will be marked as deprecated. 
+* If the developer still wants his/her freedom as before this is still possible. For a closer look at the class design please see the "Device Driver class overview" image below.
+As listed in that image you can still implement devices and drivers ”old style” but the methods that are discouraged to use will be marked as deprecated.

 **Maintainer**

@@ -278,84 +269,66 @@

 A Synth Driver communicates with JSynthLib core by using the following interfaces.

-![Device and driver class overview](http://jsynthlib.sourceforge.net/img/DeviceOverview.jpg)
+![Device and driver class overview](http://jsynthlib.sourceforge.net/img/DeviceOverview.jpg "Device Driver class overview")

 All what you have to do is to implement java classes which implements one of these interfaces. Of course you don't have to write whole code from scratch. By extending existing classes, you can implement your driver with reasonable effort.

-Most of the current synthdrivers extend the following classes;
-
-~~~~~~
-  {@link org.jsynthlib.device.model.Device} class
-
-  {@link org.jsynthlib.device.model.Driver} class implements {@link org.jsynthlib.device.model.IPatchDriver}
-  {@link org.jsynthlib.device.model.BankDriver} class implements {@link org.jsynthlib.device.model.IPatchDriver} (optional)
-  {@link org.jsynthlib.device.model.Converter} class implements {@link org.jsynthlib.device.model.IConverter} (optional)
-
-  {@link org.jsynthlib.patch.model.impl.Patch} class implements {@link core.ISinglePatch} and {@link core.IBankPatch} class
-~~~~~~
-
-Actually the interfaces described above was introduced in the JSynthLib-0.20 release.
-
 ###Writing a Device class###

-First you need to write a device file. This is very easy.
+First you need to write a device XML file. This is very easy.

 ###Create a File###

-Under *synthdrivers* directory, create a directory for your synth. Just copy an existing one, for example *KawaiK4Device.java* and change it to suit your needs.. The file name of the Device class must be **Device.java*. This is the only rule for file names for a Synth Driver.
+Under *synthdrivers* directory, create a directory for your synth. Just copy an existing one, for example *D50Device.xml* and change it to suit your needs.. The file name of the Device class must be **Device.xml*. This is the only rule for file names for a Synth Driver.

 ###Code Your Device Class###

-All what you have to do is to define two constructors. Here is from *KawaiK4Device.java*.
-
-~~~~~~
-  /** Constructor for DeviceListWriter. */
-  public KawaiK4Device() {
-    super("Kawai", "K4/K4R", "F07E..0602400000040000000000f7",
-       INFO_TEXT, "Brian Klock &amp;amp; Gerrit Gehnen");
-  }
-
-  /** Constructor for for actual work. */
-  public KawaiK4Device(Preferences prefs) {
-    this();
-    this.prefs = prefs;
-
-    addDriver(new KawaiK4BulkConverter());
-    addDriver(new KawaiK4SingleDriver());
-    addDriver(new KawaiK4BankDriver());
-    // ... other drivers
-  }
-~~~~~~
-
-The first constructor just defines various informations of your synth and authors of this Device class. This is used by the second constructor and *DeviceListWriter* described in the next section.
-
-The second constructor is used for the actual work. It creates drivers and add them onto the driver list by using addDriver method.
+Take a look at the [XML device/driver documentation](http://jsynthlib.sourceforge.net/docflex-xml/index.html) for reference.
+
+~~~~~~
+  
+  &amp;lt;xmlDeviceSpec xsi:schemaLocation="http://www.jsynthlib.org/xmldevice ../../../../../xsd/xmldevice.xsd"&amp;gt;
+   &amp;lt;manufacturer&amp;gt;Roland&amp;lt;/manufacturer&amp;gt;
+   &amp;lt;modelName&amp;gt;D-50&amp;lt;/modelName&amp;gt;
+   &amp;lt;inquiryId/&amp;gt;
+   &amp;lt;infoText&amp;gt;Roland D50.
+Single and bank drivers work together with editor.
+Saving patches onto the D50 does not work though as this must be done by manually pressing buttons on the D50.&amp;lt;/infoText&amp;gt;
+   &amp;lt;authors&amp;gt;Pascal Collberg&amp;lt;/authors&amp;gt;
+        
+   &amp;lt;drivers&amp;gt;
+       &amp;lt;xmlDriverDef&amp;gt;
+           &amp;lt;driverClass&amp;gt;org.jsynthlib.synthdrivers.RolandD50.D50SingleDriver&amp;lt;/driverClass&amp;gt;
+           &amp;lt;driverType&amp;gt;Patch&amp;lt;/driverType&amp;gt;
+       &amp;lt;/xmlDriverDef&amp;gt;
+       &amp;lt;xmlDriverDef&amp;gt;
+           &amp;lt;driverClass&amp;gt;org.jsynthlib.synthdrivers.RolandD50.D50BankDriver&amp;lt;/driverClass&amp;gt;
+           &amp;lt;driverType&amp;gt;Bank&amp;lt;/driverType&amp;gt;
+       &amp;lt;/xmlDriverDef&amp;gt;
+   &amp;lt;/drivers&amp;gt;
+&amp;lt;/xmlDeviceSpec&amp;gt;
+~~~~~~
+
+This XML snippet will provide all the necessary data about the device required by JSL. This data will be sent to the XMLDevice class which, in turn, extends the DeviceBase class. 
+
+Invoke JSynthLib, go to *Window-&amp;gt;Preferences...-&amp;gt;Synth Driver*, and click *Add Device* button. If all goes well, you see your Device name is on the list.
+
+Now JSynthLib knows about your synth driver. Now the time to write drivers :)

 ###Keeping Persistent Parameters###

-The second constructor has an argument, *java.util.prefs.Preferences* object *prefs*. By using this and overriding config() method, your driver can have persistent parameters for your synth driver. See actual code, for example RolandTD6Device, for more details.
-
-###Tell the core program about your Synth Driver###
-
-You have to let JSynthLib know about your driver. Create your Device class without addDriver() method call. Compile it, then execute the following command on your command shell,
-
-~~~~~~
-  java core/DeviceListWriter
-~~~~~~
-
-This recreates the *synthdrivers.properties* file.
-
-Invoke JSynthLib, go to *Window-&amp;gt;Preferences...-&amp;gt;Synth Driver*, and click *Add Device* button. If all goes well, you see your Device name is on the list.
-
-Now JSynthLib knows about your synth driver. Now the time to write drivers :)
+Configuration parameters can be added in this document (see &amp;lt;http: jsynthlib.sourceforge.net="" docflex-xml="" schemas="" xmldevice_xsd="" elements="" preferenceDefs.html=""&amp;gt; for details) which will generate a configuration pane in preferences dialog-&amp;gt;Synth Driver-&amp;gt;Right click on your device-&amp;gt;Property...

 ###Writing a Single Driver###

-This section describe how to write a Single Driver by extending {@link core.Driver} class which is for {@link org.jsynthlib.patch.model.impl.Patch} class. Keep in mind that what you are doing is to implement methods of {@link org.jsynthlib.patch.model.impl.PatchDriver} interface and methods which {@link org.jsynthlib.patch.model.impl.Patch} class requires.
+This section describe how to write a Single Driver by extending {@link org.jsynthlib.device.model.XMLPatchDriver} class which is for {@link org.jsynthlib.patch.model.impl.Patch} class. Keep in mind that what you are doing is to implement methods of {@link org.jsynthlib.device.model.IPatchDriver} interface and methods which {@link org.jsynthlib.patch.model.impl.Patch} class requires.

 ###Create a File###

-Copy a Single Driver from one of the other synthesizers and change its name to match your synthesizers. Go through that file and change all the references to that synthesizer to yours. I recommend using the KawaiK4SingleDriver as a starting point because it is one of the most simple drivers.
+Copy a Single Driver XML from one of the other synthesizers e.g. Roland D50 and change its name to match your synthesizers. Note that you most likely will have to create both an XMl and a java file. They must have the same name and this is the name you should specify in the driver specification element of the device. 
+Go through that file and change all the references to that synthesizer to yours. I recommend using the D50SingleDriver as a starting point because it is one of the most simple drivers. 
+The XML file will contain static data about the driver and the patches it can handle. It can also contain the full list of parameters for patches managed by the driver. This parameter list is later used to generate a GUI stub for the patch editor. 
+The java file will contain a few methods for getting/setting patch data. These methods are descried in more detail below.

 ###Write the damn thing###

&lt;/pre&gt;
&lt;/div&gt;</description><pubDate>Mon, 20 Oct 2014 19:40:03 -0000</pubDate><guid>https://sourceforge.net942824baa842eceac17e2a6f0a402495956efbaa</guid></item><item><title>Programmer's Guide modified by &lt;REDACTED&gt;</title><link>https://sourceforge.net/p/jsynthlib/wiki/Programmer%2527s%2520Guide/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v6
+++ v7
@@ -247,7 +247,7 @@
 let's describe some concepts.

 * Device
-    * A class extends {@link org.jsynthlib.device.model.Device} class. It defines some informations for your synthesizer, for example synth model name, MIDI port assigned, etc. And it has a list of drivers (Single Driver, Bank Driver, and/or Converter) described below.
+    * A concrete device implementation extends {@link org.jsynthlib.device.model.Device} class. It defines some informations for your synthesizer, for example synth model name, MIDI port assigned, etc. And it has a list of drivers (Single Driver, Bank Driver, and/or Converter) described below.

 * Single Patch
     * Single Patch is a set of MIDI system exclusive messages of a sound data, etc.
@@ -255,7 +255,7 @@
 * Single Driver
     * Single Driver provides routines to support a Single Patch.

-A Single Driver extends {@link org.jsynthlib.device.model.IPatchDriver} class and allows JSynthLib to detect a patch data for the synthesizer, to communicate with the synthesizer. Once this is written, JSynthLib will have Librarian support for your synthesizer.
+A Single Driver implements {@link org.jsynthlib.device.model.IPatchDriver} interface and allows JSynthLib to detect a patch data for the synthesizer, to communicate with the synthesizer. Once this is written, JSynthLib will have Librarian support for your synthesizer.

 A Single Driver optionally can have a Single Editor invoked by IPatchDriver.editPatch() method.

@@ -265,7 +265,7 @@
 * Bank Driver
     * Bank Driver provides routines to support a Bank Patch.

-A Bank Driver extends {@link org.jsynthlib.device.model.IPatchDriver} and allows JSynthLib to combine a single patch into a bank patch and to extract a single patch from a bank patch. While this functionality isn't strictly necessary, it is nice to have if your synth supports bulk dump patch.
+A Bank Driver implements {@link org.jsynthlib.device.model.IBankDriver} and allows JSynthLib to combine a single patch into a bank patch and to extract a single patch from a bank patch. While this functionality isn't strictly necessary, it is nice to have if your synth supports bulk dump patch.

 A Bank Driver can have a Bank Patch Editor. But you don't have to take care of it because usually the default editor can be used.

@@ -273,22 +273,12 @@
     * A driver implements {@link org.jsynthlib.device.model.IConverter} interface. This is a special driver. Converter simply converts a patch, which is imported from a file or MIDI input, into it's associated with to another format. Most of synthdrivers don't use this.

 * Single Editor
-    * This is the fun part. This is a graphical representation of the synthesizers internals which allows parameters to be changed and edited. It is invoked by a ISinglePatch.edit method.
+    * This is the fun part. This is a graphical representation of the synthesizers internals which allows parameters to be changed and edited. It is invoked by a Patch.edit method.

 A Synth Driver communicates with JSynthLib core by using the following interfaces.

-~~~~~~
-  {@link org.jsynthlib.device.model.Device} class (required)
-
-  {@link org.jsynthlib.device.model.IDriver} interface
-   {@link org.jsynthlib.device.model.IPatchDriver} interface extends {@link org.jsynthlib.device.model.IDriver} (required)
-   {@link org.jsynthlib.device.model.IConverter} interface (optional)
-
-  {@link org.jsynthlib.patch.model.impl.Patch} interface
-   {@link org.jsynthlib.device.model.ISinglePatch} interface extends {@link org.jsynthlib.patch.model.impl.Patch} (required)
-   {@link org.jsynthlib.device.model.IBankPatch} interface extends {@link org.jsynthlib.patch.model.impl.Patch} (optional)
-~~~~~~
+![Device and driver class overview](http://jsynthlib.sourceforge.net/img/DeviceOverview.jpg)

 All what you have to do is to implement java classes which implements one of these interfaces. Of course you don't have to write whole code from scratch. By extending existing classes, you can implement your driver with reasonable effort.

&lt;/pre&gt;
&lt;/div&gt;</description><pubDate>Mon, 20 Oct 2014 18:47:28 -0000</pubDate><guid>https://sourceforge.net85ad3977977f16b58e7fb410d1657887c11ad822</guid></item><item><title>Programmer's Guide modified by &lt;REDACTED&gt;</title><link>https://sourceforge.net/p/jsynthlib/wiki/Programmer%2527s%2520Guide/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v5
+++ v6
@@ -145,12 +145,14 @@
 Here is a summary of what aimed to accomplish by straightening up the framework for devices and drivers. It will benefit the following stakeholders:

 **User**
+
 * Get a more coherent feeling, functionality wise, between devices and drivers
 * The unique IDs for each parameter will in the future be great for providing easy to configure MIDI CC control to all parameters in the editors. I’m planning for a midi listener mode where you can select a control in an editor and then turn a knob on your HW MIDI controller and JSL will automatically pick up which MIDI number is sent and assign that automatically to the selected control. Like it works in Ableton Live.
 * Today it is quite unclear which drivers actually work and what is working for each driver. In a more controlled environment (that comes with a stronger framework) it will be easier to extract that information automatically and present it to the user in a centralized way
 * I think a good XML format could also potentially be used (possibly together with some XSLT) as documentation for the Sysex implementations of the devices we add to JSL. I have an old Korg DRV2000 which is impossible to find the manuals to on the Internet. Implementing a driver for that device would then be a reference of the sysex design

 **Developer**
+
 * Today you have A LOT of freedom when implementing new devices. This is good in some cases but I would say that most of the time it’s better to have strict boundaries on how to implement a ”mainstream” device. This is what I am trying to accomplish with the XML format. 
 * When you look at different drivers you can see that actually quite a lot of code has been copied over and over again to different drivers. One of my goals with the XML format is that drivers should reference implementations of certain interfaces e.g. ParamModel and ISender. I am also thinking of expand this to checksums and some other driver methods. By doing this several drivers can potentially use the same pieces of code to perform tasks that are today coded into each specific driver
 * I am also trying to build a stronger bond between the corresponding single and bank drivers. This is because naturally a lot of functionality is shared between them. This will as well decrease the amount of code the developer has to design and implement. Today there are multiple solutions implemented by different people. I will try to create a best practice that can be used in most cases.
@@ -167,6 +169,7 @@
 Thus you can still implement devices and drivers ”old style” but the methods that are discouraged to use will be marked as deprecated. 

 **Maintainer**
+
 * As stated above the JSL code is huge for what it does and there is a lot of code duplication. From a maintainer perspective this is a nightmare to handle. There are no unit tests and writing unit tests for duplicated code is quite discouraging. Therefore system tests have previously been written that verify each individual driver.

 ###How hard is it to add support for a new synthesizer to JSynthLib?###
&lt;/pre&gt;
&lt;/div&gt;</description><pubDate>Mon, 20 Oct 2014 11:40:43 -0000</pubDate><guid>https://sourceforge.net729766e8d5b5c1bbe23e42b89b89a8011bea3b10</guid></item><item><title>Programmer's Guide modified by &lt;REDACTED&gt;</title><link>https://sourceforge.net/p/jsynthlib/wiki/Programmer%2527s%2520Guide/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v4
+++ v5
@@ -2,9 +2,7 @@

 Last modified: 2014-10-20

-**Disclaimer**: This
-document is work in progress and will be updated along with code changes being
-merged to trunk.
+**Disclaimer**: This document is work in progress and will be updated along with code changes being merged to trunk.

 Go to [JSynthLib User's Guide](User Guide)

&lt;/pre&gt;
&lt;/div&gt;</description><pubDate>Mon, 20 Oct 2014 11:39:08 -0000</pubDate><guid>https://sourceforge.netecd4fd381bde1a5aab17a4c979a284b2b97efa0b</guid></item><item><title>Programmer's Guide modified by &lt;REDACTED&gt;</title><link>https://sourceforge.net/p/jsynthlib/wiki/Programmer%2527s%2520Guide/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;&lt;/pre&gt;
&lt;/div&gt;</description><pubDate>Mon, 20 Oct 2014 11:33:53 -0000</pubDate><guid>https://sourceforge.net30bb3208b22e30a08cbc9254bace884f43c8d238</guid></item><item><title>Programmer's Guide modified by &lt;REDACTED&gt;</title><link>https://sourceforge.net/p/jsynthlib/wiki/Programmer%2527s%2520Guide/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;&lt;/pre&gt;
&lt;/div&gt;</description><pubDate>Mon, 20 Oct 2014 11:33:22 -0000</pubDate><guid>https://sourceforge.net0344dc2ccfaf8ee6fd103d528fb442b6691a923a</guid></item><item><title>Programmer's Guide modified by &lt;REDACTED&gt;</title><link>https://sourceforge.net/p/jsynthlib/wiki/Programmer%2527s%2520Guide/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v1
+++ v2
@@ -170,3 +170,659 @@

 **Maintainer**
 * As stated above the JSL code is huge for what it does and there is a lot of code duplication. From a maintainer perspective this is a nightmare to handle. There are no unit tests and writing unit tests for duplicated code is quite discouraging. Therefore system tests have previously been written that verify each individual driver.
+
+###How hard is it to add support for a new synthesizer to JSynthLib?###
+
+The hardest part is simply becoming familiar with how JSynthLib works and how it's laid out internally. Spend some time looking through the driver code for other synthesizers and you'll basically pick it up by osmosis. Once your familiar with what you have to do, actually doing it shouldn't take too long. I've gotten librarian (not editing) support for synthesizers hacked up in under two hours. It depends of
+course, on the complexity of the synthesizer and the quality of the sysex specification. Adding editing support can be a little more time consuming, but is probably even more fun than writing librarian support. I've spent anywhere between 3 or 4 hours (working on the DR660 Editor) up to 5 days (working on the Matrix 1000 editor). If you run into any trouble, you can email JSynthLib mailing list for help.
+
+###What do I need in order to add support for a new synthesizer?###
+
+* At the very least, you need a sysex specification for your synthesizer. In most cases, the sysex specification is located in the back of the manual, but this is not always the case. Sometimes they are also available on the Internet if you look around enough.
+
+* You probably also need the synthesizer you wish to add support for (for testing). While it might be possible to do it without the synthesizer, it would be pretty tough.
+
+* You'll need a copy of the Java 8 (or higher) SDK. This is available for free from java.sun.com. This contains the various tools used to compile JSynthLib.
+
+* You'll need an IDE of your choice. Eclipse is the preferred IDE to use but if you prefer an other feel free to use it as long as you follow the coding guidelines.
+
+* Finally, you'll need to be able to program in Java. If you've programmed in C++ before, you can probably pick it up in about an hour (I did). If you are coming from C++ the most important thing to know is that Java passes all objects by reference, not value.
+
+###Who owns the copyright to the code I contribute to JSynthLib?&lt;br /&gt;###
+
+You do. Unless you specifically assign your copyright to me, you retain ownership. Of course, **you must release your code under the GNU General Public License** since it is considered a work derived from
+JSynthLib, but in addition to releasing it under the GNU Public License, you can do whatever else you want with it. Put the following lines at the top of **each** file.
+
+~~~~~~
+  /*
+   * Copyright 20XX Your Name
+   *
+   * This file is part of JSynthLib.
+   *
+   * JSynthLib 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.
+   *
+   * JSynthLib 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 JSynthLib; if not, write to the Free Software
+   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+   * USA
+   */
+~~~~~~
+
+Don't forget editing the first line.
+
+###The Layout of JSynthLib###
+
+If you look at the JSynthLib directory, you'll see a number of files and directories. Since you are only adding support for a synthesizer, and not working on the core program, you don't have to worry about most of these. For you, the most important areas are the *org.jsynthlib.synthdrivers* directory where code pertaining to various synthesizers are kept. Under *org.jsynthlib.synthdrivers* directory, you see many directories, like KawaiK4. As you see the names of directories has a convention, manufacturer's name followed by model name. (Usually one directory has files for the Synth Driver for one synth model. But you may have synthdrivers for multiple synth models in one directory.) In addition to the *org.jsynthlib.synthdrivers* subdirectory, you will now see *org.jsynthlib.core* directory. Inside the core directory is all the code for the main part of JSynthLib. Feel free to look around. (Probably you have to read source files which your code extends.)
+
+Compiling jSynthLib is done by calling the following maven command: 
+
+~~~~~~
+mvn package -DskipTests
+~~~~~~
+
+###JSynthLib API Document###
+
+Javadocs can be found here: http://jsynthlib.sourceforge.net/apidocs/index.html.
+ 
+If you are in need of a more up to date version of the docs you can generate them locally with this command:
+ 
+~~~~~~
+mvn clean package -DskipTests
+~~~~~~
+ 
+Once this command has terminated successfully you will be able to find the API docs here: target/apidocs/index.html
+
+###Synth Driver Structure###
+
+This section provides you a big picture of your Synth Driver. First
+let's describe some concepts.
+
+* Device
+    * A class extends {@link org.jsynthlib.device.model.Device} class. It defines some informations for your synthesizer, for example synth model name, MIDI port assigned, etc. And it has a list of drivers (Single Driver, Bank Driver, and/or Converter) described below.
+
+* Single Patch
+    * Single Patch is a set of MIDI system exclusive messages of a sound data, etc.
+
+* Single Driver
+    * Single Driver provides routines to support a Single Patch.
+
+A Single Driver extends {@link org.jsynthlib.device.model.IPatchDriver} class and allows JSynthLib to detect a patch data for the synthesizer, to communicate with the synthesizer. Once this is written, JSynthLib will have Librarian support for your synthesizer.
+
+A Single Driver optionally can have a Single Editor invoked by IPatchDriver.editPatch() method.
+
+* Bank Patch
+    * Bank Patch (bulk dump patch) is a bank of single patches.
+
+* Bank Driver
+    * Bank Driver provides routines to support a Bank Patch.
+
+A Bank Driver extends {@link org.jsynthlib.device.model.IPatchDriver} and allows JSynthLib to combine a single patch into a bank patch and to extract a single patch from a bank patch. While this functionality isn't strictly necessary, it is nice to have if your synth supports bulk dump patch.
+
+A Bank Driver can have a Bank Patch Editor. But you don't have to take care of it because usually the default editor can be used.
+
+* Converter
+    * A driver implements {@link org.jsynthlib.device.model.IConverter} interface. This is a special driver. Converter simply converts a patch, which is imported from a file or MIDI input, into it's associated with to another format. Most of synthdrivers don't use this.
+
+* Single Editor
+    * This is the fun part. This is a graphical representation of the synthesizers internals which allows parameters to be changed and edited. It is invoked by a ISinglePatch.edit method.
+
+
+A Synth Driver communicates with JSynthLib core by using the following interfaces.
+
+~~~~~~
+  {@link org.jsynthlib.device.model.Device} class (required)
+
+  {@link org.jsynthlib.device.model.IDriver} interface
+   {@link org.jsynthlib.device.model.IPatchDriver} interface extends {@link org.jsynthlib.device.model.IDriver} (required)
+   {@link org.jsynthlib.device.model.IConverter} interface (optional)
+
+  {@link org.jsynthlib.patch.model.impl.Patch} interface
+   {@link org.jsynthlib.device.model.ISinglePatch} interface extends {@link org.jsynthlib.patch.model.impl.Patch} (required)
+   {@link org.jsynthlib.device.model.IBankPatch} interface extends {@link org.jsynthlib.patch.model.impl.Patch} (optional)
+~~~~~~
+
+All what you have to do is to implement java classes which implements one of these interfaces. Of course you don't have to write whole code from scratch. By extending existing classes, you can implement your driver with reasonable effort.
+
+Most of the current synthdrivers extend the following classes;
+
+~~~~~~
+  {@link org.jsynthlib.device.model.Device} class
+
+  {@link org.jsynthlib.device.model.Driver} class implements {@link org.jsynthlib.device.model.IPatchDriver}
+  {@link org.jsynthlib.device.model.BankDriver} class implements {@link org.jsynthlib.device.model.IPatchDriver} (optional)
+  {@link org.jsynthlib.device.model.Converter} class implements {@link org.jsynthlib.device.model.IConverter} (optional)
+
+  {@link org.jsynthlib.patch.model.impl.Patch} class implements {@link core.ISinglePatch} and {@link core.IBankPatch} class
+~~~~~~
+
+Actually the interfaces described above was introduced in the JSynthLib-0.20 release.
+
+###Writing a Device class###
+
+First you need to write a device file. This is very easy.
+
+###Create a File###
+
+Under *synthdrivers* directory, create a directory for your synth. Just copy an existing one, for example *KawaiK4Device.java* and change it to suit your needs.. The file name of the Device class must be **Device.java*. This is the only rule for file names for a Synth Driver.
+
+###Code Your Device Class###
+
+All what you have to do is to define two constructors. Here is from *KawaiK4Device.java*.
+
+~~~~~~
+  /** Constructor for DeviceListWriter. */
+  public KawaiK4Device() {
+    super("Kawai", "K4/K4R", "F07E..0602400000040000000000f7",
+       INFO_TEXT, "Brian Klock &amp;amp; Gerrit Gehnen");
+  }
+
+  /** Constructor for for actual work. */
+  public KawaiK4Device(Preferences prefs) {
+    this();
+    this.prefs = prefs;
+
+    addDriver(new KawaiK4BulkConverter());
+    addDriver(new KawaiK4SingleDriver());
+    addDriver(new KawaiK4BankDriver());
+    // ... other drivers
+  }
+~~~~~~
+
+The first constructor just defines various informations of your synth and authors of this Device class. This is used by the second constructor and *DeviceListWriter* described in the next section.
+
+The second constructor is used for the actual work. It creates drivers and add them onto the driver list by using addDriver method.
+
+###Keeping Persistent Parameters###
+
+The second constructor has an argument, *java.util.prefs.Preferences* object *prefs*. By using this and overriding config() method, your driver can have persistent parameters for your synth driver. See actual code, for example RolandTD6Device, for more details.
+
+###Tell the core program about your Synth Driver###
+
+You have to let JSynthLib know about your driver. Create your Device class without addDriver() method call. Compile it, then execute the following command on your command shell,
+
+~~~~~~
+  java core/DeviceListWriter
+~~~~~~
+
+This recreates the *synthdrivers.properties* file.
+
+Invoke JSynthLib, go to *Window-&amp;gt;Preferences...-&amp;gt;Synth Driver*, and click *Add Device* button. If all goes well, you see your Device name is on the list.
+
+Now JSynthLib knows about your synth driver. Now the time to write drivers :)
+
+###Writing a Single Driver###
+
+This section describe how to write a Single Driver by extending {@link core.Driver} class which is for {@link org.jsynthlib.patch.model.impl.Patch} class. Keep in mind that what you are doing is to implement methods of {@link org.jsynthlib.patch.model.impl.PatchDriver} interface and methods which {@link org.jsynthlib.patch.model.impl.Patch} class requires.
+
+###Create a File###
+
+Copy a Single Driver from one of the other synthesizers and change its name to match your synthesizers. Go through that file and change all the references to that synthesizer to yours. I recommend using the KawaiK4SingleDriver as a starting point because it is one of the most simple drivers.
+
+###Write the damn thing###
+
+Your Single Driver will be a subclass of the {@link core.Driver} class. Take a look at the API document and open up the file *Driver.java*. All of the variables and functions are documented as to their purpose. Also look at your Single Driver code (which you copied from another synthesizer) Between these two files you should be able to figure out what to do.
+
+First, you change your constructor to provide the correct information to the driver. This information is used by the functions in Driver class to manipulate the data. If your synthesizer were very simple, that would be just about all there was to writing the driver. However, most synths have their unique quirks and features that are impossible to describe using just data. Therefore you will probably have to override some of the functions in Driver class to perform for your synth.
+
+###Implement *calculateChecksum* Method###
+
+You may have to override the {@link core.Driver#calculateChecksum(Patch, int, int, int)} and/or {@link core.Driver#calculateChecksum(Patch)} methods.
+
+{@link core.Driver#calculateChecksum(Patch, int, int, int)} actually calculate checksum. The default method uses the most common algorithm used by YAMAHA, Roland, and etc. It adds all of the data bytes, takes the lowest 7 bits, XORs them with 127 and adds one to get the checksum. If your synth uses a different algorithm, override this method.
+
+{@link core.Driver#calculateChecksum(Patch)} is called by some methods in {@link core.Driver} class. If your synth does not use checksum, override it by an empty method. If the patch for your synth consists of only one Sysex Message, you don't have to override the method. If your synth uses a patch which consists of multiple Sysex Messages, you need to override the method. See, for example, *RolandTD6SingleDriver.java*.
+
+###Implement *storePatch* and *sendPatch* Methods###
+
+Looking at your driver code (which you stole from the KawaiK4 code like I told you to). You'll see that we had to implement two methods, {@link core.Driver#storePatch(Patch, int, int)} and
+{@link core.Driver#sendPatch(Patch)}. storePatch sends a patch to a buffer in your synth specified by a user, and sendPatch sends a patch to the editing buffer in your synth. This is common, since usually, slightly different sysex messages are used to send a patch to the editing buffer (and not overwrite a patch) or to a specific patch (and overwrite). Change these functions to match your synth. If your synth has no editing buffer, you'll need to overwrite the send method to treat a specific patch location on the synth as the edit buffer it (see the EmuProteusMPS Driver for an example of this).
+
+###Implement *createPatch* and *editPatch* Methods###
+
+There are two functions that will always need to be overridden if you wish to provide that functionality because there is no default version in core\Driver.java. These are both easy to implement.
+
+One of these is the {@link core.Driver#createNewPatch} method which returns a new (blank) patch. You may use {@link core.DriverUtil#createNewPatch} for this method. See *RolandTD6SingleDriver* as an example.
+
+The other is the {@link core.Driver#editPatch} method which opens an Single Editor window for the patch. You should be able to figure out how to write these by looking at the code for the KawaiK4.
+
+There may be other functions in *Driver.java* that you will need to override for your synth. In general, spend time looking at that file, the drivers for all of the other synths, and API document to get a feel for how things are done.
+
+Once your driver is working, JSynthLib now has Librarian support for your synth. Celebrate. And send in the code to us so we can include it in the next release of JSynthLib.
+
+###Writing a Bank Driver###
+
+Basically, write a Bank Driver the same way you did the Single Driver. Copy the BankDriver from the KawaiK4 or one of the other synths and edit it to fit your needs. Change all the data in the constructor to fit you synth. The Bank Driver subclasses {@link core.BankDriver}. I recommend you look at that file and figure out which functions you need to override.
+
+You may want to use your Single Driver in your Bank Driver. You can pass your Single Driver via the constructor of your Bank Driver. Here is a part of RolandTD6Device Constructor;
+
+~~~~~~
+  public RolandTD6Device(Preferences prefs) {
+    ...
+    // add drivers
+    TD6SingleDriver singleDriver = new TD6SingleDriver();
+    addDriver(singleDriver);
+    addDriver(new TD6BankDriver(singleDriver));
+  }
+~~~~~~
+
+###Writing a Single Editor###
+
+All right, so you've written a Single Driver and maybe a Bank Driver and now have Librarian support for your synthesizer. JSynthLib can load, save and play patches. Pretty neat. But the real trick is to add editing support for your synth.
+
+Writing an editor is a little bit harder than writing a driver. It is harder because you have to write a Java Swing interface. Swing is the default graphical toolkit that comes with Java. It is the graphical interface which all of JSynthLib uses. If you don't know Swing at all you might want to get a Java book, but you can get away with just the Tutorial on java.sun.com and the API guide that you can download when you download the JDK.
+
+The job of your Single Editor class is to set up the interface for your editor by using a number of functions and widgets provided by JSynthLib and a number of Swing features. It is invoked by {@link org.jsynthlib.patch.model.impl.Patch#edit()} method. It returns a {@link core.JSLFrame} object. What you have to do is create a class extending {@link org.jsynthlib.patch.model.impl.PatchEditorFrame} class which extends {@link core.JSLFrame} class. (You don't have to extend {@link org.jsynthlib.patch.model.impl.PatchEditorFrame}, if you want to create a JSLFrame object from scratch.)
+
+I like to set up all my sliders and CheckBoxes and figure out where they go and what there ranges are first, get a nice pretty GUI on screen and then go back and put in the numbers to make it actually work. Basically you are going to create a number of JPanes and place controls inside them using the {@link org.jsynthlib.patch.model.impl.PatchEditorFrame#addWidget} method. Then you insert these JPanes onto *scrollPane* (the background of the window). *scrollPane* is created by JSynthLib for you convenience.
+
+If you want Tabs and such, you can implement them the same way the other editors do using the Swing feature. For a simple synth, you can get away with just putting all the JPanes directly onto *scrollPane*.
+
+You can do like with the Single Driver and start out by copying an existing editor over and renaming the file, classes, constructor, etc. I recommend the YamahaTX81z Editor since it is one of the simplest Single Editor.
+
+Make sure you've taken a look at how all the other Single Editors are set up, the code contained within them explains all better than I could cope with mere words.
+
+###How to Add SysexWidgets:###
+
+JSynthLib comes with several SysexWidgets I've created which automatically deal with sending sysex and whatnot. A SysexWidget subclasses {@link core.SysexWidget} class. All you have to do is tell them where to go and what values to send out. You create and layout them by using {@link org.jsynthlib.patch.model.impl.PatchEditorFrame#addWidget} method like this:
+
+~~~~~~
+  // example from the TX81z Editor
+  addWidget(cmnPane, // pane to put the SysexWidget on
+       new ScrollBarWidget("Feedback", patch, 0, 7, 0,
+                 new ParamModel(patch, 100),
+                 new VcedSender(53)),
+       1, 1,   // horizontal/vertical location
+       3, 1,   // horizontal/vertical size
+       18);   // fader number
+~~~~~~
+
+The first parameter is the JComponent (pane) you wish to put the SysexWidget on. You would have created this pane previously as a JPane. Usually I use panes to break the interface into functional sections (such as LFO parameters, filter parameters, etc.).
+
+The second parameter is the SysexWidget to create, in this case a {@link core.ScrollBarWidget}. Notice that the widget itself takes a few parameters, we'll get to that in a moment.
+
+The next four parameters represent the location and size of the SysexWidget within the Pane (Read up on gridbaglayout in Sun's Java tutorial). They are (in order) the horizontal location, the vertical location, the horizontal size, and the vertical size).
+
+The last parameter is the fader number. Each SysexWidget needs to have a unique fader number and they should go in order. label all SysexWidgets with positive numbers except for CheckBoxes which get negative numbers (buttons). So the sliders etc. would go 1, 2, 3, 4, 5.. and the CheckBoxes would go -1, -2, -3, -4, -5... etc.
+
+###The Provided SysexWidgets:###
+
+This section describes some of SysexWidgets provided. See API documents for other SysexWidgets and more details.
+
+**{@link core.ScrollBarWidget}** contain a label, a slider, and a numeric readout of the value of the slider. They are the most common SysexWidgets. The first parameter to the SysexWidget should be its label. the second one will always be *patch*. The next two values are the minimum and maximum values on the slider. The fifth value is a value offset for the slider. This is usually zero, but gets used if the parameter in the synthesizer is (for example) 0 through 127, but should be displayed as -63 to +63). The last two parameters are a Param Model and Sender for this fader (we'll get to those after we deal with some other SysexWidgets.).
+
+**{@link core.ScrollBarLookupWidget}** are just like ScrollBarWidget but they let the numeric readout contain values other than numbers. They are used rarely. For example if a parameter can take the values of OFF, 1,2,3,4,5,6 or 7, you might use one. You wouldn't want to use a ScrollBarWidget because the first value should be OFF, not zero. You could also use a ComboBoxWidget in this situation. The constructor is about the same as for a combo box.
+
+**{@link core.ComboBoxWidget}** are drop-down list of choices that are best used for non-numeric data (such as LFO shape). Here's an example of setting up a ComboBoxWidget:
+
+~~~~~~
+  addWidget(panel,
+       new ComboBoxWidget("EG Shift", patch,
+                 new ParamModel(patch, 20 + i*5),
+                 new AcedSender(i*5 + 4),
+                 new String[] {"96db", "48db", "24db", "12db"}),
+       0, 4, 1, 1, 5);
+~~~~~~
+
+Parameters to the constructor are 1) a Label, 2) *patch*, 3) a Param Model, 4) a Sender, and 5) an array of all the values that it can contain.
+
+**{@link core.CheckBoxWidget}** are used for parameters that can be either on or off. Heres an example:
+
+~~~~~~
+  addWidget(lfoPane,
+       new CheckBoxWidget("1", patch,
+                 new ParamModel(patch, 55 + 3*13),
+                 new VcedSender(3*13 + 8)),
+       3, 6, 1, 1, -19);
+~~~~~~
+
+Parameters to the Constructor are 1) a Label, 2) *patch*, 3) a Param Model, and 4) a Sender.
+
+**{@link core.EnvelopeWidget}**, the final SysexWidget type, are vastly more complex than the others.They represent several parameters on the synth, such as the attack, decay, sustain, and release of a VCA envelope.
+
+Note that the fader number you give to an envelope widget represents is its first fader number, and it will take as many as it needs starting at that one to represent all of it's parameters.
+
+The constructor for an envelope widget takes a list of {@link core.EnvelopeWidget.Node}s. Each Node is one of the movable squares on the envelope. Some of these nodes are stationary, some contain two parameters on the synth and can be moved vertically and horizontally, and others contain only one parameter and can therefore be moved in only one direction. Here is an example:
+
+~~~~~~
+  EnvelopeWidget.Node[] nodes = new EnvelopeWidget.Node[] {
+    // origin
+   new EnvelopeWidget.Node(0, 0, null, 0, 0, null, 0, false, null, null, null, null),
+    // delay time
+   new EnvelopeWidget.Node(0, 100, new K4Model(patch, 30 + i),
+               0, 0, null,
+               0, false, new K4Sender(34, i), null, "Dly", null),
+    // atack time
+   new EnvelopeWidget.Node(0, 100, new K4Model(patch, 62 + i),
+               100, 100, null,
+               25, false, new K4Sender(45, i), null, "A", null),
+    // decay time and sustain level
+   new EnvelopeWidget.Node(0, 100, new K4Model(patch, 66 + i),
+               0, 100, new K4Model(patch, 70 + i),
+               25, false, new K4Sender(46, i), new K4Sender(47, i), "D", "S"),
+    // null node for constant length horizontal line
+   new EnvelopeWidget.Node(100, 100, null,
+               EnvelopeWidget.Node.SAME, 0, null,
+               0, false, null, null, null, null),
+    // release time
+   new EnvelopeWidget.Node(0, 100, new K4Model(patch, 74 + i),
+               0, 0, null,
+               0, false, new K4Sender(48, i), null, "R", null),
+  };
+  addWidget(panel,
+       new EnvelopeWidget("DCA Envelope", patch, nodes),
+       0, 0, 3, 5, 33);
+~~~~~~
+
+As you see, the Envelope Widget takes a label, followed by *patch* and then an array of EnvelopeWidget.Node objects. The parameters given to the EnvelopeWidget.Node constructor have the following meaning:
+
+~~~~~~
+  public Node(int minx, int maxx, ParamModel pmodelx,
+        int miny, int maxy, ParamModel pmodely,
+        int basey,
+        boolean invertx,
+        SysexSender senderx, SysexSender sendery,
+        String namex, String namey)
+~~~~~~
+
+* minx, maxx, miny, maxy
+    * The minimum/maximum value permitted by the synth parameter which rides the X/Y axis of the node.
+
+* pmodelx, pmodely
+    * The Param Model which provides reading/writing abilities to the sysex data representing the parameter.
+
+* basey
+    * Sometimes you don't want zero on a Y-axis-riding-parameter to be all the way down at the bottom. This gives it a little bit of rise. *basey* will be added to all Y values. (This doesn't change the function of the EnvelopeWidget, but makes it look nicer and possibly be more intuitive to use.)
+
+* invertx
+    * Sometimes on an X-axis-riding attribute 0 is the fastest, other times it is the slowest. This allows you to choose.
+
+* senderx, sendery
+    * The Senders which send sysex messages to the synths when the Node is moved.
+
+* namex, namey
+    * The names of the parameters riding each access.
+
+
+**Using *null*s for the Param Models and Senders and setting min to max means that a node is stationary on that axis and has no related parameter.
+
+**Using EnvelopeWidget.Node.SAME for miny means that the height remains at whatever the previous node was at.
+
+I hope that made sense, if not, just take a look at the way EnvelopeWidget are used by various single editors.
+
+**{@link core.CheckBoxWidget}**,
+**{@link core.KnobWidget}**,
+**{@link core.KnobLookupWidget}**,
+**{@link core.LabelWidget}**,
+**{@link org.jsynthlib.patch.model.impl.PatchNameWidget}**,
+**{@link core.ScrollBarLookupWidget}**,
+**{@link core.VertScrollBarWidget}**,
+**{@link core.SpinnerWidget}**,
+and **{@link core.TreeWidget}** are also provided.
+
+###Param Model and Sender###
+
+Param Model (Parameter Model) and Sender are objects which communicate data between the synth and the SysexWidgets. For example every time a SysexWidget moves, its Param Model ({@link core.SysexWidget.IParamModel#set}) gets told and then Sender ({@link core.SysexWidget.ISender#send}) does. 
+
+We want to keep track of the changes to the patch so that when we next call up this patch the changes are there. We also want to be able to set the SysexWidgets to the correct values for a particular patch when the Single Editor is opened. This is what the **Param Model (Parameter Model)** is for.
+
+Param Model is a class object which implements {@link core.SysexWidget.IParamModel} interface. The interface provides two method, {@link core.SysexWidget.IParamModel#set} and {@link core.SysexWidget.IParamModel#get}. They just read (get) and write (set) a parameter value.
+
+The default Param Model (constructor *ParamModel(Patch patch, int offset)*) is used by the YamahaTX81z editor. Its constructor takes two parameters, the *patch* being edited and the *offset* into the patch of the value.
+
+Sometimes the default Param Model can be used, other times it is either necessary or more convenient to subclass ParamModel to make your own Model. Here is a simple example from the KawaiK5000 Editor:
+
+~~~~~~
+  class K5kSrcModel extends ParamModel {
+    public K5kSrcModel(Patch patch, int src, int offset) {
+      super(patch, 91 - 1 + offset + 86 * (src - 1));
+    }
+  }
+~~~~~~
+
+This overrides only constructor to make the calculation of offset easier.
+
+Here is a more complex example from the KawaiK4 Editor:
+
+~~~~~~
+  class K4Model extends ParamModel {
+    private int bitmask;
+    private int mult;
+    ...
+    public K4Model(Patch p, int offset, int bitmask) {
+      super(p, offset + 8);
+      this.bitmask = bitmask;
+      if ((bitmask &amp;amp; 1) == 1)
+        mult = 1;
+      else if ((bitmask &amp;amp; 2) == 2)
+        mult = 2;
+      else if ((bitmask &amp;amp; 4) == 4)
+        mult = 4;
+      else if ((bitmask &amp;amp; 8) == 8)
+        mult = 8;
+      else if ((bitmask &amp;amp; 16) == 16)
+        mult = 16;
+      else if ((bitmask &amp;amp; 32) == 32)
+        mult = 32;
+      else if ((bitmask &amp;amp; 64) == 64)
+        mult = 64;
+      else if ((bitmask &amp;amp; 128) == 128)
+        mult = 128;
+    }
+  
+    public void set(int i) {
+      patch.sysex[ofs] = (byte) ((i * mult) + (patch.sysex[ofs] &amp;amp; (~bitmask)));
+    }
+  
+    public int get() {
+      return ((patch.sysex[ofs] &amp;amp; bitmask) / mult);
+    }
+  }
+~~~~~~
+
+In the case of the KawaiK4, we couldn't just use the default ParamModel class, because some Kawai K4 parameters are bitmasks stored in the same byte as other parameters. The above class K4Model takes care of deciphering the bitmasks. *MIDIboxFMModel.java* is another example which uses bitmasks.
+
+You can also implement SysexWidget.IParamModel directly if you don't need *patch* or *ofs* field. See AlesisDMProModel as an exmaple. 
+
+A **Sender** sends a Sysex message generated by Param Model to the synth informing it of the change. It is a class object which implements {@link core.SysexWidget.ISender} interface. The interface has only one method, {@link core.SysexWidget.ISender#send}.
+
+Here's an example of a Sender from the Kawai K4 Editor. It extends {@link core.SysexSender} class which implements {@link core.SysexWidget.ISender}:
+
+~~~~~~
+  class K4Sender extends SysexSender {
+    private int source;
+  
+    private byte[] b = {
+        (byte) 0xF0, 0x40, 0, 0x10, 0x00,
+        0x04, 0, 0, 0, (byte) 0xF7
+    };
+  
+    public K4Sender(int parameter, int source) {
+      this.source = source;
+      b[6] = (byte) parameter;
+    }
+  
+    public K4Sender(int parameter) {
+      this.source = 0;
+      b[6] = (byte) parameter;
+    }
+  
+    public byte[] generate(int value) {
+      b[2] = (byte) (channel - 1);
+      b[7] = (byte) ((value / 128) + (source * 2));
+      b[8] = (byte) (value &amp;amp; 127);
+      return b;
+    }
+  }
+~~~~~~
+
+This sender has two constructors. One has a parameter *source* and the other does not.
+
+Here is another example of RolandJV80SystemSetupEditor which uses {@link core.SysexSender#SysexSender(String)} constructor.
+
+~~~~~~
+  static class JVSender extends SysexSender {
+    int offset;
+
+    // retrieve default from patch
+    public JVSender(int offset) {
+      super("F041@@461200000000**00F7");
+      this.offset = offset;
+    }
+
+    protected byte[] generate(int value) {
+      byte[] data = super.generate(value);
+      data[JV80Constants.ADDR4_IDX] = (byte) offset;
+      JV80Constants.calculateChecksum(data, 1);
+      return data;
+    }
+  }
+~~~~~~
+
+The constructor for a SysexSender takes a String parameter representing which parameter a particular instance of the Sender should control and creates a sysex message containing all necessary information except for the data value to be transmitted and the channel (Device ID) to transmit on. When the SysexWidget attached to this instance of the SysexSender moves, the *generate* method of the SysexSender gets called with the value to send. The generate function simply puts the value and channel into the message and returns it.
+
+RolandTD6.RolandDT1Sender is an example which implements {@link core.SysexWidget.ISender} directly without extending {@link core.SysexSender}. It is little complexed to support generic Roland DT1 (Data Transfer) message.
+
+Often a Single Editor will have one or more Param Model and/or Sender. Sometimes more than one is used because a synth may use more than one method to transfer the data.
+
+Note how the Param Models and Senders are used in the various editors. A SysexWidget doesn't care if you use the default Param Model or if you implement your own. This makes the SysexWidgets much more extensible. They can be used without needing to know how exactly the data is supposed to be accessed. The Param Model and Sender takes care of that.
+
+This all probably sounds more complex than it really is, just take a look at the editors for various other synths, try changing some things maybe to see how they work. It shouldn't be too  hard to figure out, but I'm not too good at explaining.
+
+###Action Listener###
+
+Swing provides a construct known as an action listener which allows you to write a routine which is called whenever a SysexWidget is moved. You never need to use these for dealing with built in JSynthLib SysexWidgets because they take care of it themselves. It is useful however if you want to have a SysexWidget do something more than control the synth. the Yamaha TX81x editor, for example, uses one to change the picture of the algorithm every time the 'algorithm' slider is moved.
+
+###Writing a Converter###
+
+*!!!FIXME!!! Describe the situation where Converter is used.*
+
+##Testing Your Driver...##
+
+**This section of the Documentation was written by Yves Lefebvre.**
+
+###Introduction###
+This is an attempt to do a test plan when writing a new driver for JSynthLib. It take little time to do and may help finding problem before the driver is available publicly.
+
+First thing to do: you must do some single dump and some bank dump from your synth to your computer without using JSynthLib (I use Cakewalk to do that but there should be some simple freeware to do this). Save those dump in .syx format (binary). Remember, we are not using JSynthLib at his point in order to have something "clean" to refer to when testing the new driver.
+
+One important note : It seems that some synth could have "bugs" in their factory patches. So if you resend those patch to the synth, they will be "corrected". To test this, you can simply resend the bank dump from your PC to the synth and do a new bank dump from synth to PC. If there are difference and the first bank dump and the second, this is probably the problem I mention. Normally, resending the second dump should be consistent after that. Any dump from synth to PC should be identical to the second dump since the synth has now "corrected" th original dump! I had this problem with some specific patch of my Nova after restoring original patches on the unit with the "Restore from ROM" command. I had spent some time figuring out the difference between dump so I'm warning you not to do the same mistake!
+
+Now, redo the same thing (single dump and bank dump) but this time, change your device id number on the synth (sometime call global MIDI channel). Those new dump may have some byte different or not. In most case, single dump will be identical while bank dump may be different.
+
+###Testing your Single Driver###
+
+* Try to open a "clean" .syx file from JSynthLib and send it to the edit buffer of your synth. Try it to see if the name and sound seems OK. Do a dump (with external soft) and compare the file, they should be identical. Make sure that the patch is really in the edit buffer (and not written in memory) by changing patch on the synth and going back to the patch number it was before the send: the patch you just send should not be there (This may vary with some synth Model).
+
+* Try to do a single patch dump to JSynthLib. Check that the patch name is correct in JSynthLib. Export it to a .syx file and compare it (diff) with the original "clean" version. Should be the same. (Those steps will confirm that loading external file and receiving/sending a dump give the same result)
+
+* Try to store this patch at different location in the synth. At least, try to store in patch 0 or 1 and to the highest patch number of your synth. Do that in every user bank if possible. Verify that the patch appear in all the location you save it.
+
+* Create a new patch with JSynthLib and send it to your synth. Make sure the new patch didn't do anything wrong on the synth (if your new patch is all 0 with a name, some synth may react strangely to invalid combination of values). If you want to play safe, your createNewPatch method could construct a valid default patch for your synth: just do a dump of a simple patch and integrate this in the code.
+
+* Now, redo all those step with a different id number on the synth. Change JSynthLib accordingly to that new Id (channel number). Some time, it's possible you left a bug if you didn't test with a different ID (channel number).
+
+###Testing your Bank Driver###
+* Open a "clean" .syx bank file with JSynthLib. Make sure that all individual patch name make sense.
+
+* Send one patch from the bank to your synth. Make a dump (from your synth) of that single patch with another software. Now, do a diff of this dump with a previously made dump of that same patch. This will make sure that extracting a patch from a bank and sending it to the synth gave the exact same thing. You should really do a binary compare of the file since just playing it is not enough. Even if some parameter are sent wrong, the patch may sound correct to your ear, so you need to do a real compare.
+
+* Erase all bank memory on your synth. Now, send the whole bank from JSynthLib to your synth. Do a dump from the synth to your external software. The .syx file should be the same than the original one. This is not the same thing than the previous step: extracting a single patch from a bank and sending a whole bank is very different. Note: one potential problem here is that some synth may need more time to "digest" a big bank dump from your PC. In those cases, you should put some delay in your code until you find a safe speed.
+
+* Try sending your bank to all possible banks in the synth and verify their integrity.
+
+* Now, you should redo some of those steps with a different channel number, just to make sure. Note that the bank .syx file will likely have the channel byte different so you need to extract a "clean" bank with the new channel first from your synth.
+
+###Testing your Editor###
+
+*Note: I never write an editor but here are some suggestions:*
+* Usually, modifications done in the editor are sent in real-time to your synth. However, the editor must also make the same modification in the single patch that is edited. To test that it works correctly, you should made some modification in the editor and save the patch (do not send that patch to the edit buffer of your synth). Now, on your synth, the same patch should be in the edit buffer since all single edit will have send sysex for every parameter changed. Do a dump from your synth to PC and compare it to the patch JSynthLib just created. They should be identical. Normally, you should try each fader or knob in the editor to be sure they are controlling the correct parameter. Just move each one at random when creating the patch. If you do that some time (random edit, saving and comparing the file), chance are the editor behave correctly.
+
+*Note: I suggest to move*
+each fader at random because putting all of them to 0 or max is not a good idea since your editor may send knob info to the wrong place and you will not be able to detect it by comparing the .syx file!
+
+
+Last step, send your new driver for integration in the next release of JSynthLib!
+
+Yves Lefebvre&lt;br /&gt;
+ivanohe@abacom.com&lt;br /&gt;
+www.abacom.com/~ivanohe
+
+##FAQ##
+
+###How can I send a bug report?###
+
+Send the following information to Tracker on JSynthLib SourceForge site or jsynthlib-devel mailing list.
+
+
+* Edit the log4j.properties file to make it more verbose and invoke JSynthLib. This will output debug information including Java version, OS type, etc.
+* A specific way to reproduce the bug.
+* Any other useful **'fact'**, other than 'guess'.
+
+
+###Is there any tips for debug?###
+
+Of course, nothing ever works the first time. Its never as easy as it should be. If you have problems getting the synth to do what your editor or driver is telling it to do. here's two debugging tricks I use.
+
+
+*This is pretty common, but just sprinkle
+*System.out.println* statements through out the troublesome code. Get a good idea of what values are what when and look for something that shouldn't be. Better yet, use
+*log4j loggers* instead.
+
+*Use a MIDI cable to connect your computer's MIDI out to MIDI in. Use build in MIDI Monitor Window or get a program (for example MIDI-OX for Windows) from the Internet to print out all incoming MIDI messages. Now you can see what messages your editor/driver is sending and you can check them for correctness.
+
+
+
+
+###Why shall I use an indentation level of 4 with a displayed tab width of 8?###
+
+For indentation level, any level is OK. But we need a standard to work in a team. We choose the coding style used in "Programming Language Java" out of respect for the creators of Java language as the standard. Therefore we recommend the indentation level of 4.
+
+The reason for a displayed tab width of 8 is compatibility with the following essential tools:
+
+* ... viewcvs, the CVS browser that SourceForge uses.
+* ... Notepad, the default editor of Microsoft Windows.
+* ... Unix command line tools like cat, less, tail, ...
+
+
+Most tools support the settings above.
+An open source IDE that supports these settings is e.g. Eclipse.
+Text editors that also support it are e.g. jEdit and
+SciTE which are both open source and availabe for Linux, Mac OS X and Windows like Eclipse.
+
+##Related Documentation##
+
+###Java Language###
+For overviews, tutorials, examples, guides, and tool documentation, please see:
+Java Home Page
+
+Java Sound Resources is a good resource of Java Sound.
+
+###MIDI Specification###
+
+* MMA (Midi Manufacturer Association) &amp;lt;http: www.midi.org="" techspecs="" midispec.php=""&amp;gt;The MMA is the original source for information on MIDI (Musical Instrument Digital Interface) technology.
+
+
+The **Complete MIDI 1.0 Detailed Specification** isn't downloadable from the MMA Web site.
+But you'll find a MIDI specification for example at &amp;lt;www.borg.com&amp;gt;.
+
+###Applications###
+
+* Eclipse
+* Oracle's Scene Builder
+* MIDI-OX and MIDI Yoke for MS Windows
+* Midi Monitor for Mac OS X
&lt;/pre&gt;
&lt;/div&gt;</description><pubDate>Mon, 20 Oct 2014 11:32:52 -0000</pubDate><guid>https://sourceforge.net59c5fa3ed43a71ddee52811e62b7cd6bab4efc30</guid></item></channel></rss>