Resources and Filesystem
Working with audio resources, file imports, and filesystem access
The context.resources module provides methods for working with audio resources in the Live Set. It also interacts with the filesystem on your behalf — which matters because extensions run under a restricted permission model.
Importing Files into the Project
Section titled “Importing Files into the Project”When your extension needs to add an audio file to a Live Set — for example, a file downloaded from an API, generated by an AI model, or selected by the user — you must first import it into the project:
const importedPath = await context.resources.importIntoProject("/path/to/audio.wav");
// Now use the imported path with createAudioClipconst clipSlot = context.getObjectFromHandle(handle, ClipSlot);await clipSlot.createAudioClip(importedPath, false);importIntoProject copies the file into the Live project folder so that Live manages it. The returned path points to the imported copy. Always use this returned path — not the original — when creating clips or referencing the file in subsequent API calls.
Rendering Audio from the Arrangement
Section titled “Rendering Audio from the Arrangement”To get audio data from a track in the arrangement view, use renderPreFxAudio. This renders the pre-effects audio for a given time range and returns a path to the rendered file:
const track = context.getObjectFromHandle(handle, AudioTrack);const audioPath = await context.resources.renderPreFxAudio(track, startTime, endTime);
// audioPath points to a WAV file in the extension's temp directoryconst audioData = await fs.readFile(audioPath);The rendered file is placed in the extension’s temp directory, which your extension has permission to read.
Filesystem Access
Section titled “Filesystem Access”Extensions run under a permission model that restricts which parts of the filesystem they can access. Your extension can read and write to:
- Storage directory (
context.environment.storageDirectory) — persistent storage for configuration, credentials, cached state, or any data that should survive across Live sessions. - Temp directory (
context.environment.tempDirectory) — temporary files like intermediate audio, analysis results, or downloads. May be cleaned up between sessions.
Your extension should not access arbitrary paths like the user’s Documents, Downloads, or Desktop folders.
Why these restrictions exist
Section titled “Why these restrictions exist”A stricter OS-level sandbox will be introduced in the future. The current permission model exists so that extensions are built to respect filesystem boundaries from the start. If your extension accesses paths outside the allowed set today, it will break when stricter sandboxing is enforced.
Do not work around the permission model
Section titled “Do not work around the permission model”All code that your extension runs must stay within the allowed filesystem boundaries. This includes child processes spawned via child_process and code running in native addons — they must respect the same restrictions. Any workaround that accesses files outside the allowed paths is unsupported and will likely break in the future.
If you need to work with a file that lives outside the allowed paths, use importIntoProject — it runs on the host side and can access the file on your behalf.
Practical patterns
Section titled “Practical patterns”Downloading a file from an API and adding it to the Live Set:
const response = await fetch("https://api.example.com/audio/generate");const buffer = Buffer.from(await response.arrayBuffer());
// Write to the temp directory (allowed)const tempPath = path.join(context.environment.tempDirectory, "generated.wav");await fs.writeFile(tempPath, buffer);
// Import into the project so Live manages itconst imported = await context.resources.importIntoProject(tempPath);await clipSlot.createAudioClip(imported, false);Persisting state across sessions:
const configPath = path.join(context.environment.storageDirectory, "config.json");
// Write config (allowed — storage directory is read/write)await fs.writeFile(configPath, JSON.stringify({ apiKey: "..." }));
// Read it back in a later sessionconst config = JSON.parse(await fs.readFile(configPath, "utf-8"));