Source code for jdxi_editor.ui.widgets.digital.builder

"""
Digital Display Builder

Builds JDXiDisplayState from program, tone, or parsed SysEx data.
"""

from typing import Any, Dict, Optional

from jdxi_editor.midi.sysex.sections import SysExSection
from jdxi_editor.ui.widgets.digital.state import JDXiDisplayState

# Map display synth key to program attribute (JDXiProgram or dict)
[docs] _SYNTH_TO_PROGRAM_ATTR = { "D1": "digital_1", "D2": "digital_2", "DR": "drums", "AN": "analog", }
# Map SysEx address (from input_handler) to display synth key
[docs] _SYSEX_ADDRESS_TO_SYNTH = { "12180000": None, # Program common: program name, not a tone "12190100": "D1", "12192100": "D2", "12194200": "AN", "12197000": "DR", }
[docs] class DisplayStateBuilder: """Builds JDXiDisplayState from program, tone, or parsed SysEx data.""" @staticmethod
[docs] def from_program( program: Any, active_synth: str, octave: int = 0, ) -> JDXiDisplayState: """Build display state from a program (JDXiProgram or dict) and active synth. :param program: JDXiProgram or dict with id, name, digital_1, digital_2, drums, analog. :param active_synth: "D1" | "D2" | "DR" | "AN". :param octave: Current octave (default 0). :return: JDXiDisplayState. """ program_name = _get_attr(program, "name") or "Untitled Program" program_id = _get_attr(program, "id") or "" attr = _SYNTH_TO_PROGRAM_ATTR.get(active_synth, "digital_1") tone_name = _get_attr(program, attr) or "Init Tone" return JDXiDisplayState( synth=active_synth, program_name=program_name, program_id=program_id, tone_name=tone_name, tone_number=0, octave=octave, )
@staticmethod
[docs] def from_tone( tone_name: str, tone_number: int = 0, active_synth: str = "D1", program_name: Optional[str] = None, program_id: Optional[str] = None, octave: int = 0, ) -> JDXiDisplayState: """Build display state from tone-focused data. :param tone_name: Name of the tone. :param tone_number: Tone/preset number (default 0). :param active_synth: "D1" | "D2" | "DR" | "AN" (default "D1"). :param program_name: Optional program name. :param program_id: Optional program id (e.g. "A01"). :param octave: Current octave (default 0). :return: JDXiDisplayState. """ return JDXiDisplayState( synth=active_synth, program_name=program_name or "", program_id=program_id or "", tone_name=tone_name or "Init Tone", tone_number=tone_number, octave=octave, )
@staticmethod
[docs] def from_sysex( parsed_data: Dict[str, Any], program_name: Optional[str] = None, program_id: Optional[str] = None, octave: int = 0, ) -> Optional[JDXiDisplayState]: """Build display state from parsed SysEx message (e.g. from JDXiSysExParser). :param parsed_data: Dict with ADDRESS and TONE_NAME (SysExSection keys). :param program_name: Optional program name when known. :param program_id: Optional program id when known. :param octave: Current octave (default 0). :return: JDXiDisplayState, or None if address is program-common only (no tone). """ address = parsed_data.get(SysExSection.ADDRESS) or "" tone_name = parsed_data.get(SysExSection.TONE_NAME) or "" if address == "12180000": return JDXiDisplayState( synth="D1", program_name=tone_name or program_name or "", program_id=program_id or "", tone_name="", tone_number=0, octave=octave, ) synth = _SYSEX_ADDRESS_TO_SYNTH.get(address) if synth is None: return None return JDXiDisplayState( synth=synth, program_name=program_name or "", program_id=program_id or "", tone_name=tone_name or "Init Tone", tone_number=0, octave=octave, )
[docs] def _get_attr(obj: Any, key: str) -> Optional[str]: """Get attribute or dict key; return None if missing.""" if obj is None: return None if isinstance(obj, dict): return obj.get(key) return getattr(obj, key, None)