Real-time

RMS

one-pole
time-domainreal-timesingle-carrierRMS ≈ 0.707×

An envelope detector traces the loudness contour of a waveform — the slow outline riding over the fast carrier inside it. Every graph on this page is drawn by the method's real algorithm, and the sliders at the top drive all of them at once.

The whole method, live

RMS
level 0.731280 samples
Hilbert refRMS
Attack4 samp (0.1 ms)
Release32 samp (0.7 ms)

Score card

Causality
real-time
Signal model
single-carrier
Reads
RMS ≈ 0.707×
Latency
release-dominated
Cost
trivial
Domain
time
Reads (measured on a steady sine)0.89×

Tracking error vs the true envelope, by challenge axis — longer bar is a tighter fit. Computed live across the oracle generators.

Temporal
17%
Robust
26%
Spectral
10%
Boundary
11%

How it works

Measures power, not crests — the loudness detector. Square the signal, smooth the energy with a one-pole low-pass, then take the square root. It's the contour that tracks perceived level rather than transient peaks.

The squaring pre-averages the waveform, so the curve is inherently smooth and slow to react, and it reads ≈0.707·A for a sine of amplitude A. Reach for it when you care about sustained energy or loudness — a loudness meter or a sidechain — rather than the sharp crests a limiter has to catch.

Key terms

Mean-square / power
Squaring every sample gives instantaneous power: . Always positive, it weights loud excursions far more than quiet ones, so the smoothed result follows energy rather than raw amplitude.
RMS
Root-mean-square — average the power, then take its square root. For a sine of amplitude A the RMS level is 0.707·A, the value that tracks perceived loudness.
One-pole low-pass
A single-coefficient smoother: y += k · (x − y). Each output is nudged a fraction k of the way toward the new input — a leaky integrator that melts ripple into a smooth line.

Building the envelope, step by step

Each step adds one idea and shows a graph with only that principle applied — drawn by the real algorithm on the page's own input, working up to the finished curve.

  1. Step 1The carrier

    Start with the raw waveform — a fast carrier whose height swells and fades. The envelope is the slow outline we want, not the fast wiggle inside it.

  2. Step 2Square the signal

    Instead of |x|, square every sample. Squaring is also always positive, but it weights loud excursions more — the wave becomes instantaneous power.

  3. Step 3Smooth, then root

    Average that energy with a one-pole low-pass and take the square root. The result reads ≈0.707·A for a sine of amplitude A — the RMS envelope, smooth and slow to react.

The code

Six readable forms of the exact algorithm that draws the curves above — C, JS and Python ports, an optimized C, a fixed-coefficient version, and a user-controlled one whose parameters match the sliders.

#include <math.h>

/* exp(-1/tau): the one-pole coefficient for a time constant of
   tau samples. Clamped at 1 so a tiny tau can't blow up. */
static double decay_coeff(double tau) {
    return exp(-1.0 / (tau < 1.0 ? 1.0 : tau));
}

/* RMS envelope: square, smooth the energy with a one-pole low-pass
   (faster attack coefficient, slower release), then take the root. */
void rms_envelope(const double *x, double *env, int n,
                  double attack_samples, double release_samples) {
    double ca = decay_coeff(attack_samples);
    double cr = decay_coeff(release_samples);
    double e = 0.0;
    for (int i = 0; i < n; i++) {
        double r = x[i] * x[i];         /* instantaneous power */
        double c = (r > e) ? ca : cr;   /* faster when rising */
        e = c * e + (1.0 - c) * r;
        env[i] = sqrt(e);
    }
}