@msb235/blits 0.14.0 → 0.15.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 (173) hide show
  1. package/CHANGELOG.md +154 -0
  2. package/README.md +3 -3
  3. package/dist/ahead.d.ts +26 -0
  4. package/dist/ahead.js +264 -0
  5. package/dist/around.d.ts +11 -0
  6. package/dist/around.js +32 -0
  7. package/dist/bare.js +15 -7
  8. package/dist/blank.d.ts +10 -0
  9. package/dist/blank.js +26 -0
  10. package/dist/blend.d.ts +2 -1
  11. package/dist/blend.js +1 -6
  12. package/dist/bound.d.ts +70 -0
  13. package/dist/bound.js +351 -0
  14. package/dist/chain.d.ts +2 -1
  15. package/dist/chain.js +7 -5
  16. package/dist/changes.d.ts +24 -0
  17. package/dist/changes.js +189 -0
  18. package/dist/channels.d.ts +39 -13
  19. package/dist/channels.js +14 -5
  20. package/dist/color.d.ts +12 -10
  21. package/dist/color.js +25 -25
  22. package/dist/columns.js +7 -3
  23. package/dist/contribution.d.ts +30 -0
  24. package/dist/contribution.js +374 -0
  25. package/dist/copyout.d.ts +10 -0
  26. package/dist/copyout.js +69 -24
  27. package/dist/crowd.d.ts +8 -2
  28. package/dist/crowd.js +4 -5
  29. package/dist/cue.d.ts +8 -1
  30. package/dist/cue.js +39 -13
  31. package/dist/cut.d.ts +8 -0
  32. package/dist/cut.js +4 -0
  33. package/dist/drop.d.ts +9 -0
  34. package/dist/drop.js +84 -0
  35. package/dist/due.d.ts +24 -5
  36. package/dist/due.js +113 -33
  37. package/dist/easing.d.ts +4 -4
  38. package/dist/easing.js +3 -3
  39. package/dist/everyone.d.ts +3 -2
  40. package/dist/everyone.js +3 -3
  41. package/dist/fade.d.ts +2 -1
  42. package/dist/fade.js +2 -1
  43. package/dist/fill.d.ts +3 -2
  44. package/dist/fill.js +51 -19
  45. package/dist/fit.d.ts +44 -26
  46. package/dist/fit.js +10 -9
  47. package/dist/fold.d.ts +4 -37
  48. package/dist/fold.js +5 -513
  49. package/dist/gather.d.ts +12 -7
  50. package/dist/gather.js +179 -44
  51. package/dist/gone.js +2 -2
  52. package/dist/grid.d.ts +47 -0
  53. package/dist/grid.js +247 -0
  54. package/dist/handle.d.ts +2 -0
  55. package/dist/handle.js +14 -8
  56. package/dist/held.d.ts +2 -1
  57. package/dist/history.d.ts +6 -5
  58. package/dist/history.js +7 -9
  59. package/dist/hosts.js +9 -15
  60. package/dist/index.d.ts +5 -4
  61. package/dist/keyfill.d.ts +1 -1
  62. package/dist/keyfill.js +5 -3
  63. package/dist/keyrows.d.ts +12 -0
  64. package/dist/keyrows.js +99 -12
  65. package/dist/lane.d.ts +36 -6
  66. package/dist/lane.js +32 -1
  67. package/dist/lanes.d.ts +23 -8
  68. package/dist/lanes.js +29 -8
  69. package/dist/leavings.d.ts +2 -2
  70. package/dist/leavings.js +1 -1
  71. package/dist/lives.d.ts +47 -0
  72. package/dist/lives.js +180 -0
  73. package/dist/meet.d.ts +2 -2
  74. package/dist/meet.js +90 -4
  75. package/dist/mixer.d.ts +54 -36
  76. package/dist/mixer.js +53 -171
  77. package/dist/motion.d.ts +14 -118
  78. package/dist/motion.js +16 -8
  79. package/dist/motions.d.ts +62 -155
  80. package/dist/motions.js +56 -370
  81. package/dist/moved.d.ts +1 -1
  82. package/dist/moved.js +16 -7
  83. package/dist/named.d.ts +0 -1
  84. package/dist/named.js +20 -2
  85. package/dist/numbers.d.ts +2 -0
  86. package/dist/numbers.js +4 -0
  87. package/dist/owed.d.ts +2 -0
  88. package/dist/owed.js +4 -0
  89. package/dist/pack.d.ts +2 -1
  90. package/dist/pack.js +2 -3
  91. package/dist/patch.d.ts +7 -3
  92. package/dist/patch.js +6 -2
  93. package/dist/places.d.ts +53 -0
  94. package/dist/places.js +171 -0
  95. package/dist/plot.d.ts +12 -0
  96. package/dist/plot.js +52 -0
  97. package/dist/project.d.ts +4 -4
  98. package/dist/project.js +9 -212
  99. package/dist/pull.js +11 -8
  100. package/dist/qualify.js +84 -21
  101. package/dist/reading.d.ts +6 -0
  102. package/dist/reading.js +5 -0
  103. package/dist/record.d.ts +5 -1
  104. package/dist/record.js +3 -2
  105. package/dist/relink.d.ts +1 -1
  106. package/dist/restored.d.ts +2 -2
  107. package/dist/restored.js +1 -1
  108. package/dist/rests.d.ts +9 -0
  109. package/dist/rests.js +76 -0
  110. package/dist/revive.d.ts +3 -2
  111. package/dist/revive.js +2 -2
  112. package/dist/{locus.d.ts → role.d.ts} +10 -9
  113. package/dist/{locus.js → role.js} +3 -3
  114. package/dist/roles.d.ts +10 -0
  115. package/dist/roles.js +158 -0
  116. package/dist/roster.js +3 -3
  117. package/dist/rotation.d.ts +1 -1
  118. package/dist/rotation.js +1 -1
  119. package/dist/rows.js +1 -1
  120. package/dist/sample.d.ts +2 -2
  121. package/dist/sample.js +33 -7
  122. package/dist/seek.js +5 -5
  123. package/dist/setting.d.ts +27 -0
  124. package/dist/setting.js +55 -0
  125. package/dist/shared.d.ts +1 -1
  126. package/dist/shared.js +1 -1
  127. package/dist/signals.d.ts +64 -32
  128. package/dist/signals.js +20 -18
  129. package/dist/stack.d.ts +5 -5
  130. package/dist/stack.js +5 -5
  131. package/dist/standing.d.ts +2 -1
  132. package/dist/standing.js +3 -2
  133. package/dist/store.d.ts +9 -0
  134. package/dist/store.js +24 -0
  135. package/dist/strays.d.ts +2 -1
  136. package/dist/strays.js +20 -13
  137. package/dist/stretch.d.ts +112 -0
  138. package/dist/stretch.js +9 -0
  139. package/dist/subject.d.ts +142 -0
  140. package/dist/subject.js +1 -0
  141. package/dist/tape.d.ts +9 -5
  142. package/dist/tape.js +5 -1
  143. package/dist/then.d.ts +9 -0
  144. package/dist/then.js +57 -0
  145. package/dist/ticker.d.ts +4 -4
  146. package/dist/transport.d.ts +0 -8
  147. package/dist/transport.js +0 -4
  148. package/dist/turns.d.ts +4 -3
  149. package/dist/turns.js +4 -3
  150. package/dist/types/arc.d.ts +12 -11
  151. package/dist/types/channel.d.ts +12 -8
  152. package/dist/types/history.d.ts +35 -19
  153. package/dist/types/mix.d.ts +222 -163
  154. package/dist/types/motion.d.ts +151 -0
  155. package/dist/types/motion.js +1 -0
  156. package/dist/types/patch.d.ts +67 -34
  157. package/dist/types/place.d.ts +51 -36
  158. package/dist/types/transport.d.ts +20 -18
  159. package/dist/types/voice.d.ts +136 -70
  160. package/dist/types/watch.d.ts +88 -40
  161. package/dist/types.d.ts +1 -0
  162. package/dist/voice.d.ts +7 -143
  163. package/dist/voice.js +28 -79
  164. package/dist/warn.d.ts +2 -0
  165. package/dist/warn.js +1 -1
  166. package/dist/watch.d.ts +2 -2
  167. package/dist/watch.js +5 -3
  168. package/dist/wave.d.ts +4 -3
  169. package/dist/wave.js +3 -2
  170. package/dist/weigh.d.ts +7 -1
  171. package/dist/weigh.js +27 -0
  172. package/docs/schema.html +212 -34
  173. package/package.json +2 -2
