@openmixer/plugin-qualify 0.12.0 → 0.13.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.
- package/README.md +1 -1
- package/dist/host-profiles.d.ts +1 -2
- package/dist/host-profiles.js +12 -2
- package/dist/host-profiles.js.map +1 -1
- package/dist/hosting-codes.d.ts +77 -57
- package/dist/hosting-codes.js +89 -77
- package/dist/hosting-codes.js.map +1 -1
- package/dist/hosting-suitability.d.ts +1 -2
- package/dist/hosting-suitability.js +4 -13
- package/dist/hosting-suitability.js.map +1 -1
- package/dist/measurement/cli.d.ts +1 -1
- package/dist/measurement/cli.js +1 -1
- package/dist/measurement/cli.js.map +1 -1
- package/dist/measurement/format.d.ts +1 -1
- package/dist/measurement/vocabulary.d.ts +30 -22
- package/dist/measurement/vocabulary.js +84 -163
- package/dist/measurement/vocabulary.js.map +1 -1
- package/fixtures/clap-scan/fake.json +109 -7
- package/fixtures/probe-output/success-msi.json +11 -0
- package/package.json +2 -2
- package/src/host-profiles.ts +12 -2
- package/src/hosting-codes.ts +182 -77
- package/src/hosting-suitability.ts +4 -14
- package/src/measurement/cli.ts +1 -1
- package/src/measurement/format.ts +1 -1
- package/src/measurement/vocabulary.ts +135 -167
|
@@ -10,13 +10,41 @@
|
|
|
10
10
|
* whether the plugin has nothing to measure or whether OUR PROBE failed — and each with
|
|
11
11
|
* a plain description a UI can render.
|
|
12
12
|
*
|
|
13
|
-
* Everything is a data table, not a switch.
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* Everything is a data table, not a switch. A consumer that meets a term it does not know
|
|
14
|
+
* must be able to fall back on the `kind`, which is why the readers below return a term record
|
|
15
|
+
* rather than a bare string.
|
|
16
|
+
*
|
|
17
|
+
* The WORDS are omx-contract's (`data/measurement.json` and `data/resource-profile.json`, rendered
|
|
18
|
+
* as `<ITEM>_WORDS`), in its order: a word is added there, once, and every consumer reads it. What
|
|
19
|
+
* stays here is the prose, keyed by the contract's word type, so a word the contract adds without
|
|
20
|
+
* a description here, or a description for a word it lacks, is a type error.
|
|
16
21
|
*/
|
|
17
22
|
|
|
23
|
+
import {
|
|
24
|
+
MEASUREMENT_COST_METHODS_WORDS,
|
|
25
|
+
MEASUREMENT_DIMENSIONS_WORDS,
|
|
26
|
+
MEASUREMENT_LATENCY_EXCLUSIONS_WORDS,
|
|
27
|
+
MEASUREMENT_LATENCY_METHODS_WORDS,
|
|
28
|
+
MEASUREMENT_LATENCY_SCALING_NOTES_WORDS,
|
|
29
|
+
MEASUREMENT_LATENCY_SCALING_WORDS,
|
|
30
|
+
MEASUREMENT_UNMEASURED_KINDS_WORDS,
|
|
31
|
+
MEASUREMENT_UNMEASURED_REASONS,
|
|
32
|
+
MEASUREMENT_UNMEASURED_REASONS_WORDS,
|
|
33
|
+
MEASUREMENT_VERDICT_RATINGS_WORDS,
|
|
34
|
+
MEASUREMENT_VOICE_BASES_WORDS,
|
|
35
|
+
RESOURCE_HOST_ISOLATIONS_WORDS,
|
|
36
|
+
RESOURCE_HOST_LATENCY_HANDLING_WORDS,
|
|
37
|
+
} from "@openmixer/omx-contract";
|
|
18
38
|
import { nonEmptyString } from "./guards.js";
|
|
19
39
|
|
|
40
|
+
/** Pairs each word, in the contract's order, with its description here. */
|
|
41
|
+
function described<Code extends string>(
|
|
42
|
+
words: readonly Code[],
|
|
43
|
+
descriptions: Readonly<Record<Code, string>>,
|
|
44
|
+
): readonly { readonly code: Code; readonly description: string }[] {
|
|
45
|
+
return words.map((code) => ({ code, description: descriptions[code] }));
|
|
46
|
+
}
|
|
47
|
+
|
|
20
48
|
// ---------------------------------------------------------------------------
|
|
21
49
|
// Why a figure is absent
|
|
22
50
|
// ---------------------------------------------------------------------------
|
|
@@ -35,124 +63,75 @@ import { nonEmptyString } from "./guards.js";
|
|
|
35
63
|
* a finding nor a failure; it is the shape a PARTIAL run has, and partial runs are
|
|
36
64
|
* first-class here.
|
|
37
65
|
*/
|
|
38
|
-
export type UnmeasuredKind =
|
|
66
|
+
export type UnmeasuredKind = (typeof MEASUREMENT_UNMEASURED_KINDS_WORDS)[number];
|
|
67
|
+
|
|
68
|
+
/** One reason a figure may be absent: a word of the contract's MEASUREMENT_UNMEASURED_REASONS. */
|
|
69
|
+
export type UnmeasuredCode = (typeof MEASUREMENT_UNMEASURED_REASONS_WORDS)[number];
|
|
39
70
|
|
|
40
71
|
/** One term of the "why is there no figure" vocabulary. */
|
|
41
72
|
export interface UnmeasuredTerm {
|
|
42
|
-
readonly code:
|
|
73
|
+
readonly code: UnmeasuredCode;
|
|
43
74
|
readonly kind: UnmeasuredKind;
|
|
44
75
|
/** Plain description, English. A UI localises from `code`; this is for logs and specs. */
|
|
45
76
|
readonly description: string;
|
|
46
77
|
}
|
|
47
78
|
|
|
48
79
|
/**
|
|
49
|
-
* Every reason a figure may be absent. These were derived from a sweep of 958
|
|
50
|
-
* one is an outcome that sweep actually produced, not a hypothetical.
|
|
80
|
+
* Every reason a figure may be absent, in plain English. These were derived from a sweep of 958
|
|
81
|
+
* plugins — each one is an outcome that sweep actually produced, not a hypothetical. The words and
|
|
82
|
+
* their kinds are the contract's.
|
|
51
83
|
*/
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
code: "no-audio-out",
|
|
60
|
-
kind: "nothing-to-measure",
|
|
61
|
-
description: "No audio output port: a meter or a sink. Nothing to read.",
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
code: "silent-output",
|
|
65
|
-
kind: "nothing-to-measure",
|
|
66
|
-
description:
|
|
67
|
-
"Instantiated and driven, but emitted nothing under a stimulus that should have passed. " +
|
|
84
|
+
const UNMEASURED_DESCRIPTIONS: Readonly<Record<UnmeasuredCode, string>> = {
|
|
85
|
+
"no-audio-in":
|
|
86
|
+
"No audio input port: an instrument, a generator or an analyser. Nothing to drive.",
|
|
87
|
+
"no-audio-out":
|
|
88
|
+
"No audio output port: a meter or a sink. Nothing to read.",
|
|
89
|
+
"silent-output":
|
|
90
|
+
"Instantiated and driven, but emitted nothing under a stimulus that should have passed. " +
|
|
68
91
|
"A convolver with no impulse response, a vocoder with no carrier, a gate that never opened.",
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
{
|
|
76
|
-
code: "needs-impulse-response",
|
|
77
|
-
kind: "nothing-to-measure",
|
|
78
|
-
description: "A convolver requiring an IR file the prober did not load.",
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
code: "unpinnable",
|
|
82
|
-
kind: "nothing-to-measure",
|
|
83
|
-
description:
|
|
84
|
-
"The files the host loads cannot be pinned (plugin-qualify spec §11.1): a path holding ',', '=' or " +
|
|
92
|
+
"needs-carrier":
|
|
93
|
+
"Requires a second audio input (a carrier or side-chain) the prober did not supply.",
|
|
94
|
+
"needs-impulse-response":
|
|
95
|
+
"A convolver requiring an IR file the prober did not load.",
|
|
96
|
+
"unpinnable":
|
|
97
|
+
"The files the host loads cannot be pinned (plugin-qualify spec §11.1): a path holding ',', '=' or " +
|
|
85
98
|
"whitespace, a manifest using @base or a percent-encoded IRI, or a CLAP plugin with more parameters than the " +
|
|
86
99
|
"host accepts. The plugin stays unpinned, never partly pinned.",
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
code: "no-voices",
|
|
90
|
-
kind: "nothing-to-measure",
|
|
91
|
-
description:
|
|
92
|
-
"An instrument whose voice-info declares a voice capacity of 0: there is no voice to hold down, so its " +
|
|
100
|
+
"no-voices":
|
|
101
|
+
"An instrument whose voice-info declares a voice capacity of 0: there is no voice to hold down, so its " +
|
|
93
102
|
"cost with notes held cannot be taken.",
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
description: "An instrument whose note input reads no dialect the prober speaks (CLAP's or MIDI's): it cannot be played.",
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
code: "voices-unknown",
|
|
102
|
-
kind: "not-attempted",
|
|
103
|
-
description:
|
|
104
|
-
"An instrument that declares no voice capacity, measured by a run given no probe count (`--probe-notes`): " +
|
|
103
|
+
"notes-unplayable":
|
|
104
|
+
"An instrument whose note input reads no dialect the prober speaks (CLAP's or MIDI's): it cannot be played.",
|
|
105
|
+
"voices-unknown":
|
|
106
|
+
"An instrument that declares no voice capacity, measured by a run given no probe count (`--probe-notes`): " +
|
|
105
107
|
"the run did not know how many notes to hold, so it timed none.",
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
code: "probe-timeout",
|
|
119
|
-
kind: "probe-failed",
|
|
120
|
-
description: "The probe exceeded its per-plugin time limit and was abandoned.",
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
code: "non-finite-output",
|
|
124
|
-
kind: "probe-failed",
|
|
125
|
-
description: "Output contained NaN or infinity, so no onset or block time could be trusted.",
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
code: "not-installed",
|
|
129
|
-
kind: "probe-failed",
|
|
130
|
-
description:
|
|
131
|
-
"The URI was not present in this machine's LV2 world. A fact about this installation, " +
|
|
108
|
+
"refused-instantiation":
|
|
109
|
+
"The plugin would not instantiate at this rate or block size.",
|
|
110
|
+
"probe-crashed":
|
|
111
|
+
"The probe worker died (signal or abort) while hosting this plugin.",
|
|
112
|
+
"probe-timeout":
|
|
113
|
+
"The probe exceeded its per-plugin time limit and was abandoned.",
|
|
114
|
+
"non-finite-output":
|
|
115
|
+
"Output contained NaN or infinity, so no onset or block time could be trusted.",
|
|
116
|
+
"not-installed":
|
|
117
|
+
"The URI was not present in this machine's LV2 world. A fact about this installation, " +
|
|
132
118
|
"not about the plugin — another host may well have it.",
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
code: "worker-nonconforming",
|
|
136
|
-
kind: "probe-failed",
|
|
137
|
-
description:
|
|
138
|
-
"The plugin's LV2_Worker_Interface leaves work or work_response NULL, which the LV2 worker " +
|
|
119
|
+
"worker-nonconforming":
|
|
120
|
+
"The plugin's LV2_Worker_Interface leaves work or work_response NULL, which the LV2 worker " +
|
|
139
121
|
"specification does not allow: it was refused before any call, not measured.",
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
code: "probe-error",
|
|
143
|
-
kind: "probe-failed",
|
|
144
|
-
description:
|
|
145
|
-
"The probe reported a failure with no more specific term. Its own words are kept verbatim " +
|
|
122
|
+
"probe-error":
|
|
123
|
+
"The probe reported a failure with no more specific term. Its own words are kept verbatim " +
|
|
146
124
|
"in the measurement's `unmeasuredDetail`, so a coarse code never destroys the detail.",
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
kind: "not-attempted",
|
|
151
|
-
description: "This run did not cover this plugin for this dimension. A partial run, not a finding.",
|
|
152
|
-
},
|
|
153
|
-
];
|
|
125
|
+
"not-attempted":
|
|
126
|
+
"This run did not cover this plugin for this dimension. A partial run, not a finding.",
|
|
127
|
+
};
|
|
154
128
|
|
|
155
|
-
|
|
129
|
+
/** Every reason a figure may be absent, in the contract's order, of the contract's kind. */
|
|
130
|
+
export const UNMEASURED_TERMS: readonly UnmeasuredTerm[] = Object.values(MEASUREMENT_UNMEASURED_REASONS).map(
|
|
131
|
+
(reason) => ({ code: reason.word, kind: reason.group, description: UNMEASURED_DESCRIPTIONS[reason.word] }),
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const UNMEASURED_BY_CODE: ReadonlyMap<string, UnmeasuredTerm> = new Map<string, UnmeasuredTerm>(
|
|
156
135
|
UNMEASURED_TERMS.map((term) => [term.code, term]),
|
|
157
136
|
);
|
|
158
137
|
|
|
@@ -192,25 +171,19 @@ export interface ScalingTerm {
|
|
|
192
171
|
readonly description: string;
|
|
193
172
|
}
|
|
194
173
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
"Fits neither law at a magnitude that reaches a mix: the plugin changes what it does with " +
|
|
209
|
-
"the rate. Flagged rather than averaged; nothing may be projected from it.",
|
|
210
|
-
},
|
|
211
|
-
{ code: "single-rate", description: "One usable reading, so no law can be fitted." },
|
|
212
|
-
{ code: "unmeasured", description: "No rate produced a figure." },
|
|
213
|
-
];
|
|
174
|
+
/** A word of the contract's MEASUREMENT_LATENCY_SCALING. */
|
|
175
|
+
export type ScalingCode = (typeof MEASUREMENT_LATENCY_SCALING_WORDS)[number];
|
|
176
|
+
|
|
177
|
+
export const SCALING_TERMS: readonly ScalingTerm[] = described(MEASUREMENT_LATENCY_SCALING_WORDS, {
|
|
178
|
+
"fixed-frame": "Constant frame count at every rate — an FFT window. Milliseconds halve when the rate doubles.",
|
|
179
|
+
"fixed-time": "Constant milliseconds at every rate — a look-ahead. Frames double when the rate doubles.",
|
|
180
|
+
zero: "No latency a mix can notice at any measured rate.",
|
|
181
|
+
nonconforming:
|
|
182
|
+
"Fits neither law at a magnitude that reaches a mix: the plugin changes what it does with " +
|
|
183
|
+
"the rate. Flagged rather than averaged; nothing may be projected from it.",
|
|
184
|
+
"single-rate": "One usable reading, so no law can be fitted.",
|
|
185
|
+
unmeasured: "No rate produced a figure.",
|
|
186
|
+
});
|
|
214
187
|
|
|
215
188
|
const SCALING_CODES: ReadonlySet<string> = new Set(SCALING_TERMS.map((t) => t.code));
|
|
216
189
|
|
|
@@ -225,60 +198,55 @@ export function isKnownScalingCode(code: string): boolean {
|
|
|
225
198
|
* detector's rather than the plugin's, and `informational-rate`, where only a reading below
|
|
226
199
|
* the operational rates breaks the law (`lv2-measurement-interchange.md` §1a).
|
|
227
200
|
*/
|
|
228
|
-
export const SCALING_NOTE_TERMS =
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
code: "informational-rate",
|
|
237
|
-
description:
|
|
238
|
-
"The readings together fit no law, but those at the operational rates (48 kHz and up) do; " +
|
|
239
|
-
"the reading below them stays in perRate as information and does not flag the plugin.",
|
|
240
|
-
},
|
|
241
|
-
] as const satisfies readonly ScalingTerm[];
|
|
201
|
+
export const SCALING_NOTE_TERMS = described(MEASUREMENT_LATENCY_SCALING_NOTES_WORDS, {
|
|
202
|
+
"below-budget":
|
|
203
|
+
"The readings fit no law, but every one of them is inside the per-channel latency budget, " +
|
|
204
|
+
"so the disagreement is measurement noise rather than plugin behaviour.",
|
|
205
|
+
"informational-rate":
|
|
206
|
+
"The readings together fit no law, but those at the operational rates (48 kHz and up) do; " +
|
|
207
|
+
"the reading below them stays in perRate as information and does not flag the plugin.",
|
|
208
|
+
});
|
|
242
209
|
|
|
243
210
|
/** One of the {@link SCALING_NOTE_TERMS} codes — the words `latency.scalingNote` may carry. */
|
|
244
|
-
export type ScalingNoteCode = (typeof
|
|
211
|
+
export type ScalingNoteCode = (typeof MEASUREMENT_LATENCY_SCALING_NOTES_WORDS)[number];
|
|
245
212
|
|
|
246
213
|
/**
|
|
247
214
|
* Why one rate's reading was excluded from the fit and from every rate resolution. A
|
|
248
215
|
* failed reading served as an exact answer is worse than no reading, because a zero reads
|
|
249
216
|
* as confidence.
|
|
250
217
|
*/
|
|
251
|
-
export const EXCLUSION_TERMS: readonly ScalingTerm[] =
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
"to zero, so no single latency produces this; the onset detector was defeated.",
|
|
257
|
-
},
|
|
258
|
-
];
|
|
218
|
+
export const EXCLUSION_TERMS: readonly ScalingTerm[] = described(MEASUREMENT_LATENCY_EXCLUSIONS_WORDS, {
|
|
219
|
+
"impossible-zero":
|
|
220
|
+
"Zero frames at this rate while another rate measured non-zero. Both scaling laws map zero " +
|
|
221
|
+
"to zero, so no single latency produces this; the onset detector was defeated.",
|
|
222
|
+
});
|
|
259
223
|
|
|
260
224
|
// ---------------------------------------------------------------------------
|
|
261
225
|
// How a figure was taken
|
|
262
226
|
// ---------------------------------------------------------------------------
|
|
263
227
|
|
|
264
|
-
/**
|
|
228
|
+
/** How a latency figure was taken: a word of the contract's MEASUREMENT_LATENCY_METHODS. */
|
|
229
|
+
export type LatencyMethodCode = (typeof MEASUREMENT_LATENCY_METHODS_WORDS)[number];
|
|
230
|
+
|
|
231
|
+
/** How a cost figure was taken: a word of the contract's MEASUREMENT_COST_METHODS. */
|
|
232
|
+
export type CostMethodCode = (typeof MEASUREMENT_COST_METHODS_WORDS)[number];
|
|
233
|
+
|
|
234
|
+
/** The measurement methods the format has names for: the latency methods, then the cost methods. */
|
|
265
235
|
export const METHOD_TERMS: readonly ScalingTerm[] = [
|
|
266
|
-
{
|
|
267
|
-
|
|
268
|
-
description:
|
|
236
|
+
...described(MEASUREMENT_LATENCY_METHODS_WORDS, {
|
|
237
|
+
"impulse-onset":
|
|
269
238
|
"Latency as the round-trip delay from a unit impulse to the first output sample above the " +
|
|
270
239
|
"residual floor. Measures the plugin, not what it declares.",
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
},
|
|
276
|
-
{
|
|
277
|
-
|
|
278
|
-
description:
|
|
240
|
+
"declared-port": "Latency read from the plugin's own lv2:latency output port. What it CLAIMS.",
|
|
241
|
+
"note-onset":
|
|
242
|
+
"An instrument's latency: the delay from a note on to the first output sample above the " +
|
|
243
|
+
"residual floor. Measures what the plugin does with a held note.",
|
|
244
|
+
}),
|
|
245
|
+
...described(MEASUREMENT_COST_METHODS_WORDS, {
|
|
246
|
+
"block-time-percentile":
|
|
279
247
|
"Cost as a percentile of per-block wall time under a sustained stimulus, warm-up blocks " +
|
|
280
248
|
"discarded, normalised to nanoseconds per sample.",
|
|
281
|
-
},
|
|
249
|
+
}),
|
|
282
250
|
];
|
|
283
251
|
|
|
284
252
|
const METHOD_CODES: ReadonlySet<string> = new Set(METHOD_TERMS.map((t) => t.code));
|
|
@@ -295,7 +263,7 @@ export function isKnownMethodCode(code: string): boolean {
|
|
|
295
263
|
* hosting verdict — whether a plugin survives, whether its `run()` is RT-clean, what it
|
|
296
264
|
* demands of a host — and merge under exactly the same per-plugin, per-DIMENSION precedence.
|
|
297
265
|
*/
|
|
298
|
-
export const MEASUREMENT_DIMENSIONS =
|
|
266
|
+
export const MEASUREMENT_DIMENSIONS = MEASUREMENT_DIMENSIONS_WORDS;
|
|
299
267
|
|
|
300
268
|
/**
|
|
301
269
|
* The dimensions the standalone prober (`scan.py` + `benchmark.py`, driven by `lv2-measure.mjs`
|
|
@@ -321,19 +289,19 @@ export function readDimension(value: unknown): MeasurementDimension | undefined
|
|
|
321
289
|
}
|
|
322
290
|
|
|
323
291
|
/**
|
|
324
|
-
* The four ratings a verdict speaks (`lv2-measurement-interchange.md` §3b)
|
|
325
|
-
* rating vocabulary (`rating.ts`) derives its type from it, so
|
|
326
|
-
* can never disagree on a word.
|
|
292
|
+
* The four ratings a verdict speaks (`lv2-measurement-interchange.md` §3b): the contract's
|
|
293
|
+
* MEASUREMENT_VERDICT_RATINGS. The rating vocabulary (`rating.ts`) derives its type from it, so
|
|
294
|
+
* the document and the classifier can never disagree on a word.
|
|
327
295
|
*/
|
|
328
|
-
export const VERDICT_RATINGS =
|
|
296
|
+
export const VERDICT_RATINGS = MEASUREMENT_VERDICT_RATINGS_WORDS;
|
|
329
297
|
export type VerdictRating = (typeof VERDICT_RATINGS)[number];
|
|
330
298
|
|
|
331
|
-
/** How a host runs its plugins. */
|
|
332
|
-
export const HOST_ISOLATIONS =
|
|
299
|
+
/** How a host runs its plugins: the contract's RESOURCE_HOST_ISOLATIONS. */
|
|
300
|
+
export const HOST_ISOLATIONS = RESOURCE_HOST_ISOLATIONS_WORDS;
|
|
333
301
|
export type HostIsolation = (typeof HOST_ISOLATIONS)[number];
|
|
334
302
|
|
|
335
|
-
/** Whether a host aligns on a plugin's reported latency (`compensated`) or only passes it on. */
|
|
336
|
-
export const HOST_LATENCY_HANDLING =
|
|
303
|
+
/** Whether a host aligns on a plugin's reported latency (`compensated`) or only passes it on: the contract's RESOURCE_HOST_LATENCY_HANDLING. */
|
|
304
|
+
export const HOST_LATENCY_HANDLING = RESOURCE_HOST_LATENCY_HANDLING_WORDS;
|
|
337
305
|
export type HostLatencyHandling = (typeof HOST_LATENCY_HANDLING)[number];
|
|
338
306
|
|
|
339
307
|
/**
|
|
@@ -342,7 +310,7 @@ export type HostLatencyHandling = (typeof HOST_LATENCY_HANDLING)[number];
|
|
|
342
310
|
* the caller gave (`--probe-notes`, the console's `SYNTH_VOICE_PROBE_NOTES`), used when the plugin declares
|
|
343
311
|
* none or when the caller asked for that count whatever it declares.
|
|
344
312
|
*/
|
|
345
|
-
export const VOICE_BASES =
|
|
313
|
+
export const VOICE_BASES = MEASUREMENT_VOICE_BASES_WORDS;
|
|
346
314
|
export type VoiceBasis = (typeof VOICE_BASES)[number];
|
|
347
315
|
|
|
348
316
|
export function isVoiceBasis(value: unknown): value is VoiceBasis {
|