Skip to content

Audio Test Utilities

Comprehensive testing tools for real-time safety validation and audio quality analysis.

Overview

This module provides automated tools to catch RT-safety violations and measure audio quality during development:

RT Validators

  • AllocationDetector - Catches malloc/new in RT threads
  • TimingValidator - Verifies deadline compliance

Quality Analyzers

  • THDAnalyzer - Measures Total Harmonic Distortion using Goertzel algorithm
  • DynamicAnalyzer - Measures peak, RMS, crest factor, dynamic range, LUFS

Quick Start

Detect Allocations

#include "04_14_02_realtime_validators/allocation_detector.hpp"

using namespace audiolab::test;

void test_rt_safety() {
    AllocationDetector::ScopedDetector detector;

    process_audio();  // Should not allocate

    if (detector.detected()) {
        FAIL("RT violation: " << detector.count() << " allocations!");
    }
}

Validate Timing

#include "04_14_02_realtime_validators/timing_validator.hpp"

void audio_callback() {
    TimingValidator::ScopedTimer timer(10000);  // 10ms deadline

    process_audio();

    // Timer checks deadline on destruction
}

// Check statistics
if (TimingValidator::deadline_miss_count() > 0) {
    std::cerr << "Deadline violated!\n";
}

Measure THD

#include "04_14_03_quality_analyzers/thd_analyzer.hpp"

float sine_wave[1024];
generate_sine(sine_wave, 1024, 1000.0f, 48000.0f);

auto result = THDAnalyzer::analyze(sine_wave, 1024, 1000.0f, 48000.0f);

std::cout << "THD: " << result.thd_percent << "%\n";
std::cout << "THD+N: " << result.thd_plus_noise_db << " dB\n";

assert(result.thd_percent < 1.0);  // < 1% distortion

Analyze Dynamics

#include "04_14_03_quality_analyzers/dynamic_analyzer.hpp"

auto metrics = DynamicAnalyzer::analyze(buffer, 1024, 48000.0f);

std::cout << "Peak: " << metrics.peak_db << " dBFS\n";
std::cout << "RMS: " << metrics.rms_db << " dBFS\n";
std::cout << "Crest factor: " << metrics.crest_factor_db << " dB\n";
std::cout << "LUFS: " << metrics.lufs << " LUFS\n";

Module Structure

04_14_audio_test_utilities/
├── 04_14_02_realtime_validators/
│   ├── allocation_detector.hpp/.cpp  ← Malloc tracking
│   └── timing_validator.hpp/.cpp     ← Deadline checking
├── 04_14_03_quality_analyzers/
│   ├── thd_analyzer.hpp              ← THD measurement
│   └── dynamic_analyzer.hpp          ← Dynamic analysis
└── tests/
    ├── test_rt_validators.cpp
    └── test_quality_analyzers.cpp

RT Validators

AllocationDetector

Tracks heap allocations in real-time threads using thread-local storage.

Features: - Thread-safe tracking - RAII scoped detector - Allocation history - File/line tracking (optional)

Limitations: - Only detects allocations via tracked calls - Requires enabling global new/delete override for full coverage - Doesn't catch stack overflow

Usage:

AllocationDetector::ScopedDetector detector;
process_audio();
assert(!detector.detected());

TimingValidator

Measures execution time and validates against deadlines.

Features: - High-resolution timing (nanoseconds) - Statistics tracking (max, average) - Deadline miss counting - RAII scoped timer

Typical deadlines: - 512 samples @ 48kHz = 10.67ms - 256 samples @ 48kHz = 5.33ms - 128 samples @ 48kHz = 2.67ms

Usage:

TimingValidator::ScopedTimer timer(10000);  // 10ms
process_audio();
// Checks deadline on destruction

std::cout << "Max time: " << TimingValidator::max_execution_time_us() << " us\n";
std::cout << "Misses: " << TimingValidator::deadline_miss_count() << "\n";

Quality Analyzers

THDAnalyzer

Measures Total Harmonic Distortion using the Goertzel algorithm.

Algorithm: Goertzel (efficient single-frequency DFT)

Metrics: - THD (%) - Ratio of harmonics to fundamental - THD+N (dB) - Includes noise floor - Individual harmonic levels (dB) - Fundamental level (dB)

Accuracy: - THD measurement: ~0.01% precision - Goertzel frequency resolution: 1 bin - Best with buffer size >= 1 period

Test Results:

Pure sine (1000 Hz @ 48 kHz):
  THD: 0.38% (excellent)
  Fundamental: -3.00 dB

