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)¶
add_kernel(a, b)→ sumamul_kernel(a, b)→ multiplicaciónfast_sin_kernel(x)→ sine approximationfast_exp_kernel(x)→ exponential approximationlerp_kernel(a, b, t)→ interpolación linealclamp_kernel(x, min, max)→ limitaciónwrap_kernel(x, min, max)→ wrappingfast_tanh_kernel(x)→ tanh approximationcubic_interp_kernel(...)→ interpolación cúbicafma_kernel(a, b, c)→ fused multiply-add
L1_ATOM (10 ejemplos)¶
VA_Oscillator→ oscillator virtual analogSVF_Filter→ state variable filterADSR_Envelope→ envelope generatorLFO→ low frequency oscillatorEnvelopeFollower→ signal level detectorOnePoleFilter→ simple lowpass/highpassAllpassFilter→ phase shiftWavetableOscillator→ wavetable playbackNoiseGenerator→ white/pink noisePitchShifter→ pitch shifting
L2_CELL (10 ejemplos)¶
SynthVoice→ oscillator + filter + envelopeCompressor→ dynamics processorModulationMatrix→ LFO routingEffectChain→ serial FXVoiceAllocator→ polyphony managementFilterBank→ multiple filters in parallelDelayLine→ echo/delayChorus→ modulated delayPhaser→ allpass chainEQ3Band→ 3-band equalizer
L3_ENGINE (10 ejemplos)¶
PolyphonicSynth→ complete synthFDN_Reverb→ reverb algorithmMasteringChain→ EQ + comp + limiterVocalProcessor→ complete vocal chainDrumSynthesizer→ drum machineGranularEngine→ granular synthesisSpectralProcessor→ FFT-based FXSpatializerEngine→ 3D audioModularMatrix→ modular routingHybridEngine→ multiple synthesis types
⚠️ Anti-Patterns Comunes¶
Anti-Pattern 1: Upward Dependency¶
Anti-Pattern 2: Horizontal Dependency en L1¶
Anti-Pattern 3: Circular Dependency¶
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