@tsln/live-object

v0.4.1npmsourcechangelog

LiveObject<C> wraps Max for Live's LiveAPI for Live Object Model class C, so member names, value types and function arguments are checked against @tsln/lom-types.

import LiveObject = require("./vendor/live-object");

const track = LiveObject.at("live_set tracks 0"); // LiveObject<"Track"> | null, class inferred from the path
const song = LiveObject.song(); // LiveObject<"Song"> | null; also LiveObject.app(), LiveObject.thisDevice()
if (!track || !song) return;

track.name; // string, read from Live on each access
track.mute = 1; // sends `set mute 1`
track.devices; // LiveObject<"Device">[]
track.insert_device("Simpler", 0); // checked arguments

track.get("name"); // the same members through get(), set(), call() and get_count()
const observer = track.observe("devices", (devices) => post(devices.length, "\n"));
observer?.unobserve(); // or track.unobserve("devices")

for (const device of track.devices) {
  if (device.is("SimplerDevice")) device.sample; // narrowed to the subclass
}

new LiveObject<"DeviceIO">(path); // for paths only known at runtime

Children come back as LiveObjects (or null), list children and list properties as arrays, dictionary properties as parsed objects. Accessors read from Live on every access and return new objects each time, so store a result in a variable when using it more than once. Like all Live API access, none of this works in a script's global code; wait for live.thisdevice to bang.

What it costs

A LiveAPI object is the expensive part of reaching Live from JavaScript. Measured in Live 12.4:

So what counts is how many LiveAPI objects a script makes while it runs, and a LiveObject makes as few as it can:

A LiveObject made from any other path, such as live_set tracks 0, has a LiveAPI object to itself, because the path can come to mean another object. Keep those in variables.

Install

npm install --save-dev @tsln/live-object

Max's require() searches Max's file path and knows nothing of node_modules, so the package's single CommonJS file, dist/index.js, has to be copied or bundled to somewhere Max can find it (the max-msp repository bundles it to js/vendor/live-object.js with esbuild). The types come along with a declaration file next to it:

// src/vendor/live-object.d.ts
import LiveObject = require("@tsln/live-object");
export = LiveObject;

Importing the package pulls in @tsln/max-types and @tsln/lom-types, which it depends on. List them in types too if scripts use Lom.* or Max globals without importing it.

Files