/* * Created on Apr 19, 2004 * */ package jmslexamples; import java.awt.*; import java.awt.event.*; import java.util.Vector; import com.didkovsky.portview.PVTextArea; import com.didkovsky.portview.swing.ViewFactorySwing; import com.softsynth.jmsl.*; import com.softsynth.jmsl.jsyn.JSynMusicDevice; import com.softsynth.jmsl.jsyn.SynthNoteAllPortsInstrument; import com.softsynth.jmsl.midi.MidiIO_JavaSound; import com.softsynth.jmsl.midi.MidiInstrument; import com.softsynth.jmsl.util.TuningET; import com.softsynth.jmsl.view.DimensionNameSpaceValuesEditorPanel; import com.softsynth.jmsl.view.PVPanelAdapter; /** * Play an Instrument by typing in a TextArea. Edit all dimensions of instrument * with faders. * * Demonstrates the use of Instrument.on() and Instrument.off() as well as * DimensionNameSpaceEditPanel * * This example uses both JSyn and MIDI Instruments * * This JSyn instrument uses 13 tone equal temperament tuning. * * Be sure to type in the TextArea so it can capture your key presses. * * @author Nick Didkovsky, email: didkovn@mail.rockefeller.edu, (c) 2004 Nick * Didkovsky, all rights reserved. * */ public class KeyboardInstrumentPlayer extends PVPanelAdapter implements KeyListener, DimensionNameSpaceEditable { private double[] data; private DimensionNameSpace dimensionNameSpace; private PVTextArea textArea; private Instrument instrument; static int LOWEST_PITCH = 60; static String SUPPORTED_KEYS = "zxcvbnmasdfghjklqwertyuiop"; private Vector depressedKeys = new Vector(); public KeyboardInstrumentPlayer(int rows, int cols) { textArea = JMSL.getViewFactory().createTextArea(rows, cols); textArea.addKeyListener(this); setLayout(new BorderLayout()); add(BorderLayout.WEST, textArea.getComponent()); } public void keyPressed(KeyEvent ev) { } /** Turn note on */ public void keyTyped(KeyEvent ev) { Character ch = new Character(ev.getKeyChar()); double pitch = keyToPitch(ev.getKeyChar()); if (!depressedKeys.contains(ch) && pitch != 0) { // System.out.println("keyTyped " + ev.getKeyChar()); depressedKeys.addElement(ch); if (instrument != null) { double[] dataClone = cloneDataAndSetPitch(pitch); instrument.on(JMSL.realTime(), 1.0, dataClone); } } } /** Turn note off */ public void keyReleased(KeyEvent ev) { Character ch = new Character(ev.getKeyChar()); depressedKeys.removeElement(ch); if (instrument != null) { double pitch = keyToPitch(ev.getKeyChar()); if (pitch != 0) { double[] dataClone = cloneDataAndSetPitch(pitch); instrument.off(JMSL.realTime(), 1.0, dataClone); } } } /** * This method clones data[] and sets the pitch from the key pressed. Cannot * just send data[] to instrument.play() because JSyn Instruments use a * hashtable of double[] to look up which allocated synthnote to turn off or * update() later. So each double[] must be a new object . */ private double[] cloneDataAndSetPitch(double pitch) { double[] dataClone = new double[data.length]; System.arraycopy(data, 0, dataClone, 0, data.length); dataClone[1] = pitch; return dataClone; } /** Convert key pressed to a pitch. return 0 if key not supported */ private double keyToPitch(char ch) { return indexToPitch(SUPPORTED_KEYS.indexOf(ch)); } private double indexToPitch(int index) { if (index != -1) { return index + LOWEST_PITCH; } return 0; } /** * Set instrument, store its DimensionNameSpace, build compatible double[], * and build a DimensionNameSpaceEditPanel to change the array's contents. */ public void setInstrument(Instrument instrument) { this.instrument = instrument; textArea.setText("Play Keys: " + instrument.getName()); dimensionNameSpace = instrument.getDimensionNameSpace(); data = new double[dimensionNameSpace.dimension()]; for (int i = 0; i < data.length; i++) { data[i] = dimensionNameSpace.getDefault(i); } DimensionNameSpaceValuesEditorPanel dimPanel = new DimensionNameSpaceValuesEditorPanel(dimensionNameSpace); dimPanel.addDimensionNameSpaceEditable(this); add(BorderLayout.EAST, dimPanel.getComponent()); } /** DimensionNameSpaceEditable interface */ public void setDimensionNameSpace(DimensionNameSpace d) { this.dimensionNameSpace = d; } /** DimensionNameSpaceEditable interface */ public DimensionNameSpace getDimensionNameSpace() { return dimensionNameSpace; } /** DimensionNameSpaceEditable interface */ public double[] getDoubleArray() { return data; } /** DimensionNameSpaceEditable interface */ public void setDoubleArray(double[] dar) { data = dar; } public static void main(String args[]) { JMSL.setViewFactory(new ViewFactorySwing()); Frame f = new Frame("Sonify your typing with JMSL Instruments, (c) 2004 Nick Didkovsky "); f.setLayout(new BorderLayout()); KeyboardInstrumentPlayer keyboardInstrumentPlayer1 = new KeyboardInstrumentPlayer(5, 40); KeyboardInstrumentPlayer keyboardInstrumentPlayer2 = new KeyboardInstrumentPlayer(5, 40); Panel p = new Panel(); p.setLayout(new GridLayout(2, 0, 0, 20)); p.add(keyboardInstrumentPlayer1.getComponent()); p.add(keyboardInstrumentPlayer2.getComponent()); f.add(BorderLayout.NORTH, p); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { JMSL.closeMusicDevices(); System.exit(0); } }); // open JSyn music device JSynMusicDevice dev = JSynMusicDevice.instance(); dev.edit(f); dev.open(); // open midi music device JMSL.midi = MidiIO_JavaSound.instance(); JMSL.midi.edit(f); JMSL.midi.open(); TuningET tuning13 = new TuningET(13); tuning13.setOctaveStretchCents(5); String synthNoteClassName = com.softsynth.jsyn.circuits.FilteredSawtoothBL.class.getName(); // synthNoteClassName = Synth5.class.getName(); SynthNoteAllPortsInstrument ins1 = new SynthNoteAllPortsInstrument(8, synthNoteClassName); ins1.setTuning(tuning13); keyboardInstrumentPlayer1.setInstrument(ins1); MidiInstrument ins2 = new MidiInstrument(1); keyboardInstrumentPlayer2.setInstrument(ins2); JMSLMixerContainer mixer = new JMSLMixerContainer(); mixer.start(); mixer.addInstrument(ins1, 0.4, 0.5); mixer.addInstrument(ins2, 0.6, 1.0); f.add(BorderLayout.SOUTH, mixer.getPanAmpControlPanel()); f.pack(); f.setVisible(true); System.out.println(System.getProperty("java.home")); } }