Update mapping and debugging tools to support bassbin, speakers, and booth floor
authorMark Slee <mcslee@Mark-Slees-MacBook-Pro.local>
Wed, 21 Aug 2013 00:46:41 +0000 (17:46 -0700)
committerMark Slee <mcslee@Mark-Slees-MacBook-Pro.local>
Wed, 21 Aug 2013 00:46:41 +0000 (17:46 -0700)
TestPatterns.pde
_Internals.pde
_Mappings.pde
_Overlay.pde
_PandaDriver.pde

index 51402f289467be3709e768c82606218be23f1b2d..bdaa78ac563b916aacd84974cb4a79c2c4d973c3 100644 (file)
@@ -237,8 +237,8 @@ class MappingTool extends TestPattern {
   private final int numChannels;
   
   private final PandaMapping[] pandaMappings;
-  private PandaMapping activeMapping;
-  private int mappingChannelIndex;
+  private PandaMapping activePanda;
+  private ChannelMapping activeChannel;
   
   MappingTool(GLucose glucose, PandaMapping[] pandaMappings) {
     super(glucose);
@@ -248,17 +248,19 @@ class MappingTool extends TestPattern {
   }
   
   private void setChannel() {
-    mappingChannelIndex = channelIndex % PandaMapping.CHANNELS_PER_BOARD;
-    activeMapping = pandaMappings[channelIndex / PandaMapping.CHANNELS_PER_BOARD];
+    activePanda = pandaMappings[channelIndex / PandaMapping.CHANNELS_PER_BOARD];
+    activeChannel = activePanda.channelList[channelIndex % PandaMapping.CHANNELS_PER_BOARD];
   }
   
-  private int cubeInChannel(Cube c) {
-    int i = 1;
-    for (int index : activeMapping.channelList[mappingChannelIndex]) {
-      if (c == model.getCubeByRawIndex(index)) {
-        return i;
+  private int indexOfCubeInChannel(Cube c) {
+    if (activeChannel.mode == ChannelMapping.MODE_CUBES) {
+      int i = 1;
+      for (int index : activeChannel.objectIndices) {
+        if (c == model.getCubeByRawIndex(index)) {
+          return i;
+        }
+        ++i;
       }
-      ++i;
     }
     return 0;
   }
@@ -292,7 +294,7 @@ class MappingTool extends TestPattern {
     int ci = 0;
     for (Cube cube : model.cubes) {
       boolean cubeOn = false;
-      int channelIndex = cubeInChannel(cube);
+      int indexOfCubeInChannel = indexOfCubeInChannel(cube);
       switch (mappingMode) {
         case MAPPING_MODE_ALL: cubeOn = true; break;
         case MAPPING_MODE_SINGLE_CUBE: cubeOn = (cubeIndex == ci); break;
@@ -301,7 +303,7 @@ class MappingTool extends TestPattern {
       if (cubeOn) {
         if (mappingMode == MAPPING_MODE_CHANNEL) {
           color cc = off;
-          switch (channelIndex) {
+          switch (indexOfCubeInChannel) {
             case 1: cc = r; break;
             case 2: cc = r|g; break;
             case 3: cc = g; break;
index fc06832ba72a9692447bc3111d4ad272419dde8f..580e1730433f070baf019a40e421d19997ac34fc 100644 (file)
@@ -122,8 +122,6 @@ void setup() {
   
   println("Total setup: " + (millis() - startMillis) + "ms");
   println("Hit the 'p' key to toggle Panda Board output");
-  
-  println(glucose.model.bassBox.points.size());
 }
 
 void controllerChangeReceived(rwmidi.Controller cc) {
index d7d0951dbedbde39fddd70c8ec3249bbf1ce8075..fb80ff1fe164218446ba3d9b2acc63b3b9635229 100644 (file)
@@ -230,29 +230,28 @@ public Model buildModel() {
 public PandaMapping[] buildPandaList() {
   return new PandaMapping[] {
     new PandaMapping(
-      "10.200.1.28", new int[][] {
-      {  1,  2,  3,  4 }, // ch1
-      {  5,  6,  7,  8 }, // ch2
-      {  9, 10, 11, 12 }, // ch3
-      { 13, 14, 15, 16 }, // ch4
-      { 17, 18, 19, 20 }, // ch5
-      { 21, 22, 23, 24 }, // ch6
-      { 25, 26, 27, 28 }, // ch7
-      { 29, 30, 31, 32 }, // ch8
+      "10.200.1.28", new ChannelMapping[] {
+        new ChannelMapping(ChannelMapping.MODE_BASS),
+        new ChannelMapping(ChannelMapping.MODE_FLOOR),
+        new ChannelMapping(ChannelMapping.MODE_SPEAKER, 0),
+        new ChannelMapping(ChannelMapping.MODE_SPEAKER, 1),
+        new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] {  1,  2,  3,  4 }),
+        new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] {  5,  6,  7,  8 }),
+        new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] {  9, 10, 11, 12 }),
+        new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 13, 14, 15, 16 }),
     }),
 
     new PandaMapping(
-      "10.200.1.29", new int[][] {
-      { 33, 34, 35, 36 }, // ch9
-      { 37, 38, 39, 40 }, // ch10
-      { 41, 42, 43, 44 }, // ch11
-      { 45, 46, 47, 48 }, // ch12
-      { 33, 34, 35, 36 }, // ch13
-      { 37, 38, 39, 40 }, // ch14
-      { 41, 42, 43, 44 }, // ch15
-      { 45, 46, 47, 48 }, // ch16
+      "10.200.1.29", new ChannelMapping[] {
+        new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 17, 18, 19, 20 }),
+        new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 21, 22, 23, 24 }),
+        new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 25, 26, 27, 28 }),
+        new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 29, 30, 31, 32 }),
+        new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 33, 34, 35, 36 }),
+        new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 37, 38, 39, 40 }),
+        new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 41, 42, 43, 44 }),
+        new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 45, 46, 47, 48 }),
     }),
