@soundor/vst3-host 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CMakeLists.txt +194 -0
  2. package/CMakePresets.json +115 -0
  3. package/LICENSE +21 -0
  4. package/NOTICE.md +17 -0
  5. package/README.md +40 -2
  6. package/cmake/Vst3HostDependencies.cmake +179 -0
  7. package/dist/cli.d.mts +1 -0
  8. package/dist/cli.mjs +88 -0
  9. package/dist/cli.mjs.map +1 -0
  10. package/dist/index.d.mts +586 -0
  11. package/dist/index.d.mts.map +1 -0
  12. package/dist/index.mjs +1 -0
  13. package/dist/prepare-ayjTVhfk.mjs +1149 -0
  14. package/dist/prepare-ayjTVhfk.mjs.map +1 -0
  15. package/native/src/Bundle.cpp +253 -0
  16. package/native/src/Bundle.h +32 -0
  17. package/native/src/EditorArea.h +92 -0
  18. package/native/src/EditorAreaMac.mm +52 -0
  19. package/native/src/EditorAreaWindows.cpp +66 -0
  20. package/native/src/EditorAreaX11.cpp +512 -0
  21. package/native/src/EditorWindow.h +72 -0
  22. package/native/src/EditorWindowMac.mm +134 -0
  23. package/native/src/EditorWindowWindows.cpp +148 -0
  24. package/native/src/EventLoop.h +50 -0
  25. package/native/src/EventLoopLinux.cpp +204 -0
  26. package/native/src/EventLoopMac.mm +146 -0
  27. package/native/src/EventLoopWindows.cpp +132 -0
  28. package/native/src/HostContext.cpp +217 -0
  29. package/native/src/HostContext.h +116 -0
  30. package/native/src/HostInterface.cpp +1026 -0
  31. package/native/src/HostInterface.h +138 -0
  32. package/native/src/HostWindow.cpp +901 -0
  33. package/native/src/HostWindow.h +187 -0
  34. package/native/src/Ipc.cpp +158 -0
  35. package/native/src/Ipc.h +91 -0
  36. package/native/src/Json.cpp +426 -0
  37. package/native/src/Json.h +85 -0
  38. package/native/src/LiveAudio.cpp +416 -0
  39. package/native/src/LiveAudio.h +121 -0
  40. package/native/src/Main.cpp +178 -0
  41. package/native/src/Paths.h +20 -0
  42. package/native/src/Plugin.cpp +1865 -0
  43. package/native/src/Plugin.h +321 -0
  44. package/native/src/Session.cpp +656 -0
  45. package/native/src/Session.h +82 -0
  46. package/native/src/Settings.cpp +93 -0
  47. package/native/src/Settings.h +23 -0
  48. package/native/src/Version.h.in +11 -0
  49. package/native/src/X11Library.cpp +127 -0
  50. package/native/src/X11Library.h +83 -0
  51. package/native/tools/Embed.cpp +49 -0
  52. package/package.json +58 -3
  53. package/protocol.json +7 -0
  54. package/targets.json +33 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n// soundor-vst3-host <command>\n//\n// open <plugin.vst3> [--class <name>] [--bare | --interface]\n// [--sample-rate <hz>] [--block-size <frames>] open a plugin's editor until its window closes\n// prepare [--mode prebuilt|published|source] [--artifact <dir>] select or build the executable\n// resolve print the executable launchHost() runs\n// inputs print the native input fingerprint\nimport { parseArgs } from 'node:util';\n\nimport { Vst3HostError } from './errors.ts';\nimport { launchHost } from './host.ts';\nimport { nativeInputs } from './inputs.ts';\nimport { type BuildMode, prepareHost } from './prepare.ts';\nimport { resolveHost } from './resolve.ts';\n\nconst { positionals, values } = parseArgs({\n allowPositionals: true,\n options: {\n mode: { type: 'string' },\n artifact: { type: 'string' },\n commit: { type: 'string' },\n class: { type: 'string' },\n bare: { type: 'boolean' },\n interface: { type: 'boolean' },\n 'sample-rate': { type: 'string' },\n 'block-size': { type: 'string' },\n },\n});\n\nconst USAGE = `usage: soundor-vst3-host <command>\n open <plugin.vst3> [--class <name>] [--bare | --interface] [--sample-rate <hz>] [--block-size <frames>]\n prepare [--mode prebuilt|published|source] [--artifact <dir>] [--commit <sha>]\n resolve\n inputs`;\n\n/** Opens a plugin's editor and waits until its window is closed. */\nasync function open(): Promise<void> {\n const plugin = positionals[1];\n if (plugin === undefined) throw new Error('open needs a .vst3 bundle');\n if (values.bare && values.interface)\n throw new Error('--bare and --interface are opposites');\n const number = (name: 'sample-rate' | 'block-size'): number | undefined => {\n const text = values[name];\n if (text === undefined) return undefined;\n const value = Number(text);\n if (!Number.isFinite(value)) throw new Error(`--${name} is a number`);\n return value;\n };\n const host = await launchHost({\n plugin,\n className: values.class,\n editor: true,\n presentation: values.bare ? 'editor' : values.interface ? 'host' : null,\n sampleRate: number('sample-rate'),\n blockSize: number('block-size'),\n requestTimeout: 0x7fffffff,\n onLog: (line) => console.error(line),\n });\n const closed = new Promise<void>((resolve) => {\n host.once('editorClosed', () => resolve());\n host.once('exit', () => resolve());\n process.once('SIGINT', () => resolve());\n process.once('SIGTERM', () => resolve());\n });\n console.error(\n `${host.info.name}: close its window (or press Ctrl+C) to quit`,\n );\n await closed;\n await host.close();\n}\n\ntry {\n switch (positionals[0]) {\n case 'open':\n await open();\n break;\n case 'prepare': {\n const mode = values.mode ?? 'prebuilt';\n if (mode !== 'prebuilt' && mode !== 'published' && mode !== 'source')\n throw new Error(\n `--mode is \"prebuilt\", \"published\" or \"source\", not \"${mode}\"`,\n );\n await prepareHost({\n mode: mode as BuildMode,\n artifact: values.artifact,\n commit: values.commit,\n });\n break;\n }\n case 'resolve': {\n const resolved = resolveHost();\n console.log(\n `${resolved.executable}\\t(${resolved.source}: ${resolved.reason})`,\n );\n break;\n }\n case 'inputs':\n console.log(JSON.stringify(nativeInputs(), null, 2));\n break;\n default:\n console.error(USAGE);\n process.exitCode = 64;\n }\n} catch (error) {\n console.error(\n error instanceof Vst3HostError\n ? `error (${error.code}): ${error.message}`\n : `error: ${(error as Error).message}`,\n );\n process.exitCode = 1;\n}\n"],"mappings":";;;;AAgBA,MAAM,EAAE,aAAa,WAAW,UAAU;CACxC,kBAAkB;CAClB,SAAS;EACP,MAAM,EAAE,MAAM,SAAS;EACvB,UAAU,EAAE,MAAM,SAAS;EAC3B,QAAQ,EAAE,MAAM,SAAS;EACzB,OAAO,EAAE,MAAM,SAAS;EACxB,MAAM,EAAE,MAAM,UAAU;EACxB,WAAW,EAAE,MAAM,UAAU;EAC7B,eAAe,EAAE,MAAM,SAAS;EAChC,cAAc,EAAE,MAAM,SAAS;CACjC;AACF,CAAC;AAED,MAAM,QAAQ;;;;;;AAOd,eAAe,OAAsB;CACnC,MAAM,SAAS,YAAY;CAC3B,IAAI,WAAW,KAAA,GAAW,MAAM,IAAI,MAAM,2BAA2B;CACrE,IAAI,OAAO,QAAQ,OAAO,WACxB,MAAM,IAAI,MAAM,sCAAsC;CACxD,MAAM,UAAU,SAA2D;EACzE,MAAM,OAAO,OAAO;EACpB,IAAI,SAAS,KAAA,GAAW,OAAO,KAAA;EAC/B,MAAM,QAAQ,OAAO,IAAI;EACzB,IAAI,CAAC,OAAO,SAAS,KAAK,GAAG,MAAM,IAAI,MAAM,KAAK,KAAK,aAAa;EACpE,OAAO;CACT;CACA,MAAM,OAAO,MAAM,WAAW;EAC5B;EACA,WAAW,OAAO;EAClB,QAAQ;EACR,cAAc,OAAO,OAAO,WAAW,OAAO,YAAY,SAAS;EACnE,YAAY,OAAO,aAAa;EAChC,WAAW,OAAO,YAAY;EAC9B,gBAAgB;EAChB,QAAQ,SAAS,QAAQ,MAAM,IAAI;CACrC,CAAC;CACD,MAAM,SAAS,IAAI,SAAe,YAAY;EAC5C,KAAK,KAAK,sBAAsB,QAAQ,CAAC;EACzC,KAAK,KAAK,cAAc,QAAQ,CAAC;EACjC,QAAQ,KAAK,gBAAgB,QAAQ,CAAC;EACtC,QAAQ,KAAK,iBAAiB,QAAQ,CAAC;CACzC,CAAC;CACD,QAAQ,MACN,GAAG,KAAK,KAAK,KAAK,6CACpB;CACA,MAAM;CACN,MAAM,KAAK,MAAM;AACnB;AAEA,IAAI;CACF,QAAQ,YAAY,IAApB;EACE,KAAK;GACH,MAAM,KAAK;GACX;EACF,KAAK,WAAW;GACd,MAAM,OAAO,OAAO,QAAQ;GAC5B,IAAI,SAAS,cAAc,SAAS,eAAe,SAAS,UAC1D,MAAM,IAAI,MACR,uDAAuD,KAAK,EAC9D;GACF,MAAM,YAAY;IACV;IACN,UAAU,OAAO;IACjB,QAAQ,OAAO;GACjB,CAAC;GACD;EACF;EACA,KAAK,WAAW;GACd,MAAM,WAAW,YAAY;GAC7B,QAAQ,IACN,GAAG,SAAS,WAAW,KAAK,SAAS,OAAO,IAAI,SAAS,OAAO,EAClE;GACA;EACF;EACA,KAAK;GACH,QAAQ,IAAI,KAAK,UAAU,aAAa,GAAG,MAAM,CAAC,CAAC;GACnD;EACF;GACE,QAAQ,MAAM,KAAK;GACnB,QAAQ,WAAW;CACvB;AACF,SAAS,OAAO;CACd,QAAQ,MACN,iBAAiB,gBACb,UAAU,MAAM,KAAK,KAAK,MAAM,YAChC,UAAW,MAAgB,SACjC;CACA,QAAQ,WAAW;AACrB"}
