feat(audio): Focusrite 2i2 stereo JACK config for 4CM

Adds:
- AudioConfig.mode field: 'mono' (default) or 'stereo_4cm'
- capture_channels / playback_channels properties for dynamic JACK -i/-o counts
- FOCUSRITE_PROFILES dict with focusrite_2i2_3gen entry
- AudioSystem.channel_mapping_help() static method
- stereo_4cm port auto-connect wiring (4 cable method)
- Systemd service content uses dynamic channel counts
- Default config YAML includes 'mode: mono'
- 11 new tests (31 total pass)
- Focusrite 4CM wiring docs in docs/config-audio.md
This commit is contained in:
2026-06-08 10:40:38 -04:00
parent 80011274f2
commit c2071a9724
5 changed files with 234 additions and 6 deletions
+68
View File
@@ -10,6 +10,7 @@ from system.audio import (
AudioSystem,
LATENCY_PROFILES,
I2S_CONFIGS,
FOCUSRITE_PROFILES,
CONFIG_TXT,
JACK_SERVICE_PATH,
LIMITS_CONF,
@@ -187,6 +188,73 @@ def test_systemd_service_content_custom_device():
assert "-dhw:2,0" in content
# ── Mode / stereo_4cm tests ───────────────────────────────────────
def test_audio_config_mode_default():
cfg = AudioConfig()
assert cfg.mode == "mono"
def test_audio_config_mode_stereo_4cm():
cfg = AudioConfig(mode="stereo_4cm")
assert cfg.mode == "stereo_4cm"
def test_audio_config_channel_counts_mono():
cfg = AudioConfig(mode="mono")
assert cfg.capture_channels == 1
assert cfg.playback_channels == 1
def test_audio_config_channel_counts_stereo_4cm():
cfg = AudioConfig(mode="stereo_4cm")
assert cfg.capture_channels == 2
assert cfg.playback_channels == 2
def test_audio_config_focusrite_profile_hit():
cfg = AudioConfig(hat_type="focusrite_2i2_3gen")
prof = cfg.focusrite_profile
assert prof is not None
desc, cap, play = prof
assert "Focusrite" in desc
assert cap == 2
assert play == 2
def test_audio_config_focusrite_profile_miss():
cfg = AudioConfig()
assert cfg.focusrite_profile is None
def test_focusrite_profiles_entries():
for key, (desc, cap, play) in FOCUSRITE_PROFILES.items():
assert len(desc) > 10
assert isinstance(cap, int) and cap > 0
assert isinstance(play, int) and play > 0
def test_channel_mapping_help_mono():
mapping = AudioSystem.channel_mapping_help("mono")
assert len(mapping) == 1
assert mapping[0]["capture_port"] == "system:capture_1"
assert mapping[0]["playback_port"] == "system:playback_1"
def test_channel_mapping_help_stereo_4cm():
mapping = AudioSystem.channel_mapping_help("stereo_4cm")
assert len(mapping) == 2
assert "Guitar" in mapping[0]["description"]
assert "FX Send" in mapping[1]["description"]
def test_channel_mapping_help_unknown():
import pytest
with pytest.raises(ValueError, match="Unknown mode"):
AudioSystem.channel_mapping_help("bogus")
# ── Module exports ────────────────────────────────────────────────