@vessel-dsp/chain 0.1.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/LICENSE.md +21 -0
- package/README.md +230 -0
- package/dist/chain.d.ts +31 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +208 -0
- package/dist/chain.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/ir-resample.d.ts +2 -0
- package/dist/ir-resample.d.ts.map +1 -0
- package/dist/ir-resample.js +41 -0
- package/dist/ir-resample.js.map +1 -0
- package/dist/nam/engine.d.ts +73 -0
- package/dist/nam/engine.d.ts.map +1 -0
- package/dist/nam/engine.js +89 -0
- package/dist/nam/engine.js.map +1 -0
- package/dist/nodes/amp-shaper-node.d.ts +37 -0
- package/dist/nodes/amp-shaper-node.d.ts.map +1 -0
- package/dist/nodes/amp-shaper-node.js +134 -0
- package/dist/nodes/amp-shaper-node.js.map +1 -0
- package/dist/nodes/gain-node.d.ts +19 -0
- package/dist/nodes/gain-node.d.ts.map +1 -0
- package/dist/nodes/gain-node.js +49 -0
- package/dist/nodes/gain-node.js.map +1 -0
- package/dist/nodes/input-profile-node.d.ts +38 -0
- package/dist/nodes/input-profile-node.d.ts.map +1 -0
- package/dist/nodes/input-profile-node.js +245 -0
- package/dist/nodes/input-profile-node.js.map +1 -0
- package/dist/nodes/ir-node.d.ts +56 -0
- package/dist/nodes/ir-node.d.ts.map +1 -0
- package/dist/nodes/ir-node.js +438 -0
- package/dist/nodes/ir-node.js.map +1 -0
- package/dist/nodes/master-node.d.ts +23 -0
- package/dist/nodes/master-node.d.ts.map +1 -0
- package/dist/nodes/master-node.js +93 -0
- package/dist/nodes/master-node.js.map +1 -0
- package/dist/nodes/nam-node.d.ts +81 -0
- package/dist/nodes/nam-node.d.ts.map +1 -0
- package/dist/nodes/nam-node.js +234 -0
- package/dist/nodes/nam-node.js.map +1 -0
- package/dist/nodes/runtime-node.d.ts +66 -0
- package/dist/nodes/runtime-node.d.ts.map +1 -0
- package/dist/nodes/runtime-node.js +247 -0
- package/dist/nodes/runtime-node.js.map +1 -0
- package/dist/supply-profile.d.ts +56 -0
- package/dist/supply-profile.d.ts.map +1 -0
- package/dist/supply-profile.js +139 -0
- package/dist/supply-profile.js.map +1 -0
- package/dist/types.d.ts +66 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +22 -0
- package/dist/types.js.map +1 -0
- package/nam-engine/NOTICE.md +32 -0
- package/nam-engine/nam-engine.js +2 -0
- package/nam-engine/nam-engine.wasm +0 -0
- package/package.json +67 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/** The subset of the Emscripten module this package calls. */
|
|
2
|
+
export type NamEngineModule = {
|
|
3
|
+
/** @returns a 1-based instance id, or 0 on refusal. */
|
|
4
|
+
_nam_createInstance(sampleRate: number, maxFrames: number): number;
|
|
5
|
+
_nam_destroyInstance(id: number): void;
|
|
6
|
+
/** @returns 1 on success, 0 on failure -- then read `_nam_getLastError`. */
|
|
7
|
+
_nam_loadModel(id: number, jsonPtr: number, slimSize: number): number;
|
|
8
|
+
_nam_hasModel(id: number): number;
|
|
9
|
+
/** Pointer to `maxFrames` floats. Write input, call process, read output back. */
|
|
10
|
+
_nam_getBuffer(id: number): number;
|
|
11
|
+
/** In-place over the instance's buffer. Real-time safe: no allocation, no exceptions. */
|
|
12
|
+
_nam_process(id: number, frames: number): void;
|
|
13
|
+
_nam_hasLoudness(id: number): number;
|
|
14
|
+
/** The model's own output level in dB for a nominal signal, from its metadata. */
|
|
15
|
+
_nam_getLoudness(id: number): number;
|
|
16
|
+
/** The rate the model was captured at, or negative when it states none. */
|
|
17
|
+
_nam_getExpectedSampleRate(id: number): number;
|
|
18
|
+
/** True for A2 models -- NAM's newer architecture, which can trade size for cost. */
|
|
19
|
+
_nam_isSlimmable(id: number): number;
|
|
20
|
+
_nam_setSlimmableSize(id: number, slimSize: number): void;
|
|
21
|
+
_nam_getSlimmableBreakpointCount(id: number): number;
|
|
22
|
+
_nam_getSlimmableBreakpoint(id: number, index: number): number;
|
|
23
|
+
_nam_getLastError(): number;
|
|
24
|
+
_malloc(bytes: number): number;
|
|
25
|
+
_free(ptr: number): void;
|
|
26
|
+
lengthBytesUTF8(text: string): number;
|
|
27
|
+
stringToUTF8(text: string, ptr: number, maxBytes: number): void;
|
|
28
|
+
UTF8ToString(ptr: number): string;
|
|
29
|
+
/** Re-read after anything that may grow the heap: growth detaches existing views. */
|
|
30
|
+
HEAPF32: Float32Array;
|
|
31
|
+
};
|
|
32
|
+
type NamEngineFactory = (options: {
|
|
33
|
+
readonly wasmBinary: ArrayBufferLike;
|
|
34
|
+
readonly locateFile?: (path: string) => string;
|
|
35
|
+
}) => Promise<NamEngineModule>;
|
|
36
|
+
/**
|
|
37
|
+
* Instantiate the engine from wasm bytes the caller supplies.
|
|
38
|
+
*
|
|
39
|
+
* **The bytes are passed in rather than fetched, and that is a hard requirement, not a preference.**
|
|
40
|
+
* An `AudioWorkletGlobalScope` has no `fetch`, so the glue's own loader cannot run there. For the
|
|
41
|
+
* same reason `locateFile` is stubbed to the identity: a worklet scope has no `URL` constructor
|
|
42
|
+
* either, and the glue would otherwise build a path it never uses.
|
|
43
|
+
*/
|
|
44
|
+
export declare function instantiateNamEngine(wasmBinary: ArrayBufferLike, factory: NamEngineFactory): Promise<NamEngineModule>;
|
|
45
|
+
/** Drop the memo. Tests only -- a host has no reason to re-instantiate. */
|
|
46
|
+
export declare function resetNamEngineForTests(): void;
|
|
47
|
+
/** The loudness target the engine normalises to internally, in dB. See {@link namLoudness}. */
|
|
48
|
+
export declare const NAM_LOUDNESS_TARGET_DB = -18;
|
|
49
|
+
export type NamLoudness = {
|
|
50
|
+
/** What the model states, or `null` when its metadata carries none. */
|
|
51
|
+
readonly modelLoudnessDb: number | null;
|
|
52
|
+
/**
|
|
53
|
+
* The gain the engine applies inside `nam_process`, as a linear factor.
|
|
54
|
+
*
|
|
55
|
+
* **Reported, never applied by us.** `nam_process` already multiplies by this -- it implements
|
|
56
|
+
* NAM's `Normalized` output mode, `10^((-18 - modelLoudness)/20)`, with smoothing against
|
|
57
|
+
* clicks. Applying it again in the node would double it. This value exists so a host can
|
|
58
|
+
* *show* what the engine did, which is the difference between a level a user can reason about
|
|
59
|
+
* and one that merely happens.
|
|
60
|
+
*/
|
|
61
|
+
readonly appliedGain: number;
|
|
62
|
+
};
|
|
63
|
+
/** What the engine will do to this instance's level, read from the loaded model's metadata. */
|
|
64
|
+
export declare function namLoudness(module: NamEngineModule, instanceId: number): NamLoudness;
|
|
65
|
+
/**
|
|
66
|
+
* Load a `.nam` document into an instance, or throw with the engine's own reason.
|
|
67
|
+
*
|
|
68
|
+
* Not real-time safe: it parses JSON, allocates the network and prewarms it. Call it before the
|
|
69
|
+
* node is in a running chain, which is what building the chain from a preset does.
|
|
70
|
+
*/
|
|
71
|
+
export declare function loadNamModel(module: NamEngineModule, instanceId: number, modelJson: string, slimSize: number): void;
|
|
72
|
+
export {};
|
|
73
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/nam/engine.ts"],"names":[],"mappings":"AAWA,8DAA8D;AAC9D,MAAM,MAAM,eAAe,GAAG;IAC7B,uDAAuD;IACvD,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IACnE,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,4EAA4E;IAC5E,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IACtE,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,kFAAkF;IAClF,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC,yFAAyF;IACzF,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/C,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACrC,kFAAkF;IAClF,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACrC,2EAA2E;IAC3E,0BAA0B,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/C,qFAAqF;IACrF,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACrC,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1D,gCAAgC,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACrD,2BAA2B,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/D,iBAAiB,IAAI,MAAM,CAAC;IAC5B,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtC,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAChE,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,qFAAqF;IACrF,OAAO,EAAE,YAAY,CAAC;CACtB,CAAC;AAEF,KAAK,gBAAgB,GAAG,CAAC,OAAO,EAAE;IACjC,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CAC/C,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;AAY/B;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACzC,UAAU,EAAE,eAAe,EAC3B,OAAO,EAAE,gBAAgB,GACvB,OAAO,CAAC,eAAe,CAAC,CAG1B;AAED,2EAA2E;AAC3E,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAED,+FAA+F;AAC/F,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,MAAM,MAAM,WAAW,GAAG;IACzB,uEAAuE;IACvE,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC;;;;;;;;OAQG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF,+FAA+F;AAC/F,wBAAgB,WAAW,CAC1B,MAAM,EAAE,eAAe,EACvB,UAAU,EAAE,MAAM,GAChB,WAAW,CAWb;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC3B,MAAM,EAAE,eAAe,EACvB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACd,IAAI,CAkCN"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// The typed boundary to `nam-engine/nam-engine.js`, the plain-WASM NAM inference library.
|
|
2
|
+
//
|
|
3
|
+
// Separate from the node for one reason that matters: **instantiating the module is asynchronous,
|
|
4
|
+
// and `NamNode.prepare` is not.** So the async half lives here and is awaited by whoever builds a
|
|
5
|
+
// chain, leaving the node itself synchronous and therefore testable without a promise in the audio
|
|
6
|
+
// path. Everything after instantiation -- creating an instance, loading a model, processing a block
|
|
7
|
+
// -- is a synchronous WASM call.
|
|
8
|
+
//
|
|
9
|
+
// Built and vendored by `scripts/build-nam-engine.sh`; licences in `nam-engine/NOTICE.md`. The
|
|
10
|
+
// exports below are the ones this package uses, not the module's full surface.
|
|
11
|
+
/**
|
|
12
|
+
* One module per scope, many instances inside it.
|
|
13
|
+
*
|
|
14
|
+
* Memoized because instantiation compiles 420 KB of WebAssembly, and because a second
|
|
15
|
+
* instantiation is what upstream abandoned its previous architecture over: doing it again on the
|
|
16
|
+
* audio thread triggered a ~500 MB recompile storm in WebKit that crossed the iOS Jetsam limit and
|
|
17
|
+
* crashed the tab. Multiple NAM nodes share this module and are separated by instance id.
|
|
18
|
+
*/
|
|
19
|
+
let modulePromise = null;
|
|
20
|
+
/**
|
|
21
|
+
* Instantiate the engine from wasm bytes the caller supplies.
|
|
22
|
+
*
|
|
23
|
+
* **The bytes are passed in rather than fetched, and that is a hard requirement, not a preference.**
|
|
24
|
+
* An `AudioWorkletGlobalScope` has no `fetch`, so the glue's own loader cannot run there. For the
|
|
25
|
+
* same reason `locateFile` is stubbed to the identity: a worklet scope has no `URL` constructor
|
|
26
|
+
* either, and the glue would otherwise build a path it never uses.
|
|
27
|
+
*/
|
|
28
|
+
export async function instantiateNamEngine(wasmBinary, factory) {
|
|
29
|
+
modulePromise ??= factory({ wasmBinary, locateFile: (path) => path });
|
|
30
|
+
return modulePromise;
|
|
31
|
+
}
|
|
32
|
+
/** Drop the memo. Tests only -- a host has no reason to re-instantiate. */
|
|
33
|
+
export function resetNamEngineForTests() {
|
|
34
|
+
modulePromise = null;
|
|
35
|
+
}
|
|
36
|
+
/** The loudness target the engine normalises to internally, in dB. See {@link namLoudness}. */
|
|
37
|
+
export const NAM_LOUDNESS_TARGET_DB = -18;
|
|
38
|
+
/** What the engine will do to this instance's level, read from the loaded model's metadata. */
|
|
39
|
+
export function namLoudness(module, instanceId) {
|
|
40
|
+
if (module._nam_hasLoudness(instanceId) !== 1) {
|
|
41
|
+
// NAM's `Raw` mode: no metadata, so no normalisation. The engine returns 1.0 here for the
|
|
42
|
+
// same reason, and the node must not invent a figure of its own.
|
|
43
|
+
return { modelLoudnessDb: null, appliedGain: 1 };
|
|
44
|
+
}
|
|
45
|
+
const modelLoudnessDb = module._nam_getLoudness(instanceId);
|
|
46
|
+
return {
|
|
47
|
+
modelLoudnessDb,
|
|
48
|
+
appliedGain: 10 ** ((NAM_LOUDNESS_TARGET_DB - modelLoudnessDb) / 20),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Load a `.nam` document into an instance, or throw with the engine's own reason.
|
|
53
|
+
*
|
|
54
|
+
* Not real-time safe: it parses JSON, allocates the network and prewarms it. Call it before the
|
|
55
|
+
* node is in a running chain, which is what building the chain from a preset does.
|
|
56
|
+
*/
|
|
57
|
+
export function loadNamModel(module, instanceId, modelJson, slimSize) {
|
|
58
|
+
const byteLength = module.lengthBytesUTF8(modelJson) + 1;
|
|
59
|
+
const pointer = module._malloc(byteLength);
|
|
60
|
+
// **The return of `_malloc` is validated, and this is the guard a "memory access out of
|
|
61
|
+
// bounds" crash was missing.** The engine is built with a hard 512 MiB ceiling
|
|
62
|
+
// (`scripts/build-nam-engine.sh`: `ALLOW_MEMORY_GROWTH=1`, `INITIAL_MEMORY=64MB`,
|
|
63
|
+
// `MAXIMUM_MEMORY=512MB`), and when the heap cannot grow any further emmalloc gives up and
|
|
64
|
+
// returns 0 instead of throwing. Writing the model JSON at offset 0 would then clobber
|
|
65
|
+
// Emscripten's static globals (`DYNAMICTOP_PTR`, `__heap_base`, the ctor tables), and the
|
|
66
|
+
// engine's next internal allocation would address memory past the heap's end and trap inside
|
|
67
|
+
// `_nam_loadModel` with `RuntimeError: memory access out of bounds` -- far from the point of
|
|
68
|
+
// failure, where nothing could name it. A healthy allocation always satisfies both checks by
|
|
69
|
+
// construction: a region emmalloc returns always fits in the current memory, so this can only
|
|
70
|
+
// trip on a failed or corrupt allocation, never on a legitimate one.
|
|
71
|
+
const heapBytes = module.HEAPF32.buffer.byteLength;
|
|
72
|
+
if (pointer <= 0 || pointer + byteLength > heapBytes) {
|
|
73
|
+
throw new Error(`nam-engine heap allocation failed: _malloc(${byteLength}) returned ${pointer}, ` +
|
|
74
|
+
`heap holds ${heapBytes} bytes (the engine's ceiling is 512 MiB)`);
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
module.stringToUTF8(modelJson, pointer, byteLength);
|
|
78
|
+
if (module._nam_loadModel(instanceId, pointer, slimSize) !== 1) {
|
|
79
|
+
const reason = module.UTF8ToString(module._nam_getLastError());
|
|
80
|
+
throw new Error(`nam_loadModel refused the model${reason === "" ? "" : `: ${reason}`}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
// Freed on the throwing path too: a refused model must not leak the JSON it was refused
|
|
85
|
+
// for, and a chain that reports one bad node is expected to keep running.
|
|
86
|
+
module._free(pointer);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/nam/engine.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,EAAE;AACF,kGAAkG;AAClG,kGAAkG;AAClG,mGAAmG;AACnG,oGAAoG;AACpG,iCAAiC;AACjC,EAAE;AACF,+FAA+F;AAC/F,+EAA+E;AAuC/E;;;;;;;GAOG;AACH,IAAI,aAAa,GAAoC,IAAI,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACzC,UAA2B,EAC3B,OAAyB;IAEzB,aAAa,KAAK,OAAO,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;IACtE,OAAO,aAAa,CAAC;AACtB,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,sBAAsB;IACrC,aAAa,GAAG,IAAI,CAAC;AACtB,CAAC;AAED,+FAA+F;AAC/F,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,EAAE,CAAC;AAiB1C,+FAA+F;AAC/F,MAAM,UAAU,WAAW,CAC1B,MAAuB,EACvB,UAAkB;IAElB,IAAI,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/C,0FAA0F;QAC1F,iEAAiE;QACjE,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;IAClD,CAAC;IACD,MAAM,eAAe,GAAG,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAC5D,OAAO;QACN,eAAe;QACf,WAAW,EAAE,EAAE,IAAI,CAAC,CAAC,sBAAsB,GAAG,eAAe,CAAC,GAAG,EAAE,CAAC;KACpE,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAC3B,MAAuB,EACvB,UAAkB,EAClB,SAAiB,EACjB,QAAgB;IAEhB,MAAM,UAAU,GAAG,MAAM,CAAC,eAAe,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IACzD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3C,wFAAwF;IACxF,+EAA+E;IAC/E,kFAAkF;IAClF,2FAA2F;IAC3F,uFAAuF;IACvF,0FAA0F;IAC1F,6FAA6F;IAC7F,6FAA6F;IAC7F,6FAA6F;IAC7F,8FAA8F;IAC9F,qEAAqE;IACrE,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC;IACnD,IAAI,OAAO,IAAI,CAAC,IAAI,OAAO,GAAG,UAAU,GAAG,SAAS,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CACd,8CAA8C,UAAU,cAAc,OAAO,IAAI;YAChF,cAAc,SAAS,0CAA0C,CAClE,CAAC;IACH,CAAC;IACD,IAAI,CAAC;QACJ,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QACpD,IAAI,MAAM,CAAC,cAAc,CAAC,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAChE,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC;YAC/D,MAAM,IAAI,KAAK,CACd,kCAAkC,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,EAAE,CACtE,CAAC;QACH,CAAC;IACF,CAAC;YAAS,CAAC;QACV,wFAAwF;QACxF,0EAA0E;QAC1E,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACvB,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ChainNode } from "../types.js";
|
|
2
|
+
export interface AmpShaperConfig {
|
|
3
|
+
id?: string;
|
|
4
|
+
name?: string;
|
|
5
|
+
gain?: number;
|
|
6
|
+
bass?: number;
|
|
7
|
+
middle?: number;
|
|
8
|
+
treble?: number;
|
|
9
|
+
presence?: number;
|
|
10
|
+
master?: number;
|
|
11
|
+
bias?: number;
|
|
12
|
+
}
|
|
13
|
+
export declare class AmpShaperNode implements ChainNode {
|
|
14
|
+
readonly id: string;
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly kind = "amp-shaper";
|
|
17
|
+
bypassed: boolean;
|
|
18
|
+
mix: number;
|
|
19
|
+
private gain;
|
|
20
|
+
private bass;
|
|
21
|
+
private middle;
|
|
22
|
+
private treble;
|
|
23
|
+
private presence;
|
|
24
|
+
private master;
|
|
25
|
+
private bias;
|
|
26
|
+
private sampleRate;
|
|
27
|
+
private lpState;
|
|
28
|
+
private hpState;
|
|
29
|
+
constructor(id?: string, name?: string, config?: AmpShaperConfig);
|
|
30
|
+
prepare(sampleRate: number): void;
|
|
31
|
+
reset(): void;
|
|
32
|
+
getParam(id: string): number | undefined;
|
|
33
|
+
setParam(id: string, value: number): void;
|
|
34
|
+
getParams(): Record<string, number>;
|
|
35
|
+
process(input: Float64Array | Float32Array): Float64Array;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=amp-shaper-node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amp-shaper-node.d.ts","sourceRoot":"","sources":["../../src/nodes/amp-shaper-node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,WAAW,eAAe;IAC/B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,aAAc,YAAW,SAAS;IAC9C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,gBAAgB;IAC7B,QAAQ,UAAS;IACjB,GAAG,SAAO;IAEV,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,MAAM,CAAO;IACrB,OAAO,CAAC,MAAM,CAAO;IACrB,OAAO,CAAC,QAAQ,CAAO;IACvB,OAAO,CAAC,MAAM,CAAO;IACrB,OAAO,CAAC,IAAI,CAAO;IAEnB,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,OAAO,CAAK;gBAGnB,EAAE,SAAe,EACjB,IAAI,SAAe,EACnB,MAAM,CAAC,EAAE,eAAe;IAezB,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAKjC,KAAK,IAAI,IAAI;IAKb,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAqBxC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IA0BzC,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAYnC,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,YAAY,GAAG,YAAY;CA2CzD"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
export class AmpShaperNode {
|
|
2
|
+
id;
|
|
3
|
+
name;
|
|
4
|
+
kind = "amp-shaper";
|
|
5
|
+
bypassed = false;
|
|
6
|
+
mix = 1.0;
|
|
7
|
+
gain = 1.5;
|
|
8
|
+
bass = 0.5;
|
|
9
|
+
middle = 0.5;
|
|
10
|
+
treble = 0.5;
|
|
11
|
+
presence = 0.5;
|
|
12
|
+
master = 1.0;
|
|
13
|
+
bias = 0.1;
|
|
14
|
+
sampleRate = 48000;
|
|
15
|
+
lpState = 0;
|
|
16
|
+
hpState = 0;
|
|
17
|
+
constructor(id = "amp-shaper", name = "Amp Shaper", config) {
|
|
18
|
+
this.id = id;
|
|
19
|
+
this.name = name;
|
|
20
|
+
if (config) {
|
|
21
|
+
if (config.gain !== undefined)
|
|
22
|
+
this.gain = config.gain;
|
|
23
|
+
if (config.bass !== undefined)
|
|
24
|
+
this.bass = config.bass;
|
|
25
|
+
if (config.middle !== undefined)
|
|
26
|
+
this.middle = config.middle;
|
|
27
|
+
if (config.treble !== undefined)
|
|
28
|
+
this.treble = config.treble;
|
|
29
|
+
if (config.presence !== undefined)
|
|
30
|
+
this.presence = config.presence;
|
|
31
|
+
if (config.master !== undefined)
|
|
32
|
+
this.master = config.master;
|
|
33
|
+
if (config.bias !== undefined)
|
|
34
|
+
this.bias = config.bias;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
prepare(sampleRate) {
|
|
38
|
+
this.sampleRate = sampleRate;
|
|
39
|
+
this.reset();
|
|
40
|
+
}
|
|
41
|
+
reset() {
|
|
42
|
+
this.lpState = 0;
|
|
43
|
+
this.hpState = 0;
|
|
44
|
+
}
|
|
45
|
+
getParam(id) {
|
|
46
|
+
switch (id) {
|
|
47
|
+
case "gain":
|
|
48
|
+
return this.gain;
|
|
49
|
+
case "bass":
|
|
50
|
+
return this.bass;
|
|
51
|
+
case "middle":
|
|
52
|
+
return this.middle;
|
|
53
|
+
case "treble":
|
|
54
|
+
return this.treble;
|
|
55
|
+
case "presence":
|
|
56
|
+
return this.presence;
|
|
57
|
+
case "master":
|
|
58
|
+
return this.master;
|
|
59
|
+
case "bias":
|
|
60
|
+
return this.bias;
|
|
61
|
+
default:
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
setParam(id, value) {
|
|
66
|
+
switch (id) {
|
|
67
|
+
case "gain":
|
|
68
|
+
this.gain = Math.max(0.1, Math.min(10, value));
|
|
69
|
+
break;
|
|
70
|
+
case "bass":
|
|
71
|
+
this.bass = Math.max(0, Math.min(1, value));
|
|
72
|
+
break;
|
|
73
|
+
case "middle":
|
|
74
|
+
this.middle = Math.max(0, Math.min(1, value));
|
|
75
|
+
break;
|
|
76
|
+
case "treble":
|
|
77
|
+
this.treble = Math.max(0, Math.min(1, value));
|
|
78
|
+
break;
|
|
79
|
+
case "presence":
|
|
80
|
+
this.presence = Math.max(0, Math.min(1, value));
|
|
81
|
+
break;
|
|
82
|
+
case "master":
|
|
83
|
+
this.master = Math.max(0, Math.min(3, value));
|
|
84
|
+
break;
|
|
85
|
+
case "bias":
|
|
86
|
+
this.bias = Math.max(-1, Math.min(1, value));
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
getParams() {
|
|
91
|
+
return {
|
|
92
|
+
gain: this.gain,
|
|
93
|
+
bass: this.bass,
|
|
94
|
+
middle: this.middle,
|
|
95
|
+
treble: this.treble,
|
|
96
|
+
presence: this.presence,
|
|
97
|
+
master: this.master,
|
|
98
|
+
bias: this.bias,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
process(input) {
|
|
102
|
+
const length = input.length;
|
|
103
|
+
const output = new Float64Array(length);
|
|
104
|
+
if (this.bypassed) {
|
|
105
|
+
for (let i = 0; i < length; i++) {
|
|
106
|
+
output[i] = input[i] ?? 0;
|
|
107
|
+
}
|
|
108
|
+
return output;
|
|
109
|
+
}
|
|
110
|
+
const dt = 1.0 / this.sampleRate;
|
|
111
|
+
const rcHp = 1.0 / (2 * Math.PI * (80 + 120 * this.bass));
|
|
112
|
+
const alphaHp = dt / (rcHp + dt);
|
|
113
|
+
const rcLp = 1.0 / (2 * Math.PI * (2500 + 4000 * this.treble));
|
|
114
|
+
const alphaLp = dt / (rcLp + dt);
|
|
115
|
+
const midGain = 0.5 + this.middle;
|
|
116
|
+
const presenceBoost = 1.0 + this.presence * 0.5;
|
|
117
|
+
const wetMix = Math.max(0, Math.min(1, this.mix));
|
|
118
|
+
const dryMix = 1 - wetMix;
|
|
119
|
+
for (let i = 0; i < length; i++) {
|
|
120
|
+
const dry = input[i] ?? 0;
|
|
121
|
+
const x = dry * this.gain;
|
|
122
|
+
const biased = x + this.bias;
|
|
123
|
+
const saturated = Math.tanh(biased) - Math.tanh(this.bias);
|
|
124
|
+
this.hpState += alphaHp * (saturated - this.hpState);
|
|
125
|
+
const postHp = saturated - this.hpState * (1.0 - this.bass);
|
|
126
|
+
this.lpState += alphaLp * (postHp - this.lpState);
|
|
127
|
+
const postLp = this.lpState * this.treble + postHp * (1.0 - this.treble);
|
|
128
|
+
const shaped = postLp * midGain * presenceBoost * this.master;
|
|
129
|
+
output[i] = dryMix * dry + wetMix * shaped;
|
|
130
|
+
}
|
|
131
|
+
return output;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=amp-shaper-node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amp-shaper-node.js","sourceRoot":"","sources":["../../src/nodes/amp-shaper-node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ChainNode } from "../types.js";
|
|
2
|
+
export declare class GainNode implements ChainNode {
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly kind = "gain";
|
|
6
|
+
bypassed: boolean;
|
|
7
|
+
mix: number;
|
|
8
|
+
private gainDb;
|
|
9
|
+
private linearGain;
|
|
10
|
+
constructor(id?: string, name?: string, gainDb?: number);
|
|
11
|
+
prepare(_sampleRate: number): void;
|
|
12
|
+
reset(): void;
|
|
13
|
+
getParam(id: string): number | undefined;
|
|
14
|
+
setParam(id: string, value: number): void;
|
|
15
|
+
getParams(): Record<string, number>;
|
|
16
|
+
process(input: Float64Array | Float32Array): Float64Array;
|
|
17
|
+
private updateGain;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=gain-node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gain-node.d.ts","sourceRoot":"","sources":["../../src/nodes/gain-node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,qBAAa,QAAS,YAAW,SAAS;IACzC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,UAAU;IACvB,QAAQ,UAAS;IACjB,GAAG,SAAO;IAEV,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,UAAU,CAAO;gBAEb,EAAE,SAAS,EAAE,IAAI,SAAe,EAAE,MAAM,SAAI;IAOxD,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAClC,KAAK,IAAI,IAAI;IAEb,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAKxC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAOzC,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAInC,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,YAAY,GAAG,YAAY;IAkBzD,OAAO,CAAC,UAAU;CAGlB"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export class GainNode {
|
|
2
|
+
id;
|
|
3
|
+
name;
|
|
4
|
+
kind = "gain";
|
|
5
|
+
bypassed = false;
|
|
6
|
+
mix = 1.0;
|
|
7
|
+
gainDb = 0;
|
|
8
|
+
linearGain = 1.0;
|
|
9
|
+
constructor(id = "gain", name = "Level Trim", gainDb = 0) {
|
|
10
|
+
this.id = id;
|
|
11
|
+
this.name = name;
|
|
12
|
+
this.gainDb = gainDb;
|
|
13
|
+
this.updateGain();
|
|
14
|
+
}
|
|
15
|
+
prepare(_sampleRate) { }
|
|
16
|
+
reset() { }
|
|
17
|
+
getParam(id) {
|
|
18
|
+
if (id === "gainDb")
|
|
19
|
+
return this.gainDb;
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
setParam(id, value) {
|
|
23
|
+
if (id === "gainDb") {
|
|
24
|
+
this.gainDb = value;
|
|
25
|
+
this.updateGain();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
getParams() {
|
|
29
|
+
return { gainDb: this.gainDb };
|
|
30
|
+
}
|
|
31
|
+
process(input) {
|
|
32
|
+
const length = input.length;
|
|
33
|
+
const output = new Float64Array(length);
|
|
34
|
+
if (this.bypassed) {
|
|
35
|
+
for (let i = 0; i < length; i++) {
|
|
36
|
+
output[i] = input[i] ?? 0;
|
|
37
|
+
}
|
|
38
|
+
return output;
|
|
39
|
+
}
|
|
40
|
+
for (let i = 0; i < length; i++) {
|
|
41
|
+
output[i] = (input[i] ?? 0) * this.linearGain;
|
|
42
|
+
}
|
|
43
|
+
return output;
|
|
44
|
+
}
|
|
45
|
+
updateGain() {
|
|
46
|
+
this.linearGain = 10 ** (this.gainDb / 20);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=gain-node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gain-node.js","sourceRoot":"","sources":["../../src/nodes/gain-node.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,QAAQ;IACX,EAAE,CAAS;IACX,IAAI,CAAS;IACb,IAAI,GAAG,MAAM,CAAC;IACvB,QAAQ,GAAG,KAAK,CAAC;IACjB,GAAG,GAAG,GAAG,CAAC;IAEF,MAAM,GAAG,CAAC,CAAC;IACX,UAAU,GAAG,GAAG,CAAC;IAEzB,YAAY,EAAE,GAAG,MAAM,EAAE,IAAI,GAAG,YAAY,EAAE,MAAM,GAAG,CAAC;QACvD,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,UAAU,EAAE,CAAC;IACnB,CAAC;IAED,OAAO,CAAC,WAAmB,IAAS,CAAC;IACrC,KAAK,KAAU,CAAC;IAEhB,QAAQ,CAAC,EAAU;QAClB,IAAI,EAAE,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC,MAAM,CAAC;QACxC,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,QAAQ,CAAC,EAAU,EAAE,KAAa;QACjC,IAAI,EAAE,KAAK,QAAQ,EAAE,CAAC;YACrB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;YACpB,IAAI,CAAC,UAAU,EAAE,CAAC;QACnB,CAAC;IACF,CAAC;IAED,SAAS;QACR,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;IAChC,CAAC;IAED,OAAO,CAAC,KAAkC;QACzC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC5B,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;QAExC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACjC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAC3B,CAAC;YACD,OAAO,MAAM,CAAC;QACf,CAAC;QAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACjC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;QAC/C,CAAC;QAED,OAAO,MAAM,CAAC;IACf,CAAC;IAEO,UAAU;QACjB,IAAI,CAAC,UAAU,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IAC5C,CAAC;CACD"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ChainNode, InputProfileConfig, PickupType } from "../types.js";
|
|
2
|
+
export declare class InputProfileNode implements ChainNode {
|
|
3
|
+
readonly id = "input-profile";
|
|
4
|
+
readonly name = "Guitar Input Profile";
|
|
5
|
+
readonly kind = "input-profile";
|
|
6
|
+
bypassed: boolean;
|
|
7
|
+
mix: number;
|
|
8
|
+
private config;
|
|
9
|
+
private sampleRate;
|
|
10
|
+
private linearGain;
|
|
11
|
+
private b0;
|
|
12
|
+
private b1;
|
|
13
|
+
private b2;
|
|
14
|
+
private a1;
|
|
15
|
+
private a2;
|
|
16
|
+
private x1;
|
|
17
|
+
private x2;
|
|
18
|
+
private y1;
|
|
19
|
+
private y2;
|
|
20
|
+
constructor(config?: Partial<InputProfileConfig>);
|
|
21
|
+
getConfig(): InputProfileConfig;
|
|
22
|
+
setPickupType(type: PickupType): void;
|
|
23
|
+
setGuitarCableLength(meters: number): void;
|
|
24
|
+
setCableCapacitancePfPerM(pfPerM: number): void;
|
|
25
|
+
private calculateResonantFreqHz;
|
|
26
|
+
private calculateResonantFreqHzFor;
|
|
27
|
+
setImpedance(ohms: number): void;
|
|
28
|
+
setInputGainDb(db: number): void;
|
|
29
|
+
prepare(sampleRate: number): void;
|
|
30
|
+
reset(): void;
|
|
31
|
+
getParam(id: string): number | undefined;
|
|
32
|
+
setParam(id: string, value: number): void;
|
|
33
|
+
getParams(): Record<string, number>;
|
|
34
|
+
process(input: Float64Array | Float32Array): Float64Array;
|
|
35
|
+
private updateGain;
|
|
36
|
+
private updateFilter;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=input-profile-node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-profile-node.d.ts","sourceRoot":"","sources":["../../src/nodes/input-profile-node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAiD7E,qBAAa,gBAAiB,YAAW,SAAS;IACjD,QAAQ,CAAC,EAAE,mBAAmB;IAC9B,QAAQ,CAAC,IAAI,0BAA0B;IACvC,QAAQ,CAAC,IAAI,mBAAmB;IAChC,QAAQ,UAAS;IACjB,GAAG,SAAO;IAEV,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,UAAU,CAAO;IAGzB,OAAO,CAAC,EAAE,CAAK;IACf,OAAO,CAAC,EAAE,CAAK;IACf,OAAO,CAAC,EAAE,CAAK;IACf,OAAO,CAAC,EAAE,CAAK;IACf,OAAO,CAAC,EAAE,CAAK;IACf,OAAO,CAAC,EAAE,CAAK;IACf,OAAO,CAAC,EAAE,CAAK;IACf,OAAO,CAAC,EAAE,CAAK;IACf,OAAO,CAAC,EAAE,CAAK;gBAEH,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC;IAyBhD,SAAS,IAAI,kBAAkB;IAI/B,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;IAUrC,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAM1C,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAM/C,OAAO,CAAC,uBAAuB;IAQ/B,OAAO,CAAC,0BAA0B;IAkBlC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKhC,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAKhC,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAMjC,KAAK,IAAI,IAAI;IAOb,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAmBxC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAyBzC,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAWnC,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,YAAY,GAAG,YAAY;IAgCzD,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,YAAY;CAwCpB"}
|