Skip to content

Quality Standards & Integration Layer

Purpose: The "glue code" that connects INFRA → CORE → DSP → PLUGINS

Overview

This directory contains the critical integration layer that makes all AudioLab components work together. Without this, each layer would be an isolated island.

What this provides: - Shared type system (single source of truth) - Interface contracts (explicit promises between layers) - Composition patterns (how to combine components) - Integration headers (convenient includes) - Declaration standards (coding consistency)

Directory Structure

03_10_00_shared_types/

Foundation types used across ALL layers

Files: - audiolab_types.hpp - Sample, SampleRate, ParameterValue, etc. - buffer_types.hpp - BufferConfig, BufferDescriptor, etc. - processor_types.hpp - ProcessorState, ProcessorType, etc.

Why: ONE source of truth prevents type mismatches

03_10_01_interface_contracts/

Pure virtual interfaces defining layer contracts

Files: - IAudioProcessor.hpp - THE fundamental processor contract - IParameter.hpp - Parameter automation contract - IEventListener.hpp - Event subscription contract

Why: Explicit contracts enable polymorphism and testing

03_10_02_composition_patterns/

How to compose AudioLab components

Files: - dependency_injection.hpp - No globals pattern

Why: Show HOW to use the components together

03_10_03_integration_headers/

Convenient single-header includes

Files: - audiolab.hpp - Master header (everything in one)

Why: Easy to get started (include one header, get everything)

03_10_04_declaration_standards/

Coding standards for consistency

Files: - naming_conventions.md - How to name things - header_organization.md - Include order, structure - forward_declarations.md - When/how to forward declare - api_export_macros.md - DLL export/import

Why: Consistency across entire codebase

Integration Layer Philosophy

1. Contract-First

Interfaces define WHAT, not HOW:

class IAudioProcessor {
    virtual void process(/*...*/) = 0;  // Contract
};

class MyEffect : public IAudioProcessor {
    void process(/*...*/) override {
        // HOW you implement it
    }
};

2. Explicit Dependencies

No globals, no singletons:

class Compressor {
    Compressor(
        IEventDispatcher& events,  // Injected!
        BufferPool& buffers        // Injected!
    );
};

3. Type Safety

Strong typing prevents errors:

void set_sample_rate(SampleRate rate);  // Clear
void set_config(int rate, int size);     // Ambiguous

4. Zero Circular Dependencies

Enforced through interface design:

INFRA (types, interfaces)
CORE (implements interfaces)
DSP (uses core)
PLUGINS (uses everything)

Quick Start Examples

Example 1: Minimal Processor

#include <audiolab/audiolab.hpp>

class SimpleGain : public audiolab::IAudioProcessor {
    void process(
        const audiolab::Sample* const* inputs,
        audiolab::Sample** outputs,
        audiolab::BlockSize num_samples
    ) override {
        for (audiolab::ChannelIndex ch = 0; ch < num_channels_; ++ch) {
            for (audiolab::BlockSize i = 0; i < num_samples; ++i) {
                outputs[ch][i] = inputs[ch][i] * gain_;
            }
        }
    }

    // ... implement other IAudioProcessor methods
};

Example 2: Using Shared Types

audiolab::BufferConfig config{
    .sample_rate = 48000,
    .max_block_size = 512,
    .num_channels = 2
};

if (!config.is_valid()) {
    throw std::invalid_argument("Invalid config");
}

Example 3: Dependency Injection

class MyPlugin {
    MyPlugin(
        audiolab::IEventDispatcher& events,
        audiolab::BufferPool& buffers
    ) : events_(events), buffers_(buffers) {
        // Dependencies explicitly injected
    }

private:
    audiolab::IEventDispatcher& events_;
    audiolab::BufferPool& buffers_;
};

Integration Test

See integration_test_example.cpp for a complete working example.

Compile test:

g++ -std=c++17 -I. -c integration_test_example.cpp

Expected: Clean compile with no errors or warnings

Layer Dependencies

┌─────────────────────────────────────┐
│ PLUGINS                             │
│ (Uses: CORE, DSP, INFRA)            │
└──────────────┬──────────────────────┘
┌──────────────▼──────────────────────┐
│ DSP                                 │
│ (Uses: CORE, INFRA)                 │
└──────────────┬──────────────────────┘
┌──────────────▼──────────────────────┐
│ CORE                                │
│ (Uses: INFRA)                       │
│ (Implements: IAudioProcessor, etc.) │
└──────────────┬──────────────────────┘
┌──────────────▼──────────────────────┐
│ INFRA / Integration Layer           │
│ (Defines: Types, Interfaces)        │
│ (Depends on: Nothing!)              │
└─────────────────────────────────────┘

Key: INFRA has NO dependencies. Everything depends on INFRA.

Build Integration

CMake

# Add include path
target_include_directories(my_plugin PRIVATE
    ${AUDIOLAB_ROOT}/2 - FOUNDATION/03_INFRA/03_10_quality_standards
)

# Now can use:
# #include <audiolab/audiolab.hpp>

Success Criteria

Type System: Single source of truth for all types ✅ Interfaces: Clear contracts between layers ✅ Composition: Patterns for combining components ✅ Integration: Single-header convenience ✅ Standards: Consistent coding conventions ✅ Zero Circular Dependencies: Verified ✅ Compiles: integration_test_example.cpp builds cleanly

Additional Resources


Remember: This is the foundation. Get the integration layer right, and everything else follows.