@msb235/blits 0.4.0 → 0.6.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 +289 -0
- package/README.md +2 -1
- 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 +3 -1
- package/dist/index.js +1 -0
- 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 +121 -246
- package/dist/lanes.js +150 -1578
- 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 +248 -196
- package/dist/mixer.js +270 -2220
- package/dist/motion.d.ts +66 -21
- package/dist/motion.js +325 -165
- 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 +13 -9
- package/dist/signals.js +14 -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/ticker.d.ts +48 -0
- package/dist/ticker.js +112 -0
- package/dist/tweened.d.ts +11 -0
- package/dist/tweened.js +48 -0
- package/dist/types.d.ts +237 -43
- package/dist/unreached.d.ts +5 -0
- package/dist/unreached.js +24 -0
- package/dist/voice.d.ts +240 -0
- package/dist/voice.js +324 -0
- package/dist/weigh.d.ts +26 -0
- package/dist/weigh.js +89 -0
- package/docs/schema.html +137 -56
- 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
|
}
|
|
@@ -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 — unless it
|
|
398
|
+
* set, at once where none is — unless it freezes after.
|
|
321
399
|
*/
|
|
322
400
|
loop?: boolean | number;
|
|
323
401
|
/**
|
|
@@ -328,22 +406,24 @@ export interface VoiceSpec<I, O> {
|
|
|
328
406
|
/**
|
|
329
407
|
* Show a subject the first frame before it starts — while the voice is pending and while the
|
|
330
408
|
* subject waits out its `stagger` — the last frame of the last pass after a finite loop plays
|
|
331
|
-
* out, or both. A
|
|
409
|
+
* out, or both. A frozen subject's clock stands still: `at` is asked for the edge frame and `step`
|
|
332
410
|
* does not run, past one last step to the end of the last pass. `fade.in` counts from the first
|
|
333
|
-
* frame the voice shows. A voice
|
|
334
|
-
* takes it out, so every one cued must be faded or it stays in the mix for good. Does
|
|
335
|
-
* a motion patch, which
|
|
411
|
+
* frame the voice shows. A voice freezing after stays, `frozen`, until `fade()` or an anchored
|
|
412
|
+
* `out` takes it out, so every one cued must be faded or it stays in the mix for good. Does
|
|
413
|
+
* nothing to a motion patch, which keeps its target already. Default: neither.
|
|
336
414
|
*/
|
|
415
|
+
freeze?: 'before' | 'after' | 'both';
|
|
416
|
+
/** @deprecated Use `freeze`. A voice that sets only `hold` still freezes; `freeze` wins over it. */
|
|
337
417
|
hold?: 'before' | 'after' | 'both';
|
|
338
418
|
/** Steady weight, or a signal read per subject per frame. Default 1. */
|
|
339
|
-
weight?: number | Signal<I>;
|
|
419
|
+
weight?: number | Signal<I, H>;
|
|
340
420
|
/** Ramp in and out, ms. Out applies on `fade()` and when a finite loop ends. */
|
|
341
421
|
fade?: FadeSpec;
|
|
342
422
|
/** Voices sharing a locus are alternatives: the mix folds them through each channel's `lerp`. */
|
|
343
423
|
locus?: string;
|
|
344
424
|
/** A `keys` voice whose first stop reads wherever this subject is now. */
|
|
345
425
|
from?: 'current';
|
|
346
|
-
/** Words a source attaches to this voice, so its events can be
|
|
426
|
+
/** Words a source attaches to this voice, so its events and its handle can be taken as a set. */
|
|
347
427
|
tags?: readonly string[];
|
|
348
428
|
/** What other voices call this one by. A label blits never reads. */
|
|
349
429
|
name?: string;
|
|
@@ -355,6 +435,54 @@ export interface VoiceSpec<I, O> {
|
|
|
355
435
|
score?: string;
|
|
356
436
|
/** Where it sits relative to the clock or to other voices, in place of `start`. */
|
|
357
437
|
anchor?: Placement;
|
|
438
|
+
/**
|
|
439
|
+
* Events at times on this voice's clock, which `book` hands a host ahead of time. Patch-sent
|
|
440
|
+
* events are not known ahead, so they stay drain-only; these are the plan.
|
|
441
|
+
*/
|
|
442
|
+
hits?: readonly Hit[];
|
|
443
|
+
/**
|
|
444
|
+
* The owner this voice plays under, a handle `owns` returned. Its `start` and `anchor` are then on
|
|
445
|
+
* the owner's clock, in ms from when the owner starts, and default to where that clock is now; a
|
|
446
|
+
* bare name in an anchor means a sibling, another voice the owner holds. Its clock runs on the
|
|
447
|
+
* owner's, so the owner's rate, ramp and seeks move it, and its weight is multiplied by the
|
|
448
|
+
* owner's weight and fade. Without a `freeze` of its own it takes the owner's.
|
|
449
|
+
*/
|
|
450
|
+
owner?: Handle<I>;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* What `owns` takes: an owner has no patch, and plays only through the voices it holds.
|
|
454
|
+
*
|
|
455
|
+
* @category voice
|
|
456
|
+
*/
|
|
457
|
+
export interface OwnerSpec<I, H = unknown> {
|
|
458
|
+
/**
|
|
459
|
+
* When the owner starts, on its own owner's clock: the host's for an owner on the mix, as a
|
|
460
|
+
* voice's `start` is. Default: now.
|
|
461
|
+
*/
|
|
462
|
+
start?: number;
|
|
463
|
+
/** Its clock's rate, multiplied into every child's own. Default 1. */
|
|
464
|
+
rate?: number;
|
|
465
|
+
/**
|
|
466
|
+
* Multiplied into every child's weight per subject, as the child's own fade is, before the child's
|
|
467
|
+
* locus folds it: a number, or a signal read per subject per frame. Default 1.
|
|
468
|
+
*/
|
|
469
|
+
weight?: number | Signal<I, H>;
|
|
470
|
+
/** One ramp in and out over every child, multiplied into their weights as `weight` is. */
|
|
471
|
+
fade?: FadeSpec;
|
|
472
|
+
/** The freeze every child without one of its own takes. */
|
|
473
|
+
freeze?: 'before' | 'after' | 'both';
|
|
474
|
+
/** @deprecated Use `freeze`. An owner that sets only `hold` still freezes; `freeze` wins over it. */
|
|
475
|
+
hold?: 'before' | 'after' | 'both';
|
|
476
|
+
/** Words a source attaches to it, as a voice's. */
|
|
477
|
+
tags?: readonly string[];
|
|
478
|
+
/** What other voices call it by, among its siblings. */
|
|
479
|
+
name?: string;
|
|
480
|
+
/** The plan it belongs to, as a voice's. */
|
|
481
|
+
score?: string;
|
|
482
|
+
/** Where it sits relative to its own owner's clock or to other voices, in place of `start`. */
|
|
483
|
+
anchor?: Placement;
|
|
484
|
+
/** The owner it plays under, so owners nest. */
|
|
485
|
+
owner?: Handle<I>;
|
|
358
486
|
}
|
|
359
487
|
/**
|
|
360
488
|
* How a voice leaves when it is faded: the whole voice, or one subject.
|
|
@@ -386,8 +514,10 @@ export type FadeOptions<I = unknown> = {
|
|
|
386
514
|
*/
|
|
387
515
|
export interface Handle<I = unknown> {
|
|
388
516
|
readonly id: number;
|
|
389
|
-
/** `
|
|
390
|
-
readonly state: 'pending' | 'live' | '
|
|
517
|
+
/** `frozen`: a voice freezing after has played every pass and shows its last frame until faded. */
|
|
518
|
+
readonly state: 'pending' | 'live' | 'frozen' | 'fading' | 'done';
|
|
519
|
+
/** The handle of the owner this voice plays under; undefined for one on the mix clock. */
|
|
520
|
+
readonly owner: Handle<I> | undefined;
|
|
391
521
|
/** Live. Writes land on the next sync. */
|
|
392
522
|
weight: number;
|
|
393
523
|
/** Playback rate now. Setting it changes speed at once; `ramp` eases into a new one. */
|
|
@@ -407,7 +537,7 @@ export interface Handle<I = unknown> {
|
|
|
407
537
|
/**
|
|
408
538
|
* The weight this voice gave `subject` the last frame that subject was probed: after its fades
|
|
409
539
|
* and its weight signal, before a locus folds it with its alternatives. 0 for a subject it does
|
|
410
|
-
* not reach, has not started on and does not
|
|
540
|
+
* not reach, has not started on and does not freeze before, has left at rest, or has never been
|
|
411
541
|
* probed for; 0 once done.
|
|
412
542
|
* Costs nothing until it is asked.
|
|
413
543
|
*/
|
|
@@ -425,12 +555,12 @@ export interface Handle<I = unknown> {
|
|
|
425
555
|
*
|
|
426
556
|
* @category mix
|
|
427
557
|
*/
|
|
428
|
-
export interface MixOptions {
|
|
558
|
+
export interface MixOptions<H = unknown> {
|
|
429
559
|
engine?: Engine;
|
|
430
560
|
/** Reduced motion: fades and warm-ups snap, `dt` reads Infinity. */
|
|
431
561
|
reduce?: boolean | (() => boolean);
|
|
432
|
-
/** Merged into every `setting.host`. */
|
|
433
|
-
host?:
|
|
562
|
+
/** Merged into every `setting.host`. Its type is the mix's `H`, which every patch and signal it cues reads. */
|
|
563
|
+
host?: H;
|
|
434
564
|
/**
|
|
435
565
|
* The band a rest-less channel's influence switches on and off across. It has to clear the frame
|
|
436
566
|
* noise in a real signal; these are placeholders until the klieg port measures one.
|
|
@@ -514,11 +644,26 @@ export type Columns<O> = {
|
|
|
514
644
|
*
|
|
515
645
|
* @category mix
|
|
516
646
|
*/
|
|
517
|
-
export interface Mix<I, O> {
|
|
647
|
+
export interface Mix<I, O, H = unknown> {
|
|
518
648
|
/** Cues a voice. Throws when the engine cannot run the patch's form, or the kit lacks a channel. */
|
|
519
|
-
cue(spec: VoiceSpec<I, O>): Handle<I>;
|
|
520
|
-
/**
|
|
521
|
-
|
|
649
|
+
cue(spec: VoiceSpec<I, O, H>): Handle<I>;
|
|
650
|
+
/**
|
|
651
|
+
* N voices whose weights split one signal, cued into one locus so they fold as alternatives. The
|
|
652
|
+
* signal is read once per subject per frame, with the first member's setting, and every member
|
|
653
|
+
* takes its share of that one reading; a signal keeping state keeps it once, not per member.
|
|
654
|
+
*/
|
|
655
|
+
blend(patches: readonly Patch<I, O, unknown, H>[], by: Signal<I, H>, spec?: Omit<VoiceSpec<I, O, H>, 'patch' | 'weight' | 'locus'>): Handle<I>[];
|
|
656
|
+
/**
|
|
657
|
+
* Cues an owner: a voice with no patch that holds the voices cued with `owner` set to its handle,
|
|
658
|
+
* and plays them on its own clock, so they can be placed, timed and faded as one. Its handle acts
|
|
659
|
+
* on all of them: `rate` and `ramp` multiply into theirs, `seek` moves their clocks with its own
|
|
660
|
+
* and leaves their state where it is, and `weight` and `fade()` multiply into their weights, by
|
|
661
|
+
* what its `weightOf` reports; it fades as a whole, not by subject or at rest. It is
|
|
662
|
+
* `played` once every voice it held has finished its passes, and leaves, `done`, with its last; a
|
|
663
|
+
* fade that ends takes the rest with it. One that never holds a voice stays until faded. Owners
|
|
664
|
+
* nest. Throws for a `loop`: a pass would have to restart its children.
|
|
665
|
+
*/
|
|
666
|
+
owns(spec: OwnerSpec<I, H>): Handle<I>;
|
|
522
667
|
/** The host reports the clock, once a frame. Nothing advances at the call. */
|
|
523
668
|
sync(timestamp: number): void;
|
|
524
669
|
/**
|
|
@@ -526,7 +671,30 @@ export interface Mix<I, O> {
|
|
|
526
671
|
* hidden tab comes back. Every voice, fade and subject resumes where it was left.
|
|
527
672
|
*/
|
|
528
673
|
rebase(): void;
|
|
529
|
-
/**
|
|
674
|
+
/**
|
|
675
|
+
* The mix's own playback rate, multiplied into every voice's: 1 is real time and 0 pauses the
|
|
676
|
+
* whole mix. A negative rate throws, since the mix only goes forward. Setting it changes speed at
|
|
677
|
+
* once; `ramp` eases into a new one. It scales mix time, which everything a voice owns runs on:
|
|
678
|
+
* its clock, its fades and a handle's ramp, `stagger`, an anchor's `by`, `stepMs`, `maxDt`,
|
|
679
|
+
* `history.ms`, every `dt`, and `setting.timestamp`. Timestamps on the host's clock name the same
|
|
680
|
+
* moment whatever the rate does: a `start`, an anchor given as a number, an announced mark, what
|
|
681
|
+
* `marks` reports and the time `project` reads, so a start ahead of a paused mix waits for the
|
|
682
|
+
* host's clock to reach it. A weight signal is still asked at every probe, so one reading host
|
|
683
|
+
* input follows it while the mix is paused.
|
|
684
|
+
*/
|
|
685
|
+
rate: number;
|
|
686
|
+
/**
|
|
687
|
+
* Moves the mix's rate to `rate` linearly over `over` ms of the host's clock, as `Handle.ramp`
|
|
688
|
+
* moves a voice's. Mix time integrates the ramp and a voice's clock integrates mix time, so a ramp
|
|
689
|
+
* on both multiplies and every position stays continuous. A later `rate` write or `ramp` replaces
|
|
690
|
+
* it.
|
|
691
|
+
*/
|
|
692
|
+
ramp(rate: number, over: number): void;
|
|
693
|
+
/**
|
|
694
|
+
* The merged pose for one subject at the synced frame, written into `out` when given. Without
|
|
695
|
+
* it, each call makes a new object, so a host reading every subject every frame passes `out` or
|
|
696
|
+
* reads by `pull`.
|
|
697
|
+
*/
|
|
530
698
|
probe(subject: I, out?: O): O;
|
|
531
699
|
/**
|
|
532
700
|
* Writes each subject's pose into arrays, one per channel, subject by subject in the order given:
|
|
@@ -544,16 +712,33 @@ export interface Mix<I, O> {
|
|
|
544
712
|
* older than the history reaches.
|
|
545
713
|
*/
|
|
546
714
|
project(timestamp: number): Projection<I, O>;
|
|
547
|
-
/**
|
|
715
|
+
/**
|
|
716
|
+
* Every channel at rest for this subject this frame, so a host can skip the write. After a probe
|
|
717
|
+
* of the subject this frame, it answers for the pose that probe gave, without folding again.
|
|
718
|
+
*/
|
|
548
719
|
atRest(subject: I): boolean;
|
|
720
|
+
/**
|
|
721
|
+
* A handle on every voice still in the mix, pending, live, frozen or fading, in the order they were
|
|
722
|
+
* cued; given a tag, only the voices whose `tags` carry it. Each is the handle `cue` returned for
|
|
723
|
+
* that voice, so a listed handle is `===` the cued one.
|
|
724
|
+
*/
|
|
725
|
+
voices(tag?: string): Handle<I>[];
|
|
549
726
|
/** Anything still contributing, fading, or pending. */
|
|
550
727
|
readonly live: boolean;
|
|
551
728
|
/**
|
|
552
|
-
* Another frame would change no pose, so a host's frame loop may sleep: every voice is done,
|
|
553
|
-
* at a plain weight, or a motion whose every subject has landed on its target.
|
|
554
|
-
*
|
|
729
|
+
* Another frame would change no pose, so a host's frame loop may sleep: every voice is done, frozen
|
|
730
|
+
* at a plain weight, or a motion whose every subject has landed on its target. At rate 0 it is
|
|
731
|
+
* enough that every voice not done has started, at a plain weight, with no anchor. A change made
|
|
732
|
+
* since the last sync, a retarget or a rate included, makes it false until the next.
|
|
555
733
|
*/
|
|
556
734
|
readonly inert: boolean;
|
|
735
|
+
/**
|
|
736
|
+
* Calls `fn` when a host call makes the mix need frames again after a sync: a cue, a fade, a
|
|
737
|
+
* handle's or the mix's rate, a seek, a `drop`, a motion retargeted. It fires once until the next
|
|
738
|
+
* sync clears the change, and never during `sync`. Returns a function that unsubscribes `fn`.
|
|
739
|
+
* A frame loop sleeping on `inert` subscribes here to wake.
|
|
740
|
+
*/
|
|
741
|
+
onWake(fn: () => void): () => void;
|
|
557
742
|
/** Fades every voice out: over `over` when given, over each voice's own `fade.out` otherwise. */
|
|
558
743
|
mute(opts?: {
|
|
559
744
|
over?: number;
|
|
@@ -588,6 +773,15 @@ export interface Mix<I, O> {
|
|
|
588
773
|
* whoever drains them.
|
|
589
774
|
*/
|
|
590
775
|
drain<E = unknown>(tag?: string): Sent<I, E>[];
|
|
776
|
+
/**
|
|
777
|
+
* Hands the host each mark and hit before it comes, against a clock of its own, so it can schedule
|
|
778
|
+
* the thing itself: a sound on an `AudioContext`, a MIDI message with a timestamp, a video loaded
|
|
779
|
+
* before the voice that shows it starts. Booking runs at each `sync`, `ahead` ms out, and a
|
|
780
|
+
* booking whose time moves is stopped and taken again. Nothing is booked twice: a mark is known by
|
|
781
|
+
* its voice and which mark, a hit by its voice, index and pass. `project` books nothing, and
|
|
782
|
+
* nothing about booking is replayed under `history`. A mix with no booker pays nothing for it.
|
|
783
|
+
*/
|
|
784
|
+
book<E = unknown>(opts: BookOptions<E>): Booker;
|
|
591
785
|
}
|
|
592
786
|
/**
|
|
593
787
|
* The implementation behind a mix: which patch forms it runs, and how it makes one.
|
|
@@ -598,5 +792,5 @@ export interface Engine {
|
|
|
598
792
|
readonly name: string;
|
|
599
793
|
/** Which patch forms this engine can run. A voice it cannot run is refused at `cue`, by name. */
|
|
600
794
|
readonly runs: ReadonlySet<'fn' | 'keys' | 'motion'>;
|
|
601
|
-
create<I, O>(kit: Kit<O>, opts: MixOptions): Mix<I, O>;
|
|
795
|
+
create<I, O, H = unknown>(kit: Kit<O>, opts: MixOptions<H>): Mix<I, O, H>;
|
|
602
796
|
}
|
|
@@ -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
|
+
}
|