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")