| |
| """LYGO Phase 9 — live biometric seed → LDQ friction audio (WAV).""" |
|
|
| from __future__ import annotations |
|
|
| import argparse |
| import json |
| import sys |
| import wave |
| from pathlib import Path |
|
|
| import numpy as np |
|
|
| ROOT = Path(__file__).resolve().parents[1] |
| sys.path.insert(0, str(ROOT)) |
|
|
| from protocol8_ldq_synthesis import FrictionCore, HarmonicGravity, LYRASequencer, P8_VERSION |
|
|
| P0_GOLDEN = ROOT / "protocol0_nano_kernel" / "fixtures" / "p0_canonical.sha256" |
| DEFAULT_SEED_PATH = ROOT / "tools" / "lygo_control_center" / "workspace" / "latest_seed.json" |
| P9_SYNTH_VERSION = "Δ9Φ963-PHASE9-SYNTH-v1.0" |
|
|
|
|
| def _default_seed_hex() -> str: |
| if DEFAULT_SEED_PATH.is_file(): |
| try: |
| data = json.loads(DEFAULT_SEED_PATH.read_text(encoding="utf-8")) |
| seed = data.get("seed") or data.get("seed_hex") |
| if seed: |
| return str(seed).replace("0x", "")[:64] |
| except json.JSONDecodeError: |
| pass |
| if P0_GOLDEN.is_file(): |
| return P0_GOLDEN.read_text(encoding="utf-8").strip().split()[0][:16] |
| return "7e8d18fda979cbef" |
|
|
|
|
| def generate_audio_from_seed( |
| seed_hex: str, |
| output_file: str | Path = "synthesis_output.wav", |
| *, |
| duration_sec: float = 5.0, |
| sample_rate: int = 44100, |
| ) -> dict: |
| clean = str(seed_hex).replace("0x", "").strip() |
| seed_int = int(clean[:16], 16) if clean else 0 |
| gravity = HarmonicGravity(seed_int) |
| params = gravity.get_all_parameters() |
| root_freq = params["root_frequency"] |
| intensity = params["intensity"] |
| friction = FrictionCore(phi_risk=0.618) |
| sequencer = LYRASequencer(seed_int) |
| structure = sequencer.generate_structure(num_blocks=8) |
|
|
| n = int(sample_rate * duration_sec) |
| t = np.linspace(0.0, duration_sec, n, endpoint=False) |
| signal = np.zeros(n, dtype=np.float64) |
| block_len = max(1, n // len(structure)) |
| for i, block in enumerate(structure): |
| start = i * block_len |
| end = min(n, (i + 1) * block_len) |
| seg_t = t[start:end] |
| partial = block["gate"] / 9.0 |
| freq = root_freq * (1.0 + partial * 0.12) |
| amp = intensity * (1.2 if block["accent"] else 0.85) |
| signal[start:end] = amp * np.sin(2.0 * np.pi * freq * seg_t) |
| signal = friction.process(signal) |
| peak = float(np.max(np.abs(signal))) or 1.0 |
| signal = signal / peak |
| out = Path(output_file) |
| out.parent.mkdir(parents=True, exist_ok=True) |
| with wave.open(str(out), "wb") as wf: |
| wf.setnchannels(1) |
| wf.setsampwidth(2) |
| wf.setframerate(sample_rate) |
| wf.writeframes((signal * 32767.0).astype(np.int16).tobytes()) |
| return { |
| "ok": True, |
| "output": str(out.resolve()), |
| "duration_sec": duration_sec, |
| "sample_rate": sample_rate, |
| "samples": n, |
| "root_frequency": root_freq, |
| "blocks": len(structure), |
| "seed_hex_prefix": clean[:16], |
| "signature": P9_SYNTH_VERSION, |
| "ldq": P8_VERSION, |
| } |
|
|
|
|
| def main() -> int: |
| ap = argparse.ArgumentParser(description="LYGO live LDQ synthesis") |
| ap.add_argument("--seed", default=None) |
| ap.add_argument("--output", default="synthesis_output.wav") |
| ap.add_argument("--duration", type=float, default=5.0) |
| args = ap.parse_args() |
| seed = args.seed or _default_seed_hex() |
| result = generate_audio_from_seed(seed, args.output, duration_sec=args.duration) |
| print(json.dumps(result, indent=2)) |
| return 0 if result.get("ok") else 1 |
|
|
|
|
| if __name__ == "__main__": |
| raise SystemExit(main()) |