@openmixer/plugin-qualify 0.0.0-stage → 0.3.0

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 (114) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +203 -2
  3. package/bin/plugin-qualify.mjs +77 -0
  4. package/dist/clap-loader.d.ts +147 -0
  5. package/dist/clap-loader.js +252 -0
  6. package/dist/clap-loader.js.map +1 -0
  7. package/dist/clap-qualify.d.ts +126 -0
  8. package/dist/clap-qualify.js +272 -0
  9. package/dist/clap-qualify.js.map +1 -0
  10. package/dist/host-profiles.d.ts +42 -0
  11. package/dist/host-profiles.js +106 -0
  12. package/dist/host-profiles.js.map +1 -0
  13. package/dist/hosting-codes.d.ts +62 -0
  14. package/dist/hosting-codes.js +72 -0
  15. package/dist/hosting-codes.js.map +1 -0
  16. package/dist/hosting-suitability.d.ts +354 -0
  17. package/dist/hosting-suitability.js +654 -0
  18. package/dist/hosting-suitability.js.map +1 -0
  19. package/dist/index.d.ts +17 -0
  20. package/dist/index.js +20 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/loader.d.ts +26 -0
  23. package/dist/loader.js +9 -0
  24. package/dist/loader.js.map +1 -0
  25. package/dist/lv2-loader.d.ts +7 -0
  26. package/dist/lv2-loader.js +50 -0
  27. package/dist/lv2-loader.js.map +1 -0
  28. package/dist/measurement/cli.d.ts +168 -0
  29. package/dist/measurement/cli.js +353 -0
  30. package/dist/measurement/cli.js.map +1 -0
  31. package/dist/measurement/fixtures.d.ts +23 -0
  32. package/dist/measurement/fixtures.js +129 -0
  33. package/dist/measurement/fixtures.js.map +1 -0
  34. package/dist/measurement/format.d.ts +483 -0
  35. package/dist/measurement/format.js +627 -0
  36. package/dist/measurement/format.js.map +1 -0
  37. package/dist/measurement/guards.d.ts +33 -0
  38. package/dist/measurement/guards.js +61 -0
  39. package/dist/measurement/guards.js.map +1 -0
  40. package/dist/measurement/index.d.ts +36 -0
  41. package/dist/measurement/index.js +39 -0
  42. package/dist/measurement/index.js.map +1 -0
  43. package/dist/measurement/merge.d.ts +143 -0
  44. package/dist/measurement/merge.js +315 -0
  45. package/dist/measurement/merge.js.map +1 -0
  46. package/dist/measurement/plan.d.ts +127 -0
  47. package/dist/measurement/plan.js +141 -0
  48. package/dist/measurement/plan.js.map +1 -0
  49. package/dist/measurement/probe-json.d.ts +61 -0
  50. package/dist/measurement/probe-json.js +253 -0
  51. package/dist/measurement/probe-json.js.map +1 -0
  52. package/dist/measurement/provenance.d.ts +91 -0
  53. package/dist/measurement/provenance.js +173 -0
  54. package/dist/measurement/provenance.js.map +1 -0
  55. package/dist/measurement/sweep-jsonl.d.ts +40 -0
  56. package/dist/measurement/sweep-jsonl.js +154 -0
  57. package/dist/measurement/sweep-jsonl.js.map +1 -0
  58. package/dist/measurement/vocabulary.d.ts +125 -0
  59. package/dist/measurement/vocabulary.js +217 -0
  60. package/dist/measurement/vocabulary.js.map +1 -0
  61. package/dist/qualify-cli.d.ts +83 -0
  62. package/dist/qualify-cli.js +224 -0
  63. package/dist/qualify-cli.js.map +1 -0
  64. package/dist/qualify-declarations.d.ts +98 -0
  65. package/dist/qualify-declarations.js +76 -0
  66. package/dist/qualify-declarations.js.map +1 -0
  67. package/dist/qualify-options.d.ts +22 -0
  68. package/dist/qualify-options.js +36 -0
  69. package/dist/qualify-options.js.map +1 -0
  70. package/dist/rating.d.ts +32 -0
  71. package/dist/rating.js +30 -0
  72. package/dist/rating.js.map +1 -0
  73. package/dist/tool-paths.d.ts +12 -0
  74. package/dist/tool-paths.js +29 -0
  75. package/dist/tool-paths.js.map +1 -0
  76. package/fixtures/clap-scan/controls.json +8 -0
  77. package/fixtures/clap-scan/fake.json +16 -0
  78. package/fixtures/clap-scan/mixed.json +18 -0
  79. package/fixtures/zero-path.lv2/manifest.ttl +3 -0
  80. package/fixtures/zero-path.lv2/zero-path.c +85 -0
  81. package/fixtures/zero-path.lv2/zero-path.ttl +21 -0
  82. package/package.json +91 -3
  83. package/src/clap-loader.ts +393 -0
  84. package/src/clap-qualify.ts +387 -0
  85. package/src/host-profiles.ts +122 -0
  86. package/src/hosting-codes.ts +71 -0
  87. package/src/hosting-suitability.ts +982 -0
  88. package/src/index.ts +19 -0
  89. package/src/loader.ts +30 -0
  90. package/src/lv2-loader.ts +50 -0
  91. package/src/measurement/cli.ts +458 -0
  92. package/src/measurement/fixtures.ts +141 -0
  93. package/src/measurement/format.ts +1064 -0
  94. package/src/measurement/guards.ts +64 -0
  95. package/src/measurement/index.ts +39 -0
  96. package/src/measurement/merge.ts +434 -0
  97. package/src/measurement/plan.ts +219 -0
  98. package/src/measurement/probe-json.ts +271 -0
  99. package/src/measurement/provenance.ts +220 -0
  100. package/src/measurement/sweep-jsonl.ts +173 -0
  101. package/src/measurement/vocabulary.ts +298 -0
  102. package/src/qualify-cli.ts +277 -0
  103. package/src/qualify-declarations.ts +117 -0
  104. package/src/qualify-options.ts +49 -0
  105. package/src/rating.ts +53 -0
  106. package/src/tool-paths.ts +32 -0
  107. package/tools/_declarations.py +21 -0
  108. package/tools/benchmark.py +2462 -0
  109. package/tools/gen-python-declarations.d.mts +4 -0
  110. package/tools/gen-python-declarations.mjs +92 -0
  111. package/tools/hosting-sweep.mjs +51 -0
  112. package/tools/lv2-measure.mjs +204 -0
  113. package/tools/lv2_presets.py +132 -0
  114. package/tools/scan.py +432 -0
