package jmslexamples.jsyn2; import com.softsynth.jmsl.Composable; import com.softsynth.jmsl.EventScheduler; import com.softsynth.jmsl.JMSL; import com.softsynth.jmsl.JMSLRandom; import com.softsynth.jmsl.MusicJob; import com.softsynth.jmsl.Playable; import com.softsynth.jmsl.jsyn2.JSynMusicDevice; import com.softsynth.jmsl.jsyn2.JSynUnitVoiceInstrument; import com.softsynth.jmsl.score.Clef; import com.softsynth.jmsl.score.Measure; import com.softsynth.jmsl.score.Orchestra; import com.softsynth.jmsl.score.Score; import com.softsynth.jmsl.score.ScoreFrame; import com.softsynth.jmsl.score.Tempo; import com.softsynth.jmsl.util.HalfCosineInterpolator; import com.softsynth.jmsl.util.Interpolator; import com.softsynth.jmsl.util.LinearInterpolator; import com.softsynth.jmsl.util.TimeSignature; /** * Cool new feature in JMSL lets you globally change the JMSL.clock rate. This * smoothly speeds up or slows down global scheduling and keeps all hierarchies * in synch * * This one measure has a startPlayable that launches a MusicJob that changes the JMSL.clock rate while the piece is playing * * @author Nick Didkovsky, copyright 2000 Nick Didkovsky */ public class JScoreJSynVariableClockRate { private Score score; private ScoreFrame scoreFrame; private Orchestra orch; public void start() { initJMSL(); initMusicDevices(); buildOrchestra(); buildScore(); buildRateChangers(); buildScoreFrame(); } private void initMusicDevices() { JSynMusicDevice.instance().open(); } private void initJMSL() { JMSL.clock.setAdvance(0.1); JMSL.scheduler = new EventScheduler(); JMSL.scheduler.start(); } private void termJMSL() { JMSL.scheduler.stop(); JMSL.closeMusicDevices(); } private void buildScoreFrame() { int w = score.getLayoutWidth(); int h = score.getLayoutHeight(); scoreFrame = new ScoreFrame("JMSL: Score & JSyn"); scoreFrame.addScore(score); scoreFrame.pack(); scoreFrame.setVisible(true); } private void buildScore() { int w = 800; int h = 450; int numStaves = 4; score = new Score(numStaves, w, h, "JMSL: Score & JSyn rate changing demo by Nick Didkovsky"); Measure m = score.addMeasure(8, 4); m.setTempo(60); // set bass clef for tuba score.getMeasure(0).getStaff(3).setClef(Clef.BASS_CLEF); score.setOrchestra(orch); score.getScoreLayoutManager().setZoom(0.5); score.getControlPanel().setZoom(0.5); score.setCurrentStaffNumber(0); for (int i = 0; i < 64; i++) { double dur = 0.25; double pitch = 72 + JMSLRandom.choose(12); double amp = JMSLRandom.choose(0.2, 0.6); score.addNote(dur, pitch, amp, dur * 0.8); } score.rewind(); score.setCurrentStaffNumber(1); for (int i = 0; i < 32; i++) { double dur = 0.5; double pitch = 60 + JMSLRandom.choose(12); double amp = JMSLRandom.choose(0.2, 0.6); if (JMSLRandom.choose() < 0.2) pitch = 0; score.addNote(dur, pitch, amp, dur * 0.8); } score.rewind(); score.setCurrentStaffNumber(2); for (int i = 0; i < 4; i++) { score.addNote(1, 57, 0.5, 1.5); score.addNote(1, 62, 0.5, 1.5); score.addNote(1, 65, 0.5, 1.5); score.addNote(1, 69, 0.5, 1.5); } score.rewind(); score.setCurrentStaffNumber(3); for (int i = 0; i < 4; i++) { score.addNote(2, 49, 0.5, 3.5); score.addNote(2, 54, 0.5, 3.5); } } void buildRateChangers() { for (int i = 0; i < score.size(); i++) { Measure measure = score.getMeasure(i); measure.addStartPlayable( new RateChangingPlayable(JMSLRandom.choose(0.2, 0.8), JMSLRandom.choose(1.0, 3.5))); } } private void buildOrchestra() { // Set up an JSynOrchestra to hand to Score, starts JSyn engine if it // needs to */ orch = new Orchestra(); orch.addInstrument(createBrassInstrument(), "trumpet 1"); orch.addInstrument(createBrassInstrument(), "trumpet 2"); orch.addInstrument(createBrassInstrument(), "horn"); orch.addInstrument(createBrassInstrument(), "tuba"); } private JSynUnitVoiceInstrument createBrassInstrument() { return new JSynUnitVoiceInstrument(1, com.softsynth.jmsl.jsyn2.unitvoices.FMVoice.class.getName(), com.softsynth.jmsl.jsyn2.unitvoices.FMVoice.PRESET_BRASS); } public ScoreFrame getScoreFrame() { return scoreFrame; } /* Can be run as either an application or as an applet. */ public static void main(String args[]) { JScoreJSynVariableClockRate demo = new JScoreJSynVariableClockRate(); demo.start(); } class RateResetPlayable implements Playable { @Override public double play(double time, Composable parent) throws InterruptedException { JMSL.clock.setRate(1); System.out.println("Setting rate back to 1"); return time; } } class RateChangingPlayable implements Playable { private boolean useHalfCosine = false; private double startRate = 1.0; private double endRate = 2.0; public RateChangingPlayable(double startRate, double endRate, boolean useHalfCosine) { super(); this.useHalfCosine = useHalfCosine; this.startRate = startRate; this.endRate = endRate; } public RateChangingPlayable(double startRate, double endRate) { this(startRate, endRate, false); } public double getStartRate() { return startRate; } public void setStartRate(double startRate) { this.startRate = startRate; } public double getEndRate() { return endRate; } public void setEndRate(double endRate) { this.endRate = endRate; } public boolean isUseHalfCosine() { return useHalfCosine; } public void setUseHalfCosine(boolean useHalfCosine) { this.useHalfCosine = useHalfCosine; } @Override public double play(double time, Composable parent) throws InterruptedException { Measure measure = (Measure) parent; TimeSignature ts = measure.getTimeSig(); Tempo tempo = measure.getTempo(); double totalTimeSigDuration = ts.getTotalTime(); double timeStretch = tempo.getTimeStretch(); double wallClockDurationOfMeasure = totalTimeSigDuration * timeStretch; int numberOfRepeats = ts.getNumerator() * 4; double durationOfMusicJob = wallClockDurationOfMeasure / numberOfRepeats; Interpolator rateInterp; if (isUseHalfCosine()) { rateInterp = new HalfCosineInterpolator(0, startRate, numberOfRepeats, endRate); } else { rateInterp = new LinearInterpolator(0, startRate, numberOfRepeats, endRate); } MusicJob mj = new MusicJob() { public double repeat(double playTime) { double rate = rateInterp.interp(getRepeatCount()); System.out.println("repeat count " + getRepeatCount() + ", rate=" + rate); JMSL.clock.setRate(rate); return playTime; } }; mj.setRepeatPause(durationOfMusicJob); mj.setRepeats(numberOfRepeats); mj.launch(time); System.out.println("Measure " + measure.getMeasureIndex() + ", " + wallClockDurationOfMeasure); return time; } } }