@msb235/blits 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/CHANGELOG.md +152 -0
  2. package/README.md +31 -7
  3. package/dist/bare.js +7 -1
  4. package/dist/book.d.ts +7 -0
  5. package/dist/book.js +35 -4
  6. package/dist/chain.d.ts +2 -1
  7. package/dist/chain.js +7 -3
  8. package/dist/channels.d.ts +12 -19
  9. package/dist/channels.js +18 -118
  10. package/dist/clock.d.ts +9 -2
  11. package/dist/clock.js +10 -2
  12. package/dist/closed.d.ts +15 -0
  13. package/dist/closed.js +144 -0
  14. package/dist/color.d.ts +61 -0
  15. package/dist/color.js +229 -0
  16. package/dist/columns.js +2 -1
  17. package/dist/crowd.d.ts +1 -1
  18. package/dist/crowd.js +4 -1
  19. package/dist/cue.d.ts +2 -0
  20. package/dist/cue.js +80 -27
  21. package/dist/due.js +3 -0
  22. package/dist/fade.d.ts +13 -0
  23. package/dist/fade.js +57 -4
  24. package/dist/fill.d.ts +1 -1
  25. package/dist/fill.js +15 -8
  26. package/dist/fit.d.ts +144 -0
  27. package/dist/fit.js +181 -0
  28. package/dist/fold.d.ts +3 -3
  29. package/dist/fold.js +18 -11
  30. package/dist/gather.d.ts +6 -0
  31. package/dist/gather.js +18 -0
  32. package/dist/gone.d.ts +32 -0
  33. package/dist/gone.js +134 -0
  34. package/dist/handle.d.ts +27 -2
  35. package/dist/handle.js +60 -11
  36. package/dist/held.js +4 -0
  37. package/dist/history.d.ts +15 -2
  38. package/dist/history.js +56 -9
  39. package/dist/hosts.d.ts +2 -2
  40. package/dist/hosts.js +20 -6
  41. package/dist/index.d.ts +8 -2
  42. package/dist/index.js +5 -1
  43. package/dist/lane.d.ts +1 -1
  44. package/dist/lanes.d.ts +32 -9
  45. package/dist/lanes.js +53 -24
  46. package/dist/locus.d.ts +3 -3
  47. package/dist/locus.js +1 -1
  48. package/dist/marks.d.ts +3 -0
  49. package/dist/marks.js +80 -12
  50. package/dist/meet.d.ts +3 -2
  51. package/dist/meet.js +15 -3
  52. package/dist/mixer.d.ts +56 -36
  53. package/dist/mixer.js +158 -87
  54. package/dist/motion.d.ts +2 -199
  55. package/dist/motion.js +2 -652
  56. package/dist/motions.d.ts +266 -0
  57. package/dist/motions.js +724 -0
  58. package/dist/move.d.ts +1 -1
  59. package/dist/move.js +28 -8
  60. package/dist/owner.d.ts +1 -1
  61. package/dist/owner.js +3 -3
  62. package/dist/pace.d.ts +2 -0
  63. package/dist/pace.js +8 -0
  64. package/dist/pack.d.ts +31 -0
  65. package/dist/pack.js +65 -0
  66. package/dist/paging.d.ts +63 -0
  67. package/dist/paging.js +110 -0
  68. package/dist/patch.d.ts +3 -0
  69. package/dist/patch.js +2 -0
  70. package/dist/place.js +235 -43
  71. package/dist/project.d.ts +7 -4
  72. package/dist/project.js +117 -78
  73. package/dist/pull.js +4 -3
  74. package/dist/qualify.js +4 -2
  75. package/dist/revive.d.ts +58 -0
  76. package/dist/revive.js +158 -0
  77. package/dist/sample.d.ts +1 -1
  78. package/dist/sample.js +6 -1
  79. package/dist/scored.d.ts +57 -0
  80. package/dist/scored.js +196 -0
  81. package/dist/seek.d.ts +3 -0
  82. package/dist/seek.js +311 -0
  83. package/dist/spans.d.ts +29 -0
  84. package/dist/spans.js +165 -0
  85. package/dist/strays.d.ts +1 -1
  86. package/dist/strays.js +21 -0
  87. package/dist/tape.d.ts +21 -0
  88. package/dist/tape.js +65 -0
  89. package/dist/ticker.d.ts +28 -3
  90. package/dist/ticker.js +3 -0
  91. package/dist/transport.d.ts +125 -0
  92. package/dist/transport.js +283 -0
  93. package/dist/types.d.ts +404 -38
  94. package/dist/unpage.d.ts +8 -0
  95. package/dist/unpage.js +165 -0
  96. package/dist/voice.d.ts +75 -7
  97. package/dist/voice.js +119 -4
  98. package/dist/weigh.js +2 -2
  99. package/docs/schema.html +120 -31
  100. package/package.json +2 -1
