FASE 3 - Human Feel & Dynamics (10/11 tasks): - apply_clip_fades() - T041: Fade automation per section - write_volume_automation() - T042: Curves (linear, exp, s_curve, punch) - apply_sidechain_pump() - T045: Sidechain by intensity/style - inject_pattern_fills() - T048: Snare rolls, fills by density - humanize_set() - T050: Timing + velocity + groove automation FASE 4 - Key Compatibility & Tonal (9/12 tasks): - audio_key_compatibility.py: Full KEY_COMPATIBILITY_MATRIX - analyze_key_compatibility() - T053: Harmonic compatibility scoring - suggest_key_change() - T054: Circle of fifths modulation - validate_sample_key() - T055: Sample key validation - analyze_spectral_fit() - T057/T062: Spectral role matching FASE 6 - Mastering & QA (8/13 tasks): - calibrate_gain_staging() - T079: Auto gain by bus targets - run_mix_quality_check() - T085: LUFS, peaks, L/R balance - export_stem_mixdown() - T087: 24-bit/44.1kHz stem export New files: - audio_key_compatibility.py (T052) - bus_routing_fix.py (T101-T104) - validation_system_fix.py (T105-T106) Total: 76/110 tasks (69%), 71 MCP tools exposed Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
193 lines
6.5 KiB
Python
193 lines
6.5 KiB
Python
"""
|
|
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)
|