/**
 * Automation envelopes for audio tracks.
 *
 * A lane is a list of breakpoints over one parameter — track volume, or one
 * knob of one effect in the track's FX chain. Ableton's clip-envelope model:
 * times are clip-local, so an envelope travels with the clip when it moves.
 *
 * Nothing here touches Web Audio. This module owns the format and the
 * interpolation, and the same `sampleAutomationLane` is used to draw the lane
 * in the timeline, to schedule it in preview, and to bake it at render — one
 * curve, three consumers, or the picture and the sound disagree.
 */
import { type HfAudioFxChain } from "./audioFx.js";
export declare const HF_AUDIO_AUTOMATION_ATTR = "data-automation";
/** The same attribute as a `dataset` / `dataAttributes` key. See `HF_AUDIO_FX_DATA_KEY`. */
export declare const HF_AUDIO_AUTOMATION_DATA_KEY: string;
/** Automation files are versioned; a reader must refuse a version it doesn't know. */
export declare const HF_AUDIO_AUTOMATION_VERSION = 1;
/**
 * A pathological document should not be able to hang the scheduler, which
 * expands every segment into scheduled ramps. Well past any hand-drawn
 * envelope; a lane is dense at 100 points.
 */
export declare const MAX_AUTOMATION_POINTS = 512;
export interface HfAutomationPoint {
    /** Seconds from the start of the clip, not the composition. */
    t: number;
    /** Value in the parameter's own unit — dB for a threshold, Hz for a cutoff. */
    v: number;
    /**
     * Curvature of the segment *leaving* this point, -1..1. Absent or 0 is a
     * straight line; positive holds low then rises late, negative rises early.
     */
    curve?: number;
    /**
     * An interior point the segment *leaving* this point passes through, in
     * normalised segment space: `viaX` is progress 0..1 between the two
     * breakpoints, `viaY` is how far the value has travelled by then. Both are
     * needed for either to mean anything; without them the segment falls back to
     * `curve` above, so everything authored before this existed reads unchanged.
     *
     * Two numbers rather than one because `curve` answers only "how hard", and an
     * exponent cannot say "and where". Every upward bend a single exponent can
     * draw has its deepest deviation in the first fifth of the segment, whatever
     * the author aimed at, and an exponent steep enough to reach a point near
     * either end runs past the ±1 the model accepts — so a bend dragged near the
     * right-hand breakpoint bulged on the left and then stopped following the
     * pointer at all. Naming the point the curve goes through makes both the
     * height and the position of the bend the author's to choose, and takes the
     * saturation with it: any interior point is reachable exactly.
     */
    viaX?: number;
    viaY?: number;
}
export interface HfAutomationLane {
    /** `volume`, or `fx.<nodeId>.<paramKey>`. */
    target: string;
    points: HfAutomationPoint[];
}
export interface HfAutomation {
    version: number;
    lanes: HfAutomationLane[];
}
export declare class AudioAutomationError extends Error {
    constructor(message: string);
}
export declare const VOLUME_TARGET = "volume";
export type HfAutomationTarget = {
    kind: "volume";
} | {
    kind: "fx";
    nodeId: string;
    param: string;
} | {
    kind: "preset";
    presetId: string;
};
/** Split a target string. Returns null for anything unrecognised. */
export declare function parseAutomationTarget(target: string): HfAutomationTarget | null;
export declare function fxAutomationTarget(nodeId: string, param: string): string;
/**
 * How much of a preset is applied, 0..1.
 *
 * A preset's nodes share no automatable parameter — and its worklet effects
 * expose no AudioParams at all — so there is nothing to aim a lane at
 * node-by-node. The graph wraps a preset's run in a wet/dry pair instead, and
 * this drives the blend: 0 is the dry signal untouched, 1 is the preset fully
 * applied, and between them it crossfades.
 */
export declare function presetAutomationTarget(presetId: string): string;
/** 0..1 blend, the same shape as a wet/dry mix knob. */
export declare const PRESET_RANGE: AutomationRange;
/**
 * The value range a lane is drawn and clamped against.
 *
 * Volume is linear 0..1, matching `data-volume` and the existing volume
 * envelope machinery — no dB conversion enters the volume path. Everything
 * else is read from the effect registry, so a lane can never offer a value the
 * renderer would reject, and the log-scaled knobs sweep the way a DAW's do.
 */