package/dist/types.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { Fit, Order, Strength } from './fit.js';
1
2
  /**
2
3
  * One field of a delta, with its own arithmetic.
3
4
  *
@@ -18,7 +19,7 @@ export interface Channel<V> {
18
19
  bounds?: readonly [min: number, max: number];
19
20
  /** Identity. Absent means the channel has none: it replaces rather than contributes. */
20
21
  rest?: V;
21
- /** Fold two influences into one. */
22
+ /** Fold two contributions into one. */
22
23
  merge(a: V, b: V): V;
23
24
  /** Fade toward `rest` by weight 0..1. Required when `rest` is set; absent otherwise. */
24
25
  scale?(v: V, w: number): V;
@@ -26,7 +27,7 @@ export interface Channel<V> {
26
27
  lerp(a: V, b: V, u: number): V;
27
28
  /**
28
29
  * Optional: `merge(into, scale(v, w))`, written into `into` and returned, so a channel whose
29
- * values are objects need not allocate per influence. The mix only hands it a value it made.
30
+ * values are objects need not allocate per contribution. The mix only hands it a value it made.
30
31
  */
31
32
  fold?(into: V, v: V, w: number): V;
32
33
  }
@@ -94,17 +95,18 @@ export interface Setting<S = void, H = unknown> {
94
95
  * The state `owner` keeps for this voice and this subject, made by `init` on first ask. The mix
95
96
  * holds it, so a read at another time can copy it instead of moving it. A stateful signal keeps
96
97
  * 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.
98
+ * partway through playing can have that state advanced once for one subject probed the frame
99
+ * before it starts and not on that frame; one that keeps state from its first call, or a patch
100
+ * that declares `state`, never does.
100
101
  */
101
102
  keep<K>(owner: object, init: () => K): K;
102
103
  /**
103
104
  * Reports an event at `timestamp`, for this voice and this subject. The mix queues it until the
104
105
  * host drains it, and never calls back. Meant for `step`, where under `stepMs` the timestamp is
105
106
  * the interval the event happened in rather than the frame that sampled it. Sent from a stateless
106
- * patch's `at` while it runs on a lane, it goes out for every subject the mix has met, probed that
107
- * frame or not; `at` is not asked for a subject at weight 0, so nothing is sent from it there.
107
+ * patch's `at` while it runs on a lane, it goes out for every subject the lane fills, probed that
108
+ * frame or not: each probed that frame or the last; `at` is not asked for a subject at weight 0,
109
+ * so nothing is sent from it there.
108
110
  */
109
111
  send(event: unknown): void;
110
112
  }
