Skip to content

LEVEL SEMANTICS - Definición Formal de la Jerarquía

🎯 Propósito

Este documento define formalmente la semántica de cada nivel jerárquico en AudioLab DSP. Es la fuente de verdad para clasificar módulos correctamente.


📊 Visión General de la Jerarquía

L0_KERNEL → L1_ATOM → L2_CELL → L3_ENGINE → [L4_PLUGIN]
   ↓          ↓          ↓          ↓
Primitivas  Componentes Procesadores  Sistemas
Stateless   Stateful    Composite    Complete

Regla fundamental: Cada nivel solo puede depender de niveles inferiores (bottom-up composition).


🔹 L0_KERNEL - Primitive Operations

Definición

Operaciones atómicas stateless sin dependencias de otros módulos AudioLab.

Características

Propiedad Valor
Stateful ❌ No (sin estado interno)
Composable ✅ Sí (sin side effects)
Dependencies ❌ No (cero dependencias AudioLab)
Max Dependencies 0
Typical CPU <20 cycles/sample
Examples add, mul, sin, exp, interpolate

Responsabilidades

DEBE: - Implementar una única operación matemática bien definida - Ser determinístico (same input → same output) - Ejecutar en mínimos ciclos de CPU - Proveer funciones composables sin side effects

NO DEBE: - Allocar memoria dinámica - Realizar operaciones I/O - Mantener estado mutable - Depender de otros módulos AudioLab

Ejemplos Concretos

✅ CORRECTO - L0_KERNEL:

// Kernel simple: multiplicación
float mul_kernel(float a, float b) {
    return a * b;
}

// Kernel: interpolación lineal
float lerp_kernel(float a, float b, float t) {
    return a + t * (b - a);
}

// Kernel: fast sine approximation
float fast_sin_kernel(float x) {
    // Polynomial approximation
    return x - (x*x*x)/6.0f + (x*x*x*x*x)/120.0f;
}

❌ INCORRECTO para L0:

// ❌ Mantiene estado (phase accumulator)
class Oscillator {
    float phase_;
    float process();
};

// ❌ Depende de otro módulo
float complex_operation(const SomeModule& dep);

// ❌ Allocación dinámica
std::vector<float> compute_coefficients(int order);

🔹 L1_ATOM - Basic Components

Definición

Componentes básicos stateful que implementan algoritmos DSP fundamentales usando solo kernels L0.

Características

Propiedad Valor
Stateful ✅ Sí (phase, filter state, etc.)
Composable ✅ Sí (diseñados para combinarse)
Dependencies ✅ Solo L0_KERNEL
Max Dependencies ~20 (recomendado)
Typical CPU Varía (depende del algoritmo)
Examples Oscillator, SVF_Filter, ADSR_Envelope, LFO

Responsabilidades

DEBE: - Implementar algoritmo DSP específico (oscillator, filter, envelope) - Gestionar su propio estado interno - Exponer parámetros configurables vía API clara - Proveer métodos de procesamiento eficientes - Usar únicamente kernels L0 para operaciones

NO DEBE: - Depender de otros L1_ATOM (horizontal dependency) - Depender de L2_CELL o L3_ENGINE (upward dependency) - Tener recursos únicos no-copyables (debe ser moveable/copyable)

Ejemplos Concretos

✅ CORRECTO - L1_ATOM:

class VA_Oscillator {
    // Estado interno
    float phase_ = 0.0f;
    float frequency_ = 440.0f;

    // Solo usa L0 kernels
    float process(float sample_rate) {
        phase_ += frequency_ / sample_rate;
        phase_ = wrap_kernel(phase_, 0.0f, 1.0f);  // L0
        return fast_sin_kernel(phase_ * TWO_PI);    // L0
    }

    void set_frequency(float freq) { frequency_ = freq; }
};

class SVF_Filter {
    // Estado del filtro
    float lp_ = 0.0f, bp_ = 0.0f;
    float cutoff_ = 1000.0f, resonance_ = 0.5f;

    float process(float input, float sample_rate) {
        // Solo usa kernels L0: mul, add, clamp
        float f = cutoff_ / sample_rate;
        lp_ = add_kernel(lp_, mul_kernel(f, bp_));
        bp_ = add_kernel(bp_, mul_kernel(f, /* ... */));
        return lp_;
    }
};

❌ INCORRECTO para L1:

// ❌ L1 depende de otro L1
class Filter {
    Oscillator mod_osc_;  // ❌ L1 → L1 forbidden
    float process(float in);
};

// ❌ L1 depende de L2
class SimpleProcessor {
    SynthVoice voice_;  // ❌ L1 → L2 forbidden
};

🔹 L2_CELL - Complex Processors

Definición

Procesadores compuestos que combinan múltiples L1_ATOMs para implementar funciones musicales completas.

Características

Propiedad Valor
Stateful ✅ Sí (estado de múltiples atoms)
Composable ✅ Sí (pueden combinarse sin ciclos)
Dependencies ✅ L0 + L1 + L2 (sin ciclos)
Max Dependencies ~50 (recomendado)
Typical Use Synth voice, compressor, effect chain
Examples SynthVoice, DynamicsProcessor, ModMatrix

