JMSL Tutorial: JScore
JMSL Score instruments, part 4
Designing a UnitVoice by hand
In the previous tutorial we saw that importing a predefined SynthNote into JScore was a one-step task (just type in the class name and listen to it!).
In this tutorial, we will design a UnitVoice from scratch, and load it into JScore. Our task breaks down as follows:
1) Design and compile a UnitVoice .
2) Import it into JScore by specifying the class name, just like you did in the previous tutorial. *OR* use the
JScore API to construct an Orchestra by hand,
adding this new UnitVoice to it.
The UnitVoice
We designed a UnitVoice that it uses a simple amplitude envelope. The noteOn method calls queueOn() which queues up a segmented envelope and leave it sustaining. noteOff() runs through the end of the envelope.
IMPORTANT notice that it implements JMSLPlugin. That will make it easy to import into JScore later.
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;
public class SimpleUnitVoice extends Circuit implements UnitVoice, com.softsynth.jmsl.JMSLPlugin
{
// Declare units and ports.
com.jsyn.unitgen.SawtoothOscillatorBL sawOscBL;
com.jsyn.unitgen.PassThrough frequencyPassThrough;
public UnitInputPort frequency;
com.jsyn.unitgen.PassThrough amplitudePassThrough;
public UnitInputPort amplitude;
com.jsyn.unitgen.PassThrough outputPassThrough;
public UnitOutputPort output;
SegmentedEnvelope segEnv;
com.jsyn.unitgen.VariableRateMonoReader monoRdr;
// Declare inner classes for any child circuits.
public SimpleUnitVoice()
{
// Create unit generators.
add( sawOscBL = new com.jsyn.unitgen.SawtoothOscillatorBL() );
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");
double[] segEnvData = {
0.047632021640224086, 0.9785407725321889,
0.0704125537290269, 0.3218884120171674,
0.5, 0.0,
};
segEnv = new SegmentedEnvelope( segEnvData );
segEnv.setSustainBegin( 2 );
segEnv.setSustainEnd( 2 );
add( monoRdr = new com.jsyn.unitgen.VariableRateMonoReader() );
// Connect units and ports.
sawOscBL.output.connect(outputPassThrough.input);
frequencyPassThrough.output.connect(sawOscBL.frequency);
amplitudePassThrough.output.connect(monoRdr.amplitude);
monoRdr.output.connect(sawOscBL.amplitude);
// Setup
frequency.setup(40.0, 349.22923456435507, 8000.0);
amplitude.setup(0.0, 0.5, 1.0);
monoRdr.rate.set(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;
}
}
Next we will see how to load this sound into JScore.
(C) Nick Didkovsky and Phil Burk, All Rights Reserved
JMSL is based upon HMSL (C) Phil Burk, Larry Polansky and David Rosenboom.