1// The instrument extension point. An instrument turns note events into
2// audio in two ways:
3//
4// - render(): the offline path. Given every note with times in seconds,
5// produce one mono buffer for the whole track. This is what playback
6// and WAV export use, and it may be async and arbitrarily expensive
7// (a GPU physical model, a worker, a remote call). Results are cached
8// per track and invalidated by note or instrument changes.
9//
10// - noteOn(): the optional live path, used for low-latency monitoring
11// while recording and for previewing notes from the piano roll and
12// keyboard. An instrument without it is still fully usable; monitoring
13// falls back to a small default click.
14//
15// To add a custom instrument, implement this interface and register it in
16// registry.ts. Nothing else in the application knows what an instrument is
17// made of.
19export interface NoteSpec {
20 timeSec: number;
21 durationSec: number;
22 pitch: number; // MIDI note number
23 velocity: number; // 0..1
24}
26export interface RenderRequest {
27 notes: NoteSpec[];
28 sampleRate: number;
29 lengthSamples: number;
30}
32export interface LiveVoice {
33 noteOff(): void; // begin release
34 cut(): void; // stop immediately
35}
37export interface Instrument {
38 id: string;
39 name: string;
40 render(req: RenderRequest): Float32Array | Promise<Float32Array>;
41 noteOn?(ctx: BaseAudioContext, dest: AudioNode, pitch: number, velocity: number, whenSec: number): LiveVoice;
42}