JMSL Tutorial: JSyn and JMSL, designing a UnitVoice in Syntona


Syntona is a graphical patch editor for JSyn. You may find it easier to design UnitVoices using Syntona, and automatically exporting Java source from Syntona for use in JMSL, rather than coding JSyn UnitVoices by hand.

We won't provide an in-depth Syntona tutorial here, but look at the screen shot below...
Syntona patch editor showing a UnitVoice

This patch began by the user selecting Jsyn -> voice from the menu, and then double clicking the voice unit to open it in its own editor window (pictured here).
Notice that "frequency" and "amplitude" input ports are defined, as is an "output" port (easily added by clicking the "Add Stock Ports" button in the Syntona gui). Notice too that an additional input was added, called "envRate". Later when JMSL uses this UnitVoice to create a JSynUnitVoiceInstrument, the instrument's dimension name space will be: duration, pitch, amplitude, hold, and envRate. So JMSL will be able to control every aspect of this circuit.

Note, too that there is no LineOut in this patch. There is one in the top patch, not pictured here, but we want the UnitVoice to be exported with just input ports and a single output port.

The Java source exported from Syntona is shown below. To create a JMSL instrument, import the source into your Java project and in your main class ( similar to TestSubtractiveSynthVoiceInstrument shown few pages ago), write a few lines of code like so:
JSynUnitVoiceInstrument ins = new JSynUnitVoiceInstrument(8, patches.SimpleUnitVoice.class.getName());
MusicShape s = new MusicShape(ins.getDimensionNameSpace()); 
s.prefab(); 


********* SOURCE EXPORTED FROM SYNTONA FOLLOWS *************

package patches;
import java.io.*;
import com.jsyn.*;
import com.jsyn.unitgen.*;
import com.jsyn.data.*;
import com.jsyn.ports.*;
import com.softsynth.shared.time.TimeStamp;
/**************
** WARNING - this code automatically generated by Syntona.
** The real source is probably a Syntona patch.
** Do NOT edit this file unless you copy it to another directory and change the name.
** Otherwise it is likely to get clobbered the next time you
** export Java source code from Syntona.
**
** Syntona is available from: http://www.softsynth.com/syntona/
*/
public class SimpleUnitVoice extends Circuit implements UnitVoice
{
    // Declare units and ports.
    com.jsyn.unitgen.PassThrough frequencyPassThrough;
    public UnitInputPort frequency;
    com.jsyn.unitgen.PassThrough amplitudePassThrough;
    public UnitInputPort amplitude;
    com.jsyn.unitgen.PassThrough outputPassThrough;
    public UnitOutputPort output;
    com.jsyn.unitgen.SawtoothOscillatorBL sawOscBL;
    SegmentedEnvelope segEnv;
    com.jsyn.unitgen.VariableRateMonoReader monoRdr;
    com.jsyn.unitgen.PassThrough envRatePassThrough;
    public UnitInputPort envRate;

    // Declare inner classes for any child circuits.

    public SimpleUnitVoice()
    {
        // Create unit generators.
        add( frequencyPassThrough = new com.jsyn.unitgen.PassThrough() );
        addPort( frequency = frequencyPassThrough.input, "frequency");
        add( amplitudePassThrough = new com.jsyn.unitgen.PassThrough() );
        addPort( amplitude = amplitudePassThrough.input, "amplitude");
        add( outputPassThrough = new com.jsyn.unitgen.PassThrough() );
        addPort( output = outputPassThrough.output, "output");
        add( sawOscBL = new com.jsyn.unitgen.SawtoothOscillatorBL() );
        double[] segEnvData = {
            0.06489367121878374, 0.9785407725321889,
            0.10326278115524731, 0.4892703862660944,
            0.5, 0.0,
        };
        segEnv = new SegmentedEnvelope( segEnvData );
        segEnv.setSustainBegin( 2 );
        segEnv.setSustainEnd( 2 );
        add( monoRdr = new com.jsyn.unitgen.VariableRateMonoReader() );
        add( envRatePassThrough = new com.jsyn.unitgen.PassThrough() );
        addPort( envRate = envRatePassThrough.input, "envRate");
        // Connect units and ports.
        frequencyPassThrough.output.connect(sawOscBL.frequency);
        amplitudePassThrough.output.connect(monoRdr.amplitude);
        sawOscBL.output.connect(outputPassThrough.input);
        monoRdr.output.connect(sawOscBL.amplitude);
        envRatePassThrough.output.connect(monoRdr.rate);
        // Setup
        frequency.setup(40.0, 349.22923456435507, 8000.0);
        amplitude.setup(0.0, 0.5, 1.0);
        envRate.setup(0.0, 1.0, 1.0);
    }

    public void noteOn( double frequency, double amplitude, TimeStamp timeStamp )
    {
        this.frequency.set( frequency, timeStamp );
        this.amplitude.set( amplitude, timeStamp );
        monoRdr.dataQueue.queueOn( segEnv, timeStamp);
    }

    public void noteOff( TimeStamp timeStamp )
    {
        monoRdr.dataQueue.queueOff( segEnv, false, timeStamp);
    }
    
    public UnitOutputPort getOutput()
    {
        return output;
    }
}


 
 
  (C) Phil Burk and Nick Didkovsky, All Rights Reserved
  JMSL is based upon HMSL (C) Phil Burk, Larry Polansky and David Rosenboom.