open-audiovisual
Search GitHub

01 · Play

MIDI controllers, modeled.

A library of MIDI controllers written as data: every knob, pad and key with the exact MIDI message it sends and the document that number came from. Play them here, plug the real one in and watch it move, or put one in your own page with a single line.

Every music tool makes you map your controller again. Here a controller is modeled once, with sources, for everyone to use.

devices
21
generic layouts
6
controls on the devices
1141
sources cited
75

214 of those controls are marked unverified: the number is our best reading, and learn mode rebinds it in one move.

MINILAB 3MiniLab 3ShiftHoldOct−Oct+PitchModMainKNOBS12345678FADERSS1S2S3S4PADS

Last messageTouch a control: its signal and MIDI message appear here.

Arturia MiniLab 3 48 controls Spec sheet Full screen ↗

Drag knobs and faders · tap pads and keys · Tab and arrow keys work too

02 · Catalog

Every controller in the library

The faceplates on these cards are the component itself, live: drag them. The badges say where each profile's numbers come from.

Show controllers with

Devices 21

Generic layouts 6

For a controller that is not in the library yet: pick the layout closest to it, press Learn, and move your controls in order.

Not on the list?

Open an issue with the brand and model, whether you have the unit and a link to the manual. A profile is one JSON file, so if you would rather write it yourself, the steps are in Add your controller.

03 · Choose

Which one fits what you play?

Every number here is counted from the profile files, so the table cannot disagree with the pages. Press what you need and the table keeps the controllers that have it.

I want
What is on each controller, counted from its profile
ControllerKeysPadsKnobsEncodersFadersButtonsLEDUnverifiedSourcesGood for
AKAI LPD8 (mk2)AKAI Professional –88––– – 8 4 Triggers · Many parameters
AKAI APC mini mk2AKAI Professional –64––917 yes – 5 Triggers · Mixing
AKAI MIDImixAKAI Professional ––24–919 yes – 3 Many parameters · Mixing
AKAI MPK mini mk3AKAI Professional 2588––– – 25 6 Melody · Triggers · Many parameters
AKAI APC40 mkIIAKAI Professional –401621071 yes 40 4 Triggers · Many parameters · Mixing
Arturia MiniLab 3Arturia 258814– – 1 3 Melody · Triggers · Many parameters · Mixing
Arturia KeyStep 37Arturia 37–4––1 – 41 2 Melody
Arturia BeatStepArturia –16–16–– – – 3 Triggers · Many parameters
Behringer X-TOUCH MINIBehringer –––8124 – – 3 Many parameters
DJ TechTools Midi Fighter TwisterDJ TechTools –––16–22 yes 6 2 Many parameters
Korg nanoKONTROL2KORG ––8–835 yes – 4 Many parameters · Mixing
Korg nanoKEY2KORG 25––––2 – 25 3 Melody
Novation Launchpad Mini MK3Novation –64–––16 yes 8 3 Triggers
Novation Launch Control XL (MK2)Novation ––24–824 yes – 5 Many parameters · Mixing
Novation Launch Control XL 3Novation –––24816 – – 7 Many parameters · Mixing
Novation Launchkey Mini MK3Novation 25168––– – 34 6 Melody · Triggers · Many parameters
Novation Launchkey 25 MK4Novation 25168––1 – 8 6 Melody · Triggers · Many parameters
Novation Launchkey 37 MK4Novation 37168––1 – 8 6 Melody · Triggers · Many parameters
Novation Launchpad Pro MK3Novation –64–––41 yes – 2 Triggers
ODD BallODD –34–3– – 10 1 –
OP-1 fieldteenage engineering 24––4–33 – – 2 Melody
Generic 8 knobs + 8 padsGeneric layout –88––– – – 1 Triggers · Many parameters
Generic 8 fadersGeneric layout ––––8– – – 1 Mixing
Generic 16 padsGeneric layout –16–––– – – 1 Triggers
Generic 25-key keyboardGeneric layout 25––––1 – – 1 Melody
Generic 49-key keyboardGeneric layout 49––––1 – – 1 Melody
Generic 61-key keyboardGeneric layout 61––––1 – – 1 Melody

Knobs send an absolute position; encoders turn without end and send steps. A dash means none. Unverified counts the controls whose number is our best reading.

