Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
b65bde9
DI added Tags for Components
ericahrens Oct 26, 2025
eb3d338
Launchkontrol Mk3 New Produkt
ericahrens Oct 26, 2025
6297aa3
Arturia Keylab Mk3 Stop all scene hold
ericahrens Oct 26, 2025
46b5930
Novation Definition changed
ericahrens Oct 26, 2025
d462730
Merge branch 'main' of https://github.com/ericahrens/bitwig-extensions
ericahrens Nov 2, 2025
5528606
Launchcontrol Mk3 - Vast Improvements and Layering and Binding
ericahrens Nov 9, 2025
4d355ac
Launchcontrol Mk4 latest fixes
ericahrens Nov 23, 2025
c2f73bb
Added Mpk IV
ericahrens Dec 13, 2025
14e7e90
Akai MPK mini IV Clip Control added and Controls Mapped
ericahrens Dec 17, 2025
a4527f8
Merge branch 'main' of https://github.com/ericahrens/bitwig-extensions
ericahrens Dec 17, 2025
97fb56f
Merge branch 'main' of https://github.com/ericahrens/bitwig-extensions
ericahrens Dec 17, 2025
52d9b50
First Display implementations
ericahrens Dec 19, 2025
775760c
Merge branch 'main' of https://github.com/ericahrens/bitwig-extensions
ericahrens Dec 19, 2025
26687ee
MPK4 Display Used
ericahrens Dec 25, 2025
5bfe746
MPK4 Drum Pad Mode added
ericahrens Dec 27, 2025
350bd6e
MPK4 Menus added
ericahrens Jan 9, 2026
a567756
Akai MPK mini IV Improve Remotes and other details
ericahrens Jan 12, 2026
2f93a13
Akai MPK Mini Iv Release Fixes
ericahrens Jan 17, 2026
18954af
Mpk Mk4 Version 1.0
ericahrens Jan 20, 2026
f50a178
Allen & Heath Xone K3 added
ericahrens Jan 21, 2026
39ed649
Remove Novation Launchcontrol Mk3 for now
ericahrens Jan 22, 2026
8ccf88a
Launchkontrol XL back in
ericahrens Jan 22, 2026
1d1109b
LCXL3 Display Fixes
ericahrens Feb 6, 2026
8a47af7
LC3 General Fixes
ericahrens Feb 7, 2026
a10be8b
Merge branch 'main' of https://github.com/bitwig/bitwig-extensions
ericahrens Feb 7, 2026
0b017c6
Minilab Fixes
ericahrens Feb 8, 2026
ec13bfa
Minilab Mac Midi Ports
ericahrens Feb 8, 2026
0438707
Minilab better Port Detection
ericahrens Feb 10, 2026
86eefec
Minilab better Port Detection
ericahrens Feb 10, 2026
afa96d4
Merge branch 'main' of https://github.com/ericahrens/bitwig-extensions
ericahrens Feb 10, 2026
a9e88a1
Launchcontrol Update
ericahrens Feb 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,43 +9,43 @@ public class ArturiaModeLayer extends Layer {
private final MiniLab3Extension driver;
private final NoteInput noteInput;
private final Integer[] noteTable = new Integer[128];

public ArturiaModeLayer(final MiniLab3Extension driver) {
super(driver.getLayers(), "ARTURIA_PAD");
this.driver = driver;
noteInput = driver.getMidiIn().createNoteInput("MIDI_", "89????", "99????", "A9????");
noteInput.setShouldConsumeEvents(false);
Arrays.fill(noteTable, -1);
}

private void applyNotes() {
final RgbButton[] aButtons = driver.getPadBankAButtons();
final RgbButton[] bButtons = driver.getPadBankBButtons();
for (final RgbButton button : aButtons) {
final MinilabRgbButton[] aButtons = driver.getPadBankAButtons();
final MinilabRgbButton[] bButtons = driver.getPadBankBButtons();
for (final MinilabRgbButton button : aButtons) {
noteTable[button.getNoteValue()] = button.getNoteValue();
}
for (final RgbButton button : bButtons) {
for (final MinilabRgbButton button : bButtons) {
noteTable[button.getNoteValue()] = button.getNoteValue();
}
noteInput.setKeyTranslationTable(noteTable);
}

protected void resetNotes() {
Arrays.fill(noteTable, -1);
noteInput.setKeyTranslationTable(noteTable);
}

@Override
protected void onActivate() {
super.onActivate();
applyNotes();
}


@Override
protected void onDeactivate() {
super.onDeactivate();
resetNotes();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.Arrays;

import com.bitwig.extension.controller.api.BooleanValue;
import com.bitwig.extension.controller.api.ClipLauncherSlot;
import com.bitwig.extension.controller.api.MultiStateHardwareLight;
import com.bitwig.extension.controller.api.Track;
Expand All @@ -10,35 +11,38 @@

public class ClipLaunchingLayer extends Layer {

private final RgbLightState[] sceneSlotColors = new RgbLightState[8];
private final RgbLightState[] slotColors = new RgbLightState[8];
private final BooleanValue clipLauncherOverdub;
private final long[] downTime = new long[8];
private final Layer sceneLaunchingLayer; // clips in selected scene
private final TrackBank trackBank;
private final MiniLab3Extension driver;
private int blinkState;
private long clipsStopTiming = 800;
private final BooleanValue transportPlaying;

public ClipLaunchingLayer(final MiniLab3Extension driver) {
super(driver.getLayers(), "CLIP LAUNCHER");
this.driver = driver;
clipLauncherOverdub = driver.getTransport().isClipLauncherOverdubEnabled();
transportPlaying = driver.getTransport().isPlaying();
clipLauncherOverdub.markInterested();
transportPlaying.markInterested();

sceneLaunchingLayer = new Layer(driver.getLayers(), "PER_SCENE_LAUNCHER");

Arrays.fill(sceneSlotColors, RgbLightState.OFF);
Arrays.fill(slotColors, RgbLightState.OFF);
Arrays.fill(downTime, -1);

final RgbButton[] buttons = driver.getPadBankAButtons();

trackBank = driver.getViewTrackBank();


final MultiStateHardwareLight bankLight =
driver.getSurface().createMultiStateHardwareLight("CLIP_LAUNCH_LIGHTS");
bankLight.state().onUpdateHardware(driver::updateBankState);
final MinilabRgbButton[] buttons = driver.getPadBankAButtons();

final RgbBankLightState.Handler bankLightHandler = new RgbBankLightState.Handler(PadBank.BANK_A, buttons);
sceneLaunchingLayer.bindLightState(bankLightHandler::getBankLightState, bankLight);
this.bindLightState(bankLightHandler::getBankLightState, bankLight);

setupHorizontalLaunching(driver, buttons);
setupHorizontalLaunching(driver);

driver.getPadBank().addValueObserver((this::changePadBank));
}
Expand All @@ -64,31 +68,31 @@ private void changePadBank(final PadBank newValue) {
trackBank.setShouldShowClipLauncherFeedback(newValue == PadBank.BANK_A);
}

private void setupHorizontalLaunching(final MiniLab3Extension driver, final RgbButton[] buttons) {
driver.getViewTrackBank().setShouldShowClipLauncherFeedback(driver.getPadBank().get() == PadBank.BANK_A);
for (int i = 0; i < MiniLab3Extension.NUM_PADS_TRACK; i++) {
final int index = i;
final Track track = driver.getViewTrackBank().getItemAt(i);
final ClipLauncherSlot slot = track.clipLauncherSlotBank().getItemAt(0);
prepareSlot(slot);
private void setupHorizontalLaunching(final MiniLab3Extension driver) {
final MinilabRgbButton[] buttons = driver.getPadBankAButtons();
final TrackBank trackBank = driver.getViewTrackBank();
trackBank.setShouldShowClipLauncherFeedback(driver.getPadBank().get() == PadBank.BANK_A);
for (int i = 0; i < trackBank.getSizeOfBank(); i++) {
final Track track = trackBank.getItemAt(i);
track.arm().markInterested();
for (int j = 0; j < trackBank.sceneBank().getSizeOfBank(); j++) {
final int buttonIndex = j * 4 + i;
final ClipLauncherSlot slot = track.clipLauncherSlotBank().getItemAt(j);
prepareSlot(slot, buttonIndex);
final MinilabRgbButton button = buttons[buttonIndex];
button.bindPressed(this, pressed -> handleSlotSelected(buttonIndex, track, slot, pressed));
button.bindLightState(this, () -> getLightState(buttonIndex, track, slot));
}
track.isQueuedForStop().markInterested();

slot.color().addValueObserver((r, g, b) -> sceneSlotColors[index] = RgbLightState.getColor(r, g, b));
final RgbButton button = buttons[i];
button.bindPressed(sceneLaunchingLayer, pressed -> handleSlotSelected(index, track, slot, pressed),
() -> getLightState(index, track, slot));
}
}

public void navigateScenes(final int direction) {
trackBank.sceneBank().scrollBy(direction);
}

public void launchScene() {
trackBank.sceneBank().getScene(0).launch();
}

private void prepareSlot(final ClipLauncherSlot cs) {
private void prepareSlot(final ClipLauncherSlot cs, final int index) {
cs.color().addValueObserver((r, g, b) -> slotColors[index] = RgbLightState.getColor(r, g, b));
cs.exists().markInterested();
cs.hasContent().markInterested();
cs.isPlaybackQueued().markInterested();
Expand All @@ -102,9 +106,9 @@ private void prepareSlot(final ClipLauncherSlot cs) {
public void notifyBlink(final int blinkState) {
this.blinkState = blinkState;
final long time = System.currentTimeMillis();
for (int i = 0; i < 8; i++) {
for (int i = 0; i < trackBank.getSizeOfBank(); i++) {
if (downTime[i] != -1 && (time - downTime[i]) > clipsStopTiming) {
final Track track = driver.getViewTrackBank().getItemAt(i);
final Track track = trackBank.getItemAt(i);
track.stop();
}
}
Expand All @@ -126,7 +130,10 @@ private void handleSlotSelected(final int slotIndex, final Track track, final Cl
}

RgbLightState getLightState(final int index, final Track track, final ClipLauncherSlot slot) {
final RgbLightState color = sceneSlotColors[index];
final RgbLightState color = slotColors[index];
if (!slot.exists().get()) {
return RgbLightState.OFF;
}
if (slot.hasContent().get()) {
if (slot.isPlaybackQueued().get()) {
return blinkFast(color.getDarker(), color.getBrighter());
Expand All @@ -140,13 +147,30 @@ RgbLightState getLightState(final int index, final Track track, final ClipLaunch
if (slot.isRecording().get()) {
return blinkSlow(color, RgbLightState.RED);
}
if (slot.isPlaying().get() && track.isQueuedForStop().get()) {
return blinkSlow(RgbLightState.GREEN, color.getDarker());
}
if (slot.isPlaying().get()) {
return color.getBrighter();
if (clipLauncherOverdub.get() && track.arm().get()) {
return blinkSlow(RgbLightState.RED, color.getDarker());
} else {
if (transportPlaying.get()) {
return blinkSlow(RgbLightState.GREEN, color.getBrighter());
}
return color.getBrighter();
//return RgbLightState.GREEN;
}
}
return color.getDarker();
}
if (slot.isRecordingQueued().get()) {
return blinkFast(color.getDarker(), RgbLightState.RED);
} else if (track.arm().get()) {
return RgbLightState.RED_DIMMED;
} else if (slot.isPlaybackQueued().get()) {
return blinkFast(RgbLightState.GREEN, RgbLightState.WHITE);
} else if (track.isQueuedForStop().get()) {
return blinkFast(RgbLightState.WHITE, RgbLightState.WHITE_DIMMED);
}
return RgbLightState.OFF;
}
Expand All @@ -168,14 +192,12 @@ private RgbLightState blinkFast(final RgbLightState on, final RgbLightState off)
@Override
protected void onActivate() {
super.onActivate();
sceneLaunchingLayer.activate();
trackBank.setShouldShowClipLauncherFeedback(driver.getPadBank().get() == PadBank.BANK_A);
}

@Override
protected void onDeactivate() {
super.onDeactivate();
sceneLaunchingLayer.deactivate();
trackBank.setShouldShowClipLauncherFeedback(false);
}

Expand Down
Loading
Loading