Update to new HeronLX packaging for LXParameter stuff
[SugarCubes.git] / _Internals.pde
index d616264b7bbb73f62f0677a8875b09f8356ef0e2..6a076da811d8be1eba0f2430fb67b13d39177c6a 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 ddf.minim.*;
 import ddf.minim.analysis.*;
 import processing.opengl.*;
 import rwmidi.*;
 import heronarts.lx.transition.*;
 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;
@@ -39,28 +36,32 @@ final float TRAILER_WIDTH = 240;
 final float TRAILER_DEPTH = 97;
 final float TRAILER_HEIGHT = 33;
 
 final float TRAILER_DEPTH = 97;
 final float TRAILER_HEIGHT = 33;
 
-final int MaxCubeHeight = 7;
-final int NumBackTowers = 9;
+final int MaxCubeHeight = 5;
+final int NumBackTowers = 11;
 
 int targetFramerate = 60;
 int startMillis, lastMillis;
 
 // Core engine variables
 GLucose glucose;
 
 int targetFramerate = 60;
 int startMillis, lastMillis;
 
 // Core engine variables
 GLucose glucose;
-HeronLX lx;
+LX lx;
 LXPattern[] patterns;
 LXPattern[] patterns;
+Effects effects;
 MappingTool mappingTool;
 PandaDriver[] pandaBoards;
 MappingTool mappingTool;
 PandaDriver[] pandaBoards;
+PresetManager presetManager;
 MidiEngine midiEngine;
 MidiEngine midiEngine;
-color[] threadColors;
 
 // 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;
 PImage logo;
 LXPattern restoreToPattern = null;
 PImage logo;
+float[] hsb = new float[3];
 
 // Handles to UI objects
 UIContext[] overlays;
 
 // Handles to UI objects
 UIContext[] overlays;
@@ -69,6 +70,7 @@ UICrossfader uiCrossfader;
 UIMidi uiMidi;
 UIMapping uiMapping;
 UIDebugText uiDebugText;
 UIMidi uiMidi;
 UIMapping uiMapping;
 UIDebugText uiDebugText;
+UISpeed uiSpeed;
 
 // Camera variables
 float eyeR, eyeA, eyeX, eyeY, eyeZ, midX, midY, midZ;
 
 // Camera variables
 float eyeR, eyeA, eyeX, eyeY, eyeZ, midX, midY, midZ;