@@ -0,0 +1,353 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
3
+ /**
4
+ * `lv2-measure` — the standalone utility's logic, with the subprocess spawning left out.
5
+ *
6
+ * Everything that decides WHAT to run lives here and is pure: argument parsing, the probe
7
+ * pipeline, the progress heuristic, the assembly of the finished document. `tools/lv2-measure.mjs`
8
+ * is the shell that runs the steps and touches the filesystem. Split that way because the
9
+ * interesting failures — a rate silently dropped, a pass run in the wrong order, a partial
10
+ * run written as if complete — are all decisions, and decisions can be tested without a
11
+ * 15-minute sweep and 958 real plugins.
12
+ *
13
+ * ## The pass order is load-bearing
14
+ *
15
+ * `CATALOG_PROVENANCE.md` says it and it is easy to get wrong: the declared-latency pass
16
+ * must run before the measured one, because the measured pass sizes its capture window from
17
+ * the declared figure and computes `declaredMismatch` against it. {@link buildPipeline}
18
+ * encodes that order so no operator has to remember it.
19
+ *
20
+ * ## Nothing probes without an explicit go-ahead
21
+ *
22
+ * The pipeline instantiates and runs every LV2 plugin on the machine. That is a CPU-heavy,
23
+ * mildly hazardous thing to start by accident — a plugin can and does crash its host — so it
24
+ * is gated behind `--run` (or `LV2_MEASURE_RUN=1`), exactly as `benchmark.py` gates itself.
25
+ * `--dry-run` prints the plan and probes nothing.
26
+ */
27
+ import { join } from "node:path";
28
+ import { buildMeasurementDocument } from "./format.js";
29
+ import { measuredPluginsFromProbeOutput } from "./probe-json.js";
30
+ import { buildRun, costMethodFromProbeProvenance, hostFromProbeProvenance } from "./provenance.js";
31
+ import { PROBED_DIMENSIONS } from "./vocabulary.js";
32
+ /** Name and version this tool stamps into every document it writes. */
33
+ export const TOOL_NAME = "lv2-measure";
34
+ /**
35
+ * The tool's own version, independent of {@link ../format.MEASUREMENT_FORMAT_VERSION}: the
36
+ * prober can improve without the schema moving, and a consumer comparing two documents
37
+ * needs to know which of the two it was.
38
+ */
39
+ export const TOOL_VERSION = "0.1.0";
40
+ /**
41
+ * The probe passes an invocation needs, in the only order that produces correct data.
42
+ *
43
+ * A reused `--scan` skips the scan step; everything else follows from the dimensions asked
44
+ * for. The cost pass reads whatever the latency passes produced, so a run measuring both
45
+ * ends with one file carrying both — which is also why `finalCatalog` is a property of the
46
+ * pipeline rather than a fixed name.
47
+ */
48
+ export function buildPipeline(options) {
49
+ const steps = [];
50
+ const benchmark = join(options.toolDir, "benchmark.py");
51
+ const rates = [...options.rates].sort((a, b) => a - b).join(",");
52
+ let current = options.scanPath;
53
+ if (current === undefined) {
54
+ current = join(options.workDir, "scan.json");
55
+ steps.push({
56
+ id: "scan",
57
+ command: options.python,
58
+ args: [join(options.toolDir, "scan.py"), "--out", current],
59
+ produces: current,
60
+ });
61
+ }
62
+ if (options.dimensions.includes("latency")) {
63
+ // Declared first: the measured pass sizes its capture window from this figure and
64
+ // computes declaredMismatch against it. Reversing the two silently degrades both.
65
+ const declared = join(options.workDir, "latency-declared.json");
66
+ steps.push({
67
+ id: "latency-declared",
68
+ command: options.python,
69
+ args: [benchmark, "--in", current, "--out", declared, "--run"],
70
+ produces: declared,
71
+ dimension: "latency",
72
+ });
73
+ const measured = join(options.workDir, "latency-measured.json");
74
+ steps.push({
75
+ id: "latency-measured",
76
+ command: options.python,
77
+ args: [
78
+ benchmark,
79
+ "--in",
80
+ declared,
81
+ "--out",
82
+ measured,
83
+ "--measure",
84
+ "--run",
85
+ "--rates",
86
+ rates,
87
+ ...(options.sweep ? ["--sweep"] : []),
88
+ ],
89
+ produces: measured,
90
+ dimension: "latency",
91
+ });
92
+ current = measured;
93
+ }
94
+ let costProvenance;
95
+ if (options.dimensions.includes("cost")) {
96
+ costProvenance = join(options.workDir, "cost-provenance.json");
97
+ const cost = join(options.workDir, "cost.json");
98
+ steps.push({
99
+ id: "cost",
100
+ command: options.python,
101
+ args: [
102
+ benchmark,
103
+ "--in",
104
+ current,
105
+ "--out",
106
+ cost,
107
+ "--cost",
108
+ "--run",
109
+ "--rates",
110
+ rates,
111
+ "--cost-provenance",
112
+ costProvenance,
113
+ ...(options.costCpu === undefined ? [] : ["--cost-cpu", String(options.costCpu)]),
114
+ ],
115
+ produces: cost,
116
+ dimension: "cost",
117
+ });
118
+ current = cost;
119
+ }
120
+ return {
121
+ steps,
122
+ finalCatalog: current,
123
+ ...(costProvenance === undefined ? {} : { costProvenance }),
124
+ };
125
+ }
126
+ function parseRates(text) {
127
+ const rates = text
128
+ .split(",")
129
+ .map((part) => Number(part.trim()))
130
+ .filter((rate) => Number.isFinite(rate) && rate > 0);
131
+ return rates.length > 0 ? [...new Set(rates)].sort((a, b) => a - b) : undefined;
132
+ }
133
+ function parseDimensions(text) {
134
+ const wanted = text.split(",").map((part) => part.trim());
135
+ const dimensions = PROBED_DIMENSIONS.filter((d) => wanted.includes(d));
136
+ return dimensions.length === wanted.filter((w) => w.length > 0).length && dimensions.length > 0
137
+ ? [...dimensions]
138
+ : undefined;
139
+ }
140
+ /**
141
+ * Parse `lv2-measure`'s command line.
142
+ *
143
+ * There is no default rate list and there never will be. A tool that measures 48 kHz because
144
+ * the operator forgot to say produces a document whose figures are about a rate nobody asked
145
+ * for, and the whole point of a per-rate format is that such a document is a lie by omission.
146
+ */
147
+ export function parseMeasureArgs(argv, env = {}, defaults) {
148
+ let outPath;
149
+ let rates;
150
+ let dimensions = PROBED_DIMENSIONS;
151
+ let scanPath;
152
+ let workDir = defaults.workDir;
153
+ let sweep = false;
154
+ let costCpu;
155
+ let label;
156
+ let toolDir = defaults.toolDir;
157
+ let python = env.PYTHON ?? "python3";
158
+ let run = env.LV2_MEASURE_RUN === "1";
159
+ let dryRun = false;
160
+ for (let i = 0; i < argv.length; i += 1) {
161
+ const flag = argv[i];
162
+ const next = () => {
163
+ i += 1;
164
+ return argv[i];
165
+ };
166
+ switch (flag) {
167
+ case "--out": {
168
+ const value = next();
169
+ if (value === undefined)
170
+ return { ok: false, error: "--out needs a path" };
171
+ outPath = value;
172
+ break;
173
+ }
174
+ case "--rates": {
175
+ const value = next();
176
+ const parsed = value === undefined ? undefined : parseRates(value);
177
+ if (parsed === undefined)
178
+ return { ok: false, error: "--rates needs a comma-separated list of Hz" };
179
+ rates = parsed;
180
+ break;
181
+ }
182
+ case "--dimensions": {
183
+ const value = next();
184
+ const parsed = value === undefined ? undefined : parseDimensions(value);
185
+ if (parsed === undefined) {
186
+ return { ok: false, error: `--dimensions accepts ${PROBED_DIMENSIONS.join(",")}` };
187
+ }
188
+ dimensions = parsed;
189
+ break;
190
+ }
191
+ case "--scan": {
192
+ const value = next();
193
+ if (value === undefined)
194
+ return { ok: false, error: "--scan needs a path" };
195
+ scanPath = value;
196
+ break;
197
+ }
198
+ case "--work-dir": {
199
+ const value = next();
200
+ if (value === undefined)
201
+ return { ok: false, error: "--work-dir needs a path" };
202
+ workDir = value;
203
+ break;
204
+ }
205
+ case "--tool-dir": {
206
+ const value = next();
207
+ if (value === undefined)
208
+ return { ok: false, error: "--tool-dir needs a path" };
209
+ toolDir = value;
210
+ break;
211
+ }
212
+ case "--python": {
213
+ const value = next();
214
+ if (value === undefined)
215
+ return { ok: false, error: "--python needs an interpreter" };
216
+ python = value;
217
+ break;
218
+ }
219
+ case "--cost-cpu": {
220
+ const value = next();
221
+ const cpu = value === undefined ? Number.NaN : Number(value);
222
+ if (!Number.isInteger(cpu) || cpu < 0)
223
+ return { ok: false, error: "--cost-cpu needs a core number" };
224
+ costCpu = cpu;
225
+ break;
226
+ }
227
+ case "--label": {
228
+ const value = next();
229
+ if (value === undefined)
230
+ return { ok: false, error: "--label needs text" };
231
+ label = value;
232
+ break;
233
+ }
234
+ case "--sweep":
235
+ sweep = true;
236
+ break;
237
+ case "--run":
238
+ run = true;
239
+ break;
240
+ case "--dry-run":
241
+ dryRun = true;
242
+ break;
243
+ default:
244
+ return { ok: false, error: `unknown argument: ${String(flag)}` };
245
+ }
246
+ }
247
+ if (rates === undefined) {
248
+ return {
249
+ ok: false,
250
+ error: "--rates is required: a measurement with no stated rate is not a measurement",
251
+ };
252
+ }
253
+ return {
254
+ ok: true,
255
+ options: {
256
+ rates,
257
+ dimensions,
258
+ workDir,
259
+ sweep,
260
+ toolDir,
261
+ python,
262
+ run,
263
+ dryRun,
264
+ ...(outPath === undefined ? {} : { outPath }),
265
+ ...(scanPath === undefined ? {} : { scanPath }),
266
+ ...(costCpu === undefined ? {} : { costCpu }),
267
+ ...(label === undefined ? {} : { label }),
268
+ },
269
+ };
270
+ }
271
+ /**
272
+ * Interpret one line of the prober's stderr.
273
+ *
274
+ * A HEURISTIC over a human-readable log, and worth being honest about: it recognises the
275
+ * phase banner (`== measuring N plugin(s) at R Hz`) and counts the indented one-line-per-
276
+ * plugin results that follow, successes and failures alike. It does not parse the figures —
277
+ * those come from the JSON, which is authoritative. A line it does not recognise advances
278
+ * nothing, so an unparsed log stalls the progress bar rather than corrupting the data.
279
+ */
280
+ export function parseProbeProgress(line) {
281
+ const phase = /^== (?:measuring|CPU cost of) (\d+) plugin\(s\) at (\d+) Hz/.exec(line);
282
+ if (phase !== null) {
283
+ const plugins = Number(phase[1]);
284
+ const rate = Number(phase[2]);
285
+ if (Number.isFinite(plugins) && Number.isFinite(rate))
286
+ return { kind: "phase", plugins, rate };
287
+ return undefined;
288
+ }
289
+ // Indented result lines are one per plugin. The two diagnostics that are NOT per-plugin
290
+ // are excluded by name rather than by shape, because their shape is identical.
291
+ if (/^ {2}\S/.test(line) && !/^ {2}(?:could not pin|worker spawn failed)/.test(line)) {
292
+ return { kind: "plugin" };
293
+ }
294
+ return undefined;
295
+ }
296
+ /** Nothing has been reported yet. */
297
+ export const INITIAL_PROGRESS = { rate: 0, done: 0, total: 0 };
298
+ /**
299
+ * Fold one parsed progress event into the running state.
300
+ *
301
+ * The clamp is the point. Each phase ends with its own indented summary lines, which look
302
+ * exactly like plugin results to a line-shape heuristic — so a naive counter reports 10 of 6
303
+ * plugins done, and a progress bar that overshoots teaches an operator to distrust it. Once
304
+ * the phase's own stated total is reached, further plugin lines advance nothing.
305
+ */
306
+ export function advanceProgress(state, event) {
307
+ if (event.kind === "phase")
308
+ return { rate: event.rate, done: 0, total: event.plugins };
309
+ if (state.total === 0 || state.done >= state.total)
310
+ return state;
311
+ return { ...state, done: state.done + 1 };
312
+ }
313
+ /** The latency method a `--measure` pass at this block size represents. */
314
+ export function latencyMethodFor(options, blockFrames) {
315
+ return {
316
+ method: "impulse-onset",
317
+ blockFrames,
318
+ stimulus: "unit impulse, escalating to a sustained tone and then to an opened gate for plugins " +
319
+ "that pass nothing at rest; the escalation used is recorded on each reading",
320
+ paramSweep: options.sweep,
321
+ };
322
+ }
323
+ /** The block size the latency pass uses when nothing overrides it — `benchmark.py`'s own. */
324
+ export const DEFAULT_LATENCY_BLOCK_FRAMES = 512;
325
+ /**
326
+ * Fold a finished run into a document.
327
+ *
328
+ * The cost pass's own provenance wins for the host block when it exists: it was written by
329
+ * the process that did the timing, pinned to the core it timed on, and it knows things a
330
+ * post-hoc reader cannot (which core, at what governor, at that moment). Only when there is
331
+ * no cost pass do the caller's collected facts stand in.
332
+ */
333
+ export function assembleDocument(input) {
334
+ const plugins = measuredPluginsFromProbeOutput(input.catalog, input.options.dimensions);
335
+ const costMethod = costMethodFromProbeProvenance(input.costProvenance);
336
+ const host = hostFromProbeProvenance(input.costProvenance) ?? input.host;
337
+ const run = buildRun({
338
+ id: input.runId,
339
+ measuredAt: input.measuredAt,
340
+ dimensions: input.options.dimensions,
341
+ rates: input.options.rates,
342
+ tool: { name: TOOL_NAME, version: TOOL_VERSION },
343
+ host,
344
+ ...(input.options.dimensions.includes("latency")
345
+ ? { latencyMethod: latencyMethodFor(input.options, costMethod?.blockFrames ?? DEFAULT_LATENCY_BLOCK_FRAMES) }
346
+ : {}),
347
+ ...(costMethod === undefined ? {} : { costMethod }),
348
+ ...(input.elapsedSeconds === undefined ? {} : { elapsedSeconds: input.elapsedSeconds }),
349
+ ...(input.options.label === undefined ? {} : { label: input.options.label }),
350
+ });
351
+ return buildMeasurementDocument(run, plugins);
352
+ }
353
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/measurement/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Documents the tests build on.
3
+ *
4
+ * Kept in `src/` rather than a test file so every test in this directory shares ONE idea of
5
+ * what a well-formed document looks like — a fixture copied between test files is how two
6
+ * tests end up asserting against two different formats, both of which pass.
7
+ */
8
+ import type { MeasuredPlugin, MeasurementDocument, MeasurementHost, MeasurementRun } from "./format.js";
9
+ import type { MeasurementDimension } from "./vocabulary.js";
10
+ /** A host with every optional field populated — the maximal shape a round trip must survive. */
11
+ export declare const FIXTURE_HOST: MeasurementHost;
12
+ /** A run record with both method blocks present. */
13
+ export declare function fixtureRun(overrides?: Partial<MeasurementRun>): MeasurementRun;
14
+ /** A fully measured plugin: readings at both rates, on both dimensions. */
15
+ export declare function fixturePlugin(uri: string, overrides?: Partial<MeasuredPlugin>): MeasuredPlugin;
16
+ /** A plugin with nothing to measure — an analyser, no audio output. */
17
+ export declare function fixtureUnmeasurable(uri: string, code?: string): MeasuredPlugin;
18
+ /** A plugin this run crashed on — a fact about the run, not the plugin. */
19
+ export declare function fixtureProbeFailure(uri: string): MeasuredPlugin;
20
+ /** A complete document. */
21
+ export declare function fixtureDocument(plugins?: readonly MeasuredPlugin[], run?: Partial<MeasurementRun>): MeasurementDocument;
22
+ /** Both dimensions, for tests that need the list without importing the vocabulary. */
23
+ export declare const BOTH_DIMENSIONS: readonly MeasurementDimension[];
@@ -0,0 +1,129 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
3
+ /**
4
+ * Documents the tests build on.
5
+ *
6
+ * Kept in `src/` rather than a test file so every test in this directory shares ONE idea of
7
+ * what a well-formed document looks like — a fixture copied between test files is how two
8
+ * tests end up asserting against two different formats, both of which pass.
9
+ */
10
+ import { buildMeasurementDocument } from "./format.js";
11
+ /** A host with every optional field populated — the maximal shape a round trip must survive. */
12
+ export const FIXTURE_HOST = {
13
+ hostname: "ref-desk",
14
+ kernel: "7.1.5-200.fc44.x86_64",
15
+ os: "Linux",
16
+ cpuModel: "Intel(R) Core(TM) Ultra 9 275HX",
17
+ cpuCount: 24,
18
+ pinnedCpu: 7,
19
+ pinnedCpuKind: "performance",
20
+ pinnedCpuMaxKHz: 5300000,
21
+ governor: "performance",
22
+ turboEnabled: true,
23
+ realtimePriority: false,
24
+ memoryLocked: false,
25
+ toolchain: { python: "3.14.6" },
26
+ };
27
+ /** A run record with both method blocks present. */
28
+ export function fixtureRun(overrides = {}) {
29
+ return {
30
+ id: "run-ref-2026-07-28",
31
+ measuredAt: "2026-07-28T18:03:03+02:00",
32
+ dimensions: ["latency", "cost"],
33
+ rates: [48000, 96000],
34
+ tool: { name: "lv2-measure", version: "0.1.0" },
35
+ host: FIXTURE_HOST,
36
+ method: {
37
+ latency: {
38
+ method: "impulse-onset",
39
+ blockFrames: 512,
40
+ stimulus: "unit impulse, escalating to a sustained tone",
41
+ paramSweep: true,
42
+ },
43
+ cost: {
44
+ method: "block-time-percentile",
45
+ blockFrames: 512,
46
+ warmupBlocks: 64,
47
+ minTimedBlocks: 64,
48
+ maxTimedBlocks: 512,
49
+ targetSecondsPerPlugin: 0.25,
50
+ percentile: 95,
51
+ stimulus: "sustained 1000 Hz sine at 0.5 full-scale on every audio input",
52
+ controls: "lv2:default on every control input",
53
+ timingFloorNsPerBlock: 32.5,
54
+ },
55
+ },
56
+ elapsedSeconds: 900,
57
+ label: "reference sweep",
58
+ relativeRankingOnly: true,
59
+ note: "A RELATIVE ranking measured on one machine, not a guarantee on any other.",
60
+ ...overrides,
61
+ };
62
+ }
63
+ /** A fully measured plugin: readings at both rates, on both dimensions. */
64
+ export function fixturePlugin(uri, overrides = {}) {
65
+ return {
66
+ uri,
67
+ name: "LSP Compressor Mono",
68
+ version: "1.22",
69
+ bundle: "/usr/lib64/lv2/lsp-plugins.lv2/",
70
+ lv2Class: "Compressor Plugin",
71
+ topology: { audioInputs: 2, audioOutputs: 1, midiInputs: 0, controlInputs: 40 },
72
+ latency: {
73
+ perRate: {
74
+ "48000": { frames: 0, ms: 0 },
75
+ "96000": { frames: 0, ms: 0 },
76
+ },
77
+ scalingClass: "zero",
78
+ declaredPortSymbol: "out_latency",
79
+ declaredFrames: 0,
80
+ },
81
+ cost: {
82
+ perRate: {
83
+ "48000": {
84
+ nsPerSampleMedian: 6.9,
85
+ nsPerSamplePercentile: 7.2,
86
+ nsPerSampleMin: 6.4,
87
+ nsPerSampleMax: 41.1,
88
+ blocks: 512,
89
+ blockFrames: 512,
90
+ warmupNsPerSampleMedian: 12.3,
91
+ },
92
+ "96000": {
93
+ nsPerSampleMedian: 6.95,
94
+ nsPerSamplePercentile: 7.4,
95
+ blocks: 512,
96
+ blockFrames: 512,
97
+ },
98
+ },
99
+ },
100
+ ...overrides,
101
+ };
102
+ }
103
+ /** A plugin with nothing to measure — an analyser, no audio output. */
104
+ export function fixtureUnmeasurable(uri, code = "no-audio-out") {
105
+ return {
106
+ uri,
107
+ name: "x42 Phase Wheel",
108
+ topology: { audioInputs: 2, audioOutputs: 0 },
109
+ latency: { perRate: {}, unmeasuredReason: code },
110
+ cost: { perRate: {}, unmeasuredReason: code },
111
+ };
112
+ }
113
+ /** A plugin this run crashed on — a fact about the run, not the plugin. */
114
+ export function fixtureProbeFailure(uri) {
115
+ return {
116
+ uri,
117
+ name: "x42 Meter",
118
+ topology: { audioInputs: 2, audioOutputs: 2 },
119
+ latency: { perRate: {}, unmeasuredReason: "probe-crashed", unmeasuredDetail: "worker crashed (SIGABRT)" },
120
+ cost: { perRate: {}, unmeasuredReason: "probe-crashed", unmeasuredDetail: "worker crashed (SIGABRT)" },
121
+ };
122
+ }
123
+ /** A complete document. */
124
+ export function fixtureDocument(plugins = [fixturePlugin("http://lsp-plug.in/plugins/lv2/compressor_mono")], run = {}) {
125
+ return buildMeasurementDocument(fixtureRun(run), plugins);
126
+ }
127
+ /** Both dimensions, for tests that need the list without importing the vocabulary. */
128
+ export const BOTH_DIMENSIONS = ["latency", "cost"];
129
+ //# sourceMappingURL=fixtures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixtures.js","sourceRoot":"","sources":["../../src/measurement/fixtures.ts"],"names":[],"mappings":"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"}