@msb235/blits 0.14.0 → 0.15.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 (187) hide show
  1. package/CHANGELOG.md +198 -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 +37 -14
  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.d.ts +2 -1
  23. package/dist/columns.js +62 -38
  24. package/dist/contribution.d.ts +30 -0
  25. package/dist/contribution.js +374 -0
  26. package/dist/copyout.d.ts +10 -0
  27. package/dist/copyout.js +69 -24
  28. package/dist/crowd.d.ts +16 -6
  29. package/dist/crowd.js +20 -11
  30. package/dist/cue.d.ts +8 -1
  31. package/dist/cue.js +39 -13
  32. package/dist/cut.d.ts +8 -0
  33. package/dist/cut.js +4 -0
  34. package/dist/delay.d.ts +3 -0
  35. package/dist/delay.js +7 -0
  36. package/dist/drop.d.ts +9 -0
  37. package/dist/drop.js +84 -0
  38. package/dist/due.d.ts +24 -5
  39. package/dist/due.js +114 -34
  40. package/dist/easing.d.ts +6 -4
  41. package/dist/easing.js +7 -3
  42. package/dist/everyone.d.ts +8 -2
  43. package/dist/everyone.js +33 -3
  44. package/dist/fade.d.ts +2 -1
  45. package/dist/fade.js +2 -1
  46. package/dist/fill.d.ts +3 -2
  47. package/dist/fill.js +52 -20
  48. package/dist/fit.d.ts +44 -26
  49. package/dist/fit.js +10 -9
  50. package/dist/fold.d.ts +4 -37
  51. package/dist/fold.js +5 -513
  52. package/dist/gather.d.ts +12 -7
  53. package/dist/gather.js +179 -44
  54. package/dist/gone.js +2 -2
  55. package/dist/grid.d.ts +47 -0
  56. package/dist/grid.js +247 -0
  57. package/dist/handle.d.ts +2 -0
  58. package/dist/handle.js +14 -8
  59. package/dist/held.d.ts +2 -1
  60. package/dist/held.js +2 -1
  61. package/dist/history.d.ts +6 -5
  62. package/dist/history.js +7 -9
  63. package/dist/hosts.js +9 -15
  64. package/dist/index.d.ts +5 -4
  65. package/dist/keyfill.d.ts +1 -1
  66. package/dist/keyfill.js +5 -3
  67. package/dist/keyrows.d.ts +12 -0
  68. package/dist/keyrows.js +99 -12
  69. package/dist/lane.d.ts +38 -11
  70. package/dist/lane.js +46 -11
  71. package/dist/lanes.d.ts +30 -12
  72. package/dist/lanes.js +56 -36
  73. package/dist/leavings.d.ts +2 -2
  74. package/dist/leavings.js +1 -1
  75. package/dist/lives.d.ts +47 -0
  76. package/dist/lives.js +180 -0
  77. package/dist/meet.d.ts +2 -2
  78. package/dist/meet.js +95 -7
  79. package/dist/mixer.d.ts +56 -37
  80. package/dist/mixer.js +57 -171
  81. package/dist/motion.d.ts +14 -118
  82. package/dist/motion.js +16 -8
  83. package/dist/motions.d.ts +62 -155
  84. package/dist/motions.js +56 -370
  85. package/dist/moved.d.ts +1 -1
  86. package/dist/moved.js +16 -7
  87. package/dist/named.d.ts +6 -2
  88. package/dist/named.js +49 -3
  89. package/dist/numbers.d.ts +7 -0
  90. package/dist/numbers.js +33 -0
  91. package/dist/owed.d.ts +2 -0
  92. package/dist/owed.js +4 -0
  93. package/dist/pack.d.ts +2 -1
  94. package/dist/pack.js +2 -3
  95. package/dist/patch.d.ts +7 -3
  96. package/dist/patch.js +6 -2
  97. package/dist/places.d.ts +53 -0
  98. package/dist/places.js +171 -0
  99. package/dist/plot.d.ts +12 -0
  100. package/dist/plot.js +52 -0
  101. package/dist/project.d.ts +4 -4
  102. package/dist/project.js +9 -212
  103. package/dist/pull.js +22 -9
  104. package/dist/qualify.js +93 -31
  105. package/dist/reading.d.ts +6 -0
  106. package/dist/reading.js +5 -0
  107. package/dist/record.d.ts +5 -1
  108. package/dist/record.js +3 -2
  109. package/dist/relink.d.ts +1 -1
  110. package/dist/renumber.d.ts +10 -0
  111. package/dist/renumber.js +75 -0
  112. package/dist/restored.d.ts +2 -2
  113. package/dist/restored.js +1 -1
  114. package/dist/rests.d.ts +9 -0
  115. package/dist/rests.js +76 -0
  116. package/dist/revive.d.ts +3 -2
  117. package/dist/revive.js +2 -2
  118. package/dist/{locus.d.ts → role.d.ts} +10 -9
  119. package/dist/{locus.js → role.js} +3 -3
  120. package/dist/roles.d.ts +10 -0
  121. package/dist/roles.js +158 -0
  122. package/dist/roster.js +3 -3
  123. package/dist/rotation.d.ts +1 -1
  124. package/dist/rotation.js +1 -1
  125. package/dist/rows.js +28 -20
  126. package/dist/sample.d.ts +2 -2
  127. package/dist/sample.js +33 -7
  128. package/dist/seat.d.ts +17 -0
  129. package/dist/seat.js +25 -0
  130. package/dist/seek.js +5 -5
  131. package/dist/setting.d.ts +27 -0
  132. package/dist/setting.js +55 -0
  133. package/dist/shared.d.ts +1 -1
  134. package/dist/shared.js +1 -1
  135. package/dist/signals.d.ts +64 -32
  136. package/dist/signals.js +20 -18
  137. package/dist/stack.d.ts +5 -5
  138. package/dist/stack.js +5 -5
  139. package/dist/standing.d.ts +2 -1
  140. package/dist/standing.js +3 -2
  141. package/dist/store.d.ts +9 -0
  142. package/dist/store.js +24 -0
  143. package/dist/strays.d.ts +2 -1
  144. package/dist/strays.js +23 -15
  145. package/dist/stretch.d.ts +112 -0
  146. package/dist/stretch.js +9 -0
  147. package/dist/subject.d.ts +142 -0
  148. package/dist/subject.js +1 -0
  149. package/dist/tape.d.ts +9 -5
  150. package/dist/tape.js +5 -1
  151. package/dist/then.d.ts +9 -0
  152. package/dist/then.js +57 -0
  153. package/dist/ticker.d.ts +4 -4
  154. package/dist/trace.d.ts +4 -0
  155. package/dist/trace.js +255 -0
  156. package/dist/transport.d.ts +0 -8
  157. package/dist/transport.js +0 -4
  158. package/dist/turns.d.ts +4 -3
  159. package/dist/turns.js +4 -3
  160. package/dist/types/arc.d.ts +12 -11
  161. package/dist/types/channel.d.ts +12 -8
  162. package/dist/types/history.d.ts +35 -19
  163. package/dist/types/mix.d.ts +237 -163
  164. package/dist/types/motion.d.ts +151 -0
  165. package/dist/types/motion.js +1 -0
  166. package/dist/types/patch.d.ts +67 -34
  167. package/dist/types/place.d.ts +51 -36
  168. package/dist/types/trace.d.ts +51 -0
  169. package/dist/types/trace.js +1 -0
  170. package/dist/types/transport.d.ts +20 -18
  171. package/dist/types/voice.d.ts +144 -73
  172. package/dist/types/watch.d.ts +88 -40
  173. package/dist/types.d.ts +2 -0
  174. package/dist/unreached.d.ts +2 -0
  175. package/dist/unreached.js +7 -0
  176. package/dist/voice.d.ts +10 -143
  177. package/dist/voice.js +37 -82
  178. package/dist/warn.d.ts +2 -0
  179. package/dist/warn.js +1 -1
  180. package/dist/watch.d.ts +2 -2
  181. package/dist/watch.js +5 -3
  182. package/dist/wave.d.ts +4 -3
  183. package/dist/wave.js +3 -2
  184. package/dist/weigh.d.ts +7 -1
  185. package/dist/weigh.js +27 -0
  186. package/docs/schema.html +223 -34
  187. package/package.json +2 -2
