/* * Created on Jan 4, 2005 * */ package jmslexamples.simple; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.Vector; import javax.swing.JFrame; import javax.swing.JLabel; import com.softsynth.jmsl.Composable; import com.softsynth.jmsl.EventScheduler; import com.softsynth.jmsl.Instrument; import com.softsynth.jmsl.InstrumentPlayable; import com.softsynth.jmsl.JMSL; import com.softsynth.jmsl.JMSLMixerContainer; import com.softsynth.jmsl.JMSLRandom; import com.softsynth.jmsl.MusicJob; import com.softsynth.jmsl.MusicList; import com.softsynth.jmsl.MusicShape; import com.softsynth.jmsl.PlayLurker; import com.softsynth.jmsl.jsyn2.JSynMusicDevice; import com.softsynth.jmsl.jsyn2.JSynUnitVoiceInstrument; 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 * * Upgraded to JSyn2 API Dec 6, 2016 by ND * * @author Nick Didkovsky, nick@didkovsky.com * */ public class MusicListExample extends JFrame { JMSLMixerContainer mixer; Instrument instrument; MusicList myMusicList; public void start() { JMSLRandom.randomize(); initJMSL(); initMusicDevices(); buildMixer(); buildInstrument(); buildMusicList(); launchMusicList(); } private void initJMSL() { JMSL.scheduler = new EventScheduler(); JMSL.scheduler.start(); JMSL.clock.setAdvance(0.2); } private void initMusicDevices() { JSynMusicDevice.instance().open(); } private void buildMixer() { mixer = new JMSLMixerContainer(); mixer.start(); } private void buildInstrument() { // String unitVoiceClassName = com.softsynth.jmsl.jsyn2.unitvoices.FMVoice.class.getName(); // int unitVoicePreset = com.softsynth.jmsl.jsyn2.unitvoices.FMVoice.PRESET_BRASS; // int polyphony = 8; // instrument = new JSynUnitVoiceInstrument(polyphony, unitVoiceClassName, unitVoicePreset); instrument = new JSynUnitVoiceInstrument(8, com.softsynth.jmsl.jsyn2.unitvoices.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() { myMusicList.finishAll(); try { myMusicList.waitForDone(); } catch (InterruptedException e) { e.printStackTrace(); } JMSL.scheduler.stop(); JMSL.closeMusicDevices(); } public static void main(String[] args) { MusicListExample demo = new MusicListExample(); demo.add(new JLabel("There is no GUI for this example", JLabel.CENTER)); demo.setSize(800, 200); demo.setVisible(true); demo.start(); demo.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { demo.stop(); System.exit(0); } }); } } /** * * 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, nick@didkovsky.com * */ 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"); } }