@msb235/blits 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +154 -0
- package/README.md +3 -3
- package/dist/ahead.d.ts +26 -0
- package/dist/ahead.js +264 -0
- package/dist/around.d.ts +11 -0
- package/dist/around.js +32 -0
- package/dist/bare.js +15 -7
- package/dist/blank.d.ts +10 -0
- package/dist/blank.js +26 -0
- package/dist/blend.d.ts +2 -1
- package/dist/blend.js +1 -6
- package/dist/bound.d.ts +70 -0
- package/dist/bound.js +351 -0
- package/dist/chain.d.ts +2 -1
- package/dist/chain.js +7 -5
- package/dist/changes.d.ts +24 -0
- package/dist/changes.js +189 -0
- package/dist/channels.d.ts +39 -13
- package/dist/channels.js +14 -5
- package/dist/color.d.ts +12 -10
- package/dist/color.js +25 -25
- package/dist/columns.js +7 -3
- package/dist/contribution.d.ts +30 -0
- package/dist/contribution.js +374 -0
- package/dist/copyout.d.ts +10 -0
- package/dist/copyout.js +69 -24
- package/dist/crowd.d.ts +8 -2
- package/dist/crowd.js +4 -5
- package/dist/cue.d.ts +8 -1
- package/dist/cue.js +39 -13
- package/dist/cut.d.ts +8 -0
- package/dist/cut.js +4 -0
- package/dist/drop.d.ts +9 -0
- package/dist/drop.js +84 -0
- package/dist/due.d.ts +24 -5
- package/dist/due.js +113 -33
- package/dist/easing.d.ts +4 -4
- package/dist/easing.js +3 -3
- package/dist/everyone.d.ts +3 -2
- package/dist/everyone.js +3 -3
- package/dist/fade.d.ts +2 -1
- package/dist/fade.js +2 -1
- package/dist/fill.d.ts +3 -2
- package/dist/fill.js +51 -19
- package/dist/fit.d.ts +44 -26
- package/dist/fit.js +10 -9
- package/dist/fold.d.ts +4 -37
- package/dist/fold.js +5 -513
- package/dist/gather.d.ts +12 -7
- package/dist/gather.js +179 -44
- package/dist/gone.js +2 -2
- package/dist/grid.d.ts +47 -0
- package/dist/grid.js +247 -0
- package/dist/handle.d.ts +2 -0
- package/dist/handle.js +14 -8
- package/dist/held.d.ts +2 -1
- package/dist/history.d.ts +6 -5
- package/dist/history.js +7 -9
- package/dist/hosts.js +9 -15
- package/dist/index.d.ts +5 -4
- package/dist/keyfill.d.ts +1 -1
- package/dist/keyfill.js +5 -3
- package/dist/keyrows.d.ts +12 -0
- package/dist/keyrows.js +99 -12
- package/dist/lane.d.ts +36 -6
- package/dist/lane.js +32 -1
- package/dist/lanes.d.ts +23 -8
- package/dist/lanes.js +29 -8
- package/dist/leavings.d.ts +2 -2
- package/dist/leavings.js +1 -1
- package/dist/lives.d.ts +47 -0
- package/dist/lives.js +180 -0
- package/dist/meet.d.ts +2 -2
- package/dist/meet.js +90 -4
- package/dist/mixer.d.ts +54 -36
- package/dist/mixer.js +53 -171
- package/dist/motion.d.ts +14 -118
- package/dist/motion.js +16 -8
- package/dist/motions.d.ts +62 -155
- package/dist/motions.js +56 -370
- package/dist/moved.d.ts +1 -1
- package/dist/moved.js +16 -7
- package/dist/named.d.ts +0 -1
- package/dist/named.js +20 -2
- package/dist/numbers.d.ts +2 -0
- package/dist/numbers.js +4 -0
- package/dist/owed.d.ts +2 -0
- package/dist/owed.js +4 -0
- package/dist/pack.d.ts +2 -1
- package/dist/pack.js +2 -3
- package/dist/patch.d.ts +7 -3
- package/dist/patch.js +6 -2
- package/dist/places.d.ts +53 -0
- package/dist/places.js +171 -0
- package/dist/plot.d.ts +12 -0
- package/dist/plot.js +52 -0
- package/dist/project.d.ts +4 -4
- package/dist/project.js +9 -212
- package/dist/pull.js +11 -8
- package/dist/qualify.js +84 -21
- package/dist/reading.d.ts +6 -0
- package/dist/reading.js +5 -0
- package/dist/record.d.ts +5 -1
- package/dist/record.js +3 -2
- package/dist/relink.d.ts +1 -1
- package/dist/restored.d.ts +2 -2
- package/dist/restored.js +1 -1
- package/dist/rests.d.ts +9 -0
- package/dist/rests.js +76 -0
- package/dist/revive.d.ts +3 -2
- package/dist/revive.js +2 -2
- package/dist/{locus.d.ts → role.d.ts} +10 -9
- package/dist/{locus.js → role.js} +3 -3
- package/dist/roles.d.ts +10 -0
- package/dist/roles.js +158 -0
- package/dist/roster.js +3 -3
- package/dist/rotation.d.ts +1 -1
- package/dist/rotation.js +1 -1
- package/dist/rows.js +1 -1
- package/dist/sample.d.ts +2 -2
- package/dist/sample.js +33 -7
- package/dist/seek.js +5 -5
- package/dist/setting.d.ts +27 -0
- package/dist/setting.js +55 -0
- package/dist/shared.d.ts +1 -1
- package/dist/shared.js +1 -1
- package/dist/signals.d.ts +64 -32
- package/dist/signals.js +20 -18
- package/dist/stack.d.ts +5 -5
- package/dist/stack.js +5 -5
- package/dist/standing.d.ts +2 -1
- package/dist/standing.js +3 -2
- package/dist/store.d.ts +9 -0
- package/dist/store.js +24 -0
- package/dist/strays.d.ts +2 -1
- package/dist/strays.js +20 -13
- package/dist/stretch.d.ts +112 -0
- package/dist/stretch.js +9 -0
- package/dist/subject.d.ts +142 -0
- package/dist/subject.js +1 -0
- package/dist/tape.d.ts +9 -5
- package/dist/tape.js +5 -1
- package/dist/then.d.ts +9 -0
- package/dist/then.js +57 -0
- package/dist/ticker.d.ts +4 -4
- package/dist/transport.d.ts +0 -8
- package/dist/transport.js +0 -4
- package/dist/turns.d.ts +4 -3
- package/dist/turns.js +4 -3
- package/dist/types/arc.d.ts +12 -11
- package/dist/types/channel.d.ts +12 -8
- package/dist/types/history.d.ts +35 -19
- package/dist/types/mix.d.ts +222 -163
- package/dist/types/motion.d.ts +151 -0
- package/dist/types/motion.js +1 -0
- package/dist/types/patch.d.ts +67 -34
- package/dist/types/place.d.ts +51 -36
- package/dist/types/transport.d.ts +20 -18
- package/dist/types/voice.d.ts +136 -70
- package/dist/types/watch.d.ts +88 -40
- package/dist/types.d.ts +1 -0
- package/dist/voice.d.ts +7 -143
- package/dist/voice.js +28 -79
- package/dist/warn.d.ts +2 -0
- package/dist/warn.js +1 -1
- package/dist/watch.d.ts +2 -2
- package/dist/watch.js +5 -3
- package/dist/wave.d.ts +4 -3
- package/dist/wave.js +3 -2
- package/dist/weigh.d.ts +7 -1
- package/dist/weigh.js +27 -0
- package/docs/schema.html +212 -34
- package/package.json +2 -2
package/dist/strays.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { unpart } from './fade.js';
|
|
2
2
|
import { pageOut } from './paging.js';
|
|
3
|
-
import { record, unplayable } from './tape.js';
|
|
3
|
+
import { record, taping, unplayable } from './tape.js';
|
|
4
4
|
/** Notes a motion patch that may hold state for a subject no voice playing it reaches. */
|
|
5
5
|
export function stray(mix, motion, subject) {
|
|
6
6
|
const list = mix.strays.get(subject);
|
|
@@ -24,7 +24,7 @@ export function unplay(mix, voice) {
|
|
|
24
24
|
if (voice.named === null)
|
|
25
25
|
mix.strayAll.add(motion);
|
|
26
26
|
else
|
|
27
|
-
for (const subject of voice.named)
|
|
27
|
+
for (const subject of voice.named.list)
|
|
28
28
|
stray(mix, motion, subject);
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
@@ -45,19 +45,14 @@ export function motionOwner(mix) {
|
|
|
45
45
|
seq() {
|
|
46
46
|
return mix.deref()?.transport.seq ?? Number.NaN;
|
|
47
47
|
},
|
|
48
|
+
early() {
|
|
49
|
+
const m = mix.deref();
|
|
50
|
+
return m !== undefined && (m.syncing || !m.looked);
|
|
51
|
+
},
|
|
48
52
|
changed(id, motion, subject, change) {
|
|
49
53
|
const m = mix.deref();
|
|
50
|
-
if (m
|
|
51
|
-
|
|
52
|
-
record(m, 'motion', (stage) => {
|
|
53
|
-
const to = stage.mix(m);
|
|
54
|
-
if (to === undefined)
|
|
55
|
-
return;
|
|
56
|
-
if (to !== m)
|
|
57
|
-
return changeAhead(to, id, motion, subject, change);
|
|
58
|
-
const v = cuedById(m, id) ?? m.gone.find((g) => g.id === id);
|
|
59
|
-
(v?.motion ?? motion).change(subject, { ...change });
|
|
60
|
-
});
|
|
54
|
+
if (m !== undefined && taping(m))
|
|
55
|
+
recordChange(m, id, motion, subject, change);
|
|
61
56
|
},
|
|
62
57
|
page(id, stream, subject, out) {
|
|
63
58
|
const m = mix.deref();
|
|
@@ -84,6 +79,18 @@ export function motionOwner(mix) {
|
|
|
84
79
|
},
|
|
85
80
|
};
|
|
86
81
|
}
|
|
82
|
+
// Apart from `changed`, whose body would otherwise make this closure's context on every change.
|
|
83
|
+
function recordChange(m, id, motion, subject, change) {
|
|
84
|
+
record(m, 'motion', (stage) => {
|
|
85
|
+
const to = stage.mix(m);
|
|
86
|
+
if (to === undefined)
|
|
87
|
+
return;
|
|
88
|
+
if (to !== m)
|
|
89
|
+
return changeAhead(to, id, motion, subject, change);
|
|
90
|
+
const v = cuedById(m, id) ?? m.gone.find((g) => g.id === id);
|
|
91
|
+
(v?.motion ?? motion).change(subject, { ...change });
|
|
92
|
+
});
|
|
93
|
+
}
|
|
87
94
|
/**
|
|
88
95
|
* A retarget or push the tape holds, made for a read ahead: kept on its transport for the patch
|
|
89
96
|
* to apply as it reads, since the patch's own state is the live mix's.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { Curve } from './easing.js';
|
|
2
|
+
import type { Motions } from './motions.js';
|
|
3
|
+
import type { MotionSpec } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* One closed-form stretch: released at `at` (voice ms) from `x0` moving at `v0`, toward `to`, over
|
|
6
|
+
* `ms` for a tween (0 for any other shape).
|
|
7
|
+
*/
|
|
8
|
+
export interface Segment {
|
|
9
|
+
at: number;
|
|
10
|
+
ms: number;
|
|
11
|
+
x0: number[];
|
|
12
|
+
v0: number[];
|
|
13
|
+
to: number[];
|
|
14
|
+
/** The change that released it; undefined for a subject's first stretch. */
|
|
15
|
+
change?: Change;
|
|
16
|
+
}
|
|
17
|
+
export interface Change {
|
|
18
|
+
/**
|
|
19
|
+
* Voice ms it takes effect at; absent, until the subject's next read stamps it with that read's
|
|
20
|
+
* time, for one made while no frame had met the subject.
|
|
21
|
+
*/
|
|
22
|
+
at?: number;
|
|
23
|
+
to?: number[];
|
|
24
|
+
/** Where it moves from, in place of where its stretch has it then. */
|
|
25
|
+
x?: number[];
|
|
26
|
+
v?: number[];
|
|
27
|
+
/** The mix clock when it was made, NaN where no mix was playing the patch. */
|
|
28
|
+
made?: number;
|
|
29
|
+
/** The frame it was made in, which a rewind partitions by; NaN where no mix was playing the patch. */
|
|
30
|
+
seq?: number;
|
|
31
|
+
/** Whether it was made before its frame was read, so a read of what that frame showed has it. */
|
|
32
|
+
early?: boolean;
|
|
33
|
+
}
|
|
34
|
+
/** A record of a motion patch's history leaving memory, at a mix time and frame. */
|
|
35
|
+
export interface Paging {
|
|
36
|
+
at: number;
|
|
37
|
+
seq: number;
|
|
38
|
+
data: unknown;
|
|
39
|
+
}
|
|
40
|
+
/** A subject's run as plain data: its flags, its stretches oldest first, and changes still to apply. */
|
|
41
|
+
export interface Run {
|
|
42
|
+
flags: number;
|
|
43
|
+
stretches: Segment[];
|
|
44
|
+
pending: Change[] | undefined;
|
|
45
|
+
}
|
|
46
|
+
/** `n` numbers of `from` from `at`, as an array of their own. */
|
|
47
|
+
export declare function numbers(from: Float64Array, at: number, n: number): number[];
|
|
48
|
+
/**
|
|
49
|
+
* A subject's flags: its value is a number; it has changes pending; it has older stretches; the
|
|
50
|
+
* stretch it is playing was found landed, which holds until another replaces it.
|
|
51
|
+
*/
|
|
52
|
+
export declare const enum RunFlag {
|
|
53
|
+
SCALAR = 1,
|
|
54
|
+
PENDING = 2,
|
|
55
|
+
OLDER = 4,
|
|
56
|
+
LANDED = 8
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The mix playing a patch, asked with its voice's id: an owner and an id, where a pair of closures
|
|
60
|
+
* cost two functions, their contexts and a weak reference per voice.
|
|
61
|
+
*/
|
|
62
|
+
export interface MotionOwner {
|
|
63
|
+
/** The subject's voice time at the mix's latest frame; NaN where no frame of the voice met it. */
|
|
64
|
+
frame(id: number, subject: unknown): number;
|
|
65
|
+
/**
|
|
66
|
+
* Brings a subject the voice faded out back to it, so a change is not made for nothing: its
|
|
67
|
+
* voice time now, which a change bringing it back is made at; NaN for any other subject.
|
|
68
|
+
*/
|
|
69
|
+
revive(id: number, subject: unknown): number;
|
|
70
|
+
/** The mix clock at its latest frame; NaN before the first. */
|
|
71
|
+
now(): number;
|
|
72
|
+
/** The number of the frame the mix is playing. */
|
|
73
|
+
seq(): number;
|
|
74
|
+
/** Whether a change made now comes before anything read the frame. */
|
|
75
|
+
early(): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* The host made a change, already given its time, which a seek makes again on the patch its
|
|
78
|
+
* voice plays then: a voice a history store paged out comes back with a patch of its own.
|
|
79
|
+
*/
|
|
80
|
+
changed<I>(id: number, motion: Motions<I>, subject: I, change: Change): void;
|
|
81
|
+
/** History leaving memory for a subject, which a mix with a history store pages out. */
|
|
82
|
+
page(id: number, stream: 'released' | 'stretch', subject: unknown, out: Paging[]): void;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* What a mix keeping copies of a patch's stretches is told, with its id and the subject's number,
|
|
86
|
+
* before one changes.
|
|
87
|
+
*/
|
|
88
|
+
export interface Watcher {
|
|
89
|
+
stretchChanged(id: number, s: number): void;
|
|
90
|
+
}
|
|
91
|
+
export interface Shape<I> {
|
|
92
|
+
from: (subject: I) => number[];
|
|
93
|
+
/** How fast each axis starts moving, given where it starts: still unless the options say. */
|
|
94
|
+
velocity: (subject: I, x: number[]) => number[];
|
|
95
|
+
/**
|
|
96
|
+
* Where it heads when released from `x` at `v`, given where it was heading; `put` for a stretch a
|
|
97
|
+
* `set` released.
|
|
98
|
+
*/
|
|
99
|
+
aim: (x: number[], v: number[], was: number[] | null, subject: I, put: boolean) => number[];
|
|
100
|
+
/** `[form, settle, k1, k2, k3]`. */
|
|
101
|
+
law: readonly number[];
|
|
102
|
+
/** Whether a subject's value is a number rather than an array. */
|
|
103
|
+
scalar: (subject: I) => boolean;
|
|
104
|
+
/** Whether every subject's value is a number; undefined where that depends on the subject. */
|
|
105
|
+
scalarEvery(): boolean | undefined;
|
|
106
|
+
/** A tween's easing, which its law cannot hold; undefined, but present, on every other shape. */
|
|
107
|
+
ease: Curve | undefined;
|
|
108
|
+
/** A tween's ms for a stretch the subject starts now; undefined, but present, on the rest. */
|
|
109
|
+
ms: ((subject: I) => number) | undefined;
|
|
110
|
+
/** The patch's kind and constants, as `Patch.motion` reports them. */
|
|
111
|
+
spec(): MotionSpec;
|
|
112
|
+
}
|
package/dist/stretch.js
ADDED
|
@@ -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
|
+
}
|
package/dist/subject.js
ADDED
|
@@ -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
|
|
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
|
|
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
|
|
25
|
-
* default animation frames where they exist, and a timer where they don't, as in a worker
|
|
26
|
-
*
|
|
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
|
/**
|
package/dist/transport.d.ts
CHANGED
|
@@ -31,14 +31,6 @@ export interface Frame {
|
|
|
31
31
|
at: number;
|
|
32
32
|
u: number;
|
|
33
33
|
}
|
|
34
|
-
/** Where history is cut for a seek or read: what frame `seq` made, and before it, is kept. */
|
|
35
|
-
export interface Cut {
|
|
36
|
-
seq: number;
|
|
37
|
-
/** For a read of what a frame showed: of that frame's own changes, only those made before it was read. */
|
|
38
|
-
strict: boolean;
|
|
39
|
-
}
|
|
40
|
-
/** Whether a change made in frame `seq` falls inside `cut`; `early` for one made before the frame was read. */
|
|
41
|
-
export declare function within(cut: Cut, seq: number, early?: boolean): boolean;
|
|
42
34
|
/**
|
|
43
35
|
* The clock its mixes play on: host time less what `rebase` took out, at the rate its `pace`
|
|
44
36
|
* sets, moved by `sync` and `seek`, and the tape of calls a seek plays again. A mix made alone
|
package/dist/transport.js
CHANGED
|
@@ -11,10 +11,6 @@ import { hostAt, record, replay, tapeOf } from './tape.js';
|
|
|
11
11
|
import { gave, historyFor } from './watch.js';
|
|
12
12
|
/** How far the tape's reach moves before it is pruned again, ms of mix time. */
|
|
13
13
|
const TAPE_STEP_MS = 1000;
|
|
14
|
-
/** Whether a change made in frame `seq` falls inside `cut`; `early` for one made before the frame was read. */
|
|
15
|
-
export function within(cut, seq, early = false) {
|
|
16
|
-
return seq < cut.seq || (seq === cut.seq && (!cut.strict || early));
|
|
17
|
-
}
|
|
18
14
|
/**
|
|
19
15
|
* The clock its mixes play on: host time less what `rebase` took out, at the rate its `pace`
|
|
20
16
|
* sets, moved by `sync` and `seek`, and the tape of calls a seek plays again. A mix made alone
|
package/dist/turns.d.ts
CHANGED
|
@@ -7,11 +7,12 @@ export declare function shortWay(d: number, turn: number): number;
|
|
|
7
7
|
* `fold`, which takes its axes as one value.
|
|
8
8
|
*/
|
|
9
9
|
export declare function turnInto(ch: Laned, values: Float64Array, base: number, value: unknown, w: number): void;
|
|
10
|
-
/** `turnInto` for a value held as numbers at `from` in `source`, as a
|
|
10
|
+
/** `turnInto` for a value held as numbers at `from` in `source`, as a role holds what it gathered. */
|
|
11
11
|
export declare function turnFrom(ch: Laned, values: Float64Array, base: number, source: Float64Array, from: number, w: number): void;
|
|
12
12
|
/**
|
|
13
|
-
* A
|
|
14
|
-
* the channel's own `lerp
|
|
13
|
+
* A role member's value for a channel not lerped straight across, lerped by `u` into what the
|
|
14
|
+
* members before it left at `base` through the channel's own `lerp`, or an angle's short way round;
|
|
15
|
+
* the first member's value as it is, where `taken` is 0.
|
|
15
16
|
*/
|
|
16
17
|
export declare function turnToward(ch: Laned, values: Float64Array, base: number, value: unknown, taken: number, u: number): void;
|
|
17
18
|
/** Sets every numbered subject's values on a lane to the channel's rest, as a fill starts from. */
|
package/dist/turns.js
CHANGED
|
@@ -28,7 +28,7 @@ export function turnInto(ch, values, base, value, w) {
|
|
|
28
28
|
for (let a = 0; a < axes; a++)
|
|
29
29
|
values[base + a] = out[a];
|
|
30
30
|
}
|
|
31
|
-
/** `turnInto` for a value held as numbers at `from` in `source`, as a
|
|
31
|
+
/** `turnInto` for a value held as numbers at `from` in `source`, as a role holds what it gathered. */
|
|
32
32
|
export function turnFrom(ch, values, base, source, from, w) {
|
|
33
33
|
if (ch.turn > 0) {
|
|
34
34
|
turnInto(ch, values, base, source[from], w);
|
|
@@ -38,8 +38,9 @@ export function turnFrom(ch, values, base, source, from, w) {
|
|
|
38
38
|
turnInto(ch, values, base, other, w);
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
|
-
* A
|
|
42
|
-
* the channel's own `lerp
|
|
41
|
+
* A role member's value for a channel not lerped straight across, lerped by `u` into what the
|
|
42
|
+
* members before it left at `base` through the channel's own `lerp`, or an angle's short way round;
|
|
43
|
+
* the first member's value as it is, where `taken` is 0.
|
|
43
44
|
*/
|
|
44
45
|
export function turnToward(ch, values, base, value, taken, u) {
|
|
45
46
|
if (ch.turn > 0) {
|
package/dist/types/arc.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Handle, OwnerSpec, VoiceSpec } from './voice.js';
|
|
2
2
|
/**
|
|
3
|
-
* One voice of an arc's part
|
|
4
|
-
* fades it across each boundary by `blend`, and holds its first and last frames for the blend.
|
|
3
|
+
* One voice of an arc's part. It is a voice's spec, less what the arc sets for it. The arc places
|
|
4
|
+
* it, fades it across each boundary by `blend`, and holds its first and last frames for the blend.
|
|
5
5
|
*
|
|
6
6
|
* @category score
|
|
7
7
|
*/
|
|
@@ -13,15 +13,15 @@ export interface ArcVoice<I, O, H = unknown> extends Omit<VoiceSpec<I, O, H>, 'o
|
|
|
13
13
|
duration?: number;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
* One part of an arc
|
|
17
|
-
* the longest.
|
|
16
|
+
* One part of an arc. It is a voice, or several layered together that play as one and last as
|
|
17
|
+
* long as the longest.
|
|
18
18
|
*
|
|
19
19
|
* @category score
|
|
20
20
|
*/
|
|
21
21
|
export type ArcPart<I, O, H = unknown> = ArcVoice<I, O, H> | readonly ArcVoice<I, O, H>[];
|
|
22
22
|
/**
|
|
23
|
-
* What `arc` takes
|
|
24
|
-
* `exit`, any of which may be left out.
|
|
23
|
+
* What `arc` takes. It is an owner over three parts that hand over in order, `enter`, `active`
|
|
24
|
+
* and `exit`, any of which may be left out.
|
|
25
25
|
*
|
|
26
26
|
* @category score
|
|
27
27
|
*/
|
|
@@ -33,22 +33,23 @@ export interface ArcSpec<I, O, H = unknown> extends Omit<OwnerSpec<I, H>, 'freez
|
|
|
33
33
|
/** What plays as it leaves. Its start is the arc's `out` mark, and its end the arc's `end`. */
|
|
34
34
|
exit?: ArcPart<I, O, H>;
|
|
35
35
|
/**
|
|
36
|
-
* How long `active` plays, ms on the arc's clock,
|
|
37
|
-
* passes;
|
|
38
|
-
* for good, and 0 with no `active`.
|
|
36
|
+
* How long `active` plays, ms on the arc's clock, or `'open'`. A number loops `active` for it
|
|
37
|
+
* unless its `loop` says how many passes; `'open'` plays it until `release`. Default: `active`'s
|
|
38
|
+
* own length, held open where it loops for good, and 0 with no `active`.
|
|
39
39
|
*/
|
|
40
40
|
hold?: number | 'open';
|
|
41
41
|
/** A crossfade across each boundary, ms, half before it and half after. Default 0. */
|
|
42
42
|
blend?: number;
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
45
|
-
* An arc's handle
|
|
45
|
+
* An arc's handle, which can release its hold. It is an owner's handle, and `release` ends the
|
|
46
|
+
* hold. `fade` takes it out with no exit.
|
|
46
47
|
*
|
|
47
48
|
* @category score
|
|
48
49
|
*/
|
|
49
50
|
export interface ArcHandle<I = unknown> extends Handle<I> {
|
|
50
51
|
/**
|
|
51
|
-
* Ends the hold now and plays the exit
|
|
52
|
+
* Ends the hold now and plays the exit. Its blend starts here; where the enter is still
|
|
52
53
|
* playing, the exit follows it. Nothing once the exit has begun or the arc is fading.
|
|
53
54
|
*/
|
|
54
55
|
release(): void;
|
package/dist/types/channel.d.ts
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export interface Channel<V> {
|
|
7
7
|
/**
|
|
8
|
-
* Names this channel's arithmetic
|
|
9
|
-
* another of the same name. Two channels of one kind must fold identically; the stock
|
|
10
|
-
* as `'sum'` or `'vec(3, sum)'`. Absent, a channel matches only itself.
|
|
8
|
+
* Names this channel's arithmetic. A patch written against one channel can then be checked
|
|
9
|
+
* against another of the same name. Two channels of one kind must fold identically; the stock
|
|
10
|
+
* ones set it, as `'sum'` or `'vec(3, sum)'`. Absent, a channel matches only itself.
|
|
11
11
|
*/
|
|
12
12
|
kind?: string;
|
|
13
13
|
/**
|
|
@@ -16,21 +16,25 @@ export interface Channel<V> {
|
|
|
16
16
|
* carries speed can push it out; overshoot stops flat at the bound.
|
|
17
17
|
*/
|
|
18
18
|
bounds?: readonly [min: number, max: number];
|
|
19
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* The value that changes nothing when folded in, such as 0 for `sum` or 1 for `mul`. Absent means
|
|
21
|
+
* the channel has none: it replaces rather than contributes.
|
|
22
|
+
*/
|
|
20
23
|
rest?: V;
|
|
21
24
|
/** Fold two contributions into one. */
|
|
22
25
|
merge(a: V, b: V): V;
|
|
23
26
|
/** Fade toward `rest` by weight 0..1. Required when `rest` is set; absent otherwise. */
|
|
24
27
|
scale?(v: V, w: number): V;
|
|
25
|
-
/** Interpolate, for retargeting, for blending alternatives, and for folding a
|
|
28
|
+
/** Interpolate, for retargeting, for blending alternatives, and for folding a role. */
|
|
26
29
|
lerp(a: V, b: V, u: number): V;
|
|
27
30
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
31
|
+
* Folds a weighted contribution into `into` in place. Optional. It computes
|
|
32
|
+
* `merge(into, scale(v, w))`, written into `into` and returned, so a channel whose values are
|
|
33
|
+
* objects need not allocate per contribution. The mix only hands it a value it made.
|
|
30
34
|
*/
|
|
31
35
|
fold?(into: V, v: V, w: number): V;
|
|
32
36
|
/**
|
|
33
|
-
*
|
|
37
|
+
* A fresh copy of `v`. Optional. The mix makes one of `rest` for `fold` to write into. The mix
|
|
34
38
|
* copies arrays, typed arrays and plain objects itself; a channel whose `rest` is anything else,
|
|
35
39
|
* such as a class instance, and that has `fold`, needs this or `cue` refuses it.
|
|
36
40
|
*/
|