diff --git a/player/content.py b/player/content.py new file mode 100644 index 0000000..035808d --- /dev/null +++ b/player/content.py @@ -0,0 +1,42 @@ +"""Resolve the 7-way content dial into an audio source + video on/off (§6). + +The single source of truth for design §6's table: which audio source plays and +whether the projector shows video, for each dial position. +""" + +from __future__ import annotations + +from dataclasses import dataclass + +# The four distinct audio sources. "white_noise" is generated at runtime; +# "music" is the public-domain classical pool; "audio_track" is the clip's own +# field audio; "none" is silence. +AUDIO_SOURCES = frozenset({"none", "white_noise", "music", "audio_track"}) + + +@dataclass(frozen=True) +class ContentResolution: + audio_source: str + video: bool + + +# Design §6, one row per dial position. +_TABLE = { + "off": ContentResolution("none", False), + "white_noise": ContentResolution("white_noise", False), + "music": ContentResolution("music", False), + "audio_track": ContentResolution("audio_track", False), + "video": ContentResolution("none", True), + "music_video": ContentResolution("music", True), + "audio_video": ContentResolution("audio_track", True), +} + + +def resolve_content(position: str) -> ContentResolution: + """Map a content-dial position to its audio source and video flag (§6).""" + try: + return _TABLE[position] + except KeyError: + raise ValueError( + f"unknown content position {position!r}; expected one of {sorted(_TABLE)}" + ) from None diff --git a/tests/test_player_content.py b/tests/test_player_content.py new file mode 100644 index 0000000..70b3d4e --- /dev/null +++ b/tests/test_player_content.py @@ -0,0 +1,34 @@ +import pytest + +from player.content import AUDIO_SOURCES, ContentResolution, resolve_content + + +def test_audio_sources_are_the_four_distinct_sources(): + assert AUDIO_SOURCES == frozenset({"none", "white_noise", "music", "audio_track"}) + + +# The §6 table, row by row: position -> (audio_source, video). +@pytest.mark.parametrize( + "position,audio_source,video", + [ + ("off", "none", False), + ("white_noise", "white_noise", False), + ("music", "music", False), + ("audio_track", "audio_track", False), + ("video", "none", True), + ("music_video", "music", True), + ("audio_video", "audio_track", True), + ], +) +def test_resolve_content_matches_spec_table(position, audio_source, video): + assert resolve_content(position) == ContentResolution(audio_source=audio_source, video=video) + + +def test_off_is_void_state_black_and_silent(): + r = resolve_content("off") + assert r.video is False and r.audio_source == "none" + + +def test_resolve_content_rejects_unknown_position(): + with pytest.raises(ValueError): + resolve_content("bogus")