Implement midi UI properly, no manual redraw, have UIObject listen to model
authorMark Slee <mcslee@Mark-Slees-MacBook-Pro.local>
Sun, 22 Sep 2013 17:46:03 +0000 (10:46 -0700)
committerMark Slee <mcslee@Mark-Slees-MacBook-Pro.local>
Sun, 22 Sep 2013 17:46:03 +0000 (10:46 -0700)
_Internals.pde
_UIImplementation.pde

index 7f7e35fbe6c7ffb5326d6a466d1f0383a1b47fc7..b6d835ceb923b9c00becba042121ed217526b8ed 100644 (file)
@@ -48,8 +48,8 @@ HeronLX lx;
 LXPattern[] patterns;
 MappingTool mappingTool;
 PandaDriver[] pandaBoards;
-MidiListener midiQwertyKeys;
-MidiListener midiQwertyAPC;
+SCMidiInput midiQwertyKeys;
+SCMidiInput midiQwertyAPC;
 
 // Display configuration mode
 boolean mappingMode = false;
@@ -124,12 +124,12 @@ void setup() {
   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));
+  List<SCMidiInput> midiControllers = new ArrayList<SCMidiInput>();
+  midiControllers.add(midiQwertyKeys = new SCMidiInput(SCMidiInput.KEYS));
+  midiControllers.add(midiQwertyAPC = new SCMidiInput(SCMidiInput.APC));
   for (MidiInputDevice device : RWMidi.getInputDevices()) {
     boolean enableDevice = device.getName().contains("APC");
-    midiListeners.add(new MidiListener(device).setEnabled(enableDevice));
+    midiControllers.add(new SCMidiInput(device).setEnabled(enableDevice));
   }
   SCMidiDevices.initializeStandardDevices(glucose);
   logTime("Setup MIDI devices");
@@ -144,7 +144,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(midiControllers, width-144, 332, 140, 158),
     new UIOutput(width-144, 494, 140, 106),
     
     uiCrossfader = new UICrossfader(width/2-90, height-90, 180, 86),
@@ -176,7 +176,11 @@ void setup() {
   println("Hit the 'p' key to toggle Panda Board output");
 }
 
