Skip to content

AudioLab Type System

Location: 2 - FOUNDATION/04_CORE/04_00_type_system/ Type: Header-only INTERFACE library Dependencies: None (foundational module) Target: AudioLab::TypeSystem

Purpose

The Type System module provides fundamental type definitions, SIMD types, buffer abstractions, and type traits for the entire AudioLab framework. It serves as the foundation for type-safe, high-performance audio processing.

Key Features

  • Zero Runtime Overhead: All types are constexpr when possible
  • Header-Only: No linking required, maximum inlining
  • Platform Agnostic: Automatic SIMD detection (AVX2, NEON)
  • Type Safety: Strong typing for samples, parameters, buffers
  • Compile-Time Validation: Extensive use of static_assert

Module Structure

00_type_system/
├── 00_fundamental_types/   # Sample types, channel configs, sample rates
├── 01_simd_types/          # Platform-specific SIMD wrappers
├── 02_buffer_types/        # Audio buffer abstractions
├── 03_parameter_types/     # Parameter value types & ranges
├── 04_conversion_traits/   # Type conversion utilities
└── tests/                  # Unit tests for all types

Available Types

Fundamental Types (00_fundamental_types/)

// Sample types
using Sample = float;           // Primary audio sample type
using SampleD = double;         // High-precision sample
using SampleI = int32_t;        // Integer sample (24-bit DACs)

// Channel configurations
enum class ChannelConfig {
    Mono,
    Stereo,
    Surround_5_1,
    Surround_7_1
};

// Sample rate types
template<uint32_t Rate>
struct SampleRate {
    static constexpr uint32_t value = Rate;
};

using SR_44100 = SampleRate<44100>;
using SR_48000 = SampleRate<48000>;
using SR_96000 = SampleRate<96000>;

SIMD Types (01_simd_types/)

// Platform-agnostic SIMD vector
template<typename T, size_t N>
struct SimdVector {
    // Auto-selects AVX2, NEON, or scalar fallback
};

// Common aliases
using SimdFloat4 = SimdVector<float, 4>;
using SimdFloat8 = SimdVector<float, 8>;  // AVX2 if available

Buffer Types (02_buffer_types/)

// Non-owning buffer view
template<typename SampleT>
class AudioBufferView {
    // Lightweight, passed by value
};

// Multi-channel buffer
template<typename SampleT, size_t Channels>
class AudioBuffer {
    // Aligned allocation for SIMD
};

// Circular buffer for delay lines
template<typename T>
class CircularBuffer {
    // RT-safe, power-of-2 size, fractional delay support
};

Parameter Types (03_parameter_types/)

// Type-safe parameter value
template<typename T, T Min, T Max>
struct RangedParameter {
    static constexpr T min = Min;
    static constexpr T max = Max;
    // Compile-time range validation
};

// Normalized parameter [0.0, 1.0]
struct NormalizedParam {
    float value;
    constexpr explicit NormalizedParam(float v);
};

Conversion Traits (04_conversion_traits/)

// Sample format conversion
template<typename From, typename To>
struct SampleConverter {
    static constexpr To convert(From value) noexcept;
};

// Automatic conversion detection
template<typename T>
inline constexpr bool is_sample_type_v = /* ... */;

Usage Examples

Basic Sample Processing

#include <audiolab/type_system/00_fundamental_types/sample.hpp>

constexpr Sample process(Sample input) {
    return input * 0.5f;  // Simple gain, constexpr-friendly
}

SIMD Processing

#include <audiolab/type_system/01_simd_types/simd_vector.hpp>

void process_block(AudioBufferView<float> buffer) {
    for (size_t i = 0; i < buffer.size(); i += 8) {
        auto vec = SimdFloat8::load(&buffer[i]);
        vec *= 0.5f;
        vec.store(&buffer[i]);
    }
}

Type-Safe Parameters

#include <audiolab/type_system/03_parameter_types/ranged.hpp>

using Gain = RangedParameter<float, 0.0f, 2.0f>;

constexpr Gain my_gain{1.0f};  // Compile-time validated
static_assert(my_gain.value >= Gain::min);

Circular Buffer (Delay Line)

#include <audiolab/type_system/02_buffer_types/circular_buffer.hpp>

using namespace audiolab::core::types;

// Create delay buffer: 500ms @ 48kHz
size_t bufferSize = calculateDelayBufferSize(0.5, 48000.0);  // Returns 32768
CircularBuffer<float> delayLine(bufferSize);

// Simple delay effect
void processDelay(float input, float& output) {
    delayLine.write(input);
    output = delayLine.read(24000);  // 500ms delay
}

// Chorus effect with modulated delay
void processChorus(float input, float& output, float lfoPhase) {
    delayLine.write(input);

    // Modulate delay: 10ms ± 5ms
    float delaySamples = 480.0f + 240.0f * std::sin(lfoPhase);
    output = delayLine.readLinear(delaySamples);  // Linear interpolation
}

// Multi-tap delay (reverb-style)
void processReverb(float input, float& output) {
    delayLine.write(input);

    const size_t taps[] = {1200, 2400, 4800, 9600};  // 25ms, 50ms, 100ms, 200ms
    float tapOutputs[4];
    delayLine.readMultiple(taps, tapOutputs, 4);

    output = (tapOutputs[0] + tapOutputs[1] + tapOutputs[2] + tapOutputs[3]) * 0.25f;
}

Best Practices

1. Use Strong Types

// ❌ Avoid raw primitives
void process(float gain, float pan);

// ✅ Use typed parameters
void process(GainParam gain, PanParam pan);

2. Prefer constexpr

// ✅ Enable compile-time computation
constexpr Sample db_to_linear(float db) {
    return std::pow(10.0f, db / 20.0f);
}

3. Leverage SIMD Types

// ❌ Scalar loop
for (size_t i = 0; i < N; ++i) {
    output[i] = input[i] * gain;
}

// ✅ SIMD batch processing
for (size_t i = 0; i < N; i += SimdFloat8::size) {
    auto vec = SimdFloat8::load(&input[i]);
    (vec * gain).store(&output[i]);
}

4. Use Buffer Views for APIs

// ✅ Non-owning, lightweight
void process(AudioBufferView<Sample> input,
             AudioBufferView<Sample> output);

Platform Support

Platform SIMD Status
x86_64 AVX2 ✅ Full support
x86_64 SSE4 ✅ Fallback
ARM64 NEON ✅ Full support
Generic None ✅ Scalar fallback

Dependencies

Internal: None (foundational module) External: C++17 standard library only

Testing

All types have comprehensive unit tests:

cd build
ctest -R type_system

See Also

Documentation

Detailed documentation for each type category: