Add generic grid API
authorMark Slee <mcslee@Mark-Slees-MacBook-Pro.local>
Thu, 17 Oct 2013 23:48:43 +0000 (16:48 -0700)
committerMark Slee <mcslee@Mark-Slees-MacBook-Pro.local>
Thu, 17 Oct 2013 23:48:43 +0000 (16:48 -0700)
MarkSlee.pde
_Internals.pde
_MIDI.pde
code/GLucose.jar
code/HeronLX.jar

index b90a822b701809038463308727de8990a506eae7..649d61cc4594c71e29e1960704854bb3241e3363 100644 (file)
@@ -54,7 +54,7 @@ class MidiMusic extends SCPattern {
     }
   }
   
-  public synchronized boolean noteOnReceived(Note note) {
+  public synchronized boolean noteOn(Note note) {
     if (note.getChannel() == 0) {
       for (LightUp light : allLights) {
         if (light.isAvailable()) {
@@ -74,7 +74,7 @@ class MidiMusic extends SCPattern {
     return true;
   }
   
-  public synchronized boolean noteOffReceived(Note note) {
+  public synchronized boolean noteOff(Note note) {
     if (note.getChannel() == 0) {
       LightUp light = lightMap.get(note.getPitch());
       if (light != null) {
@@ -118,6 +118,7 @@ class Pulley extends SCPattern {
     addParameter(sz);
     addParameter(beatAmount);
     trigger();
+
   }
   
   private void trigger() {
@@ -138,6 +139,7 @@ class Pulley extends SCPattern {
     if (reset.click()) {
       trigger();
     }
+        
     if (isRising) {
       // Fucking A, had to comment this all out because of that bizarre
       // Processing bug where some simple loop takes an absurd amount of
@@ -169,6 +171,15 @@ class Pulley extends SCPattern {
         }
       }
     }
+
+    // A little silliness to test the grid API    
+    for (int i = 0; i < 7; ++i) {
+      for (int j = 0; j < 8; ++j) {
+        int gi = (int) constrain(j * NUM_DIVISIONS / 8, 0, NUM_DIVISIONS-1);
+        float b = 1 - 4.*abs((6-i)/7. - gravity[gi].getValuef() / model.yMax);
+        midiEngine.grid.setState(i, j, (b < 0) ? 0 : 1);
+      }
+    }
     
     float fPos = 1 - lx.tempo.rampf();
     if (fPos < .2) {
@@ -391,7 +402,7 @@ class BouncyBalls extends SCPattern {
     }
   }
   
-  public boolean noteOnReceived(Note note) {
+  public boolean noteOn(Note note) {
     int pitch = (note.getPitch() + note.getChannel()) % NUM_BALLS;
     balls[pitch].bounce(note.getVelocity());
     return true;
@@ -821,13 +832,13 @@ public class PianoKeyPattern extends SCPattern {
     return base[index % base.length];
   }
     
-  public boolean noteOnReceived(Note note) {
+  public boolean noteOn(Note note) {
     LinearEnvelope env = getEnvelope(note.getPitch());
     env.setEndVal(min(1, env.getValuef() + (note.getVelocity() / 127.)), getAttackTime()).start();
     return true;
   }
   
-  public boolean noteOffReceived(Note note) {
+  public boolean noteOff(Note note) {
     getEnvelope(note.getPitch()).setEndVal(0, getReleaseTime()).start();
     return true;
   }
index e568c4ea8eadea0cde0ae11615cfb86dc3813a23..3aa9f3a209077f8a1bd82cf164e3c789958e34d5 100644 (file)
@@ -52,6 +52,7 @@ LXPattern[] patterns;
 MappingTool mappingTool;
 PandaDriver[] pandaBoards;
 MidiEngine midiEngine;
+GridController gridController;
 
 // Display configuration mode
 boolean mappingMode = false;
@@ -99,7 +100,6 @@ LXPattern[] _rightPatterns(GLucose glucose) {
   }
   return rightPatterns;
 }
-  
 
 void logTime(String evt) {
   int now = millis();
index 323efeeec641c8ad7412d89d68b1d19b0ec543e9..d6e90bfadd8134edb9c6574dfee6896f67aaf89a 100644 (file)
--- a/_MIDI.pde
+++ b/_MIDI.pde
@@ -22,6 +22,7 @@ interface MidiEngineListener {
 
 class MidiEngine {
 
+  public final GridController grid;
   private final List<MidiEngineListener> listeners = new ArrayList<MidiEngineListener>();
   private final List<SCMidiInput> midiControllers = new ArrayList<SCMidiInput>();
 
@@ -41,17 +42,17 @@ class MidiEngine {
   private int activeDeckIndex = 0;
 
   public MidiEngine() {
-
-    midiControllers.add(midiQwertyKeys = new SCMidiInput(SCMidiInput.KEYS));
-    midiControllers.add(midiQwertyAPC = new SCMidiInput(SCMidiInput.APC));
+    grid = new GridController(this);
+    midiControllers.add(midiQwertyKeys = new SCMidiInput(this, SCMidiInput.KEYS));
+    midiControllers.add(midiQwertyAPC = new SCMidiInput(this, SCMidiInput.APC));
     for (MidiInputDevice device : RWMidi.getInputDevices()) {
       if (device.getName().contains("APC")) {
-        midiControllers.add(new APC40MidiInput(device).setEnabled(true));
+        midiControllers.add(new APC40MidiInput(this, device).setEnabled(true));
       } else if (device.getName().contains("SLIDER/KNOB KORG")) {
-        midiControllers.add(new KorgNanoKontrolMidiInput(device).setEnabled(true));
+        midiControllers.add(new KorgNanoKontrolMidiInput(this, device).setEnabled(true));
       } else {
         boolean enabled = device.getName().contains("KEYBOARD KORG") || device.getName().contains("Bus 1 Apple");
-        midiControllers.add(new SCMidiInput(device).setEnabled(enabled));
+        midiControllers.add(new SCMidiInput(this, device).setEnabled(enabled));
       }
     }
     for (MidiOutputDevice device : RWMidi.getOutputDevices()) {
@@ -65,6 +66,14 @@ class MidiEngine {
     return this.midiControllers;
   }
 
+  public Engine.Deck getFocusedDeck() {
+    return lx.engine.getDeck(activeDeckIndex);
+  }
+
+  public SCPattern getFocusedPattern() {
+    return (SCPattern) getFocusedDeck().getActivePattern();
+  }
+
   public MidiEngine setFocusedDeck(int deckIndex) {
     if (this.activeDeckIndex != deckIndex) {
       this.activeDeckIndex = deckIndex;
@@ -75,10 +84,6 @@ class MidiEngine {
     return this;
   }
 
-  public Engine.Deck getFocusedDeck() {
-    return lx.engine.getDeck(activeDeckIndex);
-  }
-
   public boolean isQwertyEnabled() {
     return midiQwertyKeys.isEnabled() || midiQwertyAPC.isEnabled();
   }
@@ -99,6 +104,8 @@ public class SCMidiInput extends AbstractScrollItem {
   private final int mode;
   private int octaveShift = 0;
 
+  protected final MidiEngine midiEngine;
+
   class NoteMeta {
     int channel;
     int number;
@@ -122,13 +129,15 @@ public class SCMidiInput extends AbstractScrollItem {
     return this;
   }
 
-  SCMidiInput(MidiInputDevice d) {
+  SCMidiInput(MidiEngine midiEngine, MidiInputDevice d) {
+    this.midiEngine = midiEngine;
     mode = MIDI;
     d.createInput(this);
     name = d.getName().replace("Unknown vendor","");
   }
 
-  SCMidiInput(int mode) {
+  SCMidiInput(MidiEngine midiEngine, int mode) {
+    this.midiEngine = midiEngine;
     this.mode = mode;
     switch (mode) {
     case APC:
@@ -249,10 +258,6 @@ public class SCMidiInput extends AbstractScrollItem {
     return this;
   }
 
-  protected SCPattern getFocusedPattern() {
-    return (SCPattern) midiEngine.getFocusedDeck().getActivePattern();
-  }
-
   private boolean logMidi() {
     return (uiMidi != null) && uiMidi.logMidi();
   }
@@ -272,10 +277,12 @@ public class SCMidiInput extends AbstractScrollItem {
       return;
     }
     if (logMidi()) {
-      println(getLabel() + " :: Controller :: " + cc.getCC() + ":" + cc.getValue());
+      println(getLabel() + " :: Controller :: " + cc.getChannel() + " :: " + cc.getCC() + ":" + cc.getValue());
     }
-    if (!getFocusedPattern().controllerChangeReceived(cc)) {
-      handleControllerChange(cc);
+    if (!handleGridControllerChange(cc)) {
+      if (!midiEngine.getFocusedPattern().controllerChange(cc)) {
+        handleControllerChange(cc);
+      }
     }
   }
 
@@ -286,8 +293,10 @@ public class SCMidiInput extends AbstractScrollItem {
     if (logMidi()) {
       println(getLabel() + " :: Note On  :: " + note.getChannel() + ":" + note.getPitch() + ":" + note.getVelocity());
     }
-    if (!getFocusedPattern().noteOnReceived(note)) {
-      handleNoteOn(note);
+    if (!handleGridNoteOn(note)) {
+      if (!midiEngine.getFocusedPattern().noteOn(note)) {
+        handleNoteOn(note);
+      }
     }
   }
 
@@ -298,20 +307,21 @@ public class SCMidiInput extends AbstractScrollItem {
     if (logMidi()) {
       println(getLabel() + " :: Note Off :: " + note.getChannel() + ":" + note.getPitch() + ":" + note.getVelocity());
     }
-    if (!getFocusedPattern().noteOffReceived(note)) {
-      handleNoteOff(note);
+    if (!handleGridNoteOff(note)) {
+      if (!midiEngine.getFocusedPattern().noteOff(note)) {
+        handleNoteOff(note);
+      }
     }
   }
 
   // Subclasses may implement these to map top-level functionality
-  protected void handleProgramChange(ProgramChange pc) {
-  }
-  protected void handleControllerChange(rwmidi.Controller cc) {
-  }
-  protected void handleNoteOn(Note note) {
-  }
-  protected void handleNoteOff(Note note) {
-  }
+  protected boolean handleGridNoteOn(Note note) { return false; }
+  protected boolean handleGridNoteOff(Note note) { return false; }
+  protected boolean handleGridControllerChange(rwmidi.Controller cc) { return false; }
+  protected void handleProgramChange(ProgramChange pc) {}
+  protected void handleControllerChange(rwmidi.Controller cc) {}
+  protected void handleNoteOn(Note note) {}
+  protected void handleNoteOff(Note note) {}
 }
 
 public class APC40MidiInput extends SCMidiInput {
@@ -319,8 +329,42 @@ public class APC40MidiInput extends SCMidiInput {
   private boolean shiftOn = false;
   private LXEffect releaseEffect = null;
   
-  APC40MidiInput(MidiInputDevice d) {
-    super(d);
+  APC40MidiInput(MidiEngine midiEngine, MidiInputDevice d) {
+    super(midiEngine, d);
+  }
+
+  private class GridPosition {
+    public final int row, col;
+    GridPosition(int r, int c) {
+      row = r;
+      col = c;
+    }
+  }
+  
+  private GridPosition getGridPosition(Note note) {
+    int channel = note.getChannel();
+    int pitch = note.getPitch();
+    if (channel < 8) {
+      if (pitch >= 53 && pitch <=57) return new GridPosition(pitch-53, channel);
+      else if (pitch == 52) return new GridPosition(5, channel);
+    }
+    return null;
+  }
+
+  protected boolean handleGridNoteOn(Note note) {
+    GridPosition p = getGridPosition(note);
+    if (p != null) {
+      return midiEngine.grid.gridPressed(p.row, p.col);
+    }
+    return false;
+  }
+
+  protected boolean handleGridNoteOff(Note note) {
+    GridPosition p = getGridPosition(note);
+    if (p != null) {
+      return midiEngine.grid.gridReleased(p.row, p.col);
+    }
+    return false;
   }
 
   protected void handleControllerChange(rwmidi.Controller cc) {
@@ -339,7 +383,7 @@ public class APC40MidiInput extends SCMidiInput {
       parameterIndex = 8 + (number-16);
     }
     if (parameterIndex >= 0) {
-      List<LXParameter> parameters = getFocusedPattern().getParameters();
+      List<LXParameter> parameters = midiEngine.getFocusedPattern().getParameters();
       if (parameterIndex < parameters.size()) {
         parameters.get(parameterIndex).setValue(cc.getValue() / 127.);
       }
@@ -465,15 +509,15 @@ public class APC40MidiInput extends SCMidiInput {
 
 class KorgNanoKontrolMidiInput extends SCMidiInput {
   
-  KorgNanoKontrolMidiInput(MidiInputDevice d) {
-    super(d);
+  KorgNanoKontrolMidiInput(MidiEngine midiEngine, MidiInputDevice d) {
+    super(midiEngine, d);
   }
   
   protected void handleControllerChange(rwmidi.Controller cc) {
     int number = cc.getCC();
     if (number >= 16 && number <= 23) {
       int parameterIndex = number - 16;
-      List<LXParameter> parameters = getFocusedPattern().getParameters();
+      List<LXParameter> parameters = midiEngine.getFocusedPattern().getParameters();
       if (parameterIndex < parameters.size()) {
         parameters.get(parameterIndex).setValue(cc.getValue() / 127.);
       }
@@ -502,7 +546,7 @@ class KorgNanoKontrolMidiInput extends SCMidiInput {
   }
 }
 
-class APC40MidiOutput implements LXParameter.Listener {
+class APC40MidiOutput implements LXParameter.Listener, GridOutput {
   
   private final MidiEngine midiEngine;
   private final MidiOutput output;
@@ -531,6 +575,7 @@ class APC40MidiOutput implements LXParameter.Listener {
       d.addListener(deckListener);
     }
     resetParameters();
+    midiEngine.grid.addOutput(this);
   }
 
   private void resetParameters() {
@@ -557,6 +602,11 @@ class APC40MidiOutput implements LXParameter.Listener {
     while (i < 12) {
       sendKnob(i++, 0);
     }
+    for (int row = 0; row < 7; ++row) {
+      for (int col = 0; col < 8; ++col) {
+        setGridState(row, col, 0);
+      }
+    }
   }
   
   private void resetEffectParameters() {
@@ -610,4 +660,53 @@ class APC40MidiOutput implements LXParameter.Listener {
       ++i;
     }
   }
+  
+  public void setGridState(int row, int col, int state) {
+    if (col < 8) {
+      if (row < 5) output.sendNoteOn(col, 53+row, state);
+      else if (row == 6) output.sendNoteOn(col, 52, state);
+    }
+  }
+}
+
+interface GridOutput {
+  public static final int OFF = 0;
+  public static final int GREEN = 1;
+  public static final int GREEN_BLINK = 2;
+  public static final int RED = 3;
+  public static final int RED_BLINK = 4;
+  public static final int YELLOW = 5;
+  public static final int YELLOW_BLINK = 6;
+  public static final int ON = 127;
+  
+  public void setGridState(int row, int col, int state);
 }
+
+class GridController {
+  private final List<GridOutput> outputs = new ArrayList<GridOutput>();
+  
+  private final MidiEngine midiEngine;
+  
+  GridController(MidiEngine midiEngine) {
+    this.midiEngine = midiEngine;
+  }
+  
+  public void addOutput(GridOutput output) {
+    outputs.add(output);
+  }
+  
+  public boolean gridPressed(int row, int col) {
+    return midiEngine.getFocusedPattern().gridPressed(row, col);
+  }
+  
+  public boolean gridReleased(int row, int col) {
+    return midiEngine.getFocusedPattern().gridReleased(row, col);
+  }
+  
+  public void setState(int row, int col, int state) {
+    for (GridOutput g : outputs) {
+      g.setGridState(row, col, state);
+    }
+  }
+}
+
index 91dd10571d1b469e488b39317fbc639d135e1c6c..4bbff0b4aee0933ebe94c443af570c4963d62086 100755 (executable)
Binary files a/code/GLucose.jar and b/code/GLucose.jar differ
index 6069116fa5100282693f58bbf58e7c6134982384..fa0173929c7238682d054769af4a02c4d73e15b1 100755 (executable)
Binary files a/code/HeronLX.jar and b/code/HeronLX.jar differ