Responsabilidades

DEBE: - Orquestar múltiples L1_ATOMs trabajando juntos - Implementar función musical completa (voz de synth, compresor, etc.) - Gestionar routing de señal interno - Optimizar performance de la composición - Proveer API simplificada al exterior

NO DEBE: - Crear ciclos de dependencia con otros L2_CELLs - Depender de L3_ENGINE (upward dependency) - Tener topología dinámica (routing debe ser DAG estático)

Matriz de Dependencias para L2

L2_CELL puede depender de:
✅ L0_KERNEL (múltiples)
✅ L1_ATOM (múltiples)
✅ L2_CELL (otros cells, SIN CICLOS)
❌ L3_ENGINE (forbidden)

Ejemplos Concretos

✅ CORRECTO - L2_CELL:

class SynthVoice {
    // Composición de L1 atoms
    VA_Oscillator osc1_;        // L1
    VA_Oscillator osc2_;        // L1
    SVF_Filter filter_;         // L1
    ADSR_Envelope amp_env_;     // L1
    ADSR_Envelope filter_env_;  // L1

    float process(float sample_rate) {
        float sig1 = osc1_.process(sample_rate);
        float sig2 = osc2_.process(sample_rate);

        // Mix usando L0 kernel
        float mixed = add_kernel(sig1, mul_kernel(sig2, 0.5f));

        // Filter con envelope
        float env_val = filter_env_.process();
        filter_.set_cutoff(1000.0f + env_val * 10000.0f);
        float filtered = filter_.process(mixed, sample_rate);

        // Apply amp envelope
        float amp = amp_env_.process();
        return mul_kernel(filtered, amp);  // L0 kernel
    }
};

class Compressor {
    // L1 components
    EnvelopeFollower detector_;     // L1
    GainComputer gain_computer_;    // L1

    float process(float input, float sample_rate) {
        float level = detector_.process(input, sample_rate);
        float gain = gain_computer_.compute(level);
        return mul_kernel(input, gain);  // L0
    }
};

✅ CORRECTO - L2 usando L2 (sin ciclos):

class EffectChain {
    // L2 cells (no cycle)
    EQCell eq_;           // L2
    CompressorCell comp_; // L2
    ReverbCell reverb_;   // L2

    float process(float input, float sr) {
        float sig = eq_.process(input, sr);
        sig = comp_.process(sig, sr);
        sig = reverb_.process(sig, sr);
        return sig;
    }
};

❌ INCORRECTO para L2:

// ❌ Circular dependency
class CellA {
    CellB b_;  // A → B
};
class CellB {
    CellA a_;  // B → A (CYCLE!)
};

// ❌ L2 depende de L3
class SimpleCell {
    PolySynthEngine engine_;  // ❌ L2 → L3 forbidden
};

🔹 L3_ENGINE - Complete Systems

Definición

Sistemas autónomos completos listos para integración en plugins (L4). Son el output final de 05_MODULES.

Características

Propiedad Valor
Stateful ✅ Sí (estado completo del sistema)
Composable ❌ No (nodos terminales)
Dependencies ✅ L0 + L1 + L2
Max Dependencies ~100 (recomendado)
Production-Ready ✅ Sí (totalmente testeado)
Examples PolySynth, FDN_Reverb, MasteringChain

Responsabilidades

DEBE: - Ser output final de 05_MODULES (va directo a 10_PLUGINS como L4) - Implementar sistema completo, autónomo, production-ready - Incluir polyphony management si aplicable - Integrar preset/state management completo - Estar completamente testeado, optimizado, documentado

NO DEBE: - Depender de otros L3_ENGINE (horizontal isolation) - Depender de L4_PLUGIN (esos están en 10_PLUGINS, fuera de scope)

Matriz de Dependencias para L3

L3_ENGINE puede depender de:
✅ L0_KERNEL (múltiples)
✅ L1_ATOM (múltiples)
✅ L2_CELL (múltiples)
❌ L3_ENGINE (forbidden - horizontal isolation)
❌ L4_PLUGIN (fuera de scope)

Ejemplos Concretos

✅ CORRECTO - L3_ENGINE:

class PolySynthEngine {
    // Voice management
    static constexpr size_t MAX_VOICES = 16;
    std::array<SynthVoice, MAX_VOICES> voices_;  // L2 cells
    VoiceAllocator allocator_;                   // L2

    // Modulation
    ModulationMatrix mod_matrix_;  // L2

    // Effects
    EffectChain master_fx_;  // L2

    // Preset system
    PresetManager presets_;

    void note_on(int note, float velocity) {
        auto* voice = allocator_.allocate(note);
        if (voice) {
            voice->trigger(note, velocity);
        }
    }

    float process(float sample_rate) {
        float mix = 0.0f;

        // Sum all voices
        for (auto& voice : voices_) {
            if (voice.is_active()) {
                mix = add_kernel(mix, voice.process(sample_rate));
            }
        }

        // Master FX
        return master_fx_.process(mix, sample_rate);
    }

