Programmatically build Max for Live (.amxd) devices
Project description
m4l-builder
Programmatically build Max for Live devices in Python.
Overview
m4l-builder generates fully functional Max for Live (.amxd) devices without the Max GUI. Define UI, wire DSP, and export a binary .amxd that loads directly into Ableton Live.
- Max patching in code -- version-controllable, reproducible, scriptable
- No Max license required to generate devices -- only Ableton Live + Max for Live to run them
- 19 composable DSP blocks -- filters, delays, saturators, envelopes, LFOs, and more
- 16 UI components -- dials, sliders, menus, scopes, meters, JSUI, and more
- Theme system -- 4 built-in themes with automatic color injection into all UI components
- kwargs passthrough -- any Max attribute can be set on any UI component
Quick Start
git clone https://github.com/alaarab/m4l-builder.git
cd m4l-builder
pip install -e .
Minimal Example
from m4l_builder import AudioEffect
from m4l_builder.theme import WARM
device = AudioEffect("Simple Gain", width=200, height=120, theme=WARM)
device.add_panel("bg", [0, 0, 200, 120])
device.add_comment("title", [8, 8, 100, 16], "GAIN", fontsize=14.0)
device.add_dial("gain", "Gain", [70, 30, 60, 75],
min_val=0.0, max_val=100.0, initial=50.0,
annotation_name="Gain")
# DSP wiring -- AudioEffect auto-adds plugin~ and plugout~
gain_l = device.add_newobj("gain_l", "*~ 1.", numinlets=2, numoutlets=1,
outlettype=["signal"])
gain_r = device.add_newobj("gain_r", "*~ 1.", numinlets=2, numoutlets=1,
outlettype=["signal"])
scale = device.add_newobj("scale", "scale 0. 100. 0. 2.", numinlets=6,
numoutlets=1, outlettype=[""])
device.add_line("obj-plugin", 0, "gain_l", 0)
device.add_line("obj-plugin", 1, "gain_r", 0)
device.add_line("gain_l", 0, "obj-plugout", 0)
device.add_line("gain_r", 0, "obj-plugout", 1)
device.add_line("gain", 0, "scale", 0)
device.add_line("scale", 0, "gain_l", 1)
device.add_line("scale", 0, "gain_r", 1)
device.build("~/Music/Ableton/User Library/Presets/Audio Effects/"
"Max Audio Effect/Simple Gain.amxd")
Device Types
from m4l_builder import AudioEffect, Instrument, MidiEffect
device = AudioEffect("My Effect", width=300, height=170) # auto plugin~/plugout~
device = Instrument("My Synth", width=400, height=200) # no auto I/O
device = MidiEffect("My MIDI Tool", width=200, height=100) # MIDI only, no audio
UI Components (16)
All UI functions place objects in presentation mode at the specified rect. kwargs passthrough lets you set any Max attribute directly.
| Function | Component | Description |
|---|---|---|
add_panel |
panel | Background panel (auto background:1) |
add_dial |
live.dial | Rotary dial with Live parameter storage |
add_slider |
live.slider | Linear slider (vertical/horizontal) |
add_toggle |
live.toggle | On/off toggle |
add_button |
live.button | Momentary bang button |
add_tab |
live.tab | Tab bar selector |
add_menu |
live.menu | Dropdown menu |
add_number_box |
live.numbox | Numeric entry/display |
add_comment |
comment | Static text label |
add_scope |
live.scope~ | Signal oscilloscope |
add_meter |
live.meter~ | Level meter |
add_live_text |
live.text | Clickable text button/toggle |
add_fpic |
fpic | Image display |
add_live_gain |
live.gain~ | Gain fader with built-in metering |
add_multislider |
multislider | Multi-value slider array |
add_jsui |
jsui | JavaScript UI for custom drawing |
DSP Building Blocks (19)
Every DSP function returns (boxes, lines). Add to a device with:
boxes, lines = gain_stage("my_gain")
for b in boxes: device.add_box(b)
for l in lines: device.lines.append(l)
| Category | Functions |
|---|---|
| I/O | stereo_io |
| Gain/Mixing | gain_stage, dry_wet_mix, signal_divide |
| Filters | highpass_filter, lowpass_filter, onepole_filter, tilt_eq, crossover_3band |
| Saturation | saturation (tanh/overdrive/clip/degrade modes) |
| Dynamics | envelope_follower |
| Delay | delay_line, feedback_delay |
| Modulation | lfo (sine/saw/square), tremolo |
| Stereo | ms_encode_decode, dc_block |
| Routing | selector |
| Resonance | comb_resonator |
Theme System
Four built-in themes provide coordinated colors for backgrounds, text, and accents. Pass a theme to the device constructor and all UI components inherit its colors automatically.
from m4l_builder.theme import MIDNIGHT, WARM, COOL, LIGHT
device = AudioEffect("My Effect", width=400, height=200, theme=MIDNIGHT)
| Theme | Accent | Character |
|---|---|---|
MIDNIGHT |
Teal | Dark, cool, modern |
WARM |
Orange | Dark, warm, analog feel |
COOL |
Blue | Dark, clean, precise |
LIGHT |
Blue | Light background, high contrast |
Each Theme dataclass provides: bg, surface, section (background layers), text, text_dim (typography), accent (active/selected color), plus derived dial_color, needle_color, and tab_* colors. Uses Ableton Sans fonts by default.
Example Devices (17)
The examples/ directory contains complete, buildable devices:
| # | File | Device | Theme | Description |
|---|---|---|---|---|
| 1 | simple_gain.py |
Simple Gain | WARM | Minimal starter -- single gain dial |
| 2 | stereo_filter.py |
Stereo Filter | COOL | HP/LP/BP SVF filter with cutoff and resonance |
| 3 | stereo_utility.py |
Stereo Utility | COOL | Gain, pan, width (M/S), phase invert |
| 4 | simple_compressor.py |
Simple Compressor | WARM | Threshold, ratio, attack/release, makeup |
| 5 | multiband_imager.py |
Multiband Imager | COOL | 3-band crossover with per-band stereo width |
| 6 | transient_shaper.py |
Transient Shaper | WARM | Attack/sustain shaping via envelope follower |
| 7 | tape_degradation.py |
Tape Degradation | WARM | Saturation, wow/flutter, noise, head rolloff |
| 8 | stereo_delay.py |
Stereo Delay | MIDNIGHT | L/R delay with tanh feedback saturation |
| 9 | midside_suite.py |
Mid/Side Suite | COOL | M/S processing with tilt EQ and saturation |
| 10 | multiband_saturator.py |
Multiband Saturator | WARM | 3-band with tanh/overdrive/clip modes |
| 11 | rhythmic_gate.py |
Rhythmic Gate | WARM | LFO-driven gate with 4 waveforms |
| 12 | auto_filter.py |
Auto Filter | MIDNIGHT | Envelope follower + LFO modulated filter |
| 13 | comb_bank.py |
Comb Resonator | MIDNIGHT | Tuned comb filter bank with damping |
| 14 | lofi_processor.py |
LoFi Processor | WARM | Bitcrusher + sample rate reduction |
| 15 | parametric_eq.py |
Parametric EQ | -- | JSUI custom EQ curve display |
| 16 | expression_control.py |
Expression Control | MIDNIGHT | 8 macro knobs for parameter mapping |
| 17 | macro_randomizer.py |
Macro Randomizer | COOL | 7 randomizable outputs with auto/trigger |
Build any example:
uv run python examples/stereo_delay.py
Testing
882+ tests across 9 test files:
uv run pytest tests/ -v
| Test File | Coverage |
|---|---|
test_objects.py |
newobj and patchline dict structure |
test_ui.py |
All 16 UI element creators and properties |
test_dsp.py |
DSP building blocks return correct boxes/lines |
test_patcher.py |
Patcher dict generation and device type mapping |
test_container.py |
.amxd binary format: ampf header, type codes, JSON payload |
test_device.py |
Device class hierarchy, builder methods, theme injection |
test_theme.py |
Theme dataclass, color derivation, preset themes |
test_engines.py |
Engine/processing modules |
test_examples.py |
Integration: builds all 17 examples, verifies valid .amxd output |
.amxd Binary Format
Offset Size Content
------ ---- -------
0 4 Magic: "ampf"
4 4 Version: uint32 LE = 4
8 4 Type: "aaaa" (audio), "iiii" (instrument), "mmmm" (MIDI)
12 4 Section: "meta"
16 4 Metadata length (uint32 LE)
20 4 Metadata payload
24 4 Section: "ptch"
28 4 JSON length (uint32 LE, includes null terminator)
32+ N JSON patcher data, null-terminated
Recommended Tools
LiveMCP -- Control Ableton Live via the Model Context Protocol. Load devices, trigger clips, adjust mixer settings. Pairs with m4l-builder for a fully code-driven production workflow.
License
MIT
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 m4l_builder-0.3.0.tar.gz.
File metadata
- Download URL: m4l_builder-0.3.0.tar.gz
- Upload date:
- Size: 111.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a71082fe1bd2ce943c77d54d85a00b4406c57829a790da025f92833b3917ac44
|
|
| MD5 |
08ee09a347d9d5591053d4cb6ca2ed0a
|
|
| BLAKE2b-256 |
6dcb6a8b24977aedff88901e573facf75df9957378b65dd5193c77a09fcd07f3
|
File details
Details for the file m4l_builder-0.3.0-py3-none-any.whl.
File metadata
- Download URL: m4l_builder-0.3.0-py3-none-any.whl
- Upload date:
- Size: 42.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fd7febbee33c3573c48f21c09108d3d9af5fbb2af2aa1fe8cb70b76e877a48ee
|
|
| MD5 |
8d999c9641ae3bf24bb82c2709f81b04
|
|
| BLAKE2b-256 |
0a7e762e4ebbe432fec161b3d70c4df90ace8596df7c6f690828a23030ba210e
|