package jmslexamples.jsyn2; /** * Control the JMSL clock rate for a JMSL score during playback. * * Each of four staves plays elements that are twice as fast and an octave * higher than the previous (gamelan style). This lets use clearly hear that the * elements stay in sync when the clock rate changes. This demonstrates a * significant improvement in JMSL scheduling. Timestretch works great to change * playback speed instantaneously at boundaries (like measures in a score), but * didn't work for continuously changing tempo like accel and decel. Instead, we * now change the JMSL.clock rate, and this demo shows that all children of the * collection will stay in sync as the user moves the scrollbar to change * playback rate. * * 2023-01-17 * * @author Nick Didkovsky, 2023-01-17, copyright (c) 2023, Nick Didkovsky */ import java.awt.BorderLayout; import java.util.Vector; import javax.swing.JPanel; import com.didkovsky.portview.PVLabel; import com.didkovsky.portview.PVScrollbar; import com.didkovsky.portview.PVScrollbarListener; import com.didkovsky.portview.swing.ViewFactorySwing; import com.softsynth.jmsl.JMSL; import com.softsynth.jmsl.MusicShape; import com.softsynth.jmsl.jsyn2.JSynMusicDevice; import com.softsynth.jmsl.jsyn2.JSynUnitVoiceInstrument; 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.score.transcribe.BeatDivisionSchemeList; import com.softsynth.jmsl.score.transcribe.ElementMissedException; import com.softsynth.jmsl.score.transcribe.SearchPathListExpansionException; import com.softsynth.jmsl.score.transcribe.TempoTimeSignatureHolder; import com.softsynth.jmsl.score.transcribe.Transcriber; import com.softsynth.jmsl.util.TimeSignature; import com.softsynth.jmsl.view.PVLabelAdapter; public class NicksDreamScore implements PVScrollbarListener { Orchestra orch; Score score; ScoreFrame scoreFrame; private PVScrollbar speedyScrollbar; private PVLabel speedyLabel; double currentClockRate = 1.0; void buildScore() { score = new Score(4, 800, 500, "Nick's Dream"); score.setComposer("Nick Didkovsky"); score.setScoreSubtitle("demonstrates global clock rate changes"); score.addMeasure(); scoreFrame = new ScoreFrame(); scoreFrame.addScore(score); speedyScrollbar = new PVScrollbar((int) currentClockRate * 1000, 10, 6000); speedyScrollbar.addPVScrollbarListener(this); speedyScrollbar.setSize(320, 25); speedyScrollbar.setPageIncrement(100); // JPanel p = new JPanel(); speedyLabel = new PVLabelAdapter(rateString()); p.add(speedyLabel.getComponent()); p.add(speedyScrollbar.getComponent()); scoreFrame.add(BorderLayout.SOUTH, p); } String rateString() { return "Clock Rate: " + currentClockRate; } void transcribeScore() { BeatDivisionSchemeList.defaultSetup(); Transcriber transcriber = new Transcriber(); transcriber.setScore(score); Vector tempoTimeSigs = new Vector(); tempoTimeSigs.add(new TempoTimeSignatureHolder(new Tempo(60), new TimeSignature(4, 4))); transcriber.setTempoTimeSignatures(tempoTimeSigs); MusicShape[] arr = buildMusicShapes(); for (int i = 0; i < arr.length; i++) { MusicShape s = arr[i]; s.integrate(0); score.rewind(); score.setCurrentStaffNumber(i); transcriber.setSourceMusicShape(s); try { transcriber.transcribe(); } catch (SearchPathListExpansionException | ElementMissedException e) { e.printStackTrace(); } } } void initMusicDevice() { JSynMusicDevice.instance().open(); JMSL.clock.setAdvance(0.1); } void buildOrch() { orch = new Orchestra(); orch.addInstrument( new JSynUnitVoiceInstrument(1, jmslexamples.jsyn2.unitvoices.SpeedyUnitVoice.class.getName())); orch.addInstrument( new JSynUnitVoiceInstrument(1, jmslexamples.jsyn2.unitvoices.SpeedyUnitVoice.class.getName())); orch.addInstrument( new JSynUnitVoiceInstrument(1, jmslexamples.jsyn2.unitvoices.SpeedyUnitVoice.class.getName())); orch.addInstrument( new JSynUnitVoiceInstrument(1, jmslexamples.jsyn2.unitvoices.SpeedyUnitVoice.class.getName())); score.setOrchestra(orch); orch.getJMSLMixerContainer().panAmpChange(0, 0, 0.3); orch.getJMSLMixerContainer().panAmpChange(1, 1.0, 0.5); orch.getJMSLMixerContainer().panAmpChange(2, .25, 0.5); orch.getJMSLMixerContainer().panAmpChange(3, .75, 0.5); } MusicShape[] buildMusicShapes() { MusicShape[] shapes = new MusicShape[4]; MusicShape musicShape_1 = new MusicShape(9); musicShape_1.setDimensionName(0, "duration"); musicShape_1.setLimits(0, 0.0, 8.0); musicShape_1.setDefault(0, 1.0); musicShape_1.setDimensionName(1, "pitch"); musicShape_1.setLimits(1, 0.0, 127.0); musicShape_1.setDefault(1, 60.0); musicShape_1.setDimensionName(2, "amplitude"); musicShape_1.setLimits(2, 0.0, 1.0); musicShape_1.setDefault(2, 0.25); musicShape_1.setDimensionName(3, "hold"); musicShape_1.setLimits(3, 0.0, 8.0); musicShape_1.setDefault(3, 0.5); musicShape_1.setDimensionName(4, "Attack"); musicShape_1.setLimits(4, 0.0, 1.0); musicShape_1.setDefault(4, 0.01); musicShape_1.setDimensionName(5, "Decay"); musicShape_1.setLimits(5, 0.0, 1.0); musicShape_1.setDefault(5, 0.3); musicShape_1.setDimensionName(6, "Delay"); musicShape_1.setLimits(6, 0.0, 1.0); musicShape_1.setDefault(6, 0.0); musicShape_1.setDimensionName(7, "Release"); musicShape_1.setLimits(7, 0.0, 1.0); musicShape_1.setDefault(7, 0.4); musicShape_1.setDimensionName(8, "Sustain"); musicShape_1.setLimits(8, 0.0, 1.0); musicShape_1.setDefault(8, 0.8); musicShape_1.add(0.25, 93.0016917949672, 0.5, 0.225, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_1.add(0.25, 84.1044842016464, 0.5, 0.225, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_1.add(0.25, 84.86482893361556, 0.5, 0.225, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_1.add(0.25, 88.7279660722639, 0.5, 0.225, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_1.add(0.25, 86.41622513695515, 0.5, 0.225, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_1.add(0.25, 84.1044842016464, 0.5, 0.225, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_1.add(0.25, 89.9296061276893, 0.5, 0.225, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_1.add(0.25, 91.96870614499704, 0.5, 0.225, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_1.add(0.25, 82.63741520103443, 0.5, 0.225, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_1.add(0.25, 92.32567426572567, 0.5, 0.225, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_1.add(0.25, 85.3061242570718, 0.5, 0.225, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_1.add(0.25, 88.46253712707733, 0.5, 0.225, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_1.add(0.25, 81.44298711842345, 0.5, 0.225, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_1.add(0.25, 88.46253712707733, 0.5, 0.225, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_1.add(0.25, 85.3061242570718, 0.5, 0.225, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_1.add(0.25, 92.32567426572567, 0.5, 0.225, 0.01, 0.3, 0.0, 0.4, 0.8); shapes[0] = musicShape_1; MusicShape musicShape_2 = new MusicShape(9); musicShape_2.setDimensionName(0, "duration"); musicShape_2.setLimits(0, 0.0, 8.0); musicShape_2.setDefault(0, 1.0); musicShape_2.setDimensionName(1, "pitch"); musicShape_2.setLimits(1, 0.0, 127.0); musicShape_2.setDefault(1, 60.0); musicShape_2.setDimensionName(2, "amplitude"); musicShape_2.setLimits(2, 0.0, 1.0); musicShape_2.setDefault(2, 0.25); musicShape_2.setDimensionName(3, "hold"); musicShape_2.setLimits(3, 0.0, 8.0); musicShape_2.setDefault(3, 0.5); musicShape_2.setDimensionName(4, "Attack"); musicShape_2.setLimits(4, 0.0, 1.0); musicShape_2.setDefault(4, 0.01); musicShape_2.setDimensionName(5, "Decay"); musicShape_2.setLimits(5, 0.0, 1.0); musicShape_2.setDefault(5, 0.3); musicShape_2.setDimensionName(6, "Delay"); musicShape_2.setLimits(6, 0.0, 1.0); musicShape_2.setDefault(6, 0.0); musicShape_2.setDimensionName(7, "Release"); musicShape_2.setLimits(7, 0.0, 1.0); musicShape_2.setDefault(7, 0.4); musicShape_2.setDimensionName(8, "Sustain"); musicShape_2.setLimits(8, 0.0, 1.0); musicShape_2.setDefault(8, 0.8); musicShape_2.add(0.5, 72.86482893361557, 0.5, 0.45, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_2.add(0.5, 76.72796607226391, 0.5, 0.45, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_2.add(0.5, 77.64975323687389, 0.5, 0.45, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_2.add(0.5, 76.72796607226391, 0.5, 0.45, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_2.add(0.5, 78.76706608957166, 0.5, 0.45, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_2.add(0.5, 73.78661609822552, 0.5, 0.45, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_2.add(0.5, 77.64975323687389, 0.5, 0.45, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_2.add(0.5, 72.66930324552776, 0.5, 0.45, 0.01, 0.3, 0.0, 0.4, 0.8); shapes[1] = musicShape_2; MusicShape musicShape_3 = new MusicShape(9); musicShape_3.setDimensionName(0, "duration"); musicShape_3.setLimits(0, 0.0, 8.0); musicShape_3.setDefault(0, 1.0); musicShape_3.setDimensionName(1, "pitch"); musicShape_3.setLimits(1, 0.0, 127.0); musicShape_3.setDefault(1, 60.0); musicShape_3.setDimensionName(2, "amplitude"); musicShape_3.setLimits(2, 0.0, 1.0); musicShape_3.setDefault(2, 0.25); musicShape_3.setDimensionName(3, "hold"); musicShape_3.setLimits(3, 0.0, 8.0); musicShape_3.setDefault(3, 0.5); musicShape_3.setDimensionName(4, "Attack"); musicShape_3.setLimits(4, 0.0, 1.0); musicShape_3.setDefault(4, 0.01); musicShape_3.setDimensionName(5, "Decay"); musicShape_3.setLimits(5, 0.0, 1.0); musicShape_3.setDefault(5, 0.3); musicShape_3.setDimensionName(6, "Delay"); musicShape_3.setLimits(6, 0.0, 1.0); musicShape_3.setDefault(6, 0.0); musicShape_3.setDimensionName(7, "Release"); musicShape_3.setLimits(7, 0.0, 1.0); musicShape_3.setDefault(7, 0.4); musicShape_3.setDimensionName(8, "Sustain"); musicShape_3.setLimits(8, 0.0, 1.0); musicShape_3.setDefault(8, 0.8); musicShape_3.add(1.0, 64.0212418036211, 0.5, 0.9, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_3.add(1.0, 57.846363729664006, 0.5, 0.9, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_3.add(1.0, 64.86591373831787, 0.5, 0.9, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_3.add(1.0, 57.846363729664, 0.5, 0.9, 0.01, 0.3, 0.0, 0.4, 0.8); shapes[2] = musicShape_3; MusicShape musicShape_4 = new MusicShape(9); musicShape_4.setDimensionName(0, "duration"); musicShape_4.setLimits(0, 0.0, 8.0); musicShape_4.setDefault(0, 1.0); musicShape_4.setDimensionName(1, "pitch"); musicShape_4.setLimits(1, 0.0, 127.0); musicShape_4.setDefault(1, 60.0); musicShape_4.setDimensionName(2, "amplitude"); musicShape_4.setLimits(2, 0.0, 1.0); musicShape_4.setDefault(2, 0.25); musicShape_4.setDimensionName(3, "hold"); musicShape_4.setLimits(3, 0.0, 8.0); musicShape_4.setDefault(3, 0.5); musicShape_4.setDimensionName(4, "Attack"); musicShape_4.setLimits(4, 0.0, 1.0); musicShape_4.setDefault(4, 0.01); musicShape_4.setDimensionName(5, "Decay"); musicShape_4.setLimits(5, 0.0, 1.0); musicShape_4.setDefault(5, 0.3); musicShape_4.setDimensionName(6, "Delay"); musicShape_4.setLimits(6, 0.0, 1.0); musicShape_4.setDefault(6, 0.0); musicShape_4.setDimensionName(7, "Release"); musicShape_4.setLimits(7, 0.0, 1.0); musicShape_4.setDefault(7, 0.4); musicShape_4.setDimensionName(8, "Sustain"); musicShape_4.setLimits(8, 0.0, 1.0); musicShape_4.setDefault(8, 0.8); musicShape_4.add(2.0, 48.864828933615584, 0.5, 1.8, 0.01, 0.3, 0.0, 0.4, 0.8); musicShape_4.add(2.0, 46.553087998306836, 0.5, 1.8, 0.01, 0.3, 0.0, 0.4, 0.8); shapes[3] = musicShape_4; return shapes; } void show() { scoreFrame.pack(); scoreFrame.setVisible(true); } public static void main(String[] args) { JMSL.setViewFactory(new ViewFactorySwing()); NicksDreamScore nicksDreamScore = new NicksDreamScore(); nicksDreamScore.initMusicDevice(); nicksDreamScore.buildScore(); nicksDreamScore.buildOrch(); nicksDreamScore.transcribeScore(); nicksDreamScore.show(); } void handleSpeedyChange() { currentClockRate = speedyScrollbar.getValue() / 1000.0; speedyLabel.setText(rateString()); JMSL.clock.setRate(currentClockRate); } @Override public void notifyScrollbarValueChanged(PVScrollbar sb) { if (sb == speedyScrollbar) { handleSpeedyChange(); } } }