package jmslexamples.jsyn; import java.awt.*; import java.applet.Applet; import com.softsynth.jsyn.*; import com.softsynth.jsyn.view102.*; import com.softsynth.jmsl.*; import com.softsynth.jmsl.jsyn.*; /** * A small composition using the Java Audio Synthesiser. * Each voice has an FM pair. The Carrier frequency is set * to the last Frequency times a whole number ratio. The Modulator * Frequency is set to the last Frequency. * This example extends FMNoodler by adding envelopes. * @author Phil Burk */ /* * (C) 1997 Phil Burk * All Rights Reserved */ class FMNoodlerEnv extends FMNoodler { SynthEnvelope myEnvData; public EnvelopePlayer myEnv; public FMNoodlerEnv(double duration, int flags, double ampl) throws SynthException { super(duration, flags); System.out.println("FMNoodlerEnv(dur=" + duration + ", " + flags); /* Create an envelope 1/10th length as duration. */ double[] data = { duration * 0.01, ampl, /* duration,value pair for frame[0] */ duration * 0.20, 0.4 * ampl, /* duration,value pair for frame[1] */ duration * 0.80, 0.0 /* duration,value pair for frame[2] */ }; int numFrames = data.length / 2; myEnvData = new SynthEnvelope(numFrames); myEnvData.write(0, data, 0, numFrames); /* Create an envelope playing unit generator. */ myEnv = new EnvelopePlayer(); /* Add myEnv before fmPair is started so that it gets compiled into circuit. */ fmPair.add(myEnv); /* Use envelope to control oscillator amplitude. */ myEnv.output.connect(fmPair.amplitude); } /* Override repeat() method for MusicJob to play a note. */ public double repeat(double playTime) throws InterruptedException { // System.out.println("repeat(" + playTime + ")"); int itime = (int) JMSL.clock.timeToNative(playTime); try { /* Randomly skip a note. */ if (Math.random() < 0.8) { myEnv.envelopePort.clear(itime); /* Make FMPair stop when envelope finishes. */ myEnv.envelopePort.queue(itime, myEnvData, 0, myEnvData.getNumFrames(), Synth.FLAG_AUTO_STOP); } playTime = super.repeat(playTime); } catch (SynthException e) { SynthAlert.showError(null, e); } return playTime; } } /* *************************************************************** */ public class TuningNoodler1 extends Applet { public static final int NUM_NOODLERS = 4; public static final double BASE_PERIOD = 0.1; /* fundamental note delay in seconds */ FMNoodlerEnv[] noodlers = new FMNoodlerEnv[NUM_NOODLERS]; SynthScope scope; /* Can be run as either an application or as an applet. */ public static void main(String args[]) { TuningNoodler1 applet = new TuningNoodler1(); AppletFrame frame = new AppletFrame("FM Blips with Dynamic Tuning.", applet); frame.setSize(600, 400); frame.show(); /* Begin test after frame opened so that DirectSound will use Java window. */ frame.test(); } /* * Setup synthesis. */ public void start() { setLayout(new GridLayout(0, 1)); JSynMusicDevice.instance().open(); /* Create several noodlers that run at different rates. */ double ampl = 0.9 / NUM_NOODLERS; /* Guarantee no clipping. */ for (int i = 0; i < NUM_NOODLERS; i++) { noodlers[i] = new FMNoodlerEnv((1 + i) * BASE_PERIOD, FMNoodler.LEFT + FMNoodler.RIGHT, ampl); noodlers[i].setRepeats(4000); } /* Start execution of units staggered in time. */ double startTime = JMSL.now(); for (int i = 0; i < NUM_NOODLERS; i++) { noodlers[i].launch(startTime); startTime += 10 * BASE_PERIOD; } /* Add a button that polls and displays the current CPU usage. */ add(new UsageDisplay()); /* Synchronize Java display. */ getParent().validate(); getToolkit().sync(); } public void stop() { try { removeAll(); for (int i = 0; i < NUM_NOODLERS; i++) { noodlers[i].finishAll(); noodlers[i].waitForDone(); } JMSL.closeMusicDevices(); } catch (Exception e) { System.out.println("Exception when stopping! " + e); } } }