9cd8292acc
Lint & Validate / lint (push) Has been cancelled
P2-R1: ALSA + JACK2 low-latency config (scripts, quirks, tuning) P2-R2: Carla integration (build scripts, 8ch rack config, NAM LV2 support) P2-R3: Plugin manager, categories, blacklist, NAM model support P3-R1: Mixer DSP engine (channel strip, routing matrix, bus mgr, automation) P4-R1: MIDI engine (learn mode, clock sync, HID discovery, mapping store) P4-R2: Network API (OSC server, FastAPI REST, WebSocket, auth, rate limiter) P5-R1: Touchscreen UI evaluation + main entry point docs: Audio stack, Carla integration, MIDI support, UI evaluation tests: Full test suite (292 passing)
116 lines
3.9 KiB
Python
116 lines
3.9 KiB
Python
"""Tests for mixer parameter registry."""
|
|
|
|
import pytest
|
|
from src.mixer import ParameterRegistry
|
|
from src.midi.types import ParameterType, ParameterCategory
|
|
|
|
|
|
class TestParameterRegistry:
|
|
@pytest.fixture
|
|
def registry(self):
|
|
return ParameterRegistry(channels=8)
|
|
|
|
def test_all_parameters_built(self, registry):
|
|
"""Registry should have all params (master + channels + fx + transport + utility)."""
|
|
params = list(registry.iter_all())
|
|
# Master: 5, FX: 4, Transport: 6, Utility: 4, 8 channels * 25 = 200
|
|
# Total: 5 + 4 + 6 + 4 + 200 = 219
|
|
assert len(params) == 219
|
|
|
|
def test_get_master_volume(self, registry):
|
|
p = registry.get(ParameterType.MASTER_VOLUME)
|
|
assert p is not None
|
|
assert p.param_type == ParameterType.MASTER_VOLUME
|
|
assert p.channel == -1
|
|
assert p.max_val == 12.0
|
|
|
|
def test_get_channel_volume(self, registry):
|
|
p = registry.get(ParameterType.VOLUME, channel=3)
|
|
assert p is not None
|
|
assert p.param_type == ParameterType.VOLUME
|
|
assert p.channel == 3
|
|
assert p.min_val == -60.0
|
|
|
|
def test_get_nonexistent(self, registry):
|
|
p = registry.get(ParameterType.VOLUME, channel=999)
|
|
assert p is None
|
|
|
|
def test_iter_by_category(self, registry):
|
|
channel_params = list(registry.iter_by_category(ParameterCategory.CHANNEL))
|
|
# 8 channels * 25 params = 200
|
|
assert len(channel_params) == 8 * 25
|
|
|
|
master_params = list(registry.iter_by_category(ParameterCategory.MASTER))
|
|
assert len(master_params) == 5
|
|
|
|
def test_iter_by_channel(self, registry):
|
|
ch0 = list(registry.iter_by_channel(0))
|
|
assert len(ch0) == 25 # Full channel strip
|
|
|
|
ch5 = list(registry.iter_by_channel(5))
|
|
assert len(ch5) == 25
|
|
|
|
def test_set_value_and_callback(self, registry):
|
|
values = []
|
|
registry.subscribe(lambda param, value: values.append((param.param_type, value)))
|
|
|
|
registry.set_value(ParameterType.VOLUME, 2, 0.75)
|
|
|
|
assert len(values) == 1
|
|
assert values[0][0] == ParameterType.VOLUME
|
|
assert values[0][1] == 0.75
|
|
|
|
def test_unsubscribe(self, registry):
|
|
values = []
|
|
|
|
def cb(param, value):
|
|
values.append(value)
|
|
|
|
registry.subscribe(cb)
|
|
registry.set_value(ParameterType.VOLUME, 0, 0.5)
|
|
assert len(values) == 1
|
|
|
|
registry.unsubscribe(cb)
|
|
registry.set_value(ParameterType.VOLUME, 0, 0.8)
|
|
assert len(values) == 1 # Not called after unsubscribe
|
|
|
|
def test_set_nonexistent_parameter_no_error(self, registry):
|
|
"""Setting a parameter that doesn't exist should not crash."""
|
|
registry.set_value(ParameterType.VOLUME, 999, 0.5) # No error
|
|
|
|
def test_broken_callback_doesnt_block_others(self, registry):
|
|
def broken(param, value):
|
|
raise RuntimeError("broken")
|
|
|
|
good_values = []
|
|
def good(param, value):
|
|
good_values.append(value)
|
|
|
|
registry.subscribe(broken)
|
|
registry.subscribe(good)
|
|
|
|
registry.set_value(ParameterType.VOLUME, 0, 0.5)
|
|
assert len(good_values) == 1
|
|
assert good_values[0] == 0.5
|
|
|
|
def test_stereo_pan_parameters(self, registry):
|
|
p = registry.get(ParameterType.PAN, channel=0)
|
|
assert p is not None
|
|
assert p.min_val == -1.0
|
|
assert p.max_val == 1.0
|
|
assert p.default_val == 0.0
|
|
|
|
def test_mute_is_boolean(self, registry):
|
|
p = registry.get(ParameterType.MUTE, channel=0)
|
|
assert p is not None
|
|
assert p.min_val == 0.0
|
|
assert p.max_val == 1.0
|
|
assert p.step == 1.0 # Boolean-like
|
|
|
|
def test_transport_params(self, registry):
|
|
play = registry.get(ParameterType.PLAY)
|
|
stop = registry.get(ParameterType.STOP)
|
|
assert play is not None
|
|
assert stop is not None
|
|
assert play.step == 1.0 # Triggered
|