-public class MidiListener extends AbstractScrollItem {
+public interface SCMidiInputListener {
+  public void onEnabled(SCMidiInput controller, boolean enabled);
+}
+
+public class SCMidiInput extends AbstractScrollItem {
   
   public static final int MIDI = 0;
   public static final int KEYS = 1;
@@ -184,13 +188,9 @@ public class MidiListener extends AbstractScrollItem {
   
   private boolean enabled = false;
   private final String name;
-  
-  MidiListener(MidiInputDevice d) {
-    mode = MIDI;
-    d.createInput(this);
-    name = d.getName();
-  }
-  
+  private final int mode;
+  private int octaveShift = 0;
+    
   class NoteMeta {
     int channel;
     int number;
@@ -201,11 +201,26 @@ public class MidiListener extends AbstractScrollItem {
   }
   
   final Map<Character, NoteMeta> keyToNote = new HashMap<Character, NoteMeta>();
+    
+  final List<SCMidiInputListener> listeners = new ArrayList<SCMidiInputListener>();
   
-  private final int mode;
-  private int octaveShift = 0;
+  public SCMidiInput addListener(SCMidiInputListener l) {
+    listeners.add(l);
+    return this;
+  }
+
+  public SCMidiInput removeListener(SCMidiInputListener l) {
+    listeners.remove(l);
+    return this;
+  }
   
-  MidiListener(int mode) {
+  SCMidiInput(MidiInputDevice d) {
+    mode = MIDI;
+    d.createInput(this);
+    name = d.getName();
+  }
+  
+  SCMidiInput(int mode) {
     this.mode = mode;
     switch (mode) {
       case APC:
@@ -316,23 +331,30 @@ public class MidiListener extends AbstractScrollItem {
     setEnabled(!enabled);
   }
   
-  public MidiListener setEnabled(boolean enabled) {
+  public SCMidiInput setEnabled(boolean enabled) {
     if (enabled != this.enabled) {
       this.enabled = enabled;
-      if (uiMidi != null) uiMidi.redraw();
+      for (SCMidiInputListener l : listeners) {
+        l.onEnabled(this, enabled);
+      }
     }
     return this;
   }
   
   private SCPattern getFocusedPattern() {
-    return (SCPattern) uiMidi.getFocusedDeck().getActivePattern();
+    Engine.Deck focusedDeck = (uiMidi != null) ? uiMidi.getFocusedDeck() : lx.engine.getDefaultDeck();
+    return (SCPattern) focusedDeck.getActivePattern();
+  }
+  
+  private boolean logMidi() {
+    return (uiMidi != null) && uiMidi.logMidi();
   }
   
   void programChangeReceived(ProgramChange pc) {
     if (!enabled) {
       return;
     }
-    if (uiMidi.logMidi()) {
+    if (logMidi()) {
       println(getLabel() + " :: Program Change :: " + pc.getNumber());
     }
   }
@@ -341,7 +363,7 @@ public class MidiListener extends AbstractScrollItem {
     if (!enabled) {
       return;
     }
-    if (uiMidi.logMidi()) {
+    if (logMidi()) {
       println(getLabel() + " :: Controller :: " + cc.getCC() + ":" + cc.getValue());
     }
     getFocusedPattern().controllerChangeReceived(cc);
@@ -351,7 +373,7 @@ public class MidiListener extends AbstractScrollItem {
     if (!enabled) {
       return;
     }
-    if (uiMidi.logMidi()) {
+    if (logMidi()) {
       println(getLabel() + " :: Note On  :: " + note.getChannel() + ":" + note.getPitch() + ":" + note.getVelocity());
     }
     getFocusedPattern().noteOnReceived(note);
@@ -361,7 +383,7 @@ public class MidiListener extends AbstractScrollItem {
     if (!enabled) {
       return;
     }
-    if (uiMidi.logMidi()) {
+    if (logMidi()) {
       println(getLabel() + " :: Note Off :: " + note.getChannel() + ":" + note.getPitch() + ":" + note.getVelocity());
     }
     getFocusedPattern().noteOffReceived(note);
index e72d76b598976e164a04c78a0e9cb1fe7bd48627..a12c189219ba646d563f459608a508d7519a4209 100644 (file)
@@ -483,16 +483,27 @@ class UIMidi extends UIWindow {
   private final UIToggleSet deckMode;
   private final UIButton logMode;
   
-  UIMidi(List<MidiListener> midiListeners, float x, float y, float w, float h) {
+  UIMidi(List<SCMidiInput> midiControllers, float x, float y, float w, float h) {
     super("MIDI", x, y, w, h);
     // Processing compiler doesn't seem to get that list of class objects also conform to interface
     List<ScrollItem> scrollItems = new ArrayList<ScrollItem>();
-    for (MidiListener ml : midiListeners) {
-      scrollItems.add(ml);
+    for (SCMidiInput mc : midiControllers) {
+      scrollItems.add(mc);
     }
-    new UIScrollList(1, titleHeight, w-2, 100).setItems(scrollItems).addToContainer(this);
+    final UIScrollList scrollList;
+    (scrollList = new UIScrollList(1, titleHeight, w-2, 100)).setItems(scrollItems).addToContainer(this);
     (deckMode = new UIToggleSet(4, 130, 90, 20)).setOptions(new String[] { "A", "B" }).addToContainer(this);
     (logMode = new UIButton(98, 130, w-103, 20)).setLabel("LOG").addToContainer(this);
+    
+    SCMidiInputListener listener = new SCMidiInputListener() {
+      public void onEnabled(SCMidiInput controller, boolean enabled) {
+        scrollList.redraw();
+      }
+    };
+    for (SCMidiInput mc : midiControllers) {
+      mc.addListener(listener);
+    }
+
   }
   
   public boolean logMidi() {