New Grizzly code using LXOutput framework
[SugarCubes.git] / _Internals.pde
index 044d650de195f7883980342ac25d8ba419c73bcd..0100c051c82d0b4bc8b6125829c5bff708e664b3 100644 (file)
@@ -4,7 +4,7 @@
  *         //\\   //\\                 //\\   //\\  
  *        ///\\\ ///\\\               ///\\\ ///\\\
  *        \\\/// \\\///               \\\/// \\\///
  *         //\\   //\\                 //\\   //\\  
  *        ///\\\ ///\\\               ///\\\ ///\\\
  *        \\\/// \\\///               \\\/// \\\///
- *         \\//   \\//                 \\//   \\//
+ *         \\//   \\//                 \\//   \\//H
  *
  *        EXPERTS ONLY!!              EXPERTS ONLY!!
  *
  *
  *        EXPERTS ONLY!!              EXPERTS ONLY!!
  *
  */
 
 import glucose.*;
  */
 
 import glucose.*;
-import glucose.control.*;
-import glucose.effect.*;
 import glucose.model.*;
 import glucose.model.*;
-import glucose.pattern.*;
-import glucose.transform.*;
-import glucose.transition.*;
 import heronarts.lx.*;
 import heronarts.lx.*;
-import heronarts.lx.control.*;
 import heronarts.lx.effect.*;
 import heronarts.lx.modulator.*;
 import heronarts.lx.effect.*;
 import heronarts.lx.modulator.*;
+import heronarts.lx.parameter.*;
 import heronarts.lx.pattern.*;
 import heronarts.lx.pattern.*;
+import heronarts.lx.transform.*;
 import heronarts.lx.transition.*;
 import heronarts.lx.transition.*;
+import heronarts.lx.ui.*;
+import heronarts.lx.ui.component.*;
+import heronarts.lx.ui.control.*;
 import ddf.minim.*;
 import ddf.minim.analysis.*;
 import processing.opengl.*;
 import rwmidi.*;
 import ddf.minim.*;
 import ddf.minim.analysis.*;
 import processing.opengl.*;
 import rwmidi.*;
+import java.lang.reflect.*;
 
 final int VIEWPORT_WIDTH = 900;
 final int VIEWPORT_HEIGHT = 700;
 
 final int VIEWPORT_WIDTH = 900;
 final int VIEWPORT_HEIGHT = 700;
@@ -44,41 +44,74 @@ int startMillis, lastMillis;
 
 // Core engine variables
 GLucose glucose;
 
 // Core engine variables
 GLucose glucose;
-HeronLX lx;
+LX lx;
+Model model;
 LXPattern[] patterns;
 LXPattern[] patterns;
+Effects effects;
 MappingTool mappingTool;
 PandaDriver[] pandaBoards;
 MappingTool mappingTool;
 PandaDriver[] pandaBoards;
-MidiListener midiQwerty;
+PresetManager presetManager;
+MidiEngine midiEngine;
 
 // Display configuration mode
 boolean mappingMode = false;
 boolean debugMode = false;
 DebugUI debugUI;
 boolean uiOn = true;
 
 // Display configuration mode
 boolean mappingMode = false;
 boolean debugMode = false;
 DebugUI debugUI;
 boolean uiOn = true;
+boolean simulationOn = true;
+boolean diagnosticsOn = false;
 LXPattern restoreToPattern = null;
 LXPattern restoreToPattern = null;
+PImage logo;
+float[] hsb = new float[3];
 
 // Handles to UI objects
 
 // Handles to UI objects
-UIContext[] overlays;
 UIPatternDeck uiPatternA;
 UICrossfader uiCrossfader;
 UIMidi uiMidi;
 UIMapping uiMapping;
 UIDebugText uiDebugText;
 UIPatternDeck uiPatternA;
 UICrossfader uiCrossfader;
 UIMidi uiMidi;
 UIMapping uiMapping;
 UIDebugText uiDebugText;
-
-// Camera variables
-float eyeR, eyeA, eyeX, eyeY, eyeZ, midX, midY, midZ;
+UISpeed uiSpeed;
 
 /**
  * Engine construction and initialization.
  */
 
 /**
  * Engine construction and initialization.
  */
