write_clip_notes
Replace or append MIDI notes in an Ableton Live Session clip and verify the write by reading back notes within a tolerance.
Instructions
Write MIDI notes into a Session clip. Replaces notes by default.
Args:
track: Track index in song.tracks (MIDI track).
slot: Scene/slot index in track.clip_slots.
notes: List of note dictionaries with pitch, start_time, duration, velocity,
and optional probability, velocity_deviation, release_velocity, mute.
mode: Write mode, 'replace' (clears prior notes and writes) or 'append'.
verify: When True, reads back notes and compares with input using diff.
Returns:
Dictionary containing write confirmation, validation reports, and optional diff.
Note:
Times are in beats and clip-local, so beat 0 is the clip's own start.
A list straight from ``read_clip_notes`` can be written back. Live adds
``note_id`` to every note it hands out, which is identity rather than content,
so the keys in :data:`~ableton_maestro.music.notes.TOLERATED_NOTE_KEYS` are
dropped instead of refused and reported as ``input_keys_ignored``. Every other
unrecognised key is an error.
``pitch``, ``start_time`` and ``duration`` are never defaulted. A reader that
substitutes ``start_time=0.0`` and ``duration=0.25`` for missing keys turns a
list built with ``pos``/``dur`` (the humanise spelling) into a pile of
sixteenths stacked on beat 0, and reports success while doing it. Wrong keys are
refused before anything is sent.
``replace`` is remove-then-write inside one handler call. Live's own
``set_notes`` appends, so a second write silently doubles a melody instead of
correcting it (measured: 63 + 23 = 86 notes). Ask for ``append`` by name when
adding is the intent. An empty list with ``mode="replace"`` clears the clip.
A note does not come back bit-identical to the note sent. Times and durations
return with a small deviation in both directions. Measured 2026-09-01 against
Live 12.4.5: a sent 0.29 read back as 0.29000010406260407 and a sent 0.18 as
0.17999994796869798, about 4e-7 relative. Re-measured 2026-09-02 against Live
12.4.5 at 124 BPM: both values reproduced to every digit, a ``start_time`` of
2.29 came back as 2.290000104062604, and a duration of 0.5 came back exactly.
The cause is not established: it is not a tick grid (no grid of 96, 192, 480 or
960 per quarter produces those numbers) and not a single float32 conversion
(float32 of 0.29 is 0.28999999). That 0.5 survives while 0.29 does not is
consistent with a binary-representable value passing through untouched, but the
mechanism is not claimed here. At 124 BPM the error is around 50 nanoseconds, so
musically it is nothing. It matters only for comparison: never test a note time
for equality. The diff run here already uses a tolerance, which is why it
reports ``0 changed`` for values that differ in the seventh decimal.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | replace | |
| slot | Yes | ||
| notes | Yes | ||
| track | Yes | ||
| verify | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||