""" full_integration.py - Integración completa de todas las fases Este módulo conecta todos los nuevos engines con el flujo principal. """ import logging from typing import Dict, Any, List, Optional from pathlib import Path # Imports de todos los nuevos módulos from human_feel import HumanFeelEngine from audio_soundscape import SoundscapeEngine, FXEngine, TonalAnalyzer from audio_arrangement import DJArrangementEngine, TransitionEngine from audio_mastering import MasterChain, LoudnessAnalyzer, QASuite, MasteringPreset from self_ai import AutoPrompter, CritiqueEngine, AutoFixEngine logger = logging.getLogger("FullIntegration") class AbletonMCPFullPipeline: """ Pipeline completo que integra todas las fases: 1. Auto-prompter (Fase 7) 2. Palette selection (Fase 2) 3. Arrangement generation (Fase 5) 4. Human feel (Fase 3) 5. Soundscape/FX (Fase 4) 6. Mastering (Fase 6) 7. QA validation (Fase 6) 8. Critique & Auto-fix (Fase 7) """ def __init__(self, seed: int = 42): self.seed = seed self.human_engine = HumanFeelEngine(seed=seed) self.soundscape_engine = SoundscapeEngine() self.fx_engine = FXEngine() self.tonal_analyzer = TonalAnalyzer() self.arrangement_engine = DJArrangementEngine(seed=seed) self.transition_engine = TransitionEngine() self.master_chain = MasterChain() self.loudness_analyzer = LoudnessAnalyzer() self.qa_suite = QASuite() self.auto_prompter = AutoPrompter() self.critique_engine = CritiqueEngine() self.auto_fix_engine = AutoFixEngine() def generate_from_vibe(self, vibe_text: str, apply_full_pipeline: bool = True) -> Dict[str, Any]: """ Generación completa desde descripción de vibe. Args: vibe_text: Descripción (ej: "dark warehouse techno") apply_full_pipeline: Si aplicar todas las fases Returns: Dict con configuración completa del track """ logger.info(f"Starting generation from vibe: '{vibe_text}'") # Fase 7: Auto-prompter params = self.auto_prompter.generate_from_vibe(vibe_text) logger.info(f"Detected: genre={params['genre']}, bpm={params['bpm']}, key={params['key']}") # Preparar configuración config = { 'vibe_params': params, 'genre': params['genre'], 'bpm': params['bpm'], 'key': params['key'], 'style': params['style'], 'structure_type': params['structure'], 'seed': self.seed, } if apply_full_pipeline: config = self._apply_full_pipeline(config) return config def _apply_full_pipeline(self, config: Dict[str, Any]) -> Dict[str, Any]: """Aplica todas las fases del pipeline.""" # Fase 5: Generar estructura structure = self.arrangement_engine.generate_structure(config.get('structure_type', 'standard')) config['structure'] = [ {'name': s.name, 'kind': s.kind, 'bars': s.bars, 'energy': s.energy} for s in structure ] config['dj_friendly'] = self.arrangement_engine.is_dj_friendly(structure) # Fase 5: Transiciones transitions = self.transition_engine.generate_all_transitions(structure) config['transitions'] = transitions # Fase 4: Soundscape gaps timeline = [{'start': 0, 'end': s.bars * 4, 'kind': s.kind} for s in structure] gaps = self.soundscape_engine.detect_ambience_gaps(timeline) atmos_events = self.soundscape_engine.fill_with_atmos(gaps, config['genre'], config['key']) config['atmos_events'] = atmos_events # Fase 4: FX automáticos fx_events = [] for section in structure: if section.kind == 'drop': riser = self.fx_engine.auto_riser_before_drop(section.bars * 4, 8) snare_roll = self.fx_engine.auto_snare_roll(section.bars * 4, 4) fx_events.extend([riser, snare_roll]) config['fx_events'] = fx_events # Fase 6: Master chain preset = MasteringPreset.get_preset('club' if 'techno' in config['genre'] else 'streaming') self.master_chain.set_limiter_ceiling(preset['ceiling']) config['master_chain'] = self.master_chain.get_ableton_device_chain() # Fase 3: Configurar human feel config['human_feel'] = { 'enabled': True, 'timing_variation_ms': 5.0, 'velocity_variance': 0.05, 'note_skip_prob': 0.02, 'groove_style': 'shuffle', 'section_dynamics': True, } return config def critique_and_fix(self, song_data: Dict[str, Any]) -> Dict[str, Any]: """ Fase 7: Critique loop y auto-fix. Args: song_data: Datos de la canción generada Returns: Resultado con scores y fixes aplicados """ # Critique critique = self.critique_engine.critique_song(song_data) # Auto-fix si hay weaknesses if critique['weaknesses']: fixes = self.auto_fix_engine.auto_fix(critique, song_data) return { 'critique': critique, 'fixes': fixes, 'final_score': fixes['after_score'] } return { 'critique': critique, 'fixes': None, 'final_score': critique['overall_score'] } def validate_master(self, audio_data: Any) -> Dict[str, Any]: """ Fase 6: Validación completa del master. Args: audio_data: Datos de audio a validar Returns: Reporte QA """ return self.qa_suite.run_full_qa(audio_data, {}) # Instancia global _full_pipeline: Optional[AbletonMCPFullPipeline] = None def get_full_pipeline(seed: int = 42) -> AbletonMCPFullPipeline: """Obtiene instancia del pipeline completo.""" global _full_pipeline if _full_pipeline is None: _full_pipeline = AbletonMCPFullPipeline(seed=seed) return _full_pipeline def generate_complete_track(vibe_text: str, seed: int = 42) -> Dict[str, Any]: """ Función de conveniencia para generar un track completo. Args: vibe_text: Descripción del vibe deseado seed: Seed para reproducibilidad Returns: Configuración completa lista para AbletonMCP """ pipeline = get_full_pipeline(seed) return pipeline.generate_from_vibe(vibe_text, apply_full_pipeline=True)