-LXPattern[] _patterns(GLucose glucose) {
+
+LXTransition _transition(GLucose glucose) {
+  return new DissolveTransition(glucose.lx).setDuration(1000);
+}
+
+LXPattern[] _leftPatterns(GLucose glucose) {
   LXPattern[] patterns = patterns(glucose);
   for (LXPattern p : patterns) {
   LXPattern[] patterns = patterns(glucose);
   for (LXPattern p : patterns) {
-    p.setTransition(new DissolveTransition(glucose.lx).setDuration(1000));
+    p.setTransition(_transition(glucose));
   }
   return patterns;
 }
 
   }
   return patterns;
 }
 
+LXPattern[] _rightPatterns(GLucose glucose) {
+  LXPattern[] patterns = _leftPatterns(glucose);
+  LXPattern[] rightPatterns = new LXPattern[patterns.length+1];
+  int i = 0;
+  rightPatterns[i++] = new BlankPattern(glucose).setTransition(_transition(glucose));
+  for (LXPattern p : patterns) {
+    rightPatterns[i++] = p;
+  }
+  return rightPatterns;
+}
+
+LXEffect[] _effectsArray(Effects effects) {
+  List<LXEffect> effectList = new ArrayList<LXEffect>();
+  for (Field f : effects.getClass().getDeclaredFields()) {
+    try {
+      Object val = f.get(effects);
+      if (val instanceof LXEffect) {
+        effectList.add((LXEffect)val);
+      }
+    } catch (IllegalAccessException iax) {}
+  }
+  return effectList.toArray(new LXEffect[]{});
+} 
+
 void logTime(String evt) {
   int now = millis();
   println(evt + ": " + (now - lastMillis) + "ms");
 void logTime(String evt) {
   int now = millis();
   println(evt + ": " + (now - lastMillis) + "ms");
@@ -96,22 +129,39 @@ void setup() {
   logTime("Created viewport");
 
   // Create the GLucose engine to run the cubes
   logTime("Created viewport");
 
   // Create the GLucose engine to run the cubes
-  glucose = new GLucose(this, buildModel());
+  glucose = new GLucose(this, model = buildModel());
   lx = glucose.lx;
   lx.enableKeyboardTempo();
   logTime("Built GLucose engine");
   lx = glucose.lx;
   lx.enableKeyboardTempo();
   logTime("Built GLucose engine");
-  
+    
   // Set the patterns
   // Set the patterns
-  Engine engine = lx.engine;
-  engine.setPatterns(patterns = _patterns(glucose));
-  engine.addDeck(_patterns(glucose));
+  LXEngine engine = lx.engine;
+  engine.setPatterns(patterns = _leftPatterns(glucose));
+  engine.addDeck(_rightPatterns(glucose));
   logTime("Built patterns");
   glucose.setTransitions(transitions(glucose));
   logTime("Built transitions");
   logTime("Built patterns");
   glucose.setTransitions(transitions(glucose));
   logTime("Built transitions");
-  glucose.lx.addEffects(effects(glucose));
+  glucose.lx.addEffects(_effectsArray(effects = new Effects()));
   logTime("Built effects");
   logTime("Built effects");
-    
+
+  // Preset manager
+  presetManager = new PresetManager();
+  logTime("Loaded presets");
+
+  // MIDI devices
+  midiEngine = new MidiEngine();
+  logTime("Setup MIDI devices");
+
   // Build output driver
   // Build output driver
+  try {
+    GrizzlyOutput[] grizzlies = buildGrizzlies();
+    for (LXOutput output : grizzlies) {
+      lx.addOutput(output);
+    }
+  } catch (Exception x) {
+    x.printStackTrace();
+  }
+  
   PandaMapping[] pandaMappings = buildPandaList();
   pandaBoards = new PandaDriver[pandaMappings.length];
   int pbi = 0;
   PandaMapping[] pandaMappings = buildPandaList();
   pandaBoards = new PandaDriver[pandaMappings.length];
   int pbi = 0;
@@ -121,216 +171,168 @@ void setup() {
   mappingTool = new MappingTool(glucose, pandaMappings);
   logTime("Built PandaDriver");
 
   mappingTool = new MappingTool(glucose, pandaMappings);
   logTime("Built PandaDriver");
 
-  // MIDI devices
-  List<MidiListener> midiListeners = new ArrayList<MidiListener>();
-  midiListeners.add(midiQwerty = new MidiListener());
-  for (MidiInputDevice device : RWMidi.getInputDevices()) {
-    boolean enableDevice = device.getName().contains("APC");
-    midiListeners.add(new MidiListener(device).setEnabled(enableDevice));
-  }
-  SCMidiDevices.initializeStandardDevices(glucose);
-  logTime("Setup MIDI devices");
-
   // Build overlay UI
   debugUI = new DebugUI(pandaMappings);
   // Build overlay UI
   debugUI = new DebugUI(pandaMappings);
-  overlays = new UIContext[] {
-    uiPatternA = new UIPatternDeck(lx.engine.getDeck(0), "PATTERN A", 4, 4, 140, 324),
+  UIContext[] contexts = new UIContext[] {
+    uiPatternA = new UIPatternDeck(lx.ui, lx.engine.getDeck(GLucose.LEFT_DECK), "PATTERN A", 4, 4, 140, 324),
     new UIBlendMode(4, 332, 140, 86),
     new UIEffects(4, 422, 140, 144),
     new UITempo(4, 570, 140, 50),
     new UIBlendMode(4, 332, 140, 86),
     new UIEffects(4, 422, 140, 144),
     new UITempo(4, 570, 140, 50),
-    new UISpeed(4, 624, 140, 50),
+    uiSpeed = new UISpeed(4, 624, 140, 50),
         
         
-    new UIPatternDeck(lx.engine.getDeck(1), "PATTERN B", width-144, 4, 140, 324),
-    uiMidi = new UIMidi(midiListeners, width-144, 332, 140, 160),
-    new UIOutput(width-144, 498, 140, 106),
+    new UIPatternDeck(lx.ui, lx.engine.getDeck(GLucose.RIGHT_DECK), "PATTERN B", width-144, 4, 140, 324),
+    uiMidi = new UIMidi(midiEngine, width-144, 332, 140, 158),
+    new UIOutput(width-144, 494, 140, 106),
     
     uiCrossfader = new UICrossfader(width/2-90, height-90, 180, 86),
     
     uiDebugText = new UIDebugText(148, height-138, width-304, 44),
     
     uiCrossfader = new UICrossfader(width/2-90, height-90, 180, 86),
     
     uiDebugText = new UIDebugText(148, height-138, width-304, 44),
-    uiMapping = new UIMapping(mappingTool, 4, 4, 140, 324),
+    uiMapping = new UIMapping(mappingTool, 4, 4, 140, 324)
   };
   uiMapping.setVisible(false);
   };
   uiMapping.setVisible(false);
+  lx.ui.addLayer(new UICameraLayer(lx.ui).setCenter(TRAILER_WIDTH/2., glucose.model.yMax/2, TRAILER_DEPTH/2.).setRadius(290).addComponent(new UICubesLayer()));
+  for (UIContext context : contexts) {
+    lx.ui.addLayer(context);
+  }
   logTime("Built overlay UI");
   logTime("Built overlay UI");
-    
-  // Setup camera
-  midX = TRAILER_WIDTH/2.;
-  midY = glucose.model.yMax/2;
-  midZ = TRAILER_DEPTH/2.;
-  eyeR = -290;
-  eyeA = .15;
-  eyeY = midY + 70;
-  eyeX = midX + eyeR*sin(eyeA);
-  eyeZ = midZ + eyeR*cos(eyeA);
-  addMouseWheelListener(new java.awt.event.MouseWheelListener() { 
-    public void mouseWheelMoved(java.awt.event.MouseWheelEvent mwe) { 
-      mouseWheel(mwe.getWheelRotation());
-  }}); 
-  
+
+  // Load logo image
+  logo = loadImage("data/logo.png");
+      
   println("Total setup: " + (millis() - startMillis) + "ms");
   println("Hit the 'p' key to toggle Panda Board output");
 }
 
   println("Total setup: " + (millis() - startMillis) + "ms");
   println("Hit the 'p' key to toggle Panda Board output");
 }
 
-public class MidiListener extends AbstractScrollItem {
-  private boolean enabled = false;
-  private final String name;
-  
-  MidiListener(MidiInputDevice d) {
-    d.createInput(this);
-    name = d.getName();
-  }
-  
-  class NoteMeta {
-    int channel;
-    int number;
-    NoteMeta(int channel, int number) {
-      this.channel = channel;
-      this.number = number;
-    }
-  }
-  
-  final Map<Character, NoteMeta> keyToNote = new HashMap<Character, NoteMeta>();
-  
-  MidiListener() {
-    name = "QWERTY Keyboard";
-    mapNote('1', 0, 53);
-    mapNote('2', 1, 53);
-    mapNote('3', 2, 53);
-    mapNote('4', 3, 53);
-    mapNote('5', 4, 53);
-    mapNote('6', 5, 53);
-    mapNote('q', 0, 54);
-    mapNote('w', 1, 54);
-    mapNote('e', 2, 54);
-    mapNote('r', 3, 54);
-    mapNote('t', 4, 54);
-    mapNote('y', 5, 54);
-    mapNote('a', 0, 55);
-    mapNote('s', 1, 55);
-    mapNote('d', 2, 55);
-    mapNote('f', 3, 55);
-    mapNote('g', 4, 55);
-    mapNote('h', 5, 55);
-    mapNote('z', 0, 56);
-    mapNote('x', 1, 56);
-    mapNote('c', 2, 56);
-    mapNote('v', 3, 56);
-    mapNote('b', 4, 56);
-    mapNote('n', 5, 56);
-    registerKeyEvent(this);
-  }
-  
-  void mapNote(char ch, int channel, int number) {
-    keyToNote.put(ch, new NoteMeta(channel, number));
-  }
-  
-  public String getLabel() {
-    return name;
-  }
-  
-  public void keyEvent(KeyEvent e) {
-    char c = Character.toLowerCase(e.getKeyChar());
-    NoteMeta nm = keyToNote.get(c);
-    if (nm != null) {
-      switch (e.getID()) {
-        case KeyEvent.KEY_PRESSED:
-          noteOnReceived(new Note(Note.NOTE_ON, nm.channel, nm.number, 127));
-          break;
-        case KeyEvent.KEY_RELEASED:
-          noteOffReceived(new Note(Note.NOTE_OFF, nm.channel, nm.number, 0));
-          break;
-      }
-    }
-  }
-  
-  public boolean isEnabled() {
-    return enabled;
-  }
+/**
+ * Core render loop and drawing functionality.
+ */
+void draw() {
+  long drawStart = System.nanoTime();
   
   
-  public boolean isSelected() {
-    return enabled;
-  }
+  // Set background
+  background(40);
   
   
-  public void onMousePressed() {
-    setEnabled(!enabled);
+  // Send colors
+  color[] sendColors = glucose.getColors();
+  if (debugMode) {
+    debugUI.maskColors(sendColors);
   }
   
   }
   
-  public MidiListener setEnabled(boolean enabled) {
-    if (enabled != this.enabled) {
-      this.enabled = enabled;
-      uiMidi.redraw();
-    }
-    return this;
+  long gammaStart = System.nanoTime();
+  // Gamma correction here. Apply a cubic to the brightness
+  // for better representation of dynamic range
+  for (int i = 0; i < sendColors.length; ++i) {
+    lx.RGBtoHSB(sendColors[i], hsb);
+    float b = hsb[2];
+    sendColors[i] = lx.hsb(360.*hsb[0], 100.*hsb[1], 100.*(b*b*b));
   }
   }
-  
-  private SCPattern getFocusedPattern() {
-    return (SCPattern) uiMidi.getFocusedDeck().getActivePattern();
+  long gammaNanos = System.nanoTime() - gammaStart;
+
+  long sendStart = System.nanoTime();
+  for (PandaDriver p : pandaBoards) {
+    p.send(sendColors);
   }
   }
-  
-  void programChangeReceived(ProgramChange pc) {
-    if (!enabled) {
-      return;
-    }
-    if (uiMidi.logMidi()) {
-      println(getLabel() + " :: Program Change :: " + pc.getNumber());
-    }
+  long sendNanos = System.nanoTime() - sendStart;
+
+  drawFPS();
+  if (debugMode) {
+    debugUI.draw();
   }
   }
+
+  // TODO(mcslee): fix
+  long drawNanos = System.nanoTime() - drawStart;
   
   
-  void controllerChangeReceived(rwmidi.Controller cc) {
-    if (!enabled) {
-      return;
-    }
-    if (uiMidi.logMidi()) {
-      println(getLabel() + " :: Controller :: " + cc.getCC() + ":" + cc.getValue());
-    }
-    getFocusedPattern().controllerChangeReceived(cc);
-  }
+  long simulationNanos = 0, uiNanos = 0;
+  if (diagnosticsOn) {
+    drawDiagnostics(drawNanos, simulationNanos, uiNanos, gammaNanos, sendNanos);
+  }  
+}
 
 
-  void noteOnReceived(Note note) {
-    if (!enabled) {
-      return;
+class UICubesLayer extends UICameraComponent {
+  void onDraw(UI ui) {
+    color[] simulationColors = glucose.getColors();
+    String displayMode = uiCrossfader.getDisplayMode();
+    if (displayMode == "A") {
+      simulationColors = lx.engine.getDeck(GLucose.LEFT_DECK).getColors();
+    } else if (displayMode == "B") {
+      simulationColors = lx.engine.getDeck(GLucose.RIGHT_DECK).getColors();
     }
     }
-    if (uiMidi.logMidi()) {
-      println(getLabel() + " :: Note On  :: " + note.getChannel() + ":" + note.getPitch() + ":" + note.getVelocity());
+    if (debugMode) {
+      debugUI.maskColors(simulationColors);
     }
     }
-    getFocusedPattern().noteOnReceived(note);
-  }
 
 
-  void noteOffReceived(Note note) {
-    if (!enabled) {
-      return;
-    }
-    if (uiMidi.logMidi()) {
-      println(getLabel() + " :: Note Off :: " + note.getChannel() + ":" + note.getPitch() + ":" + note.getVelocity());
+    long simulationStart = System.nanoTime();
+    if (simulationOn) {
+      drawSimulation(simulationColors);
     }
     }
-    getFocusedPattern().noteOffReceived(note);
-  }
-
+    long simulationNanos = System.nanoTime() - simulationStart;
+    
+    camera();
+    javax.media.opengl.GL gl = ((PGraphicsOpenGL)g).beginGL();
+    gl.glClear(javax.media.opengl.GL.GL_DEPTH_BUFFER_BIT);
+    ((PGraphicsOpenGL)g).endGL();
+    strokeWeight(1);
+  }      
 }
 
 }
 
-/**
- * Core render loop and drawing functionality.
- */
-void draw() {
-  // Draws the simulation and the 2D UI overlay
-  background(40);
-  color[] colors = glucose.getColors();
-
-  String displayMode = uiCrossfader.getDisplayMode();
-  if (displayMode == "A") {
-    colors = lx.engine.getDeck(0).getColors();
-  } else if (displayMode == "B") {
-    colors = lx.engine.getDeck(1).getColors();
+void drawDiagnostics(long drawNanos, long simulationNanos, long uiNanos, long gammaNanos, long sendNanos) {
+  float ws = 4 / 1000000.;
+  int thirtyfps = 1000000000 / 30;
+  int sixtyfps = 1000000000 / 60;
+  int x = width - 138;
+  int y = height - 14;
+  int h = 10;
+  noFill();
+  stroke(#999999);
+  rect(x, y, thirtyfps * ws, h);
+  noStroke();
+  int xp = x;
+  float hv = 0;
+  for (long val : new long[] {lx.timer.drawNanos, simulationNanos, uiNanos, gammaNanos, sendNanos }) {
+    fill(lx.hsb(hv % 360, 100, 80));
+    rect(xp, y, val * ws, h-1);
+    hv += 140;
+    xp += val * ws;
   }
   }
-  if (debugMode) {
-    debugUI.maskColors(colors);
+  noFill();
+  stroke(#333333);
+  line(x+sixtyfps*ws, y+1, x+sixtyfps*ws, y+h-1);
+  
+  y = y - 14;
+  xp = x;
+  float tw = thirtyfps * ws;
+  noFill();
+  stroke(#999999);
+  rect(x, y, tw, h);
+  h = 5;
+  noStroke();
+  for (long val : new long[] {
+    lx.engine.timer.deckNanos,
+    lx.engine.timer.copyNanos,
+    lx.engine.timer.fxNanos}) {
+    float amt = val / (float) lx.timer.drawNanos;
+    fill(lx.hsb(hv % 360, 100, 80));
+    rect(xp, y, amt * tw, h-1);
+    hv += 140;
+    xp += amt * tw;
   }
   }
+  
+  xp = x;
+  y += h;
+  hv = 120;
+  for (long val : new long[] {
+    lx.engine.getDeck(0).timer.runNanos,
+    lx.engine.getDeck(1).timer.runNanos,
+    lx.engine.getDeck(1).getFaderTransition().timer.blendNanos}) {
+    float amt = val / (float) lx.timer.drawNanos;
+    fill(lx.hsb(hv % 360, 100, 80));
+    rect(xp, y, amt * tw, h-1);
+    hv += 140;
+    xp += amt * tw;
+  }
+}
 
 
-  camera(
-    eyeX, eyeY, eyeZ,
-    midX, midY, midZ,
-    0, -1, 0
-  );
-
+void drawSimulation(color[] simulationColors) {
   translate(0, 40, 0);
 
   noStroke();
   translate(0, 40, 0);
 
   noStroke();
@@ -344,12 +346,22 @@ void draw() {
   vertex(TRAILER_WIDTH, 0, TRAILER_DEPTH);
   vertex(0, 0, TRAILER_DEPTH);
   endShape();
   vertex(TRAILER_WIDTH, 0, TRAILER_DEPTH);
   vertex(0, 0, TRAILER_DEPTH);
   endShape();
+
+  // Draw the logo on the front of platform  
+  pushMatrix();
+  translate(0, 0, -1);
+  float s = .07;
+  scale(s, -s, s);
+  image(logo, TRAILER_WIDTH/2/s-logo.width/2, TRAILER_HEIGHT/2/s-logo.height/2-2/s);
+  popMatrix();
   
   noStroke();
   
   noStroke();
-//  drawBassBox(glucose.model.bassBox);
-//  for (Speaker s : glucose.model.speakers) {
-//    drawSpeaker(s);
-//  }
+  if (glucose.model.bassBox.exists) {
+    drawBassBox(glucose.model.bassBox, false);
+  }
+  for (Speaker speaker : glucose.model.speakers) {
+    drawSpeaker(speaker);
+  }
   for (Cube c : glucose.model.cubes) {
     drawCube(c);
   }
   for (Cube c : glucose.model.cubes) {
     drawCube(c);
   }
@@ -357,51 +369,25 @@ void draw() {
   noFill();
   strokeWeight(2);
   beginShape(POINTS);
   noFill();
   strokeWeight(2);
   beginShape(POINTS);
-  // TODO(mcslee): restore when bassBox/speakers are right again
-  // for (Point p : glucose.model.points) {
-  for (Cube cube : glucose.model.cubes) {
-    for (Point p : cube.points) {
-      stroke(colors[p.index]);
-      vertex(p.fx, p.fy, p.fz);
-    }
+  for (LXPoint p : glucose.model.points) {
+    stroke(simulationColors[p.index]);
+    vertex(p.x, p.y, p.z);
   }
   endShape();
   }
   endShape();
-  
-  // 2D Overlay UI
-  drawUI();
-    
-  // Send output colors
-  color[] sendColors = glucose.getColors();
-  if (debugMode) {
-    debugUI.maskColors(colors);
-  }
-  
-  // Gamma correction here. Apply a cubic to the brightness
-  // for better representation of dynamic range
-  for (int i = 0; i < colors.length; ++i) {
-    float b = brightness(colors[i]) / 100.f;
-    colors[i] = color(
-      hue(colors[i]),
-      saturation(colors[i]),
-      (b*b*b) * 100.
-    );
-  }
-  
-  // TODO(mcslee): move into GLucose engine
-  for (PandaDriver p : pandaBoards) {
-    p.send(colors);
-  }
 }
 
 }
 
-void drawBassBox(BassBox b) {
+void drawBassBox(BassBox b, boolean hasSub) {
+  
   float in = .15;
   float in = .15;
-
-  noStroke();
-  fill(#191919);
-  pushMatrix();
-  translate(b.x + BassBox.EDGE_WIDTH/2., b.y + BassBox.EDGE_HEIGHT/2, b.z + BassBox.EDGE_DEPTH/2.);
-  box(BassBox.EDGE_WIDTH-20*in, BassBox.EDGE_HEIGHT-20*in, BassBox.EDGE_DEPTH-20*in);
-  popMatrix();
+  
+  if (hasSub) {
+    noStroke();
+    fill(#191919);
+    pushMatrix();
+    translate(b.x + BassBox.EDGE_WIDTH/2., b.y + BassBox.EDGE_HEIGHT/2, b.z + BassBox.EDGE_DEPTH/2.);
+    box(BassBox.EDGE_WIDTH-20*in, BassBox.EDGE_HEIGHT-20*in, BassBox.EDGE_DEPTH-20*in);
+    popMatrix();
+  }
 
   noStroke();
   fill(#393939);
 
   noStroke();
   fill(#393939);
@@ -499,30 +485,15 @@ void drawBox(float x, float y, float z, float rx, float ry, float rz, float xd,
   popMatrix();
 }
 
   popMatrix();
 }
 
-void drawUI() {
-  camera();
-  javax.media.opengl.GL gl = ((PGraphicsOpenGL)g).beginGL();
-  gl.glClear(javax.media.opengl.GL.GL_DEPTH_BUFFER_BIT);
-  ((PGraphicsOpenGL)g).endGL();
-  strokeWeight(1);
-
-  if (uiOn) {
-    for (UIContext context : overlays) {
-      context.draw();
-    }
-  }
-  
+void drawFPS() {  
   // Always draw FPS meter
   fill(#555555);
   textSize(9);
   textAlign(LEFT, BASELINE);
   text("FPS: " + ((int) (frameRate*10)) / 10. + " / " + targetFramerate + " (-/+)", 4, height-4);
   // Always draw FPS meter
   fill(#555555);
   textSize(9);
   textAlign(LEFT, BASELINE);
   text("FPS: " + ((int) (frameRate*10)) / 10. + " / " + targetFramerate + " (-/+)", 4, height-4);
-
-  if (debugMode) {
-    debugUI.draw();
-  }
 }
 
 }
 
+
 /**
  * Top-level keyboard event handling
  */
 /**
  * Top-level keyboard event handling
  */
@@ -531,6 +502,44 @@ void keyPressed() {
     mappingTool.keyPressed(uiMapping);
   }
   switch (key) {
     mappingTool.keyPressed(uiMapping);
   }
   switch (key) {
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+      if (!midiEngine.isQwertyEnabled()) {
+        presetManager.select(midiEngine.getFocusedDeck(), key - '1');
+      }
+      break;
+    
+    case '!':
+      if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 0);
+      break;
+    case '@':
+      if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 1);
+      break;
+    case '#':
+      if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 2);
+      break;
+    case '$':
+      if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 3);
+      break;
+    case '%':
+      if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 4);
+      break;
+    case '^':
+      if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 5);
+      break;
+    case '&':
+      if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 6);
+      break;
+    case '*':
+      if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 7);
+      break;
+      
     case '-':
     case '_':
       frameRate(--targetFramerate);
     case '-':
     case '_':
       frameRate(--targetFramerate);
@@ -538,15 +547,18 @@ void keyPressed() {
     case '=':
     case '+':
       frameRate(++targetFramerate);
     case '=':
     case '+':
       frameRate(++targetFramerate);
-      break;
+      break; 
+    case 'b':
+      effects.boom.trigger();
+      break;    
     case 'd':
     case 'd':
-      if (!midiQwerty.isEnabled()) {
+      if (!midiEngine.isQwertyEnabled()) {
         debugMode = !debugMode;
         println("Debug output: " + (debugMode ? "ON" : "OFF"));
       }
       break;
     case 'm':
         debugMode = !debugMode;
         println("Debug output: " + (debugMode ? "ON" : "OFF"));
       }
       break;
     case 'm':
-      if (!midiQwerty.isEnabled()) {
+      if (!midiEngine.isQwertyEnabled()) {
         mappingMode = !mappingMode;
         uiPatternA.setVisible(!mappingMode);
         uiMapping.setVisible(mappingMode);
         mappingMode = !mappingMode;
         uiPatternA.setVisible(!mappingMode);
         uiMapping.setVisible(mappingMode);
@@ -562,13 +574,30 @@ void keyPressed() {
         }
       }
       break;
         }
       }
       break;
+    case 't':
+      if (!midiEngine.isQwertyEnabled()) {
+        lx.engine.setThreaded(!lx.engine.isThreaded());
+      }
+      break;
     case 'p':
       for (PandaDriver p : pandaBoards) {
         p.toggle();
       }
       break;
     case 'p':
       for (PandaDriver p : pandaBoards) {
         p.toggle();
       }
       break;
+    case 'q':
+      if (!midiEngine.isQwertyEnabled()) {
+        diagnosticsOn = !diagnosticsOn;
+      }
+      break;
+    case 's':
+      if (!midiEngine.isQwertyEnabled()) {
+        simulationOn = !simulationOn;
+      }
+      break;
     case 'u':
     case 'u':
-      uiOn = !uiOn;
+      if (!midiEngine.isQwertyEnabled()) {
+        uiOn = !uiOn;
+      }
       break;
   }
 }
       break;
   }
 }
@@ -576,53 +605,9 @@ void keyPressed() {
 /**
  * Top-level mouse event handling
  */
 /**
  * Top-level mouse event handling
  */
-int mx, my;
 void mousePressed() {
 void mousePressed() {
-  boolean debugged = false;
   if (debugMode) {
   if (debugMode) {
-    debugged = debugUI.mousePressed();
-  }
-  if (!debugged) {
-    for (UIContext context : overlays) {
-      context.mousePressed(mouseX, mouseY);
-    }
+    debugUI.mousePressed();
   }
   }
-  mx = mouseX;
-  my = mouseY;
 }
 
 }
 
-void mouseDragged() {
-  boolean dragged = false;
-  for (UIContext context : overlays) {
-    dragged |= context.mouseDragged(mouseX, mouseY);
-  }
-  if (!dragged) {
-    int dx = mouseX - mx;
-    int dy = mouseY - my;
-    mx = mouseX;
-    my = mouseY;
-    eyeA += dx*.003;
-    eyeX = midX + eyeR*sin(eyeA);
-    eyeZ = midZ + eyeR*cos(eyeA);
-    eyeY += dy;
-  }
-}
-
-void mouseReleased() {
-  for (UIContext context : overlays) {
-    context.mouseReleased(mouseX, mouseY);
-  }
-}
-void mouseWheel(int delta) {
-  boolean wheeled = false;
-  for (UIContext context : overlays) {
-    wheeled |= context.mouseWheel(mouseX, mouseY, delta);
-  }
-  
-  if (!wheeled) {
-    eyeR = constrain(eyeR - delta, -500, -80);
-    eyeX = midX + eyeR*sin(eyeA);
-    eyeZ = midZ + eyeR*cos(eyeA);
-  }
-}