@msb235/blits 0.15.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.
- package/CHANGELOG.md +44 -0
- package/README.md +1 -1
- package/dist/bare.js +22 -7
- package/dist/columns.d.ts +2 -1
- package/dist/columns.js +55 -35
- package/dist/crowd.d.ts +8 -4
- package/dist/crowd.js +17 -7
- 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 +5 -0
- package/dist/everyone.js +30 -0
- package/dist/fill.js +1 -1
- package/dist/held.js +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/lane.d.ts +2 -5
- package/dist/lane.js +14 -10
- package/dist/lanes.d.ts +7 -4
- package/dist/lanes.js +27 -28
- package/dist/meet.js +5 -3
- package/dist/mixer.d.ts +2 -1
- package/dist/mixer.js +4 -0
- 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/pull.js +11 -1
- package/dist/qualify.js +9 -10
- package/dist/renumber.d.ts +10 -0
- package/dist/renumber.js +75 -0
- package/dist/rows.js +27 -19
- package/dist/seat.d.ts +17 -0
- package/dist/seat.js +25 -0
- package/dist/shared.d.ts +1 -1
- package/dist/shared.js +1 -1
- package/dist/strays.js +3 -2
- package/dist/trace.d.ts +4 -0
- package/dist/trace.js +255 -0
- 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 +10 -5
- 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 +3 -0
- package/dist/voice.js +9 -3
- package/docs/schema.html +11 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,50 @@ This package follows [semver](https://semver.org). Below 1.0.0, a breaking chang
|
|
|
4
4
|
version and everything else the patch. Each release lists its changes as **Breaking**, **Added** and
|
|
5
5
|
**Fixed**, and the release workflow refuses a tag with no section here.
|
|
6
6
|
|
|
7
|
+
## 0.15.1
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `mix.trace(from, to, { grid })` reads the mix over a window of mix time without moving it, and
|
|
12
|
+
`trace.of(subject, channel)` gives a channel of one number as a `Run`: points joined by straight
|
|
13
|
+
lines, two points at one time for a jump, and `exact` where the lines are the mix's own values
|
|
14
|
+
throughout. Where every voice feeding the channel is a `keys` voice of known shape (plain number
|
|
15
|
+
stops eased `linear`, a number weight, a steady rate, no fade under way), the points are its own
|
|
16
|
+
breakpoints; elsewhere the run is read every `grid` ms, default 5. One trace shares its reads
|
|
17
|
+
across subjects. `Run`, `Trace`, `TraceOptions` and `NumberChannel` are exported.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- A voice cued with `subjects` asks `stagger` for each of them at `cue`, not on first sight, and a
|
|
22
|
+
finite loop ends once its latest-staggered subject is done whether or not the host has read that
|
|
23
|
+
subject yet. A read ahead now sees the same end as the live mix. A voice reaching its subjects by
|
|
24
|
+
`target` still ends by the subjects it has met.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- One-subject tween voices cost about a fifth less a frame once they have landed: a fill folds a
|
|
29
|
+
landed tween's end as it stands, without reading its clock or easing it, until its voice, its
|
|
30
|
+
stretch or its subject's delay changes or the clock reads earlier than when it landed. 10,000 of
|
|
31
|
+
them read by `pull` (`tweens^`) take 0.235 ms a frame against 0.296, `churn^` 0.301 against
|
|
32
|
+
0.356 and `turnover^` 0.419 against 0.458 (studio, medians of seven runs of 5,000 frames, each in
|
|
33
|
+
its own process); one tween voice over 10,000 subjects (`weasel^`) is unchanged.
|
|
34
|
+
- A crowd of one-subject `keys` or `fn` voices applies its voices' freezes in the fill's own loop
|
|
35
|
+
rather than through a call a row. 10,000 `keys` voices read by `pull` (`keyses^`) take 0.449 ms
|
|
36
|
+
a frame against 0.479, and allocate 6 kB a frame against 162 (studio, medians of seven runs of
|
|
37
|
+
1,500 frames, each in its own process); the same voices freezing at both ends (`frozen`,
|
|
38
|
+
`frozen^`) are unchanged.
|
|
39
|
+
- `pull` over a list whose order has drifted from the order the mix first saw it in, as a list
|
|
40
|
+
kept dense by swap-remove does, writes rests in a few runs, not one per short stretch of
|
|
41
|
+
subjects. With one subject leaving and one arriving every frame (`turnover^`), a frame takes
|
|
42
|
+
0.253 ms against 0.262. Teitou, medians of seven runs of 5,000 frames, each in its own process.
|
|
43
|
+
Other rows are unchanged.
|
|
44
|
+
- A list kept dense by swap-remove stays in the mix's own order for `pull`: a subject moved into
|
|
45
|
+
the place a dropped one left takes the number the drop freed, so `pull` reads the list in long
|
|
46
|
+
runs. `turnover^` takes 0.223 ms a frame against 0.263, close to the 0.210 of `churn^`, which
|
|
47
|
+
replaces voices without reordering anything (teitou with the node to itself, medians of seven
|
|
48
|
+
runs). The other rows are unchanged. A mix that keeps history, or has roles or a bound on its
|
|
49
|
+
lanes, keeps the old order.
|
|
50
|
+
|
|
7
51
|
## 0.15.0
|
|
8
52
|
|
|
9
53
|
### Breaking
|
package/README.md
CHANGED
|
@@ -151,7 +151,7 @@ do yet.
|
|
|
151
151
|
|
|
152
152
|
## Status
|
|
153
153
|
|
|
154
|
-
v0.15.
|
|
154
|
+
v0.15.1, with five consumers. magicsmoke runs every fault on it, wod its wheel, tricks and
|
|
155
155
|
transitions, weasel its animator's tweens, sherpa its seams, and
|
|
156
156
|
[klieg](https://github.com/orochi235/klieg) composes all three of its systems — letter motion,
|
|
157
157
|
part effects, and the environment a sign is lit by — on a mix each.
|
package/dist/bare.js
CHANGED
|
@@ -48,9 +48,15 @@ export function bareRows(lanes, c, p, id) {
|
|
|
48
48
|
!(per[q + 3 /* Per.LANE_PROBE */] > lately ||
|
|
49
49
|
per[q + 4 /* Per.GENERAL_PROBE */] > lately))
|
|
50
50
|
break;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
// Every step from `now` to a sample's progress rounds monotonically, so a row seen landed at a
|
|
52
|
+
// positive rate is landed at any later `now` while it stays ready, and folds its `to` as it is.
|
|
53
|
+
const landed = ready && now >= hot[h + 8 /* Hot.LANDED */];
|
|
54
|
+
let elapsed = 0;
|
|
55
|
+
if (!landed) {
|
|
56
|
+
elapsed = clock(hot, h, now) - data[o + 0 /* Row.DELAY */];
|
|
57
|
+
if (!(elapsed >= 0))
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
54
60
|
keepProbed(data, o, per, q, fills);
|
|
55
61
|
const w = hot[h + 4 /* Hot.WEIGHT */];
|
|
56
62
|
data[o + 2 /* Row.WEIGHT */] = w;
|
|
@@ -60,14 +66,23 @@ export function bareRows(lanes, c, p, id) {
|
|
|
60
66
|
c.deltas[p] = null;
|
|
61
67
|
}
|
|
62
68
|
hot[h + 0 /* Hot.FLAGS */] = f | 2048 /* Flag.READY */;
|
|
69
|
+
hot[h + 8 /* Hot.LANDED */] = Number.POSITIVE_INFINITY;
|
|
63
70
|
}
|
|
64
71
|
if (w <= 0)
|
|
65
72
|
continue;
|
|
66
|
-
const share = left(c.eases[p], progress(elapsed, hot[h + 8 /* Hot.AT */], hot[h + 9 /* Hot.MS */]));
|
|
67
73
|
const values = ch.values;
|
|
68
74
|
const base = slot * n;
|
|
69
|
-
const x = h +
|
|
75
|
+
const x = h + 11 /* Hot.X0 */;
|
|
70
76
|
const g = x + 2 * n;
|
|
77
|
+
if (landed) {
|
|
78
|
+
for (let a = 0; a < n; a++)
|
|
79
|
+
values[base + a] = foldNumber(op, values[base + a], hot[g + a], w);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const u = progress(elapsed, hot[h + 9 /* Hot.AT */], hot[h + 10 /* Hot.MS */]);
|
|
83
|
+
const share = left(c.eases[p], u);
|
|
84
|
+
if (u >= 1 && hot[h + 3 /* Hot.RATE */] > 0)
|
|
85
|
+
hot[h + 8 /* Hot.LANDED */] = now;
|
|
71
86
|
for (let a = 0; a < n; a++)
|
|
72
87
|
values[base + a] = foldNumber(op, values[base + a], between(hot[x + a], hot[g + a], share), w);
|
|
73
88
|
}
|
|
@@ -87,8 +102,8 @@ export function unbare(c, p) {
|
|
|
87
102
|
hot[h + 0 /* Hot.FLAGS */] = hot[h + 0 /* Hot.FLAGS */] & ~2048 /* Flag.READY */;
|
|
88
103
|
const n = c.axes;
|
|
89
104
|
const elapsed = clock(hot, h, c.bareNow) - data[o + 0 /* Row.DELAY */];
|
|
90
|
-
const share = left(c.eases[p], progress(elapsed, hot[h +
|
|
91
|
-
const x = h +
|
|
105
|
+
const share = left(c.eases[p], progress(elapsed, hot[h + 9 /* Hot.AT */], hot[h + 10 /* Hot.MS */]));
|
|
106
|
+
const x = h + 11 /* Hot.X0 */;
|
|
92
107
|
const g = x + 2 * n;
|
|
93
108
|
for (let a = 0; a < n; a++)
|
|
94
109
|
c.samples[p * n + a] = between(hot[x + a], hot[g + a], share);
|
package/dist/columns.d.ts
CHANGED
|
@@ -22,7 +22,8 @@ export declare function pullRun<I, O>(lanes: Lanes<I, O>, slots: Int32Array, lis
|
|
|
22
22
|
* Queues a subject's values for each column at subject `n`'s places, for a `pull` that reads
|
|
23
23
|
* from the lanes while every voice is on one; `flush` writes what is queued, column by column. A
|
|
24
24
|
* channel no lane holds is at rest. Anything queued is written before the lanes fill again.
|
|
25
|
+
* `slots` holds each row's lane slot, `slot` among them.
|
|
25
26
|
*/
|
|
26
|
-
export declare function writeLater<I, O>(lanes: Lanes<I, O>, slot: number, columns: readonly Column[], n: number): void;
|
|
27
|
+
export declare function writeLater<I, O>(lanes: Lanes<I, O>, slot: number, columns: readonly Column[], n: number, slots: Int32Array): void;
|
|
27
28
|
/** Writes every queued run into its columns: a channel's values as a block, a rest as a fill. */
|
|
28
29
|
export declare function flush<I, O>(lanes: Lanes<I, O>): void;
|
package/dist/columns.js
CHANGED
|
@@ -26,15 +26,8 @@ export function pullRun(lanes, slots, list, was, since, from, columns, now, vers
|
|
|
26
26
|
// Nothing in `pullRun` makes a subject owe a voice, so one with nobody owing need not ask.
|
|
27
27
|
const owing = lanes.owed.any();
|
|
28
28
|
const current = since === Number.POSITIVE_INFINITY;
|
|
29
|
-
|
|
30
|
-
flush(lanes);
|
|
31
|
-
lanes.queuedFor = columns;
|
|
32
|
-
}
|
|
29
|
+
queueFor(lanes, columns, slots);
|
|
33
30
|
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
31
|
let n = from;
|
|
39
32
|
// The run being gathered: its first slot and row, and how far it has reached.
|
|
40
33
|
let first = -1;
|
|
@@ -60,23 +53,14 @@ export function pullRun(lanes, slots, list, was, since, from, columns, now, vers
|
|
|
60
53
|
if (holds)
|
|
61
54
|
subjects[slot] = subject;
|
|
62
55
|
if (slot !== first + (n - start)) {
|
|
63
|
-
if (first >= 0)
|
|
64
|
-
|
|
65
|
-
qRows[k] = start;
|
|
66
|
-
qCounts[k] = n - start;
|
|
67
|
-
k++;
|
|
68
|
-
}
|
|
56
|
+
if (first >= 0)
|
|
57
|
+
add(lanes, first, start, n - start);
|
|
69
58
|
first = slot;
|
|
70
59
|
start = n;
|
|
71
60
|
}
|
|
72
61
|
}
|
|
73
|
-
if (first >= 0)
|
|
74
|
-
|
|
75
|
-
qRows[k] = start;
|
|
76
|
-
qCounts[k] = n - start;
|
|
77
|
-
k++;
|
|
78
|
-
}
|
|
79
|
-
lanes.queued = k;
|
|
62
|
+
if (first >= 0)
|
|
63
|
+
add(lanes, first, start, n - start);
|
|
80
64
|
if (n > from && holds)
|
|
81
65
|
lanes.holding = true;
|
|
82
66
|
return n;
|
|
@@ -85,24 +69,43 @@ export function pullRun(lanes, slots, list, was, since, from, columns, now, vers
|
|
|
85
69
|
* Queues a subject's values for each column at subject `n`'s places, for a `pull` that reads
|
|
86
70
|
* from the lanes while every voice is on one; `flush` writes what is queued, column by column. A
|
|
87
71
|
* channel no lane holds is at rest. Anything queued is written before the lanes fill again.
|
|
72
|
+
* `slots` holds each row's lane slot, `slot` among them.
|
|
88
73
|
*/
|
|
89
|
-
export function writeLater(lanes, slot, columns, n) {
|
|
90
|
-
|
|
74
|
+
export function writeLater(lanes, slot, columns, n, slots) {
|
|
75
|
+
queueFor(lanes, columns, slots);
|
|
76
|
+
add(lanes, slot, n, 1);
|
|
91
77
|
}
|
|
92
|
-
/**
|
|
93
|
-
function
|
|
94
|
-
if (columns
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
78
|
+
/** Writes what is queued for other columns or another array of slots before queuing for these. */
|
|
79
|
+
function queueFor(lanes, columns, slots) {
|
|
80
|
+
if (columns === lanes.queuedFor && slots === lanes.queueFrom)
|
|
81
|
+
return;
|
|
82
|
+
flush(lanes);
|
|
83
|
+
lanes.queuedFor = columns;
|
|
84
|
+
lanes.queueFrom = slots;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The shortest run `flush` copies as a block from consecutive slots. A shorter one, as a list kept
|
|
88
|
+
* dense by swap-remove leaves its slots, joins the rows before it in one run whose slots `flush`
|
|
89
|
+
* reads row by row, so a run's cost is paid once a stretch of rows rather than once a few.
|
|
90
|
+
*/
|
|
91
|
+
const BLOCK = 16;
|
|
92
|
+
/** Queues `count` rows from `row`, whose slots follow one apart from `slot`. */
|
|
93
|
+
function add(lanes, slot, row, count) {
|
|
98
94
|
const k = lanes.queued;
|
|
99
95
|
if (k > 0) {
|
|
100
96
|
const last = k - 1;
|
|
101
97
|
const had = lanes.queueCounts[last];
|
|
102
|
-
if (
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
98
|
+
if (row === lanes.queueRows[last] + had) {
|
|
99
|
+
const first = lanes.queueSlots[last];
|
|
100
|
+
if (first >= 0 && slot === first + had) {
|
|
101
|
+
lanes.queueCounts[last] = had + count;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (count < BLOCK && (first < 0 || had < BLOCK)) {
|
|
105
|
+
lanes.queueSlots[last] = -1;
|
|
106
|
+
lanes.queueCounts[last] = had + count;
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
106
109
|
}
|
|
107
110
|
}
|
|
108
111
|
room(lanes, k + 1);
|
|
@@ -173,16 +176,33 @@ function rests(lanes, c, runs) {
|
|
|
173
176
|
}
|
|
174
177
|
/** The longest run of values `copies` copies itself: `set` takes a view, an object a run. */
|
|
175
178
|
const VIEWED = 256;
|
|
176
|
-
/** Copies a laned channel's values for every queued run into its rows. */
|
|
179
|
+
/** Copies a laned channel's values for every queued run into its rows, a block or row by row. */
|
|
177
180
|
function copies(lanes, c, values, runs) {
|
|
178
181
|
const slots = lanes.queueSlots;
|
|
179
182
|
const rows = lanes.queueRows;
|
|
180
183
|
const counts = lanes.queueCounts;
|
|
181
184
|
const out = c.out;
|
|
182
185
|
const axes = c.axes;
|
|
186
|
+
const from = lanes.queueFrom;
|
|
183
187
|
for (let r = 0; r < runs; r++) {
|
|
188
|
+
const first = slots[r];
|
|
189
|
+
if (first < 0) {
|
|
190
|
+
const row = rows[r];
|
|
191
|
+
const end = row + counts[r];
|
|
192
|
+
if (axes === 1)
|
|
193
|
+
for (let i = row; i < end; i++)
|
|
194
|
+
out[i] = values[from[i]];
|
|
195
|
+
else
|
|
196
|
+
for (let i = row; i < end; i++) {
|
|
197
|
+
const at = i * axes;
|
|
198
|
+
const base = from[i] * axes;
|
|
199
|
+
for (let a = 0; a < axes; a++)
|
|
200
|
+
out[at + a] = values[base + a];
|
|
201
|
+
}
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
184
204
|
const at = rows[r] * axes;
|
|
185
|
-
const base =
|
|
205
|
+
const base = first * axes;
|
|
186
206
|
const span = counts[r] * axes;
|
|
187
207
|
if (span > VIEWED)
|
|
188
208
|
out.set(values.subarray(base, base + span), at);
|
package/dist/crowd.d.ts
CHANGED
|
@@ -25,10 +25,15 @@ export declare const enum Hot {
|
|
|
25
25
|
SEEKS = 5,
|
|
26
26
|
EPOCH = 6,
|
|
27
27
|
ID = 7,
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
/**
|
|
29
|
+
* A `Flag.READY` row's mix time from which its tween has landed, so a fill folds its `to` as it
|
|
30
|
+
* stands; Infinity until `bareRows` sees it land at a positive rate. Unread on any other row.
|
|
31
|
+
*/
|
|
32
|
+
LANDED = 8,
|
|
33
|
+
AT = 9,
|
|
34
|
+
MS = 10,
|
|
30
35
|
/** `x0`, `v0` and `to`, `axes` numbers each. */
|
|
31
|
-
X0 =
|
|
36
|
+
X0 = 11
|
|
32
37
|
}
|
|
33
38
|
/** A crowd row's flags, at `Hot.FLAGS`. */
|
|
34
39
|
export declare const enum Flag {
|
|
@@ -86,7 +91,6 @@ export declare class Crowd<I, O> implements Positions<I, O> {
|
|
|
86
91
|
eases: (Curve | undefined)[];
|
|
87
92
|
/** Each row's patch law, one array shared by every row whose law is the same. */
|
|
88
93
|
laws: Float64Array[];
|
|
89
|
-
readonly rowOf: Map<number, number>;
|
|
90
94
|
idle: boolean;
|
|
91
95
|
readonly line: {
|
|
92
96
|
stop: number;
|
package/dist/crowd.js
CHANGED
|
@@ -2,7 +2,7 @@ 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
7
|
/**
|
|
8
8
|
* Whether a laned voice belongs in a crowd: one naming a single subject, which shares nothing
|
|
@@ -45,7 +45,6 @@ export class Crowd {
|
|
|
45
45
|
eases = [];
|
|
46
46
|
/** Each row's patch law, one array shared by every row whose law is the same. */
|
|
47
47
|
laws = [];
|
|
48
|
-
rowOf = new Map();
|
|
49
48
|
idle = false;
|
|
50
49
|
line = SPARSE.other;
|
|
51
50
|
/** Where the fill now under way has reached. */
|
|
@@ -69,7 +68,7 @@ export class Crowd {
|
|
|
69
68
|
constructor(chans, axes) {
|
|
70
69
|
this.chans = chans;
|
|
71
70
|
this.axes = axes;
|
|
72
|
-
this.stride =
|
|
71
|
+
this.stride = 11 /* Hot.X0 */ + 3 * axes;
|
|
73
72
|
this.xs = new Float64Array(axes);
|
|
74
73
|
this.vs = new Float64Array(axes);
|
|
75
74
|
}
|
|
@@ -218,8 +217,19 @@ function rows(lanes, c, first, id) {
|
|
|
218
217
|
const voice = c.voices[p];
|
|
219
218
|
const elapsedNow = fast ? clock(hot, h, now) : voice.elapsedAt(now);
|
|
220
219
|
let elapsed = elapsedNow - delay;
|
|
220
|
+
// Its freezes applied as `one` applies them, written out: a function for it stays out of line.
|
|
221
221
|
if ((f & 256 /* Flag.FREEZES */) !== 0)
|
|
222
|
-
elapsed =
|
|
222
|
+
elapsed = !(elapsed >= 0)
|
|
223
|
+
? voice.freezesBefore
|
|
224
|
+
? 0
|
|
225
|
+
: Number.NaN
|
|
226
|
+
: elapsed > voice.span
|
|
227
|
+
? voice.hidesPast
|
|
228
|
+
? Number.NaN
|
|
229
|
+
: voice.freezesAfter
|
|
230
|
+
? voice.span
|
|
231
|
+
: elapsed
|
|
232
|
+
: elapsed;
|
|
223
233
|
if (!(elapsed >= 0)) {
|
|
224
234
|
data[o + 2 /* Row.WEIGHT */] = 0;
|
|
225
235
|
continue;
|
|
@@ -244,7 +254,7 @@ function rows(lanes, c, first, id) {
|
|
|
244
254
|
data[o + 2 /* Row.WEIGHT */] = w;
|
|
245
255
|
if ((f & 512 /* Flag.FLAT */) !== 0) {
|
|
246
256
|
if (w > 0)
|
|
247
|
-
c.keys.fold(hot[h +
|
|
257
|
+
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
258
|
continue;
|
|
249
259
|
}
|
|
250
260
|
arg[1 /* Arg.ELAPSED */] = elapsed;
|
|
@@ -274,7 +284,7 @@ function rows(lanes, c, first, id) {
|
|
|
274
284
|
c.restale(p, hot[h + 0 /* Hot.FLAGS */]);
|
|
275
285
|
continue;
|
|
276
286
|
}
|
|
277
|
-
closed(c.laws[p], c.eases[p], n, hot[h +
|
|
287
|
+
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
288
|
for (let a = 0; a < n; a++)
|
|
279
289
|
samples[p * n + a] = xs[a];
|
|
280
290
|
if (c.deltas[p] !== null)
|
|
@@ -371,7 +381,7 @@ function copyStretch(c, p, ms) {
|
|
|
371
381
|
const h = p * c.stride;
|
|
372
382
|
let f = c.hot[h + 0 /* Hot.FLAGS */] & ~(4 /* Flag.STALE */ | 8 /* Flag.BARE */ | 32 /* Flag.FOLDS */);
|
|
373
383
|
const ch = c.chans[0];
|
|
374
|
-
if (run.n === c.axes && run.stretchInto(ms, c.hot, h +
|
|
384
|
+
if (run.n === c.axes && run.stretchInto(ms, c.hot, h + 9 /* Hot.AT */)) {
|
|
375
385
|
f |= 8 /* Flag.BARE */;
|
|
376
386
|
if (run.scalar(ms) === ch.scalar && ch.plain)
|
|
377
387
|
f |= 32 /* Flag.FOLDS */;
|
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
|
/**
|
package/dist/everyone.js
CHANGED
|
@@ -185,6 +185,36 @@ export function restamp(voice, slot) {
|
|
|
185
185
|
if (voice.built !== null && voice.everyone !== null)
|
|
186
186
|
voice.everyone.seeks = -1;
|
|
187
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* The subject numbered `from` is numbered `to` now, a number let go of: what the voice keeps for it
|
|
190
|
+
* moves along, and `from` is left as `unsight` leaves it.
|
|
191
|
+
*/
|
|
192
|
+
export function resight(voice, from, to, cap) {
|
|
193
|
+
if (sighted(voice, from)) {
|
|
194
|
+
const seen = voice.seen;
|
|
195
|
+
sight(voice, to, cap);
|
|
196
|
+
voice.seen = seen;
|
|
197
|
+
}
|
|
198
|
+
const w = weightAt(voice, from);
|
|
199
|
+
if (w !== 0 || (voice.weights !== null && to < voice.weights.length))
|
|
200
|
+
weighAt(voice, to, w, cap);
|
|
201
|
+
let stamps = voice.stamps;
|
|
202
|
+
const o = from * 2 /* Stamp.SIZE */;
|
|
203
|
+
if (stamps !== null && o < stamps.length) {
|
|
204
|
+
const t = to * 2 /* Stamp.SIZE */;
|
|
205
|
+
if (t >= stamps.length) {
|
|
206
|
+
const grown = new Float64Array(Math.max(to + 1, cap) * 2 /* Stamp.SIZE */).fill(Number.NaN);
|
|
207
|
+
grown.set(stamps);
|
|
208
|
+
voice.stamps = grown;
|
|
209
|
+
stamps = grown;
|
|
210
|
+
}
|
|
211
|
+
stamps[t + 0 /* Stamp.PROBED */] = stamps[o + 0 /* Stamp.PROBED */];
|
|
212
|
+
stamps[t + 1 /* Stamp.SEEKS */] = stamps[o + 1 /* Stamp.SEEKS */];
|
|
213
|
+
const deltas = voice.deltas;
|
|
214
|
+
deltas[to] = deltas[from] ?? null;
|
|
215
|
+
}
|
|
216
|
+
unsight(voice, from);
|
|
217
|
+
}
|
|
188
218
|
/** A subject's number was let go of: the next subject to take it is one the voice has not seen. */
|
|
189
219
|
export function unsight(voice, slot) {
|
|
190
220
|
const bits = voice.sighted;
|
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/held.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { changed } from './chain.js';
|
|
2
2
|
import { stepOf } from './clock.js';
|
|
3
|
+
import { delayOf } from './delay.js';
|
|
3
4
|
import { schedule } from './due.js';
|
|
4
5
|
import { everyoneOf, inherit, sighted } from './everyone.js';
|
|
5
6
|
import { originOf } from './origin.js';
|
|
@@ -50,7 +51,7 @@ export function held(voice, subject, slot, guess = null) {
|
|
|
50
51
|
voice.keyed ??= new Set();
|
|
51
52
|
voice.keyed.add(this.keys.key(subject));
|
|
52
53
|
}
|
|
53
|
-
const delay = voice
|
|
54
|
+
const delay = delayOf(voice, subject);
|
|
54
55
|
const since = this.sinceOf(voice, delay);
|
|
55
56
|
const shown = this.shownOf(voice, since);
|
|
56
57
|
held = record(voice, true, voice.patch.state ? voice.patch.state(subject) : undefined);
|
package/dist/index.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export { fold } from './stack.js';
|
|
|
20
20
|
export type { Ticked, Ticker, TickerOptions } from './ticker.js';
|
|
21
21
|
export { ticker } from './ticker.js';
|
|
22
22
|
export { transport } from './transport.js';
|
|
23
|
-
export type { Anchor, AnnounceOptions, ArcHandle, ArcPart, ArcSpec, ArcVoice, Band, BlendMember, BookedHit, Booker, BookOptions, Channel, Circle, Columns, Described, Doubt, Easing, Engine, FadeOptions, FadeSpec, Finder, FitResult, GlideSpec, Handle, HistoryOptions, HistoryStore, Hit, Hold, Keyframe, Kit, Mark, Marked, MarkName, Mix, MixOptions, MotionSpec, OwnerSpec, Paged, PagedStream, Patch, Placement, Probed, Projection, Pulled, Query, Registry, RegistryChange, SeekOptions, Sent, Setting, Signal, SpanHandle, SpanHints, SpanSpec, SpringSpec, SubjectFade, Taken, Tape, TapeBranch, TapeMaker, TapeOp, TapeOptions, Transport, TransportOptions, TransportProjection, TweenSpec, VoiceFade, VoiceSpec, Watched, WatchedFrame, WatchedHistory, WatchedVoice, } from './types.js';
|
|
23
|
+
export type { Anchor, AnnounceOptions, ArcHandle, ArcPart, ArcSpec, ArcVoice, Band, BlendMember, BookedHit, Booker, BookOptions, Channel, Circle, Columns, Described, Doubt, Easing, Engine, FadeOptions, FadeSpec, Finder, FitResult, GlideSpec, Handle, HistoryOptions, HistoryStore, Hit, Hold, Keyframe, Kit, Mark, Marked, MarkName, Mix, MixOptions, MotionSpec, NumberChannel, OwnerSpec, Paged, PagedStream, Patch, Placement, Probed, Projection, Pulled, Query, Registry, RegistryChange, Run, SeekOptions, Sent, Setting, Signal, SpanHandle, SpanHints, SpanSpec, SpringSpec, SubjectFade, Taken, Tape, TapeBranch, TapeMaker, TapeOp, TapeOptions, Trace, TraceOptions, Transport, TransportOptions, TransportProjection, TweenSpec, VoiceFade, VoiceSpec, Watched, WatchedFrame, WatchedHistory, WatchedVoice, } from './types.js';
|
|
24
24
|
export { watched } from './watch.js';
|
|
25
25
|
export type { WaveOptions, WaveShape } from './wave.js';
|
|
26
26
|
export { wave, waveAt } from './wave.js';
|
package/dist/lane.d.ts
CHANGED
|
@@ -260,11 +260,8 @@ export declare class Lane<I, O> implements Positions<I, O> {
|
|
|
260
260
|
reserve(n: number, cap: number): void;
|
|
261
261
|
/** Gives a subject the voice reaches a position, from what its record fixed on first sight. */
|
|
262
262
|
add(slot: number, held: Subject<unknown>): void;
|
|
263
|
+
/** The subject numbered `from` is numbered `to` now, a number no position holds: same position. */
|
|
264
|
+
renumber(from: number, to: number): void;
|
|
263
265
|
/** A subject lost its number: the last position moves into its place. */
|
|
264
266
|
remove(slot: number): void;
|
|
265
267
|
}
|
|
266
|
-
/**
|
|
267
|
-
* A subject's voice time once its voice's freezes apply: frozen at 0 before it starts and at the end
|
|
268
|
-
* of its passes after, and NaN where it shows nothing, as past its end running back.
|
|
269
|
-
*/
|
|
270
|
-
export declare function frozenAt<I, O>(voice: Voice<I, O>, elapsed: number): number;
|
package/dist/lane.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { unbareLane } from './bare.js';
|
|
2
|
-
import { frozenTime } from './clock.js';
|
|
3
2
|
import { motionOf } from './motion.js';
|
|
4
3
|
/**
|
|
5
4
|
* Keeps the weight a probe read from the last fill as `Row.PROBED`, for `weightOf`, before a fill
|
|
@@ -185,6 +184,20 @@ export class Lane {
|
|
|
185
184
|
this.records[p] = held;
|
|
186
185
|
this.deltas[p] = null;
|
|
187
186
|
}
|
|
187
|
+
/** The subject numbered `from` is numbered `to` now, a number no position holds: same position. */
|
|
188
|
+
renumber(from, to) {
|
|
189
|
+
const p = this.positionOf(from);
|
|
190
|
+
if (p < 0)
|
|
191
|
+
return;
|
|
192
|
+
if (to >= this.at.length) {
|
|
193
|
+
const at = new Int32Array(Math.max(to + 1, this.at.length * 2, 64));
|
|
194
|
+
at.set(this.at);
|
|
195
|
+
this.at = at;
|
|
196
|
+
}
|
|
197
|
+
this.list[p] = to;
|
|
198
|
+
this.at[to] = p + 1;
|
|
199
|
+
this.at[from] = 0;
|
|
200
|
+
}
|
|
188
201
|
/** A subject lost its number: the last position moves into its place. */
|
|
189
202
|
remove(slot) {
|
|
190
203
|
const p = this.positionOf(slot);
|
|
@@ -214,12 +227,3 @@ export class Lane {
|
|
|
214
227
|
this.deltas[last] = null;
|
|
215
228
|
}
|
|
216
229
|
}
|
|
217
|
-
/**
|
|
218
|
-
* A subject's voice time once its voice's freezes apply: frozen at 0 before it starts and at the end
|
|
219
|
-
* of its passes after, and NaN where it shows nothing, as past its end running back.
|
|
220
|
-
*/
|
|
221
|
-
export function frozenAt(voice, elapsed) {
|
|
222
|
-
if (elapsed > voice.span && voice.hidesPast)
|
|
223
|
-
return Number.NaN;
|
|
224
|
-
return frozenTime(elapsed, voice.freezesBefore, voice.freezesAfter, voice.span);
|
|
225
|
-
}
|
package/dist/lanes.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { type Lane, type Laned, type Role } from './lane.js';
|
|
|
7
7
|
import { absent, Numbers } from './numbers.js';
|
|
8
8
|
import { Owed } from './owed.js';
|
|
9
9
|
import { Placed } from './placed.js';
|
|
10
|
+
import { type Seat } from './seat.js';
|
|
10
11
|
import type { Watcher } from './stretch.js';
|
|
11
12
|
import type { Subject } from './subject.js';
|
|
12
13
|
import type { Channel } from './types.js';
|
|
@@ -70,7 +71,7 @@ export declare class Lanes<I, O> implements Watcher {
|
|
|
70
71
|
readonly byId: Map<number, Lane<I, O>>;
|
|
71
72
|
/** The crowds of single-subject voices, one per list of channels, and which holds each voice. */
|
|
72
73
|
crowds: Crowd<I, O>[];
|
|
73
|
-
readonly
|
|
74
|
+
readonly seats: Map<number, Seat<I, O>>;
|
|
74
75
|
/** Which crowd voices' rows are placed on each subject. */
|
|
75
76
|
readonly placed: Placed;
|
|
76
77
|
/**
|
|
@@ -161,14 +162,16 @@ export declare class Lanes<I, O> implements Watcher {
|
|
|
161
162
|
*/
|
|
162
163
|
readonly late: number[];
|
|
163
164
|
/**
|
|
164
|
-
* What `writeLater` and `pullRun` have queued, for one set of columns, as runs: each
|
|
165
|
-
*
|
|
165
|
+
* What `writeLater` and `pullRun` have queued, for one set of columns, as runs of rows: each
|
|
166
|
+
* run's first row and how many follow, and its first lane slot where its slots follow one apart
|
|
167
|
+
* too, else -1, when each row's slot is read from `queueFrom` by row.
|
|
166
168
|
*/
|
|
167
169
|
queueSlots: Int32Array<ArrayBuffer>;
|
|
168
170
|
queueRows: Int32Array<ArrayBuffer>;
|
|
169
171
|
queueCounts: Int32Array<ArrayBuffer>;
|
|
170
172
|
queued: number;
|
|
171
173
|
queuedFor: readonly Column[] | null;
|
|
174
|
+
queueFrom: Int32Array | null;
|
|
172
175
|
keeps: boolean;
|
|
173
176
|
now: number;
|
|
174
177
|
filledAt: number;
|
|
@@ -285,7 +288,7 @@ export declare class Lanes<I, O> implements Watcher {
|
|
|
285
288
|
/** A voice's clock moved the `shown` of records it had already placed: copies them again. */
|
|
286
289
|
reshown(id: number): void;
|
|
287
290
|
/** Something on a voice changed: a crowd copies it again at the next fill. */
|
|
288
|
-
voiceChanged(
|
|
291
|
+
voiceChanged(voice: Voice<I, O>): void;
|
|
289
292
|
}
|
|
290
293
|
declare const methods: {
|
|
291
294
|
copy: typeof copy;
|