@@ -0,0 +1,586 @@
1
+ import { ChildProcess } from "node:child_process";
2
+ /** A bus's speaker arrangement: a channel count, or a name ("mono",
3
+ "stereo", an SDK name such as "5.1"), or a hexadecimal mask ("0x3"). */
4
+ interface BusSetup {
5
+ channels?: number;
6
+ arrangement?: string;
7
+ /** Default: main buses and the buses the plugin marks default-active. */
8
+ active?: boolean;
9
+ }
10
+ type ProcessMode = 'realtime' | 'offline' | 'prefetch';
11
+ interface ProcessingSetup {
12
+ /** Hz. Default 48000. */
13
+ sampleRate?: number;
14
+ /** The largest block the plugin is given, in frames. Default 512. */
15
+ blockSize?: number;
16
+ /** The mode the plugin is told it runs in (ProcessSetup::processMode).
17
+ Default "realtime": what a DAW's playback does. Processing is offline
18
+ either way. */
19
+ processMode?: ProcessMode;
20
+ /** By audio input bus index; `null` or a missing entry keeps the
21
+ plugin's default. */
22
+ inputs?: (BusSetup | null)[];
23
+ outputs?: (BusSetup | null)[];
24
+ }
25
+ interface BusInfo {
26
+ index: number;
27
+ name: string;
28
+ type: 'main' | 'aux';
29
+ channels: number;
30
+ /** Audio buses: the arrangement's name, or its mask in hexadecimal. */
31
+ arrangement?: string;
32
+ active: boolean;
33
+ defaultActive: boolean;
34
+ }
35
+ interface PluginClass {
36
+ name: string;
37
+ /** The class's 32-digit hexadecimal id. */
38
+ classId: string;
39
+ }
40
+ interface PluginInfo {
41
+ path: string;
42
+ name: string;
43
+ classId: string;
44
+ vendor: string;
45
+ version: string;
46
+ sdkVersion: string;
47
+ subCategories: string[];
48
+ factory: {
49
+ vendor: string;
50
+ url: string;
51
+ email: string;
52
+ };
53
+ /** Every audio processor class of the bundle. */
54
+ classes: PluginClass[];
55
+ separateController: boolean;
56
+ hasController: boolean;
57
+ sampleRate: number;
58
+ blockSize: number;
59
+ processMode: ProcessMode;
60
+ buses: {
61
+ audioInputs: BusInfo[];
62
+ audioOutputs: BusInfo[];
63
+ eventInputs: BusInfo[];
64
+ eventOutputs: BusInfo[];
65
+ };
66
+ parameterCount: number;
67
+ latencySamples: number;
68
+ tailSamples: number | 'infinite';
69
+ }
70
+ /** A VST3 parameter. `id` is the plugin's ParamID (an unsigned 32-bit
71
+ integer), stable across instances and sessions of the same plugin. */
72
+ interface ParameterInfo {
73
+ id: number;
74
+ title: string;
75
+ shortTitle: string;
76
+ units: string;
77
+ /** 0: continuous; 1: a toggle; n: n + 1 discrete values. */
78
+ stepCount: number;
79
+ defaultNormalized: number;
80
+ unitId: number;
81
+ flags: {
82
+ canAutomate: boolean;
83
+ readOnly: boolean;
84
+ wrap: boolean;
85
+ list: boolean;
86
+ hidden: boolean;
87
+ programChange: boolean;
88
+ bypass: boolean;
89
+ };
90
+ /** The current value, from 0 to 1. */
91
+ normalized: number;
92
+ /** The same value in the plugin's own units (normalizedParamToPlain). */
93
+ plain: number;
94
+ /** The plugin's text for it (getParamStringByValue), or null. */
95
+ display: string | null;
96
+ }
97
+ /** Either value; the other is derived by the plugin's controller. */
98
+ type ParameterValue = {
99
+ normalized: number;
100
+ } | {
101
+ plain: number;
102
+ };
103
+ /** A parameter found by its title, from `Vst3Host.parameter()`. */
104
+ interface HostParameter {
105
+ /** Its current values. */
106
+ get(options?: RequestOptions): Promise<ParameterInfo>;
107
+ /** Sets the controller's value now and hands the change to the processor
108
+ at the first frame of the next process call. */
109
+ set(value: ParameterValue | number, options?: RequestOptions): Promise<ParameterInfo>;
110
+ }
111
+ interface ParameterChange {
112
+ id: number;
113
+ /** Normalized, 0 to 1. */
114
+ value: number;
115
+ /** The frame it applies at, from the start of the process call. Default 0. */
116
+ time?: number;
117
+ }
118
+ interface TimedEvent {
119
+ /** The frame, from the start of the process call. Default 0. */
120
+ time?: number;
121
+ /** MIDI channel 0–15. Default 0. */
122
+ channel?: number;
123
+ }
124
+ interface NoteEventBase extends TimedEvent {
125
+ /** Event bus index. Default 0. */
126
+ bus?: number;
127
+ pitch: number;
128
+ /** -1 (default): none. */
129
+ noteId?: number;
130
+ }
131
+ interface NoteOnEvent extends NoteEventBase {
132
+ type: 'noteOn';
133
+ /** 0 to 1. Default 1. */
134
+ velocity?: number;
135
+ /** Cents. */
136
+ tuning?: number;
137
+ /** Frames, when known in advance. */
138
+ length?: number;
139
+ }
140
+ interface NoteOffEvent extends NoteEventBase {
141
+ type: 'noteOff';
142
+ velocity?: number;
143
+ tuning?: number;
144
+ }
145
+ interface PolyPressureEvent extends NoteEventBase {
146
+ type: 'polyPressure';
147
+ pressure: number;
148
+ }
149
+ /** MIDI controllers reach VST3 plugins as parameter changes, through the
150
+ plugin's IMidiMapping; one it does not map is dropped with a warning. */
151
+ interface ControlChangeEvent extends TimedEvent {
152
+ type: 'controlChange';
153
+ bus?: number;
154
+ controller: number;
155
+ /** 0 to 1 (MIDI value / 127). */
156
+ value: number;
157
+ }
158
+ interface PitchBendEvent extends TimedEvent {
159
+ type: 'pitchBend';
160
+ bus?: number;
161
+ /** -1 to 1. */
162
+ value: number;
163
+ }
164
+ interface ChannelPressureEvent extends TimedEvent {
165
+ type: 'channelPressure';
166
+ bus?: number;
167
+ /** 0 to 1. */
168
+ value: number;
169
+ }
170
+ type InputEvent = NoteOnEvent | NoteOffEvent | PolyPressureEvent | ControlChangeEvent | PitchBendEvent | ChannelPressureEvent;
171
+ type OutputEvent = {
172
+ type: 'noteOn' | 'noteOff';
173
+ time: number;
174
+ bus: number;
175
+ channel: number;
176
+ pitch: number;
177
+ velocity: number;
178
+ noteId: number;
179
+ } | {
180
+ type: 'polyPressure';
181
+ time: number;
182
+ bus: number;
183
+ channel: number;
184
+ pitch: number;
185
+ pressure: number;
186
+ noteId: number;
187
+ } | {
188
+ type: 'midiCC';
189
+ time: number;
190
+ bus: number;
191
+ channel: number;
192
+ controller: number;
193
+ value: number;
194
+ value2: number;
195
+ } | {
196
+ type: 'other';
197
+ time: number;
198
+ bus: number;
199
+ vstType: number;
200
+ };
201
+ interface Transport {
202
+ playing: boolean;
203
+ /** Beats per minute. */
204
+ tempo: number;
205
+ timeSignature: {
206
+ numerator: number;
207
+ denominator: number;
208
+ };
209
+ /** The project position, in frames. */
210
+ samplePosition: number;
211
+ /** The same position in quarter notes. */
212
+ musicalPosition: number;
213
+ }
214
+ /** Changes to the host's transport, kept for later calls. Give the position
215
+ in frames or in quarter notes, not both. */
216
+ interface TransportUpdate {
217
+ playing?: boolean;
218
+ tempo?: number;
219
+ timeSignature?: {
220
+ numerator?: number;
221
+ denominator?: number;
222
+ };
223
+ samplePosition?: number;
224
+ musicalPosition?: number;
225
+ }
226
+ /** Audio as channels: one Float32Array per channel, all the same length. */
227
+ type AudioBus = readonly Float32Array[];
228
+ interface RequestOptions {
229
+ /** Milliseconds; the host is stopped if it does not answer in time.
230
+ Default: the host's requestTimeout. */
231
+ timeout?: number;
232
+ signal?: AbortSignal;
233
+ }
234
+ interface ProcessRequest extends RequestOptions {
235
+ /** Frames to process. Default: the length of the given input channels;
236
+ required when no input is given (instruments). */
237
+ frames?: number;
238
+ /** By audio input bus index. A missing, `null` or `undefined` bus gets
239
+ silence. A given bus has exactly the bus's channel count. */
240
+ inputs?: readonly (AudioBus | null | undefined)[];
241
+ events?: readonly InputEvent[];
242
+ parameterChanges?: readonly ParameterChange[];
243
+ transport?: TransportUpdate;
244
+ }
245
+ interface ProcessResult {
246
+ frames: number;
247
+ /** By audio output bus index; an inactive bus has no channels. The
248
+ arrays are the caller's. */
249
+ outputs: Float32Array[][];
250
+ events: OutputEvent[];
251
+ /** What the processor reported (meters, read-only values), with the
252
+ frame each applies at. */
253
+ parameterChanges: Required<ParameterChange>[];
254
+ /** The transport after the call. */
255
+ transport: Transport;
256
+ /** Input the plugin could not take (an unmapped MIDI controller). */
257
+ warnings: string[];
258
+ }
259
+ /** A plugin's saved state: its processor's, then its controller's. */
260
+ interface PluginState {
261
+ component: Uint8Array;
262
+ controller: Uint8Array;
263
+ }
264
+ /**
265
+ * How an editor is shown: `editor`, a window that is the plugin's editor
266
+ * alone, or `host`, the editor with the host interface around it (a dock
267
+ * and a side panel). Either way the editor has the same size, and
268
+ * everything the interface does can be done through this API.
269
+ */
270
+ type Presentation = 'editor' | 'host';
271
+ interface EditorInfo {
272
+ open: boolean;
273
+ /** The editor's size (not the window's). */
274
+ width?: number;
275
+ height?: number;
276
+ resizable?: boolean;
277
+ scale?: number;
278
+ platformType?: string;
279
+ presentation?: Presentation;
280
+ /** The window's content size: the editor's in `editor`, more in `host`. */
281
+ window?: {
282
+ width: number;
283
+ height: number;
284
+ };
285
+ /** `host`: the frames the interface has presented. An idle window
286
+ presents none. */
287
+ interfaceFrames?: number;
288
+ }
289
+ /** Where live audio's input comes from: a 220 Hz triangle wave, a WAV
290
+ file (looped), the default recording device, or silence. It plays while
291
+ the transport does. */
292
+ type AudioInput = 'oscillator' | 'file' | 'microphone' | 'none';
293
+ interface AudioSettings {
294
+ input?: AudioInput;
295
+ /** A WAV file's path, for the `file` input (selects it when no input is given). */
296
+ file?: string;
297
+ muted?: boolean;
298
+ /** The output volume, from 0 to 1. */
299
+ volume?: number;
300
+ }
301
+ interface AudioStatus {
302
+ /** Live audio plays through the default output device. */
303
+ running: boolean;
304
+ muted: boolean;
305
+ volume: number;
306
+ input: AudioInput;
307
+ file: string | null;
308
+ /** The output device's name while running. */
309
+ device: string | null;
310
+ /** The device or the plugin's processing failed. */
311
+ error: string | null;
312
+ /** The input could not be opened (a microphone) or read (a file). */
313
+ inputError: string | null;
314
+ }
315
+ interface LatencyInfo {
316
+ latencySamples: number;
317
+ tailSamples: number | 'infinite';
318
+ }
319
+ interface HostEvents {
320
+ /** The editor's controller began, made or ended a parameter edit. */
321
+ beginEdit: {
322
+ id: number;
323
+ };
324
+ performEdit: {
325
+ id: number;
326
+ value: number;
327
+ };
328
+ endEdit: {
329
+ id: number;
330
+ };
331
+ /** The plugin asked to be restarted; the host did so between calls. */
332
+ restart: {
333
+ flags: number;
334
+ reasons: string[];
335
+ latencySamples: number;
336
+ };
337
+ dirty: {
338
+ dirty: boolean;
339
+ };
340
+ editorRequested: Record<string, never>;
341
+ editorResized: EditorInfo;
342
+ /** The user closed the editor's window. */
343
+ editorClosed: Record<string, never>;
344
+ /** Live audio changed from the host interface (started, stopped, muted,
345
+ another input or volume). */
346
+ audioChanged: AudioStatus;
347
+ /** The host process ended. */
348
+ exit: {
349
+ code: number | null;
350
+ signal: NodeJS.Signals | null;
351
+ };
352
+ }
353
+ interface LaunchOptions extends ProcessingSetup {
354
+ /** The .vst3 bundle to load, by path; it need not be installed. */
355
+ plugin: string;
356
+ /** The audio processor class, when the bundle has several. */
357
+ className?: string;
358
+ classId?: string;
359
+ /** UI mode: open the plugin's editor in a native window. Default false
360
+ (headless: no window, no display needed). */
361
+ editor?: boolean;
362
+ /** The editor's content scale (Windows, Linux). Default: the window's. */
363
+ scale?: number;
364
+ /** How the editor is shown (with `editor: true`): `editor` (the default),
365
+ a window that is the editor alone, or `host`, with the host interface.
366
+ `null`: as the user's host settings say (`host` unless they turned the
367
+ interface off), what the `open` command does. */
368
+ presentation?: Presentation | null;
369
+ /** The executable. Default: resolveHost(). */
370
+ executable?: string;
371
+ /** Runs the host in a process group of its own, so that a terminal's Ctrl+C
372
+ reaches only Node, which can ask the plugin for its state before calling
373
+ `close()`. It still ends with Node. Default false. */
374
+ detached?: boolean;
375
+ /** Added to (or, with inheritEnv: false, instead of) process.env.
376
+ SOUNDOR_DEVTOOLS_SESSION reaches the plugin this way. */
377
+ env?: Record<string, string | undefined>;
378
+ inheritEnv?: boolean;
379
+ cwd?: string;
380
+ /** Milliseconds for the host to start and load the plugin. Default 30000. */
381
+ startTimeout?: number;
382
+ /** Default timeout of each request, in milliseconds. Default 60000. */
383
+ requestTimeout?: number;
384
+ /** The largest frame either side accepts. Default 256 MiB. */
385
+ maxPayloadBytes?: number;
386
+ /** Each line the host or the plugin writes to stderr. */
387
+ onLog?: (line: string) => void;
388
+ signal?: AbortSignal;
389
+ }
390
+ /** Starts a host process, loads the plugin and resolves once it is ready. */
391
+ export declare function launchHost(options: LaunchOptions): Promise<Vst3Host>;
392
+ interface HostOptions {
393
+ maxPayloadBytes: number;
394
+ requestTimeout: number;
395
+ onLog: ((line: string) => void) | undefined;
396
+ executable: string;
397
+ }
398
+ interface HostIdentity {
399
+ protocol: number;
400
+ version: string;
401
+ sdkVersion: string;
402
+ platform: string;
403
+ arch: string;
404
+ mode: 'ui' | 'headless';
405
+ maxPayloadBytes: number;
406
+ }
407
+ /** A running host with one plugin loaded. Requests run one at a time, in
408
+ the order they are made. */
409
+ export declare class Vst3Host {
410
+ #private;
411
+ /** @internal Use launchHost(). */
412
+ constructor(child: ChildProcess, options: HostOptions);
413
+ /** The host process's id. */
414
+ get pid(): number | undefined;
415
+ /** What the host reported when it started. */
416
+ get identity(): HostIdentity;
417
+ /** The loaded plugin, as of launch or the last recreate/configure. */
418
+ get info(): PluginInfo;
419
+ /** Resolves when the process has ended. */
420
+ get exited(): Promise<{
421
+ code: number | null;
422
+ signal: NodeJS.Signals | null;
423
+ }>;
424
+ /** The end of what the host and the plugin wrote to stderr. */
425
+ get diagnostics(): string;
426
+ on<E extends keyof HostEvents>(event: E, listener: (params: HostEvents[E]) => void): this;
427
+ off<E extends keyof HostEvents>(event: E, listener: (params: HostEvents[E]) => void): this;
428
+ once<E extends keyof HostEvents>(event: E, listener: (params: HostEvents[E]) => void): this;
429
+ /** @internal */
430
+ ready(timeout: number, signal?: AbortSignal): Promise<void>;
431
+ /** @internal */
432
+ load(options: LaunchOptions, timeout: number, signal?: AbortSignal): Promise<void>;
433
+ getInfo(options?: RequestOptions): Promise<PluginInfo>;
434
+ getParameters(options?: RequestOptions): Promise<ParameterInfo[]>;
435
+ getParameter(id: number, options?: RequestOptions): Promise<ParameterInfo>;
436
+ /** Sets the controller's value now and hands the change to the processor
437
+ at the first frame of the next process call. */
438
+ setParameter(id: number, value: ParameterValue | number, options?: RequestOptions): Promise<ParameterInfo>;
439
+ /** A parameter by its title, looked up at each use (see
440
+ {@link parameterTitled}). */
441
+ parameter(title: string): HostParameter;
442
+ getLatency(options?: RequestOptions): Promise<LatencyInfo>;
443
+ /** Processes `frames` frames, in blocks of at most the block size. */
444
+ process(request?: ProcessRequest): Promise<ProcessResult>;
445
+ /** The processor's and the controller's state. Pending parameter changes
446
+ reach the processor first (in a process call of zero frames). */
447
+ getState(options?: RequestOptions): Promise<PluginState>;
448
+ setState(state: PluginState, options?: RequestOptions): Promise<void>;
449
+ /** Deactivates and reactivates the plugin: it clears delay lines, held
450
+ notes and other processing state. The transport is kept. */
451
+ reset(options?: RequestOptions): Promise<void>;
452
+ /** A fresh instance of the same class and setup, in the same process.
453
+ The transport starts over. */
454
+ recreate(options?: RequestOptions): Promise<PluginInfo>;
455
+ /** A new sample rate, block size, mode or bus layout. What is not given
456
+ stays as it is. */
457
+ configure(setup: ProcessingSetup, options?: RequestOptions): Promise<PluginInfo>;
458
+ /** Opens the editor, or shows an open one in another presentation (it
459
+ opens again there, at the same size). */
460
+ openEditor(options?: RequestOptions & {
461
+ scale?: number;
462
+ presentation?: Presentation;
463
+ }): Promise<EditorInfo>;
464
+ closeEditor(options?: RequestOptions): Promise<EditorInfo>;
465
+ resizeEditor(width: number, height: number, options?: RequestOptions): Promise<EditorInfo>;
466
+ getEditor(options?: RequestOptions): Promise<EditorInfo>;
467
+ /** Starts live audio through the default output device, with `settings`
468
+ applied first. Fails with `audio-unavailable` without a device.
469
+ While it runs, `process` fails: the plugin is processing live. */
470
+ startAudio(settings?: AudioSettings & RequestOptions): Promise<AudioStatus>;
471
+ stopAudio(options?: RequestOptions): Promise<AudioStatus>;
472
+ /** Changes live audio's input, volume or muting, running or not. */
473
+ setAudio(settings: AudioSettings & RequestOptions): Promise<AudioStatus>;
474
+ getAudio(options?: RequestOptions): Promise<AudioStatus>;
475
+ /** The host's transport, which live audio advances while it plays. */
476
+ getTransport(options?: RequestOptions): Promise<Transport>;
477
+ /** Changes the transport, as `process({ transport })` does, without
478
+ processing: play and stop live audio's transport, or set its tempo. */
479
+ setTransport(update: TransportUpdate, options?: RequestOptions): Promise<Transport>;
480
+ /** Unloads the plugin and ends the process: politely, then by force.
481
+ Safe to call more than once and after a failure. */
482
+ close(timeout?: number): Promise<{
483
+ code: number | null;
484
+ signal: NodeJS.Signals | null;
485
+ }>;
486
+ [Symbol.asyncDispose](): Promise<void>;
487
+ }
488
+ /** Codes the host reports, and the client's own. */
489
+ type Vst3HostErrorCode = 'plugin-not-found' | 'invalid-bundle' | 'incompatible-architecture' | 'load-failed' | 'unsupported-plugin' | 'no-matching-class' | 'ambiguous-class' | 'initialization-failed' | 'unsupported-configuration' | 'unknown-parameter' | 'plugin-error' | 'no-editor' | 'no-display' | 'headless' | 'audio-unavailable' | 'invalid-request' | 'invalid-state' | 'unknown-method' | 'message-too-large' | 'internal-error' | 'host-exited' | 'timeout' | 'aborted' | 'closed' | 'protocol-error' | 'incompatible-host' | 'executable-not-found' | 'platform-package-missing' | 'unsupported-platform' | 'selection-failed';
490
+ export declare class Vst3HostError extends Error {
491
+ readonly name = "Vst3HostError";
492
+ readonly code: Vst3HostErrorCode;
493
+ readonly details: Record<string, unknown> | undefined;
494
+ constructor(code: Vst3HostErrorCode, message: string, details?: Record<string, unknown>, options?: ErrorOptions);
495
+ }
496
+ interface Provenance {
497
+ format: 1;
498
+ name: '@soundor/vst3-host';
499
+ version: string;
500
+ protocol: number;
501
+ target: string;
502
+ architectures: string[];
503
+ configuration: 'Release';
504
+ /** The commit it was built from (CI), or null for a local build. */
505
+ sourceCommit: string | null;
506
+ /** nativeInputs() of the sources it was built from. */
507
+ sourceFingerprint: string;
508
+ executable: {
509
+ path: string;
510
+ sha256: string;
511
+ size: number;
512
+ };
513
+ /** Linux: the newest glibc symbol version the executable needs. */
514
+ glibc?: string;
515
+ }
516
+ interface ResolvedHost {
517
+ executable: string;
518
+ source: 'explicit' | 'package' | 'selection';
519
+ /** Why this one, for logs. */
520
+ reason: string;
521
+ provenance?: Provenance;
522
+ }
523
+ interface ResolveOptions {
524
+ executable?: string;
525
+ /** Default: this package's root. */
526
+ root?: string;
527
+ }
528
+ export declare function resolveHost(options?: ResolveOptions): ResolvedHost;
529
+ type Fetch = typeof fetch;
530
+ interface Target {
531
+ target: string;
532
+ package: string;
533
+ os: string[];
534
+ cpu: string[];
535
+ libc?: string[];
536
+ runner: string;
537
+ architectures: string[];
538
+ /** Relative to the platform package's root. */
539
+ executable: string;
540
+ }
541
+ /** The platform packages a release generates (targets.json). */
542
+ export declare const targets: readonly Target[];
543
+ interface Platform {
544
+ platform: NodeJS.Platform;
545
+ arch: string;
546
+ /** Linux: "glibc" or "musl". */
547
+ libc?: string;
548
+ /** Linux with glibc: its version, such as "2.39". */
549
+ glibc?: string;
550
+ }
551
+ /** The target whose executable runs here, if any. */
552
+ export declare function targetFor(platform?: Platform): Target | undefined;
553
+ type BuildMode = 'prebuilt' | 'published' | 'source';
554
+ interface PrepareOptions {
555
+ mode?: BuildMode;
556
+ /** A CI artifact directory (an executable and its soundor-vst3-host.json).
557
+ Default: SOUNDOR_VST3_HOST_ARTIFACT. */
558
+ artifact?: string;
559
+ /** The commit an artifact must come from. Default: GITHUB_SHA when set. */
560
+ commit?: string;
561
+ /** Default: SOUNDOR_CACHE, else the user cache directory. */
562
+ cache?: string;
563
+ registry?: string;
564
+ fetcher?: Fetch;
565
+ /** Default: console.log. */
566
+ log?: (message: string) => void;
567
+ root?: string;
568
+ /** @internal Replaces the CMake build (tests). */
569
+ build?: (reason: string) => PreparedHost;
570
+ }
571
+ interface PreparedHost {
572
+ executable: string;
573
+ mode: 'prebuilt' | 'source' | 'artifact';
574
+ reason: string;
575
+ sourceFingerprint: string;
576
+ }
577
+ export declare function prepareHost(options?: PrepareOptions): Promise<PreparedHost>;
578
+ interface NativeInputs {
579
+ fingerprint: string;
580
+ files: string[];
581
+ version: string;
582
+ }
583
+ export declare function nativeInputs(root?: string): NativeInputs;
584
+ export declare const PROTOCOL_VERSION: number;
585
+ export type { AudioBus, AudioInput, AudioSettings, AudioStatus, BuildMode, BusInfo, BusSetup, ChannelPressureEvent, ControlChangeEvent, EditorInfo, HostEvents, HostIdentity, HostParameter, InputEvent, LatencyInfo, LaunchOptions, NoteOffEvent, NoteOnEvent, OutputEvent, ParameterChange, ParameterInfo, ParameterValue, PitchBendEvent, PluginClass, PluginInfo, PluginState, PolyPressureEvent, PrepareOptions, PreparedHost, Presentation, ProcessMode, ProcessRequest, ProcessResult, ProcessingSetup, RequestOptions, ResolveOptions, ResolvedHost, Target, Transport, TransportUpdate, Vst3HostErrorCode };
586
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/host.ts","../src/errors.ts","../src/provenance.ts","../src/resolve.ts","../src/npm.ts","../src/targets.ts","../src/prepare.ts","../src/inputs.ts","../src/protocol.ts"],"mappings":"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"}
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ export { c as PROTOCOL_VERSION, n as Vst3Host, l as Vst3HostError, r as launchHost, a as nativeInputs, t as prepareHost, i as resolveHost, o as targetFor, s as targets } from "./prepare-ayjTVhfk.mjs";