Library
The Library panel uploads raw audio into your song, browses what you’ve already uploaded, and hands you the id to reference it from code. Unlike the Registry — which distributes code packages — the Library holds bytes: one per-user, session-gated store for both audio samples and whole-font SoundFonts (ADR-032).
What it projects
Section titled “What it projects”- An upload dropzone accepting samples (
.wav,.mp3,.ogg,.flac,.aiff) and SoundFonts (.sf2,.sf3— prefer.sf3, ~5x smaller). - A library list, filterable by type, showing each upload’s name, kind, and
its
/api/uploads/<id>url with a copy action.
The list is per-user: you see only what you’ve uploaded, and uploading requires a session. Once an upload exists, anyone can fetch its bytes — the serve route is public.
How upload works (and writes back)
Section titled “How upload works (and writes back)”A drop posts the file to POST /api/uploads?name=<file> (auth). The response
is the upload record you reference from code:
{ "id": "<userId>/<hash>.wav", "url": "/api/uploads/<id>", "type": "sample", "name": "kick.wav" }Keys are content-addressed — stored as uploads/<userId>/<sha>.<ext>, so
re-uploading the same bytes dedupes to the same id and a reference never breaks.
Listing is type-scoped (GET /api/uploads?type=sample|soundfont, auth,
per-user); the bytes serve from GET /api/uploads/* (public, immutable cache).
Referencing an upload from code
Section titled “Referencing an upload from code”A sample plays as a clip or via a sampler note-map:
import type { Song } from "@barline/runtime";import { bars, beats } from "@barline/core";
export const config = { bpm: 138, key: "A minor" };
export default function (song: Song) { // A multi-note sampler: map notes to upload urls. const keys = song.track({ name: "keys", output: { kind: "sampler", samples: { C3: "/api/uploads/<id>", G3: "/api/uploads/<id>" }, }, });
// A one-shot clip is scheduled on a track INSIDE a section body — never a // track option. `at`/`beats` are `Beats`, so wrap numbers with beats()/bars(). song.section("intro", bars(4), () => { keys.clip({ url: "/api/uploads/<id>", at: beats(0), beats: bars(4) }); });
song.arrange([{ section: "intro" }]);}A SoundFont is a melodic instrument — reference the font id and pick a GM
program (0..127):
song.track({ name: "rhodes", output: { kind: "soundfont", font: "<id>", program: 4 },});The font value is the upload id (a .sf3/.sf2 you dropped here), not a
separate route — always /api/uploads/<id> for bytes, never /api/soundfonts.
Library vs. Registry
Section titled “Library vs. Registry”The two stores sit side by side but never overlap: the Library is bytes you own
and serve (samples and fonts, content-addressed, public on read); the
Registry is source code others install. A sample is a url
in your song; a package is a <name>.ts in your files. Upload here when you have
audio; publish there when you have a reusable idea.