Add mappings for panda board UI and PandaDriver class
authorMark Slee <mcslee@Mark-Slees-MacBook-Pro.local>
Wed, 12 Jun 2013 02:18:44 +0000 (19:18 -0700)
committerMark Slee <mcslee@Mark-Slees-MacBook-Pro.local>
Wed, 12 Jun 2013 02:18:44 +0000 (19:18 -0700)
_Internals.pde
_Mappings.pde
_Overlay.pde
_PandaDriver.pde [new file with mode: 0644]
code/GLucose.jar
code/oscP5.jar [new file with mode: 0644]

index a103f13ace4630df806fb6b3f67dcc26f7686926..30e410da076dadf9ef3b0914000959891f2f8333 100644 (file)
@@ -29,7 +29,6 @@ import heronarts.lx.transition.*;
 import ddf.minim.*;
 import ddf.minim.analysis.*;
 import processing.opengl.*;
-import java.lang.reflect.*;
 import rwmidi.*;
 
 final int VIEWPORT_WIDTH = 900;
@@ -43,6 +42,11 @@ LXPattern[] patterns;
 LXTransition[] transitions;
 LXEffect[] effects;
 OverlayUI ui;
+OscP5 osc;
+PandaDriver pandaFront;
+PandaDriver pandaRear;
+
+boolean pandaBoardsEnabled = false;
 
 void setup() {
   startMillis = lastMillis = millis();
@@ -66,6 +70,14 @@ void setup() {
   logTime("Built effects");
   transitions = transitions(glucose);
   logTime("Built transitions");
+    
+  // Build output driver
+  int[][] frontChannels = glucose.mapping.buildFrontChannelList();
+  int[][] rearChannels = glucose.mapping.buildRearChannelList();
+  int[][] flippedRGB = glucose.mapping.buildFlippedRGBList();
+  pandaFront = new PandaDriver(new NetAddress("192.168.1.28", 9001), glucose.model, frontChannels, flippedRGB);
+  pandaRear = new PandaDriver(new NetAddress("192.168.1.29", 9001), glucose.model, rearChannels, flippedRGB);
+  logTime("Build PandaDriver");
   
   // Build overlay UI
   ui = new OverlayUI();
@@ -76,6 +88,7 @@ void setup() {
   logTime("Setup MIDI devices");
   
   println("Total setup: " + (millis() - startMillis) + "ms");
+  println("Hit the 'p' key to toggle Panda Board output");
 }
 
 void logTime(String evt) {
@@ -87,6 +100,13 @@ void logTime(String evt) {
 void draw() {
   // The glucose engine deals with the core simulation here, we don't need
   // to do anything specific. This method just needs to exist.
+  
+  // TODO(mcslee): move into GLucose engine
+  if (pandaBoardsEnabled) {
+    color[] colors = glucose.getColors();
+    pandaFront.send(colors);
+    pandaRear.send(colors);
+  }
 }
 
 void drawUI() {
@@ -102,6 +122,10 @@ boolean uiOn = true;
 boolean knobsOn = true;
 void keyPressed() {
   switch (key) {
+    case 'p':
+      pandaBoardsEnabled = !pandaBoardsEnabled;
+      println("PandaBoard Output: " + (pandaBoardsEnabled ? "ON" : "OFF"));
+      break;
     case 'u':
       uiOn = !uiOn;
       break;
index 813705046635f543bc23002302e3d3ebc752593d..fd581e56efc95188656e8cbec20200012c8362d7 100644 (file)
@@ -97,5 +97,162 @@ class SCMapping implements GLucose.Mapping {
     cubes[78] = new Cube(20, 140, 80, 0, 0, 0, false, 0, 3);
     return cubes;
   }
+
+  public int[][] buildFrontChannelList() {
+    return new int[][] {
+      {
+        1, 57, 56, 55, 0  // Pandaboard A, structural channel 1
+      }
+      , 
+      {
+        30, 31, 32, 17, 3  // Pandaboard B, structural channel 2
+      }
+      , 
+      {
+        20, 21, 15, 19, 0  // Pandaboard C, structural channel 3
+      }
+      , 
+      {
+        69, 75, 74, 76, 73  // Pandaboard D, structural channel 4
+      }
+      , 
+      {
+        16, 2, 5, 0, 0  // Pandaboard E, structural channel 5
+      }
+      , 
+      {
+        48, 47, 37, 29, 0  // Pandaboard F, structural channel 6 (is there a 5th?)
+      }
+      , 
+      {
+        68, 63, 62, 78, 45  // Pandaboard G, structural channel 7, left top front side
+      }
+      , 
+      {
+        18, 6, 7, 0, 0  // Pandaboard H, structural channel 8
+      }
+    };
+  }
+
+  public int[][] buildRearChannelList() {
+    return new int[][] {
+      {
+        22, 8, 14, 28, 0  // Pandaboard A, structural channel 9
+      }
+      , 
+      {
+        36, 34, 40, 52, 66  // Pandaboard B, structural channel 10
+      }
+      , 
+      {
+        65, 61, 60, 54, 51  // Pandaboard C, structural channel 11
+      }
+      , 
+      {
+        35, 25, 11, 10, 24  // Pandaboard D, structural channel 12
+      }
+      , 
+      {
+        23, 9, 13, 27, 12  // Pandaboard E, structural channel 13, missing taillight?
+      }
+      , 
+      {
+        64, 75, 72, 49, 50  // Pandaboard F, structural channel 14, right top backside
+      }
+      , 
+      {
+        77, 39, 46, 33, 26  // Pandaboard G, structural channel 15
+      }
+      , 
+      {
+        44, 53, 42, 43, 41  // Pandaboard H, structural channel 16, last cube busted?
+      }
+    };
+  }
+
+  public int[][] buildFlippedRGBList() {
+    // syntax is {cube #, strip #, strip #, . . . }
+    return new int[][] { 
+      {
+        22, 4, 8
+      }
+      , 
+      {
+        50, 1, 3
+      }
+      , 
+      {
+        7, 1, 2, 11
+      }
+      , 
+      {
+        49, 1
+      }
+      , 
+      {
+        39, 1
+      }
+      , 
+      {
+        41, 1
+      }
+      , 
+      {
+        26, 3, 5
+      }
+      , 
+      {
+        64, 1
+      }
+      , 
+      {
+        32, 2
+      }
+      , 
+      {
+        20, 6, 7
+      }
+      , 
+      {
+        19, 1, 2
+      }
+      , 
+      {
+        15, 6, 8
+      }
+      , 
+      {
+        29, 3, 10
+      }
+      , 
+      {
+        68, 4, 9
+      }
+      , 
+      {
+        18, 12
+      }
+      , 
+      {
+        6, 2, 4
+      }
+      , 
+      {
+        78, 11
+      }
+      , 
+      {
+        56, 2
+      }
+      , 
+      {
+        57, 3
+      }
+      , 
+      {
+        74, 6, 7
+      }
+    };
+  }
 }
 
index c08e1852a219d9ec14417ecc9aca087900f8294d..acf8505f7dc995833ecd67681dbb2a7e6627b7e3 100644 (file)
@@ -1,3 +1,5 @@
+import java.lang.reflect.*;
+
 /**
  *     DOUBLE BLACK DIAMOND        DOUBLE BLACK DIAMOND
  *
diff --git a/_PandaDriver.pde b/_PandaDriver.pde
new file mode 100644 (file)
index 0000000..7fd45c0
--- /dev/null
@@ -0,0 +1,128 @@
+import netP5.*;
+import oscP5.*;
+
+/**
+ *     DOUBLE BLACK DIAMOND        DOUBLE BLACK DIAMOND
+ *
+ *         //\\   //\\                 //\\   //\\  
+ *        ///\\\ ///\\\               ///\\\ ///\\\
+ *        \\\/// \\\///               \\\/// \\\///
+ *         \\//   \\//                 \\//   \\//
+ *
+ *        EXPERTS ONLY!!              EXPERTS ONLY!!
+ *
+ * This class implements the output function to the Panda Boards. It
+ * will be moved into GLucose once stabilized.
+ */
+public class PandaDriver {
+
+  // Address to send to
+  private final NetAddress address;
+  
+  // OSC message
+  private final OscMessage message;
+
+  // List of point indices on the board
+  private final List<Integer> points;
+
+  // Bit for flipped status of each point index
+  private final boolean[] flipped;
+
+  // Packet data
+  private final byte[] packet = new byte[4*352]; // TODO: de-magic-number
+
+  public PandaDriver(NetAddress address, Model model, int[][] channelList, int[][] flippedList) {
+    this.address = address;
+    message = new OscMessage("/shady/pointbuffer");
+    points = buildMappedList(model, channelList);
+    flipped = buildFlippedList(model, flippedList);
+  }
+
+  private ArrayList<Integer> buildMappedList(Model model, int[][] channelList) {
+    ArrayList<Integer> points = new ArrayList<Integer>();
+    for (int[] channel : channelList) {
+      for (int cubeNumber : channel) {
+        if (cubeNumber == 0) {
+          for (int i = 0; i < (Cube.CLIPS_PER_CUBE*Clip.STRIPS_PER_CLIP*Strip.POINTS_PER_STRIP); ++i) {
+            points.add(0);
+          }
+        } else {
+          Cube cube = model.getCubeByRawIndex(cubeNumber);
+          if (cube == null) {
+            throw new RuntimeException("Non-zero, non-existing cube specified in channel mapping (" + cubeNumber + ")");
+          }
+          for (Point p : cube.points) {
+            points.add(p.index);
+          }
+        }
+      }
+    }
+    return points;
+  }
+
+  private boolean[] buildFlippedList(Model model, int[][] flippedRGBList) {
+    boolean[] flipped = new boolean[model.points.size()];
+    for (int i = 0; i < flipped.length; ++i) {
+      flipped[i] = false;
+    }
+    for (int[] cubeInfo : flippedRGBList) {
+      int cubeNumber = cubeInfo[0];
+      Cube cube = model.getCubeByRawIndex(cubeNumber);
+      if (cube == null) {
+        throw new RuntimeException("Non-existing cube specified in flipped RGB mapping (" + cubeNumber + ")");
+      } else {
+        for (int i = 1; i < cubeInfo.length; ++i) {
+          int stripIndex = cubeInfo[i];
+          for (Point p : cube.strips.get(stripIndex-1).points) {
+            flipped[p.index] = true;
+          }
+        }
+      }
+    }
+    return flipped;
+  } 
+
+  public final void send(int[] colors) {
+    int len = 0;
+    int packetNum = 0;
+    for (int index : points) {
+      int c = colors[index];
+      byte r = (byte) ((c >> 16) & 0xFF);
+      byte g = (byte) ((c >> 8) & 0xFF);
+      byte b = (byte) ((c) & 0xFF);
+      if (flipped[index]) {
+        byte tmp = r;
+        r = g;
+        g = tmp;
+      }
+      packet[len++] = 0;
+      packet[len++] = r;
+      packet[len++] = g;
+      packet[len++] = b;
+
+      // Flush once packet is full buffer size
+      if (len >= packet.length) {
+        sendPacket(packetNum++, len);
+        len = 0;
+      }
+    }
+
+    // Flush any remaining data
+    if (len > 0) {
+      sendPacket(packetNum++, len);
+    }
+  }
+  
+  private void sendPacket(int packetNum, int len) {
+    message.clearArguments();
+    message.add(packetNum);
+    message.add(len);
+    message.add(packet);
+    try {
+      OscP5.flush(message, address);     
+    } catch (Exception x) {
+      x.printStackTrace();
+    }
+  }
+}
+
index 321f2a024daf58afa90f76d126ba1faf02ae471b..7b7d1bd6667c008405c35d539f21ce015d17b723 100644 (file)
Binary files a/code/GLucose.jar and b/code/GLucose.jar differ
diff --git a/code/oscP5.jar b/code/oscP5.jar
new file mode 100644 (file)
index 0000000..24c6756
Binary files /dev/null and b/code/oscP5.jar differ