Add HeadsetActiveEQPreset selector

Choice setting that lists all 16 EQ slots — 6 read-only factory
presets and 10 user-custom slots — by their getEQFriendlyName,
with "(factory)" tagging the read-only ones. Selecting calls
setActiveEQ to switch which slot drives live audio. Activation
works for any slot regardless of writability; the read-only
distinction matters only for band edits (not implemented yet).

Placed directly above HeadsetAdvancedEQ in SETTINGS so the picker
sits above the band-display panel that reflects whichever slot is
currently active.

After a successful write, drop the AdvancedParaEQ panel's cached
_value so the next read pulls the new active slot's bands. The
visible band update happens on the next refresh of that panel —
auto-redraw on selector change would need UI-side plumbing we
don't currently expose; manual refresh / panel reopen works for
read-only verification.
This commit is contained in:
Ken Sanislo 2026-04-24 21:02:55 -07:00
parent be68d48df5
commit df178225d0
1 changed files with 54 additions and 0 deletions

View File

@ -2013,6 +2013,59 @@ class HeadsetAdvancedEQ(settings.RangeFieldSetting):
return None
class HeadsetActiveEQPreset(settings.Setting):
"""Choose which AdvancedParaEQ slot drives live audio.
Activation works for any slot read-only factory presets and
user-custom slots alike. The "(factory)" tag in the slot label
distinguishes the read-only ones; that distinction matters for
band-editing (not supported yet), not for activation today.
"""
name = "headset-eq-active-preset"
label = _("EQ Preset")
description = _("Switch the active EQ preset. Factory presets are read-only.")
feature = _F.HEADSET_ADVANCED_PARA_EQ
rw_options = {"read_fnid": 0x30, "write_fnid": 0x40, "prefix": b"\x00"}
validator_class = settings_validator.ChoicesValidator
@classmethod
def build(cls, device):
info = getattr(device, "_advanced_eq_info", None) or hidpp20.get_advanced_eq_info(device)
if not info:
return None
ro_count = info.get("onboard_ro_preset_count", 0) or 0
custom_count = info.get("onboard_custom_preset_count", 0) or 0
total = ro_count + custom_count
if total == 0:
return None
choices = common.NamedInts()
for slot in range(total):
slot_name = hidpp20.get_advanced_eq_friendly_name(device, direction=0, slot=slot)
if not slot_name:
slot_name = _("Slot") + " " + str(slot)
if slot < ro_count:
slot_name = slot_name + " " + _("(factory)")
choices[slot] = slot_name
rw = settings.FeatureRW(cls.feature, **cls.rw_options)
validator = settings_validator.ChoicesValidator(choices=choices)
return cls(device, rw, validator)
def write(self, value, save=True):
result = super().write(value, save)
if result is not None:
# Drop the AdvancedParaEQ band-display cache so the panel's
# next read pulls the new active slot's bands. The visible
# values update on the next refresh of that panel (manual
# refresh icon, panel reopen, or device reconnect) — pushing
# the redraw automatically would need UI-side plumbing we
# don't currently expose from the settings layer.
eq_panel = _headset_setting_by_name(self._device, HeadsetAdvancedEQ.name)
if eq_panel is not None:
eq_panel._value = None
return result
_NO_CHANGE_COLOR = int(special_keys.COLORSPLUS["No change"])
@ -2960,6 +3013,7 @@ SETTINGS: list[settings.Setting] = [
HeadsetMixBalance,
HeadsetAutoSleep,
HeadsetOnboardEQ,
HeadsetActiveEQPreset,
HeadsetAdvancedEQ,
HeadsetLEDControl,
HeadsetLEDsPrimary,