@hyperframes/core 0.7.107 → 0.7.109
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/dist/audio/audioFxAutomation.d.ts +63 -0
- package/dist/audio/audioFxAutomation.d.ts.map +1 -0
- package/dist/audio/audioFxAutomation.js +219 -0
- package/dist/audio/audioFxAutomation.js.map +1 -0
- package/dist/audio/audioFxGraph.d.ts +73 -0
- package/dist/audio/audioFxGraph.d.ts.map +1 -0
- package/dist/audio/audioFxGraph.js +649 -0
- package/dist/audio/audioFxGraph.js.map +1 -0
- package/dist/audio/audioFxTail.d.ts +28 -0
- package/dist/audio/audioFxTail.d.ts.map +1 -0
- package/dist/audio/audioFxTail.js +95 -0
- package/dist/audio/audioFxTail.js.map +1 -0
- package/dist/audio/audioFxWorklets.d.ts +8 -0
- package/dist/audio/audioFxWorklets.d.ts.map +1 -0
- package/dist/audio/audioFxWorklets.js +263 -0
- package/dist/audio/audioFxWorklets.js.map +1 -0
- package/dist/audioAutomation.d.ts +191 -0
- package/dist/audioAutomation.d.ts.map +1 -0
- package/dist/audioAutomation.js +488 -0
- package/dist/audioAutomation.js.map +1 -0
- package/dist/audioCarve.d.ts +216 -0
- package/dist/audioCarve.d.ts.map +1 -0
- package/dist/audioCarve.js +608 -0
- package/dist/audioCarve.js.map +1 -0
- package/dist/audioFx.d.ts +182 -0
- package/dist/audioFx.d.ts.map +1 -0
- package/dist/audioFx.js +813 -0
- package/dist/audioFx.js.map +1 -0
- package/dist/audioFxCopy.d.ts +89 -0
- package/dist/audioFxCopy.d.ts.map +1 -0
- package/dist/audioFxCopy.js +340 -0
- package/dist/audioFxCopy.js.map +1 -0
- package/dist/audioFxEq.d.ts +75 -0
- package/dist/audioFxEq.d.ts.map +1 -0
- package/dist/audioFxEq.js +153 -0
- package/dist/audioFxEq.js.map +1 -0
- package/dist/audioFxJobs.d.ts +52 -0
- package/dist/audioFxJobs.d.ts.map +1 -0
- package/dist/audioFxJobs.js +92 -0
- package/dist/audioFxJobs.js.map +1 -0
- package/dist/audioFxPresets.d.ts +91 -0
- package/dist/audioFxPresets.d.ts.map +1 -0
- package/dist/audioFxPresets.js +320 -0
- package/dist/audioFxPresets.js.map +1 -0
- package/dist/audioFxProfiles.d.ts +65 -0
- package/dist/audioFxProfiles.d.ts.map +1 -0
- package/dist/audioFxProfiles.js +209 -0
- package/dist/audioFxProfiles.js.map +1 -0
- package/dist/audioLeveller.d.ts +62 -0
- package/dist/audioLeveller.d.ts.map +1 -0
- package/dist/audioLeveller.js +208 -0
- package/dist/audioLeveller.js.map +1 -0
- package/dist/canaryRegistry.d.ts.map +1 -1
- package/dist/canaryRegistry.js +8 -0
- package/dist/canaryRegistry.js.map +1 -1
- package/dist/compiler/compositionScoping.d.ts +3 -0
- package/dist/compiler/compositionScoping.d.ts.map +1 -1
- package/dist/compiler/compositionScoping.js +34 -11
- package/dist/compiler/compositionScoping.js.map +1 -1
- package/dist/compiler/htmlBundler.d.ts.map +1 -1
- package/dist/compiler/htmlBundler.js +42 -2
- package/dist/compiler/htmlBundler.js.map +1 -1
- package/dist/editing/affordances.d.ts +3 -0
- package/dist/editing/affordances.d.ts.map +1 -1
- package/dist/editing/affordances.js +1 -0
- package/dist/editing/affordances.js.map +1 -1
- package/dist/generated/audio-fx-runtime-inline.d.ts +3 -0
- package/dist/generated/audio-fx-runtime-inline.d.ts.map +1 -0
- package/dist/generated/audio-fx-runtime-inline.js +7 -0
- package/dist/generated/audio-fx-runtime-inline.js.map +1 -0
- package/dist/generated/runtime-inline.js +1 -1
- package/dist/generated/runtime-inline.js.map +1 -1
- package/dist/hyperframe.runtime.iife.js +238 -28
- package/dist/runtime/applyVariableBindings.d.ts +45 -0
- package/dist/runtime/applyVariableBindings.d.ts.map +1 -0
- package/dist/runtime/applyVariableBindings.js +194 -0
- package/dist/runtime/applyVariableBindings.js.map +1 -0
- package/dist/runtime/audioAutomationVolume.d.ts +17 -0
- package/dist/runtime/audioAutomationVolume.d.ts.map +1 -0
- package/dist/runtime/audioAutomationVolume.js +49 -0
- package/dist/runtime/audioAutomationVolume.js.map +1 -0
- package/dist/runtime/media.d.ts.map +1 -1
- package/dist/runtime/media.js +17 -1
- package/dist/runtime/media.js.map +1 -1
- package/dist/runtime/variableScope.d.ts +9 -0
- package/dist/runtime/variableScope.d.ts.map +1 -0
- package/dist/runtime/variableScope.js +21 -0
- package/dist/runtime/variableScope.js.map +1 -0
- package/package.json +51 -6
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A multi-band EQ, as a composite over effects that already ship.
|
|
3
|
+
*
|
|
4
|
+
* Bass, middle and treble is the most widely understood audio control there is
|
|
5
|
+
* — everyone has used one — which makes it the right answer for an author who
|
|
6
|
+
* would never reach for a parametric filter. It also removes a real failure:
|
|
7
|
+
* without it, a chain shaping two ranges holds two peaking filters that look
|
|
8
|
+
* identical in the rack.
|
|
9
|
+
*
|
|
10
|
+
* Built the way the carve is: one module owning several tagged nodes, rather
|
|
11
|
+
* than a new effect type. Three bands ARE a low shelf, a peaking and a high
|
|
12
|
+
* shelf, so there is nothing new in the graph, nothing new in the render, and
|
|
13
|
+
* an author who opens the details finds exactly the filters they could have
|
|
14
|
+
* added by hand.
|
|
15
|
+
*
|
|
16
|
+
* That is also forced by the registry: parameters are a flat key/value record,
|
|
17
|
+
* so an `eq` effect *type* carrying N bands would need array-shaped params it
|
|
18
|
+
* has no way to express.
|
|
19
|
+
*/
|
|
20
|
+
import { HF_AUDIO_FX_CHAIN_VERSION, mintAudioFxNodeId, normalizeAudioFxParams, } from "./audioFx.js";
|
|
21
|
+
/**
|
|
22
|
+
* How far a fader travels. The registry allows ±40 dB on these filters, which
|
|
23
|
+
* is a repair tool's range — a tone control that can bury a track under 40 dB
|
|
24
|
+
* of bass is not a tone control. ±12 is the span a hi-fi offers, and it is
|
|
25
|
+
* enough to fix a voice.
|
|
26
|
+
*/
|
|
27
|
+
export const HF_AUDIO_EQ_RANGE_DB = 12;
|
|
28
|
+
/** Bass, middle, treble — the set nobody needs taught. */
|
|
29
|
+
export const HF_AUDIO_EQ_3 = [
|
|
30
|
+
{ name: "Bass", frequency: 200, gain: 0, kind: "lowshelf" },
|
|
31
|
+
{ name: "Middle", frequency: 1000, gain: 0, q: 0.9, kind: "peaking" },
|
|
32
|
+
{ name: "Treble", frequency: 4000, gain: 0, kind: "highshelf" },
|
|
33
|
+
];
|
|
34
|
+
/**
|
|
35
|
+
* Five bands, named from the shared vocabulary the rest of the rack uses — so
|
|
36
|
+
* reaching for the EQ is also how an author learns the words.
|
|
37
|
+
*/
|
|
38
|
+
export const HF_AUDIO_EQ_5 = [
|
|
39
|
+
{ name: "Bass", frequency: 160, gain: 0, kind: "lowshelf" },
|
|
40
|
+
{ name: "Warmth", frequency: 350, gain: 0, q: 1, kind: "peaking" },
|
|
41
|
+
{ name: "Middle", frequency: 1000, gain: 0, q: 0.9, kind: "peaking" },
|
|
42
|
+
{ name: "Clarity", frequency: 3000, gain: 0, q: 1, kind: "peaking" },
|
|
43
|
+
{ name: "Air", frequency: 9000, gain: 0, kind: "highshelf" },
|
|
44
|
+
];
|
|
45
|
+
const clampGain = (db) => Number.isFinite(db) ? Math.max(-HF_AUDIO_EQ_RANGE_DB, Math.min(HF_AUDIO_EQ_RANGE_DB, db)) : 0;
|
|
46
|
+
/** Realise bands as ordinary nodes, tagged so the module can find them again. */
|
|
47
|
+
export function audioEqNodes(bands, eqId, chain) {
|
|
48
|
+
const out = [];
|
|
49
|
+
let running = { ...chain, nodes: [...chain.nodes] };
|
|
50
|
+
for (const band of bands) {
|
|
51
|
+
const made = {
|
|
52
|
+
type: band.kind,
|
|
53
|
+
id: mintAudioFxNodeId(running),
|
|
54
|
+
fromEq: eqId,
|
|
55
|
+
// The band name IS the node's job name, so a rack showing the bands
|
|
56
|
+
// individually still reads as words rather than as three filter types.
|
|
57
|
+
label: band.name,
|
|
58
|
+
enabled: true,
|
|
59
|
+
params: normalizeAudioFxParams(band.kind, {
|
|
60
|
+
frequency: band.frequency,
|
|
61
|
+
gain: clampGain(band.gain),
|
|
62
|
+
...(band.kind === "peaking" ? { q: band.q ?? 1 } : {}),
|
|
63
|
+
}),
|
|
64
|
+
};
|
|
65
|
+
out.push(made);
|
|
66
|
+
running = { ...running, nodes: [...running.nodes, made] };
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
/** Add an EQ to a chain. Returns the chain and the id the module addresses it by. */
|
|
71
|
+
export function addAudioEq(chain, bands = HF_AUDIO_EQ_3) {
|
|
72
|
+
const taken = new Set(chain.nodes.map((n) => n.fromEq).filter(Boolean));
|
|
73
|
+
let eqId = "eq1";
|
|
74
|
+
for (let i = 1; taken.has(eqId); i += 1)
|
|
75
|
+
eqId = `eq${i + 1}`;
|
|
76
|
+
return {
|
|
77
|
+
chain: { ...chain, nodes: [...chain.nodes, ...audioEqNodes(bands, eqId, chain)] },
|
|
78
|
+
eqId,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/** Every EQ in a chain, in the order their first band appears. */
|
|
82
|
+
export function audioEqIds(chain) {
|
|
83
|
+
const seen = [];
|
|
84
|
+
for (const node of chain.nodes) {
|
|
85
|
+
if (node.fromEq && !seen.includes(node.fromEq))
|
|
86
|
+
seen.push(node.fromEq);
|
|
87
|
+
}
|
|
88
|
+
return seen;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Read one EQ's bands back out of the chain.
|
|
92
|
+
*
|
|
93
|
+
* The nodes are the truth, not a cached band list: an author can open the
|
|
94
|
+
* details and move a frequency by hand, and the faders have to reflect that
|
|
95
|
+
* rather than silently overwrite it on the next drag.
|
|
96
|
+
*/
|
|
97
|
+
export function readAudioEqBands(chain, eqId) {
|
|
98
|
+
const out = [];
|
|
99
|
+
for (const node of chain.nodes) {
|
|
100
|
+
if (node.fromEq !== eqId)
|
|
101
|
+
continue;
|
|
102
|
+
if (node.type !== "lowshelf" && node.type !== "peaking" && node.type !== "highshelf")
|
|
103
|
+
continue;
|
|
104
|
+
const params = node.params ?? {};
|
|
105
|
+
const freq = params["frequency"];
|
|
106
|
+
const gain = params["gain"];
|
|
107
|
+
const q = params["q"];
|
|
108
|
+
out.push({
|
|
109
|
+
name: node.label ?? node.type,
|
|
110
|
+
frequency: typeof freq === "number" ? freq : 1000,
|
|
111
|
+
gain: typeof gain === "number" ? gain : 0,
|
|
112
|
+
...(typeof q === "number" ? { q } : {}),
|
|
113
|
+
kind: node.type,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
return out;
|
|
117
|
+
}
|
|
118
|
+
/** Move one fader. Everything else about the band is left alone. */
|
|
119
|
+
export function setAudioEqBandGain(chain, eqId, bandName, gain) {
|
|
120
|
+
return {
|
|
121
|
+
...chain,
|
|
122
|
+
nodes: chain.nodes.map((node) => node.fromEq === eqId && node.label === bandName
|
|
123
|
+
? {
|
|
124
|
+
...node,
|
|
125
|
+
params: normalizeAudioFxParams(node.type, {
|
|
126
|
+
...(node.params ?? {}),
|
|
127
|
+
gain: clampGain(gain),
|
|
128
|
+
}),
|
|
129
|
+
}
|
|
130
|
+
: node),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/** Remove a whole EQ, bands and all. */
|
|
134
|
+
export function removeAudioEq(chain, eqId) {
|
|
135
|
+
return { ...chain, nodes: chain.nodes.filter((n) => n.fromEq !== eqId) };
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* What the module says when it is closed.
|
|
139
|
+
*
|
|
140
|
+
* Named for the bands that were actually moved, so a rack of collapsed modules
|
|
141
|
+
* still reads as a sentence — and an untouched EQ says so rather than listing
|
|
142
|
+
* three zeroes.
|
|
143
|
+
*/
|
|
144
|
+
export function audioEqSummary(bands) {
|
|
145
|
+
const moved = bands.filter((b) => Math.abs(b.gain) >= 0.1);
|
|
146
|
+
if (moved.length === 0)
|
|
147
|
+
return "Flat — nothing changed yet";
|
|
148
|
+
return moved
|
|
149
|
+
.map((b) => `${b.name} ${b.gain > 0 ? "+" : "−"}${Math.abs(Number(b.gain.toFixed(1)))}`)
|
|
150
|
+
.join(", ");
|
|
151
|
+
}
|
|
152
|
+
export const HF_AUDIO_EQ_CHAIN_VERSION = HF_AUDIO_FX_CHAIN_VERSION;
|
|
153
|
+
//# sourceMappingURL=audioFxEq.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audioFxEq.js","sourceRoot":"","sources":["../src/audioFxEq.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Named jobs: the range IS the module.
|
|
3
|
+
*
|
|
4
|
+
* "Shape One Range" has three controls — where, how much, how wide — and no
|
|
5
|
+
* honest way to nominate one of them as the knob that matters. Nominating *how
|
|
6
|
+
* much* is incoherent, because boosting an unspecified frequency means nothing:
|
|
7
|
+
* the range is the first decision, not the second.
|
|
8
|
+
*
|
|
9
|
+
* So the menu offers the decision instead of the machine. Each job is a peaking
|
|
10
|
+
* filter with its frequency already chosen — Reduce Mud, Add Clarity, Soften
|
|
11
|
+
* Harshness — and picking the module IS picking the range, which makes one knob
|
|
12
|
+
* honest rather than a simplification hiding the real choice. It also dissolves
|
|
13
|
+
* the duplicate-name problem at the root: a preset that cuts mud and then lifts
|
|
14
|
+
* clarity used to read "Shape One Range" twice with nothing to tell them apart.
|
|
15
|
+
*
|
|
16
|
+
* Every job here is one the preset catalogue already ships, at the settings it
|
|
17
|
+
* ships them with, so this names the vocabulary the presets were written in
|
|
18
|
+
* rather than inventing a second one. Reasoning in
|
|
19
|
+
* `plans/audio-fx-ux/README.md` §"The hole in the single-knob rule".
|
|
20
|
+
*
|
|
21
|
+
* The frequency is a starting point, not a cage — it is an ordinary peaking node
|
|
22
|
+
* underneath, and Details opens on the same three controls it always had.
|
|
23
|
+
*/
|
|
24
|
+
import { type HfAudioFxChain, type HfAudioFxNode, type HfAudioFxParamValues } from "./audioFx.js";
|
|
25
|
+
export interface HfAudioFxJob {
|
|
26
|
+
id: string;
|
|
27
|
+
/** What the rack calls the node this makes. */
|
|
28
|
+
label: string;
|
|
29
|
+
/** The complaint that leads here, in the author's words. */
|
|
30
|
+
does: string;
|
|
31
|
+
/** The registry effect underneath. */
|
|
32
|
+
type: string;
|
|
33
|
+
/** Where it acts, and how hard — the decision the author is spared. */
|
|
34
|
+
params: HfAudioFxParamValues;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Ordered low to high, which is the order an author hears them in: weight and
|
|
38
|
+
* mud at the bottom, clarity and harshness at the top.
|
|
39
|
+
*/
|
|
40
|
+
export declare const HF_AUDIO_FX_JOBS: readonly HfAudioFxJob[];
|
|
41
|
+
export declare function getAudioFxJob(id: string): HfAudioFxJob | undefined;
|
|
42
|
+
/** Effect ids the job list covers, which the add menu offers as jobs instead. */
|
|
43
|
+
export declare const HF_AUDIO_FX_JOB_TYPES: ReadonlySet<string>;
|
|
44
|
+
/**
|
|
45
|
+
* The node a job adds: an ordinary effect carrying the job's name.
|
|
46
|
+
*
|
|
47
|
+
* `label` is the field a preset already uses to name a node for the work it
|
|
48
|
+
* does, so a job needs nothing new — and a job node and a preset node are
|
|
49
|
+
* indistinguishable afterwards, which is right. They are the same idea.
|
|
50
|
+
*/
|
|
51
|
+
export declare function audioFxJobNode(job: HfAudioFxJob, chain: HfAudioFxChain): HfAudioFxNode;
|
|
52
|
+
//# sourceMappingURL=audioFxJobs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audioFxJobs.d.ts","sourceRoot":"","sources":["../src/audioFxJobs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,oBAAoB,EAC1B,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,MAAM,EAAE,oBAAoB,CAAC;CAC9B;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,YAAY,EAoCnD,CAAC;AAEF,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAElE;AAED,iFAAiF;AACjF,eAAO,MAAM,qBAAqB,EAAE,WAAW,CAAC,MAAM,CAErD,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,GAAG,aAAa,CAatF"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Named jobs: the range IS the module.
|
|
3
|
+
*
|
|
4
|
+
* "Shape One Range" has three controls — where, how much, how wide — and no
|
|
5
|
+
* honest way to nominate one of them as the knob that matters. Nominating *how
|
|
6
|
+
* much* is incoherent, because boosting an unspecified frequency means nothing:
|
|
7
|
+
* the range is the first decision, not the second.
|
|
8
|
+
*
|
|
9
|
+
* So the menu offers the decision instead of the machine. Each job is a peaking
|
|
10
|
+
* filter with its frequency already chosen — Reduce Mud, Add Clarity, Soften
|
|
11
|
+
* Harshness — and picking the module IS picking the range, which makes one knob
|
|
12
|
+
* honest rather than a simplification hiding the real choice. It also dissolves
|
|
13
|
+
* the duplicate-name problem at the root: a preset that cuts mud and then lifts
|
|
14
|
+
* clarity used to read "Shape One Range" twice with nothing to tell them apart.
|
|
15
|
+
*
|
|
16
|
+
* Every job here is one the preset catalogue already ships, at the settings it
|
|
17
|
+
* ships them with, so this names the vocabulary the presets were written in
|
|
18
|
+
* rather than inventing a second one. Reasoning in
|
|
19
|
+
* `plans/audio-fx-ux/README.md` §"The hole in the single-knob rule".
|
|
20
|
+
*
|
|
21
|
+
* The frequency is a starting point, not a cage — it is an ordinary peaking node
|
|
22
|
+
* underneath, and Details opens on the same three controls it always had.
|
|
23
|
+
*/
|
|
24
|
+
import { defaultAudioFxParams, mintAudioFxNodeId, normalizeAudioFxParams, } from "./audioFx.js";
|
|
25
|
+
/**
|
|
26
|
+
* Ordered low to high, which is the order an author hears them in: weight and
|
|
27
|
+
* mud at the bottom, clarity and harshness at the top.
|
|
28
|
+
*/
|
|
29
|
+
export const HF_AUDIO_FX_JOBS = [
|
|
30
|
+
{
|
|
31
|
+
id: "tame-boominess",
|
|
32
|
+
label: "Tame Boominess",
|
|
33
|
+
does: "Too much low-end body — it booms.",
|
|
34
|
+
type: "peaking",
|
|
35
|
+
params: { frequency: 200, gain: -4, q: 1.4 },
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "reduce-mud",
|
|
39
|
+
label: "Reduce Mud",
|
|
40
|
+
does: "Muffled, like it is behind cardboard.",
|
|
41
|
+
type: "peaking",
|
|
42
|
+
params: { frequency: 250, gain: -3, q: 1.2 },
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: "reduce-boxiness",
|
|
46
|
+
label: "Reduce Boxiness",
|
|
47
|
+
does: "Sounds like a small room, or a box.",
|
|
48
|
+
type: "peaking",
|
|
49
|
+
params: { frequency: 400, gain: -3, q: 1.4 },
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "add-clarity",
|
|
53
|
+
label: "Add Clarity",
|
|
54
|
+
does: "It is hard to make out — it sits back.",
|
|
55
|
+
type: "peaking",
|
|
56
|
+
params: { frequency: 3000, gain: 2.5, q: 1 },
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: "soften-harshness",
|
|
60
|
+
label: "Soften Harshness",
|
|
61
|
+
does: "Harsh and tiring to listen to.",
|
|
62
|
+
type: "peaking",
|
|
63
|
+
params: { frequency: 3200, gain: -3, q: 1.6 },
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
export function getAudioFxJob(id) {
|
|
67
|
+
return HF_AUDIO_FX_JOBS.find((job) => job.id === id);
|
|
68
|
+
}
|
|
69
|
+
/** Effect ids the job list covers, which the add menu offers as jobs instead. */
|
|
70
|
+
export const HF_AUDIO_FX_JOB_TYPES = new Set(HF_AUDIO_FX_JOBS.map((job) => job.type));
|
|
71
|
+
/**
|
|
72
|
+
* The node a job adds: an ordinary effect carrying the job's name.
|
|
73
|
+
*
|
|
74
|
+
* `label` is the field a preset already uses to name a node for the work it
|
|
75
|
+
* does, so a job needs nothing new — and a job node and a preset node are
|
|
76
|
+
* indistinguishable afterwards, which is right. They are the same idea.
|
|
77
|
+
*/
|
|
78
|
+
export function audioFxJobNode(job, chain) {
|
|
79
|
+
return {
|
|
80
|
+
type: job.type,
|
|
81
|
+
id: mintAudioFxNodeId(chain),
|
|
82
|
+
enabled: true,
|
|
83
|
+
label: job.label,
|
|
84
|
+
// Through the registry, so a job cannot ship a value the effect would clamp
|
|
85
|
+
// or a key it does not have.
|
|
86
|
+
params: normalizeAudioFxParams(job.type, {
|
|
87
|
+
...defaultAudioFxParams(job.type),
|
|
88
|
+
...job.params,
|
|
89
|
+
}),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=audioFxJobs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audioFxJobs.js","sourceRoot":"","sources":["../src/audioFxJobs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,sBAAsB,GAIvB,MAAM,cAAc,CAAC;AActB;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAA4B;IACvD;QACE,EAAE,EAAE,gBAAgB;QACpB,KAAK,EAAE,gBAAgB;QACvB,IAAI,EAAE,mCAAmC;QACzC,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE;KAC7C;IACD;QACE,EAAE,EAAE,YAAY;QAChB,KAAK,EAAE,YAAY;QACnB,IAAI,EAAE,uCAAuC;QAC7C,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE;KAC7C;IACD;QACE,EAAE,EAAE,iBAAiB;QACrB,KAAK,EAAE,iBAAiB;QACxB,IAAI,EAAE,qCAAqC;QAC3C,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE;KAC7C;IACD;QACE,EAAE,EAAE,aAAa;QACjB,KAAK,EAAE,aAAa;QACpB,IAAI,EAAE,wCAAwC;QAC9C,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE;KAC7C;IACD;QACE,EAAE,EAAE,kBAAkB;QACtB,KAAK,EAAE,kBAAkB;QACzB,IAAI,EAAE,gCAAgC;QACtC,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE;KAC9C;CACF,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,EAAU;IACtC,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AACvD,CAAC;AAED,iFAAiF;AACjF,MAAM,CAAC,MAAM,qBAAqB,GAAwB,IAAI,GAAG,CAC/D,gBAAgB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CACxC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,GAAiB,EAAE,KAAqB;IACrE,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,EAAE,EAAE,iBAAiB,CAAC,KAAK,CAAC;QAC5B,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,4EAA4E;QAC5E,6BAA6B;QAC7B,MAAM,EAAE,sBAAsB,CAAC,GAAG,CAAC,IAAI,EAAE;YACvC,GAAG,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC;YACjC,GAAG,GAAG,CAAC,MAAM;SACd,CAAC;KACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Named starting points for the FX rack.
|
|
3
|
+
*
|
|
4
|
+
* Voice carve turned a pile of effects into one understandable feature. These
|
|
5
|
+
* do the same for the cases an analysis cannot decide: a preset is a chain
|
|
6
|
+
* somebody already tuned, applied in one click and editable immediately
|
|
7
|
+
* afterwards.
|
|
8
|
+
*
|
|
9
|
+
* A preset is DATA, deliberately. Applying one writes ordinary nodes into
|
|
10
|
+
* `data-fx-chain` — the same nodes hand-building would produce — so there is no
|
|
11
|
+
* second code path to keep in agreement with the rack, nothing new in the
|
|
12
|
+
* render, and no failure mode the chain does not already have. The author can
|
|
13
|
+
* see everything that was written on their behalf and change any of it.
|
|
14
|
+
*
|
|
15
|
+
* Only the parameters a preset actually means are listed; `normalizeAudioFxParams`
|
|
16
|
+
* fills the rest from the effect's own defaults. That keeps each entry readable
|
|
17
|
+
* as an intent rather than a dump of every knob.
|
|
18
|
+
*
|
|
19
|
+
* Node ORDER is load-bearing — the chain is serial, so a limiter first and a
|
|
20
|
+
* limiter last are different sounds. Every preset below runs
|
|
21
|
+
* subtractive filtering → dynamics → tone → character → limiter, the order
|
|
22
|
+
* `skills/hyperframes-audio` already teaches.
|
|
23
|
+
*/
|
|
24
|
+
import { type HfAudioFxChain, type HfAudioFxNode, type HfAudioFxParamValues } from "./audioFx.js";
|
|
25
|
+
/**
|
|
26
|
+
* Which shelf of the menu a preset sits on.
|
|
27
|
+
*
|
|
28
|
+
* Deliberately NOT the effect registry's own `group` (filter/dynamics/…): that
|
|
29
|
+
* groups by what an effect *is*, and an author picking a preset is shopping for
|
|
30
|
+
* what they *want*. "Telephone" is filters and saturation; nobody looks for it
|
|
31
|
+
* under either.
|
|
32
|
+
*/
|
|
33
|
+
export type HfAudioFxPresetFamily = "voice" | "repair" | "character" | "space";
|
|
34
|
+
export interface HfAudioFxPresetNode {
|
|
35
|
+
/** Effect id from HF_AUDIO_FX. */
|
|
36
|
+
type: string;
|
|
37
|
+
/**
|
|
38
|
+
* What the rack calls this node — the JOB it is doing, not its filter type.
|
|
39
|
+
*
|
|
40
|
+
* A peaking filter is "Shape One Range" wherever it appears, so a chain that
|
|
41
|
+
* cuts mud and then lifts clarity shows the same words twice and an author
|
|
42
|
+
* cannot follow it. Naming each node for its job is what lets a preset read
|
|
43
|
+
* as a list of things that were done.
|
|
44
|
+
*/
|
|
45
|
+
label?: string;
|
|
46
|
+
/** Only what this preset means to set; the rest come from the effect's defaults. */
|
|
47
|
+
params?: HfAudioFxParamValues;
|
|
48
|
+
}
|
|
49
|
+
export interface HfAudioFxPreset {
|
|
50
|
+
id: string;
|
|
51
|
+
label: string;
|
|
52
|
+
family: HfAudioFxPresetFamily;
|
|
53
|
+
/** One line, in the author's language — what it does, not which effects it uses. */
|
|
54
|
+
description: string;
|
|
55
|
+
nodes: readonly HfAudioFxPresetNode[];
|
|
56
|
+
}
|
|
57
|
+
export declare const HF_AUDIO_FX_PRESETS: readonly HfAudioFxPreset[];
|
|
58
|
+
export declare const HF_AUDIO_FX_PRESET_IDS: readonly string[];
|
|
59
|
+
export declare function getAudioFxPreset(id: string): HfAudioFxPreset | undefined;
|
|
60
|
+
/** Menu order: the shelves, in the order the panel lists them. */
|
|
61
|
+
export declare const HF_AUDIO_FX_PRESET_FAMILIES: readonly HfAudioFxPresetFamily[];
|
|
62
|
+
export declare function audioFxPresetsByFamily(family: HfAudioFxPresetFamily): HfAudioFxPreset[];
|
|
63
|
+
/**
|
|
64
|
+
* Realise a preset as nodes ready to splice into `chain`.
|
|
65
|
+
*
|
|
66
|
+
* Ids are minted against the chain the nodes are joining, not against the
|
|
67
|
+
* preset, so applying the same preset twice cannot collide — and every node
|
|
68
|
+
* gets one, because an automation lane addresses its effect by id and a node
|
|
69
|
+
* without one can never be automated.
|
|
70
|
+
*
|
|
71
|
+
* Params are normalised here rather than at apply time: a preset that names a
|
|
72
|
+
* value the effect would clamp should land in the file as the value that will
|
|
73
|
+
* actually be rendered, so the rack never shows a number the graph is not using.
|
|
74
|
+
*/
|
|
75
|
+
export declare function audioFxPresetNodes(preset: HfAudioFxPreset, chain: HfAudioFxChain): HfAudioFxNode[];
|
|
76
|
+
/**
|
|
77
|
+
* The chain after applying a preset.
|
|
78
|
+
*
|
|
79
|
+
* Appends by default: stacking Telephone onto an already-cleaned voice is a
|
|
80
|
+
* real thing to want, and replacing silently would throw away work. Re-applying
|
|
81
|
+
* a preset that is already present replaces ITS OWN nodes in place instead of
|
|
82
|
+
* adding a second copy — which is what `fromPreset` is for, and mirrors how the
|
|
83
|
+
* carve replaces its own bands rather than stacking new ones on hand-added
|
|
84
|
+
* effects.
|
|
85
|
+
*/
|
|
86
|
+
export declare function applyAudioFxPreset(chain: HfAudioFxChain, preset: HfAudioFxPreset, options?: {
|
|
87
|
+
replaceChain?: boolean;
|
|
88
|
+
}): HfAudioFxChain;
|
|
89
|
+
/** Every preset whose nodes are still present, for the rack's group braces. */
|
|
90
|
+
export declare function activeAudioFxPresetIds(chain: HfAudioFxChain): string[];
|
|
91
|
+
//# sourceMappingURL=audioFxPresets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audioFxPresets.d.ts","sourceRoot":"","sources":["../src/audioFxPresets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,oBAAoB,EAC1B,MAAM,cAAc,CAAC;AAEtB;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,CAAC;AAE/E,MAAM,WAAW,mBAAmB;IAClC,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oFAAoF;IACpF,MAAM,CAAC,EAAE,oBAAoB,CAAC;CAC/B;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,qBAAqB,CAAC;IAC9B,oFAAoF;IACpF,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,SAAS,mBAAmB,EAAE,CAAC;CACvC;AAwBD,eAAO,MAAM,mBAAmB,EAAE,SAAS,eAAe,EAoRzD,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,SAAS,MAAM,EAAyC,CAAC;AAI9F,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAExE;AAED,kEAAkE;AAClE,eAAO,MAAM,2BAA2B,EAAE,SAAS,qBAAqB,EAKvE,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,qBAAqB,GAAG,eAAe,EAAE,CAEvF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,cAAc,GACpB,aAAa,EAAE,CAiBjB;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,cAAc,EACrB,MAAM,EAAE,eAAe,EACvB,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAO,GACvC,cAAc,CAoBhB;AAED,+EAA+E;AAC/E,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,EAAE,CAMtE"}
|