m4l-builder
Build Max for Live devices in Python. Write scripts, emit .amxd files straight to your Ableton User Library. No Max GUI required. Everything is version-controllable, scriptable, and reproducible. Zero runtime dependencies -- pure stdlib.
Install
pip install m4l-builder
Quick start
from m4l_builder import AudioEffect, WARM, device_output_path
device = AudioEffect("My Gain", width=150, height=110, theme=WARM)
device.add_panel("bg", [0, 0, 150, 110])
device.add_dial("gain", "Gain", [10, 6, 50, 90],
min_val=-70.0, max_val=6.0, initial=0.0,
unitstyle=4, annotation_name="Gain")
device.add_newobj("mul_l", "*~ 1.", numinlets=2, numoutlets=1, outlettype=["signal"])
device.add_newobj("mul_r", "*~ 1.", numinlets=2, numoutlets=1, outlettype=["signal"])
device.add_newobj("db2a", "dbtoa", numinlets=1, numoutlets=1, outlettype=[""])
device.add_newobj("pk", "pack f 20", numinlets=2, numoutlets=1, outlettype=[""])
device.add_newobj("ln", "line~", numinlets=2, numoutlets=2, outlettype=["signal", "bang"])
device.add_line("obj-plugin", 0, "mul_l", 0) # stereo in
device.add_line("obj-plugin", 1, "mul_r", 0)
device.add_line("mul_l", 0, "obj-plugout", 0) # stereo out
device.add_line("mul_r", 0, "obj-plugout", 1)
device.add_line("gain", 0, "db2a", 0) # dial -> dbtoa -> smooth -> gain
device.add_line("db2a", 0, "pk", 0)
device.add_line("pk", 0, "ln", 0)
device.add_line("ln", 0, "mul_l", 1)
device.add_line("ln", 0, "mul_r", 1)
device.build(device_output_path("My Gain"))
Restart Ableton (or refresh the browser) and your device shows up in the User Library.
Key concepts
Device types
Three device types, matching what Ableton expects:
from m4l_builder import AudioEffect, Instrument, MidiEffect
fx = AudioEffect("FX", 300, 170) # auto-adds plugin~/plugout~
synth = Instrument("Synth", 400, 200) # no auto I/O
midi = MidiEffect("MIDI FX", 200, 100) # MIDI only
AudioEffect auto-wires stereo plugin~ / plugout~ objects (IDs obj-plugin, obj-plugout). Instruments and MIDI effects leave I/O to you.
DSP blocks
All DSP functions return (boxes, lines) tuples. Compose them with add_dsp:
from m4l_builder import gain_stage, highpass_filter
boxes, lines = gain_stage("gain")
device.add_dsp(boxes, lines)
Filters: highpass, lowpass, bandpass, notch, onepole, shelves, tilt EQ, 3-band crossover, peaking EQ, allpass Dynamics: compressor, limiter, envelope follower, gate/expander, sidechain detect, multiband compressor Delay/Reverb: delay line, feedback delay, reverb network, FDN reverb, convolver Modulation: LFO (4 waveforms), tremolo, transport LFO, morphing LFO MIDI: notein/out, ctlin/out, velocity curve, transpose, arpeggiator, chord, pitch quantize, midi learn Synthesis: wavetable osc, noise, oscillator bank, ADSR, poly voices, grain cloud Spectral: spectral gate, crossover, vocoder, phase vocoder Routing: selector, send/receive (signal + message), matrix mixer, sidechain routing Utility: param smooth, tempo sync, sample and hold, bitcrusher, coll/dict/pattr storage
90+ blocks total. See docs/api.md for the full list with signatures.
Engines (jsui visualizations)
JavaScript generators for Max's jsui object. Each returns an ES5 string for mgraphics/Cairo rendering:
from m4l_builder.engines import filter_curve_js
device.add_jsui("display", [10, 30, 200, 80],
js_code=filter_curve_js(), numinlets=3)
18 generators available: filter curves, EQ, envelopes, spectrum, waveforms, XY pad, piano roll, step grids, grain clouds, vocoder bands, and more.
Themes
Seven built-in color themes. Pass to the device constructor and all UI elements inherit colors automatically:
from m4l_builder import AudioEffect, MIDNIGHT, WARM, COOL, LIGHT, FOREST, VIOLET, SOLAR
device = AudioEffect("FX", 300, 170, theme=MIDNIGHT)
Build a theme from just an accent color:
from m4l_builder import Theme
my_theme = Theme.from_accent([0.8, 0.3, 0.1, 1.0])
Recipes
Pre-wired DSP combos for common patterns. They add objects to a device and return IDs for further wiring:
from m4l_builder import gain_controlled_stage, dry_wet_stage
ids = gain_controlled_stage(device, "out", [10, 10, 50, 70])
# ids["gain"] is the *~ you wire into your signal chain
Available: gain_controlled_stage, dry_wet_stage, tempo_synced_delay, midi_note_gate.
Layout helpers
Automatic positioning with Row, Column, and Grid context managers:
with device.row(10, 10, spacing=8, height=70) as r:
r.add_dial("d1", "Param1", width=50)
r.add_dial("d2", "Param2", width=50)
r.add_dial("d3", "Param3", width=50)
Subpatchers
Nested patchers for organizing signal chains:
from m4l_builder import Subpatcher
sub = Subpatcher("processor")
sub.add_newobj("in", "inlet~", numinlets=1, numoutlets=1)
sub.add_newobj("out", "outlet~", numinlets=1, numoutlets=1)
sub.add_line("in", 0, "out", 0)
device.add_subpatcher(sub, "proc_box", [30, 100, 80, 20])
Round-trip editing with from_amxd
Read an existing .amxd back into a Device, modify it, write it out:
device = AudioEffect.from_amxd("path/to/effect.amxd")
device.add_dial("new_knob", "NewParam", [10, 10, 50, 70])
device.build("path/to/modified.amxd")
Examples
40+ examples in examples/. A few highlights:
| File | What it builds |
|---|---|
simple_gain.py |
Minimal starter, single gain dial |
stereo_delay.py |
L/R delay with feedback saturation |
simple_compressor.py |
Threshold, ratio, attack/release |
parametric_eq.py |
JSUI custom EQ curve display |
poly_synth.py |
Polyphonic synth with wavetable |
midi_arpeggiator.py |
MIDI arpeggiator |
from_amxd_demo.py |
Round-trip: build, read back, modify |
uv run python examples/simple_gain.py # run one
for f in examples/*.py; do uv run python "$f"; done # build all
Development
git clone https://github.com/alaarab/m4l-builder.git
cd m4l-builder
uv pip install -e .
# Tests
uv run pytest tests/ -v
# With coverage
uv run pytest tests/ --cov=m4l_builder --cov-report=term-missing
API reference
Full API docs at docs/api.md.
License
MIT
Metadata
Release files for m4l-builder 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| m4l_builder-0.7.0.tar.gz | 91.5 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| m4l_builder-0.7.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 197.1 kB
Release files / m4l_builder-0.7.0.tar.gz
| Download URL | m4l_builder-0.7.0.tar.gz |
|---|---|
| Size | 91.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8a48a52564b1ad72f824492c263d5cff948273eb9d78bab2ba92196b005cd43e
|
|
BLAKE2b-256 checksum How to use checksums |
157233248271f84fe1d4bba92102ee3f4734c2672febbcc3ab38b558ffa174c5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|
Release files / m4l_builder-0.7.0-py3-none-any.whl
| Download URL | m4l_builder-0.7.0-py3-none-any.whl |
|---|---|
| Size | 105.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
17b12258295ffbb60c2709dc7083653c9ef55dbeb1cfb51ee0547b084d03cc26
|
|
BLAKE2b-256 checksum How to use checksums |
48a79f2ebf8009916b45c8574e4022d87f0374af68853c9eb6624651d43651f9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|
Security for m4l-builder 0.7.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.