diff --git a/.gitignore b/.gitignore
index d2d6f36..8c64017 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,3 +33,9 @@ nosetests.xml
.mr.developer.cfg
.project
.pydevproject
+
+*.elf
+*.hex
+*.map
+*.d
+*.o
diff --git a/healthdisplay/.idea/compiler.xml b/healthdisplay/.idea/compiler.xml
new file mode 100644
index 0000000..fa7a277
--- /dev/null
+++ b/healthdisplay/.idea/compiler.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/healthdisplay/.idea/copyright/profiles_settings.xml b/healthdisplay/.idea/copyright/profiles_settings.xml
new file mode 100644
index 0000000..3572571
--- /dev/null
+++ b/healthdisplay/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/healthdisplay/.idea/encodings.xml b/healthdisplay/.idea/encodings.xml
new file mode 100644
index 0000000..e206d70
--- /dev/null
+++ b/healthdisplay/.idea/encodings.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/healthdisplay/.idea/libraries/Maven__com_illposed_osc_javaosc_core_0_2.xml b/healthdisplay/.idea/libraries/Maven__com_illposed_osc_javaosc_core_0_2.xml
new file mode 100644
index 0000000..a12fb77
--- /dev/null
+++ b/healthdisplay/.idea/libraries/Maven__com_illposed_osc_javaosc_core_0_2.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/healthdisplay/.idea/libraries/Maven__org_jboss_netty_netty_3_2_7_Final.xml b/healthdisplay/.idea/libraries/Maven__org_jboss_netty_netty_3_2_7_Final.xml
new file mode 100644
index 0000000..f065feb
--- /dev/null
+++ b/healthdisplay/.idea/libraries/Maven__org_jboss_netty_netty_3_2_7_Final.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/healthdisplay/.idea/misc.xml b/healthdisplay/.idea/misc.xml
new file mode 100644
index 0000000..8a80acb
--- /dev/null
+++ b/healthdisplay/.idea/misc.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/healthdisplay/.idea/modules.xml b/healthdisplay/.idea/modules.xml
new file mode 100644
index 0000000..662d397
--- /dev/null
+++ b/healthdisplay/.idea/modules.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/healthdisplay/.idea/scopes/scope_settings.xml b/healthdisplay/.idea/scopes/scope_settings.xml
new file mode 100644
index 0000000..922003b
--- /dev/null
+++ b/healthdisplay/.idea/scopes/scope_settings.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/healthdisplay/.idea/uiDesigner.xml b/healthdisplay/.idea/uiDesigner.xml
new file mode 100644
index 0000000..fbab987
--- /dev/null
+++ b/healthdisplay/.idea/uiDesigner.xml
@@ -0,0 +1,128 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+
diff --git a/healthdisplay/.idea/vcs.xml b/healthdisplay/.idea/vcs.xml
new file mode 100644
index 0000000..21cbaa6
--- /dev/null
+++ b/healthdisplay/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/healthdisplay/healthdisplay.iml b/healthdisplay/healthdisplay.iml
new file mode 100644
index 0000000..e6e4b05
--- /dev/null
+++ b/healthdisplay/healthdisplay.iml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/healthdisplay/pom.xml b/healthdisplay/pom.xml
new file mode 100644
index 0000000..fe39b78
--- /dev/null
+++ b/healthdisplay/pom.xml
@@ -0,0 +1,36 @@
+
+ 4.0.0
+ Maven Default Project
+ 1.0
+
+ psychose
+ psy
+
+
+
+ com.illposed.osc
+ javaosc-core
+ 0.2
+
+
+
+ org.jboss.netty
+ netty
+ 3.2.7.Final
+
+
+
+
+
+
+ central
+ Maven Repository Switchboard
+ default
+ http://repo1.maven.org/maven2
+
+ false
+
+
+
+
+
\ No newline at end of file
diff --git a/healthdisplay/src/ActorDisplay.form b/healthdisplay/src/ActorDisplay.form
new file mode 100644
index 0000000..0506171
--- /dev/null
+++ b/healthdisplay/src/ActorDisplay.form
@@ -0,0 +1,155 @@
+
+
diff --git a/healthdisplay/src/ActorDisplay.java b/healthdisplay/src/ActorDisplay.java
new file mode 100644
index 0000000..cfcd95a
--- /dev/null
+++ b/healthdisplay/src/ActorDisplay.java
@@ -0,0 +1,117 @@
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.util.Random;
+
+/**
+ * @author: lucas
+ * @date: 14.04.14 21:44
+ */
+public class ActorDisplay {
+ private final static Color onColor = Color.WHITE;
+ private final static Color offColor = Color.RED;
+
+ private JPanel actorPanel;
+ private JLabel lblCaption;
+ private JLabel lblHeartbeat;
+ private JLabel lblPulse;
+ private JLabel lblOxy;
+ private JLabel lblEkg;
+ private JLabel lblEmg;
+ private JLabel lblTemperature;
+
+ private int counterHeartbeat = 0;
+ private int counterPulse = 0;
+ private int counterOxy = 0;
+ private int counterEkg = 0;
+ private int counterEmg = 0;
+ private int counterTemperature = 0;
+
+ private int timeout = 20; // 20 * 100ms
+
+ public void setCaption(String caption) {
+ lblCaption.setText(caption);
+ }
+
+ public void setTemperature(String temperature) {
+ lblTemperature.setText(temperature);
+ counterTemperature = 0;
+ }
+
+ public void setEkg(String value) {
+ lblEkg.setText(value);
+ counterEkg = 0;
+ }
+
+ public void setPulse(String pulse) {
+ lblPulse.setText(pulse);
+ counterPulse = 0;
+ }
+
+ public void setEmg(String emg) {
+ lblEmg.setText(emg);
+ counterEmg = 0;
+ }
+
+ public void setOxy(String oxy) {
+ lblOxy.setText(oxy);
+ counterOxy = 0;
+ }
+
+ public void setHeartbeat(String heartbeat) {
+ lblHeartbeat.setText(heartbeat);
+ counterHeartbeat = 0;
+ }
+
+ public ActorDisplay() {
+ final Random r = new Random();
+
+ final Timer timer = new Timer(100, new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+
+// actorPanel.setBackground(new Color(r.nextInt(), false));
+
+ if(++counterTemperature > timeout) {
+ lblTemperature.setForeground(offColor);
+ } else {
+ lblTemperature.setForeground(onColor);
+ }
+
+ if(++counterPulse > timeout) {
+ lblPulse.setForeground(offColor);
+ } else {
+ lblPulse.setForeground(onColor);
+ }
+
+ if(++counterOxy > timeout) {
+ lblOxy.setForeground(offColor);
+ } else {
+ lblOxy.setForeground(onColor);
+ }
+
+ if(++counterEkg > timeout) {
+ lblEkg.setForeground(offColor);
+ } else {
+ lblEkg.setForeground(onColor);
+ }
+
+ if(++counterEmg > timeout) {
+ lblEmg.setForeground(offColor);
+ } else {
+ lblEmg.setForeground(onColor);
+ }
+
+ if(++counterHeartbeat > timeout) {
+ lblHeartbeat.setForeground(offColor);
+ } else {
+ lblHeartbeat.setForeground(onColor);
+ }
+
+ }
+ });
+ timer.setRepeats(true);
+ timer.start();
+ }
+}
+
diff --git a/healthdisplay/src/ChaOSCclient.java b/healthdisplay/src/ChaOSCclient.java
new file mode 100644
index 0000000..a277421
--- /dev/null
+++ b/healthdisplay/src/ChaOSCclient.java
@@ -0,0 +1,86 @@
+import com.illposed.osc.OSCListener;
+import com.illposed.osc.OSCMessage;
+import com.illposed.osc.OSCPortIn;
+import com.illposed.osc.OSCPortOut;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.Enumeration;
+
+/**
+ * @author: lucas
+ * @date: 13.04.14 17:03
+ */
+public class ChaOSCclient {
+ private final static int OSC_CLIENT_PORT = 8123;
+ private OSCPortIn portIn;
+ private OSCPortOut portOut;
+
+ public ChaOSCclient(String host, int port) throws UnknownHostException, SocketException {
+ portOut = new OSCPortOut(InetAddress.getByName(host), port);
+ }
+
+ public void addListener(String address, OSCListener listener) {
+ portIn.addListener(address, listener);
+ }
+
+ public boolean stopReceiver() {
+ portIn.stopListening();
+ return changeChaoscSubscription(false);
+ }
+
+ public boolean startReceiver() {
+ try {
+ portIn = new OSCPortIn(OSC_CLIENT_PORT);
+ portIn.startListening();
+
+ return changeChaoscSubscription(true);
+ } catch (SocketException e) {
+ System.out.println("could not create listening socket");
+ e.printStackTrace();
+ }
+
+ return false;
+ }
+
+ private boolean changeChaoscSubscription(boolean subscribe) {
+ try {
+ OSCMessage subscribeMessage = new OSCMessage("/" + (subscribe ? "subscribe" : "unsubscribe"));
+ subscribeMessage.addArgument(getLocalAddress().getHostAddress());
+ subscribeMessage.addArgument(OSC_CLIENT_PORT);
+ subscribeMessage.addArgument("sekret");
+ subscribeMessage.addArgument("statusmonitor");
+
+ portOut.send(subscribeMessage);
+ return true;
+ } catch (SocketException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ System.out.println("could not change chaosc subscription message");
+ return false;
+ }
+
+ private InetAddress getLocalAddress() throws SocketException {
+ final Enumeration n = NetworkInterface.getNetworkInterfaces();
+ while (n.hasMoreElements()) {
+ NetworkInterface e = n.nextElement();
+
+ Enumeration a = e.getInetAddresses();
+ for (; a.hasMoreElements(); ) {
+ InetAddress addr = a.nextElement();
+
+ if (addr.isSiteLocalAddress()) {
+ return addr;
+ }
+ }
+ }
+ throw new SocketException();
+ }
+
+}
diff --git a/healthdisplay/src/MainForm.form b/healthdisplay/src/MainForm.form
new file mode 100644
index 0000000..aa1bed6
--- /dev/null
+++ b/healthdisplay/src/MainForm.form
@@ -0,0 +1,49 @@
+
+
diff --git a/healthdisplay/src/MainForm.java b/healthdisplay/src/MainForm.java
new file mode 100644
index 0000000..c5f52db
--- /dev/null
+++ b/healthdisplay/src/MainForm.java
@@ -0,0 +1,105 @@
+import com.illposed.osc.OSCListener;
+import com.illposed.osc.OSCMessage;
+
+import javax.swing.*;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.Date;
+
+/**
+ * @author: lucas
+ * @date: 14.04.14 21:43
+ */
+public class MainForm {
+ private ChaOSCclient osCclient;
+
+ private JPanel mainPanel;
+ private ActorDisplay actor1;
+ private ActorDisplay actor2;
+ private ActorDisplay actor3;
+
+ public MainForm(ChaOSCclient client) {
+ osCclient = client;
+ osCclient.startReceiver();
+
+ addActor("merle", "Merle", actor1);
+ addActor("uwe", "Uwe", actor2);
+ addActor("bjoern", "Björn", actor3);
+ }
+
+
+ private void addActor(final String actor, final String label, final ActorDisplay actorDisplay) {
+ actorDisplay.setCaption(label);
+ osCclient.addListener("/" + actor.toLowerCase() + "/heartbeat", new OSCListener() {
+ @Override
+ public void acceptMessage(Date time, OSCMessage message) {
+ if (message.getArguments().length == 3) {
+ actorDisplay.setHeartbeat(message.getArguments()[0].toString());
+ actorDisplay.setPulse(message.getArguments()[1].toString());
+ actorDisplay.setOxy(message.getArguments()[2].toString());
+ }
+ }
+ });
+
+ osCclient.addListener("/" + actor.toLowerCase() + "/ekg", new OSCListener() {
+ @Override
+ public void acceptMessage(Date time, OSCMessage message) {
+ if (message.getArguments().length == 1) {
+ actorDisplay.setEkg(message.getArguments()[0].toString());
+ }
+ }
+ });
+
+ osCclient.addListener("/" + actor.toLowerCase() + "/emg", new OSCListener() {
+ @Override
+ public void acceptMessage(Date time, OSCMessage message) {
+ if (message.getArguments().length == 1) {
+ actorDisplay.setEmg(message.getArguments()[0].toString());
+ }
+ }
+ });
+
+ osCclient.addListener("/" + actor.toLowerCase() + "/temperatur", new OSCListener() {
+ @Override
+ public void acceptMessage(Date time, OSCMessage message) {
+ if (message.getArguments().length == 1) {
+ actorDisplay.setTemperature(message.getArguments()[0].toString());
+ }
+ }
+ });
+ }
+
+ public static void main(String[] args) {
+
+ try {
+ final ChaOSCclient chaOSCclient = new ChaOSCclient("localhost", 7110);
+
+ final MainForm mainForm = new MainForm(chaOSCclient);
+ final JFrame frame = new JFrame("MainForm");
+ frame.setContentPane(mainForm.mainPanel);
+ frame.setResizable(false);
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.pack();
+
+ frame.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ chaOSCclient.stopReceiver();
+ super.windowClosing(e);
+ }
+ });
+
+ frame.setVisible(true);
+
+ new Streamer(8888, mainForm.mainPanel).run();
+
+ } catch (UnknownHostException e) {
+ e.printStackTrace();
+ } catch (SocketException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/healthdisplay/src/Streamer.java b/healthdisplay/src/Streamer.java
new file mode 100644
index 0000000..1796b55
--- /dev/null
+++ b/healthdisplay/src/Streamer.java
@@ -0,0 +1,254 @@
+import org.jboss.netty.bootstrap.ServerBootstrap;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.jboss.netty.channel.*;
+import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
+import org.jboss.netty.handler.codec.frame.TooLongFrameException;
+import org.jboss.netty.handler.codec.http.*;
+import org.jboss.netty.handler.stream.ChunkedInput;
+import org.jboss.netty.handler.stream.ChunkedWriteHandler;
+import org.jboss.netty.util.CharsetUtil;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.channels.ClosedChannelException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
+import static org.jboss.netty.handler.codec.http.HttpMethod.GET;
+import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*;
+import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1;
+
+/**
+ * @author Maurus Cuelenaere
+ * taken from http://blog.maurus.be/2012/05/09/netty-mjpeg-streamer/
+ */
+public class Streamer {
+ private final int port;
+ private final Component view;
+ private final ViewRenderer renderer;
+
+ private class ViewRenderer implements Runnable {
+ private final BufferedImage image;
+ private final AtomicReference currentBuffer;
+ private final AtomicInteger listenerCount;
+ private final int napTime;
+ private final ByteArrayOutputStream outputStream;
+
+ public ViewRenderer() {
+ this(10);
+ }
+
+ public ViewRenderer(int fps) {
+ this.napTime = 1000 / fps;
+ this.listenerCount = new AtomicInteger();
+ this.currentBuffer = new AtomicReference();
+ this.image = new BufferedImage(view.getWidth(), view.getHeight(), BufferedImage.TYPE_INT_RGB);
+ this.outputStream = new ByteArrayOutputStream();
+ }
+
+ @Override
+ public void run() {
+ while (!Thread.interrupted()) {
+ long sleepTill = System.currentTimeMillis() + napTime;
+
+ if (listenerCount.get() > 0) {
+ Graphics g = image.createGraphics();
+ view.paint(g);
+ g.dispose();
+
+ byte[] newData = null;
+ try {
+ ImageIO.write(image, "jpg", outputStream);
+ newData = outputStream.toByteArray();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ outputStream.reset();
+ }
+
+ if (newData != null) {
+ currentBuffer.set(newData);
+ synchronized (currentBuffer) {
+ currentBuffer.notifyAll();
+ }
+ }
+ }
+
+ try {
+ long remainingTime = sleepTill - System.currentTimeMillis();
+ if (remainingTime > 0)
+ Thread.sleep(remainingTime);
+ } catch (InterruptedException e) {
+ return;
+ }
+ }
+ }
+
+ public void registerListener() {
+ listenerCount.incrementAndGet();
+ }
+
+ public void unregisterListener() {
+ listenerCount.decrementAndGet();
+ }
+
+ public void waitForData() throws InterruptedException {
+ synchronized (currentBuffer) {
+ currentBuffer.wait();
+ }
+ }
+
+ public byte[] getData() {
+ return currentBuffer.get();
+ }
+ }
+
+ private class HttpMultipartReplaceStream implements ChunkedInput {
+ private final byte[] header;
+ private boolean closed;
+
+ public HttpMultipartReplaceStream(String boundary) {
+ this.header = ("--" + boundary + "\r\nContent-Type: image/jpeg\r\n\r\n").getBytes();
+
+ renderer.registerListener();
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (closed)
+ return;
+
+ closed = true;
+ renderer.unregisterListener();
+ }
+
+ @Override
+ public boolean hasNextChunk() throws Exception {
+ return !closed;
+ }
+
+ @Override
+ public boolean isEndOfInput() throws Exception {
+ return closed;
+ }
+
+ @Override
+ public Object nextChunk() throws Exception {
+ if (closed)
+ return null;
+
+ renderer.waitForData();
+ byte[] body = renderer.getData();
+
+ return ChannelBuffers.wrappedBuffer(header, body);
+ }
+ }
+
+ private class HttpStreamerHandler extends SimpleChannelUpstreamHandler {
+ @Override
+ public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
+ HttpRequest request = (HttpRequest) e.getMessage();
+ if (request.getMethod() != GET) {
+ sendError(ctx, METHOD_NOT_ALLOWED);
+ return;
+ } else if (!"/stream".equals(request.getUri())) {
+ sendError(ctx, NOT_FOUND);
+ return;
+ }
+
+ final String boundary = "thisisourmagicboundary";
+ HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
+ HttpHeaders.setHeader(response, "Connection", "close");
+ HttpHeaders.setHeader(response, "Content-Type", "multipart/x-mixed-replace;boundary=" + boundary);
+ HttpHeaders.setHeader(response, "Cache-control", "no-cache");
+ HttpHeaders.setHeader(response, "Pragma", "no-cache");
+ HttpHeaders.setHeader(response, "Expires", "Thu, 01 Dec 1994 16:00:00 GMT");
+
+ Channel ch = e.getChannel();
+
+ final HttpMultipartReplaceStream replaceStream = new HttpMultipartReplaceStream(boundary);
+ ch.getCloseFuture().addListener(new ChannelFutureListener() {
+ @Override
+ public void operationComplete(ChannelFuture future) throws Exception {
+ // Stop the stream when the channel is closed
+ replaceStream.close();
+ }
+ });
+
+ // Write the initial line and the headers
+ ch.write(response);
+
+ // Write the content
+ ChannelFuture writeFuture = ch.write(replaceStream);
+
+ // Close the connection when the whole content is written out
+ writeFuture.addListener(ChannelFutureListener.CLOSE);
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
+ Channel ch = e.getChannel();
+ Throwable cause = e.getCause();
+ if (cause instanceof TooLongFrameException) {
+ sendError(ctx, BAD_REQUEST);
+ return;
+ } else if (cause instanceof ClosedChannelException) {
+ ch.close();
+ return;
+ }
+
+ cause.printStackTrace();
+ if (ch.isConnected())
+ sendError(ctx, INTERNAL_SERVER_ERROR);
+ }
+
+ private void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
+ HttpResponse response = new DefaultHttpResponse(HTTP_1_1, status);
+ response.setHeader(CONTENT_TYPE, "text/plain; charset=UTF-8");
+ response.setContent(ChannelBuffers.copiedBuffer("Failure: " + status.toString() + "\r\n", CharsetUtil.UTF_8));
+
+ // Close the connection as soon as the error message is sent.
+ ctx.getChannel().write(response).addListener(ChannelFutureListener.CLOSE);
+ }
+ }
+
+ public Streamer(int port, Component view) {
+ this.port = port;
+ this.view = view;
+ this.renderer = new ViewRenderer();
+ }
+
+ public void run() {
+ // Configure the server.
+ ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
+
+ // Set up the event pipeline factory.
+ bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
+ @Override
+ public ChannelPipeline getPipeline() throws Exception {
+ // Create a default pipeline implementation.
+ ChannelPipeline pipeline = Channels.pipeline();
+
+ pipeline.addLast("decoder", new HttpRequestDecoder());
+ pipeline.addLast("aggregator", new HttpChunkAggregator(65536));
+ pipeline.addLast("encoder", new HttpResponseEncoder());
+ pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());
+ pipeline.addLast("handler", new HttpStreamerHandler());
+
+ return pipeline;
+ }
+ });
+
+ // Bind and start to accept incoming connections.
+ bootstrap.bind(new InetSocketAddress(port));
+
+ // Start the renderer
+ new Thread(renderer, "Image renderer").start();
+ }
+}
\ No newline at end of file
diff --git a/healthdisplay/src/Test.java b/healthdisplay/src/Test.java
new file mode 100644
index 0000000..2aec3a5
--- /dev/null
+++ b/healthdisplay/src/Test.java
@@ -0,0 +1,49 @@
+import javax.sound.midi.*;
+import java.io.File;
+
+public class Test {
+ public static final int NOTE_ON = 0x90;
+ public static final int NOTE_OFF = 0x80;
+ public static final String[] NOTE_NAMES = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};
+
+ public static void main(String[] args) throws Exception {
+ Sequence sequence = MidiSystem.getSequence(new File("/home/lucas/jake-avril_14th.mid"));
+
+ int trackNumber = 0;
+ for (Track track : sequence.getTracks()) {
+ trackNumber++;
+ System.out.println("Track " + trackNumber + ": size = " + track.size());
+ System.out.println();
+ for (int i=0; i < track.size(); i++) {
+ MidiEvent event = track.get(i);
+ System.out.print("@" + event.getTick() + " ");
+ MidiMessage message = event.getMessage();
+ if (message instanceof ShortMessage) {
+ ShortMessage sm = (ShortMessage) message;
+ System.out.print("Channel: " + sm.getChannel() + " ");
+ if (sm.getCommand() == NOTE_ON) {
+ int key = sm.getData1();
+ int octave = (key / 12)-1;
+ int note = key % 12;
+ String noteName = NOTE_NAMES[note];
+ int velocity = sm.getData2();
+ System.out.println("Note on, " + noteName + octave + " key=" + key + " velocity: " + velocity);
+ } else if (sm.getCommand() == NOTE_OFF) {
+ int key = sm.getData1();
+ int octave = (key / 12)-1;
+ int note = key % 12;
+ String noteName = NOTE_NAMES[note];
+ int velocity = sm.getData2();
+ System.out.println("Note off, " + noteName + octave + " key=" + key + " velocity: " + velocity);
+ } else {
+ System.out.println("Command:" + sm.getCommand());
+ }
+ } else {
+ System.out.println("Other message: " + message.getClass());
+ }
+ }
+
+ System.out.println();
+ }
+ }
+}
\ No newline at end of file