JavaScript API
npm install @effetune/dsp
The package is ESM-only. These signatures follow the shipped index.d.ts and
worklet.d.ts. The generated declarations remain authoritative for individual
effect options; the 90 named class/factory pairs are
not repeated here.
Chain creation and offline processing
createChain(
input: string | ChainDocumentInput | BundleDocument |
readonly (Effect | ChainEffectInput)[],
options?: CreateChainOptions
): Promise<Chain>
class Chain {
readonly preset: ChainDocument
readonly effects: readonly ChainEffect[]
setParam(effectId: string, parameterName: string, value: unknown): this
reset(): this
prewarm(options: PrewarmOptions): Promise<this>
latencySamples(options: {
sampleRate: number
channels?: number
blockSize?: number
}): Promise<number>
stream(options: StreamOptions): Promise<ChainStream>
process(
audio: readonly Float32Array[],
options: ProcessOptions
): Promise<Float32Array[]>
close(): void
}
ProcessOptions requires sampleRate and optionally accepts seed,
blockSize, and onTelemetry. CreateChainOptions accepts
assetResolver plus baseline/SIMD artifact selection and URLs. Offline processing
returns newly owned channels with fresh state. All input channels must have equal
length, and every sample must be finite; non-finite input raises ValidationError
before native state is reached.
latencySamples() takes the same option shape as prewarm() without a seed
(channels defaults to 2 and blockSize to 128) and resolves to the aggregate an
opened stream would report for that rate and layout, without processing audio. Offline
process() output is not latency-compensated, so use this value to align it.
Graph and GraphStream
createGraph(
input: string | GraphDocumentInput,
options?: CreateGraphOptions
): Promise<Graph>
class Graph {
static load(input: string | GraphDocumentInput, options?: CreateGraphOptions): Promise<Graph>
static fromChain(chain: Chain | ChainDocumentInput |
readonly (Effect | ChainEffectInput)[],
options?: CreateGraphOptions): Promise<Graph>
static wetDry(effect: Effect | ChainEffectInput, options?: WetDryGraphOptions): GraphDocument
static sendReturn(effect: Effect | ChainEffectInput, options?: SendReturnGraphOptions): GraphDocument
readonly nodes: readonly GraphNode[]
readonly edges: readonly GraphEdge[]
toJSON(): GraphDocument
toChain(): ChainDocument
serialize(space?: number): string
getNode(id: string): GraphNode | null
getEdge(id: string): GraphEdge | null
incoming(id: string): readonly GraphEdge[]
outgoing(id: string): readonly GraphEdge[]
structuralSnapshot(): GraphStructuralSnapshot
visualizationSnapshot(): GraphVisualizationSnapshot
process(audio: readonly Float32Array[], options: GraphProcessOptions): Promise<Float32Array[]>
latencySamples(options: LatencyOptions): Promise<number>
stream(options: GraphStreamOptions): Promise<GraphStream>
close(): void
}
interface GraphStream {
readonly graph: GraphDocument
readonly latencySamples: number
readonly compileSnapshot: GraphCompileSnapshot
visualizationSnapshot(): GraphVisualizationSnapshot
setParam(nodeId: string, parameterName: string, value: unknown): this
process(audio: readonly Float32Array[]): Promise<Float32Array[]>
reset(): this
close(): void
}
interface GraphStructuralSnapshot {
readonly document: GraphDocument
readonly topologicalOrder: readonly string[]
readonly incoming: Readonly<Record<string, readonly string[]>>
readonly outgoing: Readonly<Record<string, readonly string[]>>
}
interface GraphProcessOptions {
sampleRate: number
seed?: number // 0
blockSize?: number // 128
}
interface GraphStreamOptions extends GraphProcessOptions {
channels?: number // 2
}
interface GraphRecipeOptions {
nodeId?: string // the effect's own id, else "wet" / "return"
inputId?: string // "input"
outputId?: string // "output"
}
interface WetDryGraphOptions extends GraphRecipeOptions {
wet?: number // 1
dry?: number // 1
}
interface SendReturnGraphOptions extends GraphRecipeOptions {
send?: number // 1
returnGain?: number // 1
}
The trailing comments show the defaults. wet, dry, send, and returnGain
become the linear gains on the edges emitted by each recipe. The recipe helpers return a
document rather than a Graph; see Graph v1 for
the canonical node and edge IDs.
When the Graph.load() input is a string it is Graph JSON text, not a file path or
URL. toJSON(), query results, and snapshots are caller-owned copies; treat snapshots
as read-only diagnostics. toChain() accepts only an empty Graph or one serial path
whose edges all use identity controls; it returns a new Chain document. process()
uses fresh state by opening and closing a stream
internally. For a nonempty graph, createGraph() / Graph.load() validate the
document and load the selected DSP artifact; stream() then prepares native instances
and assets and compiles the graph, so either phase can fail. GraphStream.process()
accepts only audio: passing options, including events, raises ValidationError
because scheduled events are not supported. Call setParam() only between awaited
process calls; an update outside the stream-safe allowlist raises ValidationError
with GRAPH_RECONFIGURATION_REQUIRED. An unknown node ID raises
GRAPH_DOCUMENT_REFERENCE and a value the catalog rejects raises
GRAPH_DOCUMENT_PARAMETER, both as ValidationError. reset() restores initial
parameters and state, and close() is idempotent.
Stateful stream
interface ChainStream {
readonly preset: ChainDocument
readonly effects: readonly ChainEffect[]
readonly latencySamples: number
readonly droppedTelemetryFrames: number
subscribe(callback: TelemetryCallback): () => void
unsubscribe(callback: TelemetryCallback): boolean
setParam(effectId: string, parameterName: string, value: unknown): this
reset(): this
process(
audio: readonly Float32Array[],
options?: { events?: readonly ParameterEvent[] }
): Promise<Float32Array[]>
close(): void
}
StreamOptions requires sampleRate and optionally accepts channels,
seed, blockSize, and onTelemetry. Event parameter objects are partial
updates applied in input order. Rejected non-finite blocks do not change stream state.
latencySamples is the live aggregate and is numerically symmetric with Python
Stream.latency_samples. Asset-configuration parameters listed under
Streaming and events require a newly opened
stream and are rejected before processing.
ETA1 and catalog
encodeEta1(options: {
channels: readonly Float32Array[]
sampleRate: number
topology?: "unspecified" | "mono" | "independent" | "trueStereo" | "matrix"
paths?: readonly MatrixPath[]
}): ArrayBuffer
getEffectCatalog(): Readonly<{
version: 1
channels: readonly EffectChannel[]
effects: readonly Readonly<Record<string, unknown>>[]
}>
const EFFECT_CATALOG: ReturnType<typeof getEffectCatalog>
createEffect<T extends EffectType>(
type: T,
...options: T extends RequiredAssetEffectType
? [options: EffectOptionsByType[T]]
: [options?: EffectOptionsByType[T]]
): EffectClassByType[T]
encodeEta1() validates finite, equal-length planar channels and matrix paths.
EFFECT_CATALOG, EFFECT_CLASSES, and all 90 root class/factory pairs cover the
same semantic catalog as Python without private implementation data.
AudioWorklet
EffeTuneNode.create(
context: BaseAudioContext,
input: string | ChainDocumentInput | BundleDocument |
readonly (Effect | ChainEffectInput)[],
options?: EffeTuneNodeOptions
): Promise<EffeTuneNode>
node.subscribe(callback: TelemetryCallback): () => void
node.unsubscribe(callback: TelemetryCallback): boolean
node.setParam(effectId: string, parameterName: string, value: unknown): Promise<void>
node.reset(): Promise<void>
node.close(): void
node.latencySamples: number
node.droppedTelemetryFrames: number
Import EffeTuneNode from @effetune/dsp/worklet. The latencySamples getter
is refreshed by creation and awaited mutations; the wrapper does not accept scheduled
frame events. See
Compatibility for decoded
telemetry frame fields. Asset-configuration parameters listed under
Streaming and events cannot be changed on an
open node.
Other exports and errors
parsePreset(), importLegacyPreset(), and isBundleDocument() handle semantic
documents. The public package entry points are derived from the package export map:
| Import specifier | Use |
|---|---|
@effetune/dsp |
Main ESM API: Chain, effects, ETA1, and catalog helpers |
@effetune/dsp/worklet |
AudioWorklet EffeTuneNode wrapper |
@effetune/dsp/processor |
Side-effect AudioWorklet processor module |
@effetune/dsp/schemas/chain-v1.json |
Chain v1 JSON Schema |
@effetune/dsp/schemas/graph-v1.json |
Graph v1 JSON Schema |
@effetune/dsp/schemas/bundle-v1.json |
Bundle v1 JSON Schema |
@effetune/dsp/catalog |
ESM catalog exports |
@effetune/dsp/catalog.json |
Machine-readable effect catalog JSON |
These synchronous Graph document builders never load the DSP artifact:
| Export | Result |
|---|---|
normalizeGraphDocument() |
Canonical Graph document from document input, with defaults materialized and nodes/edges sorted by ID |
graphDocumentFromChain() |
Serial Graph document built from a Chain document or effect list |
chainDocumentFromGraph() |
Chain document from an empty or serial identity-control Graph |
createWetDryGraphDocument() |
Same wet/dry document as Graph.wetDry() |
createSendReturnGraphDocument() |
Same send/return document as Graph.sendReturn() |
ValidationError covers audio/documents/options,
EffectError unknown effects, AssetError assets, EffeTuneRuntimeError
backend failures, and StateError invalid lifecycle operations.