akai_standalone_remap, image 1 from its README
Firmware

akai_standalone_remap

Hype24/100

Remap hardware buttons on standalone Akai MPC / Force: any screen from any button, double taps, long presses, Shift layers (LD_PRELOAD MIDI shim)

akai_standalone_remap is custom firmware for the Akai Professional MPC Live, by @mmiroshnikov. Open source under MIT, 3 stars on GitHub.

forAkai Professional MPC Live·by@mmiroshnikov

Unclaimed. Is this yours? Sign in with GitHub as @mmiroshnikov to claim it.

Downloads
0
Stars
3
Forks
4
Commits
7
Last commit
Get the source

No release files yet. Build from source.

MIT· mmiroshnikov/akai_standalone_remap·downloads come from the creator’s GitHub releases

7
Commits
0
Releases
7 commits and 0 releases in the last year
Activity · last 12 months

akai_standalone_remap

MPC Live: Pad Bank A–D open the top row of the Mode Menu, + and − open the second row

Remap the hardware buttons of standalone Akai MPC / Force devices: open any screen from any button, add double taps, long presses and Shift layers. Tested on a first-generation MPC Live (Hakai, MPC 3.9.1) and an Akai Force (stock firmware 3.9.0).

The devices have no setting for this, so hwremap.so is an LD_PRELOAD shim that sits between the controller and the MPC/Force app. It rewrites the controller's MIDI stream: a press of a chosen button is swallowed and replaced with other buttons, pads or a touchscreen tap. To the app this looks exactly like you did it yourself.

The main trick on MPC: holding Menu and tapping a pad opens the icon in that cell of the 4×4 Mode Menu. So any button can open any screen: put the icon in the menu cell and map the button to "Menu + that pad".

Configs

FileDeviceWhat it does
configs/mpc-live.confMPC LivePad Bank A–D open the top row of the Mode Menu; +, − and their double taps open the second row
configs/force.confForceMixer ×2 = Master; Menu ×2 = Main Mode; Knobs: short = Shift + Knobs, long = Knobs, double = original long press

Install one of them as /sdcard/hwremap.conf on the device.

MPC Live

ButtonOpens (Mode Menu cell)
Pad Bank A–Dtop row, icons 1–4
+second row, icon 1
+ twicesecond row, icon 3
−second row, icon 2
− twicesecond row, icon 4

Rearrange the icons in the Mode Menu to choose what each button opens; it applies right away. Hold Shift for the original function (Shift + +/− changes values). Pad banks are not reachable while the remap is on.

Force

ButtonDoes
Mixer twiceMaster (the first press opens the mixer as usual)
Menu twicetaps the Main Mode icon in the menu
Knobs shortShift + Knobs
Knobs longa plain Knobs press
Knobs twicethe original long press: Knobs held while you hold the button, at least 0.8 s
Shift + Knobsplain Knobs

The Main Mode tap uses screen coordinates from configs/force.conf. If the icon moves, record a new tap (see "Touch coordinates").

How it works

  • The shim hooks snd_rawmidi_open and snd_rawmidi_read and only touches the controller input port whose name contains "Private". Every other MIDI port passes through untouched.
  • Buttons arrive as notes on channel 1: press is 90 nn 7F, release is 90 nn 00. Pads are notes on channel 10. The shim parses the stream properly, including running status, SysEx and realtime bytes, and replaces only the mapped button notes.
  • Injected releases use note-on with velocity 0, like the hardware does. The app ignores note-off for buttons: a Menu "released" with 80 7B .. stays held, and then tapping an icon in the menu opens it instead of letting you drag it.
  • Long presses, delayed taps and minimum holds fire from timers, when no MIDI is arriving. The app reads MIDI from a thread that waits in poll(), so the shim also hooks poll(): it adds a wake pipe and reports the controller port readable while injected bytes are queued.
  • Touch taps are written to the touchscreen input device (/dev/input/event0) as a multitouch down/up, the same events a finger produces.
  • The config is re-read whenever its modification time changes, so edits apply on the next button press.

Config reference

File: /sdcard/hwremap.conf. One rule per line; # starts a comment. Buttons are given by note number, decimal or 0x hex.

log 1                    log every input byte to /tmp/hwremap.log (keep 0 normally)
hold 49                  while this button (Shift) is held, remapped buttons pass through...
held 1 u49 b1 d49        ...unless a "held" rule exists for them: then it runs instead

54 d123 p0x30 u123       on press of 54: Menu down, tap pad 0x30, Menu up
dbl 54 d123 p0x2D u123   second press within dblms runs this instead
dbl 11 b5                with no plain rule, the first press passes through unchanged

tap 1 d49 b1 u49         short press: runs on release
long 1 b1                held past longms: runs at the threshold
                         (without a long rule, the button itself goes through, held)
dbl 1 h1                 with a tap rule: a second press within dblms runs this; the short
                         press waits out the window so it does not fire first

dblms 350                double-tap window, ms
longms 400               long-press threshold, ms
holdms 800               minimum hold for hN, ms
touchms 150              delay before a touch tap, ms

Action tokens:

TokenMeaning
dNbutton N down
uNbutton N up
bNbutton N tap (down + up)
pNpad tap, N is the pad note
hNhold button N down while the source button is held (at least holdms)
tX,Ytouchscreen tap at raw touch coordinates X,Y
xHHraw MIDI byte
mNameMPC: Menu + the pad under mode "Name" (underscores = spaces), looked up in MPC.settings

With a plain rule plus a dbl rule, the first press still runs the plain action right away, so a double tap briefly shows the first screen before the second one.

mName reads the Mode Menu layout from /media/az01-internal/Settings/MPC/MPC.settings. The app writes that file only when it saves preferences or quits, so a moved icon is picked up only after that. Only the 16 cells reachable with Menu + pad work (ModeMenuPage1Slot0..15). Fixed d123 pN u123 rules do not have this delay.

