feat: pattern-based generators from real track analysis, RPP structure fixes, randomization

- Reverse-engineer drum patterns from 2 real reggaeton tracks with librosa
- Create patterns.py with extracted frequency data (kick/snare/hihat positions)
- Rewrite rhythm.py with pattern-bank generators (dembow, dense, trapico, offbeat)
- Rewrite melodic.py with section-aware generators and humanization
- Add weighted random sample selection in SampleSelector (top-5 pool)
- Add generate_structure() with randomized templates and energy variance
- Fix RPP structure: TEMPO arity (3→4 args), string quoting for empty strings
- Rewrite quick_drumloop_test.py with correct REAPER ground truth format
- Add scripts/analyze_examples.py for reverse engineering audio tracks
- Add --seed argument for reproducible generation
- 72 tests passing
This commit is contained in:
renato97
2026-05-03 16:08:07 -03:00
parent 32dafd94e0
commit 3444006411
10 changed files with 1664 additions and 285 deletions

View File

@@ -200,14 +200,17 @@ class TestSectionBuilderIntegration:
index_path = _ROOT / "data" / "sample_index.json"
selector = SampleSelector(str(index_path))
tracks, sections = build_section_tracks(genre_config, selector, "Am", 95.0)
# Pass explicit sections_data since JSON now uses templates format
sections_data = genre_config.get("structure", {}).get("templates", {}).get("extracted_real_tracks", [])
tracks, sections = build_section_tracks(genre_config, selector, "Am", 95.0, sections_data=sections_data)
assert len(tracks) > 0, "Expected at least one track"
assert len(sections) > 0, "Expected at least one section"
# Sections should have names
# Sections should have names from the genre config
valid_names = {"intro", "verse", "build", "pre_chorus", "chorus", "drop",
"break", "gap", "bridge", "outro", "verse2", "chorus2", "chorus3"}
for sec in sections:
assert sec.name in ["intro", "verse", "chorus", "outro",
"verse2", "chorus2", "bridge", "chorus3"]
assert sec.name in valid_names, f"Unexpected section name: {sec.name}"
def test_song_definition_has_sections_field(self):
"""SongDefinition has a sections field."""