131 lines
4.6 KiB
Python
131 lines
4.6 KiB
Python
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
import numpy as np
|
|
|
|
from audio_field.cultcache_audio import (
|
|
SPATIAL_AUDIO_SCHEMA_ID,
|
|
frame_to_numpy,
|
|
get_live_audio_phase_field,
|
|
get_live_audio_source_events,
|
|
get_live_mic_field_frame,
|
|
get_live_spatial_audio_frame,
|
|
make_audio_phase_field,
|
|
make_audio_source_events,
|
|
make_mic_field_frame,
|
|
make_spatial_audio_frame,
|
|
mic_field_to_numpy,
|
|
put_live_audio_phase_field,
|
|
put_live_audio_source_events,
|
|
put_live_mic_field_frame,
|
|
put_live_spatial_audio_frame,
|
|
)
|
|
|
|
|
|
class SpatialAudioCultCacheTests(unittest.TestCase):
|
|
def test_spatial_audio_frame_round_trips_float32_ambix_block(self):
|
|
block = np.arange(32, dtype=np.float32).reshape(8, 4) / 32.0
|
|
frame = make_spatial_audio_frame(
|
|
block,
|
|
frame_id=12,
|
|
sample_rate=48000,
|
|
start_sample=1024,
|
|
audio_time_ns=50_000,
|
|
)
|
|
|
|
self.assertEqual(SPATIAL_AUDIO_SCHEMA_ID, frame.schema_version)
|
|
self.assertEqual(("W", "Y", "Z", "X"), frame.channels)
|
|
self.assertEqual("ACN", frame.channel_order)
|
|
self.assertEqual("SN3D", frame.normalization)
|
|
np.testing.assert_allclose(block, frame_to_numpy(frame))
|
|
|
|
def test_live_spatial_audio_frame_round_trips_through_cultcache(self):
|
|
block = np.ones((16, 4), dtype=np.float32)
|
|
frame = make_spatial_audio_frame(block, frame_id=3, sample_rate=48000, start_sample=2048, audio_time_ns=90_000)
|
|
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
path = Path(tmp) / "audio-state.msgpack"
|
|
put_live_spatial_audio_frame(path, frame)
|
|
loaded = get_live_spatial_audio_frame(path)
|
|
|
|
self.assertIsNotNone(loaded)
|
|
self.assertEqual(3, loaded.frame_id)
|
|
self.assertEqual(2048, loaded.start_sample)
|
|
np.testing.assert_allclose(block, frame_to_numpy(loaded))
|
|
|
|
def test_live_source_events_round_trip_through_cultcache(self):
|
|
events = make_audio_source_events(
|
|
frame_id=7,
|
|
sample_rate=48000,
|
|
start_sample=4096,
|
|
frame_count=1024,
|
|
audio_time_ns=123,
|
|
events=[{"eventId": 1, "positionMeters": [1.0, 2.0, 3.0], "confidence": 0.8}],
|
|
voice_focus=[{"anchorChannel": 4, "weight": 1.0}],
|
|
)
|
|
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
path = Path(tmp) / "audio-events.msgpack"
|
|
put_live_audio_source_events(path, events)
|
|
loaded = get_live_audio_source_events(path)
|
|
|
|
self.assertIsNotNone(loaded)
|
|
self.assertEqual(48000, loaded.sample_rate)
|
|
self.assertEqual(1, loaded.events[0]["eventId"])
|
|
self.assertEqual(4, loaded.voice_focus[0]["anchorChannel"])
|
|
|
|
def test_live_phase_field_round_trip_through_cultcache(self):
|
|
field = make_audio_phase_field(
|
|
frame_id=8,
|
|
sample_rate=48000,
|
|
start_sample=8192,
|
|
frame_count=4096,
|
|
audio_time_ns=456,
|
|
reference_id="local-loopback",
|
|
sources=[
|
|
{
|
|
"sourceId": "host-focusrite",
|
|
"delaySamples": 12.5,
|
|
"confidence": 0.92,
|
|
"suppressionWeight": 0.6,
|
|
}
|
|
],
|
|
global_confidence=0.72,
|
|
needs_active_probe=False,
|
|
)
|
|
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
path = Path(tmp) / "audio-phase-field.msgpack"
|
|
put_live_audio_phase_field(path, field)
|
|
loaded = get_live_audio_phase_field(path)
|
|
|
|
self.assertIsNotNone(loaded)
|
|
self.assertEqual("local-loopback", loaded.reference_id)
|
|
self.assertEqual(12.5, loaded.sources[0]["delaySamples"])
|
|
self.assertFalse(loaded.needs_active_probe)
|
|
|
|
def test_live_mic_field_round_trip_through_cultcache(self):
|
|
block = np.arange(48, dtype=np.float32).reshape(8, 6) / 48.0
|
|
frame = make_mic_field_frame(
|
|
block,
|
|
frame_id=11,
|
|
sample_rate=48000,
|
|
start_sample=512,
|
|
audio_time_ns=789,
|
|
)
|
|
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
path = Path(tmp) / "audio-mic-field.msgpack"
|
|
put_live_mic_field_frame(path, frame)
|
|
loaded = get_live_mic_field_frame(path)
|
|
|
|
self.assertIsNotNone(loaded)
|
|
self.assertEqual("localcast.faust.voice_separation.v1", loaded.graph_id)
|
|
self.assertEqual(6, len(loaded.channels))
|
|
self.assertEqual("host-voice-anchor", loaded.roles[0]["role"])
|
|
np.testing.assert_allclose(block, mic_field_to_numpy(loaded))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|