    // Preset management
    void load_preset(const std::string& name) {
        presets_.load(name);
        apply_preset_to_voices();
    }
};

class FDN_ReverbEngine {
    // Multiple L2 cells
    std::array<DelayLine, 8> delay_lines_;    // L2
    std::array<AllpassFilter, 16> diffusers_; // L1
    OnePoleFilter damping_;                   // L1

    float process(float input, float sr) {
        // FDN matrix processing
        // ...
    }

    void set_reverb_time(float seconds);
    void set_damping(float freq);
};

❌ INCORRECTO para L3:

// ❌ L3 depende de L3
class MainEngine {
    PolySynthEngine synth1_;  // ❌ L3 → L3 forbidden
    PolySynthEngine synth2_;  // ❌ horizontal dependency
};

🔄 Decision Tree: ¿Qué nivel es mi módulo?

START: ¿Qué es tu módulo?
├─ ¿Tiene estado interno? (phase, buffers, coefficients)
│  │
│  NO → L0_KERNEL
│  │     (add, mul, sin, interpolate)
│  │
│  YES → ¿Es combinación de otros módulos?
│       │
│       NO → L1_ATOM
│       │    (Oscillator, Filter, Envelope, LFO)
│       │
│       YES → ¿Es un sistema completo listo para plugin?
│             │
│             NO → L2_CELL
│             │    (SynthVoice, Compressor, EffectChain)
│             │
│             YES → L3_ENGINE
│                  (PolySynth, Reverb, MasteringChain)

📋 Quick Reference Card

Pregunta L0 L1 L2 L3
¿Tiene estado?
¿Compone otros módulos?
¿Listo para plugin?
Puede usar L0
Puede usar L1
Puede usar L2 ✅*
Puede usar L3

* = sin ciclos


🎓 Clasificación: 20 Ejemplos

L0_KERNEL (10 ejemplos)

  1. add_kernel(a, b) → suma
  2. mul_kernel(a, b) → multiplicación
  3. fast_sin_kernel(x) → sine approximation
  4. fast_exp_kernel(x) → exponential approximation
  5. lerp_kernel(a, b, t) → interpolación lineal
  6. clamp_kernel(x, min, max) → limitación
  7. wrap_kernel(x, min, max) → wrapping
  8. fast_tanh_kernel(x) → tanh approximation
  9. cubic_interp_kernel(...) → interpolación cúbica
  10. fma_kernel(a, b, c) → fused multiply-add

L1_ATOM (10 ejemplos)

  1. VA_Oscillator → oscillator virtual analog
  2. SVF_Filter → state variable filter
  3. ADSR_Envelope → envelope generator
  4. LFO → low frequency oscillator
  5. EnvelopeFollower → signal level detector
  6. OnePoleFilter → simple lowpass/highpass
  7. AllpassFilter → phase shift
  8. WavetableOscillator → wavetable playback
  9. NoiseGenerator → white/pink noise
  10. PitchShifter → pitch shifting

L2_CELL (10 ejemplos)

  1. SynthVoice → oscillator + filter + envelope
  2. Compressor → dynamics processor
  3. ModulationMatrix → LFO routing
  4. EffectChain → serial FX
  5. VoiceAllocator → polyphony management
  6. FilterBank → multiple filters in parallel
  7. DelayLine → echo/delay
  8. Chorus → modulated delay
  9. Phaser → allpass chain
  10. EQ3Band → 3-band equalizer

L3_ENGINE (10 ejemplos)

  1. PolyphonicSynth → complete synth
  2. FDN_Reverb → reverb algorithm
  3. MasteringChain → EQ + comp + limiter
  4. VocalProcessor → complete vocal chain
  5. DrumSynthesizer → drum machine
  6. GranularEngine → granular synthesis
  7. SpectralProcessor → FFT-based FX
  8. SpatializerEngine → 3D audio
  9. ModularMatrix → modular routing
  10. HybridEngine → multiple synthesis types

⚠️ Anti-Patterns Comunes

Anti-Pattern 1: Upward Dependency

// ❌ MAL: L0 depende de L1
float optimized_kernel(const Oscillator& osc); // L0 → L1 FORBIDDEN

Anti-Pattern 2: Horizontal Dependency en L1

// ❌ MAL: L1 depende de L1
class Filter {
    Oscillator mod_;  // L1 → L1 FORBIDDEN
};

Anti-Pattern 3: Circular Dependency

// ❌ MAL: A → B → A
class CellA { CellB b_; };
class CellB { CellA a_; };  // CYCLE!

Anti-Pattern 4: Leaky Abstraction

// ❌ MAL: L3 expone L1 en API pública
class Engine {
public:
    Oscillator& get_osc();  // Leaks internal L1
};

📚 Referencias

  • Dependency Matrix: Ver dependency_matrix.cpp
  • Validation Rules: Ver 05_01_01_composition_rules/
  • Examples: Ver examples/level_usage.cpp

Última actualización: 2025-10-10 Versión: 1.0.0