# SPRINT 1 - Análisis Espectral de Librería + Embeddings

> **Date**: 2026-04-11
> **Assigned**: Kimi K2
> **Reviewed by**: Qwen (después de completar)
> **Priority**: CRÍTICA - Base para generación inteligente

---

## OBJETIVO

Analizar TODOS los samples de `libreria/reggaeton/` (509 samples) con técnicas de análisis de audio avanzado para poder:
1. Encontrar samples similares entre sí
2. Comparar contra `reggaeton_ejemplo.mp3` como referencia
3. Generar canciones que suenen similar a la biblioteca del usuario

---

## ARCHIVOS A CREAR

### 1. `libreria_analyzer.py`
**Ubicación**: `C:\ProgramData\Ableton\Live 12 Suite\Resources\MIDI Remote Scripts\AbletonMCP_AI\mcp_server\engines\libreria_analyzer.py`

**Funcionalidad**:
- Escanea recursivamente `libreria/reggaeton/` buscando TODOS los .wav, .mp3, .aif, .flac
- Para CADA sample extraer:
  - **BPM** (tempo detection via onset detection)
  - **Key** (key detection via chromagram)
  - **RMS** (nivel de energía/promedio)
  - **Spectral Centroid** (brillo del sample)
  - **Spectral Rolloff** (frecuencia de corte)
  - **Zero Crossing Rate** (percutivo vs sostenido)
  - **MFCCs** (13 coeficientes - timbre/fingerprint)
  - **Onset Strength** (qué tan rítmico/percutivo es)
  - **Duration** (duración en segundos)
  - **Sample Rate**
  - **Channels** (mono/stereo)
- Guardar todo en cache: `libreria/reggaeton/.features_cache.json`
- Formato del JSON:
```json
{
  "version": "1.0",
  "total_samples": 509,
  "scan_date": "2026-04-11T...",
  "samples": {
    "C:/.../libreria/reggaeton/kick/kick_808.wav": {
      "name": "kick_808.wav",
      "pack": "kick",
      "bpm": 0,
      "key": "",
      "rms": -12.5,
      "spectral_centroid": 2500.0,
      "spectral_rolloff": 8000.0,
      "zero_crossing_rate": 0.15,
      "mfccs": [0.5, -0.3, 0.1, ...],
      "onset_strength": 0.85,
      "duration": 0.5,
      "sample_rate": 44100,
      "channels": 1,
      "role": "kick"
    }
  }
}
```

### 2. `embedding_engine.py`
**Ubicación**: `C:\ProgramData\Ableton\Live 12 Suite\Resources\MIDI Remote Scripts\AbletonMCP_AI\mcp_server\engines\embedding_engine.py`

**Funcionalidad**:
- Crear embedding vectorial para cada sample (numpy array de ~20 dimensiones)
- El embedding combina: BPM, Key, RMS, Spectral Centroid, Spectral Rolloff, ZCR, MFCCs(13), Onset Strength, Duration
- Normalizar todos los embeddings (min-max scaling) para que sean comparables
- Guardar en: `libreria/reggaeton/.embeddings_index.json` (como arrays serializados)
- Función `find_similar(sample_path, top_n=10)` → retorna samples más similares por distancia coseno o euclidiana
- Función `find_by_audio_reference(audio_file_path, top_n=20)` → analiza un archivo de audio completo y encuentra los samples más similares

### 3. `reference_matcher.py`
**Ubicación**: `C:\ProgramData\Ableton\Live 12 Suite\Resources\MIDI Remote Scripts\AbletonMCP_AI\mcp_server\engines\reference_matcher.py`

**Funcionalidad**:
- Analizar `libreria/reggaeton_ejemplo.mp3` como track de referencia
- Extraer su fingerprint espectral completo (BPM, Key, energy curve, timbre promedio)
- Comparar TODA la librería contra esta referencia
- Generar ranking: qué samples son más similares al estilo del usuario
- Crear "perfil de sonido" del usuario:
  - BPM preferido
  - Key preferida
  - Timbre promedio (MFCCs medios)
  - Energy curve
  - Roles de samples más usados (kick, snare, etc.)
- Guardar en: `libreria/reggaeton/.user_sound_profile.json`

---

## DETALLES DE IMPLEMENTACIÓN

### Librerías a usar
```python
import numpy as np
import librosa          # Análisis espectral principal
import librosa.feature  # MFCCs, spectral centroid, etc.
import json
import os
from pathlib import Path
```

Si librosa NO está disponible, usar fallback con:
- `scipy.io.wavfile` para leer WAVs
- Estimación de BPM por onset detection simple
- Sin MFCCs (usar spectral centroid básico)

### Estructura de la librería
```
libreria/reggaeton/
├── reggaeton_ejemplo.mp3    ← Referencia PRINCIPAL
├── kick/
├── snare/
├── bass/
├── fx/
├── drumloops/
├── hi-hat (para percs normalmente)/
├── oneshots/
├── perc loop/
├── reggaeton 3/
├── SentimientoLatino2025/
├── sounds presets/
├── (extra)/
└── flp/
```

### Detección de rol por carpeta
El rol de cada sample se infiere de la carpeta donde está:
- `kick/` → "kick"
- `snare/` → "snare"
- `bass/` → "bass"
- `fx/` → "fx"
- `drumloops/` → "drum_loop"
- `hi-hat*/` → "hat_closed"
- `oneshots/` → "oneshot"
- `perc loop/` → "perc_loop"
- `reggaeton 3/` → "synth" (default)
- `SentimientoLatino2025/` → "multi" (pack completo)

---

## ARCHIVOS A MODIFICAR

### `sample_selector.py`
Agregar método `select_by_similarity(reference_path, top_n=10)` que:
1. Usa `embedding_engine.find_similar()` para encontrar samples similares
2. Retorna un InstrumentGroup con los samples más parecidos a la referencia

---

## ARCHIVOS DE SALIDA GENERADOS

| Archivo | Contenido |
|---------|-----------|
| `libreria/reggaeton/.features_cache.json` | Features de los 509 samples |
| `libreria/reggaeton/.embeddings_index.json` | Embeddings vectoriales normalizados |
| `libreria/reggaeton/.user_sound_profile.json` | Perfil de sonido del usuario |

---

## RESTRICCIONES

1. **NO MODIFICAR** ningún sample .wav/.mp3 - solo lectura
2. **NO ELIMINAR** nada de `libreria/`
3. El análisis puede tardar varios minutos (509 samples) - mostrar progreso
4. Usar caché: si `.features_cache.json` existe y es reciente, no re-analizar
5. Todos los paths en los JSON deben ser absolutos (Windows)
6. Compilar cada archivo después de crear: `python -m py_compile "<path>"`

---

## VERIFICACIÓN (Qwen hará esto después)

```powershell
# Compilar
python -m py_compile "C:\ProgramData\Ableton\Live 12 Suite\Resources\MIDI Remote Scripts\AbletonMCP_AI\mcp_server\engines\libreria_analyzer.py"
python -m py_compile "C:\ProgramData\Ableton\Live 12 Suite\Resources\MIDI Remote Scripts\AbletonMCP_AI\mcp_server\engines\embedding_engine.py"
python -m py_compile "C:\ProgramData\Ableton\Live 12 Suite\Resources\MIDI Remote Scripts\AbletonMCP_AI\mcp_server\engines\reference_matcher.py"

# Test rápido
python -c "from engines.libreria_analyzer import LibreriaAnalyzer; a = LibreriaAnalyzer(); print(f'Scanned {len(a.features)} samples')"
```

---

**Cuando termines, avisale a Qwen para que revise, compile y cree el Sprint 2.**
