File size: 3,758 Bytes
570b87b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | """Detector, live pipeline (file), conditioning tests."""
from __future__ import annotations
import json
import sys
import tempfile
from pathlib import Path
import numpy as np
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from hoa64.analysis import angular_error_deg
from hoa64.audio_io import write_wav
from hoa64.conditioning import build_conditioning, comfy_txt2img_payload, spatial_prompt_fragment
from hoa64.detector import (
Detection,
detections_to_sphere_boxes,
load_yolo_labels,
write_demo_image_with_box,
)
from hoa64.live_audio import audio_to_hoa_stream, live_report_from_file, stereo_to_order1_hoa
from hoa64.synth import tone
from hoa64.vision import fuse_reports, report_from_boxes
def test_demo_image_detect_sphere():
with tempfile.TemporaryDirectory() as td:
img = Path(td) / "demo.png"
det = write_demo_image_with_box(img)
boxes = detections_to_sphere_boxes([det])
assert boxes[0]["label"] == "demo_object"
# center of box ~ (0.45, 0.5) → slight left az positive? cx=0.45 → az=(0.5-0.45)*90=+4.5
assert abs(boxes[0]["az"] - 4.5) < 1.0
rep = report_from_boxes(boxes, max_order=3)
assert rep.energy > 0
def test_yolo_labels():
with tempfile.TemporaryDirectory() as td:
p = Path(td) / "labels.txt"
# class 0 center front-ish
p.write_text("0 0.5 0.5 0.2 0.2 0.9\n")
dets = load_yolo_labels(p)
assert len(dets) == 1
boxes = detections_to_sphere_boxes(dets)
assert abs(boxes[0]["az"]) < 1.0 # center → az≈0
def test_live_pipeline_from_synth_wav():
with tempfile.TemporaryDirectory() as td:
wav = Path(td) / "m.wav"
sr = 16000
sig = tone(800, 0.3, sr, amplitude=0.4)
write_wav(wav, sig, sr)
rep = live_report_from_file(wav, az_deg=30.0, el_deg=0.0, max_order=1)
err = angular_error_deg(30.0, 0.0, rep.doa_az_deg, rep.doa_el_deg)
assert err < 8.0, f"err={err}"
def test_stereo_pseudo_hoa():
sr = 8000
L = tone(400, 0.2, sr, amplitude=0.5)
R = tone(400, 0.2, sr, amplitude=0.1)
hoa = stereo_to_order1_hoa(L, R, width_az_deg=40)
assert hoa.shape[0] == 64
# left-dominant → positive Y energy
assert np.mean(hoa[1] ** 2) > 0
def test_conditioning_from_fuse():
audio = {"doa_az_deg": 15.0, "doa_el_deg": 0.0, "energy": 1.0, "kind": "spatial_field"}
vision = {
"doa_az_deg": 18.0,
"doa_el_deg": 2.0,
"energy": 0.5,
"kind": "spatial_vision",
"peak_az_deg": 18.0,
"peak_el_deg": 2.0,
}
fused = fuse_reports(audio, vision)
cond = build_conditioning(fused, base_prompt="cinematic room", style="natural")
assert "cinematic room" in cond["positive_prompt"]
assert cond["schema"] == "spatial-hoa.conditioning.v1"
assert "control_vector" in cond
frag = spatial_prompt_fragment(fused, style="tags")
assert "spatial-az" in frag
# offline payload with explicit checkpoint (no Comfy required)
wf = comfy_txt2img_payload(
cond, checkpoint="sd_xl_base_1.0.safetensors", auto_checkpoint=False
)
assert "3" in wf and wf["6"]["inputs"]["text"]
assert wf["4"]["inputs"]["ckpt_name"] == "sd_xl_base_1.0.safetensors"
assert wf["5"]["inputs"]["width"] == 1024 # XL default size
if __name__ == "__main__":
test_demo_image_detect_sphere()
print("OK test_demo_image_detect_sphere")
test_yolo_labels()
print("OK test_yolo_labels")
test_live_pipeline_from_synth_wav()
print("OK test_live_pipeline_from_synth_wav")
test_stereo_pseudo_hoa()
print("OK test_stereo_pseudo_hoa")
test_conditioning_from_fuse()
print("OK test_conditioning_from_fuse")
|