cubecurl
[SugarCubes.git] / _Internals.pde
index f872d9b7a733086578108e39160096e6da27b36d..d24f13b3910c364055c769102ad0f5ddfef9aa86 100644 (file)
@@ -39,6 +39,9 @@ final float TRAILER_WIDTH = 240;
 final float TRAILER_DEPTH = 97;
 final float TRAILER_HEIGHT = 33;
 
+final int MaxCubeHeight = 7;
+final int NumBackTowers = 9;
+
 int targetFramerate = 60;
 int startMillis, lastMillis;
 
@@ -48,8 +51,7 @@ HeronLX lx;
 LXPattern[] patterns;
 MappingTool mappingTool;
 PandaDriver[] pandaBoards;
-MidiListener midiQwertyKeys;
-MidiListener midiQwertyAPC;
+MidiEngine midiEngine;
 
 // Display configuration mode
 boolean mappingMode = false;
@@ -73,14 +75,31 @@ float eyeR, eyeA, eyeX, eyeY, eyeZ, midX, midY, midZ;
 /**
  * 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) {
-    p.setTransition(new DissolveTransition(glucose.lx).setDuration(1000));
+    p.setTransition(_transition(glucose));
   }
   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;
+}
+  
+
 void logTime(String evt) {
   int now = millis();
   println(evt + ": " + (now - lastMillis) + "ms");
@@ -103,10 +122,14 @@ void setup() {
   lx.enableKeyboardTempo();
   logTime("Built GLucose engine");
   
+  // MIDI devices
+  midiEngine = new MidiEngine();
+  logTime("Setup MIDI devices");
+
   // Set the patterns
   Engine engine = lx.engine;
-  engine.setPatterns(patterns = _patterns(glucose));
-  engine.addDeck(_patterns(glucose));
+  engine.setPatterns(patterns = _leftPatterns(glucose));
+  engine.addDeck(_rightPatterns(glucose));
   logTime("Built patterns");
   glucose.setTransitions(transitions(glucose));
   logTime("Built transitions");
@@ -123,17 +146,6 @@ void setup() {
   mappingTool = new MappingTool(glucose, pandaMappings);
   logTime("Built PandaDriver");
 
-  // MIDI devices
-  List<MidiListener> midiListeners = new ArrayList<MidiListener>();
-  midiListeners.add(midiQwertyKeys = new MidiListener(MidiListener.KEYS));
-  midiListeners.add(midiQwertyAPC = new MidiListener(MidiListener.APC));
-  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);
   overlays = new UIContext[] {
@@ -144,7 +156,7 @@ void setup() {
     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, 158),
+    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),
@@ -167,6 +179,8 @@ void setup() {
   eyeY = midY + 70;
   eyeX = midX + eyeR*sin(eyeA);
   eyeZ = midZ + eyeR*cos(eyeA);
+  
+  // Add mouse scrolling event support
   addMouseWheelListener(new java.awt.event.MouseWheelListener() { 
     public void mouseWheelMoved(java.awt.event.MouseWheelEvent mwe) { 
       mouseWheel(mwe.getWheelRotation());
@@ -176,199 +190,6 @@ void setup() {
   println("Hit the 'p' key to toggle Panda Board output");
 }
 
-public class MidiListener extends AbstractScrollItem {
-  
-  public static final int MIDI = 0;
-  public static final int KEYS = 1;
-  public static final int APC = 2;
-  
-  private boolean enabled = false;
-  private final String name;
-  
-  MidiListener(MidiInputDevice d) {
-    mode = MIDI;
-    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>();
-  
-  private final int mode;
-  private int octaveShift = 0;
-  
-  MidiListener(int mode) {
-    this.mode = mode;
-    switch (mode) {
-      case APC:
-        name = "QWERTY (APC Mode)";
-        mapAPC();
-        break;
-      default:
-      case KEYS:
-        name = "QWERTY (Key Mode)";
-        mapKeys();
-        break;
-    }
-  }
-  
-  private void mapAPC() {
-    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);
-  }
-  
-  private void mapKeys() {
-    int note = 48;
-    mapNote('a', 1, note++);
-    mapNote('w', 1, note++);
-    mapNote('s', 1, note++);
-    mapNote('e', 1, note++);
-    mapNote('d', 1, note++);
-    mapNote('f', 1, note++);
-    mapNote('t', 1, note++);
-    mapNote('g', 1, note++);
-    mapNote('y', 1, note++);
-    mapNote('h', 1, note++);
-    mapNote('u', 1, note++);
-    mapNote('j', 1, note++);
-    mapNote('k', 1, note++);
-    mapNote('o', 1, note++);
-    mapNote('l', 1, note++);
-    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) {
-    if (!enabled) {
-      return;
-    }
-    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 + octaveShift*12, 127));
-          break;
-        case KeyEvent.KEY_RELEASED:
-          noteOffReceived(new Note(Note.NOTE_OFF, nm.channel, nm.number + octaveShift*12, 0));
-          break;
-      }
-    }
-    if ((mode == KEYS) && (e.getID() == KeyEvent.KEY_PRESSED)) {
-      switch (c) {
-        case 'z':
-          octaveShift = constrain(octaveShift-1, -4, 4);
-          break;
-        case 'x':
-          octaveShift = constrain(octaveShift+1, -4, 4);
-          break;
-      }
-    }
-  }
-  
-  public boolean isEnabled() {
-    return enabled;
-  }
-  
-  public boolean isSelected() {
-    return enabled;
-  }
-  
-  public void onMousePressed() {
-    setEnabled(!enabled);
-  }
-  
-  public MidiListener setEnabled(boolean enabled) {
-    if (enabled != this.enabled) {
-      this.enabled = enabled;
-      uiMidi.redraw();
-    }
-    return this;
-  }
-  
-  private SCPattern getFocusedPattern() {
-    return (SCPattern) uiMidi.getFocusedDeck().getActivePattern();
-  }
-  
-  void programChangeReceived(ProgramChange pc) {
-    if (!enabled) {
-      return;
-    }
-    if (uiMidi.logMidi()) {
-      println(getLabel() + " :: Program Change :: " + pc.getNumber());
-    }
-  }
-  
-  void controllerChangeReceived(rwmidi.Controller cc) {
-    if (!enabled) {
-      return;
-    }
-    if (uiMidi.logMidi()) {
-      println(getLabel() + " :: Controller :: " + cc.getCC() + ":" + cc.getValue());
-    }
-    getFocusedPattern().controllerChangeReceived(cc);
-  }
-
-  void noteOnReceived(Note note) {
-    if (!enabled) {
-      return;
-    }
-    if (uiMidi.logMidi()) {
-      println(getLabel() + " :: Note On  :: " + note.getChannel() + ":" + note.getPitch() + ":" + note.getVelocity());
-    }
-    getFocusedPattern().noteOnReceived(note);
-  }
-
-  void noteOffReceived(Note note) {
-    if (!enabled) {
-      return;
-    }
-    if (uiMidi.logMidi()) {
-      println(getLabel() + " :: Note Off :: " + note.getChannel() + ":" + note.getPitch() + ":" + note.getVelocity());
-    }
-    getFocusedPattern().noteOffReceived(note);
-  }
-
-}
-
 /**
  * Core render loop and drawing functionality.
  */
