Visual MIDI controller mapper that exports a JSON profile for programmatic control of hardware controllers.
Project description
midicraft
Visual editor for mapping the physical layout of a MIDI controller (buttons, knobs, pad grids...) and exporting a self-contained JSON profile that can be used to programmatically control the device — send LED colors, react to inputs — from any code, without midicraft.
Installation
pip install midicraft
Launch
midicraft
How it works
- Recreate the physical layout of your controller on the canvas (drag & drop from the palette)
- Map each element to its MIDI binding via MIDI learn (click Learn, press the physical control)
- Assign LED behaviors per element from the catalog or define custom color→value tables
- Save the profile as JSON
The exported profile is self-sufficient: it contains everything needed to drive the controller from external code.
JSON profile format
Example of a mapped button:
{
"element_type": "grid_button",
"control_id": "46e33976",
"label": "Clip 1",
"x": 0, "y": 0, "width": 1.0, "height": 1.0,
"binding": { "kind": "NOTE", "number": 36, "channel": 0 },
"led_behavior_key": "CUSTOM",
"parent_id": null,
"custom_led_values": [
["Orange blinking", 12],
["Green solid", 3],
["Off", 0]
]
}
binding: how to address the control —kind(NOTEorCONTROL_CHANGE),number,channel(0-indexed)custom_led_values: color label → MIDI value pairscontrol_id: internal unique identifier, also used to link children viaparent_id
Using the profile from Python:
import mido, json
profile = json.load(open("my_controller.json"))
out = mido.open_output("CMD LC-1")
# Light up "Clip 1" in orange blinking
btn = next(e for e in profile["elements"] if e["label"] == "Clip 1")
value = dict(btn["custom_led_values"])["Orange blinking"] # 12
out.send(mido.Message("note_on", channel=btn["binding"]["channel"],
note=btn["binding"]["number"], velocity=value))
Architecture
- Separate MIDI thread: listens to the input port continuously, classifies each message and pushes it into a thread-safe
queue.Queue. Never touches Tkinter widgets directly. - Main thread (Tkinter): drains the queue at a regular interval (
root.after(15, ...)) and updates the UI. - LED catalog decoupled from layout: an element references a behavior by key, not by duplicating values. Two buttons on the same controller can reference completely different behaviors.
- Grid coordinates, not pixels:
x/y/width/heightare expressed in logical grid units, converted to pixels only at render time. A profile remains valid regardless of display size.
Canvas features
- Drag & drop from the palette onto the canvas (with ghost preview)
- Smooth element movement with grid snap on release, collision detection
- Scroll: scrollbars + mousewheel (Shift+wheel for horizontal)
- N×M grid groups (1×5, 4×4, 8×8...) that move as one block, with individually mappable cells
- Pre-fill grids with buttons or knobs at creation time
- MIDI learn per element/cell
- Visual flash on MIDI input in normal mode
License
Copyright (c) 2026 Mehdi.A — AGPL-3.0-or-later
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file midicraft-0.3.0.tar.gz.
File metadata
- Download URL: midicraft-0.3.0.tar.gz
- Upload date:
- Size: 48.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4f9a00fea988ec4190347b2a46dadf02d9f85b90988a73481ad1fbc4779631a9
|
|
| MD5 |
1bca6beacd2cf9974ceb2c27534ca215
|
|
| BLAKE2b-256 |
86702b5ed9b42c6e1be9489a6aa9504b4f3bb5f88ca3f6748da788522ebd41bc
|
File details
Details for the file midicraft-0.3.0-py3-none-any.whl.
File metadata
- Download URL: midicraft-0.3.0-py3-none-any.whl
- Upload date:
- Size: 51.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
36ae0031ce69a2bf5e2351a50702f15f67cfa2738f517949e30c5637d6cabe80
|
|
| MD5 |
612377c002957f0fbbcab25133644ef0
|
|
| BLAKE2b-256 |
80f2f18b101668e9a7046e0a233db386540636f0beb4ddfe0cfb4030f2049856
|