Notes

MPC Live buttons (channel 1):

ButtonNoteButtonNote
Shift49+54
Menu123−55
Main52Pad Bank A35
Next Seq42Pad Bank B36
Pad Bank C37
Pad Bank D38

MPC X buttons that MPC Live also accepts: XYFX 126, Channel Mixer 116, Pad Mixer 115.

MPC pads (channel 10), laid out like the hardware. With Menu held, each pad opens the icon in the same position of the Mode Menu:

pad 13: 0x31   pad 14: 0x37   pad 15: 0x33   pad 16: 0x35    <- menu row 1
pad  9: 0x30   pad 10: 0x2F   pad 11: 0x2D   pad 12: 0x2B    <- menu row 2
pad  5: 0x28   pad  6: 0x26   pad  7: 0x2E   pad  8: 0x2C    <- menu row 3
pad  1: 0x25   pad  2: 0x24   pad  3: 0x2A   pad  4: 0x52    <- menu row 4

Force buttons (channel 1): Navigate 0, Knobs 1, Menu 2, Matrix 3, Note 4, Master 5, Clip 9, Mixer 11, Shift 49. More in TheKikGen's tables (tkgl_midimapper.h).

To find the note of any button, set log 1, press it, and read /tmp/hwremap.log.

Touch coordinates

Record a tap while touching the target on screen, then decode it:

ssh root@<device> 'cat /dev/input/event0 > /tmp/touch.bin'   # tap the target, then Ctrl-C
scp root@<device>:/tmp/touch.bin .
python3 -c "
import struct; d=open('touch.bin','rb').read()
for i in range(0,len(d)-15,16):
    s,us,t,c,v=struct.unpack('<IIHHi',d[i:i+16])
    if t==3 and c in (0x35,0x36): print('xy'[c-0x35], v)"

Build

Cross-compile for the device (armhf, glibc 2.39) and run the host tests (ASan/UBSan), both in Docker:

./build.sh          # -> hwremap.so
./build.sh test

Install

Over SSH as root. Config changes need no restart; a new hwremap.so needs an app restart (systemctl restart acvs), which closes the open project.

MPC (Hakai)

The root filesystem is read-only, and BusyBox has no install.

scp hwremap.so root@<mpc>:/tmp/hwremap.so.new
scp configs/mpc-live.conf root@<mpc>:/sdcard/hwremap.conf.new

ssh root@<mpc>
mv /sdcard/hwremap.conf.new /sdcard/hwremap.conf
systemctl stop acvs
mount -o remount,rw /
cp /tmp/hwremap.so.new /usr/lib/hwremap.so.new && chmod 755 /usr/lib/hwremap.so.new
mv /usr/lib/hwremap.so.new /usr/lib/hwremap.so

First install only: append /usr/lib/hwremap.so to every LD_PRELOAD line of the launcher, keeping a backup:

cp /usr/bin/az01-launch-MPC /usr/bin/az01-launch-MPC.orig-hwremap
sed -i 's#customBufferSizeMPC.so \$CURSOR_SO#customBufferSizeMPC.so /usr/lib/hwremap.so $CURSOR_SO#' /usr/bin/az01-launch-MPC
grep LD_PRELOAD /usr/bin/az01-launch-MPC

Then:

sync; mount -o remount,ro /
systemctl start acvs
grep -c hwremap /proc/$(pidof MPC)/maps  # non-zero = loaded

Force (stock firmware)

No root filesystem changes: the library lives in /data and a systemd drop-in adds it to the app's LD_PRELOAD (/etc is a writable overlay). Keep whatever acvs.service already preloads; on the tested Force that is /usr/lib/libforce_cursor.so (check with systemctl show acvs -p Environment).

scp hwremap.so root@<force>:/tmp/hwremap.so.new
scp configs/force.conf root@<force>:/sdcard/hwremap.conf.new

ssh root@<force>
mkdir -p /data/hwremap /etc/systemd/system/acvs.service.d
mv /tmp/hwremap.so.new /data/hwremap/hwremap.so && chmod 755 /data/hwremap/hwremap.so
mv /sdcard/hwremap.conf.new /sdcard/hwremap.conf
printf '[Service]\nEnvironment="LD_PRELOAD=/usr/lib/libforce_cursor.so /data/hwremap/hwremap.so"\n' \
  > /etc/systemd/system/acvs.service.d/hwremap.conf
systemctl daemon-reload
systemctl restart acvs
grep -c hwremap /proc/$(pidof MPC)/maps  # non-zero = loaded

Uninstall

MPC:

systemctl stop acvs
mount -o remount,rw /
cp /usr/bin/az01-launch-MPC.orig-hwremap /usr/bin/az01-launch-MPC
rm /usr/lib/hwremap.so
sync; mount -o remount,ro /
systemctl start acvs

Force:

rm /etc/systemd/system/acvs.service.d/hwremap.conf
systemctl daemon-reload
systemctl restart acvs
rm -r /data/hwremap

To disable remapping without uninstalling, empty /sdcard/hwremap.conf: with no rules the shim passes everything through.

Limitations

  • On MPC Live no MIDI note opens Clip Matrix or Clip Editor directly. Newer-model buttons like Matrix are not accepted by its firmware, so those screens are reached through the Mode Menu.
  • On MPC Live, injected Shift + Next Seq opened Next Sequence rather than the Shift function. On Force, injected Shift + Knobs is used by configs/force.conf.
  • Nothing tells the shim which screen is showing, so a mapping cannot toggle between two screens.
  • Touch taps use fixed coordinates; they break if the target moves on screen.
  • The Lua --script option does nothing in the release MPC build.