MPC
This is the main application the user interacts with on MPC devices — the sampler, sequencer and mixer UI. It is the MPC-family counterpart to Engine, but it is not a relative of it: different codebase, different UI toolkit, different command-line parser.
Application Data
Path: /usr/bin/MPC
Everything below was measured against /usr/bin/MPC from the MPC 3.9.1 update image (MPC-3.9.1-Gen1-update.img, HWIDs ACV5/ACV5S/ACV8/ACVA/ACVA2/ACVB/ACVM/ACVR). The binary reports itself as 3.9.1.2 (f3af35cdc95).
Available in firmware for
One image serves the whole family; the .dtb shipped in /boot is what distinguishes the units. Product codes and models read directly from those .dtbs:
Product code | Model | Board |
|---|---|---|
| (generic |
|
| Akai Professional MPC X SE |
|
| (generic |
|
| Akai Professional MPC One |
|
| Akai Professional MPC One+ |
|
| Akai Professional MPC Live Mk 2 |
|
| Akai Professional MPC Key 61 |
|
| Akai Professional MPC Key 37 |
|
Binary Overview
Property | Value |
|---|---|
Format | ELF 32-bit PIE, |
Size | ~108 MB ( |
Image base |
|
|
|
|
|
|
|
Real functions | 91,459 (per |
Stripped | Yes; 9,266 |
Debug link |
|
For scale, this is roughly 2.5× the code and 2× the functions of Engine at the same firmware generation. The same caveats in Engine Ghidra Analysis apply — stock Ghidra auto-analysis finds a fraction of the functions, and .ARM.exidx is the way to recover the rest.
Internal codename: acvs-sme0
Debug paths left in the binary expose the build tree:
which matches the Yocto build tag in /etc/az01-release: jenkins-ACVS-MPC3-SME0-MPC3-Yocto-563. So ACVS is the platform, SME0/MPC3 the product generation. Compare planck for Engine.
Embedded frameworks
Component | Evidence |
|---|---|
JUCE |
|
Pure Data | 179 |
sentry-native + Crashpad | 129 |
SQLite |
|
libcurl |
|
The Pd options are worth flagging because a naive scan for --prefixed strings in this binary turns up well over a hundred of them; almost all belong to embedded Pd, to an ARM CPU-feature table (-neon, -vfp4, -fp16, -sha2) or to Crashpad (--no-rate-limit, --shared-client-connection). They are not MPC's own command line.
Command-line arguments
MPC parses argv itself — there is no QCommandLineParser equivalent. The convention is --longName with a single-dash short alias, which is the opposite of Engine, where long names take a single dash.
Its built-in --help output advertises only six options:
There are fifteen in the binary. All fifteen are referenced from the argument-matching code, so none of them is inert — unlike Engine, where 11 of 44 registered options are never read. That difference is structural: MPC compares argv against the literal directly, so the literal existing is the read.
Option | Short | Value | Description / observed effect | In |
|---|---|---|---|---|
|
| Prints the usage text above | yes | |
|
| Prints the version | yes | |
| path | Settings file to use | yes | |
| path | JSON file of extra Sentry tags; errors include | yes | |
| path | Purpose not established | yes | |
|
|
| Update from the given URL | yes |
|
| Opens the | no | |
| Opens the | no | ||
| Opens the | no | ||
|
| path |
| no |
|
| path | Script library path | no |
|
| path |
| no |
|
|
| no | |
|
| path |
| no |
|
|
| no |
Nine of the fifteen are undocumented, and the scripting group (--script, --scriptLibs, --scriptOutputPath, --terminateOnFinish) plus --project and --skipStartupChecks are the interesting ones — together they amount to an unattended/automation mode.
Two separate matching sites handle these, which is why the literals sit in two clusters in .rodata:
Site | Options handled |
|---|---|
| everything except the two below |
|
|
Device identity
MPC does not hard-code which unit it is; it reads that at runtime.
Datum | Source | Populated by |
|---|---|---|
Product code |
| static, compiled into the |
Serial number |
| U-Boot at runtime — absent from every shipped |
The product code is declared in the DTS source, e.g. inmusic,product-code = "ACV5S"; in rk3288-az01-acv5s.dts. serial-number appears in none of the 14 .dtbs in /boot and in none of the DTS sources, so the node exists only because the bootloader creates it — the usual Rockchip pattern of filling it from OTP/eFuse. On an emulated guest it is there only if whatever replaces U-Boot fabricates it.
Reads go through libaz0x-info.so rather than raw open() alone: MPC imports az0x_info_get, az0x_info_datum_at/_key/_value/_category and az0x_info_category_name. Only MPC, /usr/bin/az0x-info and /usr/bin/az01-info use that API. The library exposes keyed data well beyond identity:
serial,serial-sanitized,product-code,board,bootloader,platform,hardware,secure-bootcpuid,cpuid-sanitized— from the RK3288 eFuse (/sys/devices/platform/ffb10000.efuse,ffb40000.efuse)emmc-serial,emmc-name,emmc-manfid,emmc-oemid,emmc-prv,emmc-date,emmc-fwrev,emmc-size,emmc-lifetime,emmc-pre-eol-statussd-serial,sd-cid,sd-cid-sanitized, and the samesd-*familytouch-panel,touch-firmware,wireless-chip(it distinguishes AP6255/AP6256/AP6335, and has anAP6255 / AP6256 (ambiguous!)case),usb-hub,gpu-driver,typec,panel
MPC also has a serial write path, separate from reading — ProgramSerialNumber unimplemented!, control_surface.serialnumber_reprogram, com.akaipro.hasTriedProgrammingSerialNumber, and a SerialNumber listener on AcvxHardwareIO. That is a serial held in the control-surface MCU rather than the devicetree one, the same idea as midifirmup's WriteSerialNumber in MIDI Devices. The unimplemented! string suggests at least one branch is unfinished.
Recognised product codes
The product code read from the device tree is matched against a fixed table of 26 entries at 0x068b3898 (.data.rel.ro.local, stride 0x50) — the AcvxHardware::Type enum. Verified entry layout:
Offset | Meaning |
|---|---|
|
|
|
|
|
|
|
|
| small integers, presumably capability flags |
idx | Code | id | Display name | Family |
|---|---|---|---|---|
0 |
| — | (no name — the fallback) | — |
1 |
|
| MPC Renaissance |
|
2 |
|
| MPC Studio |
|
3 |
|
| MPC Element |
|
4 |
|
| MPC X |
|
5 |
|
| MPC X SE |
|
6 |
|
| (name slot holds the code) |
|
7 |
|
| MPC Touch |
|
8 |
|
| MPC Live |
|
9 |
|
| MPC Studio Black |
|
10 |
|
| MPC One |
|
11 |
|
| MPC One+ |
|
12 |
|
| MPC One |
|
13 |
|
| MPC Live Mk II |
|
14 |
|
| MPC XL |
|
15 |
|
| MPC Studio 2 |
|
16 |
|
| MPC Live III |
|
17 |
|
| MPC Key 61 |
|
18 |
|
| (name slot holds |
|
19 |
|
| MPC Key 37 |
|
20 |
|
| MPC Key 37 |
|
21 |
|
| Force |
|
22 |
|
| Force |
|
23 |
|
| (name slot holds the code) |
|
24 |
|
| Alesis Prime Drum Module |
|
25 |
|
| Alesis Core Drum Module |
|
Three things the table shows beyond the codes themselves:
It spans product lines.
ADA2/ADA2S(Force) andLDMD/LDMF(Alesis drum modules) sit in the MPC binary's own table, so one hardware abstraction covers MPC, Force and Alesis.It spans two hardware eras.
ACV0,ACV1,ACV3,ACV7andACV9are the desktop-controller generation — USB controllers driven by desktop MPC software rather than standalone Linux units — so some codes could never appear ininmusic,product-codeon a standalone device.Three entries have no real display name:
ACV6,ACVM2andACVKcarry a code string in the name slot.ACVA3andACVR2reuse the names ofACVAandACVR.
How an unrecognised code behaves
The lookup is a plain linear search that skips entry 0 and returns 0 when nothing matches:
Address | Role |
|---|---|
| reads |
| linear search over entries 1–25; |
| accessor: |
Entry 0 is "none" with a NULL name pointer, so an unrecognised or missing product code makes the UI render the hardware name as <Unknown> — and the info screen's firmware heading, which is the hardware name plus the literal " Firmware", becomes <Unknown> Firmware.
The numeric id at +0x04 is not part of the match; the search compares the code string. The id is also not unique — ACV5/ACV5S share 0x013a, ACVF/LDMD share 0x014a, and ACVM/LDMF share 0x014b — so while it looks like a USB product ID, that has not been confirmed. Everything in this section was read from the 3.9.1 binary and has not been diffed against other versions.
Telemetry
MPC has two independent channels.
Channel | Destination | Notes |
|---|---|---|
Sentry |
| Crash reporting. Same Sentry org ( |
PostHog | not present in the image | Product analytics — see below |
Crash reporting is Crashpad-backed: compiled into MPC, plus a standalone /usr/bin/crashpad_handler that MPC launches with --no-rate-limit and --shared-client-connection. No separate minidump upload URL appears in the image, so minidumps go to the same Sentry host.
The analytics channel is Analytics::PostHog::Session/Analytics::PostHog::UserIdentity, driven through Analytics::CurlHttpSession, with settings keys AnalyticsSettings.enabled, AnalyticsSettings.PostHog.opaqueId, AnalyticsSettings.PostHog.userEmail and AnalyticsSettings.PostHog.userId. Note that this identifies the user by email — it is not anonymous.
Whether analytics is enabled by default could not be determined: AnalyticsSettings.enabled exists only inside the binary, with no shipped settings file, so the default is compiled in.
Other outbound hosts
api.inmusicbrands.com, auth.profile.inmusicbrands.com, profile.inmusicbrands.com, device.inmusicbrands.com (account, auth and device services), feedback.akaipro.com/feedback/create/ (user-initiated feedback, over plain HTTP), plus store and download links to thempcstore.com, akaipro.com, splice.com and 2getheraudio.com.
/usr/share/Splice/splicesync is a separate 5 MiB Go binary that MPC launches, bundling github.com/getsentry/sentry-go v0.11.0. It has no DSN compiled in and nothing in the rootfs sets SENTRY_DSN, so its Sentry is inert unless MPC injects one into its environment.
Related Files
MPC covers the operating system this application ships on.
Engine is the equivalent application on the Denon DJ side; the two share a Sentry organisation and an
az0xbase distribution but no code.Engine Ghidra Analysis documents the
.ARM.exidxrecovery technique, which this binary needs just as much.Test App covers the separate factory test application.