/**
 * Audio FX chain: the one description of every effect that can be applied to an
 * audio track.
 *
 * Preview and render both run the same Web Audio graph — the studio in a live
 * AudioContext, the engine in an OfflineAudioContext inside the headless
 * browser it already drives. There is only one implementation of each effect,
 * so preview predicting the render is a property of the architecture rather
 * than something to measure and defend.
 *
 * This file holds what both ends need to agree on: the parameter set for each
 * effect with its usable range, and the id of the graph builder that realises
 * it. Parameters are declared in the units a person thinks in (dB, ms, Hz);
 * the graph builders convert where the Web Audio node wants something else.
 */
export declare const HF_AUDIO_FX_ATTR = "data-fx-chain";
/**
 * The same attribute as a `dataset` / `dataAttributes` key — the `data-` prefix
 * is not part of that spelling.
 *
 * Derived rather than restated: the studio writes through
 * `HF_AUDIO_FX_ATTR` and reads through the key, so a hardcoded `"fx-chain"`
 * on the read side is a rename waiting to half-land.
 */
export declare const HF_AUDIO_FX_DATA_KEY: string;
/** Chain files are versioned; a reader must refuse a version it doesn't know. */
export declare const HF_AUDIO_FX_CHAIN_VERSION = 1;
export type HfAudioFxGroup = "filter" | "dynamics" | "nonlinear" | "time";
export interface HfAudioFxNumberParam {
    kind: "number";
    key: string;
    label: string;
    /** Shown after the value in the panel; "" for a bare ratio. */
    unit: string;
    min: number;
    max: number;
    step: number;
    default: number;
    /** Frequency-style controls need a log knob to be usable. */
    scale?: "linear" | "log";
    /**
     * The knob is backed by an AudioParam, so an automation lane can drive it.
     *
     * Not every knob can be: a WaveShaper curve, a convolution impulse and a
     * worklet's `processorOptions` are all set wholesale rather than scheduled.
     * A graph builder must expose an AudioParam for every parameter flagged here
     * — `audioFxGraph.test.ts` builds each effect and checks it.
     */
    automatable?: boolean;
    /** One line explaining what turning this does, shown on the control. */
    hint?: string;
}
export interface HfAudioFxEnumParam {
    kind: "enum";
    key: string;
    label: string;
    options: readonly {
        value: string;
        label: string;
    }[];
    default: string;
    hint?: string;
}
export type HfAudioFxParam = HfAudioFxNumberParam | HfAudioFxEnumParam;
export type HfAudioFxParamValues = Record<string, number | string>;
export interface HfAudioFxDef {
    id: string;
    label: string;
    group: HfAudioFxGroup;
    /** One sentence on what the effect is for, shown when adding it. */
    description: string;
    params: readonly HfAudioFxParam[];
    /**
     * Identifier for the Web Audio graph builder that realises this effect. Kept
     * as a string rather than a function so this module stays free of browser
     * globals and can be imported by the engine and the linter.
     */
    web: string;
}
/**
 * Every effect, in panel order. Ranges are the usable span for each control;
 * a value that survives `normalizeAudioFxParams` is always safe to realise.
 */
export declare const HF_AUDIO_FX: readonly HfAudioFxDef[];
export declare function getAudioFxDef(id: string): HfAudioFxDef | undefined;
export declare const HF_AUDIO_FX_IDS: readonly string[];
/** Every parameter at its declared default, ready to seed a freshly added effect. */
export declare function defaultAudioFxParams(id: string): HfAudioFxParamValues;
/**
 * Clamp and fill a parameter set so it is always renderable: unknown keys are
 * dropped, missing keys take their default, numbers are clamped into their
 * declared range, and an unrecognised enum value falls back to its default.
 * A non-finite number is treated as missing rather than passed through, since
 * NaN reaching an AudioParam silences the node for the rest of the render.
 */
export declare function normalizeAudioFxParams(id: string, values: Readonly<HfAudioFxParamValues> | undefined): HfAudioFxParamValues;
export interface HfAudioFxNode {
    /** Effect id from HF_AUDIO_FX. */
    type: string;
    /**
     * Stable handle for this node within its chain, minted when the node is
     * added. Automation lanes address nodes by id (`fx.<id>.<param>`) so that
     * reordering the chain never re-points a lane at a different effect. Older
     * chains have no ids; they load fine and simply cannot be automated until
     * the panel touches them.
     */
    id?: string;
    /** Set on nodes the carve analysis generated, so re-running replaces them
     *  instead of stacking another set on top of hand-added effects. */
    fromCarve?: boolean;
    /**
     * Id of the preset that wrote this node, for the same reason `fromCarve`
     * exists: re-applying a preset replaces its own nodes rather than adding a
     * second copy, and the rack can brace them together under the preset's name.
     *
     * The id rather than a flag, because a chain can carry more than one preset
     * and each has to be able to find its own.
     */
    fromPreset?: string;
    /**
     * What the rack calls this node, when the effect's own name is not specific
     * enough to be useful.
     *
     * A peaking filter is "Shape One Range" wherever it appears, so a chain that
     * cuts mud at 250 Hz and lifts clarity at 3 kHz shows the same words twice
     * and an author cannot tell the two apart. A preset names each node for the
     * JOB it is doing instead — "Reduce Mud", "Add Clarity" — and the rack reads
     * as a list of things that were done rather than a list of filter types.
     */
    label?: string;
    /**
     * Id of the multi-band EQ that owns this node, when it is one of its bands.
     *
     * Same device as `fromCarve`: the module gathers its own nodes out of the
     * chain and presents them as one control surface, so an EQ needs no new
     * effect type and its bands stay ordinary filters underneath.
     */
    fromEq?: string;
    /**
     * How much of this node's preset is applied, 0..1 — the wet/dry blend the
     * graph wraps its run in.
     *
     * On every node of the run rather than beside the chain, because the chain has
     * nowhere else to put it: `HfAudioFxChain` is a version and a list of nodes,
     * and a preset is defined by which nodes carry its tag. The graph reads it off
     * the first node of each run. Absent means fully applied, which is what every
     * chain written before this means.
     */
    presetAmount?: number;
    /**
     * Set on the gain stage the leveller writes, so re-running replaces it rather
     * than stacking a second one — the same contract `fromCarve` has.
     */
    fromLeveller?: boolean;
    /** Absent means enabled — chain files written before the field existed still load. */
    enabled?: boolean;
    params?: HfAudioFxParamValues;
}
export interface HfAudioFxChain {
    version: number;
    nodes: HfAudioFxNode[];
}
export declare class AudioFxChainError extends Error {
    constructor(message: string);
}
/**
 * Parse a chain file. Unknown effect ids are rejected rather than skipped: a
 * chain that silently loses a node would render differently from the project
 * the author saved, which is worse than refusing to render at all.
 */
export declare function parseAudioFxChain(json: string): HfAudioFxChain;
/** The nodes that should process audio, in order. */
export declare function enabledAudioFxNodes(chain: HfAudioFxChain): HfAudioFxNode[];
/** Serialise a chain for the `data-fx-chain` attribute. */
export declare function serializeAudioFxChain(chain: HfAudioFxChain): string;
/**
 * Next free node id for a chain, as `n1`, `n2`, … — counted rather than random
 * so that adding an effect produces the same document on every machine, which
 * compositions require.
 */
export declare function mintAudioFxNodeId(chain: HfAudioFxChain): string;
//# sourceMappingURL=audioFx.d.ts.map