export interface AutomationRange {
    min: number;
    max: number;
    step: number;
    unit: string;
    label: string;
    scale: "linear" | "log";
    /** Where an empty lane draws its flat line, and what a new point starts at. */
    default: number;
}
export declare const VOLUME_RANGE: AutomationRange;
/**
 * Resolve a lane's target against a chain. Returns null when the target names
 * a node or parameter that is not there — the effect was deleted, or the
 * parameter is an enum, which has no envelope between its values.
 */
export declare function resolveAutomationRange(target: string, chain: HfAudioFxChain | undefined): AutomationRange | null;
/**
 * The via point a segment will actually be drawn with, given one that was asked
 * for — pulled into the steady region, or null when it describes no bend.
 *
 * Exported so an editor can write what the model will honour rather than what the
 * pointer happened to ask for. Without it a lane's attribute claims a shape the
 * renderer quietly declines to draw, and the two only agree once the file makes a
 * round trip.
 */
export declare function steadyViaPoint(viaX: number | undefined, viaY: number | undefined): {
    viaX: number;
    viaY: number;
} | null;
/**
 * Structural normalisation, with no knowledge of the chain: sort and clean the
 * points of every lane and drop lanes that carry none. Range clamping and
 * orphan removal need the chain and happen in `resolveAutomation`.
 */
export declare function normalizeAutomation(automation: HfAutomation): HfAutomation;
/**
 * Bind automation to a chain: clamp each lane into its parameter's declared
 * range and drop lanes whose target no longer exists.
 *
 * Dropping is deliberate. An envelope on a deleted effect has nothing to
 * drive, and keeping it would silently reattach if an unrelated effect later
 * took the same node id.
 */
export declare function resolveAutomation(automation: HfAutomation, chain: HfAudioFxChain | undefined): HfAutomation;
/**
 * Parse an automation attribute.
 *
 * Malformed input throws rather than being skipped, matching the chain reader:
 * a track that quietly loses its envelope renders differently from the project
 * the author saved, which is worse than refusing.
 */
export declare function parseAutomation(json: string): HfAutomation;
/** Serialise for the `data-automation` attribute. */
export declare function serializeAutomation(automation: HfAutomation): string;
/**
 * Shape the 0..1 progress across a segment.
 *
 * `curve` is an exponent in disguise: 0 is linear, and the ends reach a
 * quarter-power and a fourth-power bend, which is about the range a DAW's
 * envelope handle covers before the segment stops reading as a curve.
 */
export declare function applyCurve(x: number, curve: number | undefined): number;
/**
 * The progress a segment leaving `point` has reached at normalised `x`.
 *
 * A via point wins when it is there, since it says strictly more than an
 * exponent can. Everything authored before via points existed carries only
 * `curve` and takes the exponent path unchanged.
 */
export declare function shapeProgress(x: number, point: {
    curve?: number | undefined;
    viaX?: number | undefined;
    viaY?: number | undefined;
}): number;
/**
 * Value of a lane at a clip-local time.
 *
 * Outside the points, the envelope holds — the first value before it starts
 * and the last value after it ends, so a lane never snaps to zero at the edges.
 */
export declare function sampleAutomationLane(lane: HfAutomationLane, t: number, scale?: "linear" | "log"): number;
/** True when the lane is a single value, i.e. worth setting once and not scheduling. */
export declare function isConstantLane(lane: HfAutomationLane): boolean;
/**
 * Sample a lane onto evenly spaced times, for consumers that want a plain
 * curve rather than a breakpoint list: `setValueCurveAtTime`, the render-side
 * volume envelope, and the lane's own drawing code.
 */
export declare function sampleAutomationCurve(lane: HfAutomationLane, from: number, to: number, count: number, scale?: "linear" | "log"): Float32Array;
//# sourceMappingURL=audioAutomation.d.ts.map