@msb235/blits 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/CHANGELOG.md +136 -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 +78 -27
  21. package/dist/due.js +3 -0
  22. package/dist/fade.d.ts +13 -0
  23. package/dist/fade.js +55 -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/handle.d.ts +27 -2
  33. package/dist/handle.js +60 -11
  34. package/dist/held.js +4 -0
  35. package/dist/history.d.ts +15 -2
  36. package/dist/history.js +54 -9
  37. package/dist/hosts.d.ts +2 -2
  38. package/dist/hosts.js +18 -5
  39. package/dist/index.d.ts +8 -2
  40. package/dist/index.js +5 -1
  41. package/dist/lane.d.ts +1 -1
  42. package/dist/lanes.d.ts +32 -9
  43. package/dist/lanes.js +53 -24
  44. package/dist/locus.d.ts +3 -3
  45. package/dist/locus.js +1 -1
  46. package/dist/marks.d.ts +3 -0
  47. package/dist/marks.js +80 -12
  48. package/dist/meet.d.ts +3 -2
  49. package/dist/meet.js +15 -3
  50. package/dist/mixer.d.ts +52 -36
  51. package/dist/mixer.js +148 -86
  52. package/dist/motion.d.ts +2 -199
  53. package/dist/motion.js +2 -652
  54. package/dist/motions.d.ts +266 -0
  55. package/dist/motions.js +724 -0
  56. package/dist/move.d.ts +1 -1
  57. package/dist/move.js +23 -7
  58. package/dist/owner.d.ts +1 -1
  59. package/dist/owner.js +3 -3
  60. package/dist/pace.d.ts +2 -0
  61. package/dist/pace.js +8 -0
  62. package/dist/pack.d.ts +31 -0
  63. package/dist/pack.js +65 -0
  64. package/dist/paging.d.ts +63 -0
  65. package/dist/paging.js +110 -0
  66. package/dist/patch.d.ts +3 -0
  67. package/dist/patch.js +2 -0
  68. package/dist/place.js +74 -25
  69. package/dist/project.d.ts +7 -4
  70. package/dist/project.js +117 -78
  71. package/dist/pull.js +4 -3
  72. package/dist/qualify.js +4 -2
  73. package/dist/revive.d.ts +58 -0
  74. package/dist/revive.js +158 -0
  75. package/dist/sample.d.ts +1 -1
  76. package/dist/sample.js +6 -1
  77. package/dist/seek.d.ts +3 -0
  78. package/dist/seek.js +311 -0
  79. package/dist/spans.d.ts +29 -0
  80. package/dist/spans.js +165 -0
  81. package/dist/strays.d.ts +1 -1
  82. package/dist/strays.js +21 -0
  83. package/dist/tape.d.ts +21 -0
  84. package/dist/tape.js +65 -0
  85. package/dist/ticker.d.ts +28 -3
  86. package/dist/ticker.js +3 -0
  87. package/dist/transport.d.ts +121 -0
  88. package/dist/transport.js +271 -0
  89. package/dist/types.d.ts +404 -38
  90. package/dist/unpage.d.ts +8 -0
  91. package/dist/unpage.js +163 -0
  92. package/dist/voice.d.ts +73 -7
  93. package/dist/voice.js +116 -4
  94. package/dist/weigh.js +2 -2
  95. package/docs/schema.html +120 -31
  96. package/package.json +2 -1
package/dist/lanes.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { row } from './crowd.js';
2
2
  import { call, fillAll, foldKeys, one, parting, readKeyed, reset, run, signalled, subjectAt, } from './fill.js';
3
- import { fold, foldDelta, foldInto, foldRun, gather } from './gather.js';
4
- import { meet, owable, reach } from './meet.js';
3
+ import { fold, foldDelta, foldInto, foldRun, gate, gather } from './gather.js';
4
+ import { meet, reach } from './meet.js';
5
5
  import { Numbers } from './numbers.js';
6
6
  import { Owed } from './owed.js';
7
7
  import { requalify, retouch } from './qualify.js';
