#!/usr/bin/env python3
"""Compose real melodic phrases (no repeated-note padding): pick a
single beep(B,C) call per note, B solved to hit ~110ms each, and
extend each scene's phrase to enough notes to reach a real target
duration on actual hardware."""
CLOCK = 3_500_000

def note_tstates(b, c):
    inner = 16 * (c - 1) + 11
    per_outer = 11 + 7 + 11 + inner + 10
    return (per_outer + 13) * (b - 1) + (per_outer + 8)

def best_b(c, target_ms):
    target_ts = target_ms / 1000 * CLOCK
    best, best_err = 1, None
    for b in range(1, 256):
        err = abs(note_tstates(b, c) - target_ts)
        if best_err is None or err < best_err:
            best, best_err = b, err
    return best

def phrase(pitches, note_ms):
    notes = [(best_b(c, note_ms), c) for c in pitches]
    total_ms = sum(note_tstates(b, c) for b, c in notes) / CLOCK * 1000
    return notes, total_ms

# a descending-blues motif, one octave-ish of pitch delays, repeated
# and varied per scene to build ~28-30 notes each (~110ms/note ~= 3.1-3.3s)
def riff(base, span=8, cycles=4):
    """base..base+span..base descending/ascending sawtooth, repeated."""
    up = list(range(base, base + span, 2))
    down = list(range(base + span, base, -2))
    one = up + down
    out = []
    for i in range(cycles):
        out += [p + (i * 3 if i % 2 else -i * 2) for p in one]
    return [max(30, min(230, p)) for p in out]

SCENES = {
    "tune1": (riff(150, 10, 3), 110),   # tunnel: slow, low, moody
    "tune2": (riff(60, 12, 3), 105),    # skyline: brighter, urgent
    "tune3": (riff(90, 10, 3), 105),    # overpass: steady mid
    "tune4": (riff(55, 10, 3), 100),    # smokestacks: tense, high
    "tune5": (riff(85, 10, 3), 110),    # suburb: warmer, settling
    "tune6": (riff(50, 10, 3), 115),    # home: resolving phrase (finale holdloop adds more after)
}

grand_total_ms = 0
for name, (pitches, note_ms) in SCENES.items():
    notes, total_ms = phrase(pitches, note_ms)
    grand_total_ms += total_ms
    bytes_str = ", ".join(f"{b},{c}" for b, c in notes)
    print(f"{name}:  defb {bytes_str}, 0,0")
    print(f"  ; {len(notes)} notes, {total_ms:.0f} ms\n")

# scene6's finale hold: one sustained low note, repeated via djnz in the
# holdloop (see asm) rather than baked into the table itself
hold_c, hold_note_ms, reps = 100, 300, 8
hold_b = best_b(hold_c, hold_note_ms)
hold_ms = note_tstates(hold_b, hold_c) / CLOCK * 1000
print(f"tune6b:  defb {hold_b},{hold_c}, 0,0")
print(f"  ; single hold-loop pass = {hold_ms:.0f} ms, x{reps} reps = {hold_ms*reps:.0f} ms")
grand_total_ms += hold_ms * reps

print(f"\nTOTAL one pass through the reel: {grand_total_ms/1000:.1f} seconds")
