Skip to content

HannWindow

Tier: Core (Internal Utility) | No ComponentType | No Parameters

Header-only 1024-entry Hann window lookup table with linear interpolation for efficient grain and STFT windowing.

Overview

The HannWindow class provides a pre-computed lookup table for the Hann window function, one of the most widely used window shapes in audio DSP. Rather than computing the trigonometric function per-sample, components look up window values from this table with linear interpolation, trading 4 KB of memory for the elimination of cos() calls in tight inner loops.

The Hann window has several properties that make it the default choice for both granular synthesis and STFT processing: it tapers smoothly to zero at both endpoints (avoiding discontinuity clicks), it has good sidelobe suppression (-31.5 dB first sidelobe), and overlapping Hann windows at 50% or 75% overlap sum to a constant (satisfying the COLA constraint for perfect reconstruction).

The table stores 1025 entries (1024 + 1 guard point) so that interpolation at the upper boundary does not require bounds checking.

File Locations

Path
Header Sources/FolioDSP/include/FolioDSP/Core/HannWindow.h
Tests (tested indirectly through component tests)

API / Interface

namespace folio::dsp {

class HannWindow {
public:
    static constexpr uint32_t kTableSize = 1024;

    /// Constructor pre-computes 1025 table entries.
    HannWindow();

    /// Look up window value at normalized phase [0, 1] with linear interpolation.
    /// Returns 0.0 at phase=0 and phase=1, returns 1.0 at phase=0.5.
    float lookup(float phase) const;

private:
    std::array<float, kTableSize + 1> table_{};  // +1 guard point
};

}

Algorithm

The Hann Window Function

The Hann window (also called "Hanning" or "raised cosine") is defined as:

\[w(n) = 0.5 \left(1 - \cos\!\left(\frac{2\pi n}{N}\right)\right)\]

where \(n\) is the sample index and \(N\) is the window length. In normalized form with phase \(\phi \in [0, 1]\):

\[w(\phi) = 0.5 \left(1 - \cos(2\pi\phi)\right)\]

Key properties:

  • \(w(0) = 0\) and \(w(1) = 0\) --- zero at endpoints
  • \(w(0.5) = 1.0\) --- unit peak at center
  • Symmetric: \(w(\phi) = w(1 - \phi)\)

Table Construction

During construction, 1025 values are computed:

\[\text{table}[i] = 0.5 \left(1 - \cos\!\left(\frac{2\pi \cdot i}{1024}\right)\right), \quad i \in [0, 1024]\]

The entry at index 1024 is the guard point --- it equals table[0] (both are 0.0) and exists solely so that interpolation between table[1023] and table[1024] does not require a conditional bounds check.

Lookup with Linear Interpolation

Given a normalized phase \(\phi \in [0, 1]\):

\[\text{idx} = \phi \times 1024\]
\[i_0 = \lfloor \text{idx} \rfloor, \quad i_1 = i_0 + 1\]
\[f = \text{idx} - i_0\]
\[w = \text{table}[i_0] + f \cdot (\text{table}[i_1] - \text{table}[i_0])\]

The guard point ensures \(i_1 \leq 1024\) is always valid without a branch. If \(i_0 \geq 1024\), it is clamped to 1023 to handle floating-point edge cases.

COLA Property

When Hann windows are overlapped at the correct hop ratio, they satisfy the Constant Overlap-Add (COLA) constraint:

\[\sum_m w(n - mH) = C \quad \text{(constant for all } n\text{)}\]

For the Hann window:

  • 50% overlap (\(H = N/2\)): Sum of two overlapping windows = 1.0
  • 75% overlap (\(H = N/4\)): Sum of four overlapping windows = 1.5 (normalized to 1.0 by dividing by the overlap factor)

This property is critical for SpectralFreeze's STFT, which uses 75% overlap to achieve artifact-free resynthesis.

Implementation Notes

  • Header-only: No .cpp file. The constructor runs once per instance, pre-computing all 1025 entries.
  • Memory footprint: \(1025 \times 4 = 4100\) bytes per instance.
  • Real-time safe lookups: The lookup() method performs one multiply, one float-to-int conversion, one clamp check, two table reads, and one linear interpolation --- no branches in the common case, no transcendental functions.
  • Construction cost: 1025 calls to std::cos() during initialization. This is a one-time cost at component construction, well before the audio thread starts.
  • Accuracy: Linear interpolation between 1024 table entries introduces a maximum error of approximately \(1.2 \times 10^{-6}\) (relative to the exact Hann function), far below audible thresholds.
  • Shared instances: Each component that uses HannWindow constructs its own instance. Since the table is small (4 KB), the memory cost of duplication is negligible compared to the simplicity of avoiding shared state.

Used By

Component Purpose
GranularEngine Amplitude envelope for each of the 32 grains --- phase sweeps from 0 to 1 over the grain's lifetime
SpectralFreeze STFT analysis and synthesis windowing with 75% overlap (4096-point FFT, 1024-sample hop)
OnsetDetector STFT analysis windowing for spectral flux computation (1024-point FFT, 256-sample hop)