-    
   };
 }
 
@@ -261,27 +260,79 @@ class PandaMapping {
   // How many channels are on the panda board
   public final static int CHANNELS_PER_BOARD = 8;
   
-  // How many cubes per channel xc_PB is configured for
-  public final static int CUBES_PER_CHANNEL = 4;
-  
-  // How many total pixels on each channel
-  public final static int PIXELS_PER_CHANNEL = Cube.POINTS_PER_CUBE * CUBES_PER_CHANNEL;
-  
   // How many total pixels on the whole board
-  public final static int PIXELS_PER_BOARD = PIXELS_PER_CHANNEL * CHANNELS_PER_BOARD;
+  public final static int PIXELS_PER_BOARD = ChannelMapping.PIXELS_PER_CHANNEL * CHANNELS_PER_BOARD;
   
   final String ip;
-  final int[][] channelList = new int[CHANNELS_PER_BOARD][CUBES_PER_CHANNEL];
+  final ChannelMapping[] channelList = new ChannelMapping[CHANNELS_PER_BOARD];
   
-  PandaMapping(String ip, int[][] rawChannelList) {
+  PandaMapping(String ip, ChannelMapping[] rawChannelList) {
     this.ip = ip;
-    for (int chi = 0; chi < CHANNELS_PER_BOARD; ++chi) {
-      int[] cubes = (chi < rawChannelList.length) ? rawChannelList[chi] : new int[]{};
-      for (int cui = 0; cui < CUBES_PER_CHANNEL; ++cui) {
-        channelList[chi][cui] = (cui < cubes.length) ? cubes[cui] : 0;
-      }
+    for (int i = 0; i < channelList.length; ++i) {
+      channelList[i] = (i < rawChannelList.length) ? rawChannelList[i] : new ChannelMapping();
     }
   }
 }
 
+class ChannelMapping {
+
+  // How many cubes per channel xc_PB is configured for
+  public final static int CUBES_PER_CHANNEL = 4;  
 
+  // How many total pixels on each channel
+  public final static int PIXELS_PER_CHANNEL = Cube.POINTS_PER_CUBE * CUBES_PER_CHANNEL;
+  
+  public static final int MODE_NULL = 0;
+  public static final int MODE_CUBES = 1;
+  public static final int MODE_BASS = 2;
+  public static final int MODE_SPEAKER = 3;
+  public static final int MODE_FLOOR = 4;
+  public static final int MODE_INVALID = 5;
+  
+  public static final int NO_OBJECT = -1;
+  
+  final int mode;
+  final int[] objectIndices = new int[CUBES_PER_CHANNEL];
+  
+  ChannelMapping() {
+    this(MODE_NULL);
+  }
+  
+  ChannelMapping(int mode) {
+    this(mode, new int[]{});
+  }
+  
+  ChannelMapping(int mode, int rawObjectIndex) {
+    this(mode, new int[]{ rawObjectIndex });
+  }
+  
+  ChannelMapping(int mode, int[] rawObjectIndices) {
+    if (mode < 0 || mode >= MODE_INVALID) {
+      throw new RuntimeException("Invalid channel mapping mode: " + mode);
+    }
+    if (mode == MODE_SPEAKER) {
+      if (rawObjectIndices.length != 1) {
+        throw new RuntimeException("Speaker channel mapping mode must specify one speaker index");
+      }
+      int speakerIndex = rawObjectIndices[0];
+      if (speakerIndex < 0 || speakerIndex >= glucose.model.speakers.size()) {
+        throw new RuntimeException("Invalid speaker channel mapping: " + speakerIndex);
+      }
+    } else if ((mode == MODE_FLOOR) || (mode == MODE_BASS) || (mode == MODE_NULL)) {
+      if (rawObjectIndices.length > 0) {
+        throw new RuntimeException("Bass/floor/null mappings cannot specify object indices");
+      }
+    } else if (mode == MODE_CUBES) {
+      for (int rawCubeIndex : rawObjectIndices) {
+        if (glucose.model.getCubeByRawIndex(rawCubeIndex) == null) {
+          throw new RuntimeException("Non-existing cube specified in cube mapping: " + rawCubeIndex);
+        }
+      }
+    }
+    
+    this.mode = mode;
+    for (int i = 0; i < objectIndices.length; ++i) {
+      objectIndices[i] = (i < rawObjectIndices.length) ? rawObjectIndices[i] : NO_OBJECT;
+    }
+  }
+}
index a02aa12fc653111915f22c6d93673ec21d91fc41..2ee00c8c26b8247d8fac858ace30873851d2b67b 100644 (file)
@@ -748,7 +748,7 @@ class MappingUI extends OverlayUI {
 
 class DebugUI {
   
-  final int[][] channelList;
+  final ChannelMapping[] channelList;
   final int debugX = 10;
   final int debugY = 42;
   final int debugXSpacing = 28;
@@ -761,10 +761,10 @@ class DebugUI {
   
   DebugUI(PandaMapping[] pandaMappings) {
     int totalChannels = pandaMappings.length * PandaMapping.CHANNELS_PER_BOARD;
-    channelList = new int[totalChannels][];
+    channelList = new ChannelMapping[totalChannels];
     int channelIndex = 0;
     for (PandaMapping pm : pandaMappings) {
-      for (int[] channel : pm.channelList) {
+      for (ChannelMapping channel : pm.channelList) {
         channelList[channelIndex++] = channel;
       }
     }
@@ -784,26 +784,44 @@ class DebugUI {
     rect(4, 32, 172, 388);
     
     int channelNum = 0;
-    for (int[] channel : channelList) {
+    for (ChannelMapping channel : channelList) {
       int xPos = xBase;
       drawNumBox(xPos, yPos, channelNum+1, debugState[channelNum][0]);
+      xPos += debugXSpacing;
       
-      boolean first = true;
-      int cubeNum = 0;
-      for (int cube : channel) {
-        if (cube <= 0) {
+      switch (channel.mode) {
+        case ChannelMapping.MODE_CUBES:
+          int stateIndex = 0;
+          boolean first = true;
+          for (int rawCubeIndex : channel.objectIndices) {
+            if (rawCubeIndex < 0) {
+              break;
+            }
+            if (first) {
+              first = false;
+            } else {
+              stroke(#999999);          
+              line(xPos - 12, yPos + 8, xPos, yPos + 8);
+            }
+            drawNumBox(xPos, yPos, rawCubeIndex, debugState[channelNum][stateIndex+1]);
+            ++stateIndex;
+            xPos += debugXSpacing;            
+          }
           break;
-        }
-        xPos += debugXSpacing;
-        if (first) {
-          first = false;
-        } else {
-          stroke(#999999);          
-          line(xPos - 12, yPos + 8, xPos, yPos + 8);
-        }
-        drawNumBox(xPos, yPos, cube, debugState[channelNum][cubeNum+1]);
-        ++cubeNum;
-      }
+        case ChannelMapping.MODE_BASS:
+          drawNumBox(xPos, yPos, "B", debugState[channelNum][1]);
+          break;
+        case ChannelMapping.MODE_SPEAKER:
+          drawNumBox(xPos, yPos, "S" + channel.objectIndices[0], debugState[channelNum][1]);
+          break;
+        case ChannelMapping.MODE_FLOOR:
+          drawNumBox(xPos, yPos, "F", debugState[channelNum][1]);
+          break;
+        case ChannelMapping.MODE_NULL:
+          break;
+        default:
+          throw new RuntimeException("Unhandled channel mapping mode: " + channel.mode);
+      }          
       
       yPos += debugYSpacing;
       ++channelNum;
@@ -851,20 +869,61 @@ class DebugUI {
     color white = #FFFFFF;
     color off = #000000;
     int channelIndex = 0;
-    for (int[] channel : channelList) {
-      int cubeIndex = 1;
-      for (int rawCubeIndex : channel) {
-        if (rawCubeIndex > 0) {
-          int state = debugState[channelIndex][cubeIndex];
-          if (state != DEBUG_STATE_ANIM) {
-            color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
-            Cube cube = glucose.model.getCubeByRawIndex(rawCubeIndex);
-            for (Point p : cube.points) {
-              colors[p.index] = debugColor;
+    int state;
+    for (ChannelMapping channel : channelList) {
+      switch (channel.mode) {
+        case ChannelMapping.MODE_CUBES:
+          int cubeIndex = 1;
+          for (int rawCubeIndex : channel.objectIndices) {
+            if (rawCubeIndex >= 0) {
+              state = debugState[channelIndex][cubeIndex];
+              if (state != DEBUG_STATE_ANIM) {
+                color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
+                Cube cube = glucose.model.getCubeByRawIndex(rawCubeIndex);
+                for (Point p : cube.points) {
+                  colors[p.index] = debugColor;
+                }
+              }
             }
+            ++cubeIndex;
           }
-        }
-        ++cubeIndex;
+          break;
+            
+         case ChannelMapping.MODE_BASS:
+           state = debugState[channelIndex][1];
+           if (state != DEBUG_STATE_ANIM) {
+              color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
+              for (Point p : glucose.model.bassBox.points) {
+                colors[p.index] = debugColor;
+              }
+           }
+           break;
+
+         case ChannelMapping.MODE_FLOOR:
+           state = debugState[channelIndex][1];
+           if (state != DEBUG_STATE_ANIM) {
+              color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
+              for (Point p : glucose.model.boothFloor.points) {
+                colors[p.index] = debugColor;
+              }
+           }
+           break;
+           
+         case ChannelMapping.MODE_SPEAKER:
+           state = debugState[channelIndex][1];
+           if (state != DEBUG_STATE_ANIM) {
+              color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
+              for (Point p : glucose.model.speakers.get(channel.objectIndices[0]).points) {
+                colors[p.index] = debugColor;
+              }
+           }
+           break;
+           
+         case ChannelMapping.MODE_NULL:
+           break;
+           
+        default:
+          throw new RuntimeException("Unhandled channel mapping mode: " + channel.mode);           
       }
       ++channelIndex;
     }
index ef86dbe71714473e20375ca7f42df31c26a55451..3f5f0113642bee32547bfed20d94220a80d3bd9d 100644 (file)
@@ -34,6 +34,8 @@ public class PandaDriver {
   // Packet data
   private final byte[] packet = new byte[4*352]; // TODO: de-magic-number, UDP related?
 
+  private static final int NO_POINT = -1;
+
   public PandaDriver(String ip) {
     this.ip = ip;
     this.address = new NetAddress(ip, 9001);
@@ -70,31 +72,62 @@ public class PandaDriver {
     };
 
     int pi = 0;
-    for (int[] channel : pm.channelList) {
-      for (int cubeNumber : channel) {
-        if (cubeNumber <= 0) {
-          for (int i = 0; i < Cube.POINTS_PER_CUBE; ++i) {
-            points[pi++] = 0;
+    for (ChannelMapping channel : pm.channelList) {
+      switch (channel.mode) {
+        case ChannelMapping.MODE_CUBES:
+          for (int rawCubeIndex : channel.objectIndices) {
+            if (rawCubeIndex < 0) {
+              for (int i = 0; i < Cube.POINTS_PER_CUBE; ++i) {
+                points[pi++] = NO_POINT;
+              }
+            } else {
+              Cube cube = model.getCubeByRawIndex(rawCubeIndex);
+              int stripOrderIndex = 0;
+              switch (cube.wiring) {
+                case FRONT_LEFT: stripOrderIndex = 0; break;
+                case FRONT_RIGHT: stripOrderIndex = 1; break;
+                case REAR_LEFT: stripOrderIndex = 2; break;
+                case REAR_RIGHT: stripOrderIndex = 3; break;
+              }
+              for (int stripIndex : stripOrderings[stripOrderIndex]) {
+                Strip s = cube.strips.get(stripIndex);
+                for (int j = s.points.size() - 1; j >= 0; --j) {
+                  points[pi++] = s.points.get(j).index;
+                }
+              }
+            }
           }
-        } else {
-          Cube cube = model.getCubeByRawIndex(cubeNumber);
-          if (cube == null) {
-            throw new RuntimeException("Non-zero, non-existing cube specified in channel mapping (" + cubeNumber + ")");
+          break;
+          
+        case ChannelMapping.MODE_BASS:
+          // TODO(mapping): figure out how these strips are wired
+          for (int i = 0; i < ChannelMapping.PIXELS_PER_CHANNEL; ++i) {
+            points[pi++] = NO_POINT;
           }
-          int stripOrderIndex = 0;
-          switch (cube.wiring) {
-            case FRONT_LEFT: stripOrderIndex = 0; break;
-            case FRONT_RIGHT: stripOrderIndex = 1; break;
-            case REAR_LEFT: stripOrderIndex = 2; break;
-            case REAR_RIGHT: stripOrderIndex = 3; break;
+          break;
+          
+        case ChannelMapping.MODE_FLOOR:        
+          // TODO(mapping): figure out how these strips are wired
+          for (int i = 0; i < ChannelMapping.PIXELS_PER_CHANNEL; ++i) {
+            points[pi++] = NO_POINT;
           }
-          for (int stripIndex : stripOrderings[stripOrderIndex]) {
-            Strip s = cube.strips.get(stripIndex);
-            for (int j = s.points.size() - 1; j >= 0; --j) {
-              points[pi++] = s.points.get(j).index;
-            }
+          break;
+          
+        case ChannelMapping.MODE_SPEAKER:
+          // TODO(mapping): figure out how these strips are wired
+          for (int i = 0; i < ChannelMapping.PIXELS_PER_CHANNEL; ++i) {
+            points[pi++] = NO_POINT;
+          }
+          break;
+          
+        case ChannelMapping.MODE_NULL:
+          for (int i = 0; i < ChannelMapping.PIXELS_PER_CHANNEL; ++i) {
+            points[pi++] = NO_POINT;
           }
-        }
+          break;
+          
+        default:
+          throw new RuntimeException("Invalid/unhandled channel mapping mode: " + channel.mode);
       }
     }
   }
@@ -106,7 +139,7 @@ public class PandaDriver {
     int len = 0;
     int packetNum = 0;
     for (int index : points) {
-      int c = colors[index];
+      int c = (index < 0) ? 0 : colors[index];
       byte r = (byte) ((c >> 16) & 0xFF);
       byte g = (byte) ((c >> 8) & 0xFF);
       byte b = (byte) ((c) & 0xFF);