package/dist/strays.js CHANGED
@@ -1,6 +1,7 @@
1
+ import { delayOf } from './delay.js';
1
2
  import { unpart } from './fade.js';
2
3
  import { pageOut } from './paging.js';
3
- import { record, unplayable } from './tape.js';
4
+ import { record, taping, unplayable } from './tape.js';
4
5
  /** Notes a motion patch that may hold state for a subject no voice playing it reaches. */
5
6
  export function stray(mix, motion, subject) {
6
7
  const list = mix.strays.get(subject);
@@ -24,7 +25,7 @@ export function unplay(mix, voice) {
24
25
  if (voice.named === null)
25
26
  mix.strayAll.add(motion);
26
27
  else
27
- for (const subject of voice.named)
28
+ for (const subject of voice.named.list)
28
29
  stray(mix, motion, subject);
29
30
  }
30
31
  /**
@@ -45,19 +46,14 @@ export function motionOwner(mix) {
45
46
  seq() {
46
47
  return mix.deref()?.transport.seq ?? Number.NaN;
47
48
  },
49
+ early() {
50
+ const m = mix.deref();
51
+ return m !== undefined && (m.syncing || !m.looked);
52
+ },
48
53
  changed(id, motion, subject, change) {
49
54
  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
- });
55
+ if (m !== undefined && taping(m))
56
+ recordChange(m, id, motion, subject, change);
61
57
  },
62
58
  page(id, stream, subject, out) {
63
59
  const m = mix.deref();
@@ -80,10 +76,22 @@ export function motionOwner(mix) {
80
76
  return Number.NaN;
81
77
  unpart(m, v, subject);
82
78
  // Its record is gone until it is next read, so its stagger is asked here as it will be there.
83
- return timeIn(m, v, v.spec.stagger ? v.spec.stagger(subject) : 0);
79
+ return timeIn(m, v, delayOf(v, subject));
84
80
  },
85
81
  };
86
82
  }
83
+ // Apart from `changed`, whose body would otherwise make this closure's context on every change.
84
+ function recordChange(m, id, motion, subject, change) {
85
+ record(m, 'motion', (stage) => {
86
+ const to = stage.mix(m);
87
+ if (to === undefined)
88
+ return;
89
+ if (to !== m)
90
+ return changeAhead(to, id, motion, subject, change);
91
+ const v = cuedById(m, id) ?? m.gone.find((g) => g.id === id);
92
+ (v?.motion ?? motion).change(subject, { ...change });
93
+ });
94
+ }
87
95
  /**
88
96
  * A retarget or push the tape holds, made for a read ahead: kept on its transport for the patch
89
97
  * to apply as it reads, since the patch's own state is the live mix's.
@@ -100,7 +108,7 @@ function changeAhead(to, id, motion, given, change) {
100
108
  unpart(to, v, subject);
101
109
  if (at === undefined) {
102
110
  const frame = frameOf(to, v, subject);
103
- const back = parted ? timeIn(to, v, v.spec.stagger ? v.spec.stagger(subject) : 0) : frame;
111
+ const back = parted ? timeIn(to, v, delayOf(v, subject)) : frame;
104
112
  if (!Number.isNaN(frame))
105
113
  at = frame;
106
114
  else if (!Number.isNaN(back))
@@ -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
  /**
@@ -0,0 +1,4 @@
1
+ import type { Mixer } from './mixer.js';
2
+ import type { Trace, TraceOptions } from './types.js';
3
+ /** `mix.trace`: see `Mix.trace`. */
4
+ export declare function traceMix<I, O>(mix: Mixer<I, O>, from: number, to: number, opts?: TraceOptions): Trace<I, O>;