Skip to main content

Programmatically build Max for Live (.amxd) devices

Project description

m4l-builder

PyPI version Tests Python 3.9+ License: MIT

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

m4l_builder-0.7.0.tar.gz (91.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

m4l_builder-0.7.0-py3-none-any.whl (105.6 kB view details)

Uploaded Python 3

File details

Details for the file m4l_builder-0.7.0.tar.gz.

File metadata

  • Download URL: m4l_builder-0.7.0.tar.gz
  • Upload date:
  • Size: 91.5 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

Hashes for m4l_builder-0.7.0.tar.gz
Algorithm Hash digest
SHA256 8a48a52564b1ad72f824492c263d5cff948273eb9d78bab2ba92196b005cd43e
MD5 b050fb0c6b34ed5fc616e5e93b003935
BLAKE2b-256 157233248271f84fe1d4bba92102ee3f4734c2672febbcc3ab38b558ffa174c5

See more details on using hashes here.

File details

Details for the file m4l_builder-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: m4l_builder-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 105.6 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

Hashes for m4l_builder-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 17b12258295ffbb60c2709dc7083653c9ef55dbeb1cfb51ee0547b084d03cc26
MD5 627afce5b90af92737b596d9af48b1ae
BLAKE2b-256 48a79f2ebf8009916b45c8574e4022d87f0374af68853c9eb6624651d43651f9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page