05_05_07 - Composition Rules¶
📋 Descripción¶
Sistema de reglas de composición y validación de tipos para topologías DSP. Garantiza la corrección semántica, compatibilidad de tipos y cumplimiento de restricciones de rendimiento antes de la generación de código.
🎯 Objetivos¶
- Sistema de tipos: Definir tipos de puerto, dominios de señal y configuraciones de canales
- Validación de compatibilidad: Verificar conexiones entre puertos con tipos diferentes
- Reglas semánticas: Validar patrones DSP específicos (filtros, feedback, osciladores)
- Validación de rendimiento: Estimar y validar presupuestos de CPU/memoria
- Integración: Validar compatibilidad con plataformas target (VST3, AU, Web Audio)
- Auto-corrección: Sugerir y aplicar correcciones automáticas
🏗️ Arquitectura¶
Componentes Principales¶
type_system.hpp/cpp # Sistema de tipos y compatibilidad
├── DataType # Audio/Control/MIDI/Parameter/Trigger
├── SignalDomain # Time/Frequency/Modal
├── ChannelConfig # Mono/Stereo/Variable
├── PortType # Especificación completa de puerto
├── TypeChecker # Verificación de compatibilidad
└── CompatibilityResult # Resultado con errores/warnings/conversiones
composition_validator.hpp/cpp # Validadores semánticos y de rendimiento
├── SemanticValidator # Reglas DSP específicas
├── PerformanceValidator # Estimación de CPU/memoria
├── IntegrationValidator # Validación por plataforma
├── TopologyValidator # Validador comprehensivo
└── ValidationFixer # Generación de correcciones
Flujo de Validación¶
Topology
↓
[Type Checking] → CompatibilityResult
↓
[Constraint Validation] → Structural constraints
↓
[Semantic Validation] → DSP-specific rules
↓
[Performance Validation] → CPU/Memory budgets
↓
[Integration Validation] → Platform requirements
↓
ValidationReport → [Auto-fix] → Corrected Topology
📊 Sistema de Tipos¶
DataType¶
Clasificación de datos de señal:
- Audio: Señal audio-rate (44.1kHz, 48kHz, etc.)
- Control: Señal control-rate (automation, LFO)
- MIDI: Eventos MIDI
- Parameter: Parámetros estáticos
- Trigger: Gates/triggers
- Generic: Tipo polimórfico
SignalDomain¶
Dominio de procesamiento:
- Time: Dominio temporal (samples)
- Frequency: Dominio frecuencial (FFT bins)
- Modal: Síntesis modal
- Any: Agnóstico al dominio
ChannelConfig¶
Configuración de canales:
ChannelConfig::mono() // 1 canal fijo
ChannelConfig::stereo() // 2 canales fijos
ChannelConfig::channels(n) // n canales fijos
ChannelConfig::variable() // Canales variables
PortType¶
Especificación completa:
struct PortType {
DataType data_type;
SignalDomain domain;
ChannelConfig channels;
size_t sample_rate;
size_t buffer_size;
std::string unit; // Hz, dB, etc.
float min_value;
float max_value;
};
🔍 Type Checker¶
Compatibilidad de Tipos¶
// Verificar compatibilidad entre puertos
PortType source_type{
DataType::Audio,
SignalDomain::Time,
ChannelConfig::mono(),
44100, 512
};
PortType target_type{
DataType::Audio,
SignalDomain::Time,
ChannelConfig::stereo(),
44100, 512
};
auto result = TypeChecker::check_compatibility(source_type, target_type);
if (result.is_compatible) {
if (result.requires_conversion) {
std::cout << "Requiere conversión: " << result.conversion_type << "\n";
}
} else {
for (const auto& error : result.errors) {
std::cout << "ERROR: " << error << "\n";
}
}
Conversiones Automáticas¶
El sistema detecta y sugiere conversiones necesarias:
| Conversión | Tipo | Descripción |
|---|---|---|
upsample |
Control → Audio | Interpolación de señal de control |
fft |
Time → Frequency | Transformada FFT |
ifft |
Frequency → Time | Transformada inversa IFFT |
mono_to_multi |
Mono → Stereo | Broadcast de mono a multi-canal |
multi_to_mono |
Stereo → Mono | Mix down a mono |
resample |
44.1kHz → 48kHz | Resampling de frecuencia |
🛡️ Validadores de Restricciones¶
Restricciones Estructurales¶
ConstraintValidator validator;
// Restricciones por defecto:
// - NoDanglingInputs: No entradas desconectadas
// - SourceToSink: Todos los sources llegan a sinks
// - TypeConsistency: Consistencia de tipos
// - MaxNodeCount: Límite de nodos (1000)
// - MaxDepth: Profundidad máxima (100)
auto report = validator.validate(topology);
if (report.has_errors()) {
std::cout << "ERRORS: " << report.error_count() << "\n";
for (const auto& error : report.errors) {
std::cout << " " << error.message << "\n";
}
}
if (report.warning_count() > 0) {
std::cout << "WARNINGS: " << report.warning_count() << "\n";
for (const auto& warning : report.warnings) {
std::cout << " " << warning.message << "\n";
}
}
Restricciones Personalizadas¶
// Crear restricción personalizada
class MaxFanOutConstraint : public CompositionConstraint {
size_t max_fanout_;
public:
explicit MaxFanOutConstraint(size_t max) : max_fanout_(max) {}
ConstraintResult check(const Topology& topology) const override {
ConstraintResult result;
result.level = ConstraintLevel::Warning;
result.satisfied = true;
for (const auto& [node_id, node] : topology.nodes()) {
size_t fanout = 0;
for (const auto& edge : topology.edges()) {
if (edge.source_node == node_id) fanout++;
}
if (fanout > max_fanout_) {
result.satisfied = false;
result.affected_nodes.push_back(node_id);
result.message += "Node '" + node_id + "' has excessive fanout: " +
std::to_string(fanout) + "\n";
}
}
return result;
}
std::string name() const override { return "MaxFanOut"; }
ConstraintLevel level() const override { return ConstraintLevel::Warning; }
};
// Agregar al validador
validator.add_constraint(std::make_unique<MaxFanOutConstraint>(10));
🔬 Validadores Semánticos¶
Feedback con Delay¶
// Valida que todos los ciclos contengan delay (causalidad)
auto result = SemanticValidator::validate_feedback_delay(topology);
if (!result.satisfied) {
std::cout << "ERROR: Feedback loops without delay:\n";
std::cout << result.message;
}
Estabilidad de Filtros¶
// Valida parámetros de filtros (Q, fc vs Nyquist)
auto result = SemanticValidator::validate_filter_stability(topology);
if (!result.satisfied) {
std::cout << "WARNING: Potentially unstable filters:\n";
std::cout << result.message;
}
Rangos de Modulación¶
// Valida que moduladores no excedan rangos razonables
auto result = SemanticValidator::validate_modulation_ranges(topology);
Longitudes de Delay¶
// Valida que delays no excedan límites (10s @ 192kHz)
auto result = SemanticValidator::validate_delay_lengths(topology);
Frecuencias de Osciladores¶
// Valida que frecuencias estén bajo Nyquist
auto result = SemanticValidator::validate_oscillator_frequencies(topology);
⚡ Validación de Rendimiento¶
Estimación de Métricas¶
auto metrics = PerformanceValidator::estimate_performance(topology);
std::cout << "Performance Metrics:\n";
std::cout << " Nodes: " << metrics.total_nodes << "\n";
std::cout << " Operations: " << metrics.total_operations << " ops/sample\n";
std::cout << " Memory: " << metrics.memory_usage / 1024 << " KB\n";
std::cout << " CPU estimate: " << metrics.cpu_estimate * 100 << "%\n";
std::cout << " Max latency: " << metrics.max_latency << " samples\n";
Validación de Presupuesto¶
// Validar contra presupuestos de CPU y memoria
float cpu_budget = 0.5f; // 50% CPU
size_t memory_budget = 1024 * 1024; // 1 MB
auto result = PerformanceValidator::validate_performance_budget(
topology, cpu_budget, memory_budget
);
if (!result.satisfied) {
std::cout << "Performance budget exceeded:\n";
std::cout << result.message;
}
Identificación de Hotspots¶
// Identificar nodos más costosos
auto hotspots = PerformanceValidator::identify_hotspots(topology);
std::cout << "Performance hotspots:\n";
for (const auto& node_id : hotspots) {
std::cout << " - " << node_id << "\n";
}
Sugerencias de Optimización¶
auto suggestions = PerformanceValidator::suggest_optimizations(topology);
std::cout << "Optimization suggestions:\n";
for (const auto& suggestion : suggestions) {
std::cout << " • " << suggestion << "\n";
}
🔌 Validación de Integración¶
VST3¶
auto result = IntegrationValidator::validate_vst3(topology);
// Requiere: exactamente 1 source y 1 sink
Audio Unit¶
auto result = IntegrationValidator::validate_audio_unit(topology);
// Requiere: exactamente 1 source y 1 sink
Web Audio API¶
auto result = IntegrationValidator::validate_web_audio(topology);
// Restricciones: no SIMD (SSE/AVX)
Embedded/Hardware¶
auto result = IntegrationValidator::validate_embedded(topology);
// Límites estrictos: 64KB RAM, 30% CPU
🔧 Validador Comprehensivo¶
Configuración¶
ValidationConfig config;
config.check_types = true;
config.check_semantics = true;
config.check_performance = true;
config.check_integration = true;
config.cpu_budget = 0.5f;
config.memory_budget = 1024 * 1024;
config.target_platform = "vst3";
TopologyValidator validator(config);
Validación Completa¶
auto report = validator.validate(topology);
std::cout << "Validation Report:\n";
std::cout << " Status: " << (report.passed ? "PASSED" : "FAILED") << "\n";
std::cout << " Errors: " << report.error_count() << "\n";
std::cout << " Warnings: " << report.warning_count() << "\n";
if (!report.passed) {
std::cout << "\nErrors:\n";
for (const auto& error : report.errors) {
std::cout << " [ERROR] " << error.message << "\n";
if (!error.affected_nodes.empty()) {
std::cout << " Affected nodes: ";
for (const auto& node : error.affected_nodes) {
std::cout << node << " ";
}
std::cout << "\n";
}
}
}
if (report.warning_count() > 0) {
std::cout << "\nWarnings:\n";
for (const auto& warning : report.warnings) {
std::cout << " [WARNING] " << warning.message << "\n";
}
}
🔨 Auto-Corrección¶
Generar Correcciones¶
auto fixes = ValidationFixer::generate_fixes(topology, report);
std::cout << "Available fixes:\n";
for (const auto& fix : fixes) {
std::cout << " " << (fix.automatic ? "[AUTO]" : "[MANUAL]")
<< " " << fix.description << "\n";
}
Aplicar Correcciones Automáticas¶
// Aplicar solo correcciones automáticas
Topology fixed_topology = ValidationFixer::apply_automatic_fixes(topology, fixes);
// Validar nuevamente
auto new_report = validator.validate(fixed_topology);
if (new_report.passed) {
std::cout << "Topology fixed successfully!\n";
}
Tipos de Correcciones¶
| Corrección | Automática | Descripción |
|---|---|---|
fix_dangling_inputs |
✅ | Conecta entradas a valores por defecto |
fix_type_mismatches |
❌ | Inserta conversores de tipo (requiere decisión) |
fix_feedback_delays |
✅ | Inserta delays z^-1 en ciclos |
📝 Ejemplo Completo¶
#include "type_system.hpp"
#include "composition_validator.hpp"
#include "../05_05_00_graph_representation/topology_builder.hpp"
using namespace audiolab::topology;
using namespace audiolab::topology::composition;
int main() {
// 1. Construir topología
auto topology = TopologyBuilder()
.setName("feedback_delay_example")
.addNode("input", "external_input", NodeType::Source)
.addNode("gain", "multiply_scalar", NodeType::Processing)
.addNode("delay", "delay_line", NodeType::Processing)
.addNode("output", "external_output", NodeType::Sink)
.connect("input", "out", "gain", "in")
.connect("gain", "out", "delay", "in")
.connect("delay", "out", "output", "in")
.connect("delay", "out", "gain", "feedback") // Feedback loop
.setParameter("delay", "delay_samples", 1.0f)
.setParameter("gain", "value", 0.5f)
.build();
// 2. Configurar validador
ValidationConfig config;
config.check_types = true;
config.check_semantics = true;
config.check_performance = true;
config.check_integration = true;
config.cpu_budget = 0.5f;
config.memory_budget = 1024 * 1024;
config.target_platform = "vst3";
TopologyValidator validator(config);
// 3. Validar
auto report = validator.validate(topology);
// 4. Procesar resultados
if (report.passed) {
std::cout << "✅ Topology validation PASSED\n";
// Mostrar métricas
auto metrics = PerformanceValidator::estimate_performance(topology);
std::cout << "\nPerformance:\n";
std::cout << " CPU: " << metrics.cpu_estimate * 100 << "%\n";
std::cout << " Memory: " << metrics.memory_usage / 1024 << " KB\n";
} else {
std::cout << "❌ Topology validation FAILED\n";
// Mostrar errores
for (const auto& error : report.errors) {
std::cout << "\n[ERROR] " << error.message;
}
// Intentar auto-corrección
auto fixes = ValidationFixer::generate_fixes(topology, report);
std::cout << "\nAvailable fixes:\n";
for (const auto& fix : fixes) {
std::cout << " " << (fix.automatic ? "[AUTO]" : "[MANUAL]")
<< " " << fix.description << "\n";
}
// Aplicar correcciones automáticas
Topology fixed = ValidationFixer::apply_automatic_fixes(topology, fixes);
auto new_report = validator.validate(fixed);
if (new_report.passed) {
std::cout << "\n✅ Topology fixed and validated successfully!\n";
topology = fixed;
}
}
// 5. Warnings (incluso si pasó)
if (report.warning_count() > 0) {
std::cout << "\nWarnings:\n";
for (const auto& warning : report.warnings) {
std::cout << " ⚠️ " << warning.message << "\n";
}
}
return report.passed ? 0 : 1;
}
📈 Métricas de Rendimiento¶
Algoritmos¶
| Algoritmo | Complejidad | Descripción |
|---|---|---|
| Type checking | O(E) | E = número de edges |
| Constraint validation | O(V + E) | V = nodos, E = edges |
| Semantic validation | O(V) | Por cada nodo |
| Performance estimation | O(V + E) | Suma de costos |
| BFS/DFS traversal | O(V + E) | Para análisis estructural |
Presupuestos por Defecto¶
| Plataforma | CPU Budget | Memory Budget |
|---|---|---|
| Desktop (VST3/AU) | 50% | 1 MB |
| Web Audio | 30% | 512 KB |
| Embedded | 30% | 64 KB |
| Mobile | 40% | 256 KB |
Costos de Operaciones (ops/sample)¶
| Operación | Costo |
|---|---|
| Add/Multiply | 1 |
| Biquad filter | 10 |
| SVF filter | 15 |
| Sine oscillator | 20 |
| Exp/Log | 30 |
| FFT (512) | 100 |
| Delay | 2 |
🔗 Integración con Otros Subsistemas¶
Con Graph Representation (05_05_00)¶
#include "../05_05_00_graph_representation/topology.hpp"
// Validar topología existente
auto result = validator.validate(topology);
Con Causality Validation (05_05_01)¶
// Semantic validator usa CausalityValidator internamente
auto result = SemanticValidator::validate_feedback_delay(topology);
Con Code Generation (05_05_06)¶
// Pre-validar antes de generar código
if (validator.validate(topology).passed) {
auto code = CodeGenerator::generate(topology, ...);
}
🎯 Casos de Uso¶
1. Validación Pre-Compilación¶
// Validar antes de generar código
auto report = validator.validate(topology);
if (!report.passed) {
std::cerr << "Cannot generate code: validation failed\n";
return;
}
// Proceder con generación
auto code = CodeGenerator::generate(topology, ...);
2. Validación Interactiva (Editor)¶
// Validar en tiempo real durante edición
void on_topology_changed(const Topology& topology) {
auto report = validator.validate(topology);
// Actualizar UI con errores/warnings
ui->clear_errors();
for (const auto& error : report.errors) {
ui->show_error(error.message, error.affected_nodes);
}
}
3. Optimización Guiada¶
// Usar validador para optimización
auto metrics = PerformanceValidator::estimate_performance(topology);
if (metrics.cpu_estimate > 0.5f) {
// Identificar hotspots
auto hotspots = PerformanceValidator::identify_hotspots(topology);
// Aplicar optimizaciones
for (const auto& node_id : hotspots) {
optimize_node(topology, node_id);
}
}
4. Testing de Compatibilidad Multi-Plataforma¶
// Validar para múltiples plataformas
std::vector<std::string> platforms = {"vst3", "au", "web", "embedded"};
for (const auto& platform : platforms) {
config.target_platform = platform;
auto report = validator.validate(topology);
std::cout << "Platform: " << platform << " → "
<< (report.passed ? "✅" : "❌") << "\n";
}
🚀 Estado del Sistema¶
- ✅ Sistema de tipos: DataType, SignalDomain, ChannelConfig, PortType
- ✅ Type checker: Verificación de compatibilidad con conversiones
- ✅ Constraint validator: 5 restricciones estructurales por defecto
- ✅ Semantic validator: 5 validadores DSP específicos
- ✅ Performance validator: Estimación de CPU/memoria, hotspots
- ✅ Integration validator: VST3, AU, Web Audio, Embedded
- ✅ Topology validator: Validación comprehensiva configurable
- ✅ Validation fixer: Generación y aplicación de correcciones
📚 Referencias¶
- Type Systems: Pierce, B. C. "Types and Programming Languages"
- DSP Validation: Smith, J. O. "Physical Audio Signal Processing"
- Performance Budgets: Reiss, J. D. "Audio Effects: Theory, Implementation and Application"
- Plugin Standards: Steinberg VST3 SDK, Apple Core Audio
Subsistema: 05_MODULES → 05_05_TOPOLOGY_DESIGN → 05_05_07_composition_rules Autor: AudioLab Development Team Versión: 1.0.0 Última actualización: 2025-10-10