@@ -99,7 +101,19 @@ LXPattern[] _rightPatterns(GLucose glucose) {
   }
   return rightPatterns;
 }
   }
   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();
 
 void logTime(String evt) {
   int now = millis();
@@ -121,19 +135,22 @@ void setup() {
   glucose = new GLucose(this, buildModel());
   lx = glucose.lx;
   lx.enableKeyboardTempo();
   glucose = new GLucose(this, buildModel());
   lx = glucose.lx;
   lx.enableKeyboardTempo();
-  threadColors = new color[lx.total];
   logTime("Built GLucose engine");
   logTime("Built GLucose engine");
-  
+    
   // Set the patterns
   // Set the patterns
-  Engine engine = lx.engine;
+  LXEngine engine = lx.engine;
   engine.setPatterns(patterns = _leftPatterns(glucose));
   engine.addDeck(_rightPatterns(glucose));
   logTime("Built patterns");
   glucose.setTransitions(transitions(glucose));
   logTime("Built transitions");
   engine.setPatterns(patterns = _leftPatterns(glucose));
   engine.addDeck(_rightPatterns(glucose));
   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");
   // MIDI devices
   midiEngine = new MidiEngine();
   logTime("Setup MIDI devices");
@@ -151,13 +168,13 @@ void setup() {
   // Build overlay UI
   debugUI = new DebugUI(pandaMappings);
   overlays = new UIContext[] {
   // Build overlay UI
   debugUI = new DebugUI(pandaMappings);
   overlays = new UIContext[] {
-    uiPatternA = new UIPatternDeck(lx.engine.getDeck(0), "PATTERN A", 4, 4, 140, 324),
+    uiPatternA = new UIPatternDeck(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),
+    new UIPatternDeck(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),
     
     uiMidi = new UIMidi(midiEngine, width-144, 332, 140, 158),
     new UIOutput(width-144, 494, 140, 106),
     
@@ -196,6 +213,8 @@ void setup() {
  * Core render loop and drawing functionality.
  */
 void draw() {
  * Core render loop and drawing functionality.
  */
 void draw() {
+  long drawStart = System.nanoTime();
+  
   // Draws the simulation and the 2D UI overlay
   background(40);
 
   // Draws the simulation and the 2D UI overlay
   background(40);
 
@@ -204,15 +223,107 @@ void draw() {
   simulationColors = sendColors = glucose.getColors();
   String displayMode = uiCrossfader.getDisplayMode();
   if (displayMode == "A") {
   simulationColors = sendColors = glucose.getColors();
   String displayMode = uiCrossfader.getDisplayMode();
   if (displayMode == "A") {
-    simulationColors = lx.engine.getDeck(0).getColors();
+    simulationColors = lx.engine.getDeck(GLucose.LEFT_DECK).getColors();
   } else if (displayMode == "B") {
   } else if (displayMode == "B") {
-    simulationColors = lx.engine.getDeck(1).getColors();
+    simulationColors = lx.engine.getDeck(GLucose.RIGHT_DECK).getColors();
   }
   if (debugMode) {
     debugUI.maskColors(simulationColors);
     debugUI.maskColors(sendColors);
   }
 
   }
   if (debugMode) {
     debugUI.maskColors(simulationColors);
     debugUI.maskColors(sendColors);
   }
 
+  long simulationStart = System.nanoTime();
+  if (simulationOn) {
+    drawSimulation(simulationColors);
+  }
+  long simulationNanos = System.nanoTime() - simulationStart;
+  
+  // 2D Overlay UI
+  long uiStart = System.nanoTime();
+  drawUI();
+  long uiNanos = System.nanoTime() - uiStart;
+  
+  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));
+  }
+  long gammaNanos = System.nanoTime() - gammaStart;
+  
+  long sendStart = System.nanoTime();
+  for (PandaDriver p : pandaBoards) {
+    p.send(sendColors);
+  }
+  long sendNanos = System.nanoTime() - sendStart;
+  
+  long drawNanos = System.nanoTime() - drawStart;
+  
+  if (diagnosticsOn) {
+    drawDiagnostics(drawNanos, simulationNanos, uiNanos, gammaNanos, sendNanos);
+  }
+}
+
+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;
+  }
+  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;
+  }
+}
+
+void drawSimulation(color[] simulationColors) {
   camera(
     eyeX, eyeY, eyeZ,
     midX, midY, midZ,
   camera(
     eyeX, eyeY, eyeZ,
     midX, midY, midZ,
@@ -255,30 +366,11 @@ void draw() {
   noFill();
   strokeWeight(2);
   beginShape(POINTS);
   noFill();
   strokeWeight(2);
   beginShape(POINTS);
-  for (Point p : glucose.model.points) {
+  for (LXPoint p : glucose.model.points) {
     stroke(simulationColors[p.index]);
     vertex(p.x, p.y, p.z);
   }
   endShape();
     stroke(simulationColors[p.index]);
     vertex(p.x, p.y, p.z);
   }
   endShape();
-  
-  // 2D Overlay UI
-  drawUI();
-    
-  // Gamma correction here. Apply a cubic to the brightness
-  // for better representation of dynamic range
-  for (int i = 0; i < sendColors.length; ++i) {
-    float b = brightness(sendColors[i]) / 100.f;
-    sendColors[i] = color(
-      hue(sendColors[i]),
-      saturation(sendColors[i]),
-      (b*b*b) * 100.
-    );
-  }
-  
-  // TODO(mcslee): move into GLucose engine
-  for (PandaDriver p : pandaBoards) {
-    p.send(sendColors);
-  }
 }
 
 void drawBassBox(BassBox b, boolean hasSub) {
 }
 
 void drawBassBox(BassBox b, boolean hasSub) {
@@ -423,6 +515,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);
@@ -432,7 +562,7 @@ void keyPressed() {
       frameRate(++targetFramerate);
       break; 
     case 'b':
       frameRate(++targetFramerate);
       break; 
     case 'b':
-      EFF_boom.trigger();
+      effects.boom.trigger();
       break;    
     case 'd':
       if (!midiEngine.isQwertyEnabled()) {
       break;    
     case 'd':
       if (!midiEngine.isQwertyEnabled()) {
@@ -467,6 +597,16 @@ void keyPressed() {
         p.toggle();
       }
       break;
         p.toggle();
       }
       break;
+    case 'q':
+      if (!midiEngine.isQwertyEnabled()) {
+        diagnosticsOn = !diagnosticsOn;
+      }
+      break;
+    case 's':
+      if (!midiEngine.isQwertyEnabled()) {
+        simulationOn = !simulationOn;
+      }
+      break;
     case 'u':
       if (!midiEngine.isQwertyEnabled()) {
         uiOn = !uiOn;
     case 'u':
       if (!midiEngine.isQwertyEnabled()) {
         uiOn = !uiOn;