// 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; } 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; }