@msb235/blits 0.7.0 → 0.8.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 +196 -0
- package/README.md +22 -4
- package/dist/book.js +4 -4
- package/dist/chain.d.ts +1 -1
- package/dist/chain.js +57 -54
- package/dist/channels.d.ts +26 -5
- package/dist/channels.js +12 -8
- package/dist/clock.d.ts +8 -1
- package/dist/clock.js +14 -3
- package/dist/clone.d.ts +3 -0
- package/dist/clone.js +16 -1
- package/dist/closed.d.ts +1 -1
- package/dist/closed.js +3 -2
- package/dist/color.d.ts +0 -11
- package/dist/color.js +4 -24
- package/dist/columns.js +0 -1
- package/dist/copyout.d.ts +6 -0
- package/dist/copyout.js +38 -0
- package/dist/crowd.d.ts +7 -5
- package/dist/crowd.js +32 -18
- package/dist/cue.d.ts +3 -1
- package/dist/cue.js +33 -20
- package/dist/departed.d.ts +34 -0
- package/dist/departed.js +73 -0
- package/dist/easing.d.ts +5 -0
- package/dist/easing.js +31 -2
- package/dist/everyone.d.ts +56 -0
- package/dist/everyone.js +221 -0
- package/dist/fade.d.ts +8 -1
- package/dist/fade.js +36 -6
- package/dist/fill.d.ts +22 -13
- package/dist/fill.js +104 -41
- package/dist/fit.js +2 -1
- package/dist/fold.d.ts +37 -0
- package/dist/fold.js +213 -28
- package/dist/gather.d.ts +15 -9
- package/dist/gather.js +60 -25
- package/dist/gone.d.ts +32 -0
- package/dist/gone.js +144 -0
- package/dist/handle.d.ts +16 -5
- package/dist/handle.js +56 -6
- package/dist/held.d.ts +8 -5
- package/dist/held.js +56 -58
- package/dist/history.d.ts +17 -13
- package/dist/history.js +49 -28
- package/dist/hosts.js +57 -9
- package/dist/index.d.ts +9 -4
- package/dist/index.js +5 -2
- package/dist/keyfill.d.ts +7 -0
- package/dist/keyfill.js +124 -0
- package/dist/keyrows.d.ts +1 -0
- package/dist/keyrows.js +1 -1
- package/dist/lane.d.ts +32 -2
- package/dist/lane.js +5 -0
- package/dist/lanes.d.ts +32 -8
- package/dist/lanes.js +69 -37
- package/dist/leavings.d.ts +26 -0
- package/dist/leavings.js +70 -0
- package/dist/meet.js +14 -8
- package/dist/mixer.d.ts +43 -7
- package/dist/mixer.js +60 -11
- package/dist/motion.d.ts +2 -0
- package/dist/motion.js +4 -1
- package/dist/motions.d.ts +22 -15
- package/dist/motions.js +40 -34
- package/dist/move.js +31 -20
- package/dist/moved.d.ts +11 -0
- package/dist/moved.js +29 -0
- package/dist/origin.d.ts +19 -0
- package/dist/origin.js +68 -0
- package/dist/owed.d.ts +4 -4
- package/dist/owed.js +8 -8
- package/dist/owner.d.ts +1 -1
- package/dist/owner.js +2 -2
- package/dist/pace.d.ts +13 -5
- package/dist/pace.js +21 -8
- package/dist/pack.d.ts +3 -1
- package/dist/pack.js +15 -24
- package/dist/paging.d.ts +8 -2
- package/dist/paging.js +44 -4
- package/dist/patch.d.ts +14 -9
- package/dist/patch.js +83 -21
- package/dist/place.js +188 -30
- package/dist/project.d.ts +12 -1
- package/dist/project.js +101 -83
- package/dist/pull.d.ts +2 -0
- package/dist/pull.js +8 -0
- package/dist/qualify.js +10 -2
- package/dist/reading.d.ts +5 -0
- package/dist/reading.js +5 -0
- package/dist/record.d.ts +9 -0
- package/dist/record.js +42 -0
- package/dist/relink.d.ts +11 -5
- package/dist/relink.js +7 -5
- package/dist/restored.d.ts +41 -0
- package/dist/restored.js +91 -0
- package/dist/revive.d.ts +10 -3
- package/dist/revive.js +31 -23
- package/dist/roster.d.ts +11 -0
- package/dist/roster.js +46 -0
- package/dist/rotation.d.ts +29 -0
- package/dist/rotation.js +91 -0
- package/dist/rows.d.ts +5 -5
- package/dist/rows.js +5 -5
- package/dist/sample.d.ts +3 -2
- package/dist/sample.js +32 -15
- package/dist/scored.d.ts +57 -0
- package/dist/scored.js +196 -0
- package/dist/seek.js +97 -114
- package/dist/shared.d.ts +6 -0
- package/dist/shared.js +15 -0
- package/dist/signals.d.ts +24 -3
- package/dist/signals.js +50 -11
- package/dist/spans.js +7 -0
- package/dist/stack.d.ts +11 -0
- package/dist/stack.js +47 -0
- package/dist/standing.d.ts +10 -0
- package/dist/standing.js +79 -0
- package/dist/store.d.ts +3 -3
- package/dist/store.js +3 -3
- package/dist/strays.js +3 -0
- package/dist/tape.d.ts +8 -5
- package/dist/tape.js +21 -13
- package/dist/testing.d.ts +35 -0
- package/dist/testing.js +116 -0
- package/dist/touch.d.ts +6 -0
- package/dist/touch.js +28 -0
- package/dist/transport.d.ts +53 -6
- package/dist/transport.js +102 -20
- package/dist/turns.d.ts +18 -0
- package/dist/turns.js +72 -0
- package/dist/tweened.js +1 -1
- package/dist/types/channel.d.ts +46 -0
- package/dist/types/channel.js +1 -0
- package/dist/types/history.d.ts +139 -0
- package/dist/types/history.js +1 -0
- package/dist/types/mix.d.ts +336 -0
- package/dist/types/mix.js +1 -0
- package/dist/types/patch.d.ts +187 -0
- package/dist/types/patch.js +1 -0
- package/dist/types/place.d.ts +157 -0
- package/dist/types/place.js +1 -0
- package/dist/types/transport.d.ts +71 -0
- package/dist/types/transport.js +1 -0
- package/dist/types/voice.d.ts +323 -0
- package/dist/types/voice.js +1 -0
- package/dist/types.d.ts +7 -1162
- package/dist/unpage.d.ts +2 -2
- package/dist/unpage.js +55 -25
- package/dist/voice.d.ts +92 -22
- package/dist/voice.js +108 -43
- package/dist/wave.d.ts +42 -0
- package/dist/wave.js +62 -0
- package/dist/weigh.js +1 -1
- package/docs/schema.html +42 -36
- package/package.json +8 -3
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import type { Kit } from './channel.js';
|
|
2
|
+
import type { HistoryOptions, Tape } from './history.js';
|
|
3
|
+
import type { Patch, Sent, Signal } from './patch.js';
|
|
4
|
+
import type { Booker, BookOptions, Marked } from './place.js';
|
|
5
|
+
import type { Transport } from './transport.js';
|
|
6
|
+
import type { Handle, OwnerSpec, SpanHandle, SpanSpec, VoiceSpec } from './voice.js';
|
|
7
|
+
/**
|
|
8
|
+
* How a mix is built: its engine, reduced motion, the host, and its limits.
|
|
9
|
+
*
|
|
10
|
+
* @category mix
|
|
11
|
+
*/
|
|
12
|
+
export interface MixOptions<H = unknown> {
|
|
13
|
+
engine?: Engine;
|
|
14
|
+
/** Reduced motion: fades and warm-ups snap, `dt` reads Infinity. */
|
|
15
|
+
reduce?: boolean | (() => boolean);
|
|
16
|
+
/** Merged into every `setting.host`. Its type is the mix's `H`, which every patch and signal it cues reads. */
|
|
17
|
+
host?: H;
|
|
18
|
+
/**
|
|
19
|
+
* The band a rest-less channel's contribution switches on and off across. It has to clear the frame
|
|
20
|
+
* noise in a real signal; these are placeholders until the klieg port measures one.
|
|
21
|
+
*/
|
|
22
|
+
band?: {
|
|
23
|
+
on: number;
|
|
24
|
+
off: number;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* The most `dt` a `step` or signal is handed, however long the gap. Off by default, since a
|
|
28
|
+
* patch with a closed form wants the whole gap; an integrator wants this set.
|
|
29
|
+
*/
|
|
30
|
+
maxDt?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Run every `step` at this fixed interval, ms, instead of once by the frame's gap, so stateful
|
|
33
|
+
* patches play the same at any frame rate. Intervals count from when a subject's delay ran out,
|
|
34
|
+
* the remainder carrying to the next sample; `maxDt` then caps how many one sample may run.
|
|
35
|
+
* Signals and `at` still see the frame. Off by default.
|
|
36
|
+
*/
|
|
37
|
+
stepMs?: number;
|
|
38
|
+
/**
|
|
39
|
+
* How far back `project` may read, in ms of mix time, and how often a stateful voice's state is
|
|
40
|
+
* kept per subject on the way, `every` ms (default 200). Within it the mix remembers what it cued,
|
|
41
|
+
* every change a handle made and when, the voices that have left, and those copies of state, so a
|
|
42
|
+
* read back restores the nearest copy and steps forward from it. Off by default, and a mix without
|
|
43
|
+
* it keeps nothing. With `inputs`, it also keeps what each input signal on a voice's weight read
|
|
44
|
+
* per subject, and the host fields patches `reads`, each time they changed, so a read back over a
|
|
45
|
+
* `level` or a pointer is known rather than held. With `tape`, the mix also records every call
|
|
46
|
+
* the host makes on it, its handles and its motion patches, so `seek` can move it and play those
|
|
47
|
+
* calls again.
|
|
48
|
+
*/
|
|
49
|
+
history?: HistoryOptions;
|
|
50
|
+
/**
|
|
51
|
+
* A subject's key, for a history `store`: unique among this mix's subjects for the session. A
|
|
52
|
+
* string or number subject is its own key; with a store, an object subject needs this.
|
|
53
|
+
*/
|
|
54
|
+
keyOf?(subject: never): string | number;
|
|
55
|
+
/**
|
|
56
|
+
* Whether a channel may run as a lane: computed for every subject at once in flat arrays, when
|
|
57
|
+
* every voice writing it can run that way. On by default; what a host reads is the same either
|
|
58
|
+
* way (`probe`, `pull`, `atRest`, `weightOf`, `inert` and `project`), so turning it off is for
|
|
59
|
+
* ruling a lane out, or for comparing against. A voice weighted by an input signal `input` did not
|
|
60
|
+
* make, or whose patch reads host fields, never runs on a lane, since a change to either
|
|
61
|
+
* between two probes would not reach it. Two things differ: a
|
|
62
|
+
* stateless patch's `setting.send` from `at` sends for every subject a lane fills, those probed
|
|
63
|
+
* this frame or the last, and a patch that first calls `setting.keep` partway through playing can
|
|
64
|
+
* advance that state once more for one subject probed the frame before (see `Setting.keep`).
|
|
65
|
+
*/
|
|
66
|
+
lanes?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* The transport this mix plays on, shared with other mixes, so they keep one clock and a query
|
|
69
|
+
* naming a score looks in all of them. The transport's `sync`, `rebase`, `rate`, `ramp` and
|
|
70
|
+
* `seek` move it, and the mix's own throw. Its history is the transport's, so the mix takes no
|
|
71
|
+
* `history` of its own.
|
|
72
|
+
*/
|
|
73
|
+
transport?: Transport;
|
|
74
|
+
/** What `Marked.mix` and errors call this mix. */
|
|
75
|
+
name?: string;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* How sure a projection is of one channel: `exact` where only the clock and known changes drove
|
|
79
|
+
* 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
|
|
81
|
+
* is not known, so the value it had is held.
|
|
82
|
+
*
|
|
83
|
+
* @category mix
|
|
84
|
+
*/
|
|
85
|
+
export type Doubt = 'exact' | 'stepped' | 'held';
|
|
86
|
+
/**
|
|
87
|
+
* The mix read at another time: what `probe` would give at that timestamp, with nothing in the
|
|
88
|
+
* live mix moved. Valid until the mix is next synced or cued.
|
|
89
|
+
*
|
|
90
|
+
* @category mix
|
|
91
|
+
*/
|
|
92
|
+
export interface Projection<I, O> {
|
|
93
|
+
/** The mix time it reads at. */
|
|
94
|
+
readonly timestamp: number;
|
|
95
|
+
/** The merged pose for one subject at this projection's timestamp. */
|
|
96
|
+
probe(subject: I, out?: O): O;
|
|
97
|
+
/** Per channel, how sure that pose is; the least sure voice that fed a channel decides. */
|
|
98
|
+
assess(subject: I): {
|
|
99
|
+
[K in keyof O]-?: Doubt;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Arrays for `pull` to write, one per channel it reads: any channel whose value is a number or an
|
|
104
|
+
* array of numbers.
|
|
105
|
+
*
|
|
106
|
+
* @category mix
|
|
107
|
+
*/
|
|
108
|
+
export type Columns<O> = {
|
|
109
|
+
[K in keyof O as NonNullable<O[K]> extends number | readonly number[] ? K : never]?: Float64Array;
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* The live voices over one kit, folded into one pose per subject per frame.
|
|
113
|
+
*
|
|
114
|
+
* @category mix
|
|
115
|
+
*/
|
|
116
|
+
export interface Mix<I, O, H = unknown> {
|
|
117
|
+
/** Cues a voice. Throws when the engine cannot run the patch's form, or the kit lacks a channel. */
|
|
118
|
+
cue(spec: VoiceSpec<I, O, H>): Handle<I>;
|
|
119
|
+
/**
|
|
120
|
+
* N voices whose weights split one signal, cued into one locus so they fold as alternatives. The
|
|
121
|
+
* 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; a signal keeping state keeps it once, not per member.
|
|
123
|
+
*/
|
|
124
|
+
blend(patches: readonly Patch<I, O, unknown, H>[], by: Signal<I, H>, spec?: Omit<VoiceSpec<I, O, H>, 'patch' | 'weight' | 'locus'>): Handle<I>[];
|
|
125
|
+
/**
|
|
126
|
+
* Cues an owner: a voice with no patch that holds the voices cued with `owner` set to its handle,
|
|
127
|
+
* and plays them on its own clock, so they can be placed, timed and faded as one. Its handle acts
|
|
128
|
+
* on all of them: `rate` and `ramp` multiply into theirs, `seek` moves their clocks with its own
|
|
129
|
+
* and rebuilds their state as it does a voice's, and `weight` and `fade()` multiply into their weights, by
|
|
130
|
+
* what its `weightOf` reports; it fades as a whole, not by subject or at rest. It is
|
|
131
|
+
* `played` once every voice it held has finished its passes, and leaves, `done`, with its last; a
|
|
132
|
+
* fade that ends takes the rest with it. One that never holds a voice stays until faded. Owners
|
|
133
|
+
* nest. Throws for a `loop`: a pass would have to restart its children.
|
|
134
|
+
*/
|
|
135
|
+
owns(spec: OwnerSpec<I, H>): Handle<I>;
|
|
136
|
+
/**
|
|
137
|
+
* Cues a span: an owner that lays out the voices it holds in `order` and fits them into its
|
|
138
|
+
* `duration`, again each time one joins or leaves early. A child's start and rate are the
|
|
139
|
+
* span's to set, so it takes neither `start` nor an anchored start; its `SpanHints` say how it
|
|
140
|
+
* may give way. A span with a budget stays until the budget has passed, though its children
|
|
141
|
+
* 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.
|
|
143
|
+
*/
|
|
144
|
+
span(spec: SpanSpec<I, H>): SpanHandle<I>;
|
|
145
|
+
/**
|
|
146
|
+
* The host reports the clock, once a frame. Nothing advances at the call. Throws for a timestamp
|
|
147
|
+
* earlier than the last sync's, short of a `rebase`: the host's clock only goes forward, and
|
|
148
|
+
* `seek` moves the mix.
|
|
149
|
+
*/
|
|
150
|
+
sync(timestamp: number): void;
|
|
151
|
+
/**
|
|
152
|
+
* The time between the last sync and the next one is not to count: a host calls it when a
|
|
153
|
+
* hidden tab comes back. Every voice, fade and subject resumes where it was left.
|
|
154
|
+
*/
|
|
155
|
+
rebase(): void;
|
|
156
|
+
/**
|
|
157
|
+
* The mix's own playback rate, multiplied into every voice's: 1 is real time and 0 pauses the
|
|
158
|
+
* whole mix. A negative rate throws: the mix plays only forward, and `seek` moves it back. Setting it changes speed at
|
|
159
|
+
* once; `ramp` eases into a new one. It scales mix time, which everything a voice owns runs on:
|
|
160
|
+
* its clock, its fades and a handle's ramp, `stagger`, an anchor's `by`, `stepMs`, `maxDt`,
|
|
161
|
+
* `history.ms`, every `dt`, and `setting.timestamp`. Timestamps on the host's clock name the same
|
|
162
|
+
* moment whatever the rate does: a `start`, an anchor given as a number, an announced mark, what
|
|
163
|
+
* `marks` reports and the time `project` reads, so a start ahead of a paused mix waits for the
|
|
164
|
+
* host's clock to reach it. A weight signal is still asked at every probe, so one reading host
|
|
165
|
+
* input follows it while the mix is paused.
|
|
166
|
+
*/
|
|
167
|
+
rate: number;
|
|
168
|
+
/**
|
|
169
|
+
* Moves the mix's rate to `rate` linearly over `over` ms of the host's clock, as `Handle.ramp`
|
|
170
|
+
* moves a voice's. Mix time integrates the ramp and a voice's clock integrates mix time, so a ramp
|
|
171
|
+
* on both multiplies and every position stays continuous. A later `rate` write or `ramp` replaces
|
|
172
|
+
* it.
|
|
173
|
+
*/
|
|
174
|
+
ramp(rate: number, over: number): void;
|
|
175
|
+
/**
|
|
176
|
+
* The merged pose for one subject at the synced frame, written into `out` when given. Without
|
|
177
|
+
* it, each call makes a new object, so a host reading every subject every frame passes `out` or
|
|
178
|
+
* reads by `pull`. An array `out` already holds for a `vec` channel, a `quat` that
|
|
179
|
+
* runs on a lane, or a `color` that averages in OKLab or runs on a lane, is written in place where it is the channel's length, so a host that
|
|
180
|
+
* kept one from an earlier probe into the same `out` sees it change: copy what has to outlast the
|
|
181
|
+
* next probe.
|
|
182
|
+
*/
|
|
183
|
+
probe(subject: I, out?: O): O;
|
|
184
|
+
/**
|
|
185
|
+
* Writes each subject's pose into arrays, one per channel, subject by subject in the order given:
|
|
186
|
+
* what `probe(subject, out)` gives, without a pose object per subject. A channel of `n` numbers
|
|
187
|
+
* takes `n` places per subject, side by side; one with no value for a subject writes NaN there.
|
|
188
|
+
* Fastest while every voice runs on a lane, and when `subjects` is an array read again in the
|
|
189
|
+
* same order: the mix remembers the last array's subjects by position, holding them until the
|
|
190
|
+
* next `pull`, and skips looking up any still in its place. Throws when an array is too short for
|
|
191
|
+
* the subjects.
|
|
192
|
+
*/
|
|
193
|
+
pull(subjects: Iterable<I>, into: Columns<O>): void;
|
|
194
|
+
/**
|
|
195
|
+
* Reads the mix at another mix time, without moving it. Ahead of the mix it plays what is cued
|
|
196
|
+
* forward, and throws for a time past a call the tape will play again after a `seek` back, which
|
|
197
|
+
* only a seek there makes; behind it, with `history`, it reads the last frame at or before `time`
|
|
198
|
+
* as that frame showed, and throws for a time older than the history reaches. On a transport it
|
|
199
|
+
* reads every mix on it together, so anchors across them answer.
|
|
200
|
+
*
|
|
201
|
+
* Without `history` it reads back only where how the mix stands now says what it showed then,
|
|
202
|
+
* and throws otherwise, saying why. Every voice has to play as it was cued and read by its clock
|
|
203
|
+
* alone: no state, motion, `from: 'current'`, anchor or owner, no write to its handle, and no channel without a rest
|
|
204
|
+
* at a weight that moves. The mix's rate has never been set. And `time` is no earlier than the
|
|
205
|
+
* last cue, `drop`, `touch`, `announce` or `rebase`, or the last frame a voice left in.
|
|
206
|
+
*/
|
|
207
|
+
project(time: number): Projection<I, O>;
|
|
208
|
+
/**
|
|
209
|
+
* Moves the mix to mix time `time`, as it stood at the end of that frame, and plays on from
|
|
210
|
+
* there; where rate 0 held the clock at `time` for several frames, the last of them. Needs
|
|
211
|
+
* `history` with a `tape`, which records the host's calls by the host time they were made at.
|
|
212
|
+
*
|
|
213
|
+
* Back, the mix restores itself: controls, records, voices and marks as they stood then. Voices
|
|
214
|
+
* that left after it are back on the handles the host holds, their `done` and `played` starting
|
|
215
|
+
* over where they had settled since. Voices cued after it wait as `pending` until the mix plays
|
|
216
|
+
* their cue again. Stateful voices restart from the copy `history` kept nearest before it and
|
|
217
|
+
* step once to it, exact under `stepMs`. A subject faded out of a voice or dropped after it comes
|
|
218
|
+
* back with the record it had, a motion patch's state included. Recorded input and host fields
|
|
219
|
+
* after it are let go: after a seek back, signals and host fields read live again, and `assess`
|
|
220
|
+
* reports what they fed as `held`.
|
|
221
|
+
*
|
|
222
|
+
* Forward, through a sync or a later seek, the mix plays the recorded calls again in the frames
|
|
223
|
+
* they were made in: cues, handle writes, fades, retargets and pushes, its rate, marks,
|
|
224
|
+
* `mute` and `drop`. A call the host makes while there are recorded calls ahead starts a new
|
|
225
|
+
* branch, and the tape keeps the old future beside it; `tape.switchBranch` picks one back.
|
|
226
|
+
* Playing past a time again sends its events and books its marks and hits again.
|
|
227
|
+
*
|
|
228
|
+
* The host goes on passing its own clock: the next `sync` reads the moment sought plus the
|
|
229
|
+
* host's time since its last sync. Throws for a time older than history reaches, and before
|
|
230
|
+
* the first sync. With a history `store`, a time older than memory needs `prepare` first, or
|
|
231
|
+
* throws `HistoryMiss` before anything moves.
|
|
232
|
+
*/
|
|
233
|
+
seek(time: number): void;
|
|
234
|
+
/** As `Transport.prepare`, for a mix made alone. */
|
|
235
|
+
prepare(time: number): Promise<void>;
|
|
236
|
+
/**
|
|
237
|
+
* The mix clock at the last sync or seek, which `seek` and `project` take; NaN before the first
|
|
238
|
+
* sync. Host time at the mix's rate, less what `rebase` took out and `seek` moved.
|
|
239
|
+
*/
|
|
240
|
+
readonly now: number;
|
|
241
|
+
/** The tape `history.tape` made, undefined without one. */
|
|
242
|
+
readonly tape: Tape | undefined;
|
|
243
|
+
/**
|
|
244
|
+
* Every channel at rest for this subject this frame, so a host can skip the write. After a probe
|
|
245
|
+
* of the subject this frame, it answers for the pose that probe gave, without folding again.
|
|
246
|
+
*/
|
|
247
|
+
atRest(subject: I): boolean;
|
|
248
|
+
/**
|
|
249
|
+
* A handle on every voice still in the mix, pending, live, frozen or fading, in the order they were
|
|
250
|
+
* cued; given a tag, only the voices whose `tags` carry it. Each is the handle `cue` returned for
|
|
251
|
+
* that voice, so a listed handle is `===` the cued one.
|
|
252
|
+
*/
|
|
253
|
+
voices(tag?: string): Handle<I>[];
|
|
254
|
+
/** Anything still contributing, fading, or pending. */
|
|
255
|
+
readonly live: boolean;
|
|
256
|
+
/**
|
|
257
|
+
* Another frame would change no pose, so a host's frame loop may sleep: every voice is done, frozen
|
|
258
|
+
* at a plain weight, or a motion whose every subject has landed on its target. At rate 0 it is
|
|
259
|
+
* enough that every voice not done has started, at a plain weight, with no anchor. A change made
|
|
260
|
+
* since the last sync, a retarget or a rate included, makes it false until the next.
|
|
261
|
+
*/
|
|
262
|
+
readonly inert: boolean;
|
|
263
|
+
/**
|
|
264
|
+
* Calls `fn` when a host call makes the mix need frames again after a sync: a cue, a fade, a
|
|
265
|
+
* handle's or the mix's rate, a seek, a `drop`, a motion retargeted. It fires once until the next
|
|
266
|
+
* sync clears the change, and never during `sync`. Returns a function that unsubscribes `fn`.
|
|
267
|
+
* A frame loop sleeping on `inert` subscribes here to wake.
|
|
268
|
+
*/
|
|
269
|
+
onWake(fn: () => void): () => void;
|
|
270
|
+
/** Fades every voice out: over `over` when given, over each voice's own `fade.out` otherwise. */
|
|
271
|
+
mute(opts?: {
|
|
272
|
+
over?: number;
|
|
273
|
+
}): void;
|
|
274
|
+
/**
|
|
275
|
+
* Forgets per-subject state, a motion patch's for the subject included, and any fade of the
|
|
276
|
+
* subject out of a voice, so nothing keeps the subject alive.
|
|
277
|
+
*/
|
|
278
|
+
drop(subject: I): void;
|
|
279
|
+
/**
|
|
280
|
+
* Says that something a patch reads from outside the mix has changed since the last sync, such as
|
|
281
|
+
* a table its `at` looks a subject up in, so the next probe calls the patch again where it would
|
|
282
|
+
* have answered with what it read this frame. Given a subject, for that subject only; with none,
|
|
283
|
+
* for every subject. The clock stays where it is and no `step` runs again, and it wakes a frame
|
|
284
|
+
* loop sleeping on `inert`, as any change does.
|
|
285
|
+
*/
|
|
286
|
+
touch(subject?: I): void;
|
|
287
|
+
/**
|
|
288
|
+
* Puts a named mark on a score, for anchors to target as they target a voice's marks: a voice
|
|
289
|
+
* placed `{ with: 'reply' }` waits until the host announces `reply`. `at` is a timestamp on the
|
|
290
|
+
* host's clock, default now, and may lie ahead, so a read ahead sees it. A mark stays while it is
|
|
291
|
+
* ahead or while the mix's history reaches it.
|
|
292
|
+
*/
|
|
293
|
+
announce(name: string, opts?: {
|
|
294
|
+
at?: number;
|
|
295
|
+
score?: string;
|
|
296
|
+
tags?: readonly string[];
|
|
297
|
+
}): void;
|
|
298
|
+
/**
|
|
299
|
+
* Every mark the plan knows between two timestamps on the host's clock, earliest first: when
|
|
300
|
+
* voices start, are fully in, end their last pass, begin to fade and are gone, and what the host
|
|
301
|
+
* announced. A mark
|
|
302
|
+
* nothing has fixed yet, such as the out of a voice that loops for good, is not listed.
|
|
303
|
+
*/
|
|
304
|
+
marks(from: number, to: number): Marked[];
|
|
305
|
+
/**
|
|
306
|
+
* Every event patches have sent since the last drain, earliest first, in the order they were sent
|
|
307
|
+
* where two share a timestamp. A subject's events are made while it catches up, which is when it is
|
|
308
|
+
* probed, so one nobody probes has sent nothing yet: promptness is the host's, by probing. A
|
|
309
|
+
* stateless patch's `at` on a lane is the exception: it runs at the frame's first probe for every
|
|
310
|
+
* subject probed that frame or the last. Under `stepMs` each carries the end of the interval it happened in, so
|
|
311
|
+
* what is sent and when does not depend on how the host spaces its probes. Time `rebase` took out
|
|
312
|
+
* sends nothing. Given a tag, it takes only the events of voices carrying it and leaves the rest for
|
|
313
|
+
* whoever drains them.
|
|
314
|
+
*/
|
|
315
|
+
drain<E = unknown>(tag?: string): Sent<I, E>[];
|
|
316
|
+
/**
|
|
317
|
+
* Hands the host each mark and hit before it comes, against a clock of its own, so it can schedule
|
|
318
|
+
* the thing itself: a sound on an `AudioContext`, a MIDI message with a timestamp, a video loaded
|
|
319
|
+
* before the voice that shows it starts. Booking runs at each `sync`, `ahead` ms out, and a
|
|
320
|
+
* booking whose time moves is stopped and taken again. Nothing is booked twice: a mark is known by
|
|
321
|
+
* its voice and which mark, a hit by its voice, index and pass. `project` books nothing, and
|
|
322
|
+
* nothing about booking is replayed under `history`. A mix with no booker pays nothing for it.
|
|
323
|
+
*/
|
|
324
|
+
book<E = unknown>(opts: BookOptions<E>): Booker;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* The implementation behind a mix: which patch forms it runs, and how it makes one.
|
|
328
|
+
*
|
|
329
|
+
* @category engine
|
|
330
|
+
*/
|
|
331
|
+
export interface Engine {
|
|
332
|
+
readonly name: string;
|
|
333
|
+
/** Which patch forms this engine can run. A voice it cannot run is refused at `cue`, by name. */
|
|
334
|
+
readonly runs: ReadonlySet<'fn' | 'keys' | 'motion'>;
|
|
335
|
+
create<I, O, H = unknown>(kit: Kit<O>, opts: MixOptions<H>): Mix<I, O, H>;
|
|
336
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import type { WaveOptions } from '../wave.js';
|
|
2
|
+
import type { Kit } from './channel.js';
|
|
3
|
+
/**
|
|
4
|
+
* A curve on 0..1, as data where it can be: CSS's names, a `cubic-bezier`, or `steps`, which a
|
|
5
|
+
* WAAPI or GPU engine can read. The function form runs on the CPU engine only.
|
|
6
|
+
*
|
|
7
|
+
* @category patch
|
|
8
|
+
*/
|
|
9
|
+
export type Easing = ((u: number) => number) | 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | {
|
|
10
|
+
readonly bezier: readonly [x1: number, y1: number, x2: number, y2: number];
|
|
11
|
+
} | {
|
|
12
|
+
readonly steps: number;
|
|
13
|
+
readonly jump?: 'start' | 'end';
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* One stop of a `keys` patch.
|
|
17
|
+
*
|
|
18
|
+
* @category patch
|
|
19
|
+
*/
|
|
20
|
+
export interface Keyframe<O> {
|
|
21
|
+
/** Phase, 0..1. */
|
|
22
|
+
at: number;
|
|
23
|
+
delta: Partial<O>;
|
|
24
|
+
ease?: Easing;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* What a patch may read and did not compute, for one subject this frame. The mix reuses the object,
|
|
28
|
+
* so it is valid only during the call it is handed to.
|
|
29
|
+
*
|
|
30
|
+
* @category state
|
|
31
|
+
*/
|
|
32
|
+
export interface Setting<S = void, H = unknown> {
|
|
33
|
+
/**
|
|
34
|
+
* The mix clock at this frame: the host's timestamp less any time `rebase` took out, run at the
|
|
35
|
+
* mix's `rate`. Identical for every probe in the frame.
|
|
36
|
+
*/
|
|
37
|
+
timestamp: number;
|
|
38
|
+
/**
|
|
39
|
+
* The gap this subject is catching up by: milliseconds since it last advanced, which is the gap
|
|
40
|
+
* since the previous sync only for a subject sampled every frame. Infinity under reduced motion;
|
|
41
|
+
* no more than `maxDt` where the mix sets one. Inside a `step` under `stepMs`, it is `stepMs`, and
|
|
42
|
+
* `timestamp` is the end of that interval.
|
|
43
|
+
*/
|
|
44
|
+
dt: number;
|
|
45
|
+
/** Milliseconds this voice has been playing, rate applied. */
|
|
46
|
+
elapsed: number;
|
|
47
|
+
/** Which pass this is, 0 first. */
|
|
48
|
+
pass: number;
|
|
49
|
+
/** This voice's weight for this subject this frame, after fades, signals and any locus. */
|
|
50
|
+
weight: number;
|
|
51
|
+
/** This subject's state, when the patch declares one. */
|
|
52
|
+
state: S;
|
|
53
|
+
/** Anything the host adds for its own patches: the mix's `host`, typed as its `H`. */
|
|
54
|
+
host: H;
|
|
55
|
+
/**
|
|
56
|
+
* The state `owner` keeps for this voice and this subject, made by `init` on first ask. The mix
|
|
57
|
+
* holds it, so a read at another time can copy it instead of moving it. A stateful signal keeps
|
|
58
|
+
* its state here and nowhere else. With lanes on, a patch or weight signal that first calls it
|
|
59
|
+
* partway through playing can have that state advanced once for one subject probed the frame
|
|
60
|
+
* before it starts and not on that frame; one that keeps state from its first call, or a patch
|
|
61
|
+
* that declares `state`, never does.
|
|
62
|
+
*/
|
|
63
|
+
keep<K>(owner: object, init: () => K): K;
|
|
64
|
+
/**
|
|
65
|
+
* Reports an event at `timestamp`, for this voice and this subject. The mix queues it until the
|
|
66
|
+
* host drains it, and never calls back. Meant for `step`, where under `stepMs` the timestamp is
|
|
67
|
+
* the interval the event happened in rather than the frame that sampled it. Sent from a stateless
|
|
68
|
+
* patch's `at` while it runs on a lane, it goes out for every subject the lane fills, probed that
|
|
69
|
+
* frame or not: each probed that frame or the last; `at` is not asked for a subject at weight 0,
|
|
70
|
+
* so nothing is sent from it there.
|
|
71
|
+
*/
|
|
72
|
+
send(event: unknown): void;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* One event a patch sent, as `drain` hands it back.
|
|
76
|
+
*
|
|
77
|
+
* @category state
|
|
78
|
+
*/
|
|
79
|
+
export interface Sent<I, E = unknown> {
|
|
80
|
+
/** The mix clock when it was sent. */
|
|
81
|
+
timestamp: number;
|
|
82
|
+
subject: I;
|
|
83
|
+
/** The id of the voice whose patch sent it, as its handle reports. */
|
|
84
|
+
voice: number;
|
|
85
|
+
/** That voice's tags. */
|
|
86
|
+
tags: readonly string[];
|
|
87
|
+
event: E;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* What a `'motion'` patch is made of, as data an engine can read: the kind of motion and its
|
|
91
|
+
* constants. Each subject's start, target and starting velocity stay on the patch, since they may
|
|
92
|
+
* be functions of the subject.
|
|
93
|
+
*
|
|
94
|
+
* @category patch
|
|
95
|
+
*/
|
|
96
|
+
export type MotionSpec = {
|
|
97
|
+
readonly kind: 'spring';
|
|
98
|
+
/** Per second squared. */
|
|
99
|
+
readonly stiffness: number;
|
|
100
|
+
/** Per second. */
|
|
101
|
+
readonly damping: number;
|
|
102
|
+
readonly mass: number;
|
|
103
|
+
readonly settle: number;
|
|
104
|
+
} | {
|
|
105
|
+
readonly kind: 'glide';
|
|
106
|
+
/** The friction's time constant, ms. */
|
|
107
|
+
readonly ms: number;
|
|
108
|
+
readonly settle: number;
|
|
109
|
+
} | {
|
|
110
|
+
readonly kind: 'tween';
|
|
111
|
+
/** How long a stretch takes; undefined where it varies by subject, kept on the patch then. */
|
|
112
|
+
readonly ms: number | undefined;
|
|
113
|
+
readonly ease: Easing;
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* A pure function of phase and a subject that returns a delta. Optionally stateful.
|
|
117
|
+
*
|
|
118
|
+
* @category patch
|
|
119
|
+
*/
|
|
120
|
+
export interface Patch<I, O, S = void, H = unknown> {
|
|
121
|
+
/**
|
|
122
|
+
* Which authoring form built it: `'fn'` from `patch`, `'keys'` from `keys`, `'motion'` from
|
|
123
|
+
* `spring`, `glide` or `tween`. An engine declares which forms it runs.
|
|
124
|
+
*/
|
|
125
|
+
readonly form: 'fn' | 'keys' | 'motion';
|
|
126
|
+
/** Milliseconds one pass lasts, whether or not the voice loops. 0 has no passes: phase and pass stay 0. */
|
|
127
|
+
readonly duration: number;
|
|
128
|
+
/** The channels this patch contributes to. Every key `at` sets, and no others. */
|
|
129
|
+
readonly writes: readonly (keyof O)[];
|
|
130
|
+
/**
|
|
131
|
+
* The channels this patch was written against. `cue` refuses a mix whose channel of the same name
|
|
132
|
+
* is of another kind, so a patch published in one package cannot fold by another's arithmetic.
|
|
133
|
+
*/
|
|
134
|
+
readonly kit?: Partial<Kit<O>>;
|
|
135
|
+
/** The fields of `setting.host` this patch reads. `cue` refuses a mix whose host lacks one. */
|
|
136
|
+
readonly reads?: readonly string[];
|
|
137
|
+
/**
|
|
138
|
+
* `phase` is 0..1 across one pass, wrapping. Not asked for a subject its voice gives no weight, unless the voice is fading to rest;
|
|
139
|
+
* `step` still runs. A `keys` patch's stops are not read there either, unless its voice is in a locus.
|
|
140
|
+
*/
|
|
141
|
+
at(phase: number, subject: I, setting: Setting<S, H>): Partial<O>;
|
|
142
|
+
/** Per-subject state, created on the first frame this patch sees a subject. */
|
|
143
|
+
state?(subject: I): S;
|
|
144
|
+
/**
|
|
145
|
+
* Advances state once per subject per sampled frame, by the whole gap since it last advanced; or,
|
|
146
|
+
* where the mix sets `stepMs`, once per whole interval of that length.
|
|
147
|
+
*/
|
|
148
|
+
step?(state: S, dt: number, subject: I, setting: Setting<S, H>): void;
|
|
149
|
+
/** Present when the patch was authored as keyframes, so an engine that reads data can. */
|
|
150
|
+
readonly keys?: readonly Keyframe<O>[];
|
|
151
|
+
/**
|
|
152
|
+
* Present on a `keys` patch that was given them: what `keys` took besides its stops, each as
|
|
153
|
+
* `KeysOptions` describes it. They are read off the patch, so a copy that changes one, as
|
|
154
|
+
* `{ ...p, ease: 'linear' }` does, plays by its own.
|
|
155
|
+
*/
|
|
156
|
+
readonly ease?: Easing;
|
|
157
|
+
easeBy?(channel: keyof O): Easing | undefined;
|
|
158
|
+
delayBy?(channel: keyof O): number;
|
|
159
|
+
lerpBy?(channel: keyof O): ((a: never, b: never, u: number) => unknown) | undefined;
|
|
160
|
+
/** Present on a `wave` patch: what `wave` took, which a copy may change as it may a `keys` field. */
|
|
161
|
+
readonly wave?: WaveOptions<O>;
|
|
162
|
+
/** Present on a `'motion'` patch: its kind and constants, for an engine that reads data. */
|
|
163
|
+
readonly motion?: MotionSpec;
|
|
164
|
+
/**
|
|
165
|
+
* A copy of `state` that shares nothing with it, for a read at another time. Default
|
|
166
|
+
* `structuredClone`, which is enough for plain data; a state holding a class instance or a
|
|
167
|
+
* function needs its own.
|
|
168
|
+
*/
|
|
169
|
+
clone?(state: S): S;
|
|
170
|
+
/**
|
|
171
|
+
* `state` as data that survives `structuredClone`, for a history `store` to keep; `unpack` makes
|
|
172
|
+
* a state from it again. With a store, a patch with `state` or `step` needs both, or `cue`
|
|
173
|
+
* refuses it.
|
|
174
|
+
*/
|
|
175
|
+
pack?(state: S): unknown;
|
|
176
|
+
unpack?(data: unknown): S;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* A 0..1 scalar resolved per subject per frame from something outside the clock. `input` is set
|
|
180
|
+
* when it reads something the clock does not drive, such as a value the host writes; a signal
|
|
181
|
+
* built on one inherits it.
|
|
182
|
+
*
|
|
183
|
+
* @category signal
|
|
184
|
+
*/
|
|
185
|
+
export type Signal<I, H = unknown> = ((subject: I, setting: Setting<void, H>) => number) & {
|
|
186
|
+
readonly input?: boolean;
|
|
187
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|