feat: reggaeton production system with intelligent sample selection and FLP generation
This commit is contained in:
71
scripts/compose.py
Normal file
71
scripts/compose.py
Normal file
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python
|
||||
"""Compose and build in one step from genre knowledge base."""
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
|
||||
from src.composer import compose_from_genre
|
||||
from scripts.build import build_project
|
||||
from src.flp_builder.writer import FLPWriter
|
||||
|
||||
KNOWLEDGE_DIR = Path(__file__).parent.parent / "knowledge" / "genres"
|
||||
OUTPUT_DIR = Path(__file__).parent.parent / "output"
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Compose and build from genre")
|
||||
parser.add_argument("genre", help="Genre filename (e.g. reggaeton_2009)")
|
||||
parser.add_argument("--key", "-k", default=None, help="Override key (e.g. Am)")
|
||||
parser.add_argument("--bpm", "-b", type=float, default=None, help="Override BPM")
|
||||
parser.add_argument("--bars", type=int, default=None, help="Override bar count")
|
||||
parser.add_argument("--output", "-o", default=None, help="Output .flp path")
|
||||
args = parser.parse_args()
|
||||
|
||||
genre_file = KNOWLEDGE_DIR / f"{args.genre}.json"
|
||||
if not genre_file.exists():
|
||||
print(json.dumps({"error": f"Genre not found: {genre_file}", "available": [p.stem for p in KNOWLEDGE_DIR.glob("*.json")]}))
|
||||
sys.exit(1)
|
||||
|
||||
overrides = {}
|
||||
if args.key:
|
||||
overrides["keys"] = [args.key]
|
||||
if args.bpm:
|
||||
overrides["bpm"] = {"default": args.bpm}
|
||||
if args.bars:
|
||||
overrides["structure"] = {"sections": [{"bars": args.bars}]}
|
||||
|
||||
composition = compose_from_genre(str(genre_file), overrides if overrides else None)
|
||||
project = build_project(composition)
|
||||
|
||||
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
output_path = args.output or str(
|
||||
OUTPUT_DIR / f"{args.genre}_{composition['meta']['key']}_{composition['meta']['bpm']}bpm.flp"
|
||||
)
|
||||
|
||||
writer = FLPWriter(project)
|
||||
writer.write(output_path)
|
||||
|
||||
result = {
|
||||
"status": "ok",
|
||||
"output": output_path,
|
||||
"genre": args.genre,
|
||||
"key": composition["meta"]["key"],
|
||||
"bpm": composition["meta"]["bpm"],
|
||||
"chord_progression": composition["meta"]["chord_progression"],
|
||||
"tracks": [
|
||||
{"role": t["role"], "notes": len(t.get("notes", []))}
|
||||
for t in composition["tracks"]
|
||||
],
|
||||
"channel_names": [ch.name for ch in project.channels],
|
||||
"total_notes": sum(len(n) for t in composition["tracks"] for n in t.get("notes", [])),
|
||||
}
|
||||
print(json.dumps(result, indent=2, ensure_ascii=False))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user