What's New in Live 11, Part 2


    The release of Ableton Live 11 introduced a number of new features for working with MIDI notes:
    • Support for MPE
    • Note probability
    • Support for velocity deviation
    • Support for release velocity
    The Max for Live API has been updated to provide access to this new data in Live, and to allow for manipulating notes without discarding this new data.
    The second part of our look at what’s new in Live for Max for Live users will provide a brief overview of the new features in the Live notes API.
    We’re also including a pair of example Max for Live devices which contain snippets that you can copy and paste to help you hit the ground running as you learn to use these new features.
    And don’t worry if you’re not really familiar with dictionaries (dicts) or note IDs in Max — two mechanisms in Max you’ll be using when you work with the notes API — we’ve tried to walk you through how dicts and note IDs are used in the example device snippets.

    Before and after

    For those of you who are already familiar with working with the notes API in Live 10 (or for those of you who’d rather read patches than text), let’s start with a device from the download (Notes API - Before and After.amxd) that will give you a side-by-side comparison of how common tasks used to be done, and the new Live 11 notes API ways of doing them:
    You’ll find examples here of all the common API-based notes operations you already know (getting, adding, removing, modifying (all notes or selected notes), duplicating and observing) with examples of the new notes API versions you can copy, paste, and modify as needed to quickly add the new functionality to your own devices.

    The API specification

    You will find the full specification for the notes API in the Live Object Model document listed as part of the Clip specification.
    The new features of the Live 11 notes API involves working with note IDs and dictionaries in Max (for more details on this, see below).
    The new notes API methods are:
    • get_notes_extended: returns a dict with all notes in a specified time and pitch range
    • get_selected_notes_extended: returns a dict with all selected notes
    • add_new_notes: accepts a notes dict without note IDs to add new notes
    • apply_note_modifications: accepts a notes dict with note IDs of notes to modify
    • remove_notes_extended: removes all notes in a pitch and time range
    • get_notes_by_id: gets a note for a certain note ID
    • remove_notes_by_id: removes a note with a certain note ID
    To see exactly what parameters to provide to each of these methods and what they return, please refer to the specification in the Live Object Model document.
    The old notes API methods are still available under conditions
    The old note access methods are still available for legacy devices in Live 11, but using them is discouraged by warnings in the Max Window.
    • get_notes
    • set_notes
    • get_selected_notes
    To prevent unintentionally removing new note data like MPE, the following old methods that remove notes will show a warning popup:
    • remove_notes
    • replace_selected_notes
    The warning pop-ups can be permanently silenced by the user by choosing Don't show again.

    Accessing the API with dicts

    The dict (short for “dictionary") object family in Max provides versatile access to all kinds of data. A dict represents series of key-value pairs in a leveled structure. The structure of these dicts follow that of the JSON format, which will be helpful for those of you who are familiar with web development: a key can point to a string, float or int, or to another dict.
    Additionally, a key can point to an array of any of these things. The Notes API Basics.amxd Max for Live device included in the download provides a basic example of how to use the notes API with Max dict objects:
    The order of key/value pairs in a dict is not fixed, nor is the number of keys and values. This is crucial to the new notes API, because it needs to be extendible; we’ll want older devices to continue to work without modifications if new note information is added in the future.

    Dicts are passed by reference

    When outputting a dict to another object, instead of copying all the data over a patch cord, a reference to this data is transmitted. That is why you see something like dictionary u944000887 when you show a dict in a message box.
    Note: Modifying a dict will affect all subsequent usages of this dict. To avoid problems, you should make a copy of a dict before modifying it. You can find a demonstration of this in the IntroToDict subpatcher you’ll find in the Notes API - Before and After device.
    For more information about dicts, take a look at the more in-depth dict reference in the Max documentation.

    Keeping track of notes with note IDs

    The previous method for modifying a note in Live 11 involved getting the note’s properties, removing them, and then adding a new note with similar properties. Adding MPE support meant that this old method would result in discarding all per-note MPE data.
    Live 11 guarantees that all note data is preserved by letting you provide new values for an existing note ID when you perform modification rather than removing and replacing note IDs.
    Note IDs are simply integers that uniquely identify a note within a clip. You cannot generate these IDs yourself; you can only find out about them by getting existing notes from a clip.
    The new procedure for modifying a note with the API looks like this:
    1. Get current notes with get_notes_extended, which provides you with a dict of all the notes.
    2. Get the note_id of the note you need to modify from the resulting dict.
    3. Create a new dict containing the new note values that retains the existing note_id.
    4. Send this new dict back to the Clip with apply_note_modifications.

    Note IDs are different from other references in Max

    Note IDs are different from existing reference types in Max, like Live Object Model IDs (e.g, id 56) or uuids (e.g., dictionary u48298492). These references are always globally unique and have a keyword prepended, whereas note IDs are unique only within a clip and are just ints (3). For more details, see the IntroToNoteIDs subpatcher in the Before and After device.

    The notes API in Javascript

    Javascript is uniquely well-equipped for dealing with the new notes API in Live 11 — the notes data is structured as JSON, and JSON is invented for Javascript. All new notes API operations are available to you; take a look at the Before and After example device, in the Javascript subpatcher for bits of example code that are ready to be copied into your own device patches.
    We hope that these articles have given you a good first look at the improvements and new features in Live 11 for Max for Live users, and we’re excited to see what you’ll make using them!

    Corrections

    2021-04-22: In a previous version of Notes API - Before and After.amxd, a pitch span of 127 was used when the intention was to apply an operation to the full pitch range. This has now been updated to 128. 2021-05-28: Added examples for outputting notes data from Javascript to dict and for inputting notes data from dict to Javascript.

    • Mar 17 2021 | 8:51 am
      This sounds awesome now i must upgrade.Thanks
    • Mar 17 2021 | 12:19 pm
      access to midi learn for custom UIs!?!????!
    • Mar 17 2021 | 12:54 pm
      Ok. That works great. Maybe the "Notes API - Before and After.amxd" file was missing in the first download? ;) Thanks a lot for the new features and finally the very good explaination!
    • Mar 17 2021 | 2:38 pm
      Many thanks for this excellent article!
    • Mar 17 2021 | 4:31 pm
      Hey all,
      I wanted to add a quick note that with the current version of Max, there is a limitation in the size of the dict that can be passed back and forth to and from Live, which might result in a warning message in the Max window when trying to change or request a lot of notes. A fix for this is in the pipeline though, this limitation should be gone in the next version of Live.
    • Mar 18 2021 | 11:43 am
      Many thanks for the JS examples. A quick question. I am adding notes to a clip in several steps (i.e., new notes to existing notes). Is there a simple way to get the note ID of the notes added the last time (we can assume that the note ID are known of the old notes if that helps). I can think of a couple of cumbversome ways to do this but if there is an easy one that would be great. Again what you are doing is superinteresting.
      All the best, Jan
    • Mar 18 2021 | 12:17 pm
      Thanks Jan! The only approach I know of is indeed to store a list of note IDs in the clip and to scan the notes again for new IDs after the new notes were added. I agree it would be better for convenience and performance if the add_new_notes method would directly return the newly added note ids. I've noted that as a feature request.
    • Mar 18 2021 | 6:45 pm
      Great,
      that would help! /Jan
    • Mar 21 2021 | 11:40 am
      Maybe here someone can help please. I'm trying to iterate through all the notes and put them out from js. I edited 'NotesAPIget.js' but don't find out how to output all elements from the array and not only one element.
      autowatch = 1 inlets = 2 outlets = 1
      var clipApi = null
      function id(id) { clipApi = new LiveAPI("id " + id) if (clipApi.path === "") clipApi = null }
      function printLatestNote(from_time, time_span) { if (clipApi == null) throw("No clip")
      var notesJson = clipApi.call("get_notes_extended", 0, 127, from_time, time_span) var notesObject = JSON.parse(notesJson) var notesArray = notesObject.notes post("length " + notesArray.length + "\n") printNote(notesArray[0]) }
      function printNote(note) { outlet(0, + note.note_id, + note.pitch, + note.start_time, + note.duration, + note.velocity, + note.release_velocity, + note.mute, + note.probability, + note.velocity_deviation)
      post("probability: " + note.probability + "\n")
      }
      Thanks for every help
    • Mar 21 2021 | 10:17 pm
      Try replacing printNote(notesArray[0]) with notesArray.forEach(printNote)
    • Mar 22 2021 | 3:35 pm
      Thanks so much, Broc. Works perfect. Tried a few different lines, also with forEach function but i didn't understand the 'grammar'. Have to learn a lot of javascript... it's so powerfull.
    • May 27 2021 | 9:10 pm
      Great article! [sneak preview from the beta testing arena: limitations with the dict size for MIDI notes and the API have been addressed in the latest beta; so soon limitations should be gone].
    • May 27 2021 | 10:06 pm
      For sets of chords it would be great to send a dictionary as a sub dictionary to another dicitonary like dict.pack but using the dict name or like dict.sub @name or using replace this would be awesome.
    • May 28 2021 | 8:30 am
      Hi Brodie,
      I am not fully sure what your use case is, but some things that are hard to do with dict objects can be done much more easily with Javascript.
      I just added two examples in the Javascript subpatcher of the Notes API Before and After device that demonstrate how to transfer notes data to and from dict objects.
    • May 28 2021 | 12:58 pm
      That sounds cool Mattijs thanks.Really big stuff!