aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <Adam Martindale@.(none)>2011-09-16 12:40:39 +0100
committerunknown <Adam Martindale@.(none)>2011-09-16 12:40:39 +0100
commit201f4564f236ee1a15ebfe1efc16929375f9947c (patch)
treed03a83839d14909d3c58c1d5b2fc6dfcd033d74d
parente1a7613135ea099deaa82e16a9eba8bd02b83689 (diff)
parent2f9556e87d356051f412e73394833627347d848e (diff)
downloadpunchingbag-201f4564f236ee1a15ebfe1efc16929375f9947c.tar
punchingbag-201f4564f236ee1a15ebfe1efc16929375f9947c.tar.gz
Merge branch 'master' of gitorious.org:punchingbag/punchingbag
Conflicts: PunchingBag/src/uk/ac/open/punchingbag/examples/SimpleKeyboard.java
-rw-r--r--PunchingBag/src/uk/ac/open/punchingbag/PunchingBag.java32
-rw-r--r--PunchingBag/src/uk/ac/open/punchingbag/PunchingBagGUI.java2
-rw-r--r--PunchingBag/src/uk/ac/open/punchingbag/examples/SimpleKeyboard.java235
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();
+
}
}
}
-
}