// The instrument extension point. An instrument turns note events into // audio in two ways: // // - render(): the offline path. Given every note with times in seconds, // produce one mono buffer for the whole track. This is what playback // and WAV export use, and it may be async and arbitrarily expensive // (a GPU physical model, a worker, a remote call). Results are cached // per track and invalidated by note or instrument changes. // // - noteOn(): the optional live path, used for low-latency monitoring // while recording and for previewing notes from the piano roll and // keyboard. An instrument without it is still fully usable; monitoring // falls back to a small default click. // // To add a custom instrument, implement this interface and register it in // registry.ts. Nothing else in the application knows what an instrument is // made of. export interface NoteSpec { timeSec: number; durationSec: number; pitch: number; // MIDI note number velocity: number; // 0..1 } export interface RenderRequest { notes: NoteSpec[]; sampleRate: number; lengthSamples: number; /** Fast preview for playback, full quality for export; instruments * without tiers ignore it. */ quality?: 'preview' | 'full'; /** Values for the instrument's knobs (per track); missing keys mean the * knob's default. */ settings?: Record; } /** A user-editable instrument parameter, declared by the instrument. */ export interface KnobSpec { key: string; label: string; min: number; max: number; default: number; step?: number; scale?: 'log'; } export interface LiveVoice { noteOff(): void; // begin release cut(): void; // stop immediately } export interface Instrument { id: string; name: string; render(req: RenderRequest): Float32Array | Promise; noteOn?(ctx: BaseAudioContext, dest: AudioNode, pitch: number, velocity: number, whenSec: number): LiveVoice; /** Curated editable parameters; tracks store their values in settings. */ knobs?: KnobSpec[]; }