package/dist/strays.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { unpart } from './fade.js';
2
2
  import { pageOut } from './paging.js';
3
- import { record, unplayable } from './tape.js';
3
+ import { record, taping, unplayable } from './tape.js';
4
4
  /** Notes a motion patch that may hold state for a subject no voice playing it reaches. */
5
5
  export function stray(mix, motion, subject) {
6
6
  const list = mix.strays.get(subject);
@@ -24,7 +24,7 @@ export function unplay(mix, voice) {
24
24
  if (voice.named === null)
25
25
  mix.strayAll.add(motion);
26
26
  else
27
- for (const subject of voice.named)
27
+ for (const subject of voice.named.list)
28
28
  stray(mix, motion, subject);
29
29
  }
30
30
  /**
@@ -45,19 +45,14 @@ export function motionOwner(mix) {
45
45
  seq() {
46
46
  return mix.deref()?.transport.seq ?? Number.NaN;
47
47
  },
48
+ early() {
49
+ const m = mix.deref();
50
+ return m !== undefined && (m.syncing || !m.looked);
51
+ },
48
52
  changed(id, motion, subject, change) {
49
53
  const m = mix.deref();
50
- if (m === undefined)
51
- return;
52
- record(m, 'motion', (stage) => {
53
- const to = stage.mix(m);
54
- if (to === undefined)
55
- return;
56
- if (to !== m)
57
- return changeAhead(to, id, motion, subject, change);
58
- const v = cuedById(m, id) ?? m.gone.find((g) => g.id === id);
59
- (v?.motion ?? motion).change(subject, { ...change });
60
- });
54
+ if (m !== undefined && taping(m))
55
+ recordChange(m, id, motion, subject, change);
61
56
  },
62
57
  page(id, stream, subject, out) {
63
58
  const m = mix.deref();
@@ -84,6 +79,18 @@ export function motionOwner(mix) {
84
79
  },
85
80
  };
86
81
  }
82
+ // Apart from `changed`, whose body would otherwise make this closure's context on every change.
83
+ function recordChange(m, id, motion, subject, change) {
84
+ record(m, 'motion', (stage) => {
85
+ const to = stage.mix(m);
86
+ if (to === undefined)
87
+ return;
88
+ if (to !== m)
89
+ return changeAhead(to, id, motion, subject, change);
90
+ const v = cuedById(m, id) ?? m.gone.find((g) => g.id === id);
91
+ (v?.motion ?? motion).change(subject, { ...change });
92
+ });
93
+ }
87
94
  /**
88
95
  * A retarget or push the tape holds, made for a read ahead: kept on its transport for the patch
89
96
  * to apply as it reads, since the patch's own state is the live mix's.
@@ -0,0 +1,112 @@
1
+ import type { Curve } from './easing.js';
2
+ import type { Motions } from './motions.js';
3
+ import type { MotionSpec } from './types.js';
4
+ /**
5
+ * One closed-form stretch: released at `at` (voice ms) from `x0` moving at `v0`, toward `to`, over
6
+ * `ms` for a tween (0 for any other shape).
7
+ */
8
+ export interface Segment {
9
+ at: number;
10
+ ms: number;
11
+ x0: number[];
12
+ v0: number[];
13
+ to: number[];
14
+ /** The change that released it; undefined for a subject's first stretch. */
15
+ change?: Change;
16
+ }
17
+ export interface Change {
18
+ /**
19
+ * Voice ms it takes effect at; absent, until the subject's next read stamps it with that read's
20
+ * time, for one made while no frame had met the subject.
21
+ */
22
+ at?: number;
23
+ to?: number[];
24
+ /** Where it moves from, in place of where its stretch has it then. */
25
+ x?: number[];
26
+ v?: number[];
27
+ /** The mix clock when it was made, NaN where no mix was playing the patch. */
28
+ made?: number;
29
+ /** The frame it was made in, which a rewind partitions by; NaN where no mix was playing the patch. */
30
+ seq?: number;
31
+ /** Whether it was made before its frame was read, so a read of what that frame showed has it. */
32
+ early?: boolean;
33
+ }
34
+ /** A record of a motion patch's history leaving memory, at a mix time and frame. */
35
+ export interface Paging {
36
+ at: number;
37
+ seq: number;
38
+ data: unknown;
39
+ }
40
+ /** A subject's run as plain data: its flags, its stretches oldest first, and changes still to apply. */
41
+ export interface Run {
42
+ flags: number;
43
+ stretches: Segment[];
44
+ pending: Change[] | undefined;
45
+ }
46
+ /** `n` numbers of `from` from `at`, as an array of their own. */
47
+ export declare function numbers(from: Float64Array, at: number, n: number): number[];
48
+ /**
49
+ * A subject's flags: its value is a number; it has changes pending; it has older stretches; the
50
+ * stretch it is playing was found landed, which holds until another replaces it.
51
+ */
52
+ export declare const enum RunFlag {
53
+ SCALAR = 1,
54
+ PENDING = 2,
55
+ OLDER = 4,
56
+ LANDED = 8
57
+ }
58
+ /**
59
+ * The mix playing a patch, asked with its voice's id: an owner and an id, where a pair of closures
60
+ * cost two functions, their contexts and a weak reference per voice.
61
+ */
62
+ export interface MotionOwner {
63
+ /** The subject's voice time at the mix's latest frame; NaN where no frame of the voice met it. */
64
+ frame(id: number, subject: unknown): number;
65
+ /**
66
+ * Brings a subject the voice faded out back to it, so a change is not made for nothing: its
67
+ * voice time now, which a change bringing it back is made at; NaN for any other subject.
68
+ */
69
+ revive(id: number, subject: unknown): number;
70
+ /** The mix clock at its latest frame; NaN before the first. */
71
+ now(): number;
72
+ /** The number of the frame the mix is playing. */
73
+ seq(): number;
74
+ /** Whether a change made now comes before anything read the frame. */
75
+ early(): boolean;
76
+ /**
77
+ * The host made a change, already given its time, which a seek makes again on the patch its
78
+ * voice plays then: a voice a history store paged out comes back with a patch of its own.
79
+ */
80
+ changed<I>(id: number, motion: Motions<I>, subject: I, change: Change): void;
81
+ /** History leaving memory for a subject, which a mix with a history store pages out. */
82
+ page(id: number, stream: 'released' | 'stretch', subject: unknown, out: Paging[]): void;
83
+ }
84
+ /**
85
+ * What a mix keeping copies of a patch's stretches is told, with its id and the subject's number,
86
+ * before one changes.
87
+ */
88
+ export interface Watcher {
89
+ stretchChanged(id: number, s: number): void;
90
+ }
91
+ export interface Shape<I> {
92
+ from: (subject: I) => number[];
93
+ /** How fast each axis starts moving, given where it starts: still unless the options say. */
94
+ velocity: (subject: I, x: number[]) => number[];
95
+ /**
96
+ * Where it heads when released from `x` at `v`, given where it was heading; `put` for a stretch a
97
+ * `set` released.
98
+ */
99
+ aim: (x: number[], v: number[], was: number[] | null, subject: I, put: boolean) => number[];
100
+ /** `[form, settle, k1, k2, k3]`. */
101
+ law: readonly number[];
102
+ /** Whether a subject's value is a number rather than an array. */
103
+ scalar: (subject: I) => boolean;
104
+ /** Whether every subject's value is a number; undefined where that depends on the subject. */
105
+ scalarEvery(): boolean | undefined;
106
+ /** A tween's easing, which its law cannot hold; undefined, but present, on every other shape. */
107
+ ease: Curve | undefined;
108
+ /** A tween's ms for a stretch the subject starts now; undefined, but present, on the rest. */
109
+ ms: ((subject: I) => number) | undefined;
110
+ /** The patch's kind and constants, as `Patch.motion` reports them. */
111
+ spec(): MotionSpec;
112
+ }
@@ -0,0 +1,9 @@
1
+ /** Where `numbers` gathers what it copies, kept an array of doubles so every copy is one too. */
2
+ const gathered = [0.5];
3
+ /** `n` numbers of `from` from `at`, as an array of their own. */
4
+ export function numbers(from, at, n) {
5
+ // `Array.from` walks a typed array by its iterator: about 500 B a call for three axes.
6
+ for (let i = 0; i < n; i++)
7
+ gathered[i] = from[at + i];
8
+ return gathered.slice(0, n);
9
+ }
@@ -0,0 +1,142 @@
1
+ import type { Stamp } from './restored.js';
2
+ /**
3
+ * A subject's record as it left a voice, faded out of it or dropped: the mix time and frame it
4
+ * left at, and `sync` where it shows in its own frame: left in the frame's sync, or before anything
5
+ * read the mix that frame.
6
+ */
7
+ export interface Left<I> {
8
+ subject: I;
9
+ at: number;
10
+ seq: number;
11
+ sync: boolean;
12
+ held: Subject<unknown>;
13
+ /**
14
+ * The voice's fade of the subject as it stood on leaving, which a seek or read back to before
15
+ * puts back: its ramp out, while running, or its having faded out.
16
+ */
17
+ ramp: Parting | null;
18
+ parted: Parted | null;
19
+ }
20
+ /** A subject's ramp out of one voice: when it began, how long it runs, and the frame it was asked in. */
21
+ export interface Parting {
22
+ at: number;
23
+ over: number;
24
+ seq: number;
25
+ }
26
+ export interface Parted {
27
+ at: number;
28
+ seq: number;
29
+ ramp: Parting | undefined;
30
+ }
31
+ /**
32
+ * What a copy of a record keeps for the seeks that put a record back from it: the copy's state
33
+ * stepped on to `ticks`, as it stood near `at`, a moment one of them sought.
34
+ */
35
+ export interface Ahead<S> {
36
+ /** The record the last seek put back, and the moment it sought, until that record steps. */
37
+ put: Subject<S> | null;
38
+ sought: number;
39
+ /** The `since` of the record put back, which the steps in `state` were counted from. */
40
+ since: number;
41
+ at: number;
42
+ ticks: number;
43
+ /** Undefined until a record has stepped on from the copy. */
44
+ state: S | undefined;
45
+ /**
46
+ * The state the record a seek replaced had stepped on to from the copy, at `leftTicks`; undefined
47
+ * until one had.
48
+ */
49
+ leftTicks: number;
50
+ left: S | undefined;
51
+ }
52
+ /** A copy of a record kept under `history`, by the mix time and frame it was taken at. */
53
+ export interface Snap<S> {
54
+ at: number;
55
+ seq: number;
56
+ held: Subject<S>;
57
+ ahead?: Ahead<S>;
58
+ /** Set where another record's list holds it too, so a seek cutting it from one lets go of it. */
59
+ shared?: true;
60
+ }
61
+ /** Everything one voice holds for one subject, chained through the next voice that reaches it. */
62
+ export interface Subject<S> {
63
+ /** The voice's `target` answer, fixed on first sight. */
64
+ reaches: boolean;
65
+ /** The voice's `stagger` answer in voice ms, fixed on first sight. */
66
+ delay: number;
67
+ /** The mix timestamp this subject's delay ran out at, which its step grid counts from. */
68
+ since: number;
69
+ /** The mix timestamp its fade in counts from: `since`, or earlier for a voice freezing before. */
70
+ shown: number;
71
+ /** The weight this voice gave this subject the last frame it was probed, 0 where it gave none. */
72
+ weight: number;
73
+ /**
74
+ * The mix time it was left at rest during a handover, so it stops contributing, and which a seek
75
+ * reads to know whether it had by then; NaN while it has not (`isRested`).
76
+ */
77
+ restedAt: number;
78
+ /**
79
+ * Per written channel, whether a rest-less contribution is on: 0 unknown, 1 on, 2 off; null until
80
+ * a rest-less channel asks.
81
+ */
82
+ bands: Uint8Array | null;
83
+ state: S;
84
+ /** The `now` this subject last caught up to, for this voice. */
85
+ stepped: number;
86
+ /** Under `stepMs`, how many intervals have run since `since`; `stepped` is where that lands. */
87
+ ticks: number;
88
+ /** The `now` this subject was last probed at, so twelve probes in a frame step once. */
89
+ probed: number;
90
+ /** The last delta computed this frame, handed back to a repeat probe unchanged. */
91
+ delta: Record<string, unknown> | null;
92
+ /** The phase `delta` was read at, to read it again once its voice's scratch has moved on. */
93
+ phase: number;
94
+ /** The voice's `seeks` when `delta` was read, so a seek later in the frame reads it again. */
95
+ seeks: number;
96
+ /** The voice's `rebuilds` when its state was last made, so a seek's rebuild reaches it once. */
97
+ rebuilt: number;
98
+ /** Its kept signal state was stepped on in one go from a copy history kept, by a seek. */
99
+ copied: boolean;
100
+ /** Stop 0 for a `from: 'current'` voice, taken the first frame this subject is seen. */
101
+ base?: Record<string, unknown>;
102
+ /** The pose's velocity per channel at that moment, units per ms, so the first segment leaves at it. */
103
+ slope?: Record<string, unknown>;
104
+ /** What `setting.keep` holds for this voice and subject, by owner; null until it holds any. */
105
+ kept: Map<object, unknown> | null;
106
+ /** Kept state a history store gave back, which each owner takes in turn on its first keep. */
107
+ unkept?: unknown[];
108
+ /** Under `history`, copies of this record by the mix time they were taken, oldest first. */
109
+ snaps?: Snap<S>[];
110
+ /** In a projection: where this record started from, and whether nothing known could be. */
111
+ from?: number;
112
+ unknown?: boolean;
113
+ /** Under `history` with `inputs`, what an input weight signal read for this subject, when it changed. */
114
+ inputs?: {
115
+ at: number;
116
+ seq: number;
117
+ value: number;
118
+ }[];
119
+ /** In a projection reading back: that record, to read in place of the signal. */
120
+ replay?: {
121
+ at: number;
122
+ value: number;
123
+ }[];
124
+ /** The voice this is the record of; null on a subject's stub. */
125
+ voice: object | null;
126
+ /** The next voice's record for this subject, in voice order, among those that reach it. */
127
+ next: Subject<unknown> | null;
128
+ /**
129
+ * On the first record, which the mix keeps per subject so a probe makes one lookup: the `version`
130
+ * the chain was linked at, and per role, by channel slot, whether a rest-less contribution is on:
131
+ * 0 never decided, 1 on, 2 off.
132
+ */
133
+ version: number;
134
+ roles: Map<string, Uint8Array> | null;
135
+ /** On the first record: the number lanes index this subject by, -1 without one. */
136
+ slot: number;
137
+ /** A motion voice's number for this subject in its patch, good while `freed` is the patch's own. */
138
+ run: number;
139
+ freed: number;
140
+ /** In a voice's store once a seek has gone back, the stamp of the seek it was last put back or written at. */
141
+ restored: Stamp | null;
142
+ }
@@ -0,0 +1 @@
1
+ export {};
package/dist/tape.d.ts CHANGED
@@ -18,15 +18,18 @@ export declare function unplayable(what: string): never;
18
18
  * at: rate 0 holds mix time still across frames, and host time tells them apart.
19
19
  */
20
20
  export declare function tapeOf(transport: Transport): Tape | undefined;
21
+ interface Recorder {
22
+ readonly tape: Tape | undefined;
23
+ readonly replaying: boolean;
24
+ readonly projecting: boolean;
25
+ }
26
+ /** Whether `record` keeps a call made on `on` now, so a caller can skip making one it would drop. */
27
+ export declare function taping(on: Recorder): boolean;
21
28
  /**
22
29
  * Records a host call, which `again` makes once more when the mix plays past it after a seek, or
23
30
  * when a read ahead does, on the stage it is given.
24
31
  */
25
- export declare function record(on: {
26
- readonly tape: Tape | undefined;
27
- readonly replaying: boolean;
28
- readonly projecting: boolean;
29
- }, label: string, again: (stage: Stage) => void): void;
32
+ export declare function record(on: Recorder, label: string, again: (stage: Stage) => void): void;
30
33
  /** The host time at which the mix clock reads `t`, under the rate it has now. */
31
34
  export declare function hostAt(clock: {
32
35
  readonly pace: Pace | null;
@@ -47,3 +50,4 @@ export declare function hostAhead(clock: {
47
50
  * stage of its copies, it makes them on those, and the caller puts the tape back.
48
51
  */
49
52
  export declare function replay(transport: Transport, due: (u: number) => boolean, onto?: Transport, on?: Stage): number;
53
+ export {};
package/dist/tape.js CHANGED
@@ -24,13 +24,17 @@ export function tapeOf(transport) {
24
24
  coalesceWindowMs: 0,
25
25
  });
26
26
  }
27
+ /** Whether `record` keeps a call made on `on` now, so a caller can skip making one it would drop. */
28
+ export function taping(on) {
29
+ return on.tape !== undefined && !on.replaying && !on.projecting;
30
+ }
27
31
  /**
28
32
  * Records a host call, which `again` makes once more when the mix plays past it after a seek, or
29
33
  * when a read ahead does, on the stage it is given.
30
34
  */
31
35
  export function record(on, label, again) {
32
36
  const tape = on.tape;
33
- if (tape === undefined || on.replaying || on.projecting)
37
+ if (tape === undefined || !taping(on))
34
38
  return;
35
39
  const op = {
36
40
  label,
package/dist/then.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { type Cut } from './cut.js';
2
+ import type { Motions } from './motions.js';
3
+ /**
4
+ * `subject`'s position and velocity at voice time `t`, into the patch's `xs` and `vs`, as frame `cut` left it:
5
+ * in the run it had then, with only the changes made by then, as a seek back there plays it. A run
6
+ * with none made since reads as it stands; one with some plays from its earliest stretch kept,
7
+ * the rest applied again in the order they take effect. Commits nothing, and gives the run's flags.
8
+ */
9
+ export declare function sampleThen<I>(motions: Motions<I>, subject: I, t: number, cut: Cut): number;
package/dist/then.js ADDED
@@ -0,0 +1,57 @@
1
+ import { within } from './cut.js';
2
+ /** Whether `c` was made by frame `cut`; one made with no mix playing its patch was. */
3
+ const madeBy = (c, cut) => c.seq === undefined || Number.isNaN(c.seq) || within(cut, c.seq, c.early === true);
4
+ /** The stretch playing at voice time `t` of a run's, oldest first: the latest released by then, else the first. */
5
+ function playingIn(list, t) {
6
+ const last = list[list.length - 1];
7
+ if (t >= last.at || list.length === 1)
8
+ return last;
9
+ if (list[0].at > t)
10
+ return list[0];
11
+ let lo = 0;
12
+ let hi = list.length - 2;
13
+ while (lo < hi) {
14
+ const mid = (lo + hi + 1) >> 1;
15
+ if (list[mid].at <= t)
16
+ lo = mid;
17
+ else
18
+ hi = mid - 1;
19
+ }
20
+ return list[lo];
21
+ }
22
+ /**
23
+ * `subject`'s position and velocity at voice time `t`, into the patch's `xs` and `vs`, as frame `cut` left it:
24
+ * in the run it had then, with only the changes made by then, as a seek back there plays it. A run
25
+ * with none made since reads as it stands; one with some plays from its earliest stretch kept,
26
+ * the rest applied again in the order they take effect. Commits nothing, and gives the run's flags.
27
+ */
28
+ export function sampleThen(motions, subject, t, cut) {
29
+ const run = motions.runThen(subject, cut) ?? motions.freshRun(subject);
30
+ let stretches = run.stretches;
31
+ let pending = run.pending ?? [];
32
+ const kept = [];
33
+ let since = false;
34
+ for (const c of [...stretches.slice(1).map((seg) => seg.change), ...pending])
35
+ if (c === undefined || madeBy(c, cut)) {
36
+ if (c !== undefined)
37
+ kept.push(c);
38
+ }
39
+ else
40
+ since = true;
41
+ if (since) {
42
+ stretches = [stretches[0]];
43
+ pending = kept
44
+ .filter((c) => c.at !== undefined)
45
+ .sort((a, b) => a.at - b.at);
46
+ }
47
+ let seg = playingIn(stretches, t);
48
+ for (const c of pending) {
49
+ const a = c.at;
50
+ if (a === undefined || !(a <= t))
51
+ break;
52
+ if (a >= seg.at)
53
+ seg = motions.applied(subject, seg, c, a);
54
+ }
55
+ motions.evaluateSegment(seg, t, motions.xs, motions.vs);
56
+ return run.flags;
57
+ }
package/dist/ticker.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * What a ticker runs: a mix, or anything that syncs, sleeps on `inert` and wakes by `onWake`.
2
+ * What a ticker runs. A mix, or anything that syncs, sleeps on `inert` and wakes by `onWake`.
3
3
  *
4
4
  * @category mix
5
5
  */
@@ -21,9 +21,9 @@ export interface TickerOptions {
21
21
  */
22
22
  fps?: number;
23
23
  /**
24
- * Where frames come from: `'frame'`, `requestAnimationFrame`, or `'timer'`, `setTimeout`. By
25
- * default animation frames where they exist, and a timer where they don't, as in a worker
26
- * without them or in Node.
24
+ * Where frames come from. `'frame'` is `requestAnimationFrame`, and `'timer'` is `setTimeout`. By
25
+ * default animation frames where they exist, and a timer where they don't, as in a worker without
26
+ * them or in Node.
27
27
  */
28
28
  grain?: 'frame' | 'timer';
29
29
  /**
@@ -31,14 +31,6 @@ export interface Frame {
31
31
  at: number;
32
32
  u: number;
33
33
  }
34
- /** Where history is cut for a seek or read: what frame `seq` made, and before it, is kept. */
35
- export interface Cut {
36
- seq: number;
37
- /** For a read of what a frame showed: of that frame's own changes, only those made before it was read. */
38
- strict: boolean;
39
- }
40
- /** Whether a change made in frame `seq` falls inside `cut`; `early` for one made before the frame was read. */
41
- export declare function within(cut: Cut, seq: number, early?: boolean): boolean;
42
34
  /**
43
35
  * The clock its mixes play on: host time less what `rebase` took out, at the rate its `pace`
44
36
  * sets, moved by `sync` and `seek`, and the tape of calls a seek plays again. A mix made alone
package/dist/transport.js CHANGED
@@ -11,10 +11,6 @@ import { hostAt, record, replay, tapeOf } from './tape.js';
11
11
  import { gave, historyFor } from './watch.js';
12
12
  /** How far the tape's reach moves before it is pruned again, ms of mix time. */
13
13
  const TAPE_STEP_MS = 1000;
14
- /** Whether a change made in frame `seq` falls inside `cut`; `early` for one made before the frame was read. */
15
- export function within(cut, seq, early = false) {
16
- return seq < cut.seq || (seq === cut.seq && (!cut.strict || early));
17
- }
18
14
  /**
19
15
  * The clock its mixes play on: host time less what `rebase` took out, at the rate its `pace`
20
16
  * sets, moved by `sync` and `seek`, and the tape of calls a seek plays again. A mix made alone
package/dist/turns.d.ts CHANGED
@@ -7,11 +7,12 @@ export declare function shortWay(d: number, turn: number): number;
7
7
  * `fold`, which takes its axes as one value.
8
8
  */
9
9
  export declare function turnInto(ch: Laned, values: Float64Array, base: number, value: unknown, w: number): void;
10
- /** `turnInto` for a value held as numbers at `from` in `source`, as a locus holds what it gathered. */
10
+ /** `turnInto` for a value held as numbers at `from` in `source`, as a role holds what it gathered. */
11
11
  export declare function turnFrom(ch: Laned, values: Float64Array, base: number, source: Float64Array, from: number, w: number): void;
12
12
  /**
13
- * A locus member's rotation lerped by `u` into what the members before it left at `base`, through
14
- * the channel's own `lerp`; the first member's value as it is, where `taken` is 0.
13
+ * A role member's value for a channel not lerped straight across, lerped by `u` into what the
14
+ * members before it left at `base` through the channel's own `lerp`, or an angle's short way round;
15
+ * the first member's value as it is, where `taken` is 0.
15
16
  */
16
17
  export declare function turnToward(ch: Laned, values: Float64Array, base: number, value: unknown, taken: number, u: number): void;
17
18
  /** Sets every numbered subject's values on a lane to the channel's rest, as a fill starts from. */
package/dist/turns.js CHANGED
@@ -28,7 +28,7 @@ export function turnInto(ch, values, base, value, w) {
28
28
  for (let a = 0; a < axes; a++)
29
29
  values[base + a] = out[a];
30
30
  }
31
- /** `turnInto` for a value held as numbers at `from` in `source`, as a locus holds what it gathered. */
31
+ /** `turnInto` for a value held as numbers at `from` in `source`, as a role holds what it gathered. */
32
32
  export function turnFrom(ch, values, base, source, from, w) {
33
33
  if (ch.turn > 0) {
34
34
  turnInto(ch, values, base, source[from], w);
@@ -38,8 +38,9 @@ export function turnFrom(ch, values, base, source, from, w) {
38
38
  turnInto(ch, values, base, other, w);
39
39
  }
40
40
  /**
41
- * A locus member's rotation lerped by `u` into what the members before it left at `base`, through
42
- * the channel's own `lerp`; the first member's value as it is, where `taken` is 0.
41
+ * A role member's value for a channel not lerped straight across, lerped by `u` into what the
42
+ * members before it left at `base` through the channel's own `lerp`, or an angle's short way round;
43
+ * the first member's value as it is, where `taken` is 0.
43
44
  */
44
45
  export function turnToward(ch, values, base, value, taken, u) {
45
46
  if (ch.turn > 0) {
@@ -1,7 +1,7 @@
1
1
  import type { Handle, OwnerSpec, VoiceSpec } from './voice.js';
2
2
  /**
3
- * One voice of an arc's part: a voice's spec, less what the arc sets for it. The arc places it,
4
- * fades it across each boundary by `blend`, and holds its first and last frames for the blend.
3
+ * One voice of an arc's part. It is a voice's spec, less what the arc sets for it. The arc places
4
+ * it, fades it across each boundary by `blend`, and holds its first and last frames for the blend.
5
5
  *
6
6
  * @category score
7
7
  */
@@ -13,15 +13,15 @@ export interface ArcVoice<I, O, H = unknown> extends Omit<VoiceSpec<I, O, H>, 'o
13
13
  duration?: number;
14
14
  }
15
15
  /**
16
- * One part of an arc: a voice, or several layered together that play as one and last as long as
17
- * the longest.
16
+ * One part of an arc. It is a voice, or several layered together that play as one and last as
17
+ * long as the longest.
18
18
  *
19
19
  * @category score
20
20
  */
21
21
  export type ArcPart<I, O, H = unknown> = ArcVoice<I, O, H> | readonly ArcVoice<I, O, H>[];
22
22
  /**
23
- * What `arc` takes: an owner over three parts that hand over in order, `enter`, `active` and
24
- * `exit`, any of which may be left out.
23
+ * What `arc` takes. It is an owner over three parts that hand over in order, `enter`, `active`
24
+ * and `exit`, any of which may be left out.
25
25
  *
26
26
  * @category score
27
27
  */
@@ -33,22 +33,23 @@ export interface ArcSpec<I, O, H = unknown> extends Omit<OwnerSpec<I, H>, 'freez
33
33
  /** What plays as it leaves. Its start is the arc's `out` mark, and its end the arc's `end`. */
34
34
  exit?: ArcPart<I, O, H>;
35
35
  /**
36
- * How long `active` plays, ms on the arc's clock, looping for it unless its `loop` says how many
37
- * passes; or `'open'`, until `release`. Default: `active`'s own length, held open where it loops
38
- * for good, and 0 with no `active`.
36
+ * How long `active` plays, ms on the arc's clock, or `'open'`. A number loops `active` for it
37
+ * unless its `loop` says how many passes; `'open'` plays it until `release`. Default: `active`'s
38
+ * own length, held open where it loops for good, and 0 with no `active`.
39
39
  */
40
40
  hold?: number | 'open';
41
41
  /** A crossfade across each boundary, ms, half before it and half after. Default 0. */
42
42
  blend?: number;
43
43
  }
44
44
  /**
45
- * An arc's handle: an owner's, and the release of its hold. `fade` takes it out with no exit.
45
+ * An arc's handle, which can release its hold. It is an owner's handle, and `release` ends the
46
+ * hold. `fade` takes it out with no exit.
46
47
  *
47
48
  * @category score
48
49
  */
49
50
  export interface ArcHandle<I = unknown> extends Handle<I> {
50
51
  /**
51
- * Ends the hold now and plays the exit, its blend starting here; where the enter is still
52
+ * Ends the hold now and plays the exit. Its blend starts here; where the enter is still
52
53
  * playing, the exit follows it. Nothing once the exit has begun or the arc is fading.
53
54
  */
54
55
  release(): void;
@@ -5,9 +5,9 @@
5
5
  */
6
6
  export interface Channel<V> {
7
7
  /**
8
- * Names this channel's arithmetic, so a patch written against one channel can be checked against
9
- * another of the same name. Two channels of one kind must fold identically; the stock ones set it,
10
- * as `'sum'` or `'vec(3, sum)'`. Absent, a channel matches only itself.
8
+ * Names this channel's arithmetic. A patch written against one channel can then be checked
9
+ * against another of the same name. Two channels of one kind must fold identically; the stock
10
+ * ones set it, as `'sum'` or `'vec(3, sum)'`. Absent, a channel matches only itself.
11
11
  */
12
12
  kind?: string;
13
13
  /**
@@ -16,21 +16,25 @@ export interface Channel<V> {
16
16
  * carries speed can push it out; overshoot stops flat at the bound.
17
17
  */
18
18
  bounds?: readonly [min: number, max: number];
19
- /** Identity. Absent means the channel has none: it replaces rather than contributes. */
19
+ /**
20
+ * The value that changes nothing when folded in, such as 0 for `sum` or 1 for `mul`. Absent means
21
+ * the channel has none: it replaces rather than contributes.
22
+ */
20
23
  rest?: V;
21
24
  /** Fold two contributions into one. */
22
25
  merge(a: V, b: V): V;
23
26
  /** Fade toward `rest` by weight 0..1. Required when `rest` is set; absent otherwise. */
24
27
  scale?(v: V, w: number): V;
25
- /** Interpolate, for retargeting, for blending alternatives, and for folding a locus. */
28
+ /** Interpolate, for retargeting, for blending alternatives, and for folding a role. */
26
29
  lerp(a: V, b: V, u: number): V;
27
30
  /**
28
- * Optional: `merge(into, scale(v, w))`, written into `into` and returned, so a channel whose
29
- * values are objects need not allocate per contribution. The mix only hands it a value it made.
31
+ * Folds a weighted contribution into `into` in place. Optional. It computes
32
+ * `merge(into, scale(v, w))`, written into `into` and returned, so a channel whose values are
33
+ * objects need not allocate per contribution. The mix only hands it a value it made.
30
34
  */
31
35
  fold?(into: V, v: V, w: number): V;
32
36
  /**
33
- * Optional: a fresh copy of `v`, which the mix makes of `rest` for `fold` to write into. The mix
37
+ * A fresh copy of `v`. Optional. The mix makes one of `rest` for `fold` to write into. The mix
34
38
  * copies arrays, typed arrays and plain objects itself; a channel whose `rest` is anything else,
35
39
  * such as a class instance, and that has `fold`, needs this or `cue` refuses it.
36
40
  */