#!/usr/bin/env python3 """ Script de validacion para el Audio Resampler. Verifica que: 1. Las 4 funciones standalone existan y sean importables 2. La clase AudioResampler funcione correctamente 3. El cache LRU opera correctamente 4. La integracion con build_transition_layers funcione """ import sys import os # Agregar el path del MCP_Server script_dir = os.path.dirname(os.path.abspath(__file__)) mcp_server_dir = os.path.join(script_dir, "AbletonMCP_AI", "MCP_Server") sys.path.insert(0, mcp_server_dir) def test_imports(): """Test 1: Verificar que todas las funciones se pueden importar""" print("=" * 60) print("TEST 1: Verificacion de imports") print("=" * 60) try: from audio_resampler import ( AudioResampler, create_reverse_fx, create_riser_fx, create_downlifter_fx, create_stutter_fx, ) print("[OK] Todos los imports exitosos") print(f" - AudioResampler: {AudioResampler}") print(f" - create_reverse_fx: {create_reverse_fx}") print(f" - create_riser_fx: {create_riser_fx}") print(f" - create_downlifter_fx: {create_downlifter_fx}") print(f" - create_stutter_fx: {create_stutter_fx}") return True except Exception as e: print(f"[ERROR] Fallo en imports: {e}") import traceback traceback.print_exc() return False def test_class_structure(): """Test 2: Verificar estructura de la clase AudioResampler""" print("\n" + "=" * 60) print("TEST 2: Estructura de AudioResampler") print("=" * 60) try: from audio_resampler import AudioResampler # Verificar metodos privados de FX required_methods = [ '_render_reverse_fx', '_render_riser', '_render_downlifter', '_render_stutter', '_load_audio', '_write_audio', '_output_path', 'build_transition_layers', 'cache_stats', 'clear_cache', ] resampler = AudioResampler() missing = [] for method in required_methods: if not hasattr(resampler, method): missing.append(method) else: print(f"[OK] Metodo encontrado: {method}") if missing: print(f"[ERROR] Metodos faltantes: {missing}") return False # Verificar constantes de cache print(f"[OK] Cache limit: {resampler._CACHE_LIMIT}") print(f"[OK] Cache max age: {resampler._CACHE_MAX_AGE_S}s") print(f"[OK] Default peak: {resampler._DEFAULT_PEAK}") return True except Exception as e: print(f"[ERROR] Fallo en estructura: {e}") import traceback traceback.print_exc() return False def test_cache_system(): """Test 3: Verificar sistema de cache""" print("\n" + "=" * 60) print("TEST 3: Sistema de Cache LRU") print("=" * 60) try: from audio_resampler import AudioResampler resampler = AudioResampler() # Verificar cache inicial vacio stats = resampler.cache_stats() print(f"[OK] Cache stats inicial: entries={stats['entries']}, hits={stats['hits']}") # Verificar que el cache funciona (incluso sin audio) assert stats['entries'] == 0, "Cache deberia estar vacio al inicio" assert stats['max_entries'] == 50, "Cache limit deberia ser 50" assert stats['max_age_s'] == 1800.0, "Cache max age deberia ser 1800s" print("[OK] Sistema de cache operando correctamente") return True except Exception as e: print(f"[ERROR] Fallo en cache: {e}") import traceback traceback.print_exc() return False def test_transition_layers_structure(): """Test 4: Verificar estructura de build_transition_layers""" print("\n" + "=" * 60) print("TEST 4: Estructura de build_transition_layers") print("=" * 60) try: from audio_resampler import AudioResampler resampler = AudioResampler() # Probar con un plan vacio empty_plan = {"matches": {}} sections = [ {"kind": "intro", "name": "Intro", "beats": 16}, {"kind": "build", "name": "Build Up", "beats": 16}, {"kind": "drop", "name": "Drop A", "beats": 32}, ] layers = resampler.build_transition_layers(empty_plan, sections, 128.0) # Verificar que retorna una lista assert isinstance(layers, list), "Debe retornar una lista" print(f"[OK] build_transition_layers retorna lista: {len(layers)} capas") # Verificar estructura de capas (si hay alguna) for i, layer in enumerate(layers): required_keys = ['name', 'file_path', 'positions', 'color', 'volume', 'source', 'generated'] missing = [k for k in required_keys if k not in layer] if missing: print(f"[WARN] Capa {i} falta keys: {missing}") else: print(f"[OK] Capa {i} '{layer['name']}' estructura correcta") print("[OK] build_transition_layers estructura correcta") return True except Exception as e: print(f"[ERROR] Fallo en transition_layers: {e}") import traceback traceback.print_exc() return False def test_function_signatures(): """Test 5: Verificar firmas de funciones standalone""" print("\n" + "=" * 60) print("TEST 5: Firmas de funciones standalone") print("=" * 60) try: from audio_resampler import ( create_reverse_fx, create_riser_fx, create_downlifter_fx, create_stutter_fx, ) import inspect functions = [ ('create_reverse_fx', create_reverse_fx), ('create_riser_fx', create_riser_fx), ('create_downlifter_fx', create_downlifter_fx), ('create_stutter_fx', create_stutter_fx), ] for name, func in functions: sig = inspect.signature(func) params = list(sig.parameters.keys()) # Verificar parametros minimos assert 'source_path' in params, f"{name} debe tener source_path" assert 'output_path' in params, f"{name} debe tener output_path" print(f"[OK] {name} firma: {sig}") print("[OK] Todas las funciones tienen firmas correctas") return True except Exception as e: print(f"[ERROR] Fallo en firmas: {e}") import traceback traceback.print_exc() return False def main(): """Ejecutar todos los tests""" print("\n" + "=" * 60) print("VALIDACION DE AUDIO RESAMPLER") print("=" * 60) results = [ ("Imports", test_imports), ("Estructura de clase", test_class_structure), ("Sistema de cache", test_cache_system), ("Transition layers", test_transition_layers_structure), ("Firmas de funciones", test_function_signatures), ] passed = 0 failed = 0 for name, test_func in results: try: if test_func(): passed += 1 else: failed += 1 except Exception as e: print(f"\n[ERROR CRITICO] {name}: {e}") failed += 1 print("\n" + "=" * 60) print("RESUMEN DE VALIDACION") print("=" * 60) print(f"Tests pasados: {passed}/{len(results)}") print(f"Tests fallidos: {failed}/{len(results)}") if failed == 0: print("\n[OK] Audio Resampler validado exitosamente!") return 0 else: print("\n[ERROR] Algunos tests fallaron") return 1 if __name__ == "__main__": sys.exit(main())