“Good for” is assigned by a rule from the counts: keys → melody; 8 or more pads → triggers; 8 or more knobs or encoders → many parameters; 4 or more faders → mixing. It is a rule of thumb, not a review.

LED feedback

LED feedback is a controller lighting its own pads and buttons. A profile that models it says which note or CC lights each control and which values mean on and off. 8 of the 27 profiles have it:

When one of them is plugged in, OAV sends those messages to its output port as a control changes, and once when the device connects, so the lights can follow what happens on screen.

The other 19 have no LED messages in their profile yet: OAV does not light them, but every control still plays and sends its message. A profile takes an led entry on each control.

04 · Spec sheets

One page for each controller

Every controller has its own page with the full MIDI map, its sources, embed code and the names it gets in p5.js. They are generated from the JSON files at build time, so they cannot drift from what the component plays.

ControllerMakerOn the faceplatePage
AKAI LPD8 (mk2)AKAI Professional8 pads · 8 knobsMIDI map →
AKAI APC mini mk2AKAI Professional64 pads · 9 faders · 17 buttonsMIDI map →
AKAI MIDImixAKAI Professional24 knobs · 9 faders · 19 buttonsMIDI map →
AKAI MPK mini mk3AKAI Professional8 pads · 25 keys · 8 knobs · 2 wheelsMIDI map →
AKAI APC40 mkIIAKAI Professional40 pads · 16 knobs · 2 encoders · 10 faders · 71 buttonsMIDI map →
Arturia MiniLab 3Arturia8 pads · 25 keys · 8 knobs · 1 encoder · 4 faders · 2 touch stripsMIDI map →
Arturia KeyStep 37Arturia37 keys · 4 knobs · 1 button · 2 touch stripsMIDI map →
Arturia BeatStepArturia16 pads · 16 encodersMIDI map →
Behringer X-TOUCH MINIBehringer8 encoders · 1 fader · 24 buttonsMIDI map →
DJ TechTools Midi Fighter TwisterDJ TechTools16 encoders · 22 buttonsMIDI map →
Korg nanoKONTROL2KORG8 knobs · 8 faders · 35 buttonsMIDI map →
Korg nanoKEY2KORG25 keys · 2 buttons · 1 touch stripMIDI map →
Novation Launchpad Mini MK3Novation64 pads · 16 buttonsMIDI map →
Novation Launch Control XL (MK2)Novation24 knobs · 8 faders · 24 buttonsMIDI map →
Novation Launch Control XL 3Novation24 encoders · 8 faders · 16 buttonsMIDI map →
Novation Launchkey Mini MK3Novation16 pads · 25 keys · 8 knobs · 2 touch stripsMIDI map →
Novation Launchkey 25 MK4Novation16 pads · 25 keys · 8 knobs · 1 button · 2 wheelsMIDI map →
Novation Launchkey 37 MK4Novation16 pads · 37 keys · 8 knobs · 1 button · 2 wheelsMIDI map →
Novation Launchpad Pro MK3Novation64 pads · 41 buttonsMIDI map →
ODD BallODD3 pads · 4 knobs · 3 fadersMIDI map →
OP-1 fieldteenage engineering24 keys · 4 encoders · 33 buttonsMIDI map →
Generic 8 knobs + 8 padsGeneric layout8 pads · 8 knobsMIDI map →
Generic 8 fadersGeneric layout8 fadersMIDI map →
Generic 16 padsGeneric layout16 padsMIDI map →
Generic 25-key keyboardGeneric layout25 keys · 1 button · 2 wheelsMIDI map →
Generic 49-key keyboardGeneric layout49 keys · 1 button · 2 wheelsMIDI map →
Generic 61-key keyboardGeneric layout61 keys · 1 button · 2 wheelsMIDI map →

05 · Embed it

Put one in your page

One line of HTML, an iframe, or JavaScript. Choose a device and options: the preview and every snippet below follow.

Layout
Show
Theme

Live preview

AKAI LPD8PADSKNOBSK1K2K3K4K5K6K7K8

The last event, as your code receives it

