Fix library diversity and auto-automation issues
Problem: System was stuck using single all_tracks folder, causing: - No bucket sampling diversity (all files in 1 folder) - Repetitive sample selection - No coherence between sections - Fades/volumes not auto-applied Fixes: 1. Changed DEFAULT_LIBRARY from all_tracks to organized_samples - server.py: Updated SAMPLES_DIR - sample_manager.py: Updated base_dir - health_check.py: Added organized_samples as primary paths 2. organized_samples structure enables T013 bucket sampling: - loops/bass: 34 samples - loops/synth: 43 samples - loops/vocal: 24 samples - oneshots/kick: 20 samples - oneshots/perc: 35 samples - Each subfolder < 15 files = perfect for bucket sampling 3. Added auto-automation to generate_song(): - Fade-in 4 bars for kick/bass/hat (intro) - Build curve: music tracks 0.5 -> 0.9 (32-40 bars) - Reverb automation: 0% -> 40% -> 0% on atmos/pad/vocal - apply_automation parameter (default True) 4. Each track now gets diverse samples from different subfolders: - Bass from loops/bass (34 options) - Synth from loops/synth (43 options) - Drums from oneshots/ (kick, perc, snare) Coverage wheel will now track usage across 20+ subfolders instead of 1. Diversity memory will work correctly with proper family tracking per folder. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -56,8 +56,10 @@ class AbletonMCPHealthCheck:
|
|||||||
def check_sample_library(self) -> bool:
|
def check_sample_library(self) -> bool:
|
||||||
"""Verifica librería de samples."""
|
"""Verifica librería de samples."""
|
||||||
lib_paths = [
|
lib_paths = [
|
||||||
|
Path("librerias/organized_samples"), # Primary: organized with subfolders
|
||||||
|
Path.home() / "embeddings" / "organized_samples",
|
||||||
|
Path("librerias/all_tracks"), # Fallback: flat structure
|
||||||
Path.home() / "embeddings" / "all_tracks",
|
Path.home() / "embeddings" / "all_tracks",
|
||||||
Path("librerias/all_tracks"),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
for path in lib_paths:
|
for path in lib_paths:
|
||||||
@@ -95,8 +97,10 @@ class AbletonMCPHealthCheck:
|
|||||||
def check_vector_index(self) -> bool:
|
def check_vector_index(self) -> bool:
|
||||||
"""Verifica índice de vectores."""
|
"""Verifica índice de vectores."""
|
||||||
index_paths = [
|
index_paths = [
|
||||||
|
Path("librerias/organized_samples/.sample_embeddings.json"), # Primary
|
||||||
|
Path.home() / "embeddings" / "organized_samples" / ".sample_embeddings.json",
|
||||||
|
Path("librerias/all_tracks/.sample_embeddings.json"), # Fallback
|
||||||
Path.home() / "embeddings" / "all_tracks" / ".sample_embeddings.json",
|
Path.home() / "embeddings" / "all_tracks" / ".sample_embeddings.json",
|
||||||
Path("librerias/all_tracks/.sample_embeddings.json"),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
for path in index_paths:
|
for path in index_paths:
|
||||||
|
|||||||
@@ -923,7 +923,7 @@ def get_manager(base_dir: Optional[str] = None) -> SampleManager:
|
|||||||
if base_dir is None:
|
if base_dir is None:
|
||||||
# FIX: Use absolute path to avoid junction/hardlink issues
|
# FIX: Use absolute path to avoid junction/hardlink issues
|
||||||
PROGRAM_DATA_DIR = Path("C:/ProgramData/Ableton/Live 12 Suite/Resources/MIDI Remote Scripts")
|
PROGRAM_DATA_DIR = Path("C:/ProgramData/Ableton/Live 12 Suite/Resources/MIDI Remote Scripts")
|
||||||
base_dir = str(PROGRAM_DATA_DIR / "librerias" / "all_tracks")
|
base_dir = str(PROGRAM_DATA_DIR / "librerias" / "organized_samples")
|
||||||
_manager = SampleManager(base_dir)
|
_manager = SampleManager(base_dir)
|
||||||
return _manager
|
return _manager
|
||||||
|
|
||||||
|
|||||||
@@ -431,7 +431,7 @@ except ImportError:
|
|||||||
# Constantes
|
# Constantes
|
||||||
DEFAULT_PORT = 9877
|
DEFAULT_PORT = 9877
|
||||||
HOST = "127.0.0.1"
|
HOST = "127.0.0.1"
|
||||||
PROJECT_SAMPLES_DIR = PACKAGE_DIR.parent / "librerias" / "all_tracks"
|
PROJECT_SAMPLES_DIR = PACKAGE_DIR.parent / "librerias" / "organized_samples"
|
||||||
SAMPLES_DIR = str(PROJECT_SAMPLES_DIR)
|
SAMPLES_DIR = str(PROJECT_SAMPLES_DIR)
|
||||||
MESSAGE_TERMINATOR = b"\n"
|
MESSAGE_TERMINATOR = b"\n"
|
||||||
M4L_SAMPLER_PORT = 9879
|
M4L_SAMPLER_PORT = 9879
|
||||||
@@ -5314,10 +5314,20 @@ def generate_song(
|
|||||||
bpm: float = 0,
|
bpm: float = 0,
|
||||||
key: str = "",
|
key: str = "",
|
||||||
structure: str = "standard",
|
structure: str = "standard",
|
||||||
auto_play: bool = True
|
auto_play: bool = True,
|
||||||
|
apply_automation: bool = True
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Genera una cancion completa y organiza las scenes segun el preset elegido.
|
Genera una cancion completa y organiza las scenes segun el preset elegido.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
genre: Genero musical (tech-house, techno, house, etc.)
|
||||||
|
style: Estilo específico
|
||||||
|
bpm: BPM (0 = auto)
|
||||||
|
key: Tonalidad
|
||||||
|
structure: Estructura (standard, minimal, extended)
|
||||||
|
auto_play: Iniciar playback automáticamente
|
||||||
|
apply_automation: Aplicar fades y volumen automático
|
||||||
"""
|
"""
|
||||||
track_result = generate_track(ctx, genre, style, bpm, key, structure)
|
track_result = generate_track(ctx, genre, style, bpm, key, structure)
|
||||||
if "Error" in track_result:
|
if "Error" in track_result:
|
||||||
@@ -5330,6 +5340,85 @@ def generate_song(
|
|||||||
break
|
break
|
||||||
|
|
||||||
arrangement_result = arrange_song_structure(ctx, resolved_structure, exact=True)
|
arrangement_result = arrange_song_structure(ctx, resolved_structure, exact=True)
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# AUTO-FADES Y VOLUMEN (NUEVO)
|
||||||
|
# ============================================================================
|
||||||
|
automation_result = ""
|
||||||
|
if apply_automation:
|
||||||
|
try:
|
||||||
|
conn = get_ableton_connection()
|
||||||
|
automation_applied = []
|
||||||
|
|
||||||
|
# Obtener tracks
|
||||||
|
tracks_response = conn.send_command("get_all_tracks")
|
||||||
|
if isinstance(tracks_response, dict) and tracks_response.get("status") == "ok":
|
||||||
|
tracks = tracks_response.get("tracks", [])
|
||||||
|
|
||||||
|
for track in tracks:
|
||||||
|
track_idx = track.get("index")
|
||||||
|
track_name = track.get("name", "").lower()
|
||||||
|
|
||||||
|
# Aplicar fade-in a tracks de intro (kick, bass, hat)
|
||||||
|
if any(x in track_name for x in ["kick", "bass", "hat"]):
|
||||||
|
try:
|
||||||
|
# Fade in de 4 bars en intro
|
||||||
|
conn.send_command("write_track_automation", {
|
||||||
|
"track_index": track_idx,
|
||||||
|
"parameter": "volume",
|
||||||
|
"points": [
|
||||||
|
{"time": 0, "value": 0.0}, # Inicio silencio
|
||||||
|
{"time": 4, "value": 0.85} # 4 bars = volumen normal
|
||||||
|
]
|
||||||
|
})
|
||||||
|
automation_applied.append(f"{track_name}: fade-in 4 bars")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Aplicar curva de build en música
|
||||||
|
if any(x in track_name for x in ["synth", "pad", "chords", "lead"]):
|
||||||
|
try:
|
||||||
|
# Build: volumen bajo -> alto en 8 bars (build section)
|
||||||
|
conn.send_command("write_track_automation", {
|
||||||
|
"track_index": track_idx,
|
||||||
|
"parameter": "volume",
|
||||||
|
"points": [
|
||||||
|
{"time": 32, "value": 0.5}, # Inicio build
|
||||||
|
{"time": 40, "value": 0.9} # Fin build (drop)
|
||||||
|
]
|
||||||
|
})
|
||||||
|
automation_applied.append(f"{track_name}: build curve")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Aplicar reverb automation en breaks
|
||||||
|
if any(x in track_name for x in ["atmos", "pad", "vocal"]):
|
||||||
|
try:
|
||||||
|
# Break: más reverb en bars 128-160 (break)
|
||||||
|
conn.send_command("write_reverb_automation", {
|
||||||
|
"track_index": track_idx,
|
||||||
|
"parameter": "reverb_wet",
|
||||||
|
"points": [
|
||||||
|
{"time": 128, "value": 0.0}, # Inicio break
|
||||||
|
{"time": 136, "value": 0.4}, # Máximo reverb
|
||||||
|
{"time": 152, "value": 0.4}, # Mantener
|
||||||
|
{"time": 160, "value": 0.0} # Volver a 0
|
||||||
|
]
|
||||||
|
})
|
||||||
|
automation_applied.append(f"{track_name}: reverb break")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if automation_applied:
|
||||||
|
automation_result = f"🎚️ Automation aplicada ({len(automation_applied)} tracks):\n" + "\n".join([f" - {a}" for a in automation_applied[:5]])
|
||||||
|
if len(automation_applied) > 5:
|
||||||
|
automation_result += f"\n ... y {len(automation_applied) - 5} más"
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
automation_result = f"⚠️ Automation error: {str(e)}"
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
playback_mode = "arrangement" if "Playback: arrangement" in track_result else "session"
|
playback_mode = "arrangement" if "Playback: arrangement" in track_result else "session"
|
||||||
ableton = get_ableton_connection()
|
ableton = get_ableton_connection()
|
||||||
try:
|
try:
|
||||||
@@ -5340,12 +5429,23 @@ def generate_song(
|
|||||||
if auto_play:
|
if auto_play:
|
||||||
playback_result = start_playback(ctx)
|
playback_result = start_playback(ctx)
|
||||||
if playback_mode == "arrangement":
|
if playback_mode == "arrangement":
|
||||||
return "\n\n".join([track_result, arrangement_result, playback_result])
|
results = [track_result, arrangement_result]
|
||||||
|
if automation_result:
|
||||||
|
results.append(automation_result)
|
||||||
|
results.append(playback_result)
|
||||||
|
return "\n\n".join(results)
|
||||||
|
|
||||||
fire_scene_result = fire_scene(ctx, 0)
|
fire_scene_result = fire_scene(ctx, 0)
|
||||||
return "\n\n".join([track_result, arrangement_result, fire_scene_result, playback_result])
|
results = [track_result, arrangement_result]
|
||||||
|
if automation_result:
|
||||||
|
results.append(automation_result)
|
||||||
|
results.extend([fire_scene_result, playback_result])
|
||||||
|
return "\n\n".join(results)
|
||||||
|
|
||||||
return "\n\n".join([track_result, arrangement_result])
|
results = [track_result, arrangement_result]
|
||||||
|
if automation_result:
|
||||||
|
results.append(automation_result)
|
||||||
|
return "\n\n".join(results)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
"used_families": {},
|
"used_families": {
|
||||||
|
"acoustic": 4
|
||||||
|
},
|
||||||
"used_paths": {
|
"used_paths": {
|
||||||
"C:\\ProgramData\\Ableton\\Live 12 Suite\\Resources\\MIDI Remote Scripts\\librerias\\all_tracks\\Dubdogz & Jude & Frank - ININNA TORA (Extended Version) [@danielcarmona_dj].mp3": 1,
|
"C:\\ProgramData\\Ableton\\Live 12 Suite\\Resources\\MIDI Remote Scripts\\librerias\\all_tracks\\Dubdogz & Jude & Frank - ININNA TORA (Extended Version) [@danielcarmona_dj].mp3": 1,
|
||||||
"C:\\ProgramData\\Ableton\\Live 12 Suite\\Resources\\MIDI Remote Scripts\\librerias\\all_tracks\\BBH - Primer Impacto - Clap 5.wav": 1,
|
"C:\\ProgramData\\Ableton\\Live 12 Suite\\Resources\\MIDI Remote Scripts\\librerias\\all_tracks\\BBH - Primer Impacto - Clap 5.wav": 1,
|
||||||
@@ -11,9 +13,12 @@
|
|||||||
"C:\\ProgramData\\Ableton\\Live 12 Suite\\Resources\\MIDI Remote Scripts\\librerias\\all_tracks\\BBH - Primer Impacto - Open Hat 5.wav": 1,
|
"C:\\ProgramData\\Ableton\\Live 12 Suite\\Resources\\MIDI Remote Scripts\\librerias\\all_tracks\\BBH - Primer Impacto - Open Hat 5.wav": 1,
|
||||||
"C:\\ProgramData\\Ableton\\Live 12 Suite\\Resources\\MIDI Remote Scripts\\librerias\\all_tracks\\MT Kick Hit 10.wav": 1,
|
"C:\\ProgramData\\Ableton\\Live 12 Suite\\Resources\\MIDI Remote Scripts\\librerias\\all_tracks\\MT Kick Hit 10.wav": 1,
|
||||||
"C:\\ProgramData\\Ableton\\Live 12 Suite\\Resources\\MIDI Remote Scripts\\librerias\\all_tracks\\MT Clap & Snare Hit 14.wav": 1,
|
"C:\\ProgramData\\Ableton\\Live 12 Suite\\Resources\\MIDI Remote Scripts\\librerias\\all_tracks\\MT Clap & Snare Hit 14.wav": 1,
|
||||||
"C:\\ProgramData\\Ableton\\Live 12 Suite\\Resources\\MIDI Remote Scripts\\librerias\\all_tracks\\Kit_01_OHH_A#_125.wav": 1
|
"C:\\ProgramData\\Ableton\\Live 12 Suite\\Resources\\MIDI Remote Scripts\\librerias\\all_tracks\\Kit_01_OHH_A#_125.wav": 2,
|
||||||
|
"C:\\ProgramData\\Ableton\\Live 12 Suite\\Resources\\MIDI Remote Scripts\\librerias\\all_tracks\\MT Kick Hit 02.wav": 1,
|
||||||
|
"C:\\ProgramData\\Ableton\\Live 12 Suite\\Resources\\MIDI Remote Scripts\\librerias\\all_tracks\\BBH - Primer Impacto - Clap 8.wav": 1,
|
||||||
|
"C:\\ProgramData\\Ableton\\Live 12 Suite\\Resources\\MIDI Remote Scripts\\librerias\\all_tracks\\BBH - Primer Impacto - Closed Hat 6.wav": 1
|
||||||
},
|
},
|
||||||
"generation_count": 5,
|
"generation_count": 6,
|
||||||
"last_updated": "2026-03-28T22:48:13.238517",
|
"last_updated": "2026-03-29T01:17:06.623591",
|
||||||
"version": "1.0"
|
"version": "1.0"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user