@@ -416,10 +237,12 @@ void draw() {
   popMatrix();
   
   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);
   }
@@ -427,13 +250,9 @@ void draw() {
   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 (Point p : glucose.model.points) {
+    stroke(colors[p.index]);
+    vertex(p.fx, p.fy, p.fz);
   }
   endShape();
   
@@ -443,35 +262,38 @@ void draw() {
   // Send output colors
   color[] sendColors = glucose.getColors();
   if (debugMode) {
-    debugUI.maskColors(colors);
+    debugUI.maskColors(sendColors);
   }
   
   // 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]),
+  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(colors);
+    p.send(sendColors);
   }
 }
 
-void drawBassBox(BassBox b) {
+void drawBassBox(BassBox b, boolean hasSub) {
+  
   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);
@@ -609,15 +431,18 @@ void keyPressed() {
     case '=':
     case '+':
       frameRate(++targetFramerate);
-      break;      
+      break; 
+    case 'b':
+      EFF_boom.trigger();
+      break;    
     case 'd':
-      if (!midiQwertyAPC.isEnabled() && !midiQwertyKeys.isEnabled()) {
+      if (!midiEngine.isQwertyEnabled()) {
         debugMode = !debugMode;
         println("Debug output: " + (debugMode ? "ON" : "OFF"));
       }
       break;
     case 'm':
-      if (!midiQwertyAPC.isEnabled() && !midiQwertyKeys.isEnabled()) {
+      if (!midiEngine.isQwertyEnabled()) {
         mappingMode = !mappingMode;
         uiPatternA.setVisible(!mappingMode);
         uiMapping.setVisible(mappingMode);
@@ -639,7 +464,7 @@ void keyPressed() {
       }
       break;
     case 'u':
-      if (!midiQwertyAPC.isEnabled() && !midiQwertyKeys.isEnabled()) {
+      if (!midiEngine.isQwertyEnabled()) {
         uiOn = !uiOn;
       }
       break;
@@ -686,8 +511,8 @@ void mouseReleased() {
     context.mouseReleased(mouseX, mouseY);
   }
 }
-void mouseWheel(int delta) {
+
+void mouseWheel(int delta) {delta*=20;
   boolean wheeled = false;
   for (UIContext context : overlays) {
     wheeled |= context.mouseWheel(mouseX, mouseY, delta);