@hyperframes/core 0.7.107 → 0.7.108

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.
Files changed (89) hide show
  1. package/dist/audio/audioFxAutomation.d.ts +63 -0
  2. package/dist/audio/audioFxAutomation.d.ts.map +1 -0
  3. package/dist/audio/audioFxAutomation.js +219 -0
  4. package/dist/audio/audioFxAutomation.js.map +1 -0
  5. package/dist/audio/audioFxGraph.d.ts +73 -0
  6. package/dist/audio/audioFxGraph.d.ts.map +1 -0
  7. package/dist/audio/audioFxGraph.js +649 -0
  8. package/dist/audio/audioFxGraph.js.map +1 -0
  9. package/dist/audio/audioFxTail.d.ts +28 -0
  10. package/dist/audio/audioFxTail.d.ts.map +1 -0
  11. package/dist/audio/audioFxTail.js +95 -0
  12. package/dist/audio/audioFxTail.js.map +1 -0
  13. package/dist/audio/audioFxWorklets.d.ts +8 -0
  14. package/dist/audio/audioFxWorklets.d.ts.map +1 -0
  15. package/dist/audio/audioFxWorklets.js +263 -0
  16. package/dist/audio/audioFxWorklets.js.map +1 -0
  17. package/dist/audioAutomation.d.ts +191 -0
  18. package/dist/audioAutomation.d.ts.map +1 -0
  19. package/dist/audioAutomation.js +488 -0
  20. package/dist/audioAutomation.js.map +1 -0
  21. package/dist/audioCarve.d.ts +216 -0
  22. package/dist/audioCarve.d.ts.map +1 -0
  23. package/dist/audioCarve.js +608 -0
  24. package/dist/audioCarve.js.map +1 -0
  25. package/dist/audioFx.d.ts +182 -0
  26. package/dist/audioFx.d.ts.map +1 -0
  27. package/dist/audioFx.js +813 -0
  28. package/dist/audioFx.js.map +1 -0
  29. package/dist/audioFxCopy.d.ts +89 -0
  30. package/dist/audioFxCopy.d.ts.map +1 -0
  31. package/dist/audioFxCopy.js +340 -0
  32. package/dist/audioFxCopy.js.map +1 -0
  33. package/dist/audioFxEq.d.ts +75 -0
  34. package/dist/audioFxEq.d.ts.map +1 -0
  35. package/dist/audioFxEq.js +153 -0
  36. package/dist/audioFxEq.js.map +1 -0
  37. package/dist/audioFxJobs.d.ts +52 -0
  38. package/dist/audioFxJobs.d.ts.map +1 -0
  39. package/dist/audioFxJobs.js +92 -0
  40. package/dist/audioFxJobs.js.map +1 -0
  41. package/dist/audioFxPresets.d.ts +91 -0
  42. package/dist/audioFxPresets.d.ts.map +1 -0
  43. package/dist/audioFxPresets.js +320 -0
  44. package/dist/audioFxPresets.js.map +1 -0
  45. package/dist/audioFxProfiles.d.ts +65 -0
  46. package/dist/audioFxProfiles.d.ts.map +1 -0
  47. package/dist/audioFxProfiles.js +209 -0
  48. package/dist/audioFxProfiles.js.map +1 -0
  49. package/dist/audioLeveller.d.ts +62 -0
  50. package/dist/audioLeveller.d.ts.map +1 -0
  51. package/dist/audioLeveller.js +208 -0
  52. package/dist/audioLeveller.js.map +1 -0
  53. package/dist/canaryRegistry.d.ts.map +1 -1
  54. package/dist/canaryRegistry.js +8 -0
  55. package/dist/canaryRegistry.js.map +1 -1
  56. package/dist/compiler/compositionScoping.d.ts +3 -0
  57. package/dist/compiler/compositionScoping.d.ts.map +1 -1
  58. package/dist/compiler/compositionScoping.js +34 -11
  59. package/dist/compiler/compositionScoping.js.map +1 -1
  60. package/dist/compiler/htmlBundler.d.ts.map +1 -1
  61. package/dist/compiler/htmlBundler.js +42 -2
  62. package/dist/compiler/htmlBundler.js.map +1 -1
  63. package/dist/editing/affordances.d.ts +3 -0
  64. package/dist/editing/affordances.d.ts.map +1 -1
  65. package/dist/editing/affordances.js +1 -0
  66. package/dist/editing/affordances.js.map +1 -1
  67. package/dist/generated/audio-fx-runtime-inline.d.ts +3 -0
  68. package/dist/generated/audio-fx-runtime-inline.d.ts.map +1 -0
  69. package/dist/generated/audio-fx-runtime-inline.js +7 -0
  70. package/dist/generated/audio-fx-runtime-inline.js.map +1 -0
  71. package/dist/generated/runtime-inline.js +1 -1
  72. package/dist/generated/runtime-inline.js.map +1 -1
  73. package/dist/hyperframe.runtime.iife.js +238 -28
  74. package/dist/runtime/applyVariableBindings.d.ts +45 -0
  75. package/dist/runtime/applyVariableBindings.d.ts.map +1 -0
  76. package/dist/runtime/applyVariableBindings.js +194 -0
  77. package/dist/runtime/applyVariableBindings.js.map +1 -0
  78. package/dist/runtime/audioAutomationVolume.d.ts +17 -0
  79. package/dist/runtime/audioAutomationVolume.d.ts.map +1 -0
  80. package/dist/runtime/audioAutomationVolume.js +49 -0
  81. package/dist/runtime/audioAutomationVolume.js.map +1 -0
  82. package/dist/runtime/media.d.ts.map +1 -1
  83. package/dist/runtime/media.js +17 -1
  84. package/dist/runtime/media.js.map +1 -1
  85. package/dist/runtime/variableScope.d.ts +9 -0
  86. package/dist/runtime/variableScope.d.ts.map +1 -0
  87. package/dist/runtime/variableScope.js +21 -0
  88. package/dist/runtime/variableScope.js.map +1 -0
  89. package/package.json +51 -6
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Plays automation envelopes through native AudioParam scheduling.
3
+ *
4
+ * Nothing here runs per frame. The envelope is handed to the audio thread once,
5
+ * as ramps and curves, so it stays sample-accurate no matter what the main
6
+ * thread is doing — and the offline render schedules it the same way, which is
7
+ * why preview and render agree by construction rather than by tolerance.
8
+ */
9
+ import { type HfAutomation, type HfAutomationLane } from "../audioAutomation.js";
10
+ import type { HfAudioFxChain } from "../audioFx.js";
11
+ import type { FxNodeHandle, FxParamTarget } from "./audioFxGraph.js";
12
+ /** Where the clip sits in context time when its source is scheduled. */
13
+ export interface AutomationTiming {
14
+ /** Context time the source was scheduled at. */
15
+ scheduledAt: number;
16
+ /** Clip-local seconds already elapsed at that moment; negative before it starts. */
17
+ elapsed: number;
18
+ /** Playback rate, which compresses clip seconds into context seconds. */
19
+ rate: number;
20
+ }
21
+ /**
22
+ * Drop every event booked on a parameter, including a curve already under way.
23
+ *
24
+ * Anything landing inside a running curve is refused — a fresh curve, or the
25
+ * plain `.value` write that re-parameterising a chain performs — so the param has
26
+ * to be cancelled first. Measured against Chrome, any cancel frees the span; this
27
+ * takes the strongest form on purpose, because curve-over-curve refusals were
28
+ * reported from the field with a cancel at the new schedule time already in place
29
+ * and have never reproduced. Cancelling from zero cannot leave a stale event
30
+ * behind whatever that mechanism is.
31
+ *
32
+ * Safe on these parameters because this scheduler is their only writer: they
33
+ * belong to effect nodes it built, and the caller re-seeds the value in the same
34
+ * breath, so nothing clicks.
35
+ */
36
+ export declare function clearParamLane(targets: readonly FxParamTarget[]): void;
37
+ /** Stop an envelope, leaving the parameter wherever it currently sits. */
38
+ export declare function cancelParamLane(targets: readonly FxParamTarget[], from: number): void;
39
+ /**
40
+ * Schedule one lane onto every AudioParam behind its knob.
41
+ *
42
+ * Existing automation from an earlier schedule is cancelled first, so calling
43
+ * this again after an edit replaces the envelope rather than layering on it.
44
+ */
45
+ export declare function scheduleParamLane(targets: readonly FxParamTarget[], lane: HfAutomationLane, scale: "linear" | "log", timing: AutomationTiming): void;
46
+ /** One built effect, paired with the chain node id lanes address it by. */
47
+ export interface AutomatableNode {
48
+ id?: string;
49
+ handle: FxNodeHandle;
50
+ }
51
+ /**
52
+ * Schedule every FX lane in an automation set against a built chain.
53
+ *
54
+ * Lanes with nowhere to write are skipped rather than reported: a one-pole
55
+ * filter exposes no frequency param, and a worklet effect exposes none at all.
56
+ * Returns the targets that were scheduled, so they can be cancelled together.
57
+ */
58
+ export declare function scheduleChainAutomation(automation: HfAutomation, chain: HfAudioFxChain, nodes: readonly AutomatableNode[], timing: AutomationTiming,
59
+ /** The wet/dry blend around each preset run, from `FxChainHandle.presets`. */
60
+ presets?: Record<string, FxParamTarget[]>): FxParamTarget[];
61
+ /** The track's volume lane, if it has one. */
62
+ export declare function volumeLane(automation: HfAutomation): HfAutomationLane | null;
63
+ //# sourceMappingURL=audioFxAutomation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audioFxAutomation.d.ts","sourceRoot":"","sources":["../../src/audio/audioFxAutomation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAKL,KAAK,YAAY,EACjB,KAAK,gBAAgB,EAEtB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAErE,wEAAwE;AACxE,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,oFAAoF;IACpF,OAAO,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;CACd;AA2ID;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,GAAG,IAAI,CAEtE;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAUrF;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,SAAS,aAAa,EAAE,EACjC,IAAI,EAAE,gBAAgB,EACtB,KAAK,EAAE,QAAQ,GAAG,KAAK,EACvB,MAAM,EAAE,gBAAgB,GACvB,IAAI,CAeN;AAED,2EAA2E;AAC3E,MAAM,WAAW,eAAe;IAC9B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,YAAY,CAAC;CACtB;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,YAAY,EACxB,KAAK,EAAE,cAAc,EACrB,KAAK,EAAE,SAAS,eAAe,EAAE,EACjC,MAAM,EAAE,gBAAgB;AACxB,8EAA8E;AAC9E,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,GACxC,aAAa,EAAE,CAuBjB;AAED,8CAA8C;AAC9C,wBAAgB,UAAU,CAAC,UAAU,EAAE,YAAY,GAAG,gBAAgB,GAAG,IAAI,CAE5E"}
@@ -0,0 +1,219 @@
1
+ /**
2
+ * Plays automation envelopes through native AudioParam scheduling.
3
+ *
4
+ * Nothing here runs per frame. The envelope is handed to the audio thread once,
5
+ * as ramps and curves, so it stays sample-accurate no matter what the main
6
+ * thread is doing — and the offline render schedules it the same way, which is
7
+ * why preview and render agree by construction rather than by tolerance.
8
+ */
9
+ import { isConstantLane, resolveAutomationRange, sampleAutomationCurve, sampleAutomationLane, } from "../audioAutomation.js";
10
+ import { parseAutomationTarget, VOLUME_TARGET } from "../audioAutomation.js";
11
+ /**
12
+ * Sampling density for segments that cannot be expressed as a ramp. Dense
13
+ * enough that a curve is inaudible from a continuous one, capped so a long
14
+ * segment cannot allocate without bound.
15
+ */
16
+ const CURVE_POINTS_PER_SEC = 100;
17
+ const MIN_CURVE_POINTS = 8;
18
+ const MAX_CURVE_POINTS = 4096;
19
+ const identity = (v) => v;
20
+ /**
21
+ * A segment is a straight line only when nothing bends it: no curvature and no
22
+ * via point on the point it leaves, a linear parameter scale, and no unit
23
+ * mapping that could be non-linear. Everything else is sampled.
24
+ *
25
+ * Both bend forms have to be checked. `curve` is an exponent; a via point names
26
+ * an interior point the segment passes through, and it is what the timeline
27
+ * writes when a bend is dragged. Testing only the exponent read every dragged
28
+ * bend as straight and played it as a linear ramp — the lane drew one shape and
29
+ * the ear got another.
30
+ */
31
+ function isStraight(point, scale, map) {
32
+ const bent = Boolean(point.curve) || (point.viaX !== undefined && point.viaY !== undefined);
33
+ return !bent && scale === "linear" && !map;
34
+ }
35
+ function curvePointCount(duration) {
36
+ const wanted = Math.ceil(duration * CURVE_POINTS_PER_SEC);
37
+ return Math.min(MAX_CURVE_POINTS, Math.max(MIN_CURVE_POINTS, wanted));
38
+ }
39
+ /**
40
+ * One segment of the envelope, as the event that plays it. Returns null when
41
+ * the segment is already behind the playhead.
42
+ */
43
+ function segmentOp(lane, index, scale, timing, map) {
44
+ const { scheduledAt, elapsed, rate } = timing;
45
+ const apply = map ?? identity;
46
+ const toCtx = (t) => scheduledAt + (t - elapsed) / rate;
47
+ const a = lane.points[index];
48
+ const b = lane.points[index + 1];
49
+ const toTime = toCtx(b.t);
50
+ if (toTime <= scheduledAt)
51
+ return null;
52
+ const fromTime = Math.max(scheduledAt, toCtx(a.t));
53
+ const duration = toTime - fromTime;
54
+ if (duration <= 0)
55
+ return null;
56
+ if (isStraight(a, scale, map)) {
57
+ return { kind: "ramp", time: toTime, value: apply(b.v) };
58
+ }
59
+ // Sample from wherever the segment is entered, which is mid-segment when the
60
+ // playhead landed inside it.
61
+ const count = curvePointCount(duration);
62
+ const raw = sampleAutomationCurve(lane, Math.max(a.t, elapsed), b.t, count, scale);
63
+ const values = new Float32Array(count);
64
+ for (let k = 0; k < count; k += 1)
65
+ values[k] = apply(raw[k] ?? 0);
66
+ return { kind: "curve", time: fromTime, duration, values };
67
+ }
68
+ /** Turn a lane into the events one AudioParam should receive. */
69
+ function planOps(lane, scale, timing, map) {
70
+ const ops = [];
71
+ for (let i = 0; i + 1 < lane.points.length; i += 1) {
72
+ const op = segmentOp(lane, i, scale, timing, map);
73
+ if (op)
74
+ ops.push(op);
75
+ }
76
+ // Hold the envelope's value at the moment playback starts. This is what makes
77
+ // a lane correct before its first point and after its last, and it gives a
78
+ // following ramp something to ramp from.
79
+ //
80
+ // A value curve may not overlap another event, so the seed is dropped when a
81
+ // curve already begins at that instant — the curve sets the value itself.
82
+ const first = ops[0];
83
+ if (!(first?.kind === "curve" && first.time <= timing.scheduledAt)) {
84
+ ops.unshift({
85
+ kind: "set",
86
+ time: timing.scheduledAt,
87
+ value: (map ?? identity)(sampleAutomationLane(lane, timing.elapsed, scale)),
88
+ });
89
+ }
90
+ return ops;
91
+ }
92
+ /**
93
+ * Hand the plan to the AudioParam, degrading a curve the browser will not take.
94
+ *
95
+ * A value curve may not overlap another, and this has been seen refused in the
96
+ * field while rescheduling mid-playback — two passes landing a render quantum
97
+ * apart, which is what applying a carve while the transport runs does. Every
98
+ * caller here cancels the parameter first, and measured against Chrome that is
99
+ * enough to free even a curve already under way, so the mechanism behind those
100
+ * reports is not understood and does not reproduce. This catch is the backstop
101
+ * for it: unhandled, the exception reached the console and abandoned every
102
+ * remaining segment of the envelope.
103
+ *
104
+ * A ramp to the same destination is always accepted, since it books no span. The
105
+ * segment loses its bend until the next full reschedule, which is a far better
106
+ * failure than the rest of the envelope never being scheduled at all.
107
+ */
108
+ function emit(param, ops) {
109
+ for (const op of ops) {
110
+ if (op.kind === "set")
111
+ param.setValueAtTime(op.value, op.time);
112
+ else if (op.kind === "ramp")
113
+ param.linearRampToValueAtTime(op.value, op.time);
114
+ else {
115
+ try {
116
+ param.setValueCurveAtTime(op.values, op.time, op.duration);
117
+ }
118
+ catch {
119
+ const end = op.values[op.values.length - 1] ?? 0;
120
+ param.linearRampToValueAtTime(end, op.time + op.duration);
121
+ }
122
+ }
123
+ }
124
+ }
125
+ /**
126
+ * Drop every event booked on a parameter, including a curve already under way.
127
+ *
128
+ * Anything landing inside a running curve is refused — a fresh curve, or the
129
+ * plain `.value` write that re-parameterising a chain performs — so the param has
130
+ * to be cancelled first. Measured against Chrome, any cancel frees the span; this
131
+ * takes the strongest form on purpose, because curve-over-curve refusals were
132
+ * reported from the field with a cancel at the new schedule time already in place
133
+ * and have never reproduced. Cancelling from zero cannot leave a stale event
134
+ * behind whatever that mechanism is.
135
+ *
136
+ * Safe on these parameters because this scheduler is their only writer: they
137
+ * belong to effect nodes it built, and the caller re-seeds the value in the same
138
+ * breath, so nothing clicks.
139
+ */
140
+ export function clearParamLane(targets) {
141
+ for (const target of targets)
142
+ target.param.cancelScheduledValues(0);
143
+ }
144
+ /** Stop an envelope, leaving the parameter wherever it currently sits. */
145
+ export function cancelParamLane(targets, from) {
146
+ for (const target of targets) {
147
+ // Keep the value the ramp had reached rather than snapping back to the
148
+ // last explicitly-set one, which would click.
149
+ if (typeof target.param.cancelAndHoldAtTime === "function") {
150
+ target.param.cancelAndHoldAtTime(from);
151
+ }
152
+ else {
153
+ target.param.cancelScheduledValues(from);
154
+ }
155
+ }
156
+ }
157
+ /**
158
+ * Schedule one lane onto every AudioParam behind its knob.
159
+ *
160
+ * Existing automation from an earlier schedule is cancelled first, so calling
161
+ * this again after an edit replaces the envelope rather than layering on it.
162
+ */
163
+ export function scheduleParamLane(targets, lane, scale, timing) {
164
+ if (lane.points.length === 0)
165
+ return;
166
+ for (const target of targets) {
167
+ // Cleared from zero rather than from this instant: a reschedule mid-playback
168
+ // lands inside the previous pass's still-running curve, and the field reports
169
+ // of that being refused had a cancel at this instant already in place. The
170
+ // plan below re-seeds the value here, so clearing costs nothing audible.
171
+ clearParamLane([target]);
172
+ if (isConstantLane(lane)) {
173
+ const value = (target.map ?? identity)(lane.points[0].v);
174
+ target.param.setValueAtTime(value, timing.scheduledAt);
175
+ continue;
176
+ }
177
+ emit(target.param, planOps(lane, scale, timing, target.map));
178
+ }
179
+ }
180
+ /**
181
+ * Schedule every FX lane in an automation set against a built chain.
182
+ *
183
+ * Lanes with nowhere to write are skipped rather than reported: a one-pole
184
+ * filter exposes no frequency param, and a worklet effect exposes none at all.
185
+ * Returns the targets that were scheduled, so they can be cancelled together.
186
+ */
187
+ export function scheduleChainAutomation(automation, chain, nodes, timing,
188
+ /** The wet/dry blend around each preset run, from `FxChainHandle.presets`. */
189
+ presets) {
190
+ const byId = new Map(nodes.filter((n) => n.id).map((n) => [n.id, n.handle]));
191
+ const scheduled = [];
192
+ for (const lane of automation.lanes) {
193
+ const parsed = parseAutomationTarget(lane.target);
194
+ if (!parsed)
195
+ continue;
196
+ // A whole-preset lane drives the wet/dry blend the graph wrapped its run in,
197
+ // rather than any node's parameter — which is the point of it: a preset's
198
+ // nodes share no automatable parameter, and its worklet effects expose none
199
+ // at all.
200
+ const targets = parsed.kind === "preset"
201
+ ? presets?.[parsed.presetId]
202
+ : parsed.kind === "fx"
203
+ ? byId.get(parsed.nodeId)?.automation?.[parsed.param]
204
+ : undefined;
205
+ if (!targets || targets.length === 0)
206
+ continue;
207
+ const range = resolveAutomationRange(lane.target, chain);
208
+ if (!range)
209
+ continue;
210
+ scheduleParamLane(targets, lane, range.scale, timing);
211
+ scheduled.push(...targets);
212
+ }
213
+ return scheduled;
214
+ }
215
+ /** The track's volume lane, if it has one. */
216
+ export function volumeLane(automation) {
217
+ return automation.lanes.find((lane) => lane.target === VOLUME_TARGET) ?? null;
218
+ }
219
+ //# sourceMappingURL=audioFxAutomation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audioFxAutomation.js","sourceRoot":"","sources":["../../src/audio/audioFxAutomation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Builds the Web Audio graph for an FX chain, one builder per `web` id in the
3
+ * core registry.
4
+ *
5
+ * Every node exposes `update`, so turning a dial re-parameterises the running
6
+ * graph instead of rebuilding it. That is the whole point of previewing in the
7
+ * browser: an AudioParam change lands on the next 128-sample render quantum,
8
+ * about 2.7 ms at 48 kHz, so the knob-to-ear loop is immediate.
9
+ */
10
+ import { type HfAudioFxChain, type HfAudioFxParamValues } from "../audioFx.js";
11
+ import { audioFxWorkletsReady, ensureAudioFxWorklets } from "./audioFxWorklets.js";
12
+ /**
13
+ * Deterministic reverb impulse, shared by both engines so the browser and the
14
+ * render convolve the identical response. Exponentially-decaying noise with a
15
+ * one-pole lowpass standing in for air absorption; the PRNG is seeded from the
16
+ * parameters so the same room always produces the same tail.
17
+ */
18
+ export declare function synthesizeReverbImpulse(sampleRate: number, size: number, damping: number): Float32Array;
19
+ /**
20
+ * Where an automation lane writes when it drives one knob.
21
+ *
22
+ * A knob is not always one AudioParam. A wet/dry mix is two gains moving in
23
+ * opposition, and a knob in milliseconds drives a delay time in seconds, so
24
+ * each target carries its own mapping out of the knob's declared unit.
25
+ */
26
+ export interface FxParamTarget {
27
+ param: AudioParam;
28
+ map?: (value: number) => number;
29
+ }
30
+ export interface FxNodeHandle {
31
+ input: AudioNode;
32
+ output: AudioNode;
33
+ update(params: HfAudioFxParamValues): void;
34
+ /**
35
+ * AudioParams behind the knobs the registry marks `automatable`, keyed by
36
+ * parameter key. Absent for a node whose values cannot be scheduled.
37
+ */
38
+ automation?: Record<string, FxParamTarget[]>;
39
+ dispose(): void;
40
+ }
41
+ /** Effect ids whose Web Audio node needs a worklet module registered first. */
42
+ export declare function chainNeedsWorklets(chain: HfAudioFxChain): boolean;
43
+ export declare function buildFxNode(ctx: BaseAudioContext, type: string, params: HfAudioFxParamValues, elapsed?: number): FxNodeHandle;
44
+ export interface FxChainHandle {
45
+ input: AudioNode;
46
+ output: AudioNode;
47
+ /** Built effects in chain order, carrying the node ids lanes address. */
48
+ nodes: {
49
+ id?: string;
50
+ type: string;
51
+ handle: FxNodeHandle;
52
+ }[];
53
+ /**
54
+ * The wet/dry blend around each preset run, by preset id — where a
55
+ * whole-preset lane writes. Two gains in opposition, the same shape
56
+ * `mixTargets` builds for an effect's own mix knob.
57
+ */
58
+ presets: Record<string, FxParamTarget[]>;
59
+ /** Re-parameterise in place when the shape is unchanged; false if a rebuild is needed. */
60
+ update(chain: HfAudioFxChain): boolean;
61
+ dispose(): void;
62
+ }
63
+ /**
64
+ * Build the whole chain in series. Returns a handle whose `input`/`output` can
65
+ * be spliced into any graph; an empty chain yields a pass-through.
66
+ *
67
+ * `elapsed` is where in the clip this is being built — see `Builder`. It only
68
+ * reaches the modulated effects, and only matters when the graph is built after
69
+ * the audio has already started.
70
+ */
71
+ export declare function buildFxChain(ctx: BaseAudioContext, chain: HfAudioFxChain, elapsed?: number): FxChainHandle;
72
+ export { audioFxWorkletsReady, ensureAudioFxWorklets };
73
+ //# sourceMappingURL=audioFxGraph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audioFxGraph.d.ts","sourceRoot":"","sources":["../../src/audio/audioFxGraph.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAIL,KAAK,cAAc,EAEnB,KAAK,oBAAoB,EAC1B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAEnF;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,YAAY,CA8Bd;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC3C;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IAC7C,OAAO,IAAI,IAAI,CAAC;CACjB;AA8aD,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAEjE;AAED,wBAAgB,WAAW,CACzB,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,oBAAoB,EAC5B,OAAO,SAAI,GACV,YAAY,CAWd;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,SAAS,CAAC;IAClB,yEAAyE;IACzE,KAAK,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,YAAY,CAAA;KAAE,EAAE,CAAC;IAC7D;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IACzC,0FAA0F;IAC1F,MAAM,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC;IACvC,OAAO,IAAI,IAAI,CAAC;CACjB;AAgED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,gBAAgB,EACrB,KAAK,EAAE,cAAc,EACrB,OAAO,SAAI,GACV,aAAa,CAwHf;AAED,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,CAAC"}