@msb235/blits 0.15.0 → 0.16.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.
- package/CHANGELOG.md +79 -0
- package/README.md +1 -1
- package/dist/ahead.js +5 -4
- package/dist/bare.js +22 -7
- package/dist/chain.js +2 -3
- package/dist/color.d.ts +36 -14
- package/dist/color.js +186 -58
- package/dist/columns.d.ts +3 -12
- package/dist/columns.js +56 -41
- package/dist/crowd.d.ts +8 -10
- package/dist/crowd.js +17 -18
- package/dist/cue.js +7 -4
- package/dist/delay.d.ts +3 -0
- package/dist/delay.js +7 -0
- package/dist/due.js +1 -1
- package/dist/easing.d.ts +2 -0
- package/dist/easing.js +4 -0
- package/dist/everyone.d.ts +22 -6
- package/dist/everyone.js +47 -8
- package/dist/fade.d.ts +11 -0
- package/dist/fade.js +44 -8
- package/dist/fill.js +1 -1
- package/dist/fold.js +4 -7
- package/dist/held.js +5 -5
- package/dist/hosts.d.ts +7 -0
- package/dist/hosts.js +18 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/lane.d.ts +2 -5
- package/dist/lane.js +14 -10
- package/dist/lanes.d.ts +33 -5
- package/dist/lanes.js +34 -28
- package/dist/lch.d.ts +23 -0
- package/dist/lch.js +126 -0
- package/dist/meet.js +5 -3
- package/dist/mixer.d.ts +6 -2
- package/dist/mixer.js +7 -0
- package/dist/motions.d.ts +4 -1
- package/dist/motions.js +16 -2
- package/dist/move.js +15 -10
- package/dist/named.d.ts +6 -1
- package/dist/named.js +29 -1
- package/dist/numbers.d.ts +5 -0
- package/dist/numbers.js +29 -0
- package/dist/owner.d.ts +7 -2
- package/dist/owner.js +13 -3
- package/dist/project.js +3 -8
- package/dist/pull.d.ts +11 -0
- package/dist/pull.js +18 -4
- package/dist/qualify.js +10 -11
- package/dist/renumber.d.ts +10 -0
- package/dist/renumber.js +75 -0
- package/dist/roles.js +1 -3
- package/dist/roster.d.ts +6 -0
- package/dist/roster.js +8 -1
- package/dist/rows.js +27 -19
- package/dist/sample.js +2 -1
- package/dist/seat.d.ts +17 -0
- package/dist/seat.js +25 -0
- package/dist/seek.js +1 -13
- package/dist/shared.d.ts +1 -1
- package/dist/shared.js +1 -1
- package/dist/spans.d.ts +4 -1
- package/dist/spans.js +6 -3
- package/dist/strays.js +3 -2
- package/dist/touch.js +1 -2
- package/dist/trace.d.ts +4 -0
- package/dist/trace.js +255 -0
- package/dist/turns.js +2 -1
- package/dist/types/mix.d.ts +15 -0
- package/dist/types/trace.d.ts +51 -0
- package/dist/types/trace.js +1 -0
- package/dist/types/voice.d.ts +13 -7
- package/dist/types.d.ts +1 -0
- package/dist/unreached.d.ts +2 -0
- package/dist/unreached.js +7 -0
- package/dist/voice.d.ts +22 -0
- package/dist/voice.js +44 -4
- package/docs/schema.html +48 -11
- package/package.json +1 -1
package/dist/columns.js
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
for (let i = at; i < at + n; i++) {
|
|
3
|
-
const x = out[i];
|
|
4
|
-
out[i] = x < lo ? lo : x > hi ? hi : x;
|
|
5
|
-
}
|
|
6
|
-
}
|
|
1
|
+
import { clampRun } from './pull.js';
|
|
7
2
|
/**
|
|
8
3
|
* For a `pull` of a list it read last time in the same order, with every voice on a lane, where
|
|
9
4
|
* each position's remembered chain head was current when the mix's `relinks` read `since`: what
|
|
@@ -26,15 +21,8 @@ export function pullRun(lanes, slots, list, was, since, from, columns, now, vers
|
|
|
26
21
|
// Nothing in `pullRun` makes a subject owe a voice, so one with nobody owing need not ask.
|
|
27
22
|
const owing = lanes.owed.any();
|
|
28
23
|
const current = since === Number.POSITIVE_INFINITY;
|
|
29
|
-
|
|
30
|
-
flush(lanes);
|
|
31
|
-
lanes.queuedFor = columns;
|
|
32
|
-
}
|
|
24
|
+
queueFor(lanes, columns, slots);
|
|
33
25
|
room(lanes, lanes.queued + list.length - from);
|
|
34
|
-
const qSlots = lanes.queueSlots;
|
|
35
|
-
const qRows = lanes.queueRows;
|
|
36
|
-
const qCounts = lanes.queueCounts;
|
|
37
|
-
let k = lanes.queued;
|
|
38
26
|
let n = from;
|
|
39
27
|
// The run being gathered: its first slot and row, and how far it has reached.
|
|
40
28
|
let first = -1;
|
|
@@ -60,23 +48,14 @@ export function pullRun(lanes, slots, list, was, since, from, columns, now, vers
|
|
|
60
48
|
if (holds)
|
|
61
49
|
subjects[slot] = subject;
|
|
62
50
|
if (slot !== first + (n - start)) {
|
|
63
|
-
if (first >= 0)
|
|
64
|
-
|
|
65
|
-
qRows[k] = start;
|
|
66
|
-
qCounts[k] = n - start;
|
|
67
|
-
k++;
|
|
68
|
-
}
|
|
51
|
+
if (first >= 0)
|
|
52
|
+
add(lanes, first, start, n - start);
|
|
69
53
|
first = slot;
|
|
70
54
|
start = n;
|
|
71
55
|
}
|
|
72
56
|
}
|
|
73
|
-
if (first >= 0)
|
|
74
|
-
|
|
75
|
-
qRows[k] = start;
|
|
76
|
-
qCounts[k] = n - start;
|
|
77
|
-
k++;
|
|
78
|
-
}
|
|
79
|
-
lanes.queued = k;
|
|
57
|
+
if (first >= 0)
|
|
58
|
+
add(lanes, first, start, n - start);
|
|
80
59
|
if (n > from && holds)
|
|
81
60
|
lanes.holding = true;
|
|
82
61
|
return n;
|
|
@@ -85,24 +64,43 @@ export function pullRun(lanes, slots, list, was, since, from, columns, now, vers
|
|
|
85
64
|
* Queues a subject's values for each column at subject `n`'s places, for a `pull` that reads
|
|
86
65
|
* from the lanes while every voice is on one; `flush` writes what is queued, column by column. A
|
|
87
66
|
* channel no lane holds is at rest. Anything queued is written before the lanes fill again.
|
|
67
|
+
* `slots` holds each row's lane slot, `slot` among them.
|
|
88
68
|
*/
|
|
89
|
-
export function writeLater(lanes, slot, columns, n) {
|
|
90
|
-
|
|
69
|
+
export function writeLater(lanes, slot, columns, n, slots) {
|
|
70
|
+
queueFor(lanes, columns, slots);
|
|
71
|
+
add(lanes, slot, n, 1);
|
|
91
72
|
}
|
|
92
|
-
/**
|
|
93
|
-
function
|
|
94
|
-
if (columns
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
73
|
+
/** Writes what is queued for other columns or another array of slots before queuing for these. */
|
|
74
|
+
function queueFor(lanes, columns, slots) {
|
|
75
|
+
if (columns === lanes.queuedFor && slots === lanes.queueFrom)
|
|
76
|
+
return;
|
|
77
|
+
flush(lanes);
|
|
78
|
+
lanes.queuedFor = columns;
|
|
79
|
+
lanes.queueFrom = slots;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The shortest run `flush` copies as a block from consecutive slots. A shorter one, as a list kept
|
|
83
|
+
* dense by swap-remove leaves its slots, joins the rows before it in one run whose slots `flush`
|
|
84
|
+
* reads row by row, so a run's cost is paid once a stretch of rows rather than once a few.
|
|
85
|
+
*/
|
|
86
|
+
const BLOCK = 16;
|
|
87
|
+
/** Queues `count` rows from `row`, whose slots follow one apart from `slot`. */
|
|
88
|
+
function add(lanes, slot, row, count) {
|
|
98
89
|
const k = lanes.queued;
|
|
99
90
|
if (k > 0) {
|
|
100
91
|
const last = k - 1;
|
|
101
92
|
const had = lanes.queueCounts[last];
|
|
102
|
-
if (
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
93
|
+
if (row === lanes.queueRows[last] + had) {
|
|
94
|
+
const first = lanes.queueSlots[last];
|
|
95
|
+
if (first >= 0 && slot === first + had) {
|
|
96
|
+
lanes.queueCounts[last] = had + count;
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (count < BLOCK && (first < 0 || had < BLOCK)) {
|
|
100
|
+
lanes.queueSlots[last] = -1;
|
|
101
|
+
lanes.queueCounts[last] = had + count;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
106
104
|
}
|
|
107
105
|
}
|
|
108
106
|
room(lanes, k + 1);
|
|
@@ -173,16 +171,33 @@ function rests(lanes, c, runs) {
|
|
|
173
171
|
}
|
|
174
172
|
/** The longest run of values `copies` copies itself: `set` takes a view, an object a run. */
|
|
175
173
|
const VIEWED = 256;
|
|
176
|
-
/** Copies a laned channel's values for every queued run into its rows. */
|
|
174
|
+
/** Copies a laned channel's values for every queued run into its rows, a block or row by row. */
|
|
177
175
|
function copies(lanes, c, values, runs) {
|
|
178
176
|
const slots = lanes.queueSlots;
|
|
179
177
|
const rows = lanes.queueRows;
|
|
180
178
|
const counts = lanes.queueCounts;
|
|
181
179
|
const out = c.out;
|
|
182
180
|
const axes = c.axes;
|
|
181
|
+
const from = lanes.queueFrom;
|
|
183
182
|
for (let r = 0; r < runs; r++) {
|
|
183
|
+
const first = slots[r];
|
|
184
|
+
if (first < 0) {
|
|
185
|
+
const row = rows[r];
|
|
186
|
+
const end = row + counts[r];
|
|
187
|
+
if (axes === 1)
|
|
188
|
+
for (let i = row; i < end; i++)
|
|
189
|
+
out[i] = values[from[i]];
|
|
190
|
+
else
|
|
191
|
+
for (let i = row; i < end; i++) {
|
|
192
|
+
const at = i * axes;
|
|
193
|
+
const base = from[i] * axes;
|
|
194
|
+
for (let a = 0; a < axes; a++)
|
|
195
|
+
out[at + a] = values[base + a];
|
|
196
|
+
}
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
184
199
|
const at = rows[r] * axes;
|
|
185
|
-
const base =
|
|
200
|
+
const base = first * axes;
|
|
186
201
|
const span = counts[r] * axes;
|
|
187
202
|
if (span > VIEWED)
|
|
188
203
|
out.set(values.subarray(base, base + span), at);
|
package/dist/crowd.d.ts
CHANGED
|
@@ -6,12 +6,6 @@ import type { Motions } from './motions.js';
|
|
|
6
6
|
import type { Scratch } from './patch.js';
|
|
7
7
|
import type { Subject } from './subject.js';
|
|
8
8
|
import type { Voice } from './voice.js';
|
|
9
|
-
/**
|
|
10
|
-
* Whether a laned voice belongs in a crowd: one naming a single subject, which shares nothing
|
|
11
|
-
* across subjects for a lane to save. A motion voice writes one channel; a keys or fn voice may
|
|
12
|
-
* write several, and joins the crowd of voices writing those same channels.
|
|
13
|
-
*/
|
|
14
|
-
export declare function crowdable<I, O>(v: Voice<I, O>): boolean;
|
|
15
9
|
/** The law of a row that has none, a keys or fn voice's. */
|
|
16
10
|
export declare const none: Float64Array<ArrayBuffer>;
|
|
17
11
|
/** Per row of a crowd's `hot`: what the fill reads of the row's voice and its current stretch. */
|
|
@@ -25,10 +19,15 @@ export declare const enum Hot {
|
|
|
25
19
|
SEEKS = 5,
|
|
26
20
|
EPOCH = 6,
|
|
27
21
|
ID = 7,
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
/**
|
|
23
|
+
* A `Flag.READY` row's mix time from which its tween has landed, so a fill folds its `to` as it
|
|
24
|
+
* stands; Infinity until `bareRows` sees it land at a positive rate. Unread on any other row.
|
|
25
|
+
*/
|
|
26
|
+
LANDED = 8,
|
|
27
|
+
AT = 9,
|
|
28
|
+
MS = 10,
|
|
30
29
|
/** `x0`, `v0` and `to`, `axes` numbers each. */
|
|
31
|
-
X0 =
|
|
30
|
+
X0 = 11
|
|
32
31
|
}
|
|
33
32
|
/** A crowd row's flags, at `Hot.FLAGS`. */
|
|
34
33
|
export declare const enum Flag {
|
|
@@ -86,7 +85,6 @@ export declare class Crowd<I, O> implements Positions<I, O> {
|
|
|
86
85
|
eases: (Curve | undefined)[];
|
|
87
86
|
/** Each row's patch law, one array shared by every row whose law is the same. */
|
|
88
87
|
laws: Float64Array[];
|
|
89
|
-
readonly rowOf: Map<number, number>;
|
|
90
88
|
idle: boolean;
|
|
91
89
|
readonly line: {
|
|
92
90
|
stop: number;
|
package/dist/crowd.js
CHANGED
|
@@ -2,19 +2,8 @@ import { bareRows, clock, unbare } from './bare.js';
|
|
|
2
2
|
import { clampWeight, passAt, phaseAt, weighed } from './clock.js';
|
|
3
3
|
import { closed } from './closed.js';
|
|
4
4
|
import { KeyRows } from './keyrows.js';
|
|
5
|
-
import {
|
|
5
|
+
import { keepProbed, SPARSE } from './lane.js';
|
|
6
6
|
import { move } from './sample.js';
|
|
7
|
-
/**
|
|
8
|
-
* Whether a laned voice belongs in a crowd: one naming a single subject, which shares nothing
|
|
9
|
-
* across subjects for a lane to save. A motion voice writes one channel; a keys or fn voice may
|
|
10
|
-
* write several, and joins the crowd of voices writing those same channels.
|
|
11
|
-
*/
|
|
12
|
-
export function crowdable(v) {
|
|
13
|
-
return (v.named !== null &&
|
|
14
|
-
v.named.size === 1 &&
|
|
15
|
-
v.spec.role === undefined &&
|
|
16
|
-
(v.slots.length === 1 || v.motion === undefined));
|
|
17
|
-
}
|
|
18
7
|
/** The law of a row that has none, a keys or fn voice's. */
|
|
19
8
|
export const none = new Float64Array(0);
|
|
20
9
|
/** Whether a row's flags let `bareRows` take it. */
|
|
@@ -45,7 +34,6 @@ export class Crowd {
|
|
|
45
34
|
eases = [];
|
|
46
35
|
/** Each row's patch law, one array shared by every row whose law is the same. */
|
|
47
36
|
laws = [];
|
|
48
|
-
rowOf = new Map();
|
|
49
37
|
idle = false;
|
|
50
38
|
line = SPARSE.other;
|
|
51
39
|
/** Where the fill now under way has reached. */
|
|
@@ -69,7 +57,7 @@ export class Crowd {
|
|
|
69
57
|
constructor(chans, axes) {
|
|
70
58
|
this.chans = chans;
|
|
71
59
|
this.axes = axes;
|
|
72
|
-
this.stride =
|
|
60
|
+
this.stride = 11 /* Hot.X0 */ + 3 * axes;
|
|
73
61
|
this.xs = new Float64Array(axes);
|
|
74
62
|
this.vs = new Float64Array(axes);
|
|
75
63
|
}
|
|
@@ -218,8 +206,19 @@ function rows(lanes, c, first, id) {
|
|
|
218
206
|
const voice = c.voices[p];
|
|
219
207
|
const elapsedNow = fast ? clock(hot, h, now) : voice.elapsedAt(now);
|
|
220
208
|
let elapsed = elapsedNow - delay;
|
|
209
|
+
// Its freezes applied as `one` applies them, written out: a function for it stays out of line.
|
|
221
210
|
if ((f & 256 /* Flag.FREEZES */) !== 0)
|
|
222
|
-
elapsed =
|
|
211
|
+
elapsed = !(elapsed >= 0)
|
|
212
|
+
? voice.freezesBefore
|
|
213
|
+
? 0
|
|
214
|
+
: Number.NaN
|
|
215
|
+
: elapsed > voice.span
|
|
216
|
+
? voice.hidesPast
|
|
217
|
+
? Number.NaN
|
|
218
|
+
: voice.freezesAfter
|
|
219
|
+
? voice.span
|
|
220
|
+
: elapsed
|
|
221
|
+
: elapsed;
|
|
223
222
|
if (!(elapsed >= 0)) {
|
|
224
223
|
data[o + 2 /* Row.WEIGHT */] = 0;
|
|
225
224
|
continue;
|
|
@@ -244,7 +243,7 @@ function rows(lanes, c, first, id) {
|
|
|
244
243
|
data[o + 2 /* Row.WEIGHT */] = w;
|
|
245
244
|
if ((f & 512 /* Flag.FLAT */) !== 0) {
|
|
246
245
|
if (w > 0)
|
|
247
|
-
c.keys.fold(hot[h +
|
|
246
|
+
c.keys.fold(hot[h + 9 /* Hot.AT */], phaseAt(elapsed, hot[h + 11 /* Hot.X0 */], hot[h + 10 /* Hot.MS */]), c.chans, slot, w);
|
|
248
247
|
continue;
|
|
249
248
|
}
|
|
250
249
|
arg[1 /* Arg.ELAPSED */] = elapsed;
|
|
@@ -274,7 +273,7 @@ function rows(lanes, c, first, id) {
|
|
|
274
273
|
c.restale(p, hot[h + 0 /* Hot.FLAGS */]);
|
|
275
274
|
continue;
|
|
276
275
|
}
|
|
277
|
-
closed(c.laws[p], c.eases[p], n, hot[h +
|
|
276
|
+
closed(c.laws[p], c.eases[p], n, hot[h + 9 /* Hot.AT */], hot[h + 10 /* Hot.MS */], hot, h + 11 /* Hot.X0 */, hot, h + 11 /* Hot.X0 */ + n, hot, h + 11 /* Hot.X0 */ + 2 * n, elapsed, xs, vs);
|
|
278
277
|
for (let a = 0; a < n; a++)
|
|
279
278
|
samples[p * n + a] = xs[a];
|
|
280
279
|
if (c.deltas[p] !== null)
|
|
@@ -371,7 +370,7 @@ function copyStretch(c, p, ms) {
|
|
|
371
370
|
const h = p * c.stride;
|
|
372
371
|
let f = c.hot[h + 0 /* Hot.FLAGS */] & ~(4 /* Flag.STALE */ | 8 /* Flag.BARE */ | 32 /* Flag.FOLDS */);
|
|
373
372
|
const ch = c.chans[0];
|
|
374
|
-
if (run.n === c.axes && run.stretchInto(ms, c.hot, h +
|
|
373
|
+
if (run.n === c.axes && run.stretchInto(ms, c.hot, h + 9 /* Hot.AT */)) {
|
|
375
374
|
f |= 8 /* Flag.BARE */;
|
|
376
375
|
if (run.scalar(ms) === ch.scalar && ch.plain)
|
|
377
376
|
f |= 32 /* Flag.FOLDS */;
|
package/dist/cue.js
CHANGED
|
@@ -3,8 +3,8 @@ import { checkHits } from './book.js';
|
|
|
3
3
|
import { bind, checkWithin } from './bound.js';
|
|
4
4
|
import { changed } from './chain.js';
|
|
5
5
|
import { copyable } from './clone.js';
|
|
6
|
+
import { roundsHue } from './color.js';
|
|
6
7
|
import { schedule } from './due.js';
|
|
7
|
-
import { shares } from './everyone.js';
|
|
8
8
|
import { finiteRate, plainWeight, VoiceHandle } from './handle.js';
|
|
9
9
|
import { begin } from './held.js';
|
|
10
10
|
import { handle } from './hosts.js';
|
|
@@ -158,11 +158,14 @@ export function playable(mix, spec) {
|
|
|
158
158
|
const motion = motionOf(patch);
|
|
159
159
|
if (motion !== undefined) {
|
|
160
160
|
const channel = patch.writes[0];
|
|
161
|
-
const
|
|
161
|
+
const ch = mix.kit[channel];
|
|
162
|
+
const rest = ch.rest;
|
|
162
163
|
if (typeof rest === 'number')
|
|
163
164
|
motion.cuedOn(String(channel), true);
|
|
164
165
|
else if (Array.isArray(rest) || ArrayBuffer.isView(rest))
|
|
165
|
-
motion.cuedOn(String(channel), false);
|
|
166
|
+
motion.cuedOn(String(channel), false, roundsHue(ch));
|
|
167
|
+
else if (roundsHue(ch))
|
|
168
|
+
motion.cuedOn(String(channel), false, true);
|
|
166
169
|
}
|
|
167
170
|
if (patch.reads) {
|
|
168
171
|
const host = mix.opts.host;
|
|
@@ -250,7 +253,7 @@ function enter(mix, voice) {
|
|
|
250
253
|
i--;
|
|
251
254
|
cued.splice(i, 0, voice);
|
|
252
255
|
scoredAdd(mix, voice);
|
|
253
|
-
voice.sharing = shares(mix, voice);
|
|
256
|
+
voice.sharing = mix.share?.shares(mix, voice) === true;
|
|
254
257
|
enlist(mix, voice);
|
|
255
258
|
changed(mix, voice);
|
|
256
259
|
mix.stir();
|
package/dist/delay.d.ts
ADDED
package/dist/delay.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** A subject's `stagger` answer: as asked at cue for a voice naming its subjects, else asked now. */
|
|
2
|
+
export function delayOf(voice, subject) {
|
|
3
|
+
const known = voice.named?.delays?.get(subject);
|
|
4
|
+
if (known !== undefined)
|
|
5
|
+
return known;
|
|
6
|
+
return voice.spec.stagger ? voice.spec.stagger(subject) : 0;
|
|
7
|
+
}
|
package/dist/due.js
CHANGED
|
@@ -159,7 +159,7 @@ function dueOf(mix, voice) {
|
|
|
159
159
|
export function schedule(mix, voice) {
|
|
160
160
|
if (mix.projecting)
|
|
161
161
|
return;
|
|
162
|
-
mix.lanes?.voiceChanged(voice
|
|
162
|
+
mix.lanes?.voiceChanged(voice);
|
|
163
163
|
const token = ++voice.dueToken;
|
|
164
164
|
const due = dueOf(mix, voice);
|
|
165
165
|
if (due === Number.POSITIVE_INFINITY)
|
package/dist/easing.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ import type { Easing } from './types.js';
|
|
|
5
5
|
* @category patch
|
|
6
6
|
*/
|
|
7
7
|
export type Curve = (u: number) => number;
|
|
8
|
+
/** Whether a segment eased by `c` runs in a straight line: no easing, or `linear`. */
|
|
9
|
+
export declare function straight(c: Curve | undefined): boolean;
|
|
8
10
|
/**
|
|
9
11
|
* How fast a curve leaves 0, for bending a retarget to the speed the subject had: Infinity where
|
|
10
12
|
* the curve jumps or leaves vertically, so no finite bend can match it.
|
package/dist/easing.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
const linear = (u) => u;
|
|
2
|
+
/** Whether a segment eased by `c` runs in a straight line: no easing, or `linear`. */
|
|
3
|
+
export function straight(c) {
|
|
4
|
+
return c === undefined || c === linear;
|
|
5
|
+
}
|
|
2
6
|
/** A CSS `cubic-bezier`: solves x(t) = u for t, then reads y(t). */
|
|
3
7
|
function bezier(x1, y1, x2, y2) {
|
|
4
8
|
const cx = 3 * x1;
|
package/dist/everyone.d.ts
CHANGED
|
@@ -51,6 +51,11 @@ export declare function open<I, O>(voice: Voice<I, O>, rec: Subject<unknown>, sl
|
|
|
51
51
|
export declare function shut<I, O>(voice: Voice<I, O>, rec: Subject<unknown>, slot: number, cap: number): void;
|
|
52
52
|
/** Makes stale what a sharing voice last read for the subject numbered `slot`, as `touch` asks. */
|
|
53
53
|
export declare function restamp<I, O>(voice: Voice<I, O>, slot: number): void;
|
|
54
|
+
/**
|
|
55
|
+
* The subject numbered `from` is numbered `to` now, a number let go of: what the voice keeps for it
|
|
56
|
+
* moves along, and `from` is left as `unsight` leaves it.
|
|
57
|
+
*/
|
|
58
|
+
export declare function resight<I, O>(voice: Voice<I, O>, from: number, to: number, cap: number): void;
|
|
54
59
|
/** A subject's number was let go of: the next subject to take it is one the voice has not seen. */
|
|
55
60
|
export declare function unsight<I, O>(voice: Voice<I, O>, slot: number): void;
|
|
56
61
|
/**
|
|
@@ -60,11 +65,22 @@ export declare function unsight<I, O>(voice: Voice<I, O>, slot: number): void;
|
|
|
60
65
|
* positions take their own records now, since each held the one.
|
|
61
66
|
*/
|
|
62
67
|
export declare function unshare<I, O>(mix: Mixer<I, O>, voice: Voice<I, O>, kept?: boolean, keeper?: I): void;
|
|
63
|
-
/**
|
|
64
|
-
* Counts what makes a mix's fold more than a walk of each chain: a role, a voice sharing one
|
|
65
|
-
* record, a voice that stopped sharing this frame. Called wherever one of the three changes, so
|
|
66
|
-
* `foldWith` asks one number.
|
|
67
|
-
*/
|
|
68
|
-
export declare function detour<I, O>(mix: Mixer<I, O>): void;
|
|
69
68
|
/** Gives a record just made for a subject a sharing voice had seen what the voice kept for it. */
|
|
70
69
|
export declare function inherit<I, O>(voice: Voice<I, O>, held: Subject<unknown>, slot: number): void;
|
|
70
|
+
/** What the general path calls on a sharing voice, reached through `Lanes`, so a lean bundle leaves it out. */
|
|
71
|
+
export declare const share: {
|
|
72
|
+
shares: typeof shares;
|
|
73
|
+
outgrow: typeof outgrow;
|
|
74
|
+
everyoneOf: typeof everyoneOf;
|
|
75
|
+
sighted: typeof sighted;
|
|
76
|
+
sight: typeof sight;
|
|
77
|
+
weightAt: typeof weightAt;
|
|
78
|
+
weighAt: typeof weighAt;
|
|
79
|
+
open: typeof open;
|
|
80
|
+
shut: typeof shut;
|
|
81
|
+
restamp: typeof restamp;
|
|
82
|
+
unsight: typeof unsight;
|
|
83
|
+
unshare: typeof unshare;
|
|
84
|
+
inherit: typeof inherit;
|
|
85
|
+
};
|
|
86
|
+
export type Share = typeof share;
|
package/dist/everyone.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { headOf } from './chain.js';
|
|
2
2
|
import { numericOf } from './channels.js';
|
|
3
3
|
import { record } from './record.js';
|
|
4
|
+
import { detour } from './roster.js';
|
|
4
5
|
/**
|
|
5
6
|
* Whether a voice can keep one record for every subject, decided when it is cued. A record holds
|
|
6
7
|
* what a voice knows of one subject; where the voice is over every subject with no stagger, keeps
|
|
@@ -185,6 +186,36 @@ export function restamp(voice, slot) {
|
|
|
185
186
|
if (voice.built !== null && voice.everyone !== null)
|
|
186
187
|
voice.everyone.seeks = -1;
|
|
187
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* The subject numbered `from` is numbered `to` now, a number let go of: what the voice keeps for it
|
|
191
|
+
* moves along, and `from` is left as `unsight` leaves it.
|
|
192
|
+
*/
|
|
193
|
+
export function resight(voice, from, to, cap) {
|
|
194
|
+
if (sighted(voice, from)) {
|
|
195
|
+
const seen = voice.seen;
|
|
196
|
+
sight(voice, to, cap);
|
|
197
|
+
voice.seen = seen;
|
|
198
|
+
}
|
|
199
|
+
const w = weightAt(voice, from);
|
|
200
|
+
if (w !== 0 || (voice.weights !== null && to < voice.weights.length))
|
|
201
|
+
weighAt(voice, to, w, cap);
|
|
202
|
+
let stamps = voice.stamps;
|
|
203
|
+
const o = from * 2 /* Stamp.SIZE */;
|
|
204
|
+
if (stamps !== null && o < stamps.length) {
|
|
205
|
+
const t = to * 2 /* Stamp.SIZE */;
|
|
206
|
+
if (t >= stamps.length) {
|
|
207
|
+
const grown = new Float64Array(Math.max(to + 1, cap) * 2 /* Stamp.SIZE */).fill(Number.NaN);
|
|
208
|
+
grown.set(stamps);
|
|
209
|
+
voice.stamps = grown;
|
|
210
|
+
stamps = grown;
|
|
211
|
+
}
|
|
212
|
+
stamps[t + 0 /* Stamp.PROBED */] = stamps[o + 0 /* Stamp.PROBED */];
|
|
213
|
+
stamps[t + 1 /* Stamp.SEEKS */] = stamps[o + 1 /* Stamp.SEEKS */];
|
|
214
|
+
const deltas = voice.deltas;
|
|
215
|
+
deltas[to] = deltas[from] ?? null;
|
|
216
|
+
}
|
|
217
|
+
unsight(voice, from);
|
|
218
|
+
}
|
|
188
219
|
/** A subject's number was let go of: the next subject to take it is one the voice has not seen. */
|
|
189
220
|
export function unsight(voice, slot) {
|
|
190
221
|
const bits = voice.sighted;
|
|
@@ -233,17 +264,25 @@ export function unshare(mix, voice, kept = false, keeper) {
|
|
|
233
264
|
detour(mix);
|
|
234
265
|
mix.lanes?.refill();
|
|
235
266
|
}
|
|
236
|
-
/**
|
|
237
|
-
* Counts what makes a mix's fold more than a walk of each chain: a role, a voice sharing one
|
|
238
|
-
* record, a voice that stopped sharing this frame. Called wherever one of the three changes, so
|
|
239
|
-
* `foldWith` asks one number.
|
|
240
|
-
*/
|
|
241
|
-
export function detour(mix) {
|
|
242
|
-
mix.detours = mix.roleVoices + mix.sharers.length + (mix.unshared ? 1 : 0);
|
|
243
|
-
}
|
|
244
267
|
/** Gives a record just made for a subject a sharing voice had seen what the voice kept for it. */
|
|
245
268
|
export function inherit(voice, held, slot) {
|
|
246
269
|
held.weight = weightAt(voice, slot);
|
|
247
270
|
open(voice, held, slot);
|
|
248
271
|
unsight(voice, slot);
|
|
249
272
|
}
|
|
273
|
+
/** What the general path calls on a sharing voice, reached through `Lanes`, so a lean bundle leaves it out. */
|
|
274
|
+
export const share = {
|
|
275
|
+
shares,
|
|
276
|
+
outgrow,
|
|
277
|
+
everyoneOf,
|
|
278
|
+
sighted,
|
|
279
|
+
sight,
|
|
280
|
+
weightAt,
|
|
281
|
+
weighAt,
|
|
282
|
+
open,
|
|
283
|
+
shut,
|
|
284
|
+
restamp,
|
|
285
|
+
unsight,
|
|
286
|
+
unshare,
|
|
287
|
+
inherit,
|
|
288
|
+
};
|
package/dist/fade.d.ts
CHANGED
|
@@ -30,7 +30,13 @@ export declare function beginFade<I, O>(mix: Mixer<I, O>, voice: Voice<I, O>, op
|
|
|
30
30
|
at?: 'rest';
|
|
31
31
|
deadline?: number;
|
|
32
32
|
back?: boolean;
|
|
33
|
+
stays?: boolean;
|
|
33
34
|
}, at?: number): void;
|
|
35
|
+
/**
|
|
36
|
+
* Keeps a voice faded at the end of its passes with its owner, live and quiet, rather than letting
|
|
37
|
+
* it leave; the owner leaves at `at` if it holds no child still playing.
|
|
38
|
+
*/
|
|
39
|
+
export declare function stay<I, O>(mix: Mixer<I, O>, voice: Voice<I, O>, at: number): void;
|
|
34
40
|
/**
|
|
35
41
|
* Turns a fading voice around: it climbs back from where its fade out had got to, up the same
|
|
36
42
|
* curve, at the whole curve per `over` ms. A fade waiting for rest is taken back at once. A voice
|
|
@@ -44,5 +50,10 @@ export declare function beginRise<I, O>(mix: Mixer<I, O>, voice: Voice<I, O>, op
|
|
|
44
50
|
* exactly there; at or behind now, the fade began then and is partway.
|
|
45
51
|
*/
|
|
46
52
|
export declare function fadeAt<I, O>(mix: Mixer<I, O>, voice: Voice<I, O>, at: number, over: number | undefined): void;
|
|
53
|
+
/**
|
|
54
|
+
* Brings back a voice kept quiet past its passes, its clock back in them by mix time `now`: it
|
|
55
|
+
* climbs from nothing over the fade it left over, from when its clock reached them.
|
|
56
|
+
*/
|
|
57
|
+
export declare function rouse<I, O>(mix: Mixer<I, O>, voice: Voice<I, O>, now: number): void;
|
|
47
58
|
/** Removes a voice, recording that it left at `at`, default now. */
|
|
48
59
|
export declare function retire<I, O>(mix: Mixer<I, O>, voice: Voice<I, O>, at?: number): void;
|
package/dist/fade.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { changed, headOf, unlink } from './chain.js';
|
|
2
2
|
import { envelope } from './clock.js';
|
|
3
3
|
import { schedule } from './due.js';
|
|
4
|
-
import { unshare, unsight } from './everyone.js';
|
|
5
4
|
import { leave, noted, releasing } from './history.js';
|
|
6
5
|
import { markOf } from './marks.js';
|
|
7
|
-
import { orphan, ownerReading } from './owner.js';
|
|
6
|
+
import { orphan, ownerReading, plays } from './owner.js';
|
|
8
7
|
import { startOf } from './place.js';
|
|
9
8
|
import { isRested } from './record.js';
|
|
10
9
|
import { scoreTouched } from './scored.js';
|
|
@@ -14,7 +13,7 @@ import { unreach } from './unreached.js';
|
|
|
14
13
|
export function fadeSubject(mix, voice, subject, over) {
|
|
15
14
|
if (voice.state === 'done' || voice.parted?.has(subject) || voice.parts?.has(subject))
|
|
16
15
|
return;
|
|
17
|
-
unshare(mix, voice);
|
|
16
|
+
mix.share?.unshare(mix, voice);
|
|
18
17
|
mix.stir();
|
|
19
18
|
const ms = mix.reduced ? 0 : (over ?? voice.fade.out ?? 0);
|
|
20
19
|
const at = Number.isNaN(mix.now) ? startOf(voice) : mix.now;
|
|
@@ -104,7 +103,7 @@ function forgetIn(mix, voice, subject) {
|
|
|
104
103
|
if (head !== undefined && head.slot >= 0) {
|
|
105
104
|
unreach(voice, head.slot, false);
|
|
106
105
|
// What the voice kept for the subject while it shared one record, which `weightOf` reads.
|
|
107
|
-
unsight(voice, head.slot);
|
|
106
|
+
mix.share?.unsight(voice, head.slot);
|
|
108
107
|
}
|
|
109
108
|
const held = voice.subjects.get(subject);
|
|
110
109
|
if (held !== undefined) {
|
|
@@ -135,7 +134,7 @@ export function beginFade(mix, voice, opts, at) {
|
|
|
135
134
|
// A fade at rest marks each subject's record as it comes to rest, at its next read: one already
|
|
136
135
|
// read this frame is read again, as after `touch`.
|
|
137
136
|
if (opts.at === 'rest') {
|
|
138
|
-
unshare(mix, voice);
|
|
137
|
+
mix.share?.unshare(mix, voice);
|
|
139
138
|
voice.seeks++;
|
|
140
139
|
}
|
|
141
140
|
voice.state = 'fading';
|
|
@@ -148,14 +147,36 @@ export function beginFade(mix, voice, opts, at) {
|
|
|
148
147
|
};
|
|
149
148
|
if (opts.back)
|
|
150
149
|
voice.out.back = true;
|
|
150
|
+
if (opts.stays)
|
|
151
|
+
voice.out.stays = true;
|
|
151
152
|
noted(mix, voice);
|
|
152
153
|
// A fade at rest, from a voice's start, or of a voice yet to start takes it off its lane.
|
|
153
154
|
if (opts.at === 'rest' || opts.back || waiting)
|
|
154
155
|
mix.lanes?.invalidate();
|
|
155
156
|
else
|
|
156
157
|
mix.lanes?.refill();
|
|
157
|
-
if (over === 0 && opts.at !== 'rest')
|
|
158
|
-
|
|
158
|
+
if (over === 0 && opts.at !== 'rest') {
|
|
159
|
+
if (opts.stays)
|
|
160
|
+
stay(mix, voice, voice.out.at);
|
|
161
|
+
else
|
|
162
|
+
retire(mix, voice, voice.out.at);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Keeps a voice faded at the end of its passes with its owner, live and quiet, rather than letting
|
|
167
|
+
* it leave; the owner leaves at `at` if it holds no child still playing.
|
|
168
|
+
*/
|
|
169
|
+
export function stay(mix, voice, at) {
|
|
170
|
+
voice.state = 'live';
|
|
171
|
+
mix.lanes?.refill();
|
|
172
|
+
const owner = voice.owner;
|
|
173
|
+
if (owner.state === 'done')
|
|
174
|
+
return;
|
|
175
|
+
const now = Number.isNaN(mix.now) ? Number.NEGATIVE_INFINITY : mix.now;
|
|
176
|
+
if (!plays(owner, now) && !lingers(owner, at))
|
|
177
|
+
retire(mix, owner, at);
|
|
178
|
+
else if (owner.fitting !== null && !voice.skipped)
|
|
179
|
+
refit(mix, owner, at);
|
|
159
180
|
}
|
|
160
181
|
/**
|
|
161
182
|
* Turns a fading voice around: it climbs back from where its fade out had got to, up the same
|
|
@@ -211,6 +232,21 @@ export function fadeAt(mix, voice, at, over) {
|
|
|
211
232
|
voice.outSet = true;
|
|
212
233
|
noted(mix, voice);
|
|
213
234
|
}
|
|
235
|
+
/**
|
|
236
|
+
* Brings back a voice kept quiet past its passes, its clock back in them by mix time `now`: it
|
|
237
|
+
* climbs from nothing over the fade it left over, from when its clock reached them.
|
|
238
|
+
*/
|
|
239
|
+
export function rouse(mix, voice, now) {
|
|
240
|
+
const out = voice.out;
|
|
241
|
+
const edge = out.back === true ? voice.soonest : voice.span + voice.latest;
|
|
242
|
+
const reached = voice.reaches(edge);
|
|
243
|
+
const at = Math.max(out.at + out.over, reached <= now ? reached : now);
|
|
244
|
+
const over = mix.reduced ? 0 : out.over;
|
|
245
|
+
voice.out = null;
|
|
246
|
+
voice.back = over > 0 ? { from: 0, at, over } : null;
|
|
247
|
+
noted(mix, voice);
|
|
248
|
+
mix.lanes?.refill();
|
|
249
|
+
}
|
|
214
250
|
/** Whether a motion patch still asks this voice of this mix for its time. */
|
|
215
251
|
function asks(mix, motion, voice) {
|
|
216
252
|
return motion.owner === mix.owner && motion.ownerId === voice.id;
|
|
@@ -248,7 +284,7 @@ export function retire(mix, voice, at) {
|
|
|
248
284
|
if (voice.owner !== null) {
|
|
249
285
|
const span = voice.owner;
|
|
250
286
|
leaving(mix, voice);
|
|
251
|
-
const owner = orphan(voice);
|
|
287
|
+
const owner = orphan(voice, now);
|
|
252
288
|
if (owner !== null && !lingers(owner, voice.doneAt))
|
|
253
289
|
retire(mix, owner, voice.doneAt);
|
|
254
290
|
// A child the fit skipped had no time in it, so the rest of the fit stands: fitting again
|
package/dist/fill.js
CHANGED
|
@@ -313,7 +313,7 @@ export function one(lane, p, slot) {
|
|
|
313
313
|
return false;
|
|
314
314
|
const delay = data[o + 0 /* Row.DELAY */];
|
|
315
315
|
const raw = elapsedNow - delay;
|
|
316
|
-
//
|
|
316
|
+
// Its freezes applied, written out: V8 left a function for it out of line here, a call a subject.
|
|
317
317
|
const elapsed = !(raw >= 0)
|
|
318
318
|
? voice.freezesBefore
|
|
319
319
|
? 0
|
package/dist/fold.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { foldNumber } from './channels.js';
|
|
2
2
|
import { copy as copyValue, first } from './clone.js';
|
|
3
|
-
import { open as openRecord, shut as shutRecord, weighAt } from './everyone.js';
|
|
4
3
|
// V8 reads a local const as a constant, where it reads an import from its module on every call.
|
|
5
4
|
const copy = copyValue;
|
|
6
|
-
const open = openRecord;
|
|
7
|
-
const shut = shutRecord;
|
|
8
5
|
/** A record's band state, made when a rest-less channel first asks. */
|
|
9
6
|
function bandsFor(held, n) {
|
|
10
7
|
const bands = new Uint8Array(n);
|
|
@@ -107,9 +104,9 @@ export function shared(voice, slot, rec, q) {
|
|
|
107
104
|
// A projection numbers no subject, and keeps nothing by subject.
|
|
108
105
|
if (slot < 0)
|
|
109
106
|
return q;
|
|
110
|
-
const
|
|
111
|
-
weighAt(voice, slot, rec.weight, cap);
|
|
112
|
-
shut(voice, rec, slot, cap);
|
|
107
|
+
const lanes = this.lanes;
|
|
108
|
+
this.share.weighAt(voice, slot, rec.weight, lanes.cap);
|
|
109
|
+
this.share.shut(voice, rec, slot, lanes.cap);
|
|
113
110
|
return q;
|
|
114
111
|
}
|
|
115
112
|
const sharers = this.sharers;
|
|
@@ -265,7 +262,7 @@ export function foldSharers(pose, subject, head, q, before, laned, dry, except,
|
|
|
265
262
|
continue;
|
|
266
263
|
if (voice.id === except || voice.state === 'done')
|
|
267
264
|
continue;
|
|
268
|
-
open(voice, rec, head.slot);
|
|
265
|
+
this.share.open(voice, rec, head.slot);
|
|
269
266
|
const delta = this.read(voice, subject, now, dry, rec);
|
|
270
267
|
if (owed >= 0 && voice.laned)
|
|
271
268
|
this.lanes.paid(voice.id, owed, rec.weight);
|