Instruments & outputs
Every track has exactly one output: the thing that turns its notes into sound.
It’s pure data — a tagged union, discriminated by kind — so the runtime
maps it to the actual voice. Four kinds: synth, sampler, soundfont, and
midi.
import type { Song } from "@barline/runtime";synth — the built-ins
Section titled “synth — the built-ins”output: { kind: "synth", synth: { id: "kick", params: { volume: -12 } } }synth.id names a built-in voice; synth.params is an optional
Record<string, number | string> of per-instrument knobs (e.g.
{ volume: -12, note: 86 }). The nine drum/synth primitives:
id | Role |
|---|---|
kick | The four-on-the-floor anchor |
hat | Closed hi-hat tick |
clap | Off-beat backbeat clap |
metal | Metallic perc / ride hit |
bass | Sub / rumble bass |
lead | Mono lead line |
kick909 | Punchier 909-style kick |
acid303 | Squelchy 303-style mono |
stab | Chord/organ stab |
FAUST polyphonic voices
Section titled “FAUST polyphonic voices”Six voices are FAUST-compiled and 16-voice polyphonic — referenced by the
same synth.id. If their wasm artifacts aren’t registered they fall back to a
Tone PolySynth, so playback never breaks:
id | Role |
|---|---|
subtractive | Classic subtractive poly |
supersaw | Detuned supersaw stack |
fm | FM operator voice |
pluck | Karplus-style pluck |
acid | 303 diode-ladder mono |
hardkick | Distorted hard-techno kick |
const lead = song.track({ name: "lead", output: { kind: "synth", synth: { id: "supersaw", params: { volume: -8 } } },});sampler — a multisample map
Section titled “sampler — a multisample map”output: { kind: "sampler", samples: { "C3": "/api/uploads/<id>", "C4": "/api/uploads/<id>" },}samples is a note → URL map. The runtime pitches each zone to fill the gaps,
so a few well-placed root notes cover a whole range. URLs are uploaded assets at
/api/uploads/<id> — see the Library for how to upload them.
soundfont — a GM program
Section titled “soundfont — a GM program”output: { kind: "soundfont", font: "<id>", program: 0 }font is an uploaded .sf2/.sf3 (an /api/uploads/<id>); program is a
General MIDI melodic program number, 0..127 (0 = acoustic grand piano).
Upload soundfonts the same way as samples — both live in the unified
Library.
midi — drive external gear
Section titled “midi — drive external gear”output: { kind: "midi", channel: 1, port: "IAC Driver Bus 1" }Sends note events out over Web MIDI on channel (1..16). port is optional —
omit it to use the default output port.
Putting it together
Section titled “Putting it together”A song file is export const config plus a default function the runtime calls
with a live song. Here are three tracks across kinds:
import type { Song } from "@barline/runtime";import { fx, notes, bars, beats, r } from "@barline/core";
export const config = { bpm: 132, key: "A minor" };
export default function (song: Song) { const kick = song.track({ name: "kick", output: { kind: "synth", synth: { id: "kick909" } }, effects: [fx.distortion({ drive: 0.3, wet: 0.5 })], });
const keys = song.track({ name: "keys", output: { kind: "soundfont", font: "<id>", program: 4 }, // electric piano });
const drums = song.track({ name: "drums", output: { kind: "sampler", samples: { "C2": "/api/uploads/<id>", "D2": "/api/uploads/<id>" }, }, });
song.section("intro", bars(4), () => { kick.play(r`x . . . x . . . x . . . x . . .`); drums.play(r`. . x . . . x .`); keys.play(notes(["C3", "Eb3", "G3"], beats(1))); });
song.arrange([{ section: "intro" }]);}Once an instrument is making sound, shape it with the track’s effects chain.