Public-ready: JSON tune specs, first-class loop API, licence, AGENTS.md

- MidiFile.set_loop(): one call writes LOOP_START/END, RPR LOOP
  START/END (Reaper) and LoopBegin/End markers - every engine finds
  its dialect; reader now parses markers and the smoke test asserts
  the round-trip
- tools/make_tune.py: declarative JSON spec -> fully arranged MIDI
  with style presets (dos_adventure, n64_ambient, chiptune_racing);
  the agent-friendly front door, no Python required
- tunes/specs/: demo tune 04 'Tea Break at the Terminal' (Am/112,
  loop bars 4-20) generated entirely from JSON
- AGENTS.md: spec schema, score grammar, verification loop, looping
  conventions for game BGM
- MIT LICENSE; history audited clean of credentials
This commit is contained in:
Hermes Agent committed 2026-10-17 06:59:04 +00:00
1 parent c3cd91d04f
commit 633eb92352
15 files changed
+387 -9

No files matched your search

+8
View File
@@ -26,6 +26,7 @@ d = Track("Drums", channel=9)
drums(d, 0, 2, "rock")
mf.add_track(lead); mf.add_track(bass); mf.add_track(acomp); mf.add_track(d)
mf.tempos = [MPQN.from_bpm(0, 120)]
mf.set_loop(bar(0), bar(2)) # loop the whole 2-bar demo
path = "/tmp/midikit_smoke.mid"
mf.write(path)
@@ -34,6 +35,13 @@ print("OK:", path, d["duration_sec"], "sec,",
sum(len(t["notes"]) for t in d["tracks"]), "notes,",
len(d["tracks"]), "tracks")
# loop markers must survive the round-trip in all three conventions
markers = sorted(set(m[1] for t in d["tracks"] for m in t["markers"]))
expected = sorted(["LOOP_START", "LOOP_END", "RPR LOOP START", "RPR LOOP END",
"LoopBegin", "LoopEnd"])
assert markers == expected, "loop markers wrong: %s" % markers
print("loop markers OK:", ", ".join(markers))
# cross-check with mido if present (third-party parser as second opinion)
try:
import mido