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>
107 lines
3.5 KiB
Python
107 lines
3.5 KiB
Python
"""
|
|
test_integration.py - Tests de integración end-to-end
|
|
"""
|
|
import sys
|
|
import os
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
|
|
import unittest
|
|
from full_integration import AbletonMCPFullPipeline, generate_complete_track
|
|
|
|
|
|
class TestFullPipeline(unittest.TestCase):
|
|
"""Tests de integración completa"""
|
|
|
|
def setUp(self):
|
|
self.pipeline = AbletonMCPFullPipeline(seed=42)
|
|
|
|
def test_generate_from_vibe_techno(self):
|
|
"""Test generación desde vibe techno."""
|
|
result = self.pipeline.generate_from_vibe("dark warehouse techno")
|
|
|
|
self.assertEqual(result['genre'], 'techno')
|
|
self.assertIn('bpm', result)
|
|
self.assertIn('key', result)
|
|
self.assertIn('structure', result)
|
|
self.assertTrue(result['dj_friendly'])
|
|
|
|
def test_generate_from_vibe_house(self):
|
|
"""Test generación desde vibe house."""
|
|
result = self.pipeline.generate_from_vibe("deep house sunset")
|
|
|
|
self.assertEqual(result['genre'], 'house')
|
|
self.assertIn('bpm', result)
|
|
self.assertGreaterEqual(result['bpm'], 110)
|
|
self.assertLessEqual(result['bpm'], 130)
|
|
|
|
def test_full_pipeline_applies_human_feel(self):
|
|
"""Test que human feel está configurado."""
|
|
result = self.pipeline.generate_from_vibe("techno", apply_full_pipeline=True)
|
|
|
|
self.assertIn('human_feel', result)
|
|
self.assertTrue(result['human_feel']['enabled'])
|
|
|
|
def test_full_pipeline_creates_structure(self):
|
|
"""Test que se crea estructura."""
|
|
result = self.pipeline.generate_from_vibe("techno")
|
|
|
|
self.assertIn('structure', result)
|
|
self.assertGreater(len(result['structure']), 0)
|
|
|
|
def test_full_pipeline_creates_transitions(self):
|
|
"""Test que se crean transiciones."""
|
|
result = self.pipeline.generate_from_vibe("techno")
|
|
|
|
self.assertIn('transitions', result)
|
|
self.assertIsInstance(result['transitions'], list)
|
|
|
|
def test_full_pipeline_creates_atmos_events(self):
|
|
"""Test que se detectan gaps y crean atmos."""
|
|
result = self.pipeline.generate_from_vibe("techno")
|
|
|
|
self.assertIn('atmos_events', result)
|
|
|
|
def test_full_pipeline_creates_fx_events(self):
|
|
"""Test que se crean FX automáticos."""
|
|
result = self.pipeline.generate_from_vibe("techno")
|
|
|
|
self.assertIn('fx_events', result)
|
|
|
|
def test_full_pipeline_creates_master_chain(self):
|
|
"""Test que se configura master chain."""
|
|
result = self.pipeline.generate_from_vibe("techno")
|
|
|
|
self.assertIn('master_chain', result)
|
|
self.assertGreater(len(result['master_chain']), 0)
|
|
|
|
def test_generate_complete_track_function(self):
|
|
"""Test función de conveniencia."""
|
|
result = generate_complete_track("industrial techno", seed=123)
|
|
|
|
self.assertIn('genre', result)
|
|
self.assertIn('vibe_params', result)
|
|
|
|
|
|
class TestCritiqueAndFix(unittest.TestCase):
|
|
"""Tests para critique y auto-fix"""
|
|
|
|
def setUp(self):
|
|
self.pipeline = AbletonMCPFullPipeline(seed=42)
|
|
|
|
def test_critique_returns_scores(self):
|
|
"""Test que critique retorna scores."""
|
|
mock_song = {
|
|
'sections': [{'name': 'Intro'}, {'name': 'Drop'}],
|
|
'tracks': [{'name': 'Drums'}, {'name': 'Bass'}]
|
|
}
|
|
|
|
result = self.pipeline.critique_and_fix(mock_song)
|
|
|
|
self.assertIn('critique', result)
|
|
self.assertIn('final_score', result)
|
|
self.assertIsInstance(result['final_score'], float)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|