/* * Created by Nick Didkovsky on Nov 28, 2004 * */ package jmsltutorial; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import com.softsynth.jmsl.*; import com.softsynth.jmsl.jsyn.JSynInsFromClassName; import com.softsynth.jmsl.jsyn.JSynMusicDevice; import com.softsynth.jmsl.view.JMSLScrollbar; import com.softsynth.jmsl.view.JMSLScrollbarProcessor; /** * Play a melody with a MusicShape while a PlayLurker is notified of every * element played. With some probability, the PlayLurker doubles the pitch * played by the MusicShape. This is modelled after Sabbath Bride, * http://www.punosmusic.com/pages/sabbathbride/sabbathbride.html * * * @author Nick Didkovsky, (c) 2004 All rights reserved, Email: * didkovn@mail.rockefeller.edu * */ public class PlayLurkerToot01 extends java.applet.Applet implements ActionListener, JMSLScrollbarProcessor { JMSLMixerContainer mixer; SabbathBrideMusicShape sabbathBrideMusicShape; JSynInsFromClassName ghostVoiceInstrument; GhostVoicePlayLurker lurker; JMSLScrollbar probScrollbar; Label probLabel; Button startButton; Button stopButton; public void init() { JMSLRandom.randomize(); JMSL.setIsApplet(true); } public void start() { synchronized (JMSL.class) { JMSL.clock.setAdvance(0.1); JSynMusicDevice.instance().open(); mixer = new JMSLMixerContainer(); mixer.start(); // this MusicShape comes with its own data and its own custom // instrument sabbathBrideMusicShape = new SabbathBrideMusicShape(); sabbathBrideMusicShape.setRepeats(Integer.MAX_VALUE); sabbathBrideMusicShape.setTimeStretch(1.2); sabbathBrideMusicShape.getInstrument().setName("Melody"); ghostVoiceInstrument = new JSynInsFromClassName(32, SlowSine.class.getName()); ghostVoiceInstrument.setName("Ghost"); mixer.addInstrument(sabbathBrideMusicShape.getInstrument(), 0.2, 0.1); mixer.addInstrument(ghostVoiceInstrument, 0.7, 0.5); // IMPORTANT! Add PlayLurker to MusicShape. PlayLurker will be // notified of every element played lurker = new GhostVoicePlayLurker(ghostVoiceInstrument); sabbathBrideMusicShape.addPlayLurker(lurker); buildGUI(); } } private void buildGUI() { Panel buttonPanel = new Panel(); buttonPanel.setLayout(new FlowLayout()); buttonPanel.add(startButton = new Button("Start")); buttonPanel.add(stopButton = new Button("Stop")); stopButton.setEnabled(false); startButton.addActionListener(this); stopButton.addActionListener(this); Panel scrollPanel = new Panel(); scrollPanel.setLayout(new FlowLayout()); scrollPanel.add(new Label("Probability of PlayLurker doubling melody")); probScrollbar = new JMSLScrollbar(this, 50, 0, 100); probScrollbar.setSize(100, 20); probScrollbar.setPageIncrement(10); probScrollbar.setLineIncrement(1); scrollPanel.add(probScrollbar); scrollPanel.add(probLabel = new Label("p=" + lurker.getPlayProbability())); setLayout(new BorderLayout()); add(BorderLayout.SOUTH, buttonPanel); add(BorderLayout.CENTER, mixer.getPanAmpControlPanel()); add(BorderLayout.NORTH, scrollPanel); } public void stop() { synchronized (JMSL.class) { sabbathBrideMusicShape.finishAll(); try { sabbathBrideMusicShape.waitForDone(); } catch (InterruptedException e) { } JMSL.closeMusicDevices(); } } public void actionPerformed(ActionEvent ev) { Object source = ev.getSource(); if (source == startButton) { sabbathBrideMusicShape.launch(JMSL.now()); startButton.setEnabled(false); stopButton.setEnabled(true); } if (source == stopButton) { sabbathBrideMusicShape.finish(); startButton.setEnabled(true); stopButton.setEnabled(false); } } public void JMSLScrollbarValueChanged(JMSLScrollbar jsb) { double p = jsb.getValue() / 100.0; lurker.setPlayProbability(p); probLabel.setText("p=" + p); } } class GhostVoicePlayLurker implements PlayLurker { double playProbability = 0.4; Instrument ins; public GhostVoicePlayLurker(Instrument ins) { this.ins = ins; } /** * PlayLurker is notified of every element being played. With some * probability, double the pitch played with a slow sine, 1 or 2 octaves * down, at pitch, or 1 or 2 octaves up * */ public void notifyPlayLurker(double playTime, MusicJob list, int index) { if (JMSLRandom.choose() < getPlayProbability()) { double[] data = ((MusicShape) list).get(index); double pitch = data[1]; // build data for instrument to perform double[] ghostData = new double[4]; ghostData[0] = JMSLRandom.choose(5.0, 10.0); int transpose = JMSLRandom.choose(5) - 2; ghostData[1] = pitch + 12 * transpose; ghostData[2] = JMSLRandom.choose(0.25, 0.4); ghostData[3] = 0.95 * ghostData[0]; // now perform it! This plays ONE pitched musical event in synch with the melody ins.play(playTime, 1.0, ghostData); } } public double getPlayProbability() { return playProbability; } public void setPlayProbability(double playProbability) { this.playProbability = playProbability; } }