File: port.py

package info (click to toggle)
raysession 0.17.4-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 19,196 kB
  • sloc: python: 44,463; sh: 1,538; makefile: 213; xml: 86
file content (258 lines) | stat: -rw-r--r-- 8,235 bytes parent folder | download
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)