#!/usr/bin/env python3
"""Parameterized v2 SFX score. Usage: gen_sfx_v2.py <project-slug> [setpiece]
setpiece: 'timeline' (Vercel), 'pipeline' (Gemini), 'fanout' (Copilot) — tunes b3 hits.
Writes <proj>/artifacts/audio/v2/sfx.wav on the 60s v2 timeline.
"""
import math, wave, struct, random, sys
SR = 48000; TOTAL = 60.0; random.seed(11)
slug = sys.argv[1]
setpiece = sys.argv[2] if len(sys.argv) > 2 else "timeline"

def pop(g=1.0):
    n = int(0.10 * SR); o = []
    for i in range(n):
        t = i / SR; f = 320 - 170 * (i / n)
        o.append(g * math.sin(2 * math.pi * f * t) * math.exp(-t * 42))
    return o
def tick(g=1.0):
    n = int(0.03 * SR); o = []
    for i in range(n):
        t = i / SR; s = math.sin(2 * math.pi * 1900 * t) + 0.3 * (random.random() * 2 - 1)
        o.append(g * 0.7 * s * math.exp(-t * 220))
    return o
def whoosh(g=1.0, dur=0.35, rev=False):
    n = int(dur * SR); raw = [(random.random() * 2 - 1) for _ in range(n)]; o = []; acc = 0.0; K = 9
    for i in range(n):
        acc += raw[i]
        if i >= K: acc -= raw[i - K]
        e = math.sin(math.pi * i / n) ** 2; o.append(g * 0.5 * (acc / K) * e)
    return o[::-1] if rev else o
def thump(g=1.0):
    n = int(0.16 * SR); o = []
    for i in range(n):
        t = i / SR; s = math.sin(2 * math.pi * 88 * t) + 0.2 * math.sin(2 * math.pi * 176 * t)
        o.append(g * s * math.exp(-t * 28))
    return o
def chime(g=1.0):
    n = int(0.6 * SR); o = []
    for i in range(n):
        t = i / SR; s = 0.6 * math.sin(2 * math.pi * 660 * t) + 0.4 * math.sin(2 * math.pi * 990 * t)
        o.append(g * 0.5 * s * math.exp(-t * 7))
    return o
def clock(g=1.0):
    n = int(0.05 * SR); o = []
    for i in range(n):
        t = i / SR; o.append(g * 0.8 * math.sin(2 * math.pi * 820 * t) * math.exp(-t * 120))
    return o
GEN = {"pop": pop, "tick": tick, "whoosh": whoosh, "thump": thump, "chime": chime, "clock": clock,
       "rewind": lambda g=1.0: whoosh(g, 0.6, rev=True)}

B = [0.0, 2.8, 6.0, 16.0, 20.0, 26.0, 32.0, 37.0, 42.0, 47.0]  # beat starts
events = []; ev = lambda t, k, g=1.0: events.append((t, k, g))

# cold open + task
ev(0.3, "thump", 0.9); ev(0.5, "pop", 0.7)
ev(B[1] + 0.2, "pop", 0.9); ev(B[1] + 0.6, "tick", 0.8)
for k in range(6): ev(B[1] + 1.2 + k * 0.25, "tick", 0.3)

# set-piece (b3), t0 = B[2]
if setpiece == "timeline":
    ev(B[2] + 0.3, "whoosh", 0.6)
    for k in range(6): ev(B[2] + 0.6 + k * 0.18, "tick", 0.5)
    ev(B[2] + 2.1, "thump", 0.8)
    for k in range(7): ev(B[2] + 1.8 + k * 0.5, "clock", 0.45)
    ev(B[2] + 5.1, "chime", 0.6); ev(B[2] + 6.3, "rewind", 0.9)
    ev(B[2] + 7.9, "pop", 0.9); ev(B[2] + 8.3, "chime", 0.8)
elif setpiece == "pipeline":
    ev(B[2] + 0.3, "whoosh", 0.6)
    for k in range(5): ev(B[2] + 1.3 + k * 1.0, "pop", 0.6)
    for k in range(9): ev(B[2] + 1.5 + k * 0.5, "clock", 0.35)
    ev(B[2] + 6.6, "chime", 0.8); ev(B[2] + 7.6, "pop", 0.9)
elif setpiece == "fanout":
    ev(B[2] + 0.3, "pop", 0.8)
    for k in range(3): ev(B[2] + 1.1 + k * 0.2, "whoosh", 0.4)   # connectors
    for k in range(3): ev(B[2] + 1.8 + k * 0.2, "pop", 0.7)      # agent cards
    for k in range(3): ev(B[2] + 5.1 + k * 0.35, "chime", 0.55)  # each done
    ev(B[2] + 7.7, "thump", 0.8)

# title
ev(B[3] + 0.2, "thump", 0.7); ev(B[3] + 0.6, "pop", 0.9)
for k in range(3): ev(B[3] + 1.7 + k * 0.2, "tick", 0.5)

# feature beats b5-b9
for bi in (4, 5, 6, 7, 8):
    ev(B[bi] + 0.25, "pop", 0.9); ev(B[bi] + 0.9, "tick", 0.7); ev(B[bi] + 1.6, "tick", 0.5)
for k in range(8): ev(B[7] + 0.8 + k * 0.25, "clock", 0.3)   # numbers counter (b8)

# closer + outro
ev(B[9] + 0.3, "pop", 0.9); ev(B[9] + 1.0, "thump", 0.6); ev(B[9] + 2.2, "chime", 0.8)
ev(53.6, "pop", 0.7); ev(54.4, "tick", 0.6); ev(55.2, "chime", 0.6)

N = int(TOTAL * SR); buf = [0.0] * N
for t, k, g in events:
    s = GEN[k](g); i0 = int(t * SR)
    for j, v in enumerate(s):
        if 0 <= i0 + j < N: buf[i0 + j] += v
peak = max(abs(v) for v in buf) or 1.0; norm = min(1.0, 0.85 / peak)
OUT = f"/Users/davendrapatel/videoclaw/projects/{slug}/artifacts/audio/v2/sfx.wav"
with wave.open(OUT, "wb") as w:
    w.setnchannels(2); w.setsampwidth(2); w.setframerate(SR)
    fr = bytearray()
    for v in buf:
        sm = int(max(-1, min(1, v * norm)) * 32767); fr += struct.pack("<hh", sm, sm)
    w.writeframes(bytes(fr))
print(f"{slug} v2 sfx ({setpiece}): {len(events)} events -> {OUT}")
