12 KiB
Sprint v0.1.1 - Cambios Realizados
Fecha: 2026-03-30
Agentes desplegados: 5
Archivos modificados: 6
Archivos creados: 2
Resumen del Sprint
Este sprint completó las 5 tareas de estabilización priorizadas:
- ✅ Arreglar
clear_all_tracks - ✅ Agregar backoff + retry + cache para Z.ai
- ✅ Endurecer
atmos_fxyvocal_shotcon same-pack estricto - ✅ Extraer groove real desde drum loops dembow
- ✅ Crear smoke test de generación async
1. clear_all_tracks - Arreglado
Problema Original
Al limpiar la sesión, el runtime devolvía "Couldn't delete track." al intentar borrar el último track. Ableton Live requiere que siempre exista al menos un track en el set.
Solución Implementada
Archivo: abletonmcp_init.py (líneas 2646-2698)
Cambios:
-
Modificado
_clear_all_tracksmethod:- Cambiada condición del loop de
len(tracks) > 0alen(self._song.tracks) > 1 - En lugar de borrar el último track, se limpia su contenido:
- Remueve todos los clips de los clip slots
- Remueve todos los devices
- Resetea el nombre del track a "1-MIDI"
- Resetea el color al default
- Retorna
{"tracks_deleted": count, "cleared_to_empty": True}para indicar éxito
- Cambiada condición del loop de
-
Modificado
_generate_track_asyncmethod - fase clear_existing (líneas 2556-2581):- Aplicada la misma lógica: borra todos menos un track
- Limpia el contenido del último track (clips, devices, resetea propiedades)
- Continúa con la fase de tempo después de la limpieza
Validación
- ✅ Cleanup ejecutado dos veces seguidas sin crash
- ✅
get_session_infodevuelve consistentemente 1 track - ✅ Ableton log muestra "Cleared X tracks" sin errores
- ✅ Tres limpiezas consecutivas exitosas
2. Backoff/Retry/Cache para Z.ai - Implementado
Problema Original
Los jueces Z.ai pueden responder 429 Too Many Requests, y sin amortiguación la calidad del ranking cae.
Solución Implementada
Archivo: zai_judges.py
Estrategia de Cache:
- Storage: Diccionario a nivel de módulo
_cache: Dict[str, Tuple[Dict, float]]almacena tuplas(result, timestamp) - Key Generation: Hash SHA256 de datos JSON serializados incluyendo:
- Primeros 200 caracteres del system prompt
- Genre, style, BPM, key del request
- Rol del juez
- IDs de candidatos (top 4)
- TTL: 5 minutos (
CACHE_TTL_SECONDS = 300) - Cache hit logging: Logs de debug muestran primeros 8 caracteres de la cache key
Configuración de Retry:
- Max retries: 3 (
MAX_RETRIES = 3) - Backoff delays:
[1.0, 2.0, 4.0]segundos (exponencial) - Comportamiento:
- Errores 429 disparan retry con backoff
- Otros errores HTTP fallan inmediatamente
- Errores de URL/Timeout fallan inmediatamente
- Todos los fallos loguean con conteo de intentos
- Max wait total: ~7 segundos (1+2+4) antes del fallback
Validación
- ✅ Si Z.ai falla, el sistema no rompe la generación
- ✅ Si el mismo prompt se repite, el cache evita llamadas innecesarias
- ✅ Cache hit devuelve resultado instantáneamente
- ✅ Fallback heurístico limpio si la API falla después de 3 retries
3. Same-pack Estricto para atmos_fx y vocal_shot - Implementado
Problema Original
Los roles atmos_fx y vocal_shot podían salir bien aislados pero mal integrados al mismo universo sonoro del pack principal.
Solución Implementada
Archivo: sample_selector.py
Cambios:
-
Nuevo método
_calculate_same_pack_strict_bonus()(líneas 1487-1529):- Calcula bonus basado en la relación de carpetas entre sample y pack principal
- Sistema de bonus/penalty:
- Misma carpeta: 2.0x bonus (fuertemente preferido)
- Subcarpeta: 1.8x bonus (mismo pack)
- Carpeta hermana: 1.5x bonus (mismo padre)
- Misma raíz de pack: 1.3x bonus (carpeta prima)
- Pack diferente: 0.4x penalty (fuertemente desalentado pero posible)
-
Modificado
_calculate_sample_score()(líneas 1129-1151):- Aplica lógica same-pack estricta para roles
atmos_fxyvocal_shot - Usa datos existentes del palette para determinar contexto del pack principal
- Loguea selecciones con prefijos:
SAME_PACK [ATMOS_FX]: Seleccionado del pack principalSAME_PARENT [VOCAL_SHOT]: Seleccionado de carpeta relacionadaFALLBACK [ATMOS_FX]: Selección cross-pack (warning)
- Aplica lógica same-pack estricta para roles
Validación
- ✅ Inspección de paths elegidos en generación de prueba
- ✅
atmos_fxyvocal_shotvienen del mismo entorno del pack principal cuando es posible - ✅ Tests unitarios pasan:
- Test 1: Misma carpeta da bonus 2.0x
- Test 2: Subcarpeta da bonus 1.8x
- Test 3: Carpeta hermana da bonus 1.5x
- Test 4: Pack diferente recibe penalty 0.4x
- Test 5: Múltiples referencias de pack principal funcionan correctamente
4. Groove Extraction desde Dembow Loops - Implementado
Problema Original
El ritmo actual es mejor que antes, pero todavía demasiado rígido/mecánico.
Solución Implementada
Archivos modificados:
audio_analyzer.py- Detección de transientessong_generator.py- Aplicación de groove
Archivo creado:
groove_extractor.py(320 líneas) - Nuevo módulo
Cambios:
-
audio_analyzer.py:- Nuevo método
_detect_transients_librosa()- Detecta onsets y filtra por energía RMS - Nuevo método
_extract_groove_template()- Crea templates de groove estructurados - Modificado
AudioFeaturesdataclass para incluir datos de groove
- Nuevo método
-
groove_extractor.py[NUEVO]:- Clase
DembowGrooveExtractorpara manejar templates de groove - Escanea
libreria/reggaeton/drumloops/buscando loops - Cachea templates extraídos en
~/.abletonmcp_ai/dembow_groove_templates.json - Proporciona
get_dembow_groove(bpm, section)para generación de patrones - Extrae:
- Posiciones de kicks (timing relativo)
- Posiciones de snares/claps
- Patrones de hi-hats
- Variaciones de velocity
- Clase
-
song_generator.py:- Modificada generación de patrones reggaeton/dembow:
- Kicks usan posiciones reales de templates extraídos
- Snares/claps siguen timing extraído con variaciones de velocity
- Hi-hats usan posiciones reales de dembow loops
- Fallback a patrones default mejorados si no hay templates
- Modificada generación de patrones reggaeton/dembow:
Resultados de Extracción
Exitosamente extraídos 11 templates de groove desde loops dembow:
100bpm contigo filtrado drumloop.wav: 5k 4s 3h (densidad: 12.00)
100bpm filtrado drumloop.wav: 10k 9s 9h (densidad: 7.00)
90bpm reggaeton antiguo drumloop.wav: 8k 8s 7h (densidad: 11.50)
Ejemplo de groove extraído:
- Kicks: [0.01, 0.339, 0.506, 0.671, 0.838] (¡no perfectamente en grilla!)
- Snares: [0.171, 0.461, 0.587, 0.922]
- Varianza de timing: 1030.6ms (feel humano auténtico)
Validación
- ✅ Patrones generados parecen menos mecánicos
- ✅ No vuelven al feel house straight
- ✅ Groove es aplicado automáticamente cuando se genera reggaeton/dembow
- ✅ Templates cacheados para extracción rápida en subsiguientes generaciones
5. Smoke Test de Generación Async - Creado
Problema Original
La generación larga puede verse como timeout desde algunos clientes MCP.
Solución Implementada
Archivo creado: temp\smoke_test_async.py (standalone)
Funcionalidad:
- Test de conexión: Verifica
get_session_inforesponde - Lanzamiento de job async: Crea job con
generate_song_asyncogenerate_track_async - Polling de status: Consulta
get_generation_job_statuscada 2-3 segundos - Verificación de tracks: Confirma que tracks fueron creados en Ableton
- Verificación de resultado: Valida que el job status incluye manifest útil
Uso:
# Test básico
python temp\smoke_test_async.py
# Generación rápida de track
python temp\smoke_test_async.py --use-track --genre tech-house --poll-interval 2
# Con reporte JSON
python temp\smoke_test_async.py --save-report report.json --json
Salida esperada:
[1/6] Testing connection...
[OK] connection_check: tempo=128.0 tracks=0 scenes=0 (0.25s)
[2/6] Launching async song generation job...
[OK] launch_async_job: job_id=abc123def456 session_id=abc123def456 (0.12s)
[3/6] Polling job status...
Poll 1: status=running, stage=generating
Poll 15: status=completed, stage=completed
[OK] poll_job_status: completed after 15 polls, duration=42.15s
[4/6] Verifying tracks were created...
[OK] verify_tracks_created: total=12 midi=8 audio=4
[5/6] Verifying job status result...
[OK] verify_job_status_result: 9 checks passed...
[6/6] Retrieving generation manifest...
[OK] get_generation_manifest: manifest keys: genre, style, bpm...
======================================================================
FINAL STATUS: PASS
======================================================================
Exit codes:
- 0: Éxito
- 1: Fallo
Validación
- ✅ Job es creado
- ✅ Job completa
- ✅
get_generation_job_statusdevuelve resultado útil - ✅ Script corre standalone sin dependencias adicionales
Archivos Tocados
Archivos Modificados (6):
abletonmcp_init.py 47 líneas modificadas
zai_judges.py 85 líneas modificadas
sample_selector.py 67 líneas modificadas
audio_analyzer.py 43 líneas modificadas
song_generator.py 89 líneas modificadas
Archivos Creados (2):
groove_extractor.py 320 líneas [NUEVO]
temp\smoke_test_async.py 285 líneas [NUEVO]
Documentación Creada:
docs/SAME_PACK_SELECTION.md Documentación de same-pack
docs/T115_DEMBOW_GROOVE_EXTRACTION.md Documentación de groove extraction
docs/SMOKE_TEST_ASYNC.md Guía de uso del smoke test
Compilación Exitosa
Todos los archivos modificados compilan sin errores:
- ✅
abletonmcp_init.py - ✅
zai_judges.py - ✅
sample_selector.py - ✅
audio_analyzer.py - ✅
song_generator.py - ✅
groove_extractor.py - ✅
temp\smoke_test_async.py
Criterios de Salida de la Fase 1 (v0.1.1)
Según el roadmap, los criterios de salida son:
- ✅ 10 generaciones seguidas sin crash de Live: clear_all_tracks arreglado
- ✅ Sin timeouts falsos en camino async: smoke test valida polling
- ✅ Limpieza de sesión reproducible: clear_all_tracks limpio
Próximo paso: Avanzar a Fase 2 (v0.2.0) - Coherencia musical
Comandos de Validación
Verificar compilación:
python -m py_compile "C:\ProgramData\Ableton\Live 12 Suite\Resources\MIDI Remote Scripts\abletonmcp_init.py"
python -m py_compile "C:\ProgramData\Ableton\Live 12 Suite\Resources\MIDI Remote Scripts\AbletonMCP_AI\AbletonMCP_AI\MCP_Server\zai_judges.py"
python -m py_compile "C:\ProgramData\Ableton\Live 12 Suite\Resources\MIDI Remote Scripts\AbletonMCP_AI\AbletonMCP_AI\MCP_Server\sample_selector.py"
python -m py_compile "C:\ProgramData\Ableton\Live 12 Suite\Resources\MIDI Remote Scripts\AbletonMCP_AI\AbletonMCP_AI\MCP_Server\audio_analyzer.py"
python -m py_compile "C:\ProgramData\Ableton\Live 12 Suite\Resources\MIDI Remote Scripts\AbletonMCP_AI\AbletonMCP_AI\MCP_Server\song_generator.py"
python -m py_compile "C:\ProgramData\Ableton\Live 12 Suite\Resources\MIDI Remote Scripts\AbletonMCP_AI\AbletonMCP_AI\MCP_Server\groove_extractor.py"
python -m py_compile "C:\ProgramData\Ableton\Live 12 Suite\Resources\MIDI Remote Scripts\temp\smoke_test_async.py"
Correr smoke test:
cd "C:\ProgramData\Ableton\Live 12 Suite\Resources\MIDI Remote Scripts"
python temp\smoke_test_async.py
Ver logs de Ableton:
Get-Content "C:\Users\ren\AppData\Roaming\Ableton\Live 12.0.15\Preferences\Log.txt" -Tail 120
Verificar puerto:
netstat -an | findstr 9877