Source code for jdxi_editor.midi.data.parameter.program.zone

"""
ProgramZoneParameter
====================

Defines the ProgramZoneParameter class for managing common program-level
parameters in the JD-Xi synthesizer.

This class provides attributes and methods for handling program-wide settings,
such as program name, level, tempo, and vocal effects. It also includes
methods for retrieving display values, validating parameter values, and
handling partial-specific addressing.

Example usage:

# Create an instance for Program Level
program_level = ProgramCommonParameter(*ProgramCommonParameter.PROGRAM_LEVEL)

# Validate a value within range
validated_value = program_level.validate_value(100)

# Get the display name of a parameter
display_name = program_level.display_name  # "Program Level"

# Get display value range
display_range = program_level.get_display_value()  # (0, 127)

# Retrieve a parameter by name
param = ProgramCommonParameter.get_by_name("PROGRAM_TEMPO")
if param:
    print(param.name, param.min_val, param.max_val)

# Get switch text representation
switch_text = program_level.get_switch_text(1)  # "ON" or "---"
"""

from typing import Optional, Tuple

from picomidi.sysex.parameter.address import AddressParameter


[docs] class ProgramZoneParam(AddressParameter): """Program Common parameters""" def __init__( self, address: int, min_val: Optional[int] = None, max_val: Optional[int] = None, display_min: Optional[int] = None, display_max: Optional[int] = None, partial_number: Optional[int] = 0, ): super().__init__(address, min_val, max_val)
[docs] self.display_min = display_min if display_min is not None else min_val
[docs] self.display_max = display_max if display_max is not None else max_val
[docs] self.partial_number = partial_number
[docs] ARPEGGIO_SWITCH = (0x03, 0, 1, 0, 1) # Arpeggio OFF, ON
[docs] ZONAL_OCTAVE_SHIFT = (0x19, 61, 67, -3, +3) # Octave shift
[docs] def get_display_value(self) -> Tuple[int, int]: """ Get the display value range (min, max) for the parameter :return: Tuple[int, int] The display value range """ if hasattr(self, "display_min") and hasattr(self, "display_max"): return self.display_min, self.display_max return self.min_val, self.max_val
[docs] def get_address_for_partial(self, partial_number: int = 0) -> Tuple[int, int]: """ Get parameter area and address adjusted for partial number. :param partial_number: int The partial number :return: Tuple[int, int] The parameter area and address """ group_map = {0: 0x30, 1: 0x31, 2: 0x32, 3: 0x33} group = group_map.get( partial_number, 0x30 ) # Default to 0x30 if partial_name is not 1, 2, or 3 return group, self.address
@property
[docs] def is_switch(self) -> bool: """ Returns True if parameter is address binary/enum switch :return: bool True if parameter is address binary/enum switch """ return self in [self.ARPEGGIO_SWITCH]
[docs] def get_switch_text(self, value: int) -> str: """ Get display text for switch values :param value: int The value :return: str The display text """ if self == self.ARPEGGIO_SWITCH: return ["OFF", "ON"][value] elif self.is_switch: return "ON" if value else "OFF" return str(value)
[docs] def validate_value(self, value: int) -> int: """ Validate and convert parameter value :param value: int The value :return: int The validated value """ if not isinstance(value, int): raise ValueError(f"Value must be integer, got {type(value)}") # Regular range check if value < self.min_val or value > self.max_val: raise ValueError( f"Value {value} out of range for {self.name} " f"(valid range: {self.min_val}-{self.max_val})" ) return value
[docs] def set_partial_number(self, partial_number: int) -> Optional[int]: """ Returns the partial number (1-4) if this is address partial parameter, None otherwise :param partial_number: int The partial number :return: Optional[int] The partial number """ self.partial_number = partial_number
[docs] def get_partial_number(self) -> Optional[int]: """ Returns the partial number (1-4) if this is address partial parameter, None otherwise :return: Optional[int] The partial number """ return self.partial_number
@staticmethod
[docs] def get_by_name(param_name: str) -> Optional[object]: """ Get the Parameter by name. :param param_name: str The parameter name :return: Optional[object] The parameter Return the parameter member by name, or None if not found """ return ProgramZoneParam.__members__.get(param_name, None)