diff options
author | unknown <Adam Martindale@.(none)> | 2011-09-16 12:40:39 +0100 |
---|---|---|
committer | unknown <Adam Martindale@.(none)> | 2011-09-16 12:40:39 +0100 |
commit | 201f4564f236ee1a15ebfe1efc16929375f9947c (patch) | |
tree | d03a83839d14909d3c58c1d5b2fc6dfcd033d74d | |
parent | e1a7613135ea099deaa82e16a9eba8bd02b83689 (diff) | |
parent | 2f9556e87d356051f412e73394833627347d848e (diff) | |
download | punchingbag-201f4564f236ee1a15ebfe1efc16929375f9947c.tar punchingbag-201f4564f236ee1a15ebfe1efc16929375f9947c.tar.gz |
Merge branch 'master' of gitorious.org:punchingbag/punchingbag
Conflicts:
PunchingBag/src/uk/ac/open/punchingbag/examples/SimpleKeyboard.java
3 files changed, 244 insertions, 25 deletions
diff --git a/PunchingBag/src/uk/ac/open/punchingbag/PunchingBag.java b/PunchingBag/src/uk/ac/open/punchingbag/PunchingBag.java index 7f0fe06..7477f0c 100644 --- a/PunchingBag/src/uk/ac/open/punchingbag/PunchingBag.java +++ b/PunchingBag/src/uk/ac/open/punchingbag/PunchingBag.java @@ -108,7 +108,7 @@ public class PunchingBag implements Runnable { * linux) */ String buttonArduinoDeviceAddress = "COM4"; // TODO: This should be cached - // localy + // localy /** * The Arduino managing the led drivers */ @@ -117,7 +117,8 @@ public class PunchingBag implements Runnable { * The device address of the led arduino (COM* on Windows, /dev/tty* on * linux) */ - String ledArduinoDeviceAddress = "COM3"; // TODO: This should be cached localy + String ledArduinoDeviceAddress = "COM3"; // TODO: This should be cached + // localy /** * Turn on to activate the command line messages regarding the run loop @@ -334,7 +335,7 @@ public class PunchingBag implements Runnable { public void noise(Rectangle rect, long time) { runningEffects.add(new Noise(rect, System.currentTimeMillis() + time)); } - + /** * @param rect * @param time @@ -359,7 +360,7 @@ public class PunchingBag implements Runnable { /** * Set when the effect should stop (use <code>stop()</code> to set). */ - private boolean stop = false; + protected boolean stop = false; /** * Used to stop the effect, removing it from the list of effects @@ -535,14 +536,16 @@ public class PunchingBag implements Runnable { this.area = area; this.endTime = endTime; } - + public Noise(Rectangle area) { this(area, (long) 0); } @Override public void draw() { - if (endTime >= System.currentTimeMillis() && endTime != 0) { + if (endTime <= System.currentTimeMillis() && endTime != 0) { + stop(); + } else { for (int y = area.y; y < (area.y + area.height); y++) { for (int x = area.x; x < (area.x + area.width); x++) { double random = Math.random(); @@ -557,8 +560,7 @@ public class PunchingBag implements Runnable { } } } - } else { - stop(); + } } } @@ -889,7 +891,8 @@ public class PunchingBag implements Runnable { /** * Processes the serial data regarding accelerations * - * @param data The data string to be processed + * @param data + * The data string to be processed */ private void readAccelData(String data) { // System.out.println("Data: " + data); @@ -928,7 +931,8 @@ public class PunchingBag implements Runnable { /** * Processes the serial data regarding buttons * - * @param data The data string to be processed + * @param data + * The data string to be processed */ private void readButtonData(String data) { // System.out.println("Data: " + data); @@ -970,13 +974,15 @@ public class PunchingBag implements Runnable { System.out.println(""); } - /* - * The run method starts a loop which processes the serial data, effects and events + /* + * The run method starts a loop which processes the serial data, effects and + * events * * @see java.lang.Runnable#run() */ public void run() { - long timeToSleep = 10; // The time slept at the end of the loop (to maintain the refresh rate) + long timeToSleep = 10; // The time slept at the end of the loop (to + // maintain the refresh rate) while (true) { if (debugTimings) { diff --git a/PunchingBag/src/uk/ac/open/punchingbag/PunchingBagGUI.java b/PunchingBag/src/uk/ac/open/punchingbag/PunchingBagGUI.java index 01c38d4..eee961c 100644 --- a/PunchingBag/src/uk/ac/open/punchingbag/PunchingBagGUI.java +++ b/PunchingBag/src/uk/ac/open/punchingbag/PunchingBagGUI.java @@ -111,7 +111,7 @@ public class PunchingBagGUI implements MouseListener, MouseMotionListener, } frame = new JFrame("Punching Bag GUI"); - //frame.setUndecorated(true); + // frame.setUndecorated(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // frame.setSize(600, 600); diff --git a/PunchingBag/src/uk/ac/open/punchingbag/examples/SimpleKeyboard.java b/PunchingBag/src/uk/ac/open/punchingbag/examples/SimpleKeyboard.java index 5a7b8fb..7c6c655 100644 --- a/PunchingBag/src/uk/ac/open/punchingbag/examples/SimpleKeyboard.java +++ b/PunchingBag/src/uk/ac/open/punchingbag/examples/SimpleKeyboard.java @@ -5,6 +5,17 @@ import java.awt.Rectangle; import java.io.File; import java.io.IOException; +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MetaEventListener; +import javax.sound.midi.MetaMessage; +import javax.sound.midi.MidiEvent; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Sequence; +import javax.sound.midi.Sequencer; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.Synthesizer; +import javax.sound.midi.Track; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.Clip; @@ -17,33 +28,113 @@ import uk.ac.open.punchingbag.Contact; import uk.ac.open.punchingbag.PunchingBag; public class SimpleKeyboard implements ButtonListener, Runnable { - - String soundDir = System.getProperty("user.dir") + String soundDir = System.getProperty("user.dir") + System.getProperty("file.separator"); File[] keys = { new File(soundDir + "G4.wav"), new File(soundDir + "C5.wav"), new File(soundDir + "D5.wav"), new File(soundDir + "E5.wav"), new File(soundDir + "F5.wav"), new File(soundDir + "G5.wav") }; - + static PunchingBag bag = PunchingBag.getBag(); long lastActionTime = System.currentTimeMillis(); boolean noising = false; - public static void main(String[] args) { + + + + public static final int DAMPER_PEDAL = 64; + + public static final int DAMPER_ON = 127; + + public static final int DAMPER_OFF = 0; + + public static final int END_OF_TRACK = 47; + + static final int[] offsets = { // add these amounts to the base value + // A B C D E F G + -4, -2, 0, 1, 3, 5, 7 }; + + public static void main(String[] args) throws InvalidMidiDataException, MidiUnavailableException, IOException { + try { bag.connectToArduinos(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } + + new SimpleKeyboard(); - + + /*int instrument = 0; + int tempo = 120; + String filename = null; + + // Parse the options + // -i <instrument number> default 0, a piano. Allowed values: 0-127 + // -t <beats per minute> default tempo is 120 quarter notes per minute + // -o <filename> save to a midi file instead of playing + int a = 0; + while (a < args.length) { + if (args[a].equals("-i")) { + instrument = Integer.parseInt(args[a + 1]); + a += 2; + } else if (args[a].equals("-t")) { + tempo = Integer.parseInt(args[a + 1]); + a += 2; + } else if (args[a].equals("-o")) { + filename = args[a + 1]; + a += 2; + } else + break; + } + + char[] notes = args[a].toCharArray(); + + // 16 ticks per quarter note. + Sequence sequence = new Sequence(Sequence.PPQ, 16); + + // Add the specified notes to the track + addTrack(sequence, instrument, tempo, notes); + + if (filename == null) { // no filename, so play the notes + // Set up the Sequencer and Synthesizer objects + Sequencer sequencer = MidiSystem.getSequencer(); + sequencer.open(); + Synthesizer synthesizer = MidiSystem.getSynthesizer(); + synthesizer.open(); + sequencer.getTransmitter().setReceiver(synthesizer.getReceiver()); + + // Specify the sequence to play, and the tempo to play it at + sequencer.setSequence(sequence); + sequencer.setTempoInBPM(tempo); + + // Let us know when it is done playing + sequencer.addMetaEventListener(new MetaEventListener() { + public void meta(MetaMessage m) { + // A message of this type is automatically sent + // when we reach the end of the track + if (m.getType() == END_OF_TRACK) + System.exit(0); + } + }); + // And start playing now. + sequencer.start(); + } else { // A file name was specified, so save the notes + int[] allowedTypes = MidiSystem.getMidiFileTypes(sequence); + if (allowedTypes.length == 0) { + System.err.println("No supported MIDI file types."); + } else { + MidiSystem.write(sequence, allowedTypes[0], new File(filename)); + System.exit(0); + } + }*/ } - + public SimpleKeyboard() { bag.addButtonListener(this); - + new Thread (this).start(); } @@ -74,7 +165,7 @@ public class SimpleKeyboard implements ButtonListener, Runnable { playKey(0); } } - + void playKey(int key) { try { AudioInputStream sound = AudioSystem.getAudioInputStream(keys[key]); @@ -98,19 +189,141 @@ public class SimpleKeyboard implements ButtonListener, Runnable { @Override public void contact(Contact c) { // TODO Auto-generated method stub - + + } + + /* + * This method parses the specified char[] of notes into a Track. The + * musical notation is the following: A-G: A named note; Add b for flat and + * # for sharp. +: Move up one octave. Persists. -: Move down one octave. + * Persists. /1: Notes are whole notes. Persists 'till changed /2: Half + * notes /4: Quarter notes /n: N can also be, 8, 16, 32, 64. s: Toggle + * sustain pedal on or off (initially off) >: Louder. Persists <: Softer. + * Persists .: Rest. Length depends on current length setting Space: Play + * the previous note or notes; notes not separated by spaces are played at + * the same time + */ + public static void addTrack(Sequence s, int instrument, int tempo, + char[] notes) throws InvalidMidiDataException { + Track track = s.createTrack(); // Begin with a new track + + // Set the instrument on channel 0 + ShortMessage sm = new ShortMessage(); + sm.setMessage(ShortMessage.PROGRAM_CHANGE, 0, instrument, 0); + track.add(new MidiEvent(sm, 0)); + + int n = 0; // current character in notes[] array + int t = 0; // time in ticks for the composition + + // These values persist and apply to all notes 'till changed + int notelength = 16; // default to quarter notes + int velocity = 64; // default to middle volume + int basekey = 60; // 60 is middle C. Adjusted up and down by octave + boolean sustain = false; // is the sustain pedal depressed? + int numnotes = 0; // How many notes in current chord? + + while (n < notes.length) { + char c = notes[n++]; + + if (c == '+') + basekey += 12; // increase octave + else if (c == '-') + basekey -= 12; // decrease octave + else if (c == '>') + velocity += 16; // increase volume; + else if (c == '<') + velocity -= 16; // decrease volume; + else if (c == '/') { + char d = notes[n++]; + if (d == '2') + notelength = 32; // half note + else if (d == '4') + notelength = 16; // quarter note + else if (d == '8') + notelength = 8; // eighth note + else if (d == '3' && notes[n++] == '2') + notelength = 2; + else if (d == '6' && notes[n++] == '4') + notelength = 1; + else if (d == '1') { + if (n < notes.length && notes[n] == '6') + notelength = 4; // 1/16th note + else + notelength = 64; // whole note + } + } else if (c == 's') { + sustain = !sustain; + // Change the sustain setting for channel 0 + ShortMessage m = new ShortMessage(); + m.setMessage(ShortMessage.CONTROL_CHANGE, 0, DAMPER_PEDAL, + sustain ? DAMPER_ON : DAMPER_OFF); + track.add(new MidiEvent(m, t)); + } else if (c >= 'A' && c <= 'G') { + int key = basekey + offsets[c - 'A']; + if (n < notes.length) { + if (notes[n] == 'b') { // flat + key--; + n++; + } else if (notes[n] == '#') { // sharp + key++; + n++; + } + } + + addNote(track, t, notelength, key, velocity); + numnotes++; + } else if (c == ' ') { + // Spaces separate groups of notes played at the same time. + // But we ignore them unless they follow a note or notes. + if (numnotes > 0) { + t += notelength; + numnotes = 0; + } + } else if (c == '.') { + // Rests are like spaces in that they force any previous + // note to be output (since they are never part of chords) + if (numnotes > 0) { + t += notelength; + numnotes = 0; + } + // Now add additional rest time + t += notelength; + } + } } + // A convenience method to add a note to the track on channel 0 + public static void addNote(Track track, int startTick, int tickLength, + int key, int velocity) throws InvalidMidiDataException { + ShortMessage on = new ShortMessage(); + on.setMessage(ShortMessage.NOTE_ON, 0, key, velocity); + ShortMessage off = new ShortMessage(); + off.setMessage(ShortMessage.NOTE_OFF, 0, key, velocity); + track.add(new MidiEvent(on, startTick)); + track.add(new MidiEvent(off, startTick + tickLength)); + } @Override public void run() { while (true) { - if ((System.currentTimeMillis() - lastActionTime) > 4000) { + System.out.println("Checking last action time"); + if ((System.currentTimeMillis() - lastActionTime) > 60000) { + System.out.println("Activating Noise"); bag.noise(new Rectangle(0, 0, 9, 20)); + noising = true; + + } else { + System.out.println("Waiting more"); + } + try { + Thread.sleep(20000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } } - } |