In case others are interested, here is my very unsophisticated Jsyn experimentation. I am sure I am violating plenty of best practices, but it works. Note that I am not versed in Java at all.
I used the sample programs PlayTone.java and HearSinePM.java with some minor modifications:
- Remove the package clause
- Replace the public class by a simple class
- Add a constructor to the class. In the case of the PlayTone example, I turned the test() method into the constructor, in the case of HearSinePM, the init() method.
- Remove the @Override from the HearSinePM constructor
- Turn the main() into setup()
To interact with the sketches, I also added an empty draw() and a keyPressed(), but found that key presses were ignored while the sound was playing. When the playing stops, they are recognized. Same for mouse clicks. Perhaps Jsyn blocks the interrupt that Processing uses for keyboard and mouse interaction.
PlayTone
import com.jsyn.JSyn;
import com.jsyn.Synthesizer;
import com.jsyn.unitgen.LineOut;
import com.jsyn.unitgen.SineOscillator;
/**
* Play a tone using a JSyn oscillator.
*
* @author Phil Burk (C) 2010 Mobileer Inc
*/
class PlayTone {
PlayTone() {
// Create a context for the synthesizer.
Synthesizer synth = JSyn.createSynthesizer();
// Start synthesizer using default stereo output at 44100 Hz.
synth.start();
// Add a tone generator.
SineOscillator oscillator = new SineOscillator();
synth.add(oscillator);
// Add a stereo audio output unit.
LineOut lineOut = new LineOut();
synth.add(lineOut);
// Connect the oscillator to both channels of the output.
oscillator.output.connect(0, lineOut.input, 0);
oscillator.output.connect(0, lineOut.input, 1);
// Set the frequency and amplitude for the sine wave.
oscillator.frequency.set(345.0);
oscillator.amplitude.set(0.6);
// We only need to start the LineOut. It will pull data from the
// oscillator.
lineOut.start();
// Sleep while the sound is generated in the background.
try {
double time = synth.getCurrentTime();
// Sleep for a few seconds.
synth.sleepUntil(time + 4.0);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Stop everything.
synth.stop();
}
}
void setup() {
PlayTone p = new PlayTone();
}
HearSinePM
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JApplet;
import javax.swing.JLabel;
import javax.swing.JPanel;
import com.jsyn.JSyn;
import com.jsyn.Synthesizer;
import com.jsyn.ports.UnitInputPort;
import com.jsyn.scope.AudioScope;
import com.jsyn.swing.DoubleBoundedRangeModel;
import com.jsyn.swing.JAppletFrame;
import com.jsyn.swing.PortModelFactory;
import com.jsyn.swing.RotaryTextController;
import com.jsyn.unitgen.LineOut;
import com.jsyn.unitgen.SineOscillator;
import com.jsyn.unitgen.SineOscillatorPhaseModulated;
/**
* Play a tone using a phase modulated sinewave oscillator. Phase modulation (PM) is very similar to
* frequency modulation (FM) but is easier to control.
*
* @author Phil Burk (C) 2010 Mobileer Inc
*/
class HearSinePM extends JApplet {
private Synthesizer synth;
SineOscillatorPhaseModulated carrier;
SineOscillator modulator;
LineOut lineOut;
AudioScope scope;
HearSinePM() {
synth = JSyn.createSynthesizer();
// Add a tone generator.
synth.add(modulator = new SineOscillator());
// Add a trigger.
synth.add(carrier = new SineOscillatorPhaseModulated());
// Add an output mixer.
synth.add(lineOut = new LineOut());
modulator.output.connect(carrier.modulation);
carrier.output.connect(0, lineOut.input, 0);
carrier.output.connect(0, lineOut.input, 1);
modulator.amplitude.setup(0.0, 1.0, 10.0);
carrier.amplitude.setup(0.0, 0.25, 1.0);
setupGUI();
}
private void setupGUI() {
setLayout(new BorderLayout());
add(new JLabel("Show Phase Modulation in an AudioScope"), BorderLayout.NORTH);
// Arrange the knob in a row.
JPanel knobPanel = new JPanel();
knobPanel.setLayout(new GridLayout(1, 0));
knobPanel.add(setupPortKnob(modulator.frequency, "MFreq"));
knobPanel.add(setupPortKnob(modulator.amplitude, "MAmp"));
knobPanel.add(setupPortKnob(carrier.frequency, "CFreq"));
knobPanel.add(setupPortKnob(carrier.amplitude, "CAmp"));
add(knobPanel, BorderLayout.SOUTH);
scope = new AudioScope(synth);
scope.addProbe(carrier.output);
scope.addProbe(modulator.output);
scope.setTriggerMode(AudioScope.TriggerMode.NORMAL);
scope.getView().setControlsVisible(true);
add(scope.getView(), BorderLayout.CENTER);
scope.start();
validate();
}
private RotaryTextController setupPortKnob(UnitInputPort port, String label) {
DoubleBoundedRangeModel model = PortModelFactory.createExponentialModel(port);
RotaryTextController knob = new RotaryTextController(model, 10);
knob.setBorder(BorderFactory.createTitledBorder(label));
knob.setTitle(label);
return knob;
}
@Override
public void start() {
// Start synthesizer using default stereo output at 44100 Hz.
synth.start();
scope.start();
// We only need to start the LineOut. It will pull data from the
// oscillator.
lineOut.start();
}
@Override
public void stop() {
scope.stop();
synth.stop();
}
}
void setup() {
/* Can be run as either an application or as an applet. */
HearSinePM applet = new HearSinePM();
JAppletFrame frame = new JAppletFrame("Hear Phase Modulation", applet);
frame.setSize(640, 400);
frame.setVisible(true);
frame.test();
}