Blog / Sound Design

Velvet Noise: The Sparse Sequence That Fools Your Ears Into Hearing a Room

Velvet Noise: The Sparse Sequence That Fools Your Ears Into Hearing a Room

A room impulse response at 44,100 Hz is 44,100 coefficients per second of reverb tail. Convolving audio with that in real time requires one multiply-and-add per coefficient per sample: for a 2-second reverb, that's 88,200 multiplications per output sample, millions of operations per second. The early reflections, the discrete echoes in the first 80 to 100 milliseconds, need that resolution. The late tail doesn't. After about 100ms, reverberation becomes diffuse: a blurry cloud of energy that the ear hears as smooth noise. Two researchers at Helsinki University of Technology asked whether you could approximate that late tail with a far cheaper sequence, without the ear noticing. The answer became velvet noise.

What Velvet Noise Is

Matti Karjalainen and Hanna Järveläinen introduced velvet noise in a 2007 paper at the AES 30th International Conference, titled "Reverberation Modeling Using Velvet Noise." They named it for its perceptual texture: softer and smoother than Gaussian white noise, like the surface of velvet fabric.

The construction is simple. A velvet-noise sequence consists entirely of three values: +1, -1, and 0. Every sample is either a unit pulse, a negated unit pulse, or silence. The pulses are distributed randomly, but with a constraint: within each grid segment of Td samples, there is exactly one pulse (or possibly none, but never two adjacent pulses). The average pulse spacing is controlled by a single density parameter.

Given a desired pulse density of ρ pulses per second at sample rate fs, the grid size is:

Td = fs / ρ

The position of the m-th pulse within its segment is:

k(m) = round(m * Td + r1(m) * (Td - 1))

where r1(m) is a uniform random number in (0, 1). The sign is:

s(m) = +1 if r2(m) >= 0.5, else -1

with r2(m) a second independent uniform random number. That's the entire algorithm. No feedback, no state beyond the two random sequences.

In C++:

std::vector<float> generateVelvetNoise(int length, float density, float sampleRate) {
    std::vector<float> vn(length, 0.0f);
    float Td = sampleRate / density;
    std::mt19937 rng(std::random_device{}());
    std::uniform_real_distribution<float> dist(0.0f, 1.0f);

    int m = 0;
    while (true) {
        int k = static_cast<int>(std::round(m * Td + dist(rng) * (Td - 1.0f)));
        if (k >= length) break;
        vn[k] = (dist(rng) >= 0.5f) ? 1.0f : -1.0f;
        m++;
    }
    return vn;
}

Most entries are zero. At a density of 2,000 pulses/second with a 44,100 Hz sample rate, the average spacing is about 22 samples. Roughly 1 in 22 samples is non-zero.

The Perceptual Threshold

Listening tests by Karjalainen and Järveläinen established that velvet noise sounds perceptually smooth, indistinguishable from white noise, when the pulse density reaches approximately 2,000 pulses per second or higher. Below that threshold, the sequence starts sounding grainy: the individual pulses become audible as separate clicks.

The reason is the auditory system's temporal resolution. The cochlea can resolve rapid events down to roughly 1 to 2 milliseconds. At 2,000 pulses per second, pulses arrive on average every 0.5 ms, below the ear's click-fusion threshold. The auditory nervous system integrates the energy from nearby pulses and perceives a smooth spectral texture.

The spectrum of a properly constructed velvet-noise sequence is flat (white) on average, because the signs are randomly distributed and the positions are statistically uniform. The power spectral density matches that of white noise. The sequence just achieves this spectrum with 95% of its values being zero.

Why This Matters for Convolution

Convolving an input signal with a filter kernel is the fundamental operation of impulse-response reverb. For a standard FIR filter:

y(n) = sum over k of [ h(k) * x(n - k) ]

If h contains N non-zero values, you need N multiplications per output sample. For a 2-second velvet-noise sequence at 2,000 pulses/second, h has only 4,000 non-zero values, not 88,200. That's a 95% reduction in multiplications.

Better: because those non-zero values are ±1, the multiplications reduce to sign-flips. A multiply by +1 is a no-op; multiply by -1 is a negation. The entire convolution becomes a sparse sum:

y(n) = sum over non-zero positions k of [ s(k) * x(n - k) ]

This replaces floating-point multiplication with conditional subtraction, a far cheaper CPU operation. For late-reverb synthesis in a plugin, this means you can afford much longer tails without proportional CPU growth.

Late Reverb Synthesis in Practice

The standard approach is to split the impulse response into two regions. The early part (roughly the first 80-100ms) is handled by a standard FDN or early-reflection model, these discrete echoes have specific timing and character that the ear tracks individually. The late tail is replaced by a velvet-noise model.

The late tail model works like this:

  1. Divide the late-reverb region into short overlapping segments (typically 10-50ms each).
  2. For each segment, fit a velvet-noise sequence whose spectral shape matches the segment. The coloration, how much energy the room has at different frequencies, is captured by a short filter applied to the velvet-noise sequence.
  3. Apply an exponential decay envelope to the velvet-noise output to match the room's RT60.
  4. Sum the segments to produce a smooth, dense, continuous late tail.

This is the "Filtered Velvet Noise" approach developed by Vesa Välimäki and colleagues at Aalto University, published in subsequent work extending the original Karjalainen-Järveläinen method. The coloring filter gives the reverb its room character, bright vs. dark, hard vs. soft, while the velvet-noise basis keeps the computation manageable.

Dark Velvet Noise

The flat spectrum of original velvet noise is fine for a bright room, but many acoustic spaces have a reverb tail that's darker than white noise. A later extension, Dark Velvet Noise, achieves a lowpass-shaped spectrum by replacing unit impulses with short pulses of variable width. Wider pulses have more low-frequency energy; modulating the pulse width along the sequence shapes the overall spectrum without requiring an explicit filter in the signal path.

What This Means for Your Reverb Plug-In

When you enable a long reverb tail in an algorithmic reverb, 8 seconds, 12 seconds, and the CPU meter barely moves, velvet noise (or a similar sparse-sequence technique) is often the reason. The perceptual smoothness of the late tail is not an accident of the algorithm; it is engineered by the statistical properties of the sequence.

The diffuse, enveloping quality that characterizes the late tail of a good room, what makes Carnegie Hall sound different from a church, is, in a computational reverb, a sequence of numbers that are mostly zero, distributed just densely enough that your ears can't count them.