DSPark 1.6.1
Header-only audio DSP framework in pure C++20 — zero dependencies
Loading...
Searching...
No Matches
dspark::DenormalGuard Class Reference

RAII scope guard to disable denormalised (subnormal) floating-point numbers. More...

#include <DenormalGuard.h>

Public Member Functions

 DenormalGuard () noexcept
 Constructs the guard, saving the current FP state and enabling FTZ (plus DAZ on x86).
 
 ~DenormalGuard () noexcept
 Destroys the guard, restoring the exact FP state captured at construction.
 
 DenormalGuard (const DenormalGuard &)=delete
 
DenormalGuardoperator= (const DenormalGuard &)=delete
 
 DenormalGuard (DenormalGuard &&)=delete
 
DenormalGuardoperator= (DenormalGuard &&)=delete
 

Static Public Member Functions

static constexpr bool isActive () noexcept
 True when this build has a real flush-to-zero implementation.
 

Detailed Description

RAII scope guard to disable denormalised (subnormal) floating-point numbers.

Denormals cause severe performance penalties (CPU spikes) in recursive DSP calculations (IIR filters, delays, reverbs) when signals decay towards zero. This guard configures the CPU to flush denormal results to zero (FTZ) and, on x86, to also treat denormal inputs as zero (DAZ) for the lifetime of the object, preventing the degradation without audible effect on sound quality.

The floating-point mode is a per-thread CPU register: construct the guard on the thread whose maths it must protect (typically at the top of the audio callback), and give it a name - a discarded temporary is destroyed immediately and protects nothing (the class is marked [[nodiscard]] so compilers flag that mistake). Guards nest safely: each one restores the exact state it captured, so the host's own floating-point configuration survives. Construction and destruction cost a handful of cycles.

Architecture support:

  • x86/x64: FTZ (bit 15) + DAZ (bit 6) of MXCSR via _mm_getcsr/_mm_setcsr. 32-bit GCC/Clang builds need -msse; without it the guard is a no-op.
  • AArch64 (GCC/Clang): FZ (bit 24) of FPCR via mrs/msr inline assembly.
  • AArch64 (MSVC): the same FZ bit via _ReadStatusReg/_WriteStatusReg.
  • 32-bit ARM (GCC/Clang, hardware FP): FZ (bit 24) of FPSCR via vmrs/vmsr.
  • WebAssembly and any other target: safe no-op (Wasm has no FTZ mode).

Use isActive() to ask at compile time whether this build has a real implementation or the no-op.

void processBlock(float* data, int numSamples) noexcept
{
dspark::DenormalGuard guard; // denormals disabled for this scope
for (int i = 0; i < numSamples; ++i)
data[i] = filter_.processSample(data[i]);
} // previous FP state restored here
RAII scope guard to disable denormalised (subnormal) floating-point numbers.

Definition at line 85 of file DenormalGuard.h.

Constructor & Destructor Documentation

◆ DenormalGuard() [1/3]

dspark::DenormalGuard::DenormalGuard ( )
inlinenoexcept

Constructs the guard, saving the current FP state and enabling FTZ (plus DAZ on x86).

Definition at line 91 of file DenormalGuard.h.

◆ ~DenormalGuard()

dspark::DenormalGuard::~DenormalGuard ( )
inlinenoexcept

Destroys the guard, restoring the exact FP state captured at construction.

Definition at line 128 of file DenormalGuard.h.

◆ DenormalGuard() [2/3]

dspark::DenormalGuard::DenormalGuard ( const DenormalGuard )
delete

◆ DenormalGuard() [3/3]

dspark::DenormalGuard::DenormalGuard ( DenormalGuard &&  )
delete

Member Function Documentation

◆ isActive()

static constexpr bool dspark::DenormalGuard::isActive ( )
inlinestaticconstexprnoexcept

True when this build has a real flush-to-zero implementation.

False where the guard compiles as a documented no-op (WebAssembly, soft-float ARM, 32-bit x86 without SSE, unknown architectures). Lets tests and diagnostics assert flushing only where the hardware can do it.

Definition at line 153 of file DenormalGuard.h.

◆ operator=() [1/2]

DenormalGuard & dspark::DenormalGuard::operator= ( const DenormalGuard )
delete

◆ operator=() [2/2]

DenormalGuard & dspark::DenormalGuard::operator= ( DenormalGuard &&  )
delete

The documentation for this class was generated from the following file: