Refactor MIDI stuff so deck focusing is listenable and controllable
authorMark Slee <mcslee@Mark-Slees-MacBook-Pro.local>
Wed, 25 Sep 2013 00:28:53 +0000 (17:28 -0700)
committerMark Slee <mcslee@Mark-Slees-MacBook-Pro.local>
Wed, 25 Sep 2013 00:57:56 +0000 (17:57 -0700)
DanUtil.pde
MarkSlee.pde
_Internals.pde
_MIDI.pde [new file with mode: 0644]
_UIImplementation.pde
code/GLucose.jar

index d3f9ac05186e314f3a302f229ac90d65f736a7fa..c27eaed0adacc2c26cd541c499f0d2d7899b5911 100644 (file)
@@ -121,7 +121,6 @@ public class DGlobals {
 
        void    controllerChangeReceived(rwmidi.Controller cc) {
                if (cc.getCC() == 7 && btwn(cc.getChannel(),0,7)) { Sliders[cc.getChannel()] = 1.*cc.getValue()/127.; }
-
                else if (cc.getCC() == 15 && cc.getChannel() == 0) {
                        lx.engine.getDeck(1).getCrossfader().setValue( 1.*cc.getValue()/127.);
                }
@@ -157,7 +156,6 @@ public class DGlobals {
        
        double Tap1 = 0;
        double getNow() { return millis() + 1000*second() + 60*1000*minute() + 3600*1000*hour(); }
-
        void noteOffReceived(Note note) {
                if (CurPat == null) return;
                int row = DG.mapRow(note.getPitch()), col = note.getChannel();
index 7738419a68880123887e8b12336853ba005baa43..3a9b530cc4d44ddef86afe6c4e9b6c311a1fe232 100644 (file)
@@ -421,13 +421,15 @@ public class PianoKeyPattern extends SCPattern {
     return base[index % base.length];
   }
     
-  public void noteOnReceived(Note note) {
+  public boolean noteOnReceived(Note note) {
     LinearEnvelope env = getEnvelope(note.getPitch());
     env.setEndVal(min(1, env.getValuef() + (note.getVelocity() / 127.)), getAttackTime()).start();
+    return true;
   }
   
-  public void noteOffReceived(Note note) {
+  public boolean noteOffReceived(Note note) {
     getEnvelope(note.getPitch()).setEndVal(0, getReleaseTime()).start();
+    return true;
   }
   
   public void run(double deltaMs) {
index 19b4ed6cf682c47e1293a6925d0a28335f1c10b8..60a5f3296e11abc121aec4607abd44edb95832a8 100644 (file)
@@ -48,8 +48,7 @@ HeronLX lx;
 LXPattern[] patterns;
 MappingTool mappingTool;
 PandaDriver[] pandaBoards;
-SCMidiInput midiQwertyKeys;
-SCMidiInput midiQwertyAPC;
+MidiEngine midiEngine;
 
 // Display configuration mode
 boolean mappingMode = false;
@@ -124,14 +123,7 @@ void setup() {
   logTime("Built PandaDriver");
 
   // MIDI devices
-  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");
-    midiControllers.add(new SCMidiInput(device).setEnabled(enableDevice));
-  }
-  SCMidiDevices.initializeStandardDevices(glucose);
+  midiEngine = new MidiEngine();
   logTime("Setup MIDI devices");
 
   // Build overlay UI
@@ -144,7 +136,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(midiControllers, 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 +159,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,221 +170,6 @@ void setup() {
   println("Hit the 'p' key to toggle Panda Board output");
 }
 
-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;
-  public static final int APC = 2;
-  
-  private boolean enabled = false;
-  private final String name;
-  private final int mode;
-  private int octaveShift = 0;
-    
-  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>();
-    
-  final List<SCMidiInputListener> listeners = new ArrayList<SCMidiInputListener>();
-  
-  public SCMidiInput addListener(SCMidiInputListener l) {
-    listeners.add(l);
-    return this;
-  }
-
-  public SCMidiInput removeListener(SCMidiInputListener l) {
-    listeners.remove(l);
-    return this;
-  }
-  
-  SCMidiInput(MidiInputDevice d) {
-    mode = MIDI;
-    d.createInput(this);
-    name = d.getName().replace("Unknown vendor","");
-  }
-  
-  SCMidiInput(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 SCMidiInput setEnabled(boolean enabled) {
-    if (enabled != this.enabled) {
-      this.enabled = enabled;
-      for (SCMidiInputListener l : listeners) {
-        l.onEnabled(this, enabled);
-      }
-    }
-    return this;
-  }
-  
-  private SCPattern getFocusedPattern() {
-    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 (logMidi()) {
-      println(getLabel() + " :: Program Change :: " + pc.getNumber());
-    }
-  }
-  
-  void controllerChangeReceived(rwmidi.Controller cc) {
-    if (!enabled) {
-      return;
-    }
-    if (logMidi()) {
-      println(getLabel() + " :: Controller :: " + cc.getCC() + ":" + cc.getValue());
-    }
-    getFocusedPattern().controllerChangeReceived(cc);
-  }
-
-  void noteOnReceived(Note note) {
-    if (!enabled) {
-      return;
-    }
-    if (logMidi()) {
-      println(getLabel() + " :: Note On  :: " + note.getChannel() + ":" + note.getPitch() + ":" + note.getVelocity());
-    }
-    getFocusedPattern().noteOnReceived(note);
-  }
-
-  void noteOffReceived(Note note) {
-    if (!enabled) {
-      return;
-    }
-    if (logMidi()) {
-      println(getLabel() + " :: Note Off :: " + note.getChannel() + ":" + note.getPitch() + ":" + note.getVelocity());
-    }
-    getFocusedPattern().noteOffReceived(note);
-  }
-
-}
-
 /**
  * Core render loop and drawing functionality.
  */
@@ -633,13 +412,13 @@ void keyPressed() {
       frameRate(++targetFramerate);
       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);
@@ -661,7 +440,7 @@ void keyPressed() {
       }
       break;
     case 'u':
-      if (!midiQwertyAPC.isEnabled() && !midiQwertyKeys.isEnabled()) {
+      if (!midiEngine.isQwertyEnabled()) {
         uiOn = !uiOn;
       }
       break;
diff --git a/_MIDI.pde b/_MIDI.pde
new file mode 100644 (file)
index 0000000..4b3f313
--- /dev/null
+++ b/_MIDI.pde
@@ -0,0 +1,459 @@
+/**
+ *     DOUBLE BLACK DIAMOND        DOUBLE BLACK DIAMOND
+ *
+ *         //\\   //\\                 //\\   //\\  
+ *        ///\\\ ///\\\               ///\\\ ///\\\
+ *        \\\/// \\\///               \\\/// \\\///
+ *         \\//   \\//                 \\//   \\//
+ *
+ *        EXPERTS ONLY!!              EXPERTS ONLY!!
+ *
+ * This file defines the MIDI mapping interfaces. This shouldn't
+ * need editing unless you're adding top level support for a
+ * specific MIDI device of some sort. Generally, all MIDI devices
+ * will just work with the default configuration, and you can
+ * set your SCPattern class to respond to the controllers that you
+ * care about.
+ */
+
+interface MidiEngineListener {
+  public void onFocusedDeck(int deckIndex);
+}
+
+class MidiEngine {
+
+  private final List<MidiEngineListener> listeners = new ArrayList<MidiEngineListener>();
+  private final List<SCMidiInput> midiControllers = new ArrayList<SCMidiInput>();
+
+  public MidiEngine addListener(MidiEngineListener l) {
+    listeners.add(l);
+    return this;
+  }
+
+  public MidiEngine removeListener(MidiEngineListener l) {
+    listeners.remove(l);
+    return this;
+  }
+
+  private SCMidiInput midiQwertyKeys;
+  private SCMidiInput midiQwertyAPC;
+
+  private int activeDeckIndex = 0;
+
+  public MidiEngine() {
+
+    midiControllers.add(midiQwertyKeys = new SCMidiInput(SCMidiInput.KEYS));
+    midiControllers.add(midiQwertyAPC = new SCMidiInput(SCMidiInput.APC));
+    for (MidiInputDevice device : RWMidi.getInputDevices()) {
+      if (device.getName().contains("APC")) {
+        midiControllers.add(new APC40MidiInput(device).setEnabled(true));
+      } else if (device.getName().contains("SLIDER/KNOB KORG")) {
+        midiControllers.add(new KorgNanoKontrolMidiInput(device).setEnabled(true));
+      } else {
+        midiControllers.add(new SCMidiInput(device));
+      }
+    }
+  }
+
+  public List<SCMidiInput> getControllers() {
+    return this.midiControllers;
+  }
+
+  public MidiEngine setFocusedDeck(int deckIndex) {
+    if (this.activeDeckIndex != deckIndex) {
+      this.activeDeckIndex = deckIndex;
+      for (MidiEngineListener listener : listeners) {
+        listener.onFocusedDeck(deckIndex);
+      }
+    }
+    return this;
+  }
+
+  public Engine.Deck getFocusedDeck() {
+    return lx.engine.getDeck(activeDeckIndex);
+  }
+
+  public boolean isQwertyEnabled() {
+    return midiQwertyKeys.isEnabled() || midiQwertyAPC.isEnabled();
+  }
+}
+
+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;
+  public static final int APC = 2;
+
+  private boolean enabled = false;
+  private final String name;
+  private final int mode;
+  private int octaveShift = 0;
+
+  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>();
+
+  final List<SCMidiInputListener> listeners = new ArrayList<SCMidiInputListener>();
+
+  public SCMidiInput addListener(SCMidiInputListener l) {
+    listeners.add(l);
+    return this;
+  }
+
+  public SCMidiInput removeListener(SCMidiInputListener l) {
+    listeners.remove(l);
+    return this;
+  }
+
+  SCMidiInput(MidiInputDevice d) {
+    mode = MIDI;
+    d.createInput(this);
+    name = d.getName().replace("Unknown vendor","");
+  }
+
+  SCMidiInput(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 SCMidiInput setEnabled(boolean enabled) {
+    if (enabled != this.enabled) {
+      this.enabled = enabled;
+      for (SCMidiInputListener l : listeners) {
+        l.onEnabled(this, enabled);
+      }
+    }
+    return this;
+  }
+
+  protected SCPattern getFocusedPattern() {
+    return (SCPattern) midiEngine.getFocusedDeck().getActivePattern();
+  }
+
+  private boolean logMidi() {
+    return (uiMidi != null) && uiMidi.logMidi();
+  }
+
+  final void programChangeReceived(ProgramChange pc) {
+    if (!enabled) {
+      return;
+    }
+    if (logMidi()) {
+      println(getLabel() + " :: Program Change :: " + pc.getNumber());
+    }
+    handleProgramChange(pc);
+  }
+
+  final void controllerChangeReceived(rwmidi.Controller cc) {
+    if (!enabled) {
+      return;
+    }
+    if (logMidi()) {
+      println(getLabel() + " :: Controller :: " + cc.getCC() + ":" + cc.getValue());
+    }
+    if (!getFocusedPattern().controllerChangeReceived(cc)) {
+      handleControllerChange(cc);
+    }
+  }
+
+  final void noteOnReceived(Note note) {
+    if (!enabled) {
+      return;
+    }
+    if (logMidi()) {
+      println(getLabel() + " :: Note On  :: " + note.getChannel() + ":" + note.getPitch() + ":" + note.getVelocity());
+    }
+    if (!getFocusedPattern().noteOnReceived(note)) {
+      handleNoteOn(note);
+    }
+  }
+
+  final void noteOffReceived(Note note) {
+    if (!enabled) {
+      return;
+    }
+    if (logMidi()) {
+      println(getLabel() + " :: Note Off :: " + note.getChannel() + ":" + note.getPitch() + ":" + note.getVelocity());
+    }
+    if (!getFocusedPattern().noteOffReceived(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) {
+  }
+}
+
+public class APC40MidiInput extends SCMidiInput {
+
+  private boolean shiftOn = false;
+  private LXEffect releaseEffect = null;
+  
+  APC40MidiInput(MidiInputDevice d) {
+    super(d);
+  }
+
+  protected void handleControllerChange(rwmidi.Controller cc) {
+    int number = cc.getCC();
+    switch (number) {
+    // Crossfader
+    case 15:
+      lx.engine.getDeck(1).getCrossfader().setValue(cc.getValue() / 127.);
+      break;
+    }
+    
+    int parameterIndex = -1;
+    if (number >= 48 && number <= 55) {
+      parameterIndex = number - 48;
+    } else if (number >= 16 && number <= 19) {
+      parameterIndex = 8 + (number-16);
+    }
+    if (parameterIndex >= 0) {
+      List<LXParameter> parameters = getFocusedPattern().getParameters();
+      if (parameterIndex < parameters.size()) {
+        parameters.get(parameterIndex).setValue(cc.getValue() / 127.);
+      }
+    }
+    
+    if (number >= 20 && number <= 23) {
+      int effectIndex = number - 20;
+      List<LXParameter> parameters = glucose.getSelectedEffect().getParameters();
+      if (effectIndex < parameters.size()) {
+        parameters.get(effectIndex).setValue(cc.getValue() / 127.);
+      }
+    }
+  }
+
+  protected void handleNoteOn(Note note) {
+    switch (note.getPitch()) {
+    case 94: // right bank
+      midiEngine.setFocusedDeck(1);
+      break;
+    case 95: // left bank
+      midiEngine.setFocusedDeck(0);
+      break;
+    case 96: // up bank
+      if (shiftOn) {
+        glucose.incrementSelectedEffectBy(1);
+      } else {
+        midiEngine.getFocusedDeck().goNext();
+      }
+      break;
+    case 97: // down bank
+      if (shiftOn) {
+        glucose.incrementSelectedEffectBy(-1);
+      } else {
+        midiEngine.getFocusedDeck().goPrev();
+      }
+      break;
+
+    case 98: // shift
+      shiftOn = true;
+      break;
+
+    case 99: // tap tempo
+      lx.tempo.tap();
+      break;
+    case 100: // nudge+
+      lx.tempo.setBpm(lx.tempo.bpm() + (shiftOn ? 1 : .1));
+      break;
+    case 101: // nudge-
+      lx.tempo.setBpm(lx.tempo.bpm() - (shiftOn ? 1 : .1));
+      break;
+
+    case 91: // play
+    case 93: // rec
+      releaseEffect = glucose.getSelectedEffect(); 
+      if (releaseEffect.isMomentary()) {
+        releaseEffect.enable();
+      } else {
+        releaseEffect.toggle();
+      }
+      break;
+
+    case 92: // stop
+      glucose.getSelectedEffect().disable();
+      break;
+    }
+  }
+
+  protected void handleNoteOff(Note note) {
+    switch (note.getPitch()) {
+    case 93: // rec
+      if (releaseEffect != null) {
+        if (releaseEffect.isMomentary()) {
+          releaseEffect.disable();
+        }
+      }
+      break;
+               
+    case 98: // shift
+      shiftOn = false;
+       break;
+    }
+  }
+}
+
+class KorgNanoKontrolMidiInput extends SCMidiInput {
+  
+  KorgNanoKontrolMidiInput(MidiInputDevice d) {
+    super(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();
+      if (parameterIndex < parameters.size()) {
+        parameters.get(parameterIndex).setValue(cc.getValue() / 127.);
+      }
+    }
+    
+    if (cc.getValue() == 127) {
+      switch (number) {
+      // Left track
+      case 58:
+        midiEngine.setFocusedDeck(0);
+        break;
+      // Right track
+      case 59:
+        midiEngine.setFocusedDeck(1);
+        break;
+      // Left chevron
+      case 43:
+        midiEngine.getFocusedDeck().goPrev();
+        break;
+      // Right chevron
+      case 44:
+        midiEngine.getFocusedDeck().goNext();
+        break;
+      }
+    }
+  }
+}
+
index a12c189219ba646d563f459608a508d7519a4209..df3a7e45236379847f17b35219f84c5599e2cb3b 100644 (file)
@@ -483,16 +483,21 @@ class UIMidi extends UIWindow {
   private final UIToggleSet deckMode;
   private final UIButton logMode;
   
-  UIMidi(List<SCMidiInput> midiControllers, float x, float y, float w, float h) {
+  UIMidi(final MidiEngine midiEngine, 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 (SCMidiInput mc : midiControllers) {
+    for (SCMidiInput mc : midiEngine.getControllers()) {
       scrollItems.add(mc);
     }
     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);
+    (deckMode = new UIToggleSet(4, 130, 90, 20) {
+      protected void onToggle(String value) {
+        midiEngine.setFocusedDeck(value == "A" ? 0 : 1);
+      }
+    }).setOptions(new String[] { "A", "B" }).addToContainer(this);
     (logMode = new UIButton(98, 130, w-103, 20)).setLabel("LOG").addToContainer(this);
     
     SCMidiInputListener listener = new SCMidiInputListener() {
@@ -500,9 +505,15 @@ class UIMidi extends UIWindow {
         scrollList.redraw();
       }
     };
-    for (SCMidiInput mc : midiControllers) {
+    for (SCMidiInput mc : midiEngine.getControllers()) {
       mc.addListener(listener);
     }
+    
+    midiEngine.addListener(new MidiEngineListener() {
+      public void onFocusedDeck(int deckIndex) {
+        deckMode.setValue(deckIndex == 0 ? "A" : "B");
+      }
+    });
 
   }
   
index 26b508fbce7d98f7413eefe22704297b0d74e543..7b558bbc2bc53d89106ef46af7770bff5e8d4854 100755 (executable)
Binary files a/code/GLucose.jar and b/code/GLucose.jar differ