5958b077e2
Every sample ran 20 Smoother::next() calls and 4 db_to_gain_fast() - one set per channel for pre-gain, makeup, mix, low slope and low curve - whether or not anything was actually moving. Measured standalone at ~17 ns/sample, so roughly 8% of the chain, paid permanently for the rare case where a knob is in motion. Params here only change on block boundaries (we do not split blocks on events), so a smoother idle at the top of a block stays idle for that block. When every smoother feeding a channel is idle - i.e. nobody is touching anything, which is the overwhelming common case - its per-sample values are constants and lift out of the loop. The moving case keeps the original per-sample path unchanged. Unlike the true-peak early-out this is an always-on saving, not a signal-dependent one. Note this path has no automated coverage: process() needs a host to drive it, so the DSP tests do not reach it. The logic is small and the moving case is byte-for-byte the old code, but automation smoothing is worth an ear in FL before trusting it - move a pre-gain or mix knob and listen for zipper. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LU1NRL7fAaZTtFMTTPn2b1