Skip to content
Original file line number Diff line number Diff line change
@@ -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<Integer> 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);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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();
Expand All @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public String getAuthor() {

@Override
public String getVersion() {
return "1.01";
return "1.02";
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<String> 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;
}

Expand Down Expand Up @@ -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<String[]> 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<String[]> getWinPortList() {
final List<String[]> 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<String> pool, final int comboSize, final int start,
final List<String> current, final List<String[]> 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++) {
Expand Down