package jmslexamples; import java.awt.*; import java.awt.event.*; import java.io.File; import java.io.IOException; import com.softsynth.jmsl.*; import com.softsynth.jmsl.midi.*; import com.softsynth.jmsl.view.JMSLScrollbar; import com.softsynth.jmsl.view.JMSLScrollbarProcessor; /** * Control the speed of a ParallelCollection. The collection has two MusicShapes in it: one plays a * riff twice as fast as the other. In order to stay in synch, the faster one has a repeat count of * 2, against a repeat count of 1 for the slower MusicShape. * * Note that when you change the timestretch in the second half of the pattern (ie during the seocnd * repeat of the faster MusicShape, the collection stays in synch. If you change timeStretch in the * first half (ie during the first repeat of the faster riff), the collection will play * out-of-synch, though accurately. Why? This is because the faster MusicShape gets the new * timeStretch value on its second repeat, and plays this secoind repeat at the new timeStretch * speed, while the slower one is still playing through its current repeat at the old timeStretch * speed. * * @author Nick Didkovsky, 1/21/99 4:54AM CalArts, copyright (c) 1999, Nick Didkovsky */ public class ParallelMidiShapesExample extends Frame implements ActionListener, JMSLScrollbarProcessor { private Button startButton; private Button stopButton; private ParallelCollection parCol; private JMSLScrollbar speedyScrollbar; private Label speedyLabel; private Button speedyButton; private double dur = 1.0; private int numShapes = 2; public ParallelMidiShapesExample() { setLayout(new BorderLayout()); Panel p = new Panel(); p.setLayout(new GridLayout(0, 1)); speedyLabel = new Label(durString()); speedyScrollbar = new JMSLScrollbar(this, (int) dur * 1000, 10, 6000); // starting value, // min, max // set the size of the scrollbar speedyScrollbar.setSize(320, 25); // set the increment that the value will jump when user clicks inside scrollbar speedyScrollbar.setPageIncrement(100); speedyButton = new Button("Set Time Stretch"); p.add(speedyLabel); p.add(speedyScrollbar); p.add(speedyButton); add("North", p); p = new Panel(); p.add(startButton = new Button("Start")); p.add(stopButton = new Button("Stop")); add("South", p); startButton.addActionListener(this); stopButton.addActionListener(this); speedyButton.addActionListener(this); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent event) { JMSL.closeMusicDevices(); System.exit(0); } }); pack(); buildParallelMidiShapes(numShapes); } /** * Build a parallel collection of shapes played by midi, each new shape twice as fast as * previous. */ void buildParallelMidiShapes(int numShapes) { parCol = new ParallelCollection(); for (int i = 0; i < numShapes; i++) { MusicShape s = new MusicShape(4); fillShape(s, i); s.setInstrument(new MidiInstrument(1)); parCol.add(s); } } void fillShape(MusicShape s, int i) { double dur = Math.pow(0.5, i); s.add(dur, 55 + 3 * i, 120, dur * 0.75); s.add(dur, 58 + 3 * i, 110, dur * 0.75); s.add(dur, 63 + 3 * i, 100, dur * 0.75); s.add(dur, 69 + 3 * i, 95, dur * 0.75); s.setRepeats(100 * (int) (1.0 / dur)); } String durString() { return "Time Stretch: " + dur; } void handleSpeedyChange() { dur = speedyScrollbar.getValue() / 1000.0; speedyLabel.setText(durString()); } /** * Any class using a JMSLScrollbar must implement JMSLScrollbarProcessor by defining this method */ public void JMSLScrollbarValueChanged(JMSLScrollbar jsb) { if (jsb == speedyScrollbar) { handleSpeedyChange(); } } void handleSpeedyButton() { parCol.setTimeStretch(dur); } void handleStart() { parCol.finishAll(); parCol.launch(JMSL.now()); } void handleStop() { parCol.finishAll(); } public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source == speedyButton) handleSpeedyButton(); if (source == startButton) handleStart(); if (source == stopButton) handleStop(); } public static void main(String args[]) { ParallelMidiShapesExample gui = new ParallelMidiShapesExample(); try { // you can download this SoundFont at http://www.algomusic.com/SoundFonts/ // this will only work if you are running Java 1.7 or higher and using JavSound's Gervill device String LOCATION_OF_SOUNDFONT = "F:/jwork/SoundFonts/FluidR3/FluidR3 GM2-2.SF2"; JMSL.midi = new MidiIOFactory().getMidiIO(MidiIOFactory.MidiIO_JAVASOUND); ((MidiIO_JavaSound) JMSL.midi).setSoundbankFile(new File(LOCATION_OF_SOUNDFONT)); String javaSpecStr = System.getProperty("java.specification.version"); double javaSpecVersion = javaSpecStr != null ? Double.parseDouble(javaSpecStr) : 0; String requestedDeviceName = javaSpecVersion < 1.7 ? "Java Sound Synthesizer" : "Gervill"; JMSL.midi.setOutDevice(requestedDeviceName); JMSL.midi.edit(gui); JMSL.midi.open(); } catch (IOException e2) { e2.printStackTrace(); } gui.setVisible(true); } }