From aa1238153c1d2aa97b6134dbda214249ae3efea6 Mon Sep 17 00:00:00 2001 From: ericahrens Date: Wed, 20 May 2026 19:43:36 +0200 Subject: [PATCH 1/6] NKS Device handling improved --- .../komplete/KompleteKontrolExtension.java | 65 ++++++++----------- .../nativeinstruments/komplete/NksDevice.java | 53 +++++++++++++++ .../komplete/midi/MidiProcessor.java | 18 ++++- 3 files changed, 97 insertions(+), 39 deletions(-) create mode 100644 src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/NksDevice.java diff --git a/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/KompleteKontrolExtension.java b/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/KompleteKontrolExtension.java index 4f713658..d5f7ead0 100644 --- a/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/KompleteKontrolExtension.java +++ b/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/KompleteKontrolExtension.java @@ -3,6 +3,7 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import com.bitwig.extension.api.Color; @@ -13,6 +14,9 @@ import com.bitwig.extension.controller.api.ControllerHost; import com.bitwig.extension.controller.api.CursorRemoteControlsPage; import com.bitwig.extension.controller.api.CursorTrack; +import com.bitwig.extension.controller.api.Device; +import com.bitwig.extension.controller.api.DeviceBank; +import com.bitwig.extension.controller.api.DeviceMatcher; import com.bitwig.extension.controller.api.DocumentState; import com.bitwig.extension.controller.api.HardwareButton; import com.bitwig.extension.controller.api.HardwareElement; @@ -239,39 +243,6 @@ protected void handle4DShiftPressed(final Track rootTrack, final CursorTrack cur } } - protected void createKompleteKontrolDeviceKompleteKontrol(final PinnableCursorDevice cursorDevice) { - final SpecificPluginDevice kompleteKontrolVst3Id = - cursorDevice.createSpecificVst3Device(KOMPLETE_KONTROL_VST3_ID); - final Parameter kompleteKontrolVst3InstId = kompleteKontrolVst3Id.createParameter(0); - kompleteKontrolVst3InstId.name().addValueObserver(midiProcessor::updateKompleteKontrolInstance); - - final SpecificPluginDevice kompleteKontrolPluginVst2 = - cursorDevice.createSpecificVst2Device(KOMPLETE_KONTROL_DEVICE_ID); - final Parameter kompleteKontrolVst2InstId = kompleteKontrolPluginVst2.createParameter(0); - kompleteKontrolVst2InstId.markInterested(); - kompleteKontrolVst2InstId.name().markInterested(); - kompleteKontrolVst2InstId.exists().markInterested(); - kompleteKontrolVst2InstId.name().addValueObserver(midiProcessor::updateKompleteKontrolInstance); - } - - protected void createKontaktDeviceKompleteKontrol(final PinnableCursorDevice cursorDevice) { - final SpecificPluginDevice kontaktVst3Id = cursorDevice.createSpecificVst3Device(KONTAKT_7_VST3_ID); - final Parameter instId = kontaktVst3Id.createParameter(2048); - instId.name().addValueObserver(midiProcessor::updateKompleteKontrolInstance); - } - - protected void createKontakt8DeviceKompleteKontrol(final PinnableCursorDevice cursorDevice) { - final SpecificPluginDevice kontaktVst3Id = cursorDevice.createSpecificVst3Device(KONTAKT_8_VST3_ID); - final Parameter instId = kontaktVst3Id.createParameter(2048); - instId.name().addValueObserver(midiProcessor::updateKompleteKontrolInstance); - } - - protected void createMaschineDeviceKompleteKontrol(final PinnableCursorDevice cursorDevice) { - final SpecificPluginDevice kontaktVst3Id = cursorDevice.createSpecificVst3Device(MASCHINE_3_VST3_ID); - final Parameter instId = kontaktVst3Id.createParameter(128); - instId.name().addValueObserver(midiProcessor::updateKompleteKontrolInstance); - } - private void changeMode(final int mode) { if (mode == 0) { navigationLayer.activate(); @@ -286,14 +257,18 @@ protected void initTrackBank() { final PinnableCursorDevice cursorDevice = viewControl.getCursorDevice(); final CursorTrack cursorTrack = viewControl.getCursorTrack(); final TrackBank mixerTrackBank = viewControl.getMixerTrackBank(); - createKompleteKontrolDeviceKompleteKontrol(cursorDevice); - createKontaktDeviceKompleteKontrol(cursorDevice); - createKontakt8DeviceKompleteKontrol(cursorDevice); - createMaschineDeviceKompleteKontrol(cursorDevice); if (hasDeviceControl()) { mixerTrackBank.scrollPosition().addValueObserver(this::handleTrackScrollChanged); } + // else { + // for (final NksDevice deviceType : NksDevice.values()) { + // final SpecificPluginDevice specDevice = deviceType.createSpecDevice(cursorDevice); + // final Parameter instId = specDevice.createParameter(deviceType.getParamOffset()); + // instId.name().addValueObserver(midiProcessor::updateKompleteKontrolInstance); + // } + // } + initNksDiscovery(cursorTrack); mainLayer.bindPressed(controlElements.getMuteSelectedButton(), cursorTrack.mute().toggleAction()); mainLayer.bindPressed(controlElements.getSoloSelectedButton(), cursorTrack.solo().toggleAction()); @@ -308,6 +283,22 @@ protected void initTrackBank() { } } + private void initNksDiscovery(final CursorTrack cursorTrack) { + final DeviceBank nksDiscoverBank = cursorTrack.createDeviceBank(1); + final DeviceMatcher matcher = getHost().createOrDeviceMatcher(Arrays.stream(NksDevice.values()) // + .map(type -> type.createMatcher(getHost())) // + .toArray(DeviceMatcher[]::new)); + + nksDiscoverBank.setDeviceMatcher(matcher); + final Device nksDevice = nksDiscoverBank.getDevice(0); + for (final NksDevice deviceType : NksDevice.values()) { + final SpecificPluginDevice specDevice = deviceType.createSpecDevice(nksDevice); + final Parameter instId = specDevice.createParameter(deviceType.getParamOffset()); + instId.name().addValueObserver(name -> midiProcessor.registerNksParam(deviceType, name)); + } + nksDevice.name().addValueObserver(name -> midiProcessor.registerNksDevice(name)); + } + private void handleTrackScrollChanged(final int pos) { midiProcessor.refreshSelectedColor(); } diff --git a/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/NksDevice.java b/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/NksDevice.java new file mode 100644 index 00000000..1e721dee --- /dev/null +++ b/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/NksDevice.java @@ -0,0 +1,53 @@ +package com.bitwig.extensions.controllers.nativeinstruments.komplete; + +import com.bitwig.extension.controller.api.ControllerHost; +import com.bitwig.extension.controller.api.Device; +import com.bitwig.extension.controller.api.DeviceMatcher; +import com.bitwig.extension.controller.api.SpecificPluginDevice; + +public enum NksDevice { + KOMPLETE(KompleteKontrolExtension.KOMPLETE_KONTROL_VST3_ID, 0), + KOMPLETE_VST2(KompleteKontrolExtension.KOMPLETE_KONTROL_DEVICE_ID, 0), + KONTAKT7(KompleteKontrolExtension.KONTAKT_7_VST3_ID, 2048), + KONTAKT8(KompleteKontrolExtension.KONTAKT_8_VST3_ID, 2048), + MASCHINE(KompleteKontrolExtension.MASCHINE_3_VST3_ID, 128); + final String id; + final int paramOffset; + final int vst2id; + + NksDevice(final String id, final int paramOffset) { + this(id, paramOffset, -1); + } + + NksDevice(final int id, final int paramOffset) { + this(null, paramOffset, id); + } + + NksDevice(final String id, final int paramOffset, final int vst2Id) { + this.id = id; + this.paramOffset = paramOffset; + this.vst2id = vst2Id; + } + + public String getId() { + return id; + } + + public int getParamOffset() { + return paramOffset; + } + + public DeviceMatcher createMatcher(final ControllerHost host) { + if (this.id != null) { + return host.createVST3DeviceMatcher(this.id); + } + return host.createVST2DeviceMatcher(this.vst2id); + } + + public SpecificPluginDevice createSpecDevice(final Device device) { + if (this.id != null) { + return device.createSpecificVst3Device(this.id); + } + return device.createSpecificVst2Device(this.vst2id); + } +} diff --git a/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/midi/MidiProcessor.java b/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/midi/MidiProcessor.java index 8e6efff0..2ecb3d54 100644 --- a/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/midi/MidiProcessor.java +++ b/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/midi/MidiProcessor.java @@ -19,6 +19,7 @@ import com.bitwig.extensions.controllers.nativeinstruments.komplete.DataStringUtil; import com.bitwig.extensions.controllers.nativeinstruments.komplete.KompleteKontrolExtension; import com.bitwig.extensions.controllers.nativeinstruments.komplete.LayoutType; +import com.bitwig.extensions.controllers.nativeinstruments.komplete.NksDevice; import com.bitwig.extensions.controllers.nativeinstruments.komplete.device.DeviceSelectionTab; public class MidiProcessor { @@ -142,7 +143,22 @@ public HardwareButton createButton(final String name, final int ccNr, final int return hwButton; } + private String currentNksDeviceName = ""; + + public void registerNksDevice(final String name) { + currentNksDeviceName = name; + } + + public void registerNksParam(final NksDevice deviceTyp, final String paramId) { + if (!paramId.isBlank()) { + updateKompleteKontrolInstance(paramId); + } + } + public void updateKompleteKontrolInstance(final String instanceParamName) { + if (instanceParamName.isBlank()) { + return; + } if (lastReportedKKInstance == null || !lastReportedKKInstance.equals(instanceParamName)) { sendTextCommand(TextCommand.SELECTED_TRACK, instanceParamName); host.scheduleTask(() -> sendTextCommand(TextCommand.SELECTED_TRACK, instanceParamName), 100); @@ -184,7 +200,6 @@ public void sendSelectCommand(final int index, final boolean selected) { if (selectedState[index] == selected) { return; } - final int nowSelected = getSelectedIndex(); selectedState[index] = selected; ValueCommand.SELECT.send(midiOut, index, selected); } @@ -293,5 +308,4 @@ public void updateParameterValue(final int index, final int value) { midiOut.sendMidi(0xBF, 0x70 + index, value); } - } From b88015079fda592af90dc335c8eaf0abb5ded8ea Mon Sep 17 00:00:00 2001 From: ericahrens Date: Mon, 15 Jun 2026 19:27:09 +0200 Subject: [PATCH 2/6] NKS Plugin Discovery improved --- .../komplete/KompleteKontrolExtension.java | 35 ++------ .../komplete/ViewControl.java | 13 +++ .../komplete/device/DeviceControl.java | 4 +- .../device/DirectParameterControl.java | 17 +++- .../komplete/midi/MidiProcessor.java | 38 ++++----- .../launchkey_mk4/LaunchkeyMk4Type.java | 4 + .../LaunchkeyMk488ExtensionDefinition.java | 79 +++++++++++++++++++ 7 files changed, 137 insertions(+), 53 deletions(-) create mode 100644 src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/LaunchkeyMk4Type.java create mode 100644 src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/definition/LaunchkeyMk488ExtensionDefinition.java diff --git a/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/KompleteKontrolExtension.java b/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/KompleteKontrolExtension.java index d5f7ead0..ac377c57 100644 --- a/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/KompleteKontrolExtension.java +++ b/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/KompleteKontrolExtension.java @@ -3,7 +3,6 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import com.bitwig.extension.api.Color; @@ -14,9 +13,6 @@ import com.bitwig.extension.controller.api.ControllerHost; import com.bitwig.extension.controller.api.CursorRemoteControlsPage; import com.bitwig.extension.controller.api.CursorTrack; -import com.bitwig.extension.controller.api.Device; -import com.bitwig.extension.controller.api.DeviceBank; -import com.bitwig.extension.controller.api.DeviceMatcher; import com.bitwig.extension.controller.api.DocumentState; import com.bitwig.extension.controller.api.HardwareButton; import com.bitwig.extension.controller.api.HardwareElement; @@ -260,15 +256,14 @@ protected void initTrackBank() { if (hasDeviceControl()) { mixerTrackBank.scrollPosition().addValueObserver(this::handleTrackScrollChanged); + } else { + for (final NksDevice deviceType : NksDevice.values()) { + final SpecificPluginDevice specDevice = deviceType.createSpecDevice(cursorDevice); + final Parameter instId = specDevice.createParameter(deviceType.getParamOffset()); + instId.name().addValueObserver(id -> midiProcessor.registerNksParam(deviceType, id)); + } } - // else { - // for (final NksDevice deviceType : NksDevice.values()) { - // final SpecificPluginDevice specDevice = deviceType.createSpecDevice(cursorDevice); - // final Parameter instId = specDevice.createParameter(deviceType.getParamOffset()); - // instId.name().addValueObserver(midiProcessor::updateKompleteKontrolInstance); - // } - // } - initNksDiscovery(cursorTrack); + //initNksDiscovery(viewControl); mainLayer.bindPressed(controlElements.getMuteSelectedButton(), cursorTrack.mute().toggleAction()); mainLayer.bindPressed(controlElements.getSoloSelectedButton(), cursorTrack.solo().toggleAction()); @@ -283,22 +278,6 @@ protected void initTrackBank() { } } - private void initNksDiscovery(final CursorTrack cursorTrack) { - final DeviceBank nksDiscoverBank = cursorTrack.createDeviceBank(1); - final DeviceMatcher matcher = getHost().createOrDeviceMatcher(Arrays.stream(NksDevice.values()) // - .map(type -> type.createMatcher(getHost())) // - .toArray(DeviceMatcher[]::new)); - - nksDiscoverBank.setDeviceMatcher(matcher); - final Device nksDevice = nksDiscoverBank.getDevice(0); - for (final NksDevice deviceType : NksDevice.values()) { - final SpecificPluginDevice specDevice = deviceType.createSpecDevice(nksDevice); - final Parameter instId = specDevice.createParameter(deviceType.getParamOffset()); - instId.name().addValueObserver(name -> midiProcessor.registerNksParam(deviceType, name)); - } - nksDevice.name().addValueObserver(name -> midiProcessor.registerNksDevice(name)); - } - private void handleTrackScrollChanged(final int pos) { midiProcessor.refreshSelectedColor(); } diff --git a/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/ViewControl.java b/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/ViewControl.java index e71d0348..5762e319 100644 --- a/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/ViewControl.java +++ b/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/ViewControl.java @@ -1,8 +1,11 @@ package com.bitwig.extensions.controllers.nativeinstruments.komplete; +import java.util.Arrays; + import com.bitwig.extension.controller.api.Application; import com.bitwig.extension.controller.api.ControllerHost; import com.bitwig.extension.controller.api.CursorTrack; +import com.bitwig.extension.controller.api.DeviceMatcher; import com.bitwig.extension.controller.api.PinnableCursorDevice; import com.bitwig.extension.controller.api.Project; import com.bitwig.extension.controller.api.TrackBank; @@ -14,6 +17,7 @@ public class ViewControl { private final NavigationState navigationState = new NavigationState(); private final CursorTrack cursorTrack; private final PinnableCursorDevice cursorDevice; + private final DeviceMatcher nksDeviceMatcher; protected TrackBank mixerTrackBank; protected Transport transport; protected Project project; @@ -35,12 +39,21 @@ public ViewControl(final ControllerHost host) { mixerTrackBank.canScrollChannelsUp().markInterested(); mixerTrackBank.followCursorTrack(cursorTrack); mixerTrackBank.setChannelScrollStepSize(8); + + nksDeviceMatcher = host.createOrDeviceMatcher(Arrays.stream(NksDevice.values()) // + .map(type -> type.createMatcher(host)) // + .toArray(DeviceMatcher[]::new)); + } public Project getProject() { return project; } + public DeviceMatcher getNksDeviceMatcher() { + return nksDeviceMatcher; + } + public NavigationState getNavigationState() { return navigationState; } diff --git a/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/device/DeviceControl.java b/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/device/DeviceControl.java index be788257..6730028a 100644 --- a/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/device/DeviceControl.java +++ b/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/device/DeviceControl.java @@ -55,6 +55,7 @@ public DeviceControl(final ControllerHost host, final MidiProcessor midiProcesso this.controlElements = controlElements; final PinnableCursorDevice cursorDevice = cursorTrack.createCursorDevice(); cursorDevice.presetName().addValueObserver(this::handlePresetName); + this.mainBank = new BankControl(cursorDevice, this.midiProcessor, this, controlElements.getShiftHeld()); this.mainBank.getCurrentFocus().addValueObserver(this::handleFocus); final BrowserHandler browserHandler = new BrowserHandler(host, cursorDevice, controlElements.getShiftHeld()); @@ -63,8 +64,7 @@ public DeviceControl(final ControllerHost host, final MidiProcessor midiProcesso deviceRemotesControl = new RemotesControl(deviceRemoteLayer, deviceRemotePages, controlElements, midiProcessor); directParameterControl = new DirectParameterControl( - directParamLayer, cursorDevice, controlElements, midiProcessor, - deviceRemotePages.pageCount()); + directParamLayer, viewControl, controlElements, midiProcessor, deviceRemotePages.pageCount()); directParameterControl.getDirectActive().addValueObserver(this::handleDirectActive); final Track rootTrack = viewControl.getProject().getRootTrackGroup(); diff --git a/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/device/DirectParameterControl.java b/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/device/DirectParameterControl.java index db2701d3..82e4fbd2 100644 --- a/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/device/DirectParameterControl.java +++ b/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/device/DirectParameterControl.java @@ -4,11 +4,14 @@ import java.util.HashMap; import java.util.List; -import com.bitwig.extension.controller.api.CursorDevice; import com.bitwig.extension.controller.api.Device; import com.bitwig.extension.controller.api.DirectParameterValueDisplayObserver; import com.bitwig.extension.controller.api.IntegerValue; +import com.bitwig.extension.controller.api.Parameter; import com.bitwig.extension.controller.api.RelativeHardwareKnob; +import com.bitwig.extension.controller.api.SpecificPluginDevice; +import com.bitwig.extensions.controllers.nativeinstruments.komplete.NksDevice; +import com.bitwig.extensions.controllers.nativeinstruments.komplete.ViewControl; import com.bitwig.extensions.controllers.nativeinstruments.komplete.binding.KnobDirectBinding; import com.bitwig.extensions.controllers.nativeinstruments.komplete.control.ControlElements; import com.bitwig.extensions.controllers.nativeinstruments.komplete.midi.MidiProcessor; @@ -35,11 +38,17 @@ public class DirectParameterControl extends AbstractParameterControl { private String deviceName; private boolean fineTune; - public DirectParameterControl(final Layer layer, final CursorDevice device, final ControlElements controlElements, - final MidiProcessor midiProcessor, final IntegerValue remotePageCount) { + public DirectParameterControl(final Layer layer, final ViewControl viewControl, + final ControlElements controlElements, final MidiProcessor midiProcessor, final IntegerValue remotePageCount) { super(layer); + this.device = viewControl.getCursorDevice(); this.midiProcessor = midiProcessor; - this.device = device; + for (final NksDevice deviceType : NksDevice.values()) { + final SpecificPluginDevice specDevice = deviceType.createSpecDevice(device); + final Parameter instId = specDevice.createParameter(deviceType.getParamOffset()); + instId.name().addValueObserver(name -> midiProcessor.registerNksParam(deviceType, name)); + } + for (int i = 0; i < MAX_PARAMS; i++) { allSlots.add(new DirectSlot(i)); } diff --git a/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/midi/MidiProcessor.java b/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/midi/MidiProcessor.java index 2ecb3d54..a892cfd6 100644 --- a/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/midi/MidiProcessor.java +++ b/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/midi/MidiProcessor.java @@ -23,6 +23,7 @@ import com.bitwig.extensions.controllers.nativeinstruments.komplete.device.DeviceSelectionTab; public class MidiProcessor { + private long initStartTime; final NhiaSyexLevelsCommand trackLevelMeterCommand = new NhiaSyexLevelsCommand(0x49); private final static String INCOMING_HEADER = "f0002109000044430100"; private final static String INCOMING_INDEX = INCOMING_HEADER + "7000"; @@ -81,6 +82,19 @@ private void handleSysex(final String sysExData) { public void intoDawMode(final int protocol) { this.expectedProtocol = protocol; midiOut.sendMidi(0xBF, 0x1, protocol); + host.scheduleTask(this::initProcess, 1000); + initStartTime = System.currentTimeMillis(); + } + + private void initProcess() { + final long diff = System.currentTimeMillis() - initStartTime; + KompleteKontrolExtension.println(" Running Init Process %d kk=%s", diff, lastReportedKKInstance); + if (diff < 20000) { + host.scheduleTask(this::initProcess, 1000); + } + if (lastReportedKKInstance != null) { + sendTextCommand(TextCommand.SELECTED_TRACK, lastReportedKKInstance); + } } public void delay(final Runnable action, final int delay) { @@ -143,26 +157,12 @@ public HardwareButton createButton(final String name, final int ccNr, final int return hwButton; } - private String currentNksDeviceName = ""; - - public void registerNksDevice(final String name) { - currentNksDeviceName = name; - } - public void registerNksParam(final NksDevice deviceTyp, final String paramId) { - if (!paramId.isBlank()) { - updateKompleteKontrolInstance(paramId); - } - } - - public void updateKompleteKontrolInstance(final String instanceParamName) { - if (instanceParamName.isBlank()) { - return; - } - if (lastReportedKKInstance == null || !lastReportedKKInstance.equals(instanceParamName)) { - sendTextCommand(TextCommand.SELECTED_TRACK, instanceParamName); - host.scheduleTask(() -> sendTextCommand(TextCommand.SELECTED_TRACK, instanceParamName), 100); - lastReportedKKInstance = instanceParamName; + // KompleteKontrolExtension.println(" REG NKS %s : %s ", lastReportedKKInstance, paramId); + if (lastReportedKKInstance == null || !lastReportedKKInstance.equals(paramId)) { + sendTextCommand(TextCommand.SELECTED_TRACK, paramId); + host.scheduleTask(() -> sendTextCommand(TextCommand.SELECTED_TRACK, paramId), 100); + lastReportedKKInstance = paramId; } } diff --git a/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/LaunchkeyMk4Type.java b/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/LaunchkeyMk4Type.java new file mode 100644 index 00000000..4261f035 --- /dev/null +++ b/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/LaunchkeyMk4Type.java @@ -0,0 +1,4 @@ +package com.bitwig.extensions.controllers.novation.launchkey_mk4; + +public enum LaunckeyMk4Type { +} 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..6f70187e --- /dev/null +++ b/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/definition/LaunchkeyMk488ExtensionDefinition.java @@ -0,0 +1,79 @@ +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; + +public class LaunchkeyMk4ExtensionDefinition extends AbstractLaunchkeyMk4ExtensionDefinition { + private static final UUID DRIVER_ID = UUID.fromString("ef68e909-d5f1-4557-8526-2ce6978cabaa"); + private static final List VARIANTS = List.of(25, 37, 49, 61); + + @Override + public String getName() { + return "Launchkey Mk4"; + } + + @Override + public String getHardwareModel() { + return "Launchkey Mk4"; + } + + @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 %d MIDI%s".formatted(variant, (i & 0x1) != 0 ? ")" : ""), + "Launchkey MK4 %d MIDI".formatted(variant) + }, new String[] { + "MIDIOUT2 (Launchkey MK4 %d MIDI%s".formatted(variant, (i & 0x2) != 0 ? ")" : ""), + "Launchkey MK4 %d MIDI".formatted(variant) + }); + } + } + } else if (platformType == PlatformType.MAC) { + for (final int variant : VARIANTS) { + list.add( + new String[] { + "Launchkey MK4 %d DAW Out".formatted(variant), "Launchkey MK4 %d MIDI Out".formatted(variant) + }, new String[] { + "Launchkey MK4 %d DAW In".formatted(variant), "Launchkey MK4 %d MIDI In".formatted(variant) + }); + } + } else if (platformType == PlatformType.LINUX) { + for (final int variant : VARIANTS) { + list.add( + new String[] { + "Launchkey MK4 %d Launchkey".formatted(variant), + "Launchkey MK4 %d Launchkey #2".formatted(variant) + }, new String[] { + "Launchkey MK4 %d Launchkey".formatted(variant), + "Launchkey MK4 %d Launchkey #2".formatted(variant) + }); + } + } + } + + @Override + public LaunchkeyMk4Extension createInstance(final ControllerHost host) { + return new LaunchkeyMk4Extension(this, host, false); + } + +} From a71a66f48d873c6071c242b9341e2dd021529544 Mon Sep 17 00:00:00 2001 From: ericahrens Date: Mon, 15 Jun 2026 19:35:21 +0200 Subject: [PATCH 3/6] NKS remove uneeded function --- .../komplete/KompleteKontrolExtension.java | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/KompleteKontrolExtension.java b/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/KompleteKontrolExtension.java index a5b1a095..a0ba3b77 100644 --- a/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/KompleteKontrolExtension.java +++ b/src/main/java/com/bitwig/extensions/controllers/nativeinstruments/komplete/KompleteKontrolExtension.java @@ -3,7 +3,6 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import com.bitwig.extension.api.Color; @@ -14,9 +13,6 @@ import com.bitwig.extension.controller.api.ControllerHost; import com.bitwig.extension.controller.api.CursorRemoteControlsPage; import com.bitwig.extension.controller.api.CursorTrack; -import com.bitwig.extension.controller.api.Device; -import com.bitwig.extension.controller.api.DeviceBank; -import com.bitwig.extension.controller.api.DeviceMatcher; import com.bitwig.extension.controller.api.DocumentState; import com.bitwig.extension.controller.api.HardwareButton; import com.bitwig.extension.controller.api.HardwareElement; @@ -267,7 +263,6 @@ protected void initTrackBank() { instId.name().addValueObserver(id -> midiProcessor.registerNksParam(deviceType, id)); } } - //initNksDiscovery(viewControl); mainLayer.bindPressed(controlElements.getMuteSelectedButton(), cursorTrack.mute().toggleAction()); mainLayer.bindPressed(controlElements.getSoloSelectedButton(), cursorTrack.solo().toggleAction()); @@ -282,21 +277,6 @@ protected void initTrackBank() { } } - private void initNksDiscovery(final CursorTrack cursorTrack) { - final DeviceBank nksDiscoverBank = cursorTrack.createDeviceBank(1); - final DeviceMatcher matcher = getHost().createOrDeviceMatcher(Arrays.stream(NksDevice.values()) // - .map(type -> type.createMatcher(getHost())) // - .toArray(DeviceMatcher[]::new)); - - nksDiscoverBank.setDeviceMatcher(matcher); - final Device nksDevice = nksDiscoverBank.getDevice(0); - for (final NksDevice deviceType : NksDevice.values()) { - final SpecificPluginDevice specDevice = deviceType.createSpecDevice(nksDevice); - final Parameter instId = specDevice.createParameter(deviceType.getParamOffset()); - instId.name().addValueObserver(name -> midiProcessor.registerNksParam(deviceType, name)); - } - } - private void handleTrackScrollChanged(final int pos) { midiProcessor.refreshSelectedColor(); } From 3d91017c211392faf868aed2521bba44dd914bdb Mon Sep 17 00:00:00 2001 From: ericahrens Date: Mon, 15 Jun 2026 20:15:55 +0200 Subject: [PATCH 4/6] Fix Arm/Select Display switcharoo bug --- .../launchkey_mk4/LaunchkeyMk4Extension.java | 12 +++++------ .../launchkey_mk4/LaunchkeyMk4Type.java | 14 ++++++++++++- .../novation/launchkey_mk4/MidiProcessor.java | 20 ++++++------------- .../novation/launchkey_mk4/TrackControl.java | 4 ++-- .../LaunchkeyMiniMk4ExtensionDefinition.java | 3 ++- .../LaunchkeyMk4ExtensionDefinition.java | 3 ++- 6 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/LaunchkeyMk4Extension.java b/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/LaunchkeyMk4Extension.java index a4594ee2..4105bc2a 100644 --- a/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/LaunchkeyMk4Extension.java +++ b/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/LaunchkeyMk4Extension.java @@ -26,7 +26,7 @@ public class LaunchkeyMk4Extension extends ControllerExtension { private HardwareSurface surface; private Layer mainLayer; private Layer shiftLayer; - private final boolean isMini; + private final LaunchkeyMk4Type type; private MidiProcessor midiProcessor; private SessionLayer sessionLayer; private Layer currentMainModeLayer; @@ -42,9 +42,9 @@ public static void println(final String format, final Object... args) { } public LaunchkeyMk4Extension(final AbstractLaunchkeyMk4ExtensionDefinition definition, final ControllerHost host, - final boolean miniVersion) { + final LaunchkeyMk4Type type) { super(definition, host); - this.isMini = miniVersion; + this.type = type; } @Override @@ -53,7 +53,7 @@ public void init() { final ControllerHost host = diContext.getService(ControllerHost.class); debugHost = host; surface = diContext.getService(HardwareSurface.class); - midiProcessor = new MidiProcessor(host, isMini); + midiProcessor = new MidiProcessor(host, type); diContext.registerService(MidiProcessor.class, midiProcessor); mainLayer = diContext.createLayer("MAIN"); @@ -160,7 +160,7 @@ public void initControl(final Context diContext) { mainLayer.bind(hwElements.getMasterSlider(), masterTrack.volume()); - preapareTransport(transport); + prepareTransport(transport); hwElements.getButton(CcAssignments.PLAY).bindPressed(mainLayer, () -> handleRestartPlay(transport)); hwElements.getButton(CcAssignments.PLAY).bindLightOnOff(mainLayer, transport.isPlaying()); @@ -186,7 +186,7 @@ public void initControl(final Context diContext) { undoButton.bindLightOnOff(shiftLayer, application.canRedo()); } - private static void preapareTransport(final Transport transport) { + private static void prepareTransport(final Transport transport) { transport.isPlaying().markInterested(); transport.isMetronomeEnabled().markInterested(); transport.isClipLauncherOverdubEnabled().markInterested(); diff --git a/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/LaunchkeyMk4Type.java b/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/LaunchkeyMk4Type.java index 4261f035..8dc53df1 100644 --- a/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/LaunchkeyMk4Type.java +++ b/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/LaunchkeyMk4Type.java @@ -1,4 +1,16 @@ package com.bitwig.extensions.controllers.novation.launchkey_mk4; -public enum LaunckeyMk4Type { +public enum LaunchkeyMk4Type { + STANDARD((byte) 0x14), + MINI((byte) 0x13); + + private final byte sysExCode; + + LaunchkeyMk4Type(final byte sysExCode) { + this.sysExCode = sysExCode; + } + + public byte getSysExCode() { + return sysExCode; + } } diff --git a/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/MidiProcessor.java b/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/MidiProcessor.java index 990bbecf..6c683ee6 100644 --- a/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/MidiProcessor.java +++ b/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/MidiProcessor.java @@ -21,7 +21,6 @@ import com.bitwig.extensions.framework.time.TimedEvent; public class MidiProcessor { - private static final String DEVICE_INQUIRY = "F0 7E 7F 06 01 F7"; private static final String NOVATION_HEADER = "F0 00 20 29 02 %02X "; private static final byte[] TEXT_CONFIG_COMMAND = {(byte) 0xF0, 0x00, 0x20, 0x29, 0x02, 0x14, 0x04, 0x00, 0x00, (byte) 0xF7}; @@ -30,26 +29,20 @@ public class MidiProcessor { private final MidiOut midiOut; private final NoteInput noteInput; private int blinkCounter = 0; - private final boolean miniVersion; + private final LaunchkeyMk4Type launchkeyType; private final Queue timedEvents = new LinkedList<>(); - private final MidiOut midiOut2; private final List modeListeners = new ArrayList<>(); private final List noteHandlers = new ArrayList<>(); private final String header; - private final int modelIdCode; private final NoteInput padNoteInput; - public MidiProcessor(final ControllerHost host, final boolean mini) { + public MidiProcessor(final ControllerHost host, final LaunchkeyMk4Type type) { this.host = host; - this.miniVersion = mini; - this.modelIdCode = mini ? 0x13 : 0x14; - this.header = NOVATION_HEADER.formatted(modelIdCode); - if (mini) { - TEXT_CONFIG_COMMAND[5] = 0x13; - } + this.launchkeyType = type; + this.header = NOVATION_HEADER.formatted(type.getSysExCode()); + TEXT_CONFIG_COMMAND[5] = type.getSysExCode(); this.midiIn = host.getMidiInPort(0); this.midiOut = host.getMidiOutPort(0); - this.midiOut2 = host.getMidiOutPort(1); padNoteInput = midiIn.createNoteInput("DRUM", "89????", "99????", "A?????"); @@ -70,7 +63,7 @@ public String getSysexHeader() { } public boolean isMiniVersion() { - return miniVersion; + return launchkeyType == LaunchkeyMk4Type.MINI; } public void addModeListener(final ModeListener listener) { @@ -78,7 +71,6 @@ public void addModeListener(final ModeListener listener) { } private void handleMidiIn(final int statusByte, final int data1, final int data2) { - final int cmd = statusByte & 0xF0; if (statusByte == 0xB6) { if (data1 == 0x1E) { fireMode(ModeType.ENCODER, data2); diff --git a/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/TrackControl.java b/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/TrackControl.java index 3b2403ea..424cd22c 100644 --- a/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/TrackControl.java +++ b/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/TrackControl.java @@ -97,11 +97,11 @@ private void toggleMode() { if (this.mode == Mode.ARM) { this.currentLayer = selectLayer; this.mode = Mode.SELECT; - displayControl.show2Line("Fader Mode", "Arm"); + displayControl.show2Line("Fader Mode", "Select"); } else { this.currentLayer = armLayer; this.mode = Mode.ARM; - displayControl.show2Line("Fader Mode", "Select"); + displayControl.show2Line("Fader Mode", "Arm"); } this.currentLayer.setIsActive(true); } diff --git a/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/definition/LaunchkeyMiniMk4ExtensionDefinition.java b/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/definition/LaunchkeyMiniMk4ExtensionDefinition.java index c35f6af7..706b461f 100644 --- a/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/definition/LaunchkeyMiniMk4ExtensionDefinition.java +++ b/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/definition/LaunchkeyMiniMk4ExtensionDefinition.java @@ -7,6 +7,7 @@ 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 LaunchkeyMiniMk4ExtensionDefinition extends AbstractLaunchkeyMk4ExtensionDefinition { private static final UUID DRIVER_ID = UUID.fromString("ef68e909-d5f1-4557-8526-2ce6978fabcc"); @@ -76,7 +77,7 @@ public void listAutoDetectionMidiPortNames(final AutoDetectionMidiPortNamesList @Override public LaunchkeyMk4Extension createInstance(final ControllerHost host) { - return new LaunchkeyMk4Extension(this, host, true); + return new LaunchkeyMk4Extension(this, host, LaunchkeyMk4Type.MINI); } } diff --git a/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/definition/LaunchkeyMk4ExtensionDefinition.java b/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/definition/LaunchkeyMk4ExtensionDefinition.java index 6f70187e..c5f48259 100644 --- a/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/definition/LaunchkeyMk4ExtensionDefinition.java +++ b/src/main/java/com/bitwig/extensions/controllers/novation/launchkey_mk4/definition/LaunchkeyMk4ExtensionDefinition.java @@ -7,6 +7,7 @@ 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 LaunchkeyMk4ExtensionDefinition extends AbstractLaunchkeyMk4ExtensionDefinition { private static final UUID DRIVER_ID = UUID.fromString("ef68e909-d5f1-4557-8526-2ce6978cabaa"); @@ -73,7 +74,7 @@ public void listAutoDetectionMidiPortNames(final AutoDetectionMidiPortNamesList @Override public LaunchkeyMk4Extension createInstance(final ControllerHost host) { - return new LaunchkeyMk4Extension(this, host, false); + return new LaunchkeyMk4Extension(this, host, LaunchkeyMk4Type.STANDARD); } } From 603f2d183dd99b7a2501258b4468fe2dd0d66838 Mon Sep 17 00:00:00 2001 From: ericahrens Date: Wed, 17 Jun 2026 17:52:01 +0200 Subject: [PATCH 5/6] LK Mk4 88 key added --- .../LaunchkeyMk488ExtensionDefinition.java | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) 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 index 6f70187e..3afacf43 100644 --- 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 @@ -7,19 +7,20 @@ 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 LaunchkeyMk4ExtensionDefinition extends AbstractLaunchkeyMk4ExtensionDefinition { - private static final UUID DRIVER_ID = UUID.fromString("ef68e909-d5f1-4557-8526-2ce6978cabaa"); +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"; + return "Launchkey Mk4 88"; } @Override public String getHardwareModel() { - return "Launchkey Mk4"; + return "Launchkey Mk4 88"; } @Override @@ -40,11 +41,11 @@ public void listAutoDetectionMidiPortNames(final AutoDetectionMidiPortNamesList for (int i = 0; i < 4; i++) { list.add( new String[] { - "MIDIIN2 (Launchkey MK4 %d MIDI%s".formatted(variant, (i & 0x1) != 0 ? ")" : ""), - "Launchkey MK4 %d MIDI".formatted(variant) + "MIDIIN2 (Launchkey MK4 88 %d MIDI%s".formatted(variant, (i & 0x1) != 0 ? ")" : ""), + "Launchkey MK4 88 %d MIDI".formatted(variant) }, new String[] { - "MIDIOUT2 (Launchkey MK4 %d MIDI%s".formatted(variant, (i & 0x2) != 0 ? ")" : ""), - "Launchkey MK4 %d MIDI".formatted(variant) + "MIDIOUT2 (Launchkey MK4 88 %d MIDI%s".formatted(variant, (i & 0x2) != 0 ? ")" : ""), + "Launchkey MK4 88 %d MIDI".formatted(variant) }); } } @@ -52,20 +53,22 @@ public void listAutoDetectionMidiPortNames(final AutoDetectionMidiPortNamesList for (final int variant : VARIANTS) { list.add( new String[] { - "Launchkey MK4 %d DAW Out".formatted(variant), "Launchkey MK4 %d MIDI Out".formatted(variant) + "Launchkey MK4 88 %d DAW Out".formatted(variant), + "Launchkey MK4 88 %d MIDI Out".formatted(variant) }, new String[] { - "Launchkey MK4 %d DAW In".formatted(variant), "Launchkey MK4 %d MIDI In".formatted(variant) + "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 %d Launchkey".formatted(variant), - "Launchkey MK4 %d Launchkey #2".formatted(variant) + "Launchkey MK4 88 %d Launchkey".formatted(variant), + "Launchkey MK4 88 %d Launchkey #2".formatted(variant) }, new String[] { - "Launchkey MK4 %d Launchkey".formatted(variant), - "Launchkey MK4 %d Launchkey #2".formatted(variant) + "Launchkey MK4 88 %d Launchkey".formatted(variant), + "Launchkey MK4 88 %d Launchkey #2".formatted(variant) }); } } @@ -73,7 +76,7 @@ public void listAutoDetectionMidiPortNames(final AutoDetectionMidiPortNamesList @Override public LaunchkeyMk4Extension createInstance(final ControllerHost host) { - return new LaunchkeyMk4Extension(this, host, false); + return new LaunchkeyMk4Extension(this, host, LaunchkeyMk4Type.STANDARD); } } From 96dc8741a1d2023aac37e34b494c9a3523dcc6ab Mon Sep 17 00:00:00 2001 From: ericahrens Date: Mon, 29 Jun 2026 08:28:24 +0200 Subject: [PATCH 6/6] Softube DAW Control fix initial connect on startup --- .../console1/ConsoleMidiProcessor.java | 35 ++++++++---- .../Console1ExtensionDefinition.java | 2 +- ...ubeDawControlMultiExtensionDefinition.java | 57 +++++++++++++++---- 3 files changed, 71 insertions(+), 23 deletions(-) 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++) {