JMSL Tutorial: JSyn and JMSL, Controlling all input ports of a JSyn Circuit

The previous sections showed you how to play a JSyn UnitVoice by specifying duration, pitch, amplitude, and hold time. There's a lot more to sound than that! For example, SubtractiveSynthVoice also has SynthInputs called "Cutoff", "Q", and "PitchMod". Here we show you how to control all these custom input ports.

You may want to review the tutorial on DimensionNameSpace before proceeding.

When JSynUnitVoiceInstrument was handed a Circuit in the previous example ( TestSubtractiveSynthVoiceInstrument ), it detects all its input ports and builds a DimensionNameSpace, keeping dimensions 0..3 the standard duration, pitch, amplitude, hold, and assigning dimensions higher than 3 to these custom input ports. We did not see these in the MusicShape because we told the MusicShape to use a standard 4 dimensional DimensionNameSpace (duration, pitch, amplitude, hold). The instrument knew about more, but the MusicShape only asked to perform its frequency and amplitude.

DimensionNameSpace built by JSynUnitVoiceInstrument for com.jsyn.instruments.SubtractiveSynthVoice


0 duration
1 pitch
2 amplitude
3 hold
4 PitchMod
5 Cutoff
6 CutoffRange
Nine additional dimensions!

Note that besides the four common names "duration", "pitch", "amplitude", and "hold", that additional dimension names show up as well (in bold above).  This is unique to SubtractiveSynthVoice and was discovered by JSynUnitVoiceInstrument. Now any MusicShape that has values in dimension 4 and higher can use this instrument to control these parameters. 

To support these additional dimensions, all we'd have to do is change the MusicShape constructor in the example from:
// boring 4 dimensional version
MusicShape s = new MusicShape(4);
s.useStandardDimensionNameSpace();
s.add(etc etc etc);

TO:

// exciting all dimensional version
s = new MusicShape(ins.getDimensionNameSpace());
s.prefab();

The prefab() method enumerates through all dimensions and generates random data for each that is within range. You can write your own data generators of course, such as:

double[] data = new double[musicshape.dimension()];
for (int dim = 0; dim < musicshape.dimension(); dim++) {
 	double value = JMSLRandom.choose(musicshape.getLowLimit(dim), musicshape.getHighLimit(dim));
	data[dim] = value;
}
musicshape.add(data);

This video demonstrates.

Source below, with the most important lines bolded:
package jmsltutorial;

import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;

import com.jsyn.instruments.SubtractiveSynthVoice;
import com.softsynth.jmsl.JMSL;
import com.softsynth.jmsl.JMSLMixerContainer;
import com.softsynth.jmsl.MusicShape;
import com.softsynth.jmsl.jsyn2.JSynMusicDevice;
import com.softsynth.jmsl.jsyn2.JSynUnitVoiceInstrument;
import com.softsynth.jmsl.view.MusicShapeEditor;

/**
 * Test JSynUnitVoiceInstrument by putting it into a MusicShape that plays all
 * its dimensions
 * 
 * Uses pure Java JSyn API
 * 
 * @author Nick Didkovsky, Dec. 2, 2024
 */

public class TestSubtractiveSynthVoiceInstrumentAllDimensions extends JFrame {

    JSynUnitVoiceInstrument ins;
    MusicShape s;
    JMSLMixerContainer mixer;

    void initJSyn() {
        JMSL.clock.setAdvance(0.1);
        JSynMusicDevice dev = JSynMusicDevice.instance();
        dev.edit(new Frame());
        dev.open();
    }

    void buildInstrumentAndMixer() {
        ins = new JSynUnitVoiceInstrument(8, SubtractiveSynthVoice.class.getName());
        mixer = new JMSLMixerContainer();
        mixer.start();
        mixer.addInstrument(ins);
    }

    void buildMusicShape() {
        // Build a MusicShape based on the DimensionNameSpace of the
        // JSynUnitVoiceInstrument

        s = new MusicShape(ins.getDimensionNameSpace());  
        // generate random data for all dimensions of the instrument, controlling all
        // the inputs of the UnitVoice
        s.prefab(); 

        
//        s.add(0.5, 66, 0.35, 1.66); // this won't work because s has more than 4 dimensions now
     // you can put values into this prefabricated MusicShape like so:
        s.set(0.5, 0, 0); // set the 0th dimension of the 0th element to duration 0.5
        s.set(66, 0, 1); // set the 1st dimension of the 0th element to pitch 66
        s.set(.35, 0, 2); // set the 2nd dimension of the 0th element to amplitude 0.35
        s.set(1.66, 0, 3); // set the 3rd dimension of the 0th element to a hold time of 1.66 seconds

        // put our instrument into the MusicShape
        s.setInstrument(ins);
        // make it repeat a long time, and launch it
        s.setRepeats(1000);
    }

    void go() {
        s.launch(JMSL.now());
    }

    void buildLayout() {
        // create a graphical editor to play with the shape data in realtime
        MusicShapeEditor se = new MusicShapeEditor();
        se.addMusicShape(s);

        // add the MusicShapeEditor and mixer panel to the JFrame
        add(BorderLayout.NORTH, se.getComponent());
        add(BorderLayout.SOUTH, mixer.getPanAmpControlPanel());
    }

    public static void main(String args[]) {

        TestSubtractiveSynthVoiceInstrumentAllDimensions test = new TestSubtractiveSynthVoiceInstrumentAllDimensions();
        test.setLayout(new BorderLayout());
        test.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                JMSL.closeMusicDevices();
                System.exit(0);
            }
        });

        test.initJSyn();
        test.buildInstrumentAndMixer();
        test.buildMusicShape();
        test.buildLayout();

        test.pack();
        test.setVisible(true);

        test.go();

    }

}


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