+ return true;
+ }
+ }
+
+ return false;
+ }
+}
+
+class APC40MidiOutput implements LXParameter.Listener, GridOutput {
+
+ private final MidiEngine midiEngine;
+ private final MidiOutput output;
+ private LXPattern focusedPattern = null;
+ private LXEffect focusedEffect = null;
+ private final LXDeck targetDeck;
+
+ APC40MidiOutput(MidiEngine midiEngine, MidiOutputDevice device) {
+ this(midiEngine, device, -1);
+ }
+
+ APC40MidiOutput(MidiEngine midiEngine, MidiOutputDevice device, int deckIndex) {
+ this.midiEngine = midiEngine;
+ output = device.createOutput();
+ targetDeck = (deckIndex < 0) ? null : lx.engine.getDecks().get(deckIndex);
+ setDPatternOutputs();
+ if (targetDeck != null) {
+ midiEngine.addListener(new MidiEngineListener() {
+ public void onFocusedDeck(int deckIndex) {
+ resetPatternParameters();
+ for (int i = 0; i < 8; ++i) {
+ output.sendNoteOn(i, 52, 0);
+ }
+ }
+ });
+ }
+ glucose.addEffectListener(new GLucose.EffectListener() {
+ public void effectSelected(LXEffect effect) {
+ resetEffectParameters();
+ }
+ });
+ LXDeck.Listener deckListener = new LXDeck.AbstractListener() {
+ public void patternDidChange(LXDeck deck, LXPattern pattern) {
+ if (deck == getTargetDeck()) {
+ resetPatternParameters();
+ }
+ }
+ };
+ for (LXDeck d : lx.engine.getDecks()) {
+ if (targetDeck == null || d == targetDeck) {
+ d.addListener(deckListener);
+ }
+ }
+ presetManager.addListener(new PresetListener() {
+ public void onPresetSelected(LXDeck deck, Preset preset) {
+ if (deck == getTargetDeck()) {
+ for (int i = 0; i < 8; ++i) {
+ output.sendNoteOn(i, 52, (preset.index == i) ? 1 : 0);
+ }
+ }
+ }
+ public void onPresetDirty(LXDeck deck, Preset preset) {
+ if (deck == getTargetDeck()) {
+ output.sendNoteOn(preset.index, 52, 2);
+ }
+ }
+ public void onPresetStored(LXDeck deck, Preset preset) {
+ onPresetSelected(deck, preset);
+ }
+ });
+ resetParameters();
+ midiEngine.grid.addOutput(this);
+
+ lx.cycleBaseHue(60000);
+ output.sendNoteOn(6, 49, 127);
+
+ // Turn off the track selection lights and preset selectors
+ for (int i = 0; i < 8; ++i) {
+ output.sendNoteOn(i, 51, 0);
+ output.sendNoteOn(i, 52, 0);
+ }
+
+ // Turn off the MASTER selector
+ output.sendNoteOn(0, 80, 0);
+ }
+
+ private void setDPatternOutputs() {
+ for (LXDeck deck : lx.engine.getDecks()) {
+ if (targetDeck == null || deck == targetDeck) {
+ for (LXPattern pattern : deck.getPatterns()) {
+ if (pattern instanceof DPat) {
+ ((DPat)pattern).setAPCOutput(output);
+ }
+ }
+ }
+ }
+ }
+
+ protected LXDeck getTargetDeck() {
+ return (targetDeck != null) ? targetDeck : midiEngine.getFocusedDeck();
+ }
+
+ private void resetParameters() {
+ resetPatternParameters();
+ resetEffectParameters();
+ }
+
+ private void resetPatternParameters() {
+ LXPattern newPattern = getTargetDeck().getActivePattern();
+ if (newPattern == focusedPattern) {
+ return;
+ }
+ if (focusedPattern != null) {
+ for (LXParameter p : focusedPattern.getParameters()) {
+ ((LXListenableParameter) p).removeListener(this);
+ }
+ }
+ focusedPattern = newPattern;
+ int i = 0;
+ for (LXParameter p : focusedPattern.getParameters()) {
+ ((LXListenableParameter) p).addListener(this);
+ sendKnob(i++, p);
+ }
+ while (i < 12) {
+ sendKnob(i++, 0);
+ }
+ if (focusedPattern instanceof DPat) {
+ ((DPat)focusedPattern).updateLights();
+ } else {
+ for (int j = 0; j < 8; ++j) {
+ output.sendNoteOn(j, 48, 0);
+ }
+ for (int row = 0; row < 7; ++row) {
+ for (int col = 0; col < 8; ++col) {
+ setGridState(row, col, 0);
+ }
+ }
+ }
+ }
+
+ private void resetEffectParameters() {
+ LXEffect newEffect = glucose.getSelectedEffect();
+ if (newEffect == focusedEffect) {
+ return;
+ }
+ if (focusedEffect != null) {
+ for (LXParameter p : focusedPattern.getParameters()) {
+ ((LXListenableParameter) p).removeListener(this);
+ }
+ }
+ focusedEffect = newEffect;
+ int i = 0;
+ for (LXParameter p : focusedEffect.getParameters()) {
+ ((LXListenableParameter) p).addListener(this);
+ sendKnob(12 + i++, p);
+ }
+ while (i < 4) {
+ sendKnob(12 + i++, 0);
+ }
+ }
+
+ private void sendKnob(int i, LXParameter p) {
+ sendKnob(i, (int) (p.getValuef() * 127.));
+ }
+
+ private void sendKnob(int i, int value) {
+ if (i < 8) {
+ output.sendController(0, 48+i, value);
+ } else if (i < 16) {
+ output.sendController(0, 8+i, value);
+ }
+ }
+
+ public void onParameterChanged(LXParameter parameter) {
+ int i = 0;
+ for (LXParameter p : focusedPattern.getParameters()) {
+ if (p == parameter) {
+ sendKnob(i, p);
+ break;
+ }
+ ++i;
+ }
+ i = 12;
+ for (LXParameter p : focusedEffect.getParameters()) {
+ if (p == parameter) {
+ sendKnob(i, p);