diff --git a/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/definition/LaunchkeyMk488ExtensionDefinition.java b/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/definition/LaunchkeyMk488ExtensionDefinition.java new file mode 100644 index 00000000..3afacf43 --- /dev/null +++ b/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/definition/LaunchkeyMk488ExtensionDefinition.java @@ -0,0 +1,82 @@ +package com.bitwig.extensions.controllers.novation.launchkey_mk4.definition; + +import java.util.List; +import java.util.UUID; + +import com.bitwig.extension.api.PlatformType; +import com.bitwig.extension.controller.AutoDetectionMidiPortNamesList; +import com.bitwig.extension.controller.api.ControllerHost; +import com.bitwig.extensions.controllers.novation.launchkey_mk4.LaunchkeyMk4Extension; +import com.bitwig.extensions.controllers.novation.launchkey_mk4.LaunchkeyMk4Type; + +public class LaunchkeyMk488ExtensionDefinition extends AbstractLaunchkeyMk4ExtensionDefinition { + private static final UUID DRIVER_ID = UUID.fromString("ef68e909-d5f1-4557-8526-efe6978cabaa"); + private static final List VARIANTS = List.of(25, 37, 49, 61); + + @Override + public String getName() { + return "Launchkey Mk4 88"; + } + + @Override + public String getHardwareModel() { + return "Launchkey Mk4 88"; + } + + @Override + public UUID getId() { + return DRIVER_ID; + } + + @Override + public String getHelpFilePath() { + return "Controllers/Novation/LaunchKey Mk4.pdf"; + } + + @Override + public void listAutoDetectionMidiPortNames(final AutoDetectionMidiPortNamesList list, + final PlatformType platformType) { + if (platformType == PlatformType.WINDOWS) { + for (final int variant : VARIANTS) { + for (int i = 0; i < 4; i++) { + list.add( + new String[] { + "MIDIIN2 (Launchkey MK4 88 %d MIDI%s".formatted(variant, (i & 0x1) != 0 ? ")" : ""), + "Launchkey MK4 88 %d MIDI".formatted(variant) + }, new String[] { + "MIDIOUT2 (Launchkey MK4 88 %d MIDI%s".formatted(variant, (i & 0x2) != 0 ? ")" : ""), + "Launchkey MK4 88 %d MIDI".formatted(variant) + }); + } + } + } else if (platformType == PlatformType.MAC) { + for (final int variant : VARIANTS) { + list.add( + new String[] { + "Launchkey MK4 88 %d DAW Out".formatted(variant), + "Launchkey MK4 88 %d MIDI Out".formatted(variant) + }, new String[] { + "Launchkey MK4 88 %d DAW In".formatted(variant), + "Launchkey MK4 88 %d MIDI In".formatted(variant) + }); + } + } else if (platformType == PlatformType.LINUX) { + for (final int variant : VARIANTS) { + list.add( + new String[] { + "Launchkey MK4 88 %d Launchkey".formatted(variant), + "Launchkey MK4 88 %d Launchkey #2".formatted(variant) + }, new String[] { + "Launchkey MK4 88 %d Launchkey".formatted(variant), + "Launchkey MK4 88 %d Launchkey #2".formatted(variant) + }); + } + } + } + + @Override + public LaunchkeyMk4Extension createInstance(final ControllerHost host) { + return new LaunchkeyMk4Extension(this, host, LaunchkeyMk4Type.STANDARD); + } + +} diff --git a/src/main/java/com/bitwig/extensions/controllers/softube/console1/ConsoleMidiProcessor.java b/src/main/java/com/bitwig/extensions/controllers/softube/console1/ConsoleMidiProcessor.java index 6f11f829..c8b00bff 100644 --- a/src/main/java/com/bitwig/extensions/controllers/softube/console1/ConsoleMidiProcessor.java +++ b/src/main/java/com/bitwig/extensions/controllers/softube/console1/ConsoleMidiProcessor.java @@ -22,6 +22,8 @@ public class ConsoleMidiProcessor { private boolean engineActiveState = false; private final String name; + private long connectTime = -1L; + private boolean enableState = false; public ConsoleMidiProcessor(final ControllerHost host, final int ports, final String name) { this.host = host; @@ -91,8 +93,11 @@ private void handleJson(final int port, final String json) { handleResetReceived(); } else if ("ENABLE".equals(cmdValue)) { println(" ENABLE <%s>", name); + enableState = true; + connectionListeners.forEach(listener -> listener.isConnected(true)); } else if ("DISABLE".equals(cmdValue)) { println(" DISABLE <%s>", name); + enableState = false; connectionListeners.forEach(listener -> listener.isConnected(false)); } else { println(" Unknown COMMAND %s", cmdValue); @@ -105,9 +110,13 @@ private void handleJson(final int port, final String json) { } private void handleResetReceived() { - println(" RESET received INIT=%s", connectionInit); - if (!connectionInit) { + final long upTime = System.currentTimeMillis() - connectTime; + println(" RESET received INIT=%s uptime=%d enabled=%s", connectionInit, upTime, enableState); + if (!connectionInit || upTime < 2000) { + println(" >>> Restart Handshake"); + connectionInit = false; trackSlotControl.setBlockMidi(false); + connectionListeners.forEach(listener -> listener.isConnected(false)); startHandshake(); } else { trackSlotControl.updateAllTracks(); @@ -120,26 +129,30 @@ private void handleHandshake(final int port, final boolean acknowledged) { if (acknowledged) { connectToDevice(port); } else { - if (connectionInit) { - println(" Let us ignore this "); - } else { - connectionInit = false; - host.getMidiOutPort(port).sendSysex(SysexUtil.toJsonSysEx(SysexUtil.RESET_CMD)); - connectionListeners.forEach(listener -> listener.isConnected(false)); + if (!connectionInit) { + host.scheduleTask(() -> invokeRetry(port), 30); } } } + private void invokeRetry(final int port) { + if (!connectionInit) { + println(" INVOKE RETRY %d", port); + host.getMidiOutPort(port).sendSysex(SysexUtil.toJsonSysEx(SysexUtil.RESET_CMD)); + connectionListeners.forEach(listener -> listener.isConnected(false)); + } + } + private void connectToDevice(final int port) { - // println(" ####### Connect to Device %d ########### ", port); + println(" ####### Connect to Device %d ########### ", port); + enableState = true; midiOut = host.getMidiOutPort(port); - + connectTime = System.currentTimeMillis(); host.scheduleTask(this::launchTrackUpdate, 500); if (!connectionInit) { connectionInit = true; connectionListeners.forEach(listener -> listener.isConnected(true)); } - } private void launchTrackUpdate() { diff --git a/src/main/java/com/bitwig/extensions/controllers/softube/console1/definition/Console1ExtensionDefinition.java b/src/main/java/com/bitwig/extensions/controllers/softube/console1/definition/Console1ExtensionDefinition.java index fcb3b0fc..abd22ea0 100644 --- a/src/main/java/com/bitwig/extensions/controllers/softube/console1/definition/Console1ExtensionDefinition.java +++ b/src/main/java/com/bitwig/extensions/controllers/softube/console1/definition/Console1ExtensionDefinition.java @@ -17,7 +17,7 @@ public String getAuthor() { @Override public String getVersion() { - return "1.01"; + return "1.02"; } @Override diff --git a/src/main/java/com/bitwig/extensions/controllers/softube/console1/definition/SoftubeDawControlMultiExtensionDefinition.java b/src/main/java/com/bitwig/extensions/controllers/softube/console1/definition/SoftubeDawControlMultiExtensionDefinition.java index 4422ff2e..de75dd32 100644 --- a/src/main/java/com/bitwig/extensions/controllers/softube/console1/definition/SoftubeDawControlMultiExtensionDefinition.java +++ b/src/main/java/com/bitwig/extensions/controllers/softube/console1/definition/SoftubeDawControlMultiExtensionDefinition.java @@ -1,5 +1,7 @@ package com.bitwig.extensions.controllers.softube.console1.definition; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; import com.bitwig.extension.api.PlatformType; @@ -13,11 +15,17 @@ public class SoftubeDawControlMultiExtensionDefinition extends Console1Extension private final int portCount; + private static final String WIN_PORT_CHANNEL = "Console 1 Fader Mk III"; + private static final String WIN_PORT_FADER = "Console 1 Channel Mk III"; + private static final String WIN_PORT_FLOW = "Softube Flow Studio"; + private static final List DEVICE_POOL = + List.of(WIN_PORT_CHANNEL, WIN_PORT_FADER, WIN_PORT_FLOW, "Softube Console 1 Compact"); + public SoftubeDawControlMultiExtensionDefinition() { this(2); } - public SoftubeDawControlMultiExtensionDefinition(int ports) { + public SoftubeDawControlMultiExtensionDefinition(final int ports) { this.portCount = ports; } @@ -50,26 +58,53 @@ public int getNumMidiOutPorts() { public void listAutoDetectionMidiPortNames(final AutoDetectionMidiPortNamesList list, final PlatformType platformType) { if (platformType == PlatformType.WINDOWS) { // - final String[] winPortList = getWinPortList(); - list.add(winPortList, winPortList); + final List portSelection = getWinPortList(); + for (final String[] winPortList : portSelection) { + list.add(winPortList, winPortList); + } } else { final String[] macPortList = getMacPortList(); list.add(macPortList, macPortList); } } - private String[] getWinPortList() { - String[] ports = new String[portCount]; - ports[0] = "Console 1 Fader Mk III"; - ports[1] = "Console 1 Channel Mk III"; - for (int i = 2; i < ports.length; i++) { - ports[i] = "Console 1 Channel Mk 0%d".formatted(i - 2); + protected List getWinPortList() { + final List selection = new ArrayList<>(); + final int poolSize = DEVICE_POOL.size(); + final int comboSize = Math.min(portCount, poolSize); + + // Generate all combinations of size comboSize from DEVICE_POOL + generateCombinations(DEVICE_POOL, comboSize, 0, new ArrayList<>(), selection, portCount); + + return selection; + } + + private void generateCombinations(final List pool, final int comboSize, final int start, + final List current, final List result, final int totalPorts) { + + if (current.size() == comboSize) { + // Build full array: chosen pool entries + overflow slots + final String[] ports = new String[totalPorts]; + for (int i = 0; i < current.size(); i++) { + ports[i] = current.get(i); + } + // Fill overflow beyond pool size + for (int i = comboSize; i < totalPorts; i++) { + ports[i] = "Console 1 Channel Mk 0%d".formatted(i - comboSize); + } + result.add(ports); + return; + } + + for (int i = start; i < pool.size(); i++) { + current.add(pool.get(i)); + generateCombinations(pool, comboSize, i + 1, current, result, totalPorts); + current.remove(current.size() - 1); } - return ports; } private String[] getMacPortList() { - String[] ports = new String[portCount]; + final String[] ports = new String[portCount]; ports[0] = "Console 1 Channel Mk III DAW FA0000000073"; ports[1] = "Console 1 Channel Mk III DAW FA0000000073"; for (int i = 2; i < ports.length; i++) {