@msb235/blits 0.10.0 → 0.12.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 +248 -0
- package/README.md +15 -4
- package/dist/arcs.d.ts +40 -0
- package/dist/arcs.js +239 -0
- package/dist/blend.js +1 -5
- package/dist/book.d.ts +2 -0
- package/dist/book.js +27 -3
- package/dist/chain.d.ts +17 -1
- package/dist/chain.js +57 -15
- package/dist/channels.d.ts +2 -0
- package/dist/channels.js +12 -1
- package/dist/clock.d.ts +14 -0
- package/dist/clock.js +9 -1
- package/dist/clone.js +16 -4
- package/dist/columns.d.ts +4 -5
- package/dist/columns.js +11 -5
- package/dist/crowd.d.ts +1 -1
- package/dist/crowd.js +4 -1
- package/dist/cue.js +63 -7
- package/dist/departed.d.ts +8 -3
- package/dist/departed.js +76 -29
- package/dist/due.d.ts +4 -0
- package/dist/due.js +16 -3
- package/dist/easing.d.ts +12 -1
- package/dist/easing.js +7 -1
- package/dist/everyone.d.ts +14 -1
- package/dist/everyone.js +27 -2
- package/dist/fade.d.ts +12 -5
- package/dist/fade.js +57 -19
- package/dist/fill.js +16 -9
- package/dist/fit.d.ts +8 -1
- package/dist/fit.js +7 -3
- package/dist/fold.d.ts +1 -1
- package/dist/fold.js +112 -9
- package/dist/frames.d.ts +2 -0
- package/dist/frames.js +17 -0
- package/dist/gather.js +38 -7
- package/dist/handle.d.ts +7 -2
- package/dist/handle.js +28 -12
- package/dist/held.d.ts +13 -2
- package/dist/held.js +43 -9
- package/dist/history.d.ts +25 -2
- package/dist/history.js +163 -35
- package/dist/hosts.js +45 -17
- package/dist/index.d.ts +5 -2
- package/dist/index.js +3 -1
- package/dist/keyfill.js +3 -1
- package/dist/lane.d.ts +1 -1
- package/dist/lane.js +3 -1
- package/dist/lanes.d.ts +31 -7
- package/dist/lanes.js +57 -6
- package/dist/lean.d.ts +15 -0
- package/dist/lean.js +23 -0
- package/dist/leavings.d.ts +6 -1
- package/dist/leavings.js +16 -2
- package/dist/marks.d.ts +7 -3
- package/dist/marks.js +105 -27
- package/dist/meet.js +1 -0
- package/dist/mixer.d.ts +35 -6
- package/dist/mixer.js +113 -45
- package/dist/motion.d.ts +4 -1
- package/dist/motion.js +16 -2
- package/dist/motions.d.ts +4 -0
- package/dist/motions.js +45 -11
- package/dist/move.js +35 -12
- package/dist/numbers.d.ts +5 -1
- package/dist/numbers.js +4 -0
- package/dist/owner.d.ts +18 -2
- package/dist/owner.js +44 -3
- package/dist/pack.d.ts +1 -0
- package/dist/pack.js +3 -0
- package/dist/place.d.ts +8 -0
- package/dist/place.js +16 -8
- package/dist/placed.d.ts +19 -0
- package/dist/placed.js +54 -0
- package/dist/project.d.ts +5 -2
- package/dist/project.js +238 -34
- package/dist/pull.js +37 -8
- package/dist/qualify.d.ts +10 -0
- package/dist/qualify.js +60 -3
- package/dist/reading.d.ts +8 -1
- package/dist/reading.js +8 -1
- package/dist/record.d.ts +6 -0
- package/dist/record.js +2 -0
- package/dist/restored.d.ts +69 -17
- package/dist/restored.js +163 -50
- package/dist/revive.d.ts +6 -3
- package/dist/revive.js +11 -3
- package/dist/roster.js +2 -1
- package/dist/rows.js +15 -5
- package/dist/seek.d.ts +7 -2
- package/dist/seek.js +152 -43
- package/dist/shared.d.ts +5 -0
- package/dist/shared.js +5 -0
- package/dist/signals.d.ts +10 -0
- package/dist/signals.js +17 -0
- package/dist/spans.d.ts +5 -0
- package/dist/spans.js +75 -5
- package/dist/store.d.ts +13 -0
- package/dist/store.js +23 -0
- package/dist/strays.js +50 -2
- package/dist/tape.d.ts +29 -4
- package/dist/tape.js +49 -11
- package/dist/touch.js +3 -2
- package/dist/transport.d.ts +11 -2
- package/dist/transport.js +26 -10
- package/dist/types/arc.d.ts +55 -0
- package/dist/types/arc.js +1 -0
- package/dist/types/mix.d.ts +57 -14
- package/dist/types/patch.d.ts +5 -1
- package/dist/types/place.d.ts +11 -4
- package/dist/types/transport.d.ts +12 -3
- package/dist/types/voice.d.ts +72 -5
- package/dist/types/watch.d.ts +126 -0
- package/dist/types/watch.js +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/unpage.d.ts +6 -1
- package/dist/unpage.js +34 -2
- package/dist/voice.d.ts +93 -16
- package/dist/voice.js +60 -3
- package/dist/watch.d.ts +26 -0
- package/dist/watch.js +441 -0
- package/dist/weigh.d.ts +13 -2
- package/dist/weigh.js +10 -3
- package/docs/schema.html +106 -38
- package/package.json +10 -4
package/dist/tape.js
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import { move } from './move.js';
|
|
2
|
+
const live = { transport: (of) => of, mix: (of) => of };
|
|
3
|
+
/** The stage the tape is playing calls on; the live one outside a read ahead's replay. */
|
|
4
|
+
let stage = live;
|
|
5
|
+
/** What a call threw on a read ahead's stage, for `replay` to throw once the tape has the entry back. */
|
|
6
|
+
let failed;
|
|
7
|
+
/** Refuses a recorded call a read ahead's copies cannot take. */
|
|
8
|
+
export function unplayable(what) {
|
|
9
|
+
throw new Error(`blits: the tape holds ${what}, which a read ahead cannot play; seek there to see it`);
|
|
10
|
+
}
|
|
2
11
|
/** What a recorded call's `invert` gives: a mix goes back by restoring, never by undoing a call. */
|
|
3
12
|
const undone = { apply() { }, invert: () => undone };
|
|
4
13
|
/**
|
|
@@ -15,7 +24,10 @@ export function tapeOf(transport) {
|
|
|
15
24
|
coalesceWindowMs: 0,
|
|
16
25
|
});
|
|
17
26
|
}
|
|
18
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* Records a host call, which `again` makes once more when the mix plays past it after a seek, or
|
|
29
|
+
* when a read ahead does, on the stage it is given.
|
|
30
|
+
*/
|
|
19
31
|
export function record(on, label, again) {
|
|
20
32
|
const tape = on.tape;
|
|
21
33
|
if (tape === undefined || on.replaying || on.projecting)
|
|
@@ -23,7 +35,16 @@ export function record(on, label, again) {
|
|
|
23
35
|
const op = {
|
|
24
36
|
label,
|
|
25
37
|
apply() {
|
|
26
|
-
|
|
38
|
+
if (stage === live)
|
|
39
|
+
again(stage);
|
|
40
|
+
// Thrown inside the tape's `redo`, it would leave the tape without the entry.
|
|
41
|
+
else
|
|
42
|
+
try {
|
|
43
|
+
again(stage);
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
failed ??= { error: e };
|
|
47
|
+
}
|
|
27
48
|
},
|
|
28
49
|
invert: () => undone,
|
|
29
50
|
};
|
|
@@ -33,16 +54,26 @@ export function record(on, label, again) {
|
|
|
33
54
|
export function hostAt(clock, t) {
|
|
34
55
|
return clock.pace === null ? t : clock.pace.timeOf(t);
|
|
35
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* The host time a move ahead to mix time `t` lands at: never behind the clock's own, since rate 0
|
|
59
|
+
* reads `t` at every host time from the earliest `hostAt` gives, and a call stamped earlier than
|
|
60
|
+
* one already on the tape would cut it out of order.
|
|
61
|
+
*/
|
|
62
|
+
export function hostAhead(clock, t) {
|
|
63
|
+
const at = hostAt(clock, t);
|
|
64
|
+
return clock.u > at ? clock.u : at;
|
|
65
|
+
}
|
|
36
66
|
/**
|
|
37
67
|
* Makes the recorded calls `due` by the host time each was made at again, each host time's in a
|
|
38
68
|
* frame of its own with every mix on the transport moved to where it stood then, as the host made
|
|
39
|
-
* them. Answers the host time of the last frame it played, NaN for none.
|
|
69
|
+
* them. Answers the host time of the last frame it played, NaN for none. Given `onto` and the
|
|
70
|
+
* stage of its copies, it makes them on those, and the caller puts the tape back.
|
|
40
71
|
*/
|
|
41
|
-
export function replay(transport, due) {
|
|
72
|
+
export function replay(transport, due, onto = transport, on = live) {
|
|
42
73
|
const tape = transport.tape;
|
|
43
74
|
if (tape === undefined)
|
|
44
75
|
return Number.NaN;
|
|
45
|
-
const u =
|
|
76
|
+
const u = onto.u;
|
|
46
77
|
let last = Number.NaN;
|
|
47
78
|
try {
|
|
48
79
|
for (;;) {
|
|
@@ -51,23 +82,30 @@ export function replay(transport, due) {
|
|
|
51
82
|
return last;
|
|
52
83
|
if (at !== last) {
|
|
53
84
|
last = at;
|
|
54
|
-
|
|
55
|
-
const now =
|
|
56
|
-
if (now >
|
|
57
|
-
for (const m of
|
|
85
|
+
onto.u = at;
|
|
86
|
+
const now = onto.pace === null ? at : onto.pace.reading(at);
|
|
87
|
+
if (now > onto.now)
|
|
88
|
+
for (const m of onto.members)
|
|
58
89
|
move(m, now);
|
|
59
|
-
|
|
90
|
+
onto.tick(onto.now);
|
|
60
91
|
}
|
|
61
92
|
transport.replaying = true;
|
|
93
|
+
stage = on;
|
|
62
94
|
try {
|
|
63
95
|
tape.redo();
|
|
64
96
|
}
|
|
65
97
|
finally {
|
|
66
98
|
transport.replaying = false;
|
|
99
|
+
stage = live;
|
|
100
|
+
}
|
|
101
|
+
if (failed !== undefined) {
|
|
102
|
+
const { error } = failed;
|
|
103
|
+
failed = undefined;
|
|
104
|
+
throw error;
|
|
67
105
|
}
|
|
68
106
|
}
|
|
69
107
|
}
|
|
70
108
|
finally {
|
|
71
|
-
|
|
109
|
+
onto.u = u;
|
|
72
110
|
}
|
|
73
111
|
}
|
package/dist/touch.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { headOf } from './chain.js';
|
|
1
2
|
import { restamp } from './everyone.js';
|
|
2
3
|
import { nextFrame } from './move.js';
|
|
3
4
|
/**
|
|
@@ -16,10 +17,10 @@ export function touch(mix, subject) {
|
|
|
16
17
|
}
|
|
17
18
|
else {
|
|
18
19
|
// No voice's `seeks` is below 0, so no record stamped with it reads as current.
|
|
19
|
-
let held = mix
|
|
20
|
+
let held = headOf(mix, subject) ?? null;
|
|
20
21
|
for (; held !== null; held = held.next)
|
|
21
22
|
held.seeks = -1;
|
|
22
|
-
const slot = mix
|
|
23
|
+
const slot = headOf(mix, subject)?.slot ?? -1;
|
|
23
24
|
for (const voice of mix.sharers)
|
|
24
25
|
restamp(voice, slot);
|
|
25
26
|
}
|
package/dist/transport.d.ts
CHANGED
|
@@ -94,6 +94,11 @@ export declare class Transport implements TransportApi {
|
|
|
94
94
|
settle(): void;
|
|
95
95
|
/** The frame the rate was first set in, which a seek or read back to before it finds unset. */
|
|
96
96
|
pacedSeq: number;
|
|
97
|
+
/**
|
|
98
|
+
* On a read ahead's own transport, the retargets and pushes its tape's calls made, which
|
|
99
|
+
* `reading.ahead` hands the motion patches while it reads.
|
|
100
|
+
*/
|
|
101
|
+
ahead: Map<object, Map<unknown, unknown[]>>;
|
|
97
102
|
/** True while the tape makes a recorded call again, so it is not recorded twice. */
|
|
98
103
|
replaying: boolean;
|
|
99
104
|
announced: Announced[];
|
|
@@ -114,7 +119,9 @@ export declare class Transport implements TransportApi {
|
|
|
114
119
|
drop<I, O, H>(mix: Mix<I, O, H>): void;
|
|
115
120
|
/** A seek back to frame `seq`: every mix dropped after it is back on, as it stood then. */
|
|
116
121
|
undrop(seq: number): void;
|
|
117
|
-
seek(
|
|
122
|
+
seek(to: number | {
|
|
123
|
+
readonly frame: number;
|
|
124
|
+
}): void;
|
|
118
125
|
prepare(time: number): Promise<void>;
|
|
119
126
|
announce(name: string, opts: {
|
|
120
127
|
at?: number;
|
|
@@ -122,7 +129,9 @@ export declare class Transport implements TransportApi {
|
|
|
122
129
|
tags?: readonly string[];
|
|
123
130
|
}): void;
|
|
124
131
|
marks(from: number, to: number): Marked[];
|
|
125
|
-
project(
|
|
132
|
+
project(at: number | {
|
|
133
|
+
readonly frame: number;
|
|
134
|
+
}): TransportProjection;
|
|
126
135
|
get live(): boolean;
|
|
127
136
|
get inert(): boolean;
|
|
128
137
|
onWake(fn: () => void): () => void;
|
package/dist/transport.js
CHANGED
|
@@ -8,6 +8,7 @@ import { projectAll } from './project.js';
|
|
|
8
8
|
import { scoredDrop, scoredJoin } from './scored.js';
|
|
9
9
|
import { seek } from './seek.js';
|
|
10
10
|
import { hostAt, record, replay, tapeOf } from './tape.js';
|
|
11
|
+
import { gave, historyFor } from './watch.js';
|
|
11
12
|
/** How far the tape's reach moves before it is pruned again, ms of mix time. */
|
|
12
13
|
const TAPE_STEP_MS = 1000;
|
|
13
14
|
/** Whether a change made in frame `seq` falls inside `cut`; `early` for one made before the frame was read. */
|
|
@@ -68,6 +69,11 @@ export class Transport {
|
|
|
68
69
|
}
|
|
69
70
|
/** The frame the rate was first set in, which a seek or read back to before it finds unset. */
|
|
70
71
|
pacedSeq = Number.POSITIVE_INFINITY;
|
|
72
|
+
/**
|
|
73
|
+
* On a read ahead's own transport, the retargets and pushes its tape's calls made, which
|
|
74
|
+
* `reading.ahead` hands the motion patches while it reads.
|
|
75
|
+
*/
|
|
76
|
+
ahead = new Map();
|
|
71
77
|
/** True while the tape makes a recorded call again, so it is not recorded twice. */
|
|
72
78
|
replaying = false;
|
|
73
79
|
announced = [];
|
|
@@ -110,7 +116,11 @@ export class Transport {
|
|
|
110
116
|
m.dropped = true;
|
|
111
117
|
if (this.history !== undefined) {
|
|
112
118
|
this.dropped.push({ mix: m, at: this.now, seq: this.seq });
|
|
113
|
-
record(this, 'drop', () =>
|
|
119
|
+
record(this, 'drop', (stage) => {
|
|
120
|
+
const to = stage.mix(m);
|
|
121
|
+
if (to !== undefined)
|
|
122
|
+
stage.transport(this).drop(to);
|
|
123
|
+
});
|
|
114
124
|
}
|
|
115
125
|
}
|
|
116
126
|
/** A seek back to frame `seq`: every mix dropped after it is back on, as it stood then. */
|
|
@@ -124,8 +134,8 @@ export class Transport {
|
|
|
124
134
|
this.join(d.mix, d.mix.slot);
|
|
125
135
|
}
|
|
126
136
|
}
|
|
127
|
-
seek(
|
|
128
|
-
seek(this,
|
|
137
|
+
seek(to) {
|
|
138
|
+
seek(this, to);
|
|
129
139
|
}
|
|
130
140
|
prepare(time) {
|
|
131
141
|
return prepare(this, time);
|
|
@@ -138,8 +148,8 @@ export class Transport {
|
|
|
138
148
|
marks(from, to) {
|
|
139
149
|
return listedAll(this, from, to).map(({ order: _, ...m }) => m);
|
|
140
150
|
}
|
|
141
|
-
project(
|
|
142
|
-
return projectAll(this,
|
|
151
|
+
project(at) {
|
|
152
|
+
return projectAll(this, at);
|
|
143
153
|
}
|
|
144
154
|
get live() {
|
|
145
155
|
return this.members.some((m) => m.live);
|
|
@@ -286,7 +296,8 @@ export class Transport {
|
|
|
286
296
|
if (!(rate >= 0 && rate < Number.POSITIVE_INFINITY))
|
|
287
297
|
throw new RangeError(`blits: a mix's rate is a finite number, 0 or more, not ${rate}`);
|
|
288
298
|
if (this.pace === null) {
|
|
289
|
-
|
|
299
|
+
// A read ahead keeps every clock too: it moves once across calls a mix met frame by frame.
|
|
300
|
+
this.pace = new Pace(this.history !== undefined || this.projecting);
|
|
290
301
|
this.pacedSeq = this.seq;
|
|
291
302
|
// Until now mix time was host time, so a pending voice's start is the host time it was given.
|
|
292
303
|
for (const m of this.members)
|
|
@@ -298,7 +309,7 @@ export class Transport {
|
|
|
298
309
|
this.pace.change(this.u, rate, over, reach, this.seq);
|
|
299
310
|
for (const m of this.members)
|
|
300
311
|
m.stir();
|
|
301
|
-
record(this, 'rate', () => this.ramp(rate, over));
|
|
312
|
+
record(this, 'rate', (stage) => stage.transport(this).ramp(rate, over));
|
|
302
313
|
}
|
|
303
314
|
}
|
|
304
315
|
/** Puts a mark on a score: one the transport announced, or a mix on it, `slot`. */
|
|
@@ -316,8 +327,9 @@ export function announce(transport, name, opts, slot, mix) {
|
|
|
316
327
|
};
|
|
317
328
|
transport.announced.push(mark);
|
|
318
329
|
transport.settle();
|
|
319
|
-
record(transport, 'announce', () => {
|
|
320
|
-
|
|
330
|
+
record(transport, 'announce', (stage) => {
|
|
331
|
+
const to = stage.transport(transport);
|
|
332
|
+
to.announced.push({ ...mark, seq: to.seq });
|
|
321
333
|
});
|
|
322
334
|
}
|
|
323
335
|
/**
|
|
@@ -326,5 +338,9 @@ export function announce(transport, name, opts, slot, mix) {
|
|
|
326
338
|
* @category mix
|
|
327
339
|
*/
|
|
328
340
|
export function transport(opts = {}) {
|
|
329
|
-
|
|
341
|
+
const { history, added } = historyFor(opts);
|
|
342
|
+
const t = new Transport(history, true);
|
|
343
|
+
if (added)
|
|
344
|
+
gave(t);
|
|
345
|
+
return t;
|
|
330
346
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Handle, OwnerSpec, VoiceSpec } from './voice.js';
|
|
2
|
+
/**
|
|
3
|
+
* One voice of an arc's part: a voice's spec, less what the arc sets for it. The arc places it,
|
|
4
|
+
* fades it across each boundary by `blend`, and holds its first and last frames for the blend.
|
|
5
|
+
*
|
|
6
|
+
* @category score
|
|
7
|
+
*/
|
|
8
|
+
export interface ArcVoice<I, O, H = unknown> extends Omit<VoiceSpec<I, O, H>, 'owner' | 'start' | 'anchor' | 'freeze' | 'fade' | 'faster' | 'slower' | 'overlap' | 'ballast' | 'priority' | 'earliest' | 'rank'> {
|
|
9
|
+
/**
|
|
10
|
+
* How long the part holds the arc, ms on the arc's clock. Default: the patch's duration times
|
|
11
|
+
* its passes, which leaves out a `stagger`, so a part whose last subject lands later says so here.
|
|
12
|
+
*/
|
|
13
|
+
duration?: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* One part of an arc: a voice, or several layered together that play as one and last as long as
|
|
17
|
+
* the longest.
|
|
18
|
+
*
|
|
19
|
+
* @category score
|
|
20
|
+
*/
|
|
21
|
+
export type ArcPart<I, O, H = unknown> = ArcVoice<I, O, H> | readonly ArcVoice<I, O, H>[];
|
|
22
|
+
/**
|
|
23
|
+
* What `arc` takes: an owner over three parts that hand over in order, `enter`, `active` and
|
|
24
|
+
* `exit`, any of which may be left out.
|
|
25
|
+
*
|
|
26
|
+
* @category score
|
|
27
|
+
*/
|
|
28
|
+
export interface ArcSpec<I, O, H = unknown> extends Omit<OwnerSpec<I, H>, 'freeze'> {
|
|
29
|
+
/** What plays as it arrives. Its end is the arc's `in` mark. */
|
|
30
|
+
enter?: ArcPart<I, O, H>;
|
|
31
|
+
/** What plays between the two, over the hold. Its end is the arc's `coast` mark. */
|
|
32
|
+
active?: ArcPart<I, O, H>;
|
|
33
|
+
/** What plays as it leaves. Its start is the arc's `out` mark, and its end the arc's `end`. */
|
|
34
|
+
exit?: ArcPart<I, O, H>;
|
|
35
|
+
/**
|
|
36
|
+
* How long `active` plays, ms on the arc's clock, looping for it unless its `loop` says how many
|
|
37
|
+
* passes; or `'open'`, until `release`. Default: `active`'s own length, held open where it loops
|
|
38
|
+
* for good, and 0 with no `active`.
|
|
39
|
+
*/
|
|
40
|
+
hold?: number | 'open';
|
|
41
|
+
/** A crossfade across each boundary, ms, half before it and half after. Default 0. */
|
|
42
|
+
blend?: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* An arc's handle: an owner's, and the release of its hold. `fade` takes it out with no exit.
|
|
46
|
+
*
|
|
47
|
+
* @category score
|
|
48
|
+
*/
|
|
49
|
+
export interface ArcHandle<I = unknown> extends Handle<I> {
|
|
50
|
+
/**
|
|
51
|
+
* Ends the hold now and plays the exit, its blend starting here; where the enter is still
|
|
52
|
+
* playing, the exit follows it. Nothing once the exit has begun or the arc is fading.
|
|
53
|
+
*/
|
|
54
|
+
release(): void;
|
|
55
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/types/mix.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import type { ArcHandle, ArcSpec } from './arc.js';
|
|
1
2
|
import type { Kit } from './channel.js';
|
|
2
3
|
import type { HistoryOptions, Tape } from './history.js';
|
|
3
4
|
import type { Patch, Sent, Signal } from './patch.js';
|
|
4
5
|
import type { Booker, BookOptions, Marked } from './place.js';
|
|
5
6
|
import type { Transport } from './transport.js';
|
|
6
|
-
import type { Handle, OwnerSpec, SpanHandle, SpanSpec, VoiceSpec } from './voice.js';
|
|
7
|
+
import type { BlendMember, Handle, OwnerSpec, SpanHandle, SpanSpec, VoiceSpec } from './voice.js';
|
|
7
8
|
/**
|
|
8
9
|
* How a mix is built: its engine, reduced motion, the host, and its limits.
|
|
9
10
|
*
|
|
@@ -52,6 +53,11 @@ export interface MixOptions<H = unknown> {
|
|
|
52
53
|
* string or number subject is its own key; with a store, an object subject needs this.
|
|
53
54
|
*/
|
|
54
55
|
keyOf?(subject: never): string | number;
|
|
56
|
+
/**
|
|
57
|
+
* What a debugger calls a subject (see `watched`); where it gives nothing, the subject's own
|
|
58
|
+
* `name` or `id`, a DOM element's tag, id and classes, or its class and a number.
|
|
59
|
+
*/
|
|
60
|
+
labelOf?(subject: never): string | undefined;
|
|
55
61
|
/**
|
|
56
62
|
* Whether a channel may run as a lane: computed for every subject at once in flat arrays, when
|
|
57
63
|
* every voice writing it can run that way. On by default; what a host reads is the same either
|
|
@@ -77,7 +83,7 @@ export interface MixOptions<H = unknown> {
|
|
|
77
83
|
/**
|
|
78
84
|
* How sure a projection is of one channel: `exact` where only the clock and known changes drove
|
|
79
85
|
* it; `stepped` where state was advanced across a gap in one go, which is as good as the patch's
|
|
80
|
-
* step makes it; `held` where it depends on input from outside the clock, whose value at that time
|
|
86
|
+
* step makes it, or a signal's state was read back from a copy; `held` where it depends on input from outside the clock, whose value at that time
|
|
81
87
|
* is not known, so the value it had is held.
|
|
82
88
|
*
|
|
83
89
|
* @category mix
|
|
@@ -119,9 +125,11 @@ export interface Mix<I, O, H = unknown> {
|
|
|
119
125
|
/**
|
|
120
126
|
* N voices whose weights split one signal, cued into one locus so they fold as alternatives. The
|
|
121
127
|
* signal is read once per subject per frame, with the first member's setting, and every member
|
|
122
|
-
* takes its share of that one reading
|
|
128
|
+
* takes its share of that one reading, which `share` reads outside the blend; a signal keeping
|
|
129
|
+
* state keeps it once, not per member. One `spec` cues them all, and a member given as a
|
|
130
|
+
* `BlendMember` carries its own `name`, `tags` and `hits` in place of the spec's.
|
|
123
131
|
*/
|
|
124
|
-
blend(
|
|
132
|
+
blend(members: readonly (Patch<I, O, unknown, H> | BlendMember<I, O, H>)[], by: Signal<I, H>, spec?: Omit<VoiceSpec<I, O, H>, 'patch' | 'weight' | 'locus'>): Handle<I>[];
|
|
125
133
|
/**
|
|
126
134
|
* Cues an owner: a voice with no patch that holds the voices cued with `owner` set to its handle,
|
|
127
135
|
* and plays them on its own clock, so they can be placed, timed and faded as one. Its handle acts
|
|
@@ -139,9 +147,23 @@ export interface Mix<I, O, H = unknown> {
|
|
|
139
147
|
* span's to set, so it takes neither `start` nor an anchored start; its `SpanHints` say how it
|
|
140
148
|
* may give way. A span with a budget stays until the budget has passed, though its children
|
|
141
149
|
* finish sooner, so late ones can still join, and its `end` mark is where its children end or
|
|
142
|
-
* its budget does, whichever is later. A voice that loops for good cannot join one.
|
|
150
|
+
* its budget does, whichever is later. A voice that loops for good cannot join one. Throws for
|
|
151
|
+
* a `rate` below 0: a span lays its children out forward from its start, and its handle's `rate`
|
|
152
|
+
* turns it once it plays.
|
|
143
153
|
*/
|
|
144
154
|
span(spec: SpanSpec<I, H>): SpanHandle<I>;
|
|
155
|
+
/**
|
|
156
|
+
* Cues an arc: an owner holding three parts that hand over in order on its clock, `enter`, then
|
|
157
|
+
* `active` for the `hold`, then `exit`, each a voice or several layered. Its marks are its own:
|
|
158
|
+
* `start` as the enter begins, `in` as it ends, `coast` as the hold ends and `out` as the exit
|
|
159
|
+
* begins, which are one time, and `end` as the exit ends, where it leaves and `done` resolves.
|
|
160
|
+
* While the hold is open, `coast`, `out` and `end` are unknown until `release` fixes them. Each
|
|
161
|
+
* part shows its first and last frames through the blends either side of it, and a part left
|
|
162
|
+
* out leaves its time to the one before it. Its `fade` takes it out with no exit. An arc with a
|
|
163
|
+
* finite hold may sit in a span. Throws for a `rate` below 0, a hold below 0, and an `enter` or
|
|
164
|
+
* `exit` that never ends.
|
|
165
|
+
*/
|
|
166
|
+
arc(spec: ArcSpec<I, O, H>): ArcHandle<I>;
|
|
145
167
|
/**
|
|
146
168
|
* The host reports the clock, once a frame. Nothing advances at the call. Throws for a timestamp
|
|
147
169
|
* earlier than the last sync's, short of a `rebase`: the host's clock only goes forward, and
|
|
@@ -194,8 +216,11 @@ export interface Mix<I, O, H = unknown> {
|
|
|
194
216
|
/**
|
|
195
217
|
* Reads the mix at another mix time, without moving it. At the mix's own time it reads what
|
|
196
218
|
* `probe` does: what the host has done since the last sync lands at the next. Ahead of the mix
|
|
197
|
-
* it plays what is cued forward,
|
|
198
|
-
*
|
|
219
|
+
* it plays what is cued forward, with the calls the tape holds after a `seek` back, and while a
|
|
220
|
+
* voice could carry state (a patch that steps, a signal weight) it reads each subject asked about
|
|
221
|
+
* at every known event on the way: each call, and each mark `marks` would list. It throws
|
|
222
|
+
* for the two a copy cannot take: a `drop` of a subject a motion patch holds, and a retarget or
|
|
223
|
+
* push made before its voice met the subject. Behind it, with `history`, it reads the last frame at or before `time`
|
|
199
224
|
* as that frame showed, and throws for a time older than the history reaches. On a transport it
|
|
200
225
|
* reads every mix on it together, so anchors across them answer.
|
|
201
226
|
*
|
|
@@ -204,8 +229,13 @@ export interface Mix<I, O, H = unknown> {
|
|
|
204
229
|
* alone: no state, motion, `from: 'current'`, anchor or owner, no write to its handle, and no channel without a rest
|
|
205
230
|
* at a weight that moves. The mix's rate has never been set. And `time` is no earlier than the
|
|
206
231
|
* last cue, `drop`, `touch`, `announce` or `rebase`, or the last frame a voice left in.
|
|
232
|
+
*
|
|
233
|
+
* Given `{ frame }`, a number `seq` read, it reads that frame as it showed, as `seek` does; it
|
|
234
|
+
* needs `history`.
|
|
207
235
|
*/
|
|
208
|
-
project(
|
|
236
|
+
project(at: number | {
|
|
237
|
+
readonly frame: number;
|
|
238
|
+
}): Projection<I, O>;
|
|
209
239
|
/**
|
|
210
240
|
* Moves the mix to mix time `time`, as it stood at the end of that frame, and plays on from
|
|
211
241
|
* there; where rate 0 held the clock at `time` for several frames, the last of them. Needs
|
|
@@ -214,11 +244,12 @@ export interface Mix<I, O, H = unknown> {
|
|
|
214
244
|
* Back, the mix restores itself: controls, records, voices and marks as they stood then. Voices
|
|
215
245
|
* that left after it are back on the handles the host holds, their `done` and `played` starting
|
|
216
246
|
* over where they had settled since. Voices cued after it wait as `pending` until the mix plays
|
|
217
|
-
* their cue again
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
247
|
+
* their cue again, and a write to the handle of one waiting changes nothing. Stateful voices
|
|
248
|
+
* restart from the copy `history` kept nearest before it and step once to it, exact under
|
|
249
|
+
* `stepMs`. A subject faded out of a voice or dropped after it comes back with the record it
|
|
250
|
+
* had, a motion patch's state included. Recorded input and host fields after it are let go:
|
|
251
|
+
* after a seek back, signals and host fields read live again, and `assess` reports what they
|
|
252
|
+
* fed as `held`.
|
|
222
253
|
*
|
|
223
254
|
* Forward, through a sync or a later seek, the mix plays the recorded calls again in the frames
|
|
224
255
|
* they were made in: cues, handle writes, fades, retargets and pushes, its rate, marks,
|
|
@@ -230,8 +261,15 @@ export interface Mix<I, O, H = unknown> {
|
|
|
230
261
|
* host's time since its last sync. Throws for a time older than history reaches, and before
|
|
231
262
|
* the first sync. With a history `store`, a time older than memory needs `prepare` first, or
|
|
232
263
|
* throws `HistoryMiss` before anything moves.
|
|
264
|
+
*
|
|
265
|
+
* Given `{ frame }`, a number `seq` read, it moves to the end of that frame instead, which is
|
|
266
|
+
* how a host reaches an earlier one of several frames rate 0 held at one mix time. The frame has
|
|
267
|
+
* to be one history still holds: not let go with age, and not after a moment an earlier seek went
|
|
268
|
+
* back to. With a store, one older than memory needs `prepare` of its mix time first.
|
|
233
269
|
*/
|
|
234
|
-
seek(
|
|
270
|
+
seek(to: number | {
|
|
271
|
+
readonly frame: number;
|
|
272
|
+
}): void;
|
|
235
273
|
/** As `Transport.prepare`, for a mix made alone. */
|
|
236
274
|
prepare(time: number): Promise<void>;
|
|
237
275
|
/**
|
|
@@ -241,6 +279,11 @@ export interface Mix<I, O, H = unknown> {
|
|
|
241
279
|
readonly now: number;
|
|
242
280
|
/** The host's timestamp at the last sync; NaN before the first. */
|
|
243
281
|
readonly timestamp: number;
|
|
282
|
+
/**
|
|
283
|
+
* The number of the frame being played, which `seek({ frame })` and `project({ frame })` take:
|
|
284
|
+
* each sync and seek begins a frame with a higher one, so two frames at one mix time differ.
|
|
285
|
+
*/
|
|
286
|
+
readonly seq: number;
|
|
244
287
|
/** The tape `history.tape` made, undefined without one. */
|
|
245
288
|
readonly tape: Tape | undefined;
|
|
246
289
|
/**
|
package/dist/types/patch.d.ts
CHANGED
|
@@ -129,7 +129,11 @@ export interface Patch<I, O, S = void, H = unknown> {
|
|
|
129
129
|
readonly form: 'fn' | 'keys' | 'motion';
|
|
130
130
|
/** Milliseconds one pass lasts, whether or not the voice loops. 0 has no passes: phase and pass stay 0. */
|
|
131
131
|
readonly duration: number;
|
|
132
|
-
/**
|
|
132
|
+
/**
|
|
133
|
+
* The channels this patch contributes to. Every key `at` sets, and no others: a mix drops any
|
|
134
|
+
* other key, and warns once per patch outside production when it finds one in the first delta a
|
|
135
|
+
* voice's `at` returns.
|
|
136
|
+
*/
|
|
133
137
|
readonly writes: readonly (keyof O)[];
|
|
134
138
|
/**
|
|
135
139
|
* The channels this patch was written against. `cue` refuses a mix whose channel of the same name
|
package/dist/types/place.d.ts
CHANGED
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
* @category score
|
|
9
9
|
*/
|
|
10
10
|
export type Mark = 'start' | 'in' | 'coast' | 'out' | 'end';
|
|
11
|
+
/**
|
|
12
|
+
* A mark by name: one of a voice's own five, or one it places inside itself with `marks`.
|
|
13
|
+
*
|
|
14
|
+
* @category score
|
|
15
|
+
*/
|
|
16
|
+
export type MarkName = Mark | (string & {});
|
|
11
17
|
/**
|
|
12
18
|
* Selects voices by what the plan knows of them, never by a channel's value, within the asking
|
|
13
19
|
* voice's own score unless it names another. Where several match,
|
|
@@ -26,7 +32,8 @@ export interface Query {
|
|
|
26
32
|
resolver?: 'last' | 'first' | 'next' | 'earliest' | 'latest';
|
|
27
33
|
}
|
|
28
34
|
/**
|
|
29
|
-
* A time given by another voice: `mark` of the voice `of` selects, moved by `by` ms
|
|
35
|
+
* A time given by another voice: `mark` of the voice `of` selects, moved by `by` ms, where `mark`
|
|
36
|
+
* is one of its five or one it places inside itself with `marks`. `after` is
|
|
30
37
|
* sugar for that voice's `end`, `with` for its `start`, and `before` for its start less `by`. A
|
|
31
38
|
* string selects by name. `all` is the latest of its anchors, known once every one is; `any` the
|
|
32
39
|
* earliest, known once one has passed or every one is known.
|
|
@@ -35,7 +42,7 @@ export interface Query {
|
|
|
35
42
|
*/
|
|
36
43
|
export type Anchor = {
|
|
37
44
|
of: string | Query;
|
|
38
|
-
mark:
|
|
45
|
+
mark: MarkName;
|
|
39
46
|
by?: number;
|
|
40
47
|
} | {
|
|
41
48
|
after: string | Query;
|
|
@@ -77,8 +84,8 @@ export interface Placement {
|
|
|
77
84
|
export interface Marked {
|
|
78
85
|
/** On the host's clock. */
|
|
79
86
|
timestamp: number;
|
|
80
|
-
/** Which of a voice's this is; undefined for an announced mark. */
|
|
81
|
-
mark:
|
|
87
|
+
/** Which of a voice's this is, one of its five or one it placed inside itself; undefined for an announced mark. */
|
|
88
|
+
mark: MarkName | undefined;
|
|
82
89
|
/** The voice it belongs to; undefined for an announced mark. */
|
|
83
90
|
voice: number | undefined;
|
|
84
91
|
score: string | undefined;
|
|
@@ -39,13 +39,17 @@ export interface Transport {
|
|
|
39
39
|
* tape plays every mix's calls again in the order they were made, so an anchor across mixes
|
|
40
40
|
* answers as it did. A mix dropped after the moment sought is back on the transport.
|
|
41
41
|
*/
|
|
42
|
-
seek(
|
|
42
|
+
seek(to: number | {
|
|
43
|
+
readonly frame: number;
|
|
44
|
+
}): void;
|
|
43
45
|
/**
|
|
44
46
|
* Loads from the history `store` what `seek(time)` and `project(time)` will need, where that
|
|
45
47
|
* reaches past memory. Without a store, or within memory, it loads nothing.
|
|
46
48
|
*/
|
|
47
49
|
prepare(time: number): Promise<void>;
|
|
48
50
|
readonly now: number;
|
|
51
|
+
/** As `Mix.seq`: the number of the frame being played, the same for every mix on it. */
|
|
52
|
+
readonly seq: number;
|
|
49
53
|
readonly tape: Tape | undefined;
|
|
50
54
|
/** Puts a named mark on a score every mix on it sees. Throws without a `score`. */
|
|
51
55
|
announce(name: string, opts: {
|
|
@@ -55,8 +59,13 @@ export interface Transport {
|
|
|
55
59
|
}): void;
|
|
56
60
|
/** Every mark of every mix on it, and every mark announced on it, earliest first. */
|
|
57
61
|
marks(from: number, to: number): Marked[];
|
|
58
|
-
/**
|
|
59
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Every mix on it read at mix time `at`, or at the frame `{ frame }` names, together, so anchors
|
|
64
|
+
* across them answer.
|
|
65
|
+
*/
|
|
66
|
+
project(at: number | {
|
|
67
|
+
readonly frame: number;
|
|
68
|
+
}): TransportProjection;
|
|
60
69
|
/** Any mix on it live. */
|
|
61
70
|
readonly live: boolean;
|
|
62
71
|
/** Every mix on it inert. */
|