package jmslexamples.jsyn; import java.awt.Button; import java.awt.TextArea; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import com.softsynth.jmsl.*; import com.softsynth.jmsl.jsyn.JSynMusicDevice; import com.softsynth.jsyn.*; /** * PlayModShape.java * * Shows how to play JSyn with JMSL without using support classs like * SynthNoteAllPortsInstrument and without using standard dimension name spaces * * This applet starts two Shapes in parallel. Each MusicShape has an instrument * whose Interpreter interprets the shape data as frequency and modulation * values. * * This demonstrates how to build an arbitrary custom instrument, which uses a * custom Interpreter to interpret shape data and play it. * * Note that OscModIns has its own LineOut which is not recommended. We present * it here because some people like to and need to break rules all the time, and * everyone likes to and needs to break rules some of the time. This was written * before JMSLv103 made stuff like this unrecommended practice. * * @author Phil Burk and Nick Didkovsky */ /* * (C) 1997 Phil Burk and Nick Didkovsky, All Rights Reserved JMSL is based upon * HMSL (C) Phil Burk, Larry Polansky and David Rosenboom. */ public class PlayModShape extends java.applet.Applet { public ParallelCollection col; MusicShape s1; MusicShape s2; TextArea textArea; // to print hierarchy Button launchButton; Button haltButton; /* Can be run as either an application or as an applet. */ public static void main(String args[]) { PlayModShape applet = new PlayModShape(); AppletFrame frame = new AppletFrame("Play shape with modulation rates.", applet); frame.setSize(600, 400); frame.show(); /* * Begin test after frame opened so that DirectSound will use Java * window. */ frame.test(); } public void init() { // textArea = new TextArea(); // JMSL.setSTDOut(new TextAreaOut(textArea)); add(launchButton = new Button("Launch")); launchButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JMSL.out.println("LAUNCH"); col.launch(JMSL.now()); } }); add(haltButton = new Button("Finish")); haltButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JMSL.out.println("Finish"); col.finishAll(); try { col.waitForDone(); } catch (InterruptedException e1) { e1.printStackTrace(); } } }); } public void start() { JSynMusicDevice.instance().open(); buildShapes(); buildCollection(); printInfo(); /* Synchronize Java display. */ getParent().validate(); getToolkit().sync(); } public void stop() { col.finishAll(); try { col.waitForDone(); } catch (InterruptedException e) { e.printStackTrace(); } removeAll(); JMSL.closeMusicDevices(); } void buildCollection() { col = new ParallelCollection(s1, s2); col.setRepeats(2000); } void niceNames(MusicShape s) { s.setDimensionName(0, "Dur"); // give dimensions human friendly names s.setDimensionName(1, "Freq"); s.setDimensionName(2, "Rate"); s.setDimensionName(3, "Depth"); } void buildShapes() { s1 = new MusicShape(4); niceNames(s1); // dimensions are: duration, freq, rate, depth s1.add(1.0, 600, 0.5, 30); s1.add(1.0, 300, 3.0, 100); s1.add(1.0, 400, 2.0, 200); s1.add(2.0, 550, 12.0, 80); s1.add(1.0, 200, 4.0, 90); s1.setInstrument(new OscModIns(0)); s1.addStopPlayable(new RanTS()); s2 = new MusicShape(4); niceNames(s2); s2.add(1.0, 500, 0.6, 80); s2.add(1.0, 400, 16.0, 100); s2.add(2.0, 700, 1.5, 100); s2.add(1.0, 500, 3.0, 200); s2.add(1.0, 300, 5.0, 30); s2.setInstrument(new OscModIns(1)); s2.addStopPlayable(new RanTS()); } void printInfo() { col.printHierarchy(); System.out.println("--------"); col.print(); System.out.println("--------"); s1.print(); System.out.println("--------"); s2.print(); } // Define these as inner classes so the names don't conflict with other // classes. /** * One triangle wave modulating the other. * * @author (C) 1997 Phil Burk, All Rights Reserved */ class OscModCirc extends SynthNote { public TriangleOscillator osc1, osc2; public ExponentialLag expLag; public MultiplyAddUnit freqScalar; /* Declare ports. */ public SynthInput modDepth; /* Effect of LFO. */ public SynthInput modRate; /* Frequency of LFO. */ /* * Setup synthesis. */ public OscModCirc() throws SynthException { super(); /* Create various unit generators and add them to circuit. */ add(osc1 = new TriangleOscillator()); add(osc2 = new TriangleOscillator()); add(expLag = new ExponentialLag()); add(freqScalar = new MultiplyAddUnit()); osc1.output.connect(freqScalar.inputA); freqScalar.output.connect(expLag.input); expLag.output.connect(osc2.frequency); /* Make ports on internal units appear as ports on circuit. */ addPort(modRate = osc1.frequency, "modRate"); addPort(frequency = freqScalar.inputC, "frequency"); addPort(amplitude = osc2.amplitude); addPort(modDepth = freqScalar.inputB, "modDepth"); addPort(output = osc2.output); /* * Set signal type for frequency control so that we can operate in * hertz. */ frequency.setSignalType(Synth.SIGNAL_TYPE_OSC_FREQ); modDepth.setSignalType(Synth.SIGNAL_TYPE_OSC_FREQ); frequency.set(200.0); amplitude.set(0.2); modDepth.set(50.0); modRate.set(2.0); amplitude.set(0.5); expLag.halfLife.set(0.01); } } /** * A new custom instrument which uses an OscModCirc. */ class OscModIns extends InstrumentAdapter { OscModCirc circuit; LineOut unitOut; OscModIns(int leftRight) { try { circuit = new OscModCirc(); unitOut = new LineOut(); circuit.output.connect(0, unitOut.input, leftRight); } catch (SynthException e) { System.err.println(e); } } public double open(double time) throws InterruptedException { int itime = (int) JMSL.clock.timeToNative(time); // System.out.println("Instrument opened at " + itime ); circuit.start(itime); unitOut.start(itime); return time; } public double close(double time) throws InterruptedException { int itime = (int) JMSL.clock.timeToNative(time); // System.out.println("Instrument closed at " + itime ); circuit.stop(itime); unitOut.stop(itime); return time; } /* * Override play() method for Instrument class to provide custom * interpretation of shape data. */ public double play(double playTime, double timeStretch, double dar[]) { if (timeStretch < 0.1) { System.err.println("ERROR - timeStretch = " + timeStretch); System.exit(0); } // System.out.println("instr play( " + playTime + ", " + timeStretch // ); setModulation(playTime, dar[1], // freq dar[2] / timeStretch, // modRate - modulate slower when we // play slower dar[3]); // modDepth return playTime + (dar[0] * timeStretch); } /* Map shape parameters to frequency, modRate and ModDepth */ public void setModulation(double time, double frequency, double modRate, double modDepth) { try { int itime = (int) JMSL.clock.timeToNative(time); circuit.frequency.set(itime, frequency); circuit.modRate.set(itime, modRate); circuit.modDepth.set(itime, modDepth); } catch (SynthException e) { System.err.println(e); } } } class RanTS implements Playable { public double play(double playTime, Composable thing) { double stretch = (Math.random() * Math.random() * 2.0) + 0.1; thing.setTimeStretch(stretch); System.out.println("Stretch = " + stretch); return playTime; } } }