@msb235/blits 0.7.1 → 0.8.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 (156) hide show
  1. package/CHANGELOG.md +193 -0
  2. package/README.md +22 -4
  3. package/dist/book.js +4 -4
  4. package/dist/chain.d.ts +1 -1
  5. package/dist/chain.js +57 -54
  6. package/dist/channels.d.ts +26 -5
  7. package/dist/channels.js +12 -8
  8. package/dist/clock.d.ts +8 -1
  9. package/dist/clock.js +14 -3
  10. package/dist/clone.d.ts +8 -0
  11. package/dist/clone.js +22 -0
  12. package/dist/closed.d.ts +1 -1
  13. package/dist/closed.js +3 -2
  14. package/dist/color.d.ts +0 -11
  15. package/dist/color.js +4 -24
  16. package/dist/columns.js +0 -1
  17. package/dist/copyout.d.ts +6 -0
  18. package/dist/copyout.js +38 -0
  19. package/dist/crowd.d.ts +7 -5
  20. package/dist/crowd.js +32 -18
  21. package/dist/cue.d.ts +3 -1
  22. package/dist/cue.js +31 -20
  23. package/dist/departed.d.ts +34 -0
  24. package/dist/departed.js +73 -0
  25. package/dist/easing.d.ts +5 -0
  26. package/dist/easing.js +31 -2
  27. package/dist/everyone.d.ts +56 -0
  28. package/dist/everyone.js +221 -0
  29. package/dist/fade.d.ts +8 -1
  30. package/dist/fade.js +34 -6
  31. package/dist/fill.d.ts +22 -13
  32. package/dist/fill.js +104 -41
  33. package/dist/fit.js +2 -1
  34. package/dist/fold.d.ts +37 -0
  35. package/dist/fold.js +216 -31
  36. package/dist/frames.d.ts +21 -0
  37. package/dist/frames.js +59 -0
  38. package/dist/gather.d.ts +15 -9
  39. package/dist/gather.js +60 -25
  40. package/dist/gone.js +10 -0
  41. package/dist/handle.d.ts +16 -5
  42. package/dist/handle.js +56 -6
  43. package/dist/held.d.ts +8 -5
  44. package/dist/held.js +56 -58
  45. package/dist/history.d.ts +17 -13
  46. package/dist/history.js +47 -28
  47. package/dist/hosts.js +55 -8
  48. package/dist/index.d.ts +9 -4
  49. package/dist/index.js +5 -2
  50. package/dist/keyfill.d.ts +7 -0
  51. package/dist/keyfill.js +124 -0
  52. package/dist/keyrows.d.ts +1 -0
  53. package/dist/keyrows.js +1 -1
  54. package/dist/lane.d.ts +32 -2
  55. package/dist/lane.js +5 -0
  56. package/dist/lanes.d.ts +32 -8
  57. package/dist/lanes.js +69 -37
  58. package/dist/leavings.d.ts +26 -0
  59. package/dist/leavings.js +70 -0
  60. package/dist/locus.js +2 -2
  61. package/dist/meet.js +14 -8
  62. package/dist/mixer.d.ts +39 -7
  63. package/dist/mixer.js +50 -10
  64. package/dist/motion.d.ts +2 -0
  65. package/dist/motion.js +4 -1
  66. package/dist/motions.d.ts +22 -15
  67. package/dist/motions.js +40 -34
  68. package/dist/move.js +23 -16
  69. package/dist/moved.d.ts +11 -0
  70. package/dist/moved.js +29 -0
  71. package/dist/origin.d.ts +19 -0
  72. package/dist/origin.js +68 -0
  73. package/dist/owed.d.ts +4 -4
  74. package/dist/owed.js +8 -8
  75. package/dist/owner.d.ts +1 -1
  76. package/dist/owner.js +2 -2
  77. package/dist/pace.d.ts +13 -5
  78. package/dist/pace.js +21 -8
  79. package/dist/pack.d.ts +3 -1
  80. package/dist/pack.js +15 -24
  81. package/dist/paging.d.ts +8 -2
  82. package/dist/paging.js +39 -4
  83. package/dist/patch.d.ts +14 -9
  84. package/dist/patch.js +83 -21
  85. package/dist/place.js +18 -3
  86. package/dist/project.d.ts +12 -1
  87. package/dist/project.js +101 -83
  88. package/dist/pull.d.ts +2 -0
  89. package/dist/pull.js +8 -0
  90. package/dist/qualify.js +10 -2
  91. package/dist/reading.d.ts +5 -0
  92. package/dist/reading.js +5 -0
  93. package/dist/record.d.ts +9 -0
  94. package/dist/record.js +42 -0
  95. package/dist/relink.d.ts +11 -5
  96. package/dist/relink.js +7 -5
  97. package/dist/restored.d.ts +41 -0
  98. package/dist/restored.js +91 -0
  99. package/dist/revive.d.ts +10 -3
  100. package/dist/revive.js +31 -23
  101. package/dist/roster.d.ts +11 -0
  102. package/dist/roster.js +46 -0
  103. package/dist/rotation.d.ts +29 -0
  104. package/dist/rotation.js +91 -0
  105. package/dist/rows.d.ts +5 -5
  106. package/dist/rows.js +5 -5
  107. package/dist/sample.d.ts +3 -2
  108. package/dist/sample.js +32 -15
  109. package/dist/seek.js +97 -114
  110. package/dist/shared.d.ts +6 -0
  111. package/dist/shared.js +15 -0
  112. package/dist/signals.d.ts +24 -3
  113. package/dist/signals.js +50 -11
  114. package/dist/spans.js +7 -0
  115. package/dist/stack.d.ts +11 -0
  116. package/dist/stack.js +47 -0
  117. package/dist/standing.d.ts +10 -0
  118. package/dist/standing.js +79 -0
  119. package/dist/store.d.ts +3 -3
  120. package/dist/store.js +3 -3
  121. package/dist/strays.js +3 -0
  122. package/dist/tape.d.ts +8 -5
  123. package/dist/tape.js +21 -13
  124. package/dist/testing.d.ts +35 -0
  125. package/dist/testing.js +116 -0
  126. package/dist/touch.d.ts +6 -0
  127. package/dist/touch.js +28 -0
  128. package/dist/transport.d.ts +45 -6
  129. package/dist/transport.js +64 -19
  130. package/dist/turns.d.ts +18 -0
  131. package/dist/turns.js +72 -0
  132. package/dist/tweened.js +1 -1
  133. package/dist/types/channel.d.ts +46 -0
  134. package/dist/types/channel.js +1 -0
  135. package/dist/types/history.d.ts +139 -0
  136. package/dist/types/history.js +1 -0
  137. package/dist/types/mix.d.ts +336 -0
  138. package/dist/types/mix.js +1 -0
  139. package/dist/types/patch.d.ts +187 -0
  140. package/dist/types/patch.js +1 -0
  141. package/dist/types/place.d.ts +157 -0
  142. package/dist/types/place.js +1 -0
  143. package/dist/types/transport.d.ts +71 -0
  144. package/dist/types/transport.js +1 -0
  145. package/dist/types/voice.d.ts +323 -0
  146. package/dist/types/voice.js +1 -0
  147. package/dist/types.d.ts +7 -1162
  148. package/dist/unpage.d.ts +2 -2
  149. package/dist/unpage.js +53 -25
  150. package/dist/voice.d.ts +90 -22
  151. package/dist/voice.js +105 -43
  152. package/dist/wave.d.ts +42 -0
  153. package/dist/wave.js +62 -0
  154. package/dist/weigh.js +1 -1
  155. package/docs/schema.html +42 -36
  156. package/package.json +8 -3