@@ -26,6 +26,9 @@ export class Lanes {
26
26
  overlap = false;
27
27
  /** The loci whose voices are on lanes, every member of each on one. */
28
28
  loci = [];
29
+ /** The lane and record `one` is folding, whose band state a rest-less channel reads. */
30
+ folding = null;
31
+ rec = null;
29
32
  /** While a fill gathers a locus: that locus and the member gathering, where folds go instead. */
30
33
  into = null;
31
34
  intoId = 0;
@@ -52,14 +55,17 @@ export class Lanes {
52
55
  /** The highest voice id the last qualify or settling of `touched` considered. */
53
56
  known = 0;
54
57
  /**
55
- * Per subject number, `SLOT` numbers side by side, so a probe reads one place in memory: which
56
- * fill last wrote it (0 for none); the latest lane epoch a probe of it has checked it against;
57
- * how many idle lanes reach it, since a probe reads lanes only where none do; and the probe count
58
- * at its last probe read from the lanes and at its last probe folded by the general path, with
59
- * the fill the former read, which say whether a lane or a record holds what `weightOf` reports.
58
+ * Per subject number, `SLOT` numbers side by side, so a probe reads one place in memory: the
59
+ * fill that last left it to the general path, being late, owing, newly numbered or forgotten;
60
+ * the latest lane epoch a probe of it has checked it against; how many idle lanes reach it,
61
+ * since a probe reads lanes only where none do; and the probe count at its last probe read from
62
+ * the lanes and at its last probe folded by the general path, with the fill the former read,
63
+ * which say whether a lane or a record holds what `weightOf` reports.
60
64
  */
61
65
  per = new Float64Array(0);
62
66
  fills = 0;
67
+ /** The latest fill if it ran a lane, else 0: a subject whose `FILLED` is below it reads it. */
68
+ busyFill = 0;
63
69
  probes = 0;
64
70
  /**
65
71
  * Each subject by number as last probed, held from that probe until the next fill uses it, so a
@@ -104,6 +110,11 @@ export class Lanes {
104
110
  lastDistinct = 0;
105
111
  /** Numbered subjects alive. */
106
112
  live = 0;
113
+ /**
114
+ * The probe count a subject's last probe must pass for this fill to fill it: the start of the
115
+ * last frame with a probe, or -1 while every subject alive was probed then, when it fills all.
116
+ */
117
+ lately = -1;
107
118
  filledVersion = Number.NaN;
108
119
  qualifiedVersion = Number.NaN;
109
120
  constructor(host) {
@@ -132,7 +143,7 @@ export class Lanes {
132
143
  const slot = this.numbers.take(subject);
133
144
  this.live++;
134
145
  this.grow(slot + 1);
135
- this.per[slot * 6 /* Per.SLOT */ + 0 /* Per.FILLED */] = 0;
146
+ this.per[slot * 6 /* Per.SLOT */ + 0 /* Per.FILLED */] = this.fills;
136
147
  this.per[slot * 6 /* Per.SLOT */ + 1 /* Per.SEEN */] = -1;
137
148
  this.per[slot * 6 /* Per.SLOT */ + 2 /* Per.IDLE */] = 0;
138
149
  this.per[slot * 6 /* Per.SLOT */ + 3 /* Per.LANE_PROBE */] = 0;
@@ -195,9 +206,10 @@ export class Lanes {
195
206
  * them. One that a lane has not met yet, newly numbered or newly reached, takes the general path
196
207
  * this frame, which is where it is first seen; so does one probed from inside a fill.
197
208
  */
198
- prepare(slot, subject, now, version, head) {
199
- const ready = this.filled(now, version) ? 1 /* Begin.READY */ : this.begin(now, version);
200
- if (ready === 0 /* Begin.GENERAL */)
209
+ prepare(slot, subject, version, head) {
210
+ // Read, not passed: a double passed to a call V8 does not inline is boxed, once a probe.
211
+ const now = this.host.clock.now;
212
+ if (!this.filled(now, version) && this.begin(now, version) === 0 /* Begin.GENERAL */)
201
213
  return this.general(slot);
202
214
  if (slot < 0)
203
215
  return false;
@@ -206,18 +218,9 @@ export class Lanes {
206
218
  const probe = ++this.probes;
207
219
  const per = this.per;
208
220
  const o = slot * 6 /* Per.SLOT */;
209
- let lane = per[o + 0 /* Per.FILLED */] === this.fills && per[o + 2 /* Per.IDLE */] === 0;
210
- if (per[o + 1 /* Per.SEEN */] < this.wide && meet(this, slot, subject, head)) {
211
- // The fill ran before the subject had these positions. Where every voice it just met folds
212
- // after every other laned voice, the general path folds just those onto the lanes' values;
213
- // otherwise it reads the general path all frame.
214
- if (lane && per[o + 2 /* Per.IDLE */] === 0 && owable(this, slot))
215
- this.owed.owe(slot, this.met);
216
- else {
217
- per[o + 0 /* Per.FILLED */] = 0;
218
- lane = false;
219
- }
220
- }
221
+ let lane = per[o + 0 /* Per.FILLED */] < this.busyFill && per[o + 2 /* Per.IDLE */] === 0;
222
+ if (per[o + 1 /* Per.SEEN */] < this.wide)
223
+ lane = meet(this, slot, subject, head, lane);
221
224
  if (lane) {
222
225
  per[o + 3 /* Per.LANE_PROBE */] = probe;
223
226
  per[o + 5 /* Per.LANE_FILL */] = this.fills;
@@ -283,6 +286,20 @@ export class Lanes {
283
286
  this.per[slot * 6 /* Per.SLOT */ + 4 /* Per.GENERAL_PROBE */] = ++this.probes;
284
287
  return false;
285
288
  }
289
+ /**
290
+ * Whether this fill leaves the subject at `slot` to the general path, for not having been probed
291
+ * this frame or the last: a probe of it before the next fill then takes the general path.
292
+ */
293
+ unread(slot) {
294
+ const per = this.per;
295
+ const o = slot * 6 /* Per.SLOT */;
296
+ const lately = this.lately;
297
+ if (per[o + 3 /* Per.LANE_PROBE */] > lately ||
298
+ per[o + 4 /* Per.GENERAL_PROBE */] > lately)
299
+ return false;
300
+ per[o + 0 /* Per.FILLED */] = this.fills;
301
+ return true;
302
+ }
286
303
  /** Whether a probe has read the subject since the frame began, on either path. */
287
304
  probedThisFrame(slot) {
288
305
  const from = this.frameProbes;
@@ -312,6 +329,11 @@ export class Lanes {
312
329
  rests(slot) {
313
330
  for (const ch of this.laned) {
314
331
  const values = ch.values;
332
+ if (ch.op === 'last') {
333
+ if (!Number.isNaN(values[slot * ch.axes]))
334
+ return false;
335
+ continue;
336
+ }
315
337
  if (ch.scalar) {
316
338
  if (!(Math.abs(values[slot] - ch.rest) < 1e-9))
317
339
  return false;
@@ -333,6 +355,12 @@ export class Lanes {
333
355
  for (let c = 0; c < laned.length; c++) {
334
356
  const ch = laned[c];
335
357
  const axes = ch.axes;
358
+ // Never `delete`: it drops a reused out object into dictionary mode for good.
359
+ if (ch.op === 'last' && Number.isNaN(ch.values[slot * axes])) {
360
+ if (pose[ch.name] !== undefined)
361
+ pose[ch.name] = undefined;
362
+ continue;
363
+ }
336
364
  if (ch.scalar) {
337
365
  pose[ch.name] = ch.values[slot];
338
366
  continue;
@@ -355,7 +383,7 @@ export class Lanes {
355
383
  if (c.list[p] === slot)
356
384
  unplace(this, c, p);
357
385
  if (slot < this.cap)
358
- this.per[slot * 6 /* Per.SLOT */ + 0 /* Per.FILLED */] = 0;
386
+ this.per[slot * 6 /* Per.SLOT */ + 0 /* Per.FILLED */] = this.fills;
359
387
  this.subjects[slot] = undefined;
360
388
  }
361
389
  grow(size) {
@@ -417,6 +445,7 @@ const methods = {
417
445
  foldDelta,
418
446
  foldRun,
419
447
  foldInto,
448
+ gate,
420
449
  };
421
450
  for (const [name, value] of Object.entries(methods))
422
451
  Object.defineProperty(Lanes.prototype, name, { value, writable: true, configurable: true });
package/dist/locus.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { Mixer } from './mixer.js';
2
2
  import type { Subject, Voice } from './voice.js';
3
3
  /**
4
- * What a fold with a locus in play gathers, kept from one fold to the next: the influences in
4
+ * What a fold with a locus in play gathers, kept from one fold to the next: the contributions in
5
5
  * voice order, each a voice's own or a locus's first member; every locus member; and per channel
6
6
  * slot, a locus's folding value, the weight taken into it and the array it owns.
7
7
  */
@@ -11,7 +11,7 @@ export interface LocusScratch<I, O> {
11
11
  helds: (Subject<unknown> | null)[];
12
12
  deltas: (Record<string, unknown> | null)[];
13
13
  weights: number[];
14
- /** Per influence, -1 for a voice's own, or which of `names` it is. */
14
+ /** Per contribution, -1 for a voice's own, or which of `names` it is. */
15
15
  groups: number[];
16
16
  names: string[];
17
17
  m: number;
@@ -32,7 +32,7 @@ export declare function locusScratch<I, O>(channels: number): LocusScratch<I, O>
32
32
  */
33
33
  export declare function own<I, O>(k: LocusScratch<I, O>, slot: number, value: number[], rest: number[]): number[];
34
34
  /**
35
- * Folds one locus's members into one influence through each channel's own `lerp`: its value per
35
+ * Folds one locus's members into one contribution through each channel's own `lerp`: its value per
36
36
  * channel goes in `k.values`, the channels in `k.touched` in the order first met, and its weight
37
37
  * is returned. A channel folding by scale takes its value in an array of `k`'s own, lerped in
38
38
  * place, since the fold only reads it.
package/dist/locus.js CHANGED
@@ -35,7 +35,7 @@ export function own(k, slot, value, rest) {
35
35
  return out;
36
36
  }
37
37
  /**
38
- * Folds one locus's members into one influence through each channel's own `lerp`: its value per
38
+ * Folds one locus's members into one contribution through each channel's own `lerp`: its value per
39
39
  * channel goes in `k.values`, the channels in `k.touched` in the order first met, and its weight
40
40
  * is returned. A channel folding by scale takes its value in an array of `k`'s own, lerped in
41
41
  * place, since the fold only reads it.
package/dist/marks.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { Listed } from './book.js';
2
2
  import type { Mixer } from './mixer.js';
3
+ import type { Transport } from './transport.js';
3
4
  import type { Mark } from './types.js';
4
5
  import { type Voice } from './voice.js';
5
6
  /** The host timestamp the mix clock reads mix time `t` at; Infinity where it never will. */
@@ -8,5 +9,7 @@ export declare function hostOf<I, O>(mix: Mixer<I, O>, t: number): number;
8
9
  export declare function readingAt<I, O>(mix: Mixer<I, O>, u: number): number;
9
10
  /** Every mark between two host timestamps, earliest first, with the order that tells each apart. */
10
11
  export declare function listed<I, O>(mix: Mixer<I, O>, from: number, to: number): Listed[];
12
+ /** Every mark of every mix on a transport and every one announced on it, earliest first. */
13
+ export declare function listedAll(transport: Transport, from: number, to: number): Listed[];
11
14
  /** When a voice reaches a mark, mix time, or undefined while nothing has fixed it. */
12
15
  export declare function markOf<I, O>(mix: Mixer<I, O>, voice: Voice<I, O>, mark: Mark): number | undefined;
package/dist/marks.js CHANGED
@@ -10,22 +10,52 @@ export function readingAt(mix, u) {
10
10
  }
11
11
  /** Every mark between two host timestamps, earliest first, with the order that tells each apart. */
12
12
  export function listed(mix, from, to) {
13
- const lo = from - mix.offset;
14
- const hi = to - mix.offset;
13
+ const out = voiceMarks(mix, from, to);
14
+ for (const a of announcedMarks(mix.transport, from, to))
15
+ if (a.score !== undefined || a.slot === mix.slot)
16
+ out.push(a.listed);
17
+ return sorted(out);
18
+ }
19
+ /** Every mark of every mix on a transport and every one announced on it, earliest first. */
20
+ export function listedAll(transport, from, to) {
21
+ const out = [];
22
+ for (const m of transport.members)
23
+ out.push(...voiceMarks(m, from, to));
24
+ for (const a of announcedMarks(transport, from, to))
25
+ out.push(a.listed);
26
+ return sorted(out);
27
+ }
28
+ function sorted(out) {
29
+ return out.sort((a, b) => a.timestamp - b.timestamp || a.order - b.order);
30
+ }
31
+ function announcedMarks(transport, from, to) {
32
+ const lo = from - transport.offset;
33
+ const hi = to - transport.offset;
15
34
  const out = [];
16
- for (const a of mix.announced)
35
+ for (const a of transport.announced)
17
36
  if (a.at >= lo && a.at <= hi)
18
37
  out.push({
19
- timestamp: a.at + mix.offset,
20
- mark: undefined,
21
- voice: undefined,
22
38
  score: a.score,
23
- name: a.name,
24
- tags: a.tags,
25
- order: a.order,
39
+ slot: a.slot,
40
+ listed: {
41
+ timestamp: a.at + transport.offset,
42
+ mark: undefined,
43
+ voice: undefined,
44
+ score: a.score,
45
+ name: a.name,
46
+ tags: a.tags,
47
+ mix: a.mix,
48
+ order: a.order,
49
+ },
26
50
  });
51
+ return out;
52
+ }
53
+ function voiceMarks(mix, from, to) {
54
+ const lo = from - mix.offset;
55
+ const hi = to - mix.offset;
56
+ const out = [];
27
57
  for (const voice of [...mix.cued, ...mix.gone]) {
28
- for (const mark of ['start', 'in', 'out', 'end']) {
58
+ for (const mark of ['start', 'in', 'coast', 'out', 'end']) {
29
59
  const m = markOf(mix, voice, mark);
30
60
  const t = m === undefined ? m : hostOf(mix, m) - mix.offset;
31
61
  if (t === undefined || t < lo || t > hi)
@@ -37,11 +67,11 @@ export function listed(mix, from, to) {
37
67
  score: voice.spec.score,
38
68
  name: voice.spec.name,
39
69
  tags: voice.spec.tags ?? none,
70
+ mix: mix.name,
40
71
  order: voice.id,
41
72
  });
42
73
  }
43
74
  }
44
- out.sort((a, b) => a.timestamp - b.timestamp || a.order - b.order);
45
75
  return out;
46
76
  }
47
77
  /** When a voice reaches a mark, mix time, or undefined while nothing has fixed it. */
@@ -56,12 +86,19 @@ export function markOf(mix, voice, mark) {
56
86
  return start;
57
87
  if (mark === 'in')
58
88
  return start + (voice.fade.in ?? 0);
89
+ if (mark === 'coast')
90
+ return coastOf(mix, voice, start);
59
91
  const out = voice.out;
60
92
  let outAt;
61
93
  if (out !== null)
62
94
  outAt = out.at;
63
95
  else if (Number.isFinite(voice.outAt))
64
96
  outAt = voice.outAt;
97
+ else if (voice.fitting !== null) {
98
+ const t = voice.timeAt(voice.fitting.end);
99
+ if (Number.isFinite(t))
100
+ outAt = Math.max(start, t);
101
+ }
65
102
  else if (!voice.freezesAfter && Number.isFinite(voice.span)) {
66
103
  const t = voice.timeAt(voice.span + voice.latest);
67
104
  if (Number.isFinite(t))
@@ -76,5 +113,36 @@ export function markOf(mix, voice, mark) {
76
113
  return out.deadline === undefined ? undefined : out.at + out.deadline;
77
114
  return out.at + out.over;
78
115
  }
79
- return outAt === undefined ? undefined : outAt + (mix.reduced ? 0 : (voice.fade.out ?? 0));
116
+ const over = Number.isNaN(voice.outOver) ? (voice.fade.out ?? 0) : voice.outOver;
117
+ return outAt === undefined ? undefined : outAt + (mix.reduced ? 0 : over);
118
+ }
119
+ /**
120
+ * When a voice's last pass ends, mix time: an owner's when its fit ends, or its last child's. None
121
+ * for a voice that never ends its passes, or that leaves or begins to fade before they end.
122
+ */
123
+ function coastOf(mix, voice, start) {
124
+ if (voice.unplayed)
125
+ return undefined;
126
+ let t;
127
+ if (voice.fitting !== null)
128
+ t = voice.timeAt(voice.fitting.end);
129
+ else if (voice.holding !== null) {
130
+ const children = voice.holding.children;
131
+ if (children.length === 0)
132
+ return undefined;
133
+ t = Number.NEGATIVE_INFINITY;
134
+ for (const child of children) {
135
+ const c = markOf(mix, child, 'coast');
136
+ if (c === undefined)
137
+ return undefined;
138
+ t = Math.max(t, c);
139
+ }
140
+ }
141
+ else if (Number.isFinite(voice.span))
142
+ t = voice.timeAt(voice.span + voice.latest);
143
+ if (t === undefined || !Number.isFinite(t))
144
+ return undefined;
145
+ t = Math.max(start, t);
146
+ const cut = voice.out !== null ? voice.out.at : voice.state === 'done' ? voice.doneAt : voice.outAt;
147
+ return cut < t ? undefined : t;
80
148
  }
package/dist/meet.d.ts CHANGED
@@ -9,8 +9,9 @@ import type { Subject } from './voice.js';
9
9
  export declare function owable<I, O>(lanes: Lanes<I, O>, slot: number): boolean;
10
10
  /**
11
11
  * Gives a probed subject a position on every lane that started playing since the subject was last
12
- * checked and that reaches it. True when any did, so the probe takes the general path.
12
+ * checked and that reaches it, and says whether the probe still reads the lanes, given `lane`,
13
+ * whether it would have. Kept out of `prepare`, which V8 then inlines into its callers.
13
14
  */
14
- export declare function meet<I, O>(lanes: Lanes<I, O>, slot: number, subject: I, head: Subject<unknown> | null): boolean;
15
+ export declare function meet<I, O>(lanes: Lanes<I, O>, slot: number, subject: I, head: Subject<unknown> | null, lane: boolean): boolean;
15
16
  /** Counts an idle lane more or fewer reaching a subject. */
16
17
  export declare function reach<I, O>(lanes: Lanes<I, O>, slot: number, by: number): void;
package/dist/meet.js CHANGED
@@ -27,9 +27,10 @@ export function owable(lanes, slot) {
27
27
  }
28
28
  /**
29
29
  * Gives a probed subject a position on every lane that started playing since the subject was last
30
- * checked and that reaches it. True when any did, so the probe takes the general path.
30
+ * checked and that reaches it, and says whether the probe still reads the lanes, given `lane`,
31
+ * whether it would have. Kept out of `prepare`, which V8 then inlines into its callers.
31
32
  */
32
- export function meet(lanes, slot, subject, head) {
33
+ export function meet(lanes, slot, subject, head, lane) {
33
34
  const seen = lanes.per[slot * 6 /* Per.SLOT */ + 1 /* Per.SEEN */];
34
35
  const from = seen < 0 ? -1 - seen : seen;
35
36
  lanes.per[slot * 6 /* Per.SLOT */ + 1 /* Per.SEEN */] = lanes.epochs;
@@ -75,7 +76,18 @@ export function meet(lanes, slot, subject, head) {
75
76
  lanes.met.push(voice.id);
76
77
  met = true;
77
78
  }
78
- return met;
79
+ if (!met)
80
+ return lane;
81
+ // The fill ran before the subject had these positions. Where every voice it just met folds
82
+ // after every other laned voice, the general path folds just those onto the lanes' values;
83
+ // otherwise it reads the general path all frame.
84
+ const o = slot * 6 /* Per.SLOT */;
85
+ if (lane && lanes.per[o + 2 /* Per.IDLE */] === 0 && owable(lanes, slot)) {
86
+ lanes.owed.owe(slot, lanes.met);
87
+ return true;
88
+ }
89
+ lanes.per[o + 0 /* Per.FILLED */] = lanes.fills;
90
+ return false;
79
91
  }
80
92
  /** Places a crowd voice's row on the subject a probe met, as `Lane.add` adds a position. */
81
93
  function place(lanes, voice, slot, subject, from, head) {
package/dist/mixer.d.ts CHANGED
@@ -1,20 +1,24 @@
1
1
  import { blended, laneRead, shareKept } from './blend.js';
2
2
  import type { Book } from './book.js';
3
- import { aims, chain, linkable } from './chain.js';
3
+ import { aims, chain, linkable, relink } from './chain.js';
4
4
  import { type LerpInto } from './channels.js';
5
5
  import type { Due } from './due.js';
6
6
  import { parting } from './fade.js';
7
- import { apply, baseFor, clamp, fold, folded, foldLoci, foldWith, influence, isRest, type Key, keyed, linked, owedBy, passes, read, slopeFor, tick } from './fold.js';
7
+ import { apply, baseFor, clamp, contribution, fold, folded, foldLoci, foldWith, isRest, type Key, keyed, linked, owedBy, passes, read, slopeFor, tick } from './fold.js';
8
8
  import type { HandleHost } from './handle.js';
9
9
  import { held, shownOf, sinceOf, unreachedOf } from './held.js';
10
10
  import { Lanes } from './lanes.js';
11
11
  import { foldLocus, type LocusScratch } from './locus.js';
12
- import type { MotionOwner, Motions } from './motion.js';
13
- import { Pace } from './pace.js';
12
+ import type { MotionOwner, Motions } from './motions.js';
13
+ import type { Pace } from './pace.js';
14
+ import { Keys } from './paging.js';
14
15
  import { keep } from './pull.js';
15
16
  import { Steps } from './relink.js';
17
+ import { Outs } from './revive.js';
18
+ import { Fitting } from './spans.js';
16
19
  import { Store } from './store.js';
17
- import type { Booker, BookOptions, Channel, Columns, Engine, Handle, Kit, Marked, Mix, MixOptions, OwnerSpec, Patch, Projection, Sent, Signal, VoiceSpec } from './types.js';
20
+ import { type Announced, Transport } from './transport.js';
21
+ import type { Booker, BookOptions, Channel, Columns, Engine, Handle, Kit, Marked, Mix, MixOptions, OwnerSpec, Patch, Projection, Sent, Signal, SpanHandle, SpanSpec, Tape, VoiceSpec } from './types.js';
18
22
  import { type Subject, type Voice } from './voice.js';
19
23
  import { base, capped, fadeOf, horizonFor, ownedBy, ownerBase, prime, weigh, weighOwned } from './weigh.js';
20
24
  export declare class Mixer<I, O> implements Mix<I, O> {
@@ -37,19 +41,6 @@ export declare class Mixer<I, O> implements Mix<I, O> {
37
41
  at: number;
38
42
  fields: Record<string, unknown>;
39
43
  }[];
40
- /**
41
- * Marks the host announced on a score: `at` in host time, so the mix's rate never moves one, and
42
- * NaN until the next sync for one announced as now before any sync; `made` is the mix time it was
43
- * announced, for a read back to know what was known.
44
- */
45
- announced: {
46
- name: string;
47
- score: string | undefined;
48
- tags: readonly string[];
49
- at: number;
50
- made: number;
51
- order: number;
52
- }[];
53
44
  hostThen: {
54
45
  fields: Record<string, unknown>;
55
46
  } | undefined;
@@ -60,22 +51,17 @@ export declare class Mixer<I, O> implements Mix<I, O> {
60
51
  prev: O | undefined;
61
52
  prevAt: number;
62
53
  }>;
63
- nextId: number;
64
- /**
65
- * The mix clock: host time at the mix's rate. Host time is the host's timestamp less every gap
66
- * `rebase` has taken out, `u` at the last sync.
67
- */
68
- now: number;
69
- u: number;
54
+ /** The clock this mix plays on, which also holds its tape and the marks announced on it. */
55
+ readonly transport: Transport;
56
+ /** Its place among the mixes on its transport, in the order they joined. */
57
+ slot: number;
58
+ /** Taken off its transport, so it takes no more calls until a seek puts it back. */
59
+ dropped: boolean;
60
+ readonly name: string | undefined;
70
61
  /** This mix's frame among every mix's: moved by a sync, and by a control change or drop within one. */
71
62
  frame: number;
72
- offset: number;
73
- /** The mix's own rate; null while it has never been set, when mix time is host time. */
74
- pace: Pace | null;
75
63
  /** Pending voices whose start the host gave, by its host time, kept where the rate puts it. */
76
64
  pins: Map<Voice<I, O>, number> | null;
77
- last: number;
78
- rebasing: boolean;
79
65
  wantsPose: boolean;
80
66
  /** The pose `pull` folds a subject into where it cannot read straight from the lanes. */
81
67
  scratch: O | undefined;
@@ -110,7 +96,7 @@ export declare class Mixer<I, O> implements Mix<I, O> {
110
96
  * where none does. Relinked when `version` moves, which is whenever the list or a voice's pending
111
97
  * state changes.
112
98
  */
113
- readonly chains: Store<I, Subject<unknown>>;
99
+ chains: Store<I, Subject<unknown>>;
114
100
  version: number;
115
101
  readonly steps: Steps<Voice<I, O>>;
116
102
  /** Per subject, the voices whose `subjects` name it, in voice order. */
@@ -143,7 +129,9 @@ export declare class Mixer<I, O> implements Mix<I, O> {
143
129
  subject: I;
144
130
  };
145
131
  readonly send: (event: unknown) => void;
146
- /** The weight `influence` found besides the delta, read by the caller at once. */
132
+ /** The moment a seek went back to: what is stepped again up to it was sent the first time. */
133
+ sentTo: number;
134
+ /** The weight `contribution` found besides the delta, read by the caller at once. */
147
135
  w: number;
148
136
  readonly names: Key<O>[];
149
137
  readonly channels: Channel<unknown>[];
@@ -155,13 +143,36 @@ export declare class Mixer<I, O> implements Mix<I, O> {
155
143
  readonly locusScratch: LocusScratch<I, O>[];
156
144
  locusDepth: number;
157
145
  readonly slotOf: Map<string, number>;
158
- readonly lanes: Lanes<I, O> | null;
146
+ lanes: Lanes<I, O> | null;
159
147
  handles: HandleHost<I, O> | null;
160
148
  /** What `book` made, still booking; null while there is none. */
161
149
  bookers: Book<I, O>[] | null;
150
+ /** The fit a span being cued takes, which `cue` hands its voice. */
151
+ fitting: Fitting | null;
162
152
  /** Every owner still in the mix, null until one is cued. */
163
153
  owners: Voice<I, O>[] | null;
154
+ /** With a history store, the key each subject is paged under; null without one. */
155
+ keys: Keys | null;
156
+ /** With a history store, the voices it paged out whose handles are still held; null without one. */
157
+ outs: Outs | null;
164
158
  constructor(kit: Kit<O>, opts: MixOptions);
159
+ /** Throws where the clock is a shared transport's, which only the transport moves. */
160
+ private own;
161
+ get now(): number;
162
+ set now(v: number);
163
+ get u(): number;
164
+ set u(v: number);
165
+ get offset(): number;
166
+ set offset(v: number);
167
+ get pace(): Pace | null;
168
+ set pace(v: Pace | null);
169
+ get announced(): Announced[];
170
+ set announced(v: Announced[]);
171
+ get nextId(): number;
172
+ set nextId(v: number);
173
+ get last(): number;
174
+ get tape(): Tape | undefined;
175
+ get replaying(): boolean;
165
176
  get reduced(): boolean;
166
177
  get band(): {
167
178
  on: number;
@@ -170,17 +181,21 @@ export declare class Mixer<I, O> implements Mix<I, O> {
170
181
  cue(spec: VoiceSpec<I, O>): Handle<I>;
171
182
  blend(patches: readonly Patch<I, O, unknown>[], by: Signal<I>, spec?: Omit<VoiceSpec<I, O>, 'patch' | 'weight' | 'locus'>): Handle<I>[];
172
183
  owns(spec: OwnerSpec<I>): Handle<I>;
184
+ span(spec: SpanSpec<I>): SpanHandle<I>;
173
185
  sync(timestamp: number): void;
174
- private syncAt;
175
186
  book(opts: BookOptions): Booker;
176
187
  probe(subject: I, out?: O): O;
177
188
  pull(subjects: Iterable<I>, into: Columns<O>): void;
178
- project(timestamp: number): Projection<I, O>;
189
+ seek(time: number): void;
190
+ prepare(time: number): Promise<void>;
191
+ project(time: number): Projection<I, O>;
179
192
  announce(name: string, opts?: {
180
193
  at?: number;
181
194
  score?: string;
182
195
  tags?: readonly string[];
183
196
  }): void;
197
+ /** Throws for a mix taken off its transport. */
198
+ attached(): void;
184
199
  marks(from: number, to: number): Marked[];
185
200
  atRest(subject: I): boolean;
186
201
  rests(pose: O): boolean;
@@ -225,7 +240,7 @@ declare const methods: {
225
240
  owedBy: typeof owedBy;
226
241
  foldLoci: typeof foldLoci;
227
242
  read: typeof read;
228
- influence: typeof influence;
243
+ contribution: typeof contribution;
229
244
  keyed: typeof keyed;
230
245
  tick: typeof tick;
231
246
  apply: typeof apply;
@@ -248,6 +263,7 @@ declare const methods: {
248
263
  shareKept: typeof shareKept;
249
264
  parting: typeof parting;
250
265
  chain: typeof chain;
266
+ relink: typeof relink;
251
267
  linkable: typeof linkable;
252
268
  aims: typeof aims;
253
269
  held: typeof held;