HOA7 Spatial Field Decoder (hoa64 v0.5.0): 7th-order Ambisonics encode/decode, Wigner-D rotation, DOA analysis, vision fuse, diffusion conditioning
570b87b verified | #!/usr/bin/env python3 | |
| """Phase 3 + Qwythos wiring demo: vision boxes, fuse with audio, HTTP API.""" | |
| from __future__ import annotations | |
| import json | |
| import sys | |
| import urllib.request | |
| from pathlib import Path | |
| sys.path.insert(0, str(Path(__file__).resolve().parents[1])) | |
| from hoa64.report import report_from_scene | |
| from hoa64.stream import SourceSpec | |
| from hoa64.synth import envelope_adsr, tone | |
| from hoa64.vision import fuse_reports, report_from_boxes | |
| def main() -> None: | |
| sr = 48000 | |
| dur = 0.4 | |
| n = int(sr * dur) | |
| env = envelope_adsr(n, sr) | |
| audio_rep = report_from_scene( | |
| [ | |
| SourceSpec(20.0, 0.0, tone(500, dur, sr, amplitude=0.5) * env, "beep"), | |
| ], | |
| sr, | |
| max_order=3, | |
| ) | |
| vision_rep = report_from_boxes( | |
| [ | |
| {"az": 25.0, "el": 2.0, "w_deg": 12, "h_deg": 12, "weight": 1.0, "label": "speaker"}, | |
| {"az": -100.0, "el": 0.0, "w_deg": 8, "h_deg": 8, "weight": 0.3, "label": "clutter"}, | |
| ], | |
| max_order=3, | |
| ) | |
| fused = fuse_reports(audio_rep.to_dict(), {**vision_rep.to_dict(), "one_liner": vision_rep.one_liner()}) | |
| print("AUDIO ", audio_rep.one_liner()) | |
| print("VISION", vision_rep.one_liner()) | |
| print("FUSE ", fused["one_liner"]) | |
| print(json.dumps({"agreement": fused["agreement"], "sep_deg": fused["angular_separation_deg"]}, indent=2)) | |
| # Optional live API check | |
| try: | |
| req = urllib.request.Request( | |
| "http://127.0.0.1:8765/health", | |
| method="GET", | |
| ) | |
| with urllib.request.urlopen(req, timeout=1) as r: | |
| health = json.loads(r.read().decode()) | |
| print("API ", health) | |
| req = urllib.request.Request( | |
| "http://127.0.0.1:8765/v1/spatial/analyze", | |
| data=json.dumps({"mode": "vision", "order": 3, "boxes": [{"az": 0, "el": 0, "kind": "point"}]}).encode(), | |
| headers={"Content-Type": "application/json"}, | |
| method="POST", | |
| ) | |
| with urllib.request.urlopen(req, timeout=5) as r: | |
| api = json.loads(r.read().decode()) | |
| print("API vision one_liner:", api.get("one_liner")) | |
| except Exception as e: | |
| print(f"API not running yet ({e}); start: systemctl --user start spatial-hoa") | |
| print("\nPhase 3 vision + fuse ready. Qwythos: curl :8765 or spatial-report CLI.") | |
| if __name__ == "__main__": | |
| main() | |