1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
|
from typing import TYPE_CHECKING, Optional
from patshared import PortMode, PortType, PortSubType, Naming, JackMetadata
from ..patchcanvas import patchcanvas
from .elements import JackPortFlag
from .connection import Connection
if TYPE_CHECKING:
from ..patchbay_manager import PatchbayManager
from .group import Group
class Port:
graceful_name = ''
group: 'Group'
group_id = -1
portgroup_id = 0
prevent_stereo = False
last_digit_to_add = ''
in_canvas = False
order: Optional[int] = None
uuid = 0
'contains the real JACK uuid'
def __init__(self, manager: 'PatchbayManager', port_id: int, name: str,
port_type: PortType, flags: int, uuid: int):
self.manager = manager
self.port_id = port_id
self.full_name = name
self.type = port_type
self.flags = flags
self.uuid = uuid
self.subtype = PortSubType.REGULAR
match port_type:
case PortType.AUDIO_JACK:
if (flags & JackPortFlag.IS_CONTROL_VOLTAGE
or self.mdata_signal_type == 'CV'):
self.subtype = PortSubType.CV
case PortType.MIDI_JACK:
if self.full_name.startswith(('a2j:', 'Midi-Bridge:')):
self.subtype = PortSubType.A2J
self.conns_hidden_in_canvas = set[Connection]()
def __repr__(self) -> str:
return f"Port({self.full_name})"
@property
def mode(self) -> PortMode:
if self.flags & JackPortFlag.IS_OUTPUT:
return PortMode.OUTPUT
if self.flags & JackPortFlag.IS_INPUT:
return PortMode.INPUT
return PortMode.NULL
@property
def full_type(self) -> tuple[PortType, PortSubType]:
return (self.type, self.subtype)
@property
def short_name(self) -> str:
if (self.type is PortType.MIDI_ALSA
and self.full_name.startswith((':ALSA_IN:', ':ALSA_OUT:'))):
return ':'.join(self.full_name.split(':')[5:])
if self.full_name.startswith('a2j:'):
long_name = self.full_name.partition(':')[2]
if ': ' in long_name:
# normal case for a2j
return long_name.partition(': ')[2]
if self.full_name.startswith('Midi-Bridge:'):
# suppress 'Midi-Bridge:' at port name begginning
long_name = self.full_name.partition(':')[2]
if ') ' in long_name:
# normal case, name is after ') '
return long_name.partition(') ')[2]
if ': ' in long_name:
# pipewire jack.filter_name = True
# Midi-bridge names starts with 'MidiBridge:ClientName:'
return long_name.partition(': ')[2]
return self.full_name.partition(':')[2]
@property
def cnv_name(self):
'The name of this port in the canvas, depending on Naming options'
if self.manager.naming & Naming.METADATA_PRETTY:
mdata_pretty_name = self.mdata_pretty_name
if mdata_pretty_name:
return mdata_pretty_name
if self.manager.naming & Naming.CUSTOM:
custom_name = self.custom_name
if custom_name:
return custom_name
if self.manager.naming & Naming.GRACEFUL:
return self.graceful_name
return self.short_name
@property
def mdata_pretty_name(self) -> str:
if not self.uuid:
return ''
return self.manager.jack_metadatas.pretty_name(self.uuid)
@property
def mdata_portgroup(self) -> str:
if not self.uuid:
return ''
return self.manager.jack_metadatas.str_for_key(
self.uuid, JackMetadata.PORT_GROUP)
@property
def mdata_signal_type(self) -> str:
if not self.uuid:
return ''
return self.manager.jack_metadatas.str_for_key(
self.uuid, JackMetadata.SIGNAL_TYPE)
@property
def custom_name(self) -> str:
'The custom name of this port, if it exists'
return self.manager.custom_names.custom_port(self.full_name_id_free)
@property
def alsa_client_id(self) -> int:
if self.type is not PortType.MIDI_ALSA:
return -1
splitted_name = self.full_name.split(':')
if len(splitted_name) < 6:
return -1
alsa_client_id_str = splitted_name[2]
if not alsa_client_id_str.isdigit():
return -1
return int(alsa_client_id_str)
@property
def full_name_id_free(self) -> str:
'full_name without alsa client or port id, useful for pretty_names'
if self.type is PortType.MIDI_ALSA:
names = self.full_name.split(':')
return ':'.join(names[0:2] + names[4:])
return self.full_name
def add_the_last_digit(self):
self.graceful_name += ' ' + self.last_digit_to_add
self.last_digit_to_add = ''
self.rename_in_canvas()
def add_to_canvas(self, ignore_gpos=False, hidden_sides=PortMode.NULL):
if self.manager.very_fast_operation:
return
if self.in_canvas:
return
if not self.manager.port_type_shown(self.full_type):
return
if ignore_gpos:
if hidden_sides & self.mode:
return
else:
if self.group.current_position.hidden_port_modes() & self.mode:
return
patchcanvas.add_port(
self.group_id, self.port_id, self.cnv_name,
self.mode, self.type, self.subtype)
self.in_canvas = True
if self.conns_hidden_in_canvas:
visible_conns = set[Connection]()
for conn in self.conns_hidden_in_canvas:
for other_port in (conn.port_out, conn.port_in):
if other_port is self:
continue
if other_port.in_canvas:
visible_conns.add(conn)
other_port.set_hidden_conn_in_canvas(conn, False)
for conn in visible_conns:
self.set_hidden_conn_in_canvas(conn, False)
if self.conns_hidden_in_canvas:
patchcanvas.port_has_hidden_connection(
self.group_id, self.port_id,
bool(self.conns_hidden_in_canvas))
def remove_from_canvas(self):
if self.manager.very_fast_operation:
return
if not self.in_canvas:
return
patchcanvas.remove_port(self.group_id, self.port_id)
self.in_canvas = False
if self.conns_hidden_in_canvas:
for conn in self.conns_hidden_in_canvas:
for other_port in (conn.port_out, conn.port_in):
if other_port is self:
continue
def rename_in_canvas(self):
if not self.in_canvas:
return
patchcanvas.rename_port(
self.group_id, self.port_id, self.cnv_name)
def select_in_canvas(self):
if not self.in_canvas:
return
patchcanvas.select_port(self.group_id, self.port_id)
def set_hidden_conn_in_canvas(self, conn: Connection, yesno: bool):
had_hidden_conns = bool(self.conns_hidden_in_canvas)
if yesno:
self.conns_hidden_in_canvas.add(conn)
else:
self.conns_hidden_in_canvas.discard(conn)
if not self.in_canvas:
return
if had_hidden_conns == bool(self.conns_hidden_in_canvas):
return
patchcanvas.port_has_hidden_connection(
self.group_id, self.port_id,
bool(self.conns_hidden_in_canvas))
def __lt__(self, other: 'Port') -> bool:
if self.type != other.type:
return (self.type < other.type)
if self.subtype is not other.subtype:
return self.subtype < other.subtype
if self.order is None and other.order is None:
return self.port_id < other.port_id
if self.order is None:
return False
if other.order is None:
return True
return bool(self.order < other.order)
|