Distorted sine (10% 3rd harmonic):
  THD: 9.88% (detected correctly)
  3rd harmonic: -23.11 dB (matches -20 dB expected)

Typical Values: - Excellent: < 0.1% - Good: < 1% - Moderate: < 5% - Poor: > 10%

DynamicAnalyzer

Measures dynamic properties of audio signals.

Metrics: - Peak - Maximum absolute value (dBFS) - RMS - Root Mean Square level (dBFS) - Crest Factor - Peak/RMS ratio (dB) - Dynamic Range - Difference between peak and noise floor - LUFS - Loudness Units (simplified, without K-weighting)

Test Results:

Sine wave (0.5 amplitude):
  Peak: -6.02 dBFS
  RMS: -9.03 dBFS
  Crest factor: 3.01 dB (matches theoretical 3 dB)

Crest Factor Reference: - Sine wave: 3 dB - Square wave: 0 dB - Music (compressed): 6-12 dB - Music (dynamic): 12-20 dB

Notes: - LUFS implementation is simplified (no K-weighting filter) - For production loudness measurement, implement ITU-R BS.1770-4 - Dynamic range estimation assumes fixed noise floor

Performance

RT Validators: - AllocationDetector: ~10 ns overhead per allocation - TimingValidator: ~100 ns overhead per scope

Quality Analyzers: - THD (4096 samples, 10 harmonics): ~0.5 ms - Dynamic analysis (4096 samples): ~0.1 ms

Integration

CMake

target_link_libraries(my_tests PRIVATE AudioLab::AudioTestUtilities)

Include

#include "04_14_02_realtime_validators/allocation_detector.hpp"
#include "04_14_02_realtime_validators/timing_validator.hpp"
#include "04_14_03_quality_analyzers/thd_analyzer.hpp"
#include "04_14_03_quality_analyzers/dynamic_analyzer.hpp"

Testing

All utilities tested with comprehensive test suites:

cd build/Release
./test_rt_validators.exe      # RT safety tests
./test_quality_analyzers.exe   # Audio quality tests

Test Coverage: - ✅ Allocation detection - ✅ Timing validation (within/exceeding deadlines) - ✅ Timing statistics - ✅ THD of pure/distorted sine waves - ✅ Dynamic range metrics - ✅ Peak detection - ✅ Goertzel accuracy

Limitations & Future Work

Current Limitations: 1. AllocationDetector requires global new/delete override for full coverage 2. No lock detection (mutex usage tracking) 3. LUFS is simplified (no K-weighting) 4. No frequency response analyzer 5. No aliasing detector

Future Enhancements: - LockDetector with instrumented mutex - Full ITU-R BS.1770-4 loudness measurement - FrequencyResponse analyzer with sweep - AliasingDetector for Nyquist violations - RT violation reporter with stack traces

API Reference

AllocationDetector

static void enable_for_this_thread();
static void disable_for_this_thread();
static bool allocations_detected();
static uint32_t allocation_count();
static std::vector<AllocationInfo> allocation_history();
static void reset();

class ScopedDetector {
    bool detected() const;
    uint32_t count() const;
};

TimingValidator

static bool deadline_met();
static uint64_t execution_time_us();
static uint64_t max_execution_time_us();
static uint64_t avg_execution_time_us();
static uint32_t deadline_miss_count();
static void reset_stats();

class ScopedTimer {
    explicit ScopedTimer(uint64_t deadline_us);
    uint64_t elapsed_us() const;
};

THDAnalyzer

struct THDResult {
    float thd_percent;
    float thd_plus_noise_db;
    float fundamental_db;
    float noise_floor_db;
    std::vector<float> harmonic_levels_db;
};

static THDResult analyze(
    const float* buffer,
    uint32_t num_samples,
    float fundamental_freq_hz,
    float sample_rate,
    uint32_t num_harmonics = 10
);

DynamicAnalyzer

struct DynamicMetrics {
    float peak_db;
    float rms_db;
    float crest_factor_db;
    float dynamic_range_db;
    float lufs;
};

static DynamicMetrics analyze(
    const float* buffer,
    uint32_t num_samples,
    float sample_rate = 48000.0f
);

References

  • Goertzel Algorithm: Efficient single-frequency DFT
  • THD Measurement: IEEE Standard 1057
  • LUFS: ITU-R BS.1770-4 (simplified version here)
  • RT Safety: Real-Time Audio Programming 101

License

Part of AudioLab framework.