Play the preview: its control event appears here.
  1. One line, any page

    No import map, no build step. Shadow DOM keeps your page's CSS out and the controller's CSS in.

    html
    <script type="module" src="https://openaudiovisual.com/packages/midi/element.js"></script>
    <oav-controller profile="akai-lpd8" readout></oav-controller>
  2. An iframe

    For places that only take an iframe. Every event arrives as a postMessage; you can send set and ingest back.

    html
    <iframe src="https://openaudiovisual.com/embed/controller/?profile=akai-lpd8&readout"
            width="720" height="216" style="border:0;max-width:100%" allow="midi"
            title="AKAI LPD8 (mk2)"></iframe>
    <script>
      // every control the visitor plays arrives here
      addEventListener('message', (e) => {
        if (e.data?.source !== 'openav' || e.data.type !== 'control') return;
        console.log(e.data.detail.signal, e.data.detail.value);
      });
    </script>
  3. JavaScript, any framework

    createController() is the element without the element: React, Vue, Svelte or plain. It works headless, with no faceplate at all.

    javascript
    import { createController } from 'https://openaudiovisual.com/packages/midi/index.js';
    
    const ctl = createController('akai-lpd8');
    ctl.mount(document.querySelector('#controller'));   // optional: headless works too
    ctl.on('control', (e) => console.log(e.signal, e.value));
    ctl.connectHardware();   // optional: follow the real one (asks for Web MIDI)
  4. Listen to it

    Events bubble and cross the shadow root. Each payload is plain JSON: the control, its value, its signal name, the MIDI message and the bytes.

    javascript
    const el = document.querySelector('oav-controller');
    el.addEventListener('control', (e) => {
      const { id, value, signal, message, source } = e.detail;
      // 'k1'  0..1  'midi/lpd8/k1'  { type: 'cc', ch: 1, cc: 70, value: 64 }  'ui' | 'hardware'
    });
    el.addEventListener('noteon', (e) => console.log(e.detail.note, e.detail.velocity));
    
    await el.ready;
    el.set('k1', 0.5);              // move a control: fires 'control', reaches MIDI out
    el.set('pad1', 1); el.set('pad1', 0);   // strike and release
    el.ingest([0xb0, 70, 64]);   // MIDI from anywhere (a WebSocket, another tab)
  5. Play your DAW with it

    What you play on screen leaves as real MIDI, into Ableton Live, TouchDesigner, Resolume or any software that takes a MIDI input.

    html
    <!-- what you play on this controller → the IAC bus (macOS) → Ableton, TouchDesigner, Resolume -->
    <script type="module" src="https://openaudiovisual.com/packages/midi/element.js"></script>
    <oav-controller profile="akai-lpd8" midi-out="IAC" readout></oav-controller>
    <!-- Windows: midi-out="loopMIDI" · let the visitor pick a port: midi-out="ask" -->

MIDI out to Ableton, TouchDesigner, Resolume

  1. macOS: open Audio MIDI Setup → Window → Show MIDI Studio, double-click IAC Driver, tick “Device is online”.
  2. Windows 11: the built-in Windows MIDI Services include a loopback port (not tested by us). Older Windows: install loopMIDI and add a port.
  3. Ableton Live: Settings → Link, Tempo & MIDI → turn on Track and Remote for the IAC or loopMIDI input. TouchDesigner: a MIDI In CHOP on that device. Resolume: Preferences → MIDI.

Web MIDI works in Chrome and Edge, and in Firefox after it asks you to allow the site. Safari and iPad have none: the controller still plays and fires every event, and MIDI out reports that it is unavailable.

No feedback loops: the engine never listens to IAC inputs, the element mutes any input with the same name as its output (the loopMIDI echo), and moves from your real hardware are not forwarded, because your software already hears the device.

Usage stats: each embed sends one anonymous hit per page load (which kind, which controller, the page’s origin; no cookies, nothing you play). telemetry="off" turns it off. What exactly is sent.

iframe messages

The iframe posts every event to its parent and accepts a few commands back. Add &frame=name to tell several iframes apart, and &origin=https://your.site to talk to your page only.

postMessage
// iframe → your page, for every event
{ source: 'openav', v: 1, type: 'control', frame: 'pads',
  detail: { id, type, value, raw, signal, message, bytes, source } }
// type: ready · control · noteon · noteoff · connect · disconnect · status · profilechange · error

// your page → iframe
const win = document.querySelector('iframe').contentWindow;
win.postMessage({ target: 'openav', type: 'set', id: 'k1', value: 0.5 }, '*');
win.postMessage({ target: 'openav', type: 'ingest', bytes: [0xb0, 70, 64] }, '*');
win.postMessage({ target: 'openav', type: 'get' }, '*');   // answers with type 'values'
// also: press · release · reset · profile · layout

The element, in one table

NameKindWhat it does
profileattributewhich device: an id, a short name, or a URL to a profile JSON
layoutattributeauto, face (as it looks) or stack (re-gridded for a tall box)
hardwareattributefollow the real device: on, ask (a button), or a port name
midi-outattributesend what is played to an output: a port name, /regex/, or ask
channelattribute1–16: move every control to the channel your unit is set to
picker · readout · learn · followattributedevice picker, last-message line, learn button, switch to the device you plug in
controleventany control moved: id, type, value, raw, signal, message, bytes, source
noteon · noteoffeventpads, keys and note buttons, with note and velocity
connect · disconnect · statuseventthe hardware port came or went; the state of hardware and MIDI out
set(id, value) · get(id) · values() · reset()methodmove a control like a hand would, read it, read all, bring all home
ingest(bytes) · send(bytes)methodMIDI in from anywhere (the faceplate follows) · raw bytes to the output port
on(name, fn)methodsubscribe, returns an unsubscribe function

Everything, with every field of every payload: the package README →

06 · Model yours

Add your controller

A profile is one JSON file. If the manual has a MIDI implementation chart, the profile can be exact; if it does not, say so in the file.

  1. Start from the closest file Copy a device that looks like yours, or a generic layout. The faceplate is sections on a grid in face units, so the screen version looks like the desk.
  2. Write down what each control sends Type, message (cc, note, pitchbend), channel, number. Encoders name their relative mode; buttons say momentary or toggle; LEDs say what lights them.
  3. Cite every number Each source has a title, a link and what it confirmed. A number nobody has checked gets "verified": false and a note.
  4. Validate validateProfile() returns every problem in words, or an empty list. The test suite runs it on every shipped profile.
  5. Try it before you send it <oav-controller profile="./my-pads.json"> loads a profile from a URL, so you can play your file on your own page first.
  6. Open a pull request Put the file in packages/midi/profiles/ and add it to profiles/index.js. Tell us which unit and firmware you checked it on.

A profile, in short

packages/midi/profiles/my-pads.json
{
  "id": "my-pads", "short": "mypads", "name": "My Pads", "maker": "…", "kind": "device",
  "match": { "ports": ["my\\s*pads"] },
  "sources": [{ "title": "My Pads manual, MIDI implementation chart", "url": "https://…",
                "note": "pads: notes 36–43 on channel 10" }],
  "face": { "w": 100, "h": 30, "label": "MY PADS" },
  "sections": [{ "id": "pads", "x": 2, "y": 4, "w": 60, "h": 24, "cols": 4, "rows": 2,
                 "controls": ["pad1", "pad2", "…"] }],
  "controls": [
    { "id": "pad1", "type": "pad", "msg": "note", "ch": 10, "note": 36, "label": "1" },
    { "id": "k1", "type": "knob", "msg": "cc", "cc": 70, "label": "K1",
      "verified": false, "note": "default not printed in the manual" }
  ]
}

Check it

check.mjs
// check.mjs — run: node check.mjs
import { validateProfile } from './packages/midi/profiles.js';
import p from './packages/midi/profiles/my-pads.json' with { type: 'json' };

console.log(validateProfile(p));   // [] = valid; otherwise every problem, in words

Control types

TypeSendsSignal value
knob · faderCC, absolute 0–1270..1
encoderCC, relative (offset64, offset16, twos, signbit)position 0..1, plus /delta steps
padnote with velocity (or CC); optional aftertouchvelocity while held, 0 on release, plus /hit
buttonnote or CC; momentary or toggle0 or 1
keysa note range/on and /off pulses, n<note> while held
wheel · stripCC or pitch bend; may spring back0..1, or −1..1 when bipolar

No manual? Learn it

Choose a generic layout, press Learn, and move your controls in order: the layout fills itself with your device's messages. exportMapping() gives you the result as JSON, the start of a real profile.