Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 1 addition & 14 deletions bitwig-extensions.iml
Original file line number Diff line number Diff line change
@@ -1,17 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" version="4">
<module version="4">
<component name="ExternalSystem" externalSystem="Maven" />
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_19">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: com.bitwig:extension-api:18" level="project" />
</component>
</module>
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,25 @@
public class MpkMidiProcessor {

private static final String DEVICE_INQUIRY = "F0 7E 7F 06 01 F7";
private static final String DEVICE_RESPONSE_HEADER = "f07e7f0602475d0019";

private static final String IN_SYSEX_HEADER = "f0477f5d";

private static final String IN_MODE_SYSEX = IN_SYSEX_HEADER + "2a00";
private static final String IN_SCREEN_OWNER_SHIP = IN_SYSEX_HEADER + "19000100f7";
private static final String IN_DAW_MODE_SYSEX = IN_SYSEX_HEADER + "190000f7";
private static final String IN_SCREEN_STATUS = IN_SYSEX_HEADER + "190011";
// SYSEX = f0477f5d2d000100f7
// SYSEX = f0477f5d2b000101f7


private static final String AKAI_HEADER = "F0 47 7F 5D ";
private static final String SET_PRESET_DAW = AKAI_HEADER + "2D 00 00 F7";
private static final String SET_SCREEN_OWNER = AKAI_HEADER + "1C 00 01 02 F7";
private static final String SET_SCREEN_FW = AKAI_HEADER + "1C 00 01 00 F7";
private static final String SET_MODE_CLIP = AKAI_HEADER + "2A 00 01 01 F7";
private static final String SET_DISPLAY_STRING = AKAI_HEADER + "10 ";
private static final String SET_DISPLAY_COLOR = AKAI_HEADER + "11 00 02 %02X %02X F7";
private static final String SET_DISPLAY_ROW = AKAI_HEADER + "14 ";
private static final String SET_PAD_NOTES_ENABLED = AKAI_HEADER + "2E 00 01 %s F7";
private static final String DISABLE_PADS = AKAI_HEADER + "2B 00 01 01 F7";
private static String DEVICE_RESPONSE_HEADER;

private static String IN_MODE_SYSEX;
private static String IN_SCREEN_OWNER_SHIP;
private static String IN_DAW_MODE_SYSEX;
private static String IN_SCREEN_STATUS;

private static byte productId;
private static String akaiHeader;
private static String set_preset_daw;
private static String set_screen_owner;
private static String set_screen_fw;
private static String set_mode_clip;
private static String set_display_string;
private static String set_display_color;
private static String set_display_row;
private static String set_pad_notes_enabled;
private static String IN_SYSEX_HEADER;
private static String disable_pads;
private static final byte[] ROW_DISPLAY_COLOR = prepareFixedData(0x14, 9);
private static final byte[] CLEAR_LINE_TEXT = prepareFixedData(0x15, 4);

Expand All @@ -66,6 +63,26 @@ public interface NoteListener {
void playNote(int note, int vel);
}

public void setHeader(final byte productId) {
MpkMidiProcessor.productId = productId;
akaiHeader = "F0 47 7F %02X ".formatted(productId);
set_preset_daw = akaiHeader + "2D 00 00 F7";
set_screen_owner = akaiHeader + "1C 00 01 02 F7";
set_screen_fw = akaiHeader + "1C 00 01 00 F7";
set_mode_clip = akaiHeader + "2A 00 01 01 F7";
set_display_string = akaiHeader + "10 ";
set_display_color = akaiHeader + "11 00 02 %02X %02X F7";
set_display_row = akaiHeader + "14 ";
set_pad_notes_enabled = akaiHeader + "2E 00 01 %s F7";
disable_pads = akaiHeader + "2B 00 01 01 F7";
DEVICE_RESPONSE_HEADER = "f07e7f060247%02x0019".formatted(productId);
IN_SYSEX_HEADER = "f0477f%02x".formatted(productId);
IN_MODE_SYSEX = IN_SYSEX_HEADER + "2a00";
IN_SCREEN_OWNER_SHIP = IN_SYSEX_HEADER + "19000100f7";
IN_DAW_MODE_SYSEX = IN_SYSEX_HEADER + "190000f7";
IN_SCREEN_STATUS = IN_SYSEX_HEADER + "190011";
}

public MpkMidiProcessor(final ControllerHost host, final GlobalStates globalStates) {
this.host = host;
this.globalStates = globalStates;
Expand All @@ -74,6 +91,10 @@ public MpkMidiProcessor(final ControllerHost host, final GlobalStates globalStat
noteInput.setShouldConsumeEvents(false);
this.dawMidiOut = host.getMidiOutPort(0);
this.playMidiIn = host.getMidiInPort(1);
switch (globalStates.getVariant()) {
case MINI -> setHeader((byte) 0x5D);
case MINI_PLUS -> setHeader((byte) 0x03);
}

playMidiIn.createNoteInput("IN", "??????");
this.dawMidiIn.setSysexCallback(this::handleSysEx);
Expand All @@ -85,14 +106,18 @@ private static byte[] prepareFixedData(final int commandId, final int fixedPayLo
data[0] = (byte) 0xF0;
data[1] = (byte) 0x47;
data[2] = (byte) 0x7F;
data[3] = (byte) 0x5D;
data[3] = productId;
data[4] = (byte) commandId;
data[5] = (byte) 0x00;
data[6] = (byte) fixedPayLoad;
data[data.length - 1] = (byte) 0xF7;
return data;
}

public byte getProductId() {
return productId;
}

public void init() {
dawMidiOut.sendSysex(DEVICE_INQUIRY);
}
Expand Down Expand Up @@ -125,7 +150,7 @@ private void handlePing() {
}
final long diff = System.currentTimeMillis() - lastScreenRequest;
if (diff > 5800) {
dawMidiOut.sendSysex(SET_SCREEN_OWNER);
dawMidiOut.sendSysex(set_screen_owner);
lastScreenRequest = now;
}
host.scheduleTask(this::handlePing, 50);
Expand Down Expand Up @@ -163,7 +188,7 @@ private void handleSysEx(final String data) {
}

public void setPadNotesEnabled(final boolean enabled) {
dawMidiOut.sendSysex(SET_PAD_NOTES_ENABLED.formatted(enabled ? "00" : "01"));
dawMidiOut.sendSysex(set_pad_notes_enabled.formatted(enabled ? "00" : "01"));
}

public void addModeChangeListener(final IntConsumer listener) {
Expand All @@ -175,11 +200,11 @@ public void registerMainDisplay(final LineDisplay mainLineDisplay) {
}

private void startConnection() {
dawMidiOut.sendSysex(SET_PRESET_DAW);
dawMidiOut.sendSysex(SET_MODE_CLIP);
dawMidiOut.sendSysex(SET_SCREEN_OWNER);
dawMidiOut.sendSysex(AKAI_HEADER + "2B 00 00 F7");
dawMidiOut.sendSysex(AKAI_HEADER + "3A 00 00 F7");
dawMidiOut.sendSysex(set_preset_daw);
dawMidiOut.sendSysex(set_mode_clip);
dawMidiOut.sendSysex(set_screen_owner);
dawMidiOut.sendSysex(akaiHeader + "2B 00 00 F7");
dawMidiOut.sendSysex(akaiHeader + "3A 00 00 F7");
setPadNotesEnabled(false);
mainDisplay.updateCurrent();
host.scheduleTask(this::handlePing, 50);
Expand All @@ -198,7 +223,7 @@ public void sendMidi(final int status, final int val1, final int val2) {

public void configureLine(final MpkDisplayFont font, final int lineIndex, final int justification,
final Color foreGround, final Color background) {
final String sb = SET_DISPLAY_ROW + "00 09 " //
final String sb = set_display_row + "00 09 " //
+ "%02X ".formatted(font.getValue()) //
+ "%02X ".formatted(lineIndex) //
+ "%02X ".formatted(justification) //
Expand All @@ -213,7 +238,7 @@ public void configureLine(final MpkDisplayFont font, final int lineIndex, final
}

public void setText(final int line, final MpkDisplayFont font, final String text) {
final StringBuilder sb = new StringBuilder(SET_DISPLAY_STRING);
final StringBuilder sb = new StringBuilder(set_display_string);
final String asciiText = StringUtil.toAsciiDisplay(text, 31);
sb.append("%02X ".formatted(0));
final int length = asciiText.length();
Expand All @@ -229,30 +254,25 @@ public void setText(final int line, final MpkDisplayFont font, final String text
}

public void setRowDisplayColor(final ScreenRowState rowState) {
// ROW_DISPLAY_COLOR
// Screen State
}

public void clearLineText(final int lineIndex, final int red, final int green, final int blue) {

}

public void sendSysEx(final byte[] data) {
//MpkMk4ControllerExtension.println(" :: %s", StringUtil.sysExString(data));
dawMidiOut.sendSysex(data);
}

public void setDisplayColor(final int line, final int color) {
dawMidiOut.sendSysex(SET_DISPLAY_COLOR.formatted(line, color));
dawMidiOut.sendSysex(set_display_color.formatted(line, color));
}

public void exit() {
dawMidiOut.sendSysex(SET_SCREEN_FW);
dawMidiOut.sendSysex(set_screen_fw);
setPadNotesEnabled(true);
}

private static int getValue(final String data, final int byteOffset) {
//MpkMk4ControllerExtension.println(" ==> = %s", data);
final int stringOffset = byteOffset * 2;
if (stringOffset < data.length()) {
final String stringValue = data.substring(stringOffset, stringOffset + 2);
Expand All @@ -265,7 +285,6 @@ private static int getValue(final String data, final int byteOffset) {
}

private static int getPayload(final String data) {
//MpkMk4ControllerExtension.println(" ==> = %s", data);
final int high = getValue(data, 5);
final int low = getValue(data, 6);
return high << 7 | low;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package com.bitwig.extensions.controllers.akai.mpkmk4;

import java.util.UUID;

import com.bitwig.extension.api.PlatformType;
import com.bitwig.extension.controller.AutoDetectionMidiPortNamesList;
import com.bitwig.extension.controller.ControllerExtension;
import com.bitwig.extension.controller.ControllerExtensionDefinition;
import com.bitwig.extension.controller.api.ControllerHost;

public class MpkMiniPlusControllerExtensionDefinition extends ControllerExtensionDefinition {

private final static UUID ID = UUID.fromString("3ad31d42-81d1-a603-8719-d0462633d943");

@Override
public String getHardwareVendor() {
return "Akai";
}

@Override
public String getHardwareModel() {
return "MPK Mini Plus";
}

@Override
public int getNumMidiInPorts() {
return 2;
}

@Override
public int getNumMidiOutPorts() {
return 2;
}

@Override
public void listAutoDetectionMidiPortNames(final AutoDetectionMidiPortNamesList list,
final PlatformType platformType) {
if (platformType == PlatformType.WINDOWS) {
list.add(
new String[] {"MIDIIN2 (MPK mini Plus II)", "MPK mini Plus II"},
new String[] {"MIDIOUT2 (MPK mini Plus II)", "MPK mini Plus II"});
} else if (platformType == PlatformType.MAC) {
list.add(
new String[] {"MPK mini Plus II DAW Port", "MPK mini Plus II MIDI Port"},
new String[] {"MPK mini Plus II DAW Port", "MPK mini Plus II MIDI Port"});
} else if (platformType == PlatformType.LINUX) {
list.add(
new String[] {"MPK mini Plus II MPK mini Plus II DAW Por", "MPK mini IV MPK mini IV MIDI Po"},
new String[] {"MPK mini Plus II DAW Port", "MPK mini Plus II MIDI Port"});
}
}

@Override
public ControllerExtension createInstance(final ControllerHost host) {
return new MpkMk4ControllerExtension(this, host, MpkMk4ControllerExtension.Variant.MINI_PLUS);
}

@Override
public String getHelpFilePath() {
return "Controllers/Akai/MPK Mini Mk4.pdf";
}

@Override
public String getName() {
return "MPK Mini IV";
}

@Override
public String getAuthor() {
return "Bitwig";
}

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

@Override
public UUID getId() {
return ID;
}

@Override
public int getRequiredAPIVersion() {
return 24;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public static void println(final String format, final Object... args) {
}

public enum Variant {
MINI_PLUS,
MINI
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.Arrays;

import com.bitwig.extensions.controllers.akai.mpkmk4.MpkMidiProcessor;
import com.bitwig.extensions.controllers.akai.mpkmk4.MpkMk4ControllerExtension;

public class ParameterValues {

Expand All @@ -13,11 +14,12 @@ public class ParameterValues {

public ParameterValues(final MpkMidiProcessor midiProcessor) {
this.midiProcessor = midiProcessor;
MpkMk4ControllerExtension.println(" PID = %s", midiProcessor.getProductId());
Arrays.fill(this.data, (byte) 0x20);
data[0] = (byte) 0xF0;
data[1] = (byte) 0x47;
data[2] = (byte) 0x7F;
data[3] = (byte) 0x5D;
data[3] = midiProcessor.getProductId();
data[4] = (byte) 0x1D;
data[5] = (byte) 0x01;
data[6] = (byte) 0x00;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class TrackSlot {
private long lastReleased;
public static final String NEG_INFINITY = "\"-Infinity\"";
private static final String CONSOLE_1 = "2FF966F3A2DA4112BBB38DC29B336457";
private static final String FLOW_MIXING_SUITE = "74D14512EBBF4BBA9F0E508E4A0EAEC6";

private String trackId;
private final Channel track;
Expand Down Expand Up @@ -363,9 +364,14 @@ private void applyChange(final String key, final Object value) {
}

private void loadPlugin(final String plugin) {
control.println(" LOAD <%s>", plugin);
final long diff = System.currentTimeMillis() - lastConsoleLoadInvocation;
if (diff > 10000) {
track.endOfDeviceChainInsertionPoint().insertVST3Device(CONSOLE_1);
switch (plugin) {
case "Console 1" -> track.endOfDeviceChainInsertionPoint().insertVST3Device(CONSOLE_1);
case "Flow Mixing Suite" -> track.endOfDeviceChainInsertionPoint().insertVST3Device(FLOW_MIXING_SUITE);
}

lastConsoleLoadInvocation = System.currentTimeMillis();
}
}
Expand Down
Loading