72 lines
2.5 KiB
Python
72 lines
2.5 KiB
Python
#!/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()
|