package/dist/fill.js CHANGED
@@ -1,14 +1,20 @@
1
1
  import { foldNumber, lerpNumber } from './channels.js';
2
- import { passAt, phaseAt, silent, weighed } from './clock.js';
2
+ import { passAt, phaseAt, same, silent, weighed } from './clock.js';
3
3
  import { flush } from './columns.js';
4
4
  import { crowdsUpTo, freshen } from './crowd.js';
5
+ import { open as openRecord, shut as shutRecord } from './everyone.js';
5
6
  import { foldLocus, gatherLocus } from './gather.js';
7
+ import { runKeys } from './keyfill.js';
6
8
  import { frozenAt } from './lane.js';
7
9
  import { reach } from './meet.js';
8
10
  import { absent } from './numbers.js';
9
11
  import { AT, NOTHING, readKeys, seg, segment, shifted } from './patch.js';
10
12
  import { reading } from './reading.js';
11
13
  import { move, runMotion } from './sample.js';
14
+ import { rested } from './turns.js';
15
+ // V8 reads a local const as a constant, where it reads an import from its module on every call.
16
+ const open = openRecord;
17
+ const shut = shutRecord;
12
18
  /** The least prime at least `n`, and 1 below 2. */
13
19
  function primeFrom(n) {
14
20
  if (n < 2)
@@ -47,7 +53,7 @@ export function fillAll(lanes, now, version) {
47
53
  for (const lane of lanes.lanes) {
48
54
  if (decide) {
49
55
  // A lane with few subjects, such as one naming its own, goes by the share of all probed;
50
- // one with a single subject shares nothing a fill could save, as a solo lane does not.
56
+ // one with a single subject shares nothing a fill could save.
51
57
  const line = lane.line;
52
58
  const n = lane.list.length;
53
59
  if (n >= 64)
@@ -77,7 +83,7 @@ export function fillAll(lanes, now, version) {
77
83
  }
78
84
  if (busy) {
79
85
  for (const ch of lanes.laned)
80
- ch.values.fill(ch.rest, 0, size * ch.axes);
86
+ rested(ch, size);
81
87
  for (const g of lanes.loci)
82
88
  gatherLocus(lanes, g);
83
89
  for (const lane of lanes.lanes) {
@@ -104,6 +110,7 @@ export function fillAll(lanes, now, version) {
104
110
  lanes.holding = false;
105
111
  }
106
112
  lanes.moved = reading.moved;
113
+ lanes.inputs = reading.inputs;
107
114
  }
108
115
  finally {
109
116
  lanes.filling = false;
@@ -168,21 +175,29 @@ export function wake(lanes, lane) {
168
175
  reach(lanes, slot, -1);
169
176
  }
170
177
  /**
171
- * A voice with a signal weight: its weight for the subject at `slot` under the voice's fade `fade`,
172
- * through the general path's own arithmetic; NaN where that path has not made the voice's first
173
- * call for the subject, which it then makes this frame, so a signal that keeps state is first
174
- * called where the general path would call it.
178
+ * A voice with a signal weight: its weight for the subject at `slot`, left in `Arg.WEIGHT`, at the
179
+ * voice time, pass and fade in `Arg.ELAPSED`, `Arg.PASS` and `Arg.FADE`, through the general path's
180
+ * own arithmetic. False where that path has not made the voice's first call for the subject, which
181
+ * it then makes this frame, so a signal that keeps state is first called where the general path
182
+ * would call it.
175
183
  */
176
- export function signalled(voice, slot, rec, elapsed, pass, fade) {
184
+ export function signalled(voice, slot, rec) {
185
+ const arg = this.arg;
186
+ const elapsed = arg[1 /* Arg.ELAPSED */];
187
+ const pass = arg[3 /* Arg.PASS */];
188
+ const fade = arg[5 /* Arg.FADE */];
177
189
  if (Number.isNaN(rec.probed)) {
178
190
  this.late.push(slot);
179
- return Number.NaN;
191
+ return false;
180
192
  }
181
193
  const subject = this.subjectAt(slot);
182
- if (subject === absent)
183
- return 0;
194
+ if (subject === absent) {
195
+ arg[0 /* Arg.WEIGHT */] = 0;
196
+ return true;
197
+ }
184
198
  const base = this.host.signal(voice, subject, rec, elapsed, pass, slot);
185
- return weighed(base, fade, voice.parts === null ? 1 : this.host.parting(voice, subject));
199
+ arg[0 /* Arg.WEIGHT */] = weighed(base, fade, voice.parts === null ? 1 : this.host.parting(voice, subject));
200
+ return true;
186
201
  }
187
202
  /** What a subject's own ramp out of a voice leaves of its weight: 1 with none. */
188
203
  export function parting(voice, slot) {
@@ -228,25 +243,53 @@ export function run(lane) {
228
243
  runMotion(this, lane, lane.motion);
229
244
  return;
230
245
  }
231
- const elapsed = voice.elapsedAt(this.now);
232
- const duration = voice.duration;
233
- const passes = voice.passes;
246
+ if (voice.built !== null && typeof voice.spec.weight !== 'function') {
247
+ runKeys(this, lane);
248
+ return;
249
+ }
250
+ lane.elapsedNow = voice.elapsedAt(this.now);
234
251
  const list = lane.list;
252
+ if (voice.sharing) {
253
+ this.runEveryone(lane);
254
+ return;
255
+ }
235
256
  for (let p = 0; p < list.length; p++) {
236
- this.one(lane, p, list[p], elapsed, duration, passes);
257
+ this.one(lane, p, list[p]);
237
258
  // Its patch just made kept state: no further call this fill, the general path makes them.
238
259
  if (voice.keeping)
239
260
  return;
240
261
  }
241
262
  }
263
+ /**
264
+ * `run`'s loop for a voice keeping one record for every subject: the record is pointed at each
265
+ * subject before its call and taken back after, so `one` and `call` read it as a record of the
266
+ * subject's own. A loop of its own, which leaves theirs as they were for every other voice.
267
+ */
268
+ export function runEveryone(lane) {
269
+ const voice = lane.voice;
270
+ const rec = voice.everyone;
271
+ const list = lane.list;
272
+ const cap = this.cap;
273
+ for (let p = 0; p < list.length; p++) {
274
+ const slot = list[p];
275
+ open(voice, rec, slot);
276
+ this.one(lane, p, slot);
277
+ // Its patch just made kept state, and the record is now that subject's own.
278
+ if (voice.keeping)
279
+ return;
280
+ shut(voice, rec, slot, cap);
281
+ }
282
+ }
242
283
  /**
243
284
  * One subject's contribution from a lane's voice. True where the voice gave the subject a delta,
244
285
  * as the general path's `contribution` does where it returns one, which is what makes a voice in a
245
286
  * locus one of its members for the subject.
246
287
  */
247
- export function one(lane, p, slot, elapsedNow, duration, passes) {
288
+ export function one(lane, p, slot) {
248
289
  const host = this.host;
249
290
  const voice = lane.voice;
291
+ const elapsedNow = lane.elapsedNow;
292
+ const arg = this.arg;
250
293
  const data = lane.data;
251
294
  const o = p * 8 /* Row.STRIDE */;
252
295
  // A probe read this subject from the last fill: keep the weight it read for `weightOf`.
@@ -260,25 +303,28 @@ export function one(lane, p, slot, elapsedNow, duration, passes) {
260
303
  data[o + 2 /* Row.WEIGHT */] = 0;
261
304
  return false;
262
305
  }
263
- if (!lane.placed || !Object.is(elapsed, lane.placedAt)) {
306
+ if (!lane.placed || !same(elapsed, lane.placedAt)) {
264
307
  lane.placed = true;
265
308
  lane.placedAt = elapsed;
266
- lane.phase = phaseAt(elapsed, duration, passes);
267
- lane.pass = passAt(elapsed, duration, passes);
309
+ lane.phase = phaseAt(elapsed, voice.duration, voice.passes);
310
+ lane.pass = passAt(elapsed, voice.duration, voice.passes);
268
311
  }
269
312
  const since = data[o + 1 /* Row.SINCE */];
270
- if (!lane.flat && (!lane.weighed || !Object.is(since, lane.weighedSince))) {
313
+ if (!lane.flat && (!lane.weighed || !same(since, lane.weighedSince))) {
271
314
  lane.fade = host.envelope(voice, since);
272
315
  lane.weighed = true;
273
316
  lane.weighedSince = since;
274
317
  }
275
318
  let w;
276
319
  if (typeof voice.spec.weight === 'function') {
277
- w = this.signalled(voice, slot, lane.records[p], elapsed, lane.pass, lane.fade);
278
- if (Number.isNaN(w)) {
320
+ arg[1 /* Arg.ELAPSED */] = elapsed;
321
+ arg[3 /* Arg.PASS */] = lane.pass;
322
+ arg[5 /* Arg.FADE */] = lane.fade;
323
+ if (!this.signalled(voice, slot, lane.records[p])) {
279
324
  data[o + 2 /* Row.WEIGHT */] = 0;
280
325
  return false;
281
326
  }
327
+ w = arg[0 /* Arg.WEIGHT */];
282
328
  }
283
329
  else
284
330
  w = weighed(voice.weight, lane.fade, this.parting(voice, slot));
@@ -286,14 +332,16 @@ export function one(lane, p, slot, elapsedNow, duration, passes) {
286
332
  this.folding = lane;
287
333
  this.rec = lane.records[p] ?? null;
288
334
  if (voice.built !== null) {
289
- if (!lane.read || !Object.is(elapsed, lane.readAt)) {
335
+ if (!lane.read || !same(elapsed, lane.readAt)) {
290
336
  this.readKeyed(voice, lane.phase, lane.delta, lane.scratch);
291
337
  lane.read = true;
292
338
  lane.readAt = elapsed;
293
339
  this.gather(lane, lane.delta);
294
340
  }
295
- if (w > 0)
296
- this.fold(lane, slot, w);
341
+ if (w > 0) {
342
+ arg[0 /* Arg.WEIGHT */] = w;
343
+ this.fold(lane, slot);
344
+ }
297
345
  return true;
298
346
  }
299
347
  const rec = lane.records[p];
@@ -303,18 +351,25 @@ export function one(lane, p, slot, elapsedNow, duration, passes) {
303
351
  return false;
304
352
  }
305
353
  // A motion patch needs the subject only to number it, so the lookup waits until then.
354
+ arg[1 /* Arg.ELAPSED */] = elapsed;
355
+ arg[4 /* Arg.DELAY */] = delay;
356
+ arg[0 /* Arg.WEIGHT */] = w;
306
357
  if (lane.motion !== undefined) {
307
- move(this, lane, lane.motion, p, slot, rec, elapsed, delay, w);
358
+ move(this, lane, lane.motion, p, slot, rec);
308
359
  return true;
309
360
  }
310
- return this.call(voice, lane.chans, rec, slot, elapsed, lane.phase, lane.pass, delay, w);
361
+ arg[2 /* Arg.PHASE */] = lane.phase;
362
+ arg[3 /* Arg.PASS */] = lane.pass;
363
+ return this.call(voice, lane.chans, rec, slot);
311
364
  }
312
365
  /**
313
- * A keys voice's stops at `phase` folded straight into a subject's values, without a delta: what
314
- * `readKeyed` then `foldDelta` give, through the same segment search and the stock channels' own
315
- * lerp, which is all a laned keys voice can use.
366
+ * A keys voice's stops at `Arg.PHASE` folded straight into a subject's values at `Arg.WEIGHT`,
367
+ * without a delta: what `readKeyed` then `foldDelta` give, through the same segment search and the
368
+ * stock channels' own lerp, which is all a laned keys voice can use.
316
369
  */
317
- export function foldKeys(voice, chans, phase, slot, w) {
370
+ export function foldKeys(voice, chans, slot) {
371
+ const phase = this.arg[2 /* Arg.PHASE */];
372
+ const w = this.arg[0 /* Arg.WEIGHT */];
318
373
  const built = voice.built;
319
374
  const tracks = built.tracks;
320
375
  for (let i = 0; i < tracks.length; i++) {
@@ -324,14 +379,14 @@ export function foldKeys(voice, chans, phase, slot, w) {
324
379
  if (found === NOTHING)
325
380
  continue;
326
381
  if (found === AT) {
327
- this.foldInto(ch, slot, seg.a, w);
382
+ this.foldInto(ch, slot, seg.a);
328
383
  continue;
329
384
  }
330
385
  const a = seg.a;
331
386
  const b = seg.b;
332
387
  const u = seg.eased;
333
- if (ch.scalar) {
334
- this.foldInto(ch, slot, voice.lerps[i](a, b, u), w);
388
+ if (ch.scalar || !ch.plain) {
389
+ this.foldInto(ch, slot, voice.lerps[i](a, b, u));
335
390
  continue;
336
391
  }
337
392
  // `vec`'s lerp, reading each end past its length as the rest, then its fold.
@@ -351,10 +406,18 @@ export function readKeyed(voice, phase, delta, scratch) {
351
406
  readKeys(voice.built, phase, delta, undefined, voice.lerps, undefined, voice.intos, scratch);
352
407
  }
353
408
  /**
354
- * Calls a stateless fn voice's patch for a subject its general path has met, and folds the delta;
355
- * false for a subject the host has let go of.
409
+ * Calls a stateless fn voice's patch for a subject its general path has met, and folds the delta,
410
+ * at the voice time, phase, pass, delay and weight in `Arg`; false where it gave no delta, for a
411
+ * subject the host has let go of or a weight the voice is silent at. As arguments those cost nothing where V8 inlines the call and 31 bytes a call where it
412
+ * does not, which differs by V8 version: Node 26.1 does not (2026-10-09).
356
413
  */
357
- export function call(voice, chans, rec, slot, elapsed, phase, pass, delay, w) {
414
+ export function call(voice, chans, rec, slot) {
415
+ const arg = this.arg;
416
+ const elapsed = arg[1 /* Arg.ELAPSED */];
417
+ const phase = arg[2 /* Arg.PHASE */];
418
+ const pass = arg[3 /* Arg.PASS */];
419
+ const delay = arg[4 /* Arg.DELAY */];
420
+ const w = arg[0 /* Arg.WEIGHT */];
358
421
  const host = this.host;
359
422
  const subject = this.subjectAt(slot);
360
423
  if (subject === absent)
@@ -362,11 +425,11 @@ export function call(voice, chans, rec, slot, elapsed, phase, pass, delay, w) {
362
425
  // Called already this frame, by the general path or a fill before a refill: reuse, as a probe does.
363
426
  if (rec.probed === this.now && rec.delta !== null && rec.seeks === voice.seeks) {
364
427
  if (w > 0)
365
- this.foldDelta(chans, slot, rec.delta, w);
428
+ this.foldDelta(chans, slot, rec.delta);
366
429
  return true;
367
430
  }
368
431
  if (silent(voice, w))
369
- return true;
432
+ return false;
370
433
  const kept = reading.kept;
371
434
  host.ready(voice, subject, rec, elapsed, pass, w);
372
435
  if (this.keeps)
@@ -383,6 +446,6 @@ export function call(voice, chans, rec, slot, elapsed, phase, pass, delay, w) {
383
446
  if (reading.kept !== kept && !voice.keeping)
384
447
  host.kept(voice);
385
448
  if (w > 0)
386
- this.foldDelta(chans, slot, delta, w);
449
+ this.foldDelta(chans, slot, delta);
387
450
  return true;
388
451
  }
package/dist/fit.js CHANGED
@@ -93,7 +93,8 @@ export function condense() {
93
93
  if (fits(span, kids, plan) || !kids.some((k) => k.overlap))
94
94
  return plan;
95
95
  const at = (s) => ({ ...plan, share: s });
96
- // `least` finds the smallest x that fits; the share wanted is the largest, so search 1 - share.
96
+ // `least` finds the smallest x that fits; the share wanted is the largest, so search how far
97
+ // under the plan's it is.
97
98
  const x = least(0, plan.share, (d) => fits(span, kids, at(plan.share - d)));
98
99
  return at(plan.share - x);
99
100
  };
package/dist/fold.d.ts CHANGED
@@ -1,7 +1,14 @@
1
1
  import type { Mixer } from './mixer.js';
2
+ import type { Channel } from './types.js';
2
3
  import type { Subject, Voice } from './voice.js';
3
4
  export type Key<O> = keyof O & string;
4
5
  export declare function near(a: unknown, b: unknown): boolean;
6
+ /**
7
+ * `merge(acc, b)`, where a result that is `b` itself, as `last()` gives, is copied into `acc` or a
8
+ * new array: `b` belongs to a patch or the mix's scratch, and a host may edit the pose. `acc` is a
9
+ * value this fold made.
10
+ */
11
+ export declare function merged(channel: Channel<unknown>, acc: unknown, b: unknown): unknown;
5
12
  export type Values = Record<string, unknown>;
6
13
  /**
7
14
  * One live voice's delta for one subject this frame, through its record for the subject, or null
@@ -28,12 +35,30 @@ export declare function baseFor<I, O>(this: Mixer<I, O>, voice: Voice<I, O>, sub
28
35
  */
29
36
  export declare function slopeFor<I, O>(this: Mixer<I, O>, voice: Voice<I, O>, subject: I): Record<string, unknown> | undefined;
30
37
  export declare function isRest<I, O>(this: Mixer<I, O>, delta: Record<string, unknown>): boolean;
38
+ /**
39
+ * A record's band state once its voice is skipped at weight 0: off, as `passes` would have said, so
40
+ * a weight that comes back inside the band does not find it still on.
41
+ */
42
+ export declare function unband(held: Subject<unknown> | null | undefined): void;
31
43
  /** Whether a rest-less channel's contribution is switched on, across a band rather than an edge. */
32
44
  export declare function passes<I, O>(this: Mixer<I, O>, was: boolean | undefined, w: number): boolean;
33
45
  /** Folds one voice's delta into the pose, its band state kept on the subject's record. */
34
46
  export declare function apply<I, O>(this: Mixer<I, O>, pose: Record<string, unknown>, voice: Voice<I, O>, held: Subject<unknown>, delta: Record<string, unknown>, weight: number): void;
35
47
  /** Clamps every bounded channel of a folded pose into its range, in place. */
36
48
  export declare function clamp<I, O>(this: Mixer<I, O>, pose: Record<string, unknown>): Record<string, unknown>;
49
+ /** A folded value held to its channel's bounds: a number clamped, an array clamped in place. */
50
+ export declare function bound(channel: Channel<unknown>, v: unknown): unknown;
51
+ /**
52
+ * Whether a fold's next voice is its chain's next record, `held`, and not the next voice sharing
53
+ * one record, `sharers[q]`: the two lists are each in voice order, and a fold takes them as one.
54
+ */
55
+ export declare function chainFirst<I, O>(held: Subject<unknown> | null, sharers: readonly Voice<I, O>[], q: number): boolean;
56
+ /**
57
+ * After a fold read a sharing voice for the subject numbered `slot`: keeps the weight it gave and
58
+ * what the read left on its record, and gives the fold's place in `sharers`, which moves back where
59
+ * the read made the voice share no more.
60
+ */
61
+ export declare function shared<I, O>(this: Mixer<I, O>, voice: Voice<I, O>, slot: number, rec: Subject<unknown>, q: number): number;
37
62
  export declare function fold<I, O>(this: Mixer<I, O>, subject: I, out?: O, dry?: boolean, except?: number): O;
38
63
  export declare function folded<I, O>(this: Mixer<I, O>, subject: I, out?: O, dry?: boolean, except?: number): O;
39
64
  /**
@@ -43,6 +68,18 @@ export declare function folded<I, O>(this: Mixer<I, O>, subject: I, out?: O, dry
43
68
  export declare function linked<I, O>(this: Mixer<I, O>, subject: I): Subject<unknown> | null;
44
69
  /** The fold after a subject's chain is linked and its lanes asked whether it reads from them. */
45
70
  export declare function foldWith<I, O>(this: Mixer<I, O>, subject: I, out: O, head: Subject<unknown> | null, laned: boolean, dry: boolean, except?: number): O;
71
+ /**
72
+ * `foldWith`'s voices in a mix with a locus or a voice sharing one record in it. The chain is taken
73
+ * again where a voice stopped sharing since it was linked, as a patch call in this probe's fill can
74
+ * make one do. With no locus, the chain's records fold in voice order, and each voice sharing one
75
+ * record, which is in no chain, before the first chain record that comes after it.
76
+ */
77
+ export declare function foldDetour<I, O>(this: Mixer<I, O>, subject: I, pose: Record<string, unknown>, linkedHead: Subject<unknown>, laned: boolean, dry: boolean, except: number | undefined, owed: number): O;
78
+ /**
79
+ * Folds the voices sharing one record from `sharers[q]` up to the first whose id is `before` or
80
+ * more, as `foldWith` folds a chain's records, and gives the place it stopped at.
81
+ */
82
+ export declare function foldSharers<I, O>(this: Mixer<I, O>, pose: Record<string, unknown>, subject: I, head: Subject<unknown>, q: number, before: number, laned: boolean, dry: boolean, except: number | undefined, owed: number): number;
46
83
  /** Whether the subject numbered `owed` reads laned `voice` from the general path this fill. */
47
84
  export declare function owedBy<I, O>(this: Mixer<I, O>, owed: number, voice: Voice<I, O>): boolean;
48
85
  /** `foldWith`'s voices with a locus in play: each locus folds at its first member's place. */