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:
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¶
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.