@@ -175,7 +177,7 @@ export interface Patch<I, O, S = void, H = unknown> {
175
177
  readonly reads?: readonly string[];
176
178
  /**
177
179
  * `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.
180
+ * `step` still runs. A `keys` patch's stops are not read there either, unless its voice is in a locus.
179
181
  */
180
182
  at(phase: number, subject: I, setting: Setting<S, H>): Partial<O>;
181
183
  /** Per-subject state, created on the first frame this patch sees a subject. */
@@ -195,6 +197,13 @@ export interface Patch<I, O, S = void, H = unknown> {
195
197
  * function needs its own.
196
198
  */
197
199
  clone?(state: S): S;
200
+ /**
201
+ * `state` as data that survives `structuredClone`, for a history `store` to keep; `unpack` makes
202
+ * a state from it again. With a store, a patch with `state` or `step` needs both, or `cue`
203
+ * refuses it.
204
+ */
205
+ pack?(state: S): unknown;
206
+ unpack?(data: unknown): S;
198
207
  }
199
208
  /**
200
209
  * A 0..1 scalar resolved per subject per frame from something outside the clock. `input` is set
@@ -217,12 +226,15 @@ export interface FadeSpec {
217
226
  ease?: Easing;
218
227
  }
219
228
  /**
220
- * The four times a voice is known by on the mix clock: when its fade in begins (`start`), when it is
221
- * fully in (`in`), when its fade out begins (`out`), and when it is gone (`end`).
229
+ * The times a voice is known by on the mix clock: when its fade in begins (`start`), when it is
230
+ * fully in (`in`), when its last pass ends (`coast`), when its fade out begins (`out`), and when it
231
+ * is gone (`end`). A voice coasts when `played` resolves true, for its latest-staggered subject: at
232
+ * its `out` where it does not freeze, and where it starts showing its last frame where it does. A
233
+ * voice that loops for good, or fades before its last pass ends, never coasts.
222
234
  *
223
235
  * @category score
224
236
  */
225
- export type Mark = 'start' | 'in' | 'out' | 'end';
237
+ export type Mark = 'start' | 'in' | 'coast' | 'out' | 'end';
226
238
  /**
227
239
  * Selects voices by what the plan knows of them, never by a channel's value, within the asking
228
240
  * voice's own score unless it names another. Where several match,
@@ -243,7 +255,8 @@ export interface Query {
243
255
  /**
244
256
  * A time given by another voice: `mark` of the voice `of` selects, moved by `by` ms. `after` is
245
257
  * sugar for that voice's `end`, `with` for its `start`, and `before` for its start less `by`. A
246
- * string selects by name.
258
+ * string selects by name. `all` is the latest of its anchors, known once every one is; `any` the
259
+ * earliest, known once one has passed or every one is known.
247
260
  *
248
261
  * @category score
249
262
  */
@@ -260,6 +273,10 @@ export type Anchor = {
260
273
  } | {
261
274
  before: string | Query;
262
275
  by?: number;
276
+ } | {
277
+ all: readonly Anchor[];
278
+ } | {
279
+ any: readonly Anchor[];
263
280
  };
264
281
  /**
265
282
  * Where a voice sits on the mix clock: at most one of `start` and `in`, and at most one of `out`
@@ -276,21 +293,23 @@ export interface Placement {
276
293
  end?: number | Anchor;
277
294
  }
278
295
  /**
279
- * One mark as `marks` lists it: one of a voice's four, or one the host announced on a score, which
280
- * has a name and no voice.
296
+ * One mark as `marks` lists it: one of a voice's, or one the host announced on a score, which has a
297
+ * name and no voice.
281
298
  *
282
299
  * @category score
283
300
  */
284
301
  export interface Marked {
285
302
  /** On the host's clock. */
286
303
  timestamp: number;
287
- /** Which of a voice's four this is; undefined for an announced mark. */
304
+ /** Which of a voice's this is; undefined for an announced mark. */
288
305
  mark: Mark | undefined;
289
306
  /** The voice it belongs to; undefined for an announced mark. */
290
307
  voice: number | undefined;
291
308
  score: string | undefined;
292
309
  name: string | undefined;
293
310
  tags: readonly string[];
311
+ /** The `name` of the mix the voice is in, or that announced the mark; undefined for none. */
312
+ mix: string | undefined;
294
313
  }
295
314
  /**
296
315
  * An event at a time on a voice's own clock, which `book` hands a host ahead of time. It plays once
@@ -368,8 +387,31 @@ export interface Booker {
368
387
  *
369
388
  * @category voice
370
389
  */
371
- export interface VoiceSpec<I, O, H = unknown> {
390
+ /**
391
+ * How a voice or owner held by a span may give way so the span keeps its budget, which the span's
392
+ * fit reads. Anything it does not allow, it will not do. Read only under a span.
393
+ *
394
+ * @category score
395
+ */
396
+ export interface SpanHints {
397
+ /** How many times faster than its own rate it may play. Default 1: no faster. */
398
+ faster?: number;
399
+ /** How many times slower than its own rate it may play. Default 1: no slower. */
400
+ slower?: number;
401
+ /** Whether it may start before the one before it ends, where the span's order would not. */
402
+ overlap?: boolean;
403
+ /** Whether it may jump to its end instead of playing. A span held by a span is never skipped. */
404
+ ballast?: boolean;
405
+ /** How hard its own length holds against the span's budget. Default `weak`. */
406
+ priority?: Strength;
407
+ }
408
+ export interface VoiceSpec<I, O, H = unknown> extends SpanHints {
372
409
  patch: Patch<I, O, unknown, H>;
410
+ /**
411
+ * What `history.revive` rebuilds this spec from, so a history `store` can page the voice out once
412
+ * it has left. A voice cued without it stays in memory for as long as history reaches it.
413
+ */
414
+ as?: Described;
373
415
  /**
374
416
  * Which subjects this voice reaches. Default: all of them. The predicate is fixed at `cue`; it
375
417
  * runs per subject the first time the mix sees that subject, and the answer is kept. Every
@@ -454,7 +496,7 @@ export interface VoiceSpec<I, O, H = unknown> {
454
496
  *
455
497
  * @category voice
456
498
  */
457
- export interface OwnerSpec<I, H = unknown> {
499
+ export interface OwnerSpec<I, H = unknown> extends SpanHints {
458
500
  /**
459
501
  * When the owner starts, on its own owner's clock: the host's for an owner on the mix, as a
460
502
  * voice's `start` is. Default: now.
@@ -484,6 +526,58 @@ export interface OwnerSpec<I, H = unknown> {
484
526
  /** The owner it plays under, so owners nest. */
485
527
  owner?: Handle<I>;
486
528
  }
529
+ /**
530
+ * What `span` takes: an owner with a budget, which lays out the voices it holds in an order and
531
+ * fits them into the budget.
532
+ *
533
+ * @category score
534
+ */
535
+ export interface SpanSpec<I, H = unknown> extends OwnerSpec<I, H> {
536
+ /** Its budget, ms on its own clock. Default: none, so its children only keep their order. */
537
+ duration?: number;
538
+ /** How hard the budget holds against its children's own lengths. Default `strong`. */
539
+ priority?: Strength;
540
+ /** How its children are laid out, in the order they were cued. Default `queue`. */
541
+ order?: Order;
542
+ /** How far through the one before a child starts under `stagger`, 0..1. Default 0.5. */
543
+ share?: number;
544
+ /**
545
+ * How the children are fitted once they are retimed toward the budget, faster or slower as
546
+ * their hints allow. Default `pipe(condense(), shed())`.
547
+ */
548
+ fit?: Fit;
549
+ /**
550
+ * What happens where the fit leaves them too long for a span at least `strong`: `instant` jumps
551
+ * every child weaker than the span to its end at once, and `overrun` lets them run long.
552
+ * Default `instant`.
553
+ */
554
+ spill?: 'instant' | 'overrun';
555
+ }
556
+ /**
557
+ * How a span's last fit came out.
558
+ *
559
+ * @category score
560
+ */
561
+ export interface FitResult {
562
+ /** Its budget, ms on its own clock; Infinity for none. */
563
+ budget: number;
564
+ /** Where its children end, ms on its own clock from its start. */
565
+ length: number;
566
+ /** How far `length` runs past the budget, 0 where it does not. */
567
+ over: number;
568
+ /** How many children it jumps to their end. */
569
+ skipped: number;
570
+ /** Whether the fit failed and `spill` decided. */
571
+ fell: boolean;
572
+ }
573
+ /**
574
+ * A span's handle: an owner's, and how its children were last fitted.
575
+ *
576
+ * @category score
577
+ */
578
+ export interface SpanHandle<I = unknown> extends Handle<I> {
579
+ readonly result: FitResult;
580
+ }
487
581
  /**
488
582
  * How a voice leaves when it is faded: the whole voice, or one subject.
489
583
  *
@@ -492,8 +586,13 @@ export interface OwnerSpec<I, H = unknown> {
492
586
  export type FadeOptions<I = unknown> = {
493
587
  /** The ramp, ms. Defaults to the voice's own `fade.out`. */
494
588
  over?: number;
495
- /** Leave per subject at the first frame that subject's contribution is at rest. */
496
- at?: 'rest';
589
+ /**
590
+ * When the fade begins. A mix time: ahead, the voice plays untouched until then and begins
591
+ * its fade exactly there, its `out` mark fixed from now, and `rise` before then takes it
592
+ * back with nothing changed; at or behind now, the fade began then and is partway. `'rest'`:
593
+ * leave per subject at the first frame that subject's contribution is at rest. Default now.
594
+ */
595
+ at?: number | 'rest';
497
596
  /** Ms after which the voice leaves whether or not it rested. */
498
597
  deadline?: number;
499
598
  subject?: never;
@@ -534,6 +633,15 @@ export interface Handle<I = unknown> {
534
633
  */
535
634
  seek(elapsed: number): void;
536
635
  fade(opts?: FadeOptions<I>): void;
636
+ /**
637
+ * Turns a fade out around: the voice climbs back from where its fade had got to, up the same
638
+ * curve, over `over` ms for the whole curve (default its `fade.in`, else its `fade.out`), and
639
+ * plays on as if never faded. A fade waiting for rest is taken back at once; a voice not fading
640
+ * is left as it is. A voice whose own end began the fade starts it again at its next frame.
641
+ */
642
+ rise(opts?: {
643
+ over?: number;
644
+ }): void;
537
645
  /**
538
646
  * The weight this voice gave `subject` the last frame that subject was probed: after its fades
539
647
  * and its weight signal, before a locus folds it with its alternatives. 0 for a subject it does
@@ -562,7 +670,7 @@ export interface MixOptions<H = unknown> {
562
670
  /** Merged into every `setting.host`. Its type is the mix's `H`, which every patch and signal it cues reads. */
563
671
  host?: H;
564
672
  /**
565
- * The band a rest-less channel's influence switches on and off across. It has to clear the frame
673
+ * The band a rest-less channel's contribution switches on and off across. It has to clear the frame
566
674
  * noise in a real signal; these are placeholders until the klieg port measures one.
567
675
  */
568
676
  band?: {
@@ -588,23 +696,232 @@ export interface MixOptions<H = unknown> {
588
696
  * read back restores the nearest copy and steps forward from it. Off by default, and a mix without
589
697
  * it keeps nothing. With `inputs`, it also keeps what each input signal on a voice's weight read
590
698
  * per subject, and the host fields patches `reads`, each time they changed, so a read back over a
591
- * `level` or a pointer is known rather than held.
699
+ * `level` or a pointer is known rather than held. With `tape`, the mix also records every call
700
+ * the host makes on it, its handles and its motion patches, so `seek` can move it and play those
701
+ * calls again.
592
702
  */
593
- history?: {
594
- ms: number;
595
- every?: number;
596
- inputs?: boolean;
597
- };
703
+ history?: HistoryOptions;
704
+ /**
705
+ * A subject's key, for a history `store`: unique among this mix's subjects for the session. A
706
+ * string or number subject is its own key; with a store, an object subject needs this.
707
+ */
708
+ keyOf?(subject: never): string | number;
598
709
  /**
599
710
  * Whether a channel may run as a lane: computed for every subject at once in flat arrays, when
600
711
  * every voice writing it can run that way. On by default; the pose is the same either way, so
601
712
  * turning it off is for ruling a lane out, or for comparing against. Two things differ: a
602
- * stateless patch's `setting.send` from `at` sends for every subject a lane fills, probed or not,
603
- * and a patch that first calls `setting.keep` partway through playing can advance that state once
604
- * more for one unprobed subject (see `Setting.keep`).
713
+ * stateless patch's `setting.send` from `at` sends for every subject a lane fills, those probed
714
+ * this frame or the last, and a patch that first calls `setting.keep` partway through playing can
715
+ * advance that state once more for one subject probed the frame before (see `Setting.keep`).
605
716
  */
606
717
  lanes?: boolean;
718
+ /**
719
+ * The transport this mix plays on, shared with other mixes, so they keep one clock and a query
720
+ * naming a score looks in all of them. The transport's `sync`, `rebase`, `rate`, `ramp` and
721
+ * `seek` move it, and the mix's own throw. Its history is the transport's, so the mix takes no
722
+ * `history` of its own.
723
+ */
724
+ transport?: Transport;
725
+ /** What `Marked.mix` and errors call this mix. */
726
+ name?: string;
727
+ }
728
+ /**
729
+ * What a mix or transport remembers, for `seek` and `project` to read back: see
730
+ * `MixOptions.history`.
731
+ *
732
+ * @category mix
733
+ */
734
+ export interface HistoryOptions {
735
+ /** How much stays in memory, ms of mix time. With a `store`, the rest is paged out, not dropped. */
736
+ ms: number;
737
+ every?: number;
738
+ inputs?: boolean;
739
+ tape?: TapeMaker;
740
+ /**
741
+ * Where history older than `ms` goes instead of being dropped. A `seek` or `project` reaching
742
+ * past memory needs `prepare` first, or throws `HistoryMiss`. With a store, blits never prunes
743
+ * the tape: the host bounds it.
744
+ */
745
+ store?: HistoryStore;
746
+ /** Rebuilds a cued voice's spec from the descriptor it was cued with, so the voice can be paged out. */
747
+ revive?(d: Described): VoiceSpec<any, any>;
748
+ }
749
+ /**
750
+ * A voice as plain data: `kind` names what built it, and `data` survives `structuredClone`.
751
+ *
752
+ * @category mix
753
+ */
754
+ export interface Described {
755
+ kind: string;
756
+ data: unknown;
757
+ }
758
+ /**
759
+ * Where a history `store` keeps what memory let go of. blits decides what is kept and when it is
760
+ * read back; the store decides where it lives.
761
+ *
762
+ * @category mix
763
+ */
764
+ export interface HistoryStore {
765
+ /** Records leaving memory. One brought back by a seek may be paged again: keep one per key and `at`. */
766
+ page(out: readonly Paged[]): void;
767
+ /**
768
+ * What a restore to mix time `t` needs, for every mix: from each stream, per voice and subject,
769
+ * the latest record at or before `t` and every record after it. Returning everything is fine.
770
+ */
771
+ load(t: number): Promise<readonly Paged[]>;
772
+ /** A seek went back to `t`: every record after it is from a future the tape makes again. Forget them. */
773
+ cut(t: number): void;
774
+ }
775
+ /**
776
+ * What a history record holds: a voice's `controls`, a stateful record's `snap`, an `input`
777
+ * signal's reading, a subject's record when it `left` a voice, a motion subject's `released` run
778
+ * or older `stretch`, the `host` fields patches read, or a whole `voice` that has left.
779
+ *
780
+ * @category mix
781
+ */
782
+ export type PagedStream = 'voice' | 'snap' | 'input' | 'left' | 'released' | 'stretch' | 'host' | 'controls';
783
+ /**
784
+ * One history record leaving memory, as plain data.
785
+ *
786
+ * @category mix
787
+ */
788
+ export interface Paged {
789
+ /** The mix's `name`; '' for a mix made alone without one. */
790
+ mix: string;
791
+ stream: PagedStream;
792
+ /** The voice's id, for every stream but `host`. */
793
+ voice?: number;
794
+ /** The subject's key, for a record of one subject. */
795
+ subject?: string | number;
796
+ /** Mix time. */
797
+ at: number;
798
+ data: unknown;
799
+ }
800
+ /**
801
+ * How a transport is made: what history it keeps for every mix on it.
802
+ *
803
+ * @category mix
804
+ */
805
+ export interface TransportOptions {
806
+ history?: MixOptions['history'];
807
+ }
808
+ /**
809
+ * Every mix on a transport read at another mix time, with nothing live moved: `of` gives one mix's
810
+ * reading. Valid until the transport is next synced or a mix on it cued.
811
+ *
812
+ * @category mix
813
+ */
814
+ export interface TransportProjection {
815
+ readonly timestamp: number;
816
+ of<I, O, H>(mix: Mix<I, O, H>): Projection<I, O>;
817
+ }
818
+ /**
819
+ * One clock several mixes play on, each over its own kit: one sync, one rate, one seek and one
820
+ * tape for all of them, and a score that spans them, so an anchor in one mix waits on a voice in
821
+ * another by naming the score they share. A query naming no score stays in its own mix.
822
+ *
823
+ * @category mix
824
+ */
825
+ export interface Transport {
826
+ /** The host reports the clock once a frame, after the frame's cues, as `Mix.sync` does. */
827
+ sync(timestamp: number): void;
828
+ /** As `Mix.rebase`, for every mix on it. */
829
+ rebase(): void;
830
+ /** As `Mix.rate`, multiplied into every voice of every mix on it. */
831
+ rate: number;
832
+ ramp(rate: number, over: number): void;
833
+ /**
834
+ * As `Mix.seek`, for every mix on it at once: back, each mix restores itself; forward, the one
835
+ * tape plays every mix's calls again in the order they were made, so an anchor across mixes
836
+ * answers as it did. A mix dropped after the moment sought is back on the transport.
837
+ */
838
+ seek(time: number): void;
839
+ /**
840
+ * Loads from the history `store` what `seek(time)` and `project(time)` will need, where that
841
+ * reaches past memory. Without a store, or within memory, it loads nothing.
842
+ */
843
+ prepare(time: number): Promise<void>;
844
+ readonly now: number;
845
+ readonly tape: Tape | undefined;
846
+ /** Puts a named mark on a score every mix on it sees. Throws without a `score`. */
847
+ announce(name: string, opts: {
848
+ at?: number;
849
+ score: string;
850
+ tags?: readonly string[];
851
+ }): void;
852
+ /** Every mark of every mix on it, and every mark announced on it, earliest first. */
853
+ marks(from: number, to: number): Marked[];
854
+ /** Every mix on it read at mix time `time`, together, so anchors across them answer. */
855
+ project(time: number): TransportProjection;
856
+ /** Any mix on it live. */
857
+ readonly live: boolean;
858
+ /** Every mix on it inert. */
859
+ readonly inert: boolean;
860
+ /** Calls `fn` when any mix on it needs frames again after a sync, once until the next sync. */
861
+ onWake(fn: () => void): () => void;
862
+ /**
863
+ * Takes a mix off: it is no longer synced and takes no more calls. With history, a seek back
864
+ * before the drop puts it back as it was then; without, it is let go.
865
+ */
866
+ drop<I, O, H>(mix: Mix<I, O, H>): void;
607
867
  }
868
+ /**
869
+ * One host call a mix recorded on its tape: `apply` makes it again, and `invert` does nothing,
870
+ * since a mix goes back by restoring what it kept rather than by undoing calls.
871
+ *
872
+ * @category mix
873
+ */
874
+ export interface TapeOp {
875
+ apply(adapter: unknown): void;
876
+ invert(): TapeOp;
877
+ label?: string;
878
+ }
879
+ /**
880
+ * One future a tape keeps at its current entry: the calls the host made after the mix last went
881
+ * back here, before it made new ones.
882
+ *
883
+ * @category mix
884
+ */
885
+ export interface TapeBranch {
886
+ /** Its first entry's id, which `switchBranch` takes. */
887
+ id: number;
888
+ label: string;
889
+ timestamp: number;
890
+ /** How many entries run along it from here. */
891
+ length: number;
892
+ /** Whether the mix plays it on from here. */
893
+ current: boolean;
894
+ }
895
+ /**
896
+ * Where a mix keeps the host's calls, by mix time, for `seek`. weasel-history's `History`
897
+ * (`@weasel-js/history`) has this shape. A host reads `branches` and calls `switchBranch` to pick
898
+ * which recorded future plays on; moving it any other way is the mix's job.
899
+ *
900
+ * @category mix
901
+ */
902
+ export interface Tape {
903
+ recordEntry(ops: TapeOp[], label: string): void;
904
+ undoDepth(): number;
905
+ timestampAt(i: number): number | undefined;
906
+ depthAt(t: number): number;
907
+ goto(n: number): void;
908
+ redo(): void;
909
+ prune(t: number): void;
910
+ branches(): readonly TapeBranch[];
911
+ switchBranch(id: number): void;
912
+ }
913
+ /**
914
+ * Makes a mix's tape: weasel-history's `createHistory` is one. The mix passes the clock it stamps
915
+ * calls with, branching on, so a call made after going back keeps the old future as a branch, and
916
+ * coalescing off.
917
+ *
918
+ * @category mix
919
+ */
920
+ export type TapeMaker = (adapter: unknown, opts: {
921
+ now: () => number;
922
+ branching: boolean;
923
+ coalesceWindowMs: number;
924
+ }) => Tape;
608
925
  /**
609
926
  * How sure a projection is of one channel: `exact` where only the clock and known changes drove
610
927
  * it; `stepped` where state was advanced across a gap in one go, which is as good as the patch's
@@ -621,7 +938,7 @@ export type Doubt = 'exact' | 'stepped' | 'held';
621
938
  * @category mix
622
939
  */
623
940
  export interface Projection<I, O> {
624
- /** The timestamp it reads at, on the host's clock. */
941
+ /** The mix time it reads at. */
625
942
  readonly timestamp: number;
626
943
  /** The merged pose for one subject at this projection's timestamp. */
627
944
  probe(subject: I, out?: O): O;
@@ -664,7 +981,20 @@ export interface Mix<I, O, H = unknown> {
664
981
  * nest. Throws for a `loop`: a pass would have to restart its children.
665
982
  */
666
983
  owns(spec: OwnerSpec<I, H>): Handle<I>;
667
- /** The host reports the clock, once a frame. Nothing advances at the call. */
984
+ /**
985
+ * Cues a span: an owner that lays out the voices it holds in `order` and fits them into its
986
+ * `duration`, again each time one joins or leaves early. A child's start and rate are the
987
+ * span's to set, so it takes neither `start` nor an anchored start; its `SpanHints` say how it
988
+ * may give way. A span with a budget stays until the budget has passed, though its children
989
+ * finish sooner, so late ones can still join, and its `end` mark is where its children end or
990
+ * its budget does, whichever is later. A voice that loops for good cannot join one.
991
+ */
992
+ span(spec: SpanSpec<I, H>): SpanHandle<I>;
993
+ /**
994
+ * The host reports the clock, once a frame. Nothing advances at the call. Throws for a timestamp
995
+ * earlier than the last sync's, short of a `rebase`: the host's clock only goes forward, and
996
+ * `seek` moves the mix.
997
+ */
668
998
  sync(timestamp: number): void;
669
999
  /**
670
1000
  * The time between the last sync and the next one is not to count: a host calls it when a
@@ -673,7 +1003,7 @@ export interface Mix<I, O, H = unknown> {
673
1003
  rebase(): void;
674
1004
  /**
675
1005
  * 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
1006
+ * whole mix. A negative rate throws: the mix plays only forward, and `seek` moves it back. Setting it changes speed at
677
1007
  * once; `ramp` eases into a new one. It scales mix time, which everything a voice owns runs on:
678
1008
  * its clock, its fades and a handle's ramp, `stagger`, an anchor's `by`, `stepMs`, `maxDt`,
679
1009
  * `history.ms`, every `dt`, and `setting.timestamp`. Timestamps on the host's clock name the same
@@ -707,11 +1037,47 @@ export interface Mix<I, O, H = unknown> {
707
1037
  */
708
1038
  pull(subjects: Iterable<I>, into: Columns<O>): void;
709
1039
  /**
710
- * Reads the mix at another timestamp, on the host's clock, without moving it. Ahead of the last
711
- * sync it plays what is cued forward; behind it, it needs `history`, and throws for a timestamp
712
- * older than the history reaches.
1040
+ * Reads the mix at another mix time, without moving it. Ahead of the mix it plays what is cued
1041
+ * forward, and throws for a time past a call the tape will play again after a `seek` back, which
1042
+ * only a seek there makes; behind it, it needs `history`, and throws for a time older than the
1043
+ * history reaches. On a transport it reads every mix on it together, so anchors across them
1044
+ * answer.
1045
+ */
1046
+ project(time: number): Projection<I, O>;
1047
+ /**
1048
+ * Moves the mix to mix time `time`, as it stood at the end of that frame, and plays on from
1049
+ * there. Needs `history` with a `tape`, which records the host's calls by mix time.
1050
+ *
1051
+ * Back, the mix restores itself: controls, records, voices and marks as they stood then. Voices
1052
+ * that left after it are back on the handles the host holds, their `done` and `played` starting
1053
+ * over where they had settled since. Voices cued after it wait as `pending` until the mix plays
1054
+ * their cue again. Stateful voices restart from the copy `history` kept nearest before it and
1055
+ * step once to it, exact under `stepMs`. A subject faded out of a voice or dropped after it comes
1056
+ * back with the record it had, a motion patch's state included. Recorded input and host fields
1057
+ * after it are let go: after a seek back, signals and host fields read live again, and `assess`
1058
+ * reports what they fed as `held`.
1059
+ *
1060
+ * Forward, through a sync or a later seek, the mix plays the recorded calls again at the mix
1061
+ * times they were made: cues, handle writes, fades, retargets and pushes, its rate, marks,
1062
+ * `mute` and `drop`. A call the host makes while there are recorded calls ahead starts a new
1063
+ * branch, and the tape keeps the old future beside it; `tape.switchBranch` picks one back.
1064
+ * Playing past a time again sends its events and books its marks and hits again.
1065
+ *
1066
+ * The host goes on passing its own clock: the next `sync` reads the moment sought plus the
1067
+ * host's time since its last sync. Throws for a time older than history reaches, and before
1068
+ * the first sync. With a history `store`, a time older than memory needs `prepare` first, or
1069
+ * throws `HistoryMiss` before anything moves.
1070
+ */
1071
+ seek(time: number): void;
1072
+ /** As `Transport.prepare`, for a mix made alone. */
1073
+ prepare(time: number): Promise<void>;
1074
+ /**
1075
+ * The mix clock at the last sync or seek, which `seek` and `project` take; NaN before the first
1076
+ * sync. Host time at the mix's rate, less what `rebase` took out and `seek` moved.
713
1077
  */
714
- project(timestamp: number): Projection<I, O>;
1078
+ readonly now: number;
1079
+ /** The tape `history.tape` made, undefined without one. */
1080
+ readonly tape: Tape | undefined;
715
1081
  /**
716
1082
  * Every channel at rest for this subject this frame, so a host can skip the write. After a probe
717
1083
  * of the subject this frame, it answers for the pose that probe gave, without folding again.
@@ -766,8 +1132,8 @@ export interface Mix<I, O, H = unknown> {
766
1132
  * Every event patches have sent since the last drain, earliest first, in the order they were sent
767
1133
  * where two share a timestamp. A subject's events are made while it catches up, which is when it is
768
1134
  * probed, so one nobody probes has sent nothing yet: promptness is the host's, by probing. A
769
- * stateless patch's `at` on a lane is the exception: it runs for every subject the mix has met, at
770
- * the frame's first probe. Under `stepMs` each carries the end of the interval it happened in, so
1135
+ * stateless patch's `at` on a lane is the exception: it runs at the frame's first probe for every
1136
+ * subject probed that frame or the last. Under `stepMs` each carries the end of the interval it happened in, so
771
1137
  * what is sent and when does not depend on how the host spaces its probes. Time `rebase` took out
772
1138
  * sends nothing. Given a tag, it takes only the events of voices carrying it and leaves the rest for
773
1139
  * whoever drains them.
@@ -0,0 +1,8 @@
1
+ import type { Transport } from './transport.js';
2
+ /**
3
+ * Makes memory reach mix time `t` for a seek or read there, from what `prepare` loaded; true where
4
+ * it took records from the store. Throws before anything moves where it cannot.
5
+ */
6
+ export declare function cover(transport: Transport, t: number): boolean;
7
+ /** A seek back to `t`: what the store and `prepare` hold after it is from a future the tape makes again. */
8
+ export declare function cut(transport: Transport, t: number, unpaged: boolean): void;