/* * Created on Jan 4, 2005 * */ package jmslexamples.simple; import java.applet.Applet; import java.util.Vector; import com.softsynth.jmsl.*; import com.softsynth.jmsl.jsyn.JSynInsFromClassName; import com.softsynth.jmsl.jsyn.JSynMusicDevice; import com.softsynth.jmsl.util.HarmonicComplexity; /** * Schedule a sequence of chord-making objects. * * MusicList holds InstrumentPlayable objects. When a MusicList is launched, it calls the play() * method of each of its InstrumentPlayables sequentially. MusicList passes its instrument to each * InstrumentPlayable's play() method, and waits for the timestamp returned by InstrumentPlayable's * play() method. * * Use this if you want to schedule Objects in a way similar to the way MusicShape schedules * elements of double[] * * Also demonstrates how to define a PlayLurker which receives notification of objects being played * * @author Nick Didkovsky, didkovn@mail.rockefeller.edu * */ public class MusicListExample extends Applet { JMSLMixerContainer mixer; Instrument instrument; MusicList myMusicList; public void init() { JMSL.setIsApplet(true); JMSLRandom.randomize(); } public void start() { synchronized (JMSL.class) { initJMSL(); initMusicDevices(); buildMixer(); buildInstrument(); buildMusicList(); launchMusicList(); } } private void initJMSL() { JMSL.scheduler = new EventScheduler(); JMSL.scheduler.start(); JMSL.clock.setAdvance(0.1); } private void initMusicDevices() { JSynMusicDevice.instance().open(); } private void buildMixer() { mixer = new JMSLMixerContainer(); mixer.start(); } private void buildInstrument() { instrument = new JSynInsFromClassName(8, com.softsynth.jsyn.circuits.FilteredSawtoothBL.class.getName()); mixer.addInstrument(instrument); } protected void buildMusicList() { myMusicList = new MusicList(); myMusicList.setInstrument(instrument); myMusicList.addPlayLurker(new Skulker()); // The following chords all have the same root pitch with up to six intervals above, with // increasing // harmonic complexity limit. So chords at the beginning will sound generally less strident // than chords at the end myMusicList.add(new ChordMaker(3.0, 50, 6, 0)); myMusicList.add(new ChordMaker(3.0, 50, 6, 1)); myMusicList.add(new ChordMaker(3.0, 50, 6, 2)); myMusicList.add(new ChordMaker(3.0, 50, 6, 3)); myMusicList.add(new ChordMaker(3.0, 50, 6, 4)); myMusicList.add(new ChordMaker(3.0, 50, 6, 5)); myMusicList.add(new ChordMaker(3.0, 50, 6, 6)); myMusicList.add(new ChordMaker(3.0, 50, 6, 7)); myMusicList.add(new ChordMaker(3.0, 50, 6, 8)); myMusicList.add(new ChordMaker(3.0, 50, 6, 9)); myMusicList.add(new ChordMaker(3.0, 50, 6, 10)); myMusicList.add(new ChordMaker(3.0, 50, 6, 11)); } private void launchMusicList() { myMusicList.launch(JMSL.now()); } public void stop() { synchronized (JMSL.class) { myMusicList.finishAll(); try { myMusicList.waitForDone(); } catch (InterruptedException e) { e.printStackTrace(); } JMSL.scheduler.stop(); JMSL.closeMusicDevices(); } } } /** * * plays a chord using the instrument passed in to play(). Chord is built based on root, number of * intervals, and harmonic complexity * * @author Nick Didkovsky, didkovn@mail.rockefeller.edu * */ class ChordMaker implements InstrumentPlayable { private double duration; private double root; private double numIntervals; private int harmonicComplexity; public ChordMaker(double duration, double root, double numIntervals, int harmonicComplexity) { this.duration = duration; this.root = root; this.numIntervals = numIntervals; this.harmonicComplexity = harmonicComplexity; } public double play(double playTime, Composable parent, Instrument ins) { JMSL.out.println("ChordMaker making chord with root " + root + " and up to " + numIntervals + " intervals, with harmonic complexity limit " + harmonicComplexity); double amplitude = 1.0 / (numIntervals + 1); double[] data = MusicShape.getDefaultArray(ins.getDimensionNameSpace()); data[0] = duration; // duration in array[0] by convention data[1] = root; // pitch in array[1] by convention data[2] = amplitude; // amp in array[2] by convention data[3] = duration * 0.9; // hold (sustain) time in array[3] by convention JMSL.out.print("root: "); JMSL.printDoubleArray(data); ins.play(playTime, 1.0, data); // prevent hitting the same pitch twice by storing played pitches Vector pitchesPlayed = new Vector(); pitchesPlayed.addElement(new Double(root)); for (int i = 0; i < numIntervals; i++) { double pitch = root + HarmonicComplexity.gimmeRandomHarmonicComplexity(harmonicComplexity); if (!pitchesPlayed.contains(new Double(pitch))) { pitchesPlayed.addElement(new Double(pitch)); data[1] = pitch; ins.play(playTime, 1.0, data); JMSL.out.print("interval: "); JMSL.printDoubleArray(data); } } return playTime + duration; } } class Skulker implements PlayLurker { public void notifyPlayLurker(double playTime, MusicJob list, int index) { JMSL.out.println("Skulker is being notifed that InstrumentPlayable index " + index + " is being played"); } }