Files
ableton-mcp-ai/validate_audio_resampler.py
renato97 6ec8663954 Initial commit: AbletonMCP-AI complete system
- MCP Server with audio fallback, sample management
- Song generator with bus routing
- Reference listener and audio resampler
- Vector-based sample search
- Master chain with limiter and calibration
- Fix: Audio fallback now works without M4L
- Fix: Full song detection in sample loader

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 22:53:10 -03:00

251 lines
7.6 KiB
Python

#!/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())