Documentation

Chain and presets

Chain v1 is an ordered serial list. Each item uses a unique optional ID, semantic type, enabled flag, channel selector, semantic parameters, and optional asset references. Unknown fields are rejected. EffeTune app presets with pipeline or plugins are a different contract and require the explicit legacy importer.

The importer accepts app presets whose effects form one ordered serial path. It rejects branched or multi-bus routing because flattening it into Chain v1 would change the acoustic result. To migrate such a preset, first move or copy the desired effects into one serial path in the app and export it again, or reproduce the branching in the host around separate Chains.

App presets containing FIR Crossover, 5Band FIR PEQ, Group Delay EQ, Group Delay PEQ, Room EQ, or IR Reverb cannot be imported: the library drives these six effects from a caller-supplied precomputed impulse-response asset instead of the app’s filter-design parameters, so those parameters have no conversion and the importer rejects the node with an EffectError naming the effect. Construct such an effect directly and supply its asset.

Visual editor to code

The example below imports an asset-free stereo app preset and processes a fixed stereo input through the canonical Chain. The import report identifies editor-only metadata that is intentionally discarded; unsupported fields are not silently dropped.

In the desktop app, build a pipeline containing only Volume at -6 dB, choose File > Export Preset…, and save it as listening.effetune_preset in your working directory (the export is named after the preset by default). Alternatively, save the following example under that name:

{
  "name": "DSP docs Volume",
  "pipeline": [
    {
      "name": "Volume",
      "enabled": true,
      "parameters": {
        "vl": -6
      },
      "channel": "A"
    }
  ],
  "timestamp": 1710000000000
}

Run this Python example from the same directory. It checks that the imported preset applies the expected gain to a short stereo signal:

import json
from pathlib import Path

import numpy as np
import effetune as et

exported = json.loads(Path("listening.effetune_preset").read_text("utf-8"))
chain, report = et.Chain.from_legacy_preset(exported)
assert isinstance(report.warnings, tuple)
audio = np.ones((2, 256), dtype=np.float32) * np.float32(0.25)
output = chain(audio, 48_000, seed=0)
expected = audio * np.float32(10 ** (-6 / 20))
assert output.shape == audio.shape
assert np.allclose(output, expected, rtol=1e-5, atol=1e-6)