@msb235/blits 0.3.0 → 0.5.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/CHANGELOG.md +314 -0
- package/README.md +3 -2
- package/dist/bare.d.ts +29 -0
- package/dist/bare.js +105 -0
- package/dist/blend.d.ts +34 -0
- package/dist/blend.js +102 -0
- package/dist/book.d.ts +53 -0
- package/dist/book.js +218 -0
- package/dist/chain.d.ts +22 -0
- package/dist/chain.js +150 -0
- package/dist/channels.d.ts +2 -0
- package/dist/channels.js +3 -1
- package/dist/clock.d.ts +50 -3
- package/dist/clock.js +102 -9
- package/dist/clone.d.ts +7 -0
- package/dist/clone.js +57 -0
- package/dist/columns.d.ts +29 -0
- package/dist/columns.js +183 -0
- package/dist/crowd.d.ts +128 -0
- package/dist/crowd.js +354 -0
- package/dist/cue.d.ts +3 -0
- package/dist/cue.js +115 -0
- package/dist/due.d.ts +12 -0
- package/dist/due.js +93 -0
- package/dist/fade.d.ts +19 -0
- package/dist/fade.js +133 -0
- package/dist/fill.d.ts +42 -0
- package/dist/fill.js +381 -0
- package/dist/fold.d.ts +51 -0
- package/dist/fold.js +475 -0
- package/dist/gather.d.ts +24 -0
- package/dist/gather.js +186 -0
- package/dist/handle.d.ts +31 -0
- package/dist/handle.js +56 -0
- package/dist/held.d.ts +14 -0
- package/dist/held.js +117 -0
- package/dist/history.d.ts +22 -0
- package/dist/history.js +149 -0
- package/dist/hosts.d.ts +16 -0
- package/dist/hosts.js +178 -0
- package/dist/index.d.ts +1 -1
- package/dist/keyrows.d.ts +36 -0
- package/dist/keyrows.js +138 -0
- package/dist/lane.d.ts +210 -0
- package/dist/lane.js +187 -0
- package/dist/lanes.d.ts +143 -122
- package/dist/lanes.js +236 -742
- package/dist/locus.d.ts +40 -0
- package/dist/locus.js +89 -0
- package/dist/marks.d.ts +12 -0
- package/dist/marks.js +80 -0
- package/dist/meet.d.ts +16 -0
- package/dist/meet.js +113 -0
- package/dist/mixer.d.ts +244 -169
- package/dist/mixer.js +321 -1793
- package/dist/motion.d.ts +104 -19
- package/dist/motion.js +448 -180
- package/dist/move.d.ts +9 -0
- package/dist/move.js +190 -0
- package/dist/named.d.ts +12 -0
- package/dist/named.js +39 -0
- package/dist/numbers.d.ts +18 -6
- package/dist/numbers.js +59 -31
- package/dist/owed.d.ts +24 -0
- package/dist/owed.js +51 -0
- package/dist/owner.d.ts +43 -0
- package/dist/owner.js +117 -0
- package/dist/pace.d.ts +40 -0
- package/dist/pace.js +113 -0
- package/dist/patch.d.ts +51 -10
- package/dist/patch.js +140 -45
- package/dist/place.d.ts +20 -0
- package/dist/place.js +196 -0
- package/dist/project.d.ts +4 -0
- package/dist/project.js +233 -0
- package/dist/pull.d.ts +5 -0
- package/dist/pull.js +175 -0
- package/dist/qualify.d.ts +31 -0
- package/dist/qualify.js +345 -0
- package/dist/relink.d.ts +25 -0
- package/dist/relink.js +59 -0
- package/dist/rows.d.ts +33 -0
- package/dist/rows.js +282 -0
- package/dist/sample.d.ts +21 -0
- package/dist/sample.js +232 -0
- package/dist/signals.d.ts +12 -9
- package/dist/signals.js +8 -5
- package/dist/store.d.ts +10 -3
- package/dist/store.js +44 -9
- package/dist/strays.d.ts +21 -0
- package/dist/strays.js +84 -0
- package/dist/tweened.d.ts +11 -0
- package/dist/tweened.js +48 -0
- package/dist/types.d.ts +261 -42
- package/dist/unreached.d.ts +5 -0
- package/dist/unreached.js +24 -0
- package/dist/voice.d.ts +240 -0
- package/dist/voice.js +322 -0
- package/dist/weigh.d.ts +26 -0
- package/dist/weigh.js +89 -0
- package/docs/schema.html +151 -46
- package/package.json +5 -2
package/dist/types.d.ts
CHANGED
|
@@ -67,10 +67,10 @@ export interface Keyframe<O> {
|
|
|
67
67
|
*
|
|
68
68
|
* @category state
|
|
69
69
|
*/
|
|
70
|
-
export interface Setting<S = void> {
|
|
70
|
+
export interface Setting<S = void, H = unknown> {
|
|
71
71
|
/**
|
|
72
|
-
* The mix clock at this frame: the host's timestamp less any time `rebase` took out
|
|
73
|
-
* for every probe in the frame.
|
|
72
|
+
* The mix clock at this frame: the host's timestamp less any time `rebase` took out, run at the
|
|
73
|
+
* mix's `rate`. Identical for every probe in the frame.
|
|
74
74
|
*/
|
|
75
75
|
timestamp: number;
|
|
76
76
|
/**
|
|
@@ -88,14 +88,15 @@ export interface Setting<S = void> {
|
|
|
88
88
|
weight: number;
|
|
89
89
|
/** This subject's state, when the patch declares one. */
|
|
90
90
|
state: S;
|
|
91
|
-
/** Anything the host adds for its own patches
|
|
92
|
-
host:
|
|
91
|
+
/** Anything the host adds for its own patches: the mix's `host`, typed as its `H`. */
|
|
92
|
+
host: H;
|
|
93
93
|
/**
|
|
94
94
|
* The state `owner` keeps for this voice and this subject, made by `init` on first ask. The mix
|
|
95
95
|
* holds it, so a read at another time can copy it instead of moving it. A stateful signal keeps
|
|
96
|
-
* its state here and nowhere else. With lanes on, a patch that first calls it
|
|
97
|
-
* playing can have that state advanced once for one subject not probed on the
|
|
98
|
-
*
|
|
96
|
+
* its state here and nowhere else. With lanes on, a patch or weight signal that first calls it
|
|
97
|
+
* partway through playing can have that state advanced once for one subject not probed on the
|
|
98
|
+
* frame it starts; one that keeps state from its first call, or a patch that declares `state`,
|
|
99
|
+
* never does.
|
|
99
100
|
*/
|
|
100
101
|
keep<K>(owner: object, init: () => K): K;
|
|
101
102
|
/**
|
|
@@ -103,7 +104,7 @@ export interface Setting<S = void> {
|
|
|
103
104
|
* host drains it, and never calls back. Meant for `step`, where under `stepMs` the timestamp is
|
|
104
105
|
* the interval the event happened in rather than the frame that sampled it. Sent from a stateless
|
|
105
106
|
* patch's `at` while it runs on a lane, it goes out for every subject the mix has met, probed that
|
|
106
|
-
* frame or not.
|
|
107
|
+
* frame or not; `at` is not asked for a subject at weight 0, so nothing is sent from it there.
|
|
107
108
|
*/
|
|
108
109
|
send(event: unknown): void;
|
|
109
110
|
}
|
|
@@ -144,8 +145,8 @@ export type MotionSpec = {
|
|
|
144
145
|
readonly settle: number;
|
|
145
146
|
} | {
|
|
146
147
|
readonly kind: 'tween';
|
|
147
|
-
/** How long a stretch takes. */
|
|
148
|
-
readonly ms: number;
|
|
148
|
+
/** How long a stretch takes; undefined where it varies by subject, kept on the patch then. */
|
|
149
|
+
readonly ms: number | undefined;
|
|
149
150
|
readonly ease: Easing;
|
|
150
151
|
};
|
|
151
152
|
/**
|
|
@@ -153,14 +154,16 @@ export type MotionSpec = {
|
|
|
153
154
|
*
|
|
154
155
|
* @category patch
|
|
155
156
|
*/
|
|
156
|
-
export interface Patch<I, O, S = void> {
|
|
157
|
+
export interface Patch<I, O, S = void, H = unknown> {
|
|
157
158
|
/**
|
|
158
159
|
* Which authoring form built it: `'fn'` from `patch`, `'keys'` from `keys`, `'motion'` from
|
|
159
160
|
* `spring`, `glide` or `tween`. An engine declares which forms it runs.
|
|
160
161
|
*/
|
|
161
162
|
readonly form: 'fn' | 'keys' | 'motion';
|
|
162
|
-
/** Milliseconds one pass lasts. 0
|
|
163
|
-
readonly
|
|
163
|
+
/** Milliseconds one pass lasts, whether or not the voice loops. 0 has no passes: phase and pass stay 0. */
|
|
164
|
+
readonly duration: number;
|
|
165
|
+
/** @deprecated Use `duration`. A patch that sets only `period` still plays. */
|
|
166
|
+
readonly period?: number;
|
|
164
167
|
/** The channels this patch contributes to. Every key `at` sets, and no others. */
|
|
165
168
|
readonly writes: readonly (keyof O)[];
|
|
166
169
|
/**
|
|
@@ -170,15 +173,18 @@ export interface Patch<I, O, S = void> {
|
|
|
170
173
|
readonly kit?: Partial<Kit<O>>;
|
|
171
174
|
/** The fields of `setting.host` this patch reads. `cue` refuses a mix whose host lacks one. */
|
|
172
175
|
readonly reads?: readonly string[];
|
|
173
|
-
/**
|
|
174
|
-
|
|
176
|
+
/**
|
|
177
|
+
* `phase` is 0..1 across one pass, wrapping. Not asked for a subject its voice gives no weight, unless the voice is fading to rest;
|
|
178
|
+
* `step` still runs.
|
|
179
|
+
*/
|
|
180
|
+
at(phase: number, subject: I, setting: Setting<S, H>): Partial<O>;
|
|
175
181
|
/** Per-subject state, created on the first frame this patch sees a subject. */
|
|
176
182
|
state?(subject: I): S;
|
|
177
183
|
/**
|
|
178
184
|
* Advances state once per subject per sampled frame, by the whole gap since it last advanced; or,
|
|
179
185
|
* where the mix sets `stepMs`, once per whole interval of that length.
|
|
180
186
|
*/
|
|
181
|
-
step?(state: S, dt: number, subject: I, setting: Setting<S>): void;
|
|
187
|
+
step?(state: S, dt: number, subject: I, setting: Setting<S, H>): void;
|
|
182
188
|
/** Present when the patch was authored as keyframes, so an engine that reads data can. */
|
|
183
189
|
readonly keys?: readonly Keyframe<O>[];
|
|
184
190
|
/** Present on a `'motion'` patch: its kind and constants, for an engine that reads data. */
|
|
@@ -197,7 +203,7 @@ export interface Patch<I, O, S = void> {
|
|
|
197
203
|
*
|
|
198
204
|
* @category signal
|
|
199
205
|
*/
|
|
200
|
-
export type Signal<I> = ((subject: I, setting: Setting) => number) & {
|
|
206
|
+
export type Signal<I, H = unknown> = ((subject: I, setting: Setting<void, H>) => number) & {
|
|
201
207
|
readonly input?: boolean;
|
|
202
208
|
};
|
|
203
209
|
/**
|
|
@@ -286,19 +292,91 @@ export interface Marked {
|
|
|
286
292
|
name: string | undefined;
|
|
287
293
|
tags: readonly string[];
|
|
288
294
|
}
|
|
295
|
+
/**
|
|
296
|
+
* An event at a time on a voice's own clock, which `book` hands a host ahead of time. It plays once
|
|
297
|
+
* per pass, for the voice and not per subject, so `stagger` does not spread it.
|
|
298
|
+
*
|
|
299
|
+
* @category score
|
|
300
|
+
*/
|
|
301
|
+
export interface Hit<E = unknown> {
|
|
302
|
+
/** Voice ms into each pass: 0 up to the patch's `duration`, or any time at all for a patch with none. */
|
|
303
|
+
at: number;
|
|
304
|
+
event: E;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* One pass of one hit, as `book` takes it.
|
|
308
|
+
*
|
|
309
|
+
* @category score
|
|
310
|
+
*/
|
|
311
|
+
export interface BookedHit<E = unknown> {
|
|
312
|
+
/** On the host's clock. */
|
|
313
|
+
timestamp: number;
|
|
314
|
+
voice: number;
|
|
315
|
+
/** Which of the voice's `hits`, by index. */
|
|
316
|
+
hit: number;
|
|
317
|
+
/** Which pass, 0 first. */
|
|
318
|
+
pass: number;
|
|
319
|
+
event: E;
|
|
320
|
+
score: string | undefined;
|
|
321
|
+
name: string | undefined;
|
|
322
|
+
tags: readonly string[];
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* What `book` takes: an outside clock, how far ahead to book on it, and what to do with each item.
|
|
326
|
+
*
|
|
327
|
+
* @category score
|
|
328
|
+
*/
|
|
329
|
+
export interface BookOptions<E = unknown> {
|
|
330
|
+
/**
|
|
331
|
+
* The outside clock, in ms: `audio.currentTime * 1000`, `performance.now()`, or whatever the host
|
|
332
|
+
* schedules against. Read once a sync. The mix maps its host time onto it by an offset that folds
|
|
333
|
+
* in 5% of each frame's difference, and starts over from the clock's own reading on a jump past
|
|
334
|
+
* 50 ms, such as a suspended context or a hidden tab.
|
|
335
|
+
*/
|
|
336
|
+
clock: () => number;
|
|
337
|
+
/** How far ahead to book, host ms. It has to cover the longest gap between two syncs. */
|
|
338
|
+
ahead: number;
|
|
339
|
+
/** How far past an item first seen late may be and still be taken, host ms. */
|
|
340
|
+
late: number;
|
|
341
|
+
/**
|
|
342
|
+
* Called once per item: a mark as `marks` lists it, or a hit. `when` is on the outside clock;
|
|
343
|
+
* `lateBy` is how many host ms past the item was when first seen, 0 for one booked ahead, which
|
|
344
|
+
* is then taken at the clock's now. Return a `stop` to hear about a booking whose time moved by
|
|
345
|
+
* more than 1 ms or that went away (a seek, a rate or ramp on the voice or the mix, a fade, a
|
|
346
|
+
* `rebase`, an anchor's target moving, the voice leaving); the item is then booked again, at its
|
|
347
|
+
* new time, at the same sync.
|
|
348
|
+
*/
|
|
349
|
+
take(item: Marked | BookedHit<E>, when: number, lateBy: number): {
|
|
350
|
+
stop(): void;
|
|
351
|
+
} | undefined;
|
|
352
|
+
/** Book only the voices, and announced marks, carrying this tag. */
|
|
353
|
+
tag?: string;
|
|
354
|
+
/** Book only this score's voices and marks. */
|
|
355
|
+
score?: string;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* A running booker, returned by `book`.
|
|
359
|
+
*
|
|
360
|
+
* @category score
|
|
361
|
+
*/
|
|
362
|
+
export interface Booker {
|
|
363
|
+
/** Stops every booking still ahead, and books nothing more. */
|
|
364
|
+
stop(): void;
|
|
365
|
+
}
|
|
289
366
|
/**
|
|
290
367
|
* What `cue` takes: a patch, and the clock, weight and reach it plays with.
|
|
291
368
|
*
|
|
292
369
|
* @category voice
|
|
293
370
|
*/
|
|
294
|
-
export interface VoiceSpec<I, O> {
|
|
295
|
-
patch: Patch<I, O, unknown>;
|
|
371
|
+
export interface VoiceSpec<I, O, H = unknown> {
|
|
372
|
+
patch: Patch<I, O, unknown, H>;
|
|
296
373
|
/**
|
|
297
374
|
* Which subjects this voice reaches. Default: all of them. The predicate is fixed at `cue`; it
|
|
298
375
|
* runs per subject the first time the mix sees that subject, and the answer is kept. Every
|
|
299
376
|
* voice's predicate meets every subject, so voices that each reach a known few cost the square
|
|
300
|
-
* of their number
|
|
301
|
-
*
|
|
377
|
+
* of their number in time; name those with `subjects` instead. A no is kept as a bit by the
|
|
378
|
+
* number lanes give the subject, but with `lanes: false` as a map entry per voice per subject
|
|
379
|
+
* asked (about 37 MB for 1,000 such voices over 1,000 subjects).
|
|
302
380
|
*/
|
|
303
381
|
target?: (subject: I) => boolean;
|
|
304
382
|
/**
|
|
@@ -317,7 +395,7 @@ export interface VoiceSpec<I, O> {
|
|
|
317
395
|
/**
|
|
318
396
|
* true loops for good, false plays one pass, n plays n passes. A finite loop leaves when its
|
|
319
397
|
* passes are done for the latest-staggered subject it has seen — over `fade.out` where one is
|
|
320
|
-
* set, at once where none is.
|
|
398
|
+
* set, at once where none is — unless it holds after.
|
|
321
399
|
*/
|
|
322
400
|
loop?: boolean | number;
|
|
323
401
|
/**
|
|
@@ -325,15 +403,25 @@ export interface VoiceSpec<I, O> {
|
|
|
325
403
|
* Like `target`, it runs once per subject on first sight, and the answer is kept.
|
|
326
404
|
*/
|
|
327
405
|
stagger?: (subject: I) => number;
|
|
406
|
+
/**
|
|
407
|
+
* Show a subject the first frame before it starts — while the voice is pending and while the
|
|
408
|
+
* subject waits out its `stagger` — the last frame of the last pass after a finite loop plays
|
|
409
|
+
* out, or both. A held subject's clock stands still: `at` is asked for the edge frame and `step`
|
|
410
|
+
* does not run, past one last step to the end of the last pass. `fade.in` counts from the first
|
|
411
|
+
* frame the voice shows. A voice holding after stays, `held`, until `fade()` or an anchored `out`
|
|
412
|
+
* takes it out, so every one cued must be faded or it stays in the mix for good. Does nothing to
|
|
413
|
+
* a motion patch, which holds its target already. Default: neither.
|
|
414
|
+
*/
|
|
415
|
+
hold?: 'before' | 'after' | 'both';
|
|
328
416
|
/** Steady weight, or a signal read per subject per frame. Default 1. */
|
|
329
|
-
weight?: number | Signal<I>;
|
|
417
|
+
weight?: number | Signal<I, H>;
|
|
330
418
|
/** Ramp in and out, ms. Out applies on `fade()` and when a finite loop ends. */
|
|
331
419
|
fade?: FadeSpec;
|
|
332
420
|
/** Voices sharing a locus are alternatives: the mix folds them through each channel's `lerp`. */
|
|
333
421
|
locus?: string;
|
|
334
422
|
/** A `keys` voice whose first stop reads wherever this subject is now. */
|
|
335
423
|
from?: 'current';
|
|
336
|
-
/** Words a source attaches to this voice, so its events can be
|
|
424
|
+
/** Words a source attaches to this voice, so its events and its handle can be taken as a set. */
|
|
337
425
|
tags?: readonly string[];
|
|
338
426
|
/** What other voices call this one by. A label blits never reads. */
|
|
339
427
|
name?: string;
|
|
@@ -345,20 +433,76 @@ export interface VoiceSpec<I, O> {
|
|
|
345
433
|
score?: string;
|
|
346
434
|
/** Where it sits relative to the clock or to other voices, in place of `start`. */
|
|
347
435
|
anchor?: Placement;
|
|
436
|
+
/**
|
|
437
|
+
* Events at times on this voice's clock, which `book` hands a host ahead of time. Patch-sent
|
|
438
|
+
* events are not known ahead, so they stay drain-only; these are the plan.
|
|
439
|
+
*/
|
|
440
|
+
hits?: readonly Hit[];
|
|
441
|
+
/**
|
|
442
|
+
* The owner this voice plays under, a handle `owns` returned. Its `start` and `anchor` are then on
|
|
443
|
+
* the owner's clock, in ms from when the owner starts, and default to where that clock is now; a
|
|
444
|
+
* bare name in an anchor means a sibling, another voice the owner holds. Its clock runs on the
|
|
445
|
+
* owner's, so the owner's rate, ramp and seeks move it, and its weight is multiplied by the
|
|
446
|
+
* owner's weight and fade. Without a `hold` of its own it takes the owner's.
|
|
447
|
+
*/
|
|
448
|
+
owner?: Handle<I>;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* What `owns` takes: an owner has no patch, and plays only through the voices it holds.
|
|
452
|
+
*
|
|
453
|
+
* @category voice
|
|
454
|
+
*/
|
|
455
|
+
export interface OwnerSpec<I, H = unknown> {
|
|
456
|
+
/**
|
|
457
|
+
* When the owner starts, on its own owner's clock: the host's for an owner on the mix, as a
|
|
458
|
+
* voice's `start` is. Default: now.
|
|
459
|
+
*/
|
|
460
|
+
start?: number;
|
|
461
|
+
/** Its clock's rate, multiplied into every child's own. Default 1. */
|
|
462
|
+
rate?: number;
|
|
463
|
+
/**
|
|
464
|
+
* Multiplied into every child's weight per subject, as the child's own fade is, before the child's
|
|
465
|
+
* locus folds it: a number, or a signal read per subject per frame. Default 1.
|
|
466
|
+
*/
|
|
467
|
+
weight?: number | Signal<I, H>;
|
|
468
|
+
/** One ramp in and out over every child, multiplied into their weights as `weight` is. */
|
|
469
|
+
fade?: FadeSpec;
|
|
470
|
+
/** The hold every child without one of its own takes. */
|
|
471
|
+
hold?: 'before' | 'after' | 'both';
|
|
472
|
+
/** Words a source attaches to it, as a voice's. */
|
|
473
|
+
tags?: readonly string[];
|
|
474
|
+
/** What other voices call it by, among its siblings. */
|
|
475
|
+
name?: string;
|
|
476
|
+
/** The plan it belongs to, as a voice's. */
|
|
477
|
+
score?: string;
|
|
478
|
+
/** Where it sits relative to its own owner's clock or to other voices, in place of `start`. */
|
|
479
|
+
anchor?: Placement;
|
|
480
|
+
/** The owner it plays under, so owners nest. */
|
|
481
|
+
owner?: Handle<I>;
|
|
348
482
|
}
|
|
349
483
|
/**
|
|
350
|
-
* How a voice leaves when it is faded.
|
|
484
|
+
* How a voice leaves when it is faded: the whole voice, or one subject.
|
|
351
485
|
*
|
|
352
486
|
* @category blending
|
|
353
487
|
*/
|
|
354
|
-
export
|
|
488
|
+
export type FadeOptions<I = unknown> = {
|
|
355
489
|
/** The ramp, ms. Defaults to the voice's own `fade.out`. */
|
|
356
490
|
over?: number;
|
|
357
491
|
/** Leave per subject at the first frame that subject's contribution is at rest. */
|
|
358
492
|
at?: 'rest';
|
|
359
493
|
/** Ms after which the voice leaves whether or not it rested. */
|
|
360
494
|
deadline?: number;
|
|
361
|
-
|
|
495
|
+
subject?: never;
|
|
496
|
+
} | {
|
|
497
|
+
/**
|
|
498
|
+
* The one subject to fade out of this voice, which plays on for the rest. Once the ramp ends
|
|
499
|
+
* the voice forgets the subject and reaches it no more, until a motion patch's `to` brings it
|
|
500
|
+
* back, met afresh: `from`, `target` and `stagger` asked again.
|
|
501
|
+
*/
|
|
502
|
+
subject: I;
|
|
503
|
+
/** The ramp, ms. Defaults to the voice's own `fade.out`; 0 takes the subject out at once. */
|
|
504
|
+
over?: number;
|
|
505
|
+
};
|
|
362
506
|
/**
|
|
363
507
|
* The live controls on one voice, returned by `cue`.
|
|
364
508
|
*
|
|
@@ -366,7 +510,10 @@ export interface FadeOptions {
|
|
|
366
510
|
*/
|
|
367
511
|
export interface Handle<I = unknown> {
|
|
368
512
|
readonly id: number;
|
|
369
|
-
|
|
513
|
+
/** `held`: a voice holding after has played every pass and shows its last frame until faded. */
|
|
514
|
+
readonly state: 'pending' | 'live' | 'held' | 'fading' | 'done';
|
|
515
|
+
/** The handle of the owner this voice plays under; undefined for one on the mix clock. */
|
|
516
|
+
readonly owner: Handle<I> | undefined;
|
|
370
517
|
/** Live. Writes land on the next sync. */
|
|
371
518
|
weight: number;
|
|
372
519
|
/** Playback rate now. Setting it changes speed at once; `ramp` eases into a new one. */
|
|
@@ -382,28 +529,34 @@ export interface Handle<I = unknown> {
|
|
|
382
529
|
* accumulated into, so state is left where it is and never run forward to meet the new position.
|
|
383
530
|
*/
|
|
384
531
|
seek(elapsed: number): void;
|
|
385
|
-
fade(opts?: FadeOptions): void;
|
|
532
|
+
fade(opts?: FadeOptions<I>): void;
|
|
386
533
|
/**
|
|
387
534
|
* The weight this voice gave `subject` the last frame that subject was probed: after its fades
|
|
388
535
|
* and its weight signal, before a locus folds it with its alternatives. 0 for a subject it does
|
|
389
|
-
* not reach, has not started on, has left at rest, or has never been
|
|
536
|
+
* not reach, has not started on and does not hold before, has left at rest, or has never been
|
|
537
|
+
* probed for; 0 once done.
|
|
390
538
|
* Costs nothing until it is asked.
|
|
391
539
|
*/
|
|
392
540
|
weightOf(subject: I): number;
|
|
393
541
|
/** Resolves when the voice has been removed from the mix, however that happened. */
|
|
394
542
|
readonly done: Promise<void>;
|
|
543
|
+
/**
|
|
544
|
+
* Resolves true when a finite loop's last pass ends, for the latest-staggered subject it has
|
|
545
|
+
* seen, and false if the voice leaves before that. Never rejects.
|
|
546
|
+
*/
|
|
547
|
+
readonly played: Promise<boolean>;
|
|
395
548
|
}
|
|
396
549
|
/**
|
|
397
550
|
* How a mix is built: its engine, reduced motion, the host, and its limits.
|
|
398
551
|
*
|
|
399
552
|
* @category mix
|
|
400
553
|
*/
|
|
401
|
-
export interface MixOptions {
|
|
554
|
+
export interface MixOptions<H = unknown> {
|
|
402
555
|
engine?: Engine;
|
|
403
556
|
/** Reduced motion: fades and warm-ups snap, `dt` reads Infinity. */
|
|
404
557
|
reduce?: boolean | (() => boolean);
|
|
405
|
-
/** Merged into every `setting.host`. */
|
|
406
|
-
host?:
|
|
558
|
+
/** Merged into every `setting.host`. Its type is the mix's `H`, which every patch and signal it cues reads. */
|
|
559
|
+
host?: H;
|
|
407
560
|
/**
|
|
408
561
|
* The band a rest-less channel's influence switches on and off across. It has to clear the frame
|
|
409
562
|
* noise in a real signal; these are placeholders until the klieg port measures one.
|
|
@@ -487,11 +640,26 @@ export type Columns<O> = {
|
|
|
487
640
|
*
|
|
488
641
|
* @category mix
|
|
489
642
|
*/
|
|
490
|
-
export interface Mix<I, O> {
|
|
643
|
+
export interface Mix<I, O, H = unknown> {
|
|
491
644
|
/** Cues a voice. Throws when the engine cannot run the patch's form, or the kit lacks a channel. */
|
|
492
|
-
cue(spec: VoiceSpec<I, O>): Handle<I>;
|
|
493
|
-
/**
|
|
494
|
-
|
|
645
|
+
cue(spec: VoiceSpec<I, O, H>): Handle<I>;
|
|
646
|
+
/**
|
|
647
|
+
* N voices whose weights split one signal, cued into one locus so they fold as alternatives. The
|
|
648
|
+
* signal is read once per subject per frame, with the first member's setting, and every member
|
|
649
|
+
* takes its share of that one reading; a signal keeping state keeps it once, not per member.
|
|
650
|
+
*/
|
|
651
|
+
blend(patches: readonly Patch<I, O, unknown, H>[], by: Signal<I, H>, spec?: Omit<VoiceSpec<I, O, H>, 'patch' | 'weight' | 'locus'>): Handle<I>[];
|
|
652
|
+
/**
|
|
653
|
+
* Cues an owner: a voice with no patch that holds the voices cued with `owner` set to its handle,
|
|
654
|
+
* and plays them on its own clock, so they can be placed, timed and faded as one. Its handle acts
|
|
655
|
+
* on all of them: `rate` and `ramp` multiply into theirs, `seek` moves their clocks with its own
|
|
656
|
+
* and leaves their state where it is, and `weight` and `fade()` multiply into their weights, by
|
|
657
|
+
* what its `weightOf` reports; it fades as a whole, not by subject or at rest. It is
|
|
658
|
+
* `played` once every voice it held has finished its passes, and leaves, `done`, with its last; a
|
|
659
|
+
* fade that ends takes the rest with it. One that never holds a voice stays until faded. Owners
|
|
660
|
+
* nest. Throws for a `loop`: a pass would have to restart its children.
|
|
661
|
+
*/
|
|
662
|
+
owns(spec: OwnerSpec<I, H>): Handle<I>;
|
|
495
663
|
/** The host reports the clock, once a frame. Nothing advances at the call. */
|
|
496
664
|
sync(timestamp: number): void;
|
|
497
665
|
/**
|
|
@@ -499,13 +667,39 @@ export interface Mix<I, O> {
|
|
|
499
667
|
* hidden tab comes back. Every voice, fade and subject resumes where it was left.
|
|
500
668
|
*/
|
|
501
669
|
rebase(): void;
|
|
502
|
-
/**
|
|
670
|
+
/**
|
|
671
|
+
* The mix's own playback rate, multiplied into every voice's: 1 is real time and 0 pauses the
|
|
672
|
+
* whole mix. A negative rate throws, since the mix only goes forward. Setting it changes speed at
|
|
673
|
+
* once; `ramp` eases into a new one. It scales mix time, which everything a voice owns runs on:
|
|
674
|
+
* its clock, its fades and a handle's ramp, `stagger`, an anchor's `by`, `stepMs`, `maxDt`,
|
|
675
|
+
* `history.ms`, every `dt`, and `setting.timestamp`. Timestamps on the host's clock name the same
|
|
676
|
+
* moment whatever the rate does: a `start`, an anchor given as a number, an announced mark, what
|
|
677
|
+
* `marks` reports and the time `project` reads, so a start ahead of a paused mix waits for the
|
|
678
|
+
* host's clock to reach it. A weight signal is still asked at every probe, so one reading host
|
|
679
|
+
* input follows it while the mix is paused.
|
|
680
|
+
*/
|
|
681
|
+
rate: number;
|
|
682
|
+
/**
|
|
683
|
+
* Moves the mix's rate to `rate` linearly over `over` ms of the host's clock, as `Handle.ramp`
|
|
684
|
+
* moves a voice's. Mix time integrates the ramp and a voice's clock integrates mix time, so a ramp
|
|
685
|
+
* on both multiplies and every position stays continuous. A later `rate` write or `ramp` replaces
|
|
686
|
+
* it.
|
|
687
|
+
*/
|
|
688
|
+
ramp(rate: number, over: number): void;
|
|
689
|
+
/**
|
|
690
|
+
* The merged pose for one subject at the synced frame, written into `out` when given. Without
|
|
691
|
+
* it, each call makes a new object, so a host reading every subject every frame passes `out` or
|
|
692
|
+
* reads by `pull`.
|
|
693
|
+
*/
|
|
503
694
|
probe(subject: I, out?: O): O;
|
|
504
695
|
/**
|
|
505
696
|
* Writes each subject's pose into arrays, one per channel, subject by subject in the order given:
|
|
506
697
|
* what `probe(subject, out)` gives, without a pose object per subject. A channel of `n` numbers
|
|
507
698
|
* takes `n` places per subject, side by side; one with no value for a subject writes NaN there.
|
|
508
|
-
* Fastest while every voice runs on a lane
|
|
699
|
+
* Fastest while every voice runs on a lane, and when `subjects` is an array read again in the
|
|
700
|
+
* same order: the mix remembers the last array's subjects by position, holding them until the
|
|
701
|
+
* next `pull`, and skips looking up any still in its place. Throws when an array is too short for
|
|
702
|
+
* the subjects.
|
|
509
703
|
*/
|
|
510
704
|
pull(subjects: Iterable<I>, into: Columns<O>): void;
|
|
511
705
|
/**
|
|
@@ -514,10 +708,26 @@ export interface Mix<I, O> {
|
|
|
514
708
|
* older than the history reaches.
|
|
515
709
|
*/
|
|
516
710
|
project(timestamp: number): Projection<I, O>;
|
|
517
|
-
/**
|
|
711
|
+
/**
|
|
712
|
+
* Every channel at rest for this subject this frame, so a host can skip the write. After a probe
|
|
713
|
+
* of the subject this frame, it answers for the pose that probe gave, without folding again.
|
|
714
|
+
*/
|
|
518
715
|
atRest(subject: I): boolean;
|
|
716
|
+
/**
|
|
717
|
+
* A handle on every voice still in the mix, pending, live, held or fading, in the order they were
|
|
718
|
+
* cued; given a tag, only the voices whose `tags` carry it. Each is the handle `cue` returned for
|
|
719
|
+
* that voice, so a listed handle is `===` the cued one.
|
|
720
|
+
*/
|
|
721
|
+
voices(tag?: string): Handle<I>[];
|
|
519
722
|
/** Anything still contributing, fading, or pending. */
|
|
520
723
|
readonly live: boolean;
|
|
724
|
+
/**
|
|
725
|
+
* Another frame would change no pose, so a host's frame loop may sleep: every voice is done, held
|
|
726
|
+
* at a plain weight, or a motion whose every subject has landed on its target. At rate 0 it is
|
|
727
|
+
* enough that every voice not done has started, at a plain weight, with no anchor. A change made
|
|
728
|
+
* since the last sync, a retarget or a rate included, makes it false until the next.
|
|
729
|
+
*/
|
|
730
|
+
readonly inert: boolean;
|
|
521
731
|
/** Fades every voice out: over `over` when given, over each voice's own `fade.out` otherwise. */
|
|
522
732
|
mute(opts?: {
|
|
523
733
|
over?: number;
|
|
@@ -552,6 +762,15 @@ export interface Mix<I, O> {
|
|
|
552
762
|
* whoever drains them.
|
|
553
763
|
*/
|
|
554
764
|
drain<E = unknown>(tag?: string): Sent<I, E>[];
|
|
765
|
+
/**
|
|
766
|
+
* Hands the host each mark and hit before it comes, against a clock of its own, so it can schedule
|
|
767
|
+
* the thing itself: a sound on an `AudioContext`, a MIDI message with a timestamp, a video loaded
|
|
768
|
+
* before the voice that shows it starts. Booking runs at each `sync`, `ahead` ms out, and a
|
|
769
|
+
* booking whose time moves is stopped and taken again. Nothing is booked twice: a mark is known by
|
|
770
|
+
* its voice and which mark, a hit by its voice, index and pass. `project` books nothing, and
|
|
771
|
+
* nothing about booking is replayed under `history`. A mix with no booker pays nothing for it.
|
|
772
|
+
*/
|
|
773
|
+
book<E = unknown>(opts: BookOptions<E>): Booker;
|
|
555
774
|
}
|
|
556
775
|
/**
|
|
557
776
|
* The implementation behind a mix: which patch forms it runs, and how it makes one.
|
|
@@ -562,5 +781,5 @@ export interface Engine {
|
|
|
562
781
|
readonly name: string;
|
|
563
782
|
/** Which patch forms this engine can run. A voice it cannot run is refused at `cue`, by name. */
|
|
564
783
|
readonly runs: ReadonlySet<'fn' | 'keys' | 'motion'>;
|
|
565
|
-
create<I, O>(kit: Kit<O>, opts: MixOptions): Mix<I, O>;
|
|
784
|
+
create<I, O, H = unknown>(kit: Kit<O>, opts: MixOptions<H>): Mix<I, O, H>;
|
|
566
785
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Voice } from './voice.js';
|
|
2
|
+
/** Whether the voice's shared unreached record stands for the subject numbered `slot`. */
|
|
3
|
+
export declare function unreached<I, O>(voice: Voice<I, O>, slot: number): boolean;
|
|
4
|
+
/** Marks or clears the subject numbered `slot` as one the voice does not reach. */
|
|
5
|
+
export declare function unreach<I, O>(voice: Voice<I, O>, slot: number, on: boolean): void;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Whether the voice's shared unreached record stands for the subject numbered `slot`. */
|
|
2
|
+
export function unreached(voice, slot) {
|
|
3
|
+
const bits = voice.unreachedBits;
|
|
4
|
+
if (bits === null || slot < 0)
|
|
5
|
+
return false;
|
|
6
|
+
const word = slot >>> 5;
|
|
7
|
+
return word < bits.length && (bits[word] & (1 << (slot & 31))) !== 0;
|
|
8
|
+
}
|
|
9
|
+
/** Marks or clears the subject numbered `slot` as one the voice does not reach. */
|
|
10
|
+
export function unreach(voice, slot, on) {
|
|
11
|
+
let bits = voice.unreachedBits;
|
|
12
|
+
const word = slot >>> 5;
|
|
13
|
+
if (bits === null || word >= bits.length) {
|
|
14
|
+
if (!on)
|
|
15
|
+
return;
|
|
16
|
+
const grown = new Uint32Array(Math.max(word + 1, (bits?.length ?? 0) * 2, 2));
|
|
17
|
+
if (bits !== null)
|
|
18
|
+
grown.set(bits);
|
|
19
|
+
voice.unreachedBits = grown;
|
|
20
|
+
bits = grown;
|
|
21
|
+
}
|
|
22
|
+
const bit = 1 << (slot & 31);
|
|
23
|
+
bits[word] = on ? bits[word] | bit : bits[word] & ~bit;
|
|
24
|
+
}
|