Source code for jdxi_editor.midi.sysex.parser.dynamic

"""
Dynamic Parameter Map resolver
"""

from typing import Dict

from decologr import Decologr as log

from jdxi_editor.core.jdxi import JDXi
from jdxi_editor.midi.data.address.address import (
    JDXiSysExOffsetTemporaryToneUMB as TemporaryToneUMB,
)
from jdxi_editor.midi.data.parameter.drum.partial import DrumPartialParam
from jdxi_editor.midi.data.parameter.system.common import SystemCommonParam
from jdxi_editor.midi.data.parameter.system.controller import SystemControllerParam
from jdxi_editor.midi.map.parameter_address import (
    JDXiMapParameterAddress,
)
from jdxi_editor.midi.message.sysex.offset import JDXiSysExMessageLayout
from jdxi_editor.midi.sysex.parser.tone_mapper import (
    get_drum_tone,
    get_program_section,
    get_synth_tone,
    get_temporary_area,
)
from jdxi_editor.midi.sysex.parser.utils import (
    _return_minimal_metadata,
    initialize_parameters,
    update_data_with_parsed_parameters,
    update_short_data_with_parsed_parameters,
)
from jdxi_editor.midi.sysex.sections import SysExSection


[docs] def dynamic_map_resolver(data: bytes) -> Dict[str, str]: """ Dynamically resolve mappings for SysEx data. :param data: bytes SysEx message data :return: Dict[str, str] """ try: # Extract temporary area temporary_area = get_temporary_area(data) # Handle drum tones, program sections, and system areas dynamically address_lmb = data[JDXiSysExMessageLayout.ADDRESS.LMB] if temporary_area == TemporaryToneUMB.DRUM_KIT.name: synth_tone, offset = get_drum_tone(address_lmb) elif temporary_area == "TEMPORARY_PROGRAM": synth_tone, offset = get_program_section(address_lmb) elif temporary_area in ("SYSTEM_COMMON", "SYSTEM_CONTROLLER"): synth_tone = "COMMON" offset = 0 else: synth_tone, offset = get_synth_tone(address_lmb) # Resolve parameter class dynamically parameter_cls = JDXiMapParameterAddress.MAP.get( (temporary_area, synth_tone), DrumPartialParam # Default fallback ) # Log the mappings for debugging log.parameter("temporary_area", temporary_area) log.parameter("synth_tone", synth_tone) log.parameter( "parameter_cls", parameter_cls.__name__ if parameter_cls else "None" ) return { SysExSection.TEMPORARY_AREA: temporary_area, SysExSection.SYNTH_TONE: synth_tone, "PARAMETER_CLASS": parameter_cls.__name__ if parameter_cls else "Unknown", } except Exception as ex: log.error(f"Error resolving mappings: {ex}") return { SysExSection.TEMPORARY_AREA: "Error", SysExSection.SYNTH_TONE: "Error", "PARAMETER_CLASS": "Error", }
[docs] def parse_sysex_with_dynamic_mapping(data: bytes) -> Dict[str, str]: """ Parse SysEx data using dynamic mapping. :param data: bytes SysEx message data :return: Dict[str, str] """ # Log the raw data log.parameter("data", data, silent=True) if len(data) < JDXi.Midi.SYSEX.PARAMETER.LENGTH.ONE_BYTE: log.warning("Insufficient data length for parsing.") return _return_minimal_metadata(data) # Use dynamic map resolver resolved_mapping = dynamic_map_resolver(data) # Initialize parameters using resolved mappings parsed_data = initialize_parameters(data) # Get parameter type from resolved mapping parameter_cls_name = resolved_mapping.get("PARAMETER_CLASS", "Unknown") parameter_cls = globals().get(parameter_cls_name, None) # Update parsed data with parameters if parameter_cls: if len(data) < JDXi.Midi.SYSEX.PARAMETER.LENGTH.FOUR_BYTE: update_short_data_with_parsed_parameters(data, parameter_cls, parsed_data) else: update_data_with_parsed_parameters(data, parameter_cls, parsed_data) # Log the parsed data log.json(parsed_data, silent=True) return parsed_data