Skip to content

Midi

MIDI ¤

Manages all MIDI communication and target devices

  • System class - (mostly for internal use) provides methods for interacting with all MIDI output ports and sending messages.
  • Targets class - represents the desired MIDI output ports (aka targets) to use when sending commands.
  • Commands class - provides easy to use (no MIDI knowledge required) methods for sending commands to targets.

Note

The corresponding commands will automatically be called when the active setlist, preset, or snapshot changes.

Source code in helixapi\midi.py
  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
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
class MIDI:
    """
    Manages all MIDI communication and target devices

    * System class - (mostly for internal use) provides methods for interacting with all MIDI output ports and sending messages.
    * Targets class - represents the desired MIDI output ports (aka targets) to use when sending commands.
    * Commands class - provides easy to use (no MIDI knowledge required) methods for sending commands to targets.

    !!! note
        The corresponding commands will automatically be called when the active setlist, preset, or snapshot changes.    
    """

    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super(MIDI, cls).__new__(cls, *args, **kwargs)
        return cls._instance

    def __init__(self) -> None:
        """Initialize the MIDI class with settings and devices."""
        if not hasattr(self, '_initialized'):  # Ensure the class is only initialized once
            self.system = self.System()
            self.targets = self.Targets(self.system)
            self.commands = self.Commands(self.targets)
            logging.debug("MIDI initialized with targets: %s", self.targets)
            self._initialized = True

    class System:
        """
        System class for managing MIDI output ports and sending messages.

        !!! note

            While this class is mostly for internal use, it can be used to list MIDI output ports and send messages.
            Most users should use the Commands class instead.
        """
        def __init__(self) -> None:
            self._available_ports = mido.get_output_names()

        @property
        def ports(self) -> List[str]:
            """
            Return a list of available MIDI output ports.

            Returns:
                List[str]: A list of available MIDI output ports.
            """
            logging.debug("Available MIDI ports: %s", self._available_ports)
            return self._available_ports

        def send_cc(self, port: str, channel: int, control: int, value: int) -> None:
            """
            Send a Control Change (CC) message to a MIDI target.

            Args:
                port (str): The name of the MIDI output port.
                channel (int): The MIDI channel to send the message on.
                control (int): The control number.
                value (int): The value to set the control to.
            """
            message = self._create_cc_message(channel, control, value)
            logging.debug("Sending CC message: %s", message)
            self._send_message(port, message)

        def send_pc(self, port: str, channel: int, program: int) -> None:
            """
            Send a Program Change (PC) message to a MIDI target.

            Args:
                port (str): The name of the MIDI output port.
                channel (int): The MIDI channel to send the message on.
                program (int): The program number to change to.
            """
            message = self._create_pc_message(channel, program)
            logging.debug("Sending PC message: %s", message)
            self._send_message(port, message)

        def send_ccpc(self, port: str, cc_channel: int, cc_control: int, cc_value: int, pc_channel: int, pc_program: int) -> None:
            """
            Send both Control Change (CC) and Program Change (PC) messages to a MIDI target.

            Args:
                port (str): The name of the MIDI output port.
                cc_channel (int): The MIDI channel to send the CC message on.
                cc_control (int): The control number for the CC message.
                cc_value (int): The value for the CC message.
                pc_channel (int): The MIDI channel to send the PC message on.
                pc_program (int): The program number for the PC message.
            """
            cc_message = self._create_cc_message(cc_channel, cc_control, cc_value)
            pc_message = self._create_pc_message(pc_channel, pc_program)
            logging.debug("Sending CC message: %s", cc_message)
            logging.debug("Sending PC message: %s", pc_message)
            self._send_message(port, cc_message)
            self._send_message(port, pc_message)

        def _create_cc_message(self, channel: int, control: int, value: int) -> mido.Message:
            """
            Create a Control Change (CC) message.

            Args:
                channel (int): The MIDI channel to send the message on.
                control (int): The control number.
                value (int): The value to set the control to.

            Returns:
                mido.Message: The created CC message.
            """
            return mido.Message('control_change', channel=channel, control=control, value=value)

        def _create_pc_message(self, channel: int, program: int) -> mido.Message:
            """
            Create a Program Change (PC) message.

            Args:
                channel (int): The MIDI channel to send the message on.
                program (int): The program number to change to.

            Returns:
                mido.Message: The created PC message.
            """
            return mido.Message('program_change', channel=channel, program=program)

        def _send_message(self, port: str, message: mido.Message) -> None:
            """
            Send a MIDI message to a specific MIDI target.

            Args:
                port (str): The name of the MIDI output port.
                message (mido.Message): The MIDI message to send.
            """
            with mido.open_output(port) as output:
                output.send(message)
                logging.debug("Sent message: %s to target: %s", message, port)

    class Targets:
        """
        Targets class for managing desired MIDI output ports.

        "Targets" are the MIDI output ports you want commands to be sent to.
        Target names are saved in and loaded from the settings.yaml file.
        """
        def __init__(self, system) -> None:
            self._settings = Settings()
            self._system = system
            self._items = self._load_targets()

        def _load_targets(self) -> List[str]:
            """
            Load targets from settings if they match available ports.

            Returns:
                List[str]: A list of matched MIDI targets.
            """
            saved_targets = self._settings.midi_targets
            logging.debug("Saved MIDI targets: %s", saved_targets)

            matched_targets = []
            for target in saved_targets:
                if target in self._system.ports:
                    matched_targets.append(target)
                else:
                    logging.warning("MIDI target '%s' not matched to any available port.", target)
            return matched_targets

        def __getitem__(self, index):
            return self._items[index]

        def __setitem__(self, index, value):
            self._items[index] = value

        def __len__(self):
            return len(self._items)

        def __iter__(self):
            return iter(self._items)

        def __contains__(self, item):
            return item in self._items

        def save(self) -> None:
            """
            Save the current list of MIDI targets to the settings.
            """
            settings_file = os.path.abspath(os.path.join(os.path.dirname(__file__), 'settings.yaml'))
            with open(settings_file, 'w') as file:
                yaml.safe_dump(self._items, file)
            logging.debug("MIDI targets saved: %s", self._items)

        def add(self, target_name: str) -> None:
            """
            Add a MIDI target to the list of targets if it is not already present and is available.

            Args:
                target_name (str): The name of the MIDI target to add.
            """
            if target_name in self._system.ports:
                if target_name not in self._items:
                    self._items.append(target_name)
                    self.save()
                    logging.debug("Added MIDI target: %s", target_name)
            else:
                logging.warning("Cannot add MIDI target '%s': not available.", target_name)

        def remove(self, target_name: str) -> None:
            """
            Remove a MIDI target from the list of targets if it is present.

            Args:
                target_name (str): The name of the MIDI target to remove.
            """
            if target_name in self._items:
                self._items.remove(target_name)
                self.save()
                logging.debug("Removed MIDI target: %s", target_name)

    class Commands:
        """
        Commands class for MIDI controllable commands to the Helix device.

        This class eliminates the need to understand MIDI and the specific MIDI messages and order needed to communicate with a Helix device.
        Instead, you simply call the commands you want (ex. change_to_setlist) and the class will take care of the rest.
        """
        def __init__(self, targets) -> None:
            self.targets = targets

        def change_to_setlist(self, setlist_index: int) -> None:
            """
            Change to a specific setlist on the Helix device.

            Args:
                setlist_index (int): The index of the setlist to change to.
            """
            for target in self.targets:
                self.targets.system.send_cc(port=target, channel=0, control=69, value=setlist_index)
                logging.debug("Changed to setlist %d on target %s", setlist_index, target)

        def change_to_preset(self, preset_index: int) -> None:
            """
            Change to a specific preset on the Helix device.

            Args:
                preset_index (int): The index of the preset to change to.
            """
            for target in self.targets:
                self.targets.system.send_pc(port=target, channel=0, program=preset_index)
                logging.debug("Changed to preset %d on target %s", preset_index, target)

        def change_to_snapshot(self, snapshot_index: int) -> None:
            """
            Change to a specific snapshot on the Helix device.

            Args:
                snapshot_index (int): The index of the snapshot to change to.
            """
            for target in self.targets:
                self.targets.system.send_cc(port=target, channel=0, control=69, value=snapshot_index)
                logging.debug("Changed to snapshot %d on target %s", snapshot_index, target)

        def next_preset(self) -> None:
            """
            Change to the next preset on the Helix device.
            """
            for target in self.targets:
                self.targets.system.send_cc(port=target, channel=0, control=72, value=64)
                logging.debug("Changed to next preset on target: %s", target)

        def previous_preset(self) -> None:
            """
            Change to the previous preset on the Helix device.
            """
            for target in self.targets:
                self.targets.system.send_cc(port=target, channel=0, control=72, value=0)
                logging.debug("Changed to previous preset on target: %s", target)

        def next_snapshot(self) -> None:
            """
            Change to the next snapshot on the Helix device.
            """
            for target in self.targets:
                self.targets.system.send_cc(port=target, channel=0, control=69, value=8)
                logging.debug("Changed to next snapshot on target: %s", target)

        def previous_snapshot(self) -> None:
            """
            Change to the previous snapshot on the Helix device.
            """
            for target in self.targets:
                self.targets.system.send_cc(port=target, channel=0, control=69, value=9)
                logging.debug("Changed to previous snapshot on target: %s", target)

        def toggle_toe(self) -> None:
            """
            Toggles the toe switch on the Helix device.
            """
            for device in self.devices:
                self.devices.system.send_cc(port=device, channel=0, control=59, value=0)
                logging.debug("Toggled toe switch on device: %s", device)

        def toggle_tuner(self) -> None:
            """
            Toggles the tuner on the Helix device.
            """
            for device in self.devices:
                self.devices.system.send_cc(port=device, channel=0, control=68, value=0)
                logging.debug("Toggled tuner on device: %s", device)

commands = self.Commands(self.targets) instance-attribute ¤

system = self.System() instance-attribute ¤

targets = self.Targets(self.system) instance-attribute ¤

Commands ¤

Commands class for MIDI controllable commands to the Helix device.

This class eliminates the need to understand MIDI and the specific MIDI messages and order needed to communicate with a Helix device. Instead, you simply call the commands you want (ex. change_to_setlist) and the class will take care of the rest.

Source code in helixapi\midi.py
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
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
class Commands:
    """
    Commands class for MIDI controllable commands to the Helix device.

    This class eliminates the need to understand MIDI and the specific MIDI messages and order needed to communicate with a Helix device.
    Instead, you simply call the commands you want (ex. change_to_setlist) and the class will take care of the rest.
    """
    def __init__(self, targets) -> None:
        self.targets = targets

    def change_to_setlist(self, setlist_index: int) -> None:
        """
        Change to a specific setlist on the Helix device.

        Args:
            setlist_index (int): The index of the setlist to change to.
        """
        for target in self.targets:
            self.targets.system.send_cc(port=target, channel=0, control=69, value=setlist_index)
            logging.debug("Changed to setlist %d on target %s", setlist_index, target)

    def change_to_preset(self, preset_index: int) -> None:
        """
        Change to a specific preset on the Helix device.

        Args:
            preset_index (int): The index of the preset to change to.
        """
        for target in self.targets:
            self.targets.system.send_pc(port=target, channel=0, program=preset_index)
            logging.debug("Changed to preset %d on target %s", preset_index, target)

    def change_to_snapshot(self, snapshot_index: int) -> None:
        """
        Change to a specific snapshot on the Helix device.

        Args:
            snapshot_index (int): The index of the snapshot to change to.
        """
        for target in self.targets:
            self.targets.system.send_cc(port=target, channel=0, control=69, value=snapshot_index)
            logging.debug("Changed to snapshot %d on target %s", snapshot_index, target)

    def next_preset(self) -> None:
        """
        Change to the next preset on the Helix device.
        """
        for target in self.targets:
            self.targets.system.send_cc(port=target, channel=0, control=72, value=64)
            logging.debug("Changed to next preset on target: %s", target)

    def previous_preset(self) -> None:
        """
        Change to the previous preset on the Helix device.
        """
        for target in self.targets:
            self.targets.system.send_cc(port=target, channel=0, control=72, value=0)
            logging.debug("Changed to previous preset on target: %s", target)

    def next_snapshot(self) -> None:
        """
        Change to the next snapshot on the Helix device.
        """
        for target in self.targets:
            self.targets.system.send_cc(port=target, channel=0, control=69, value=8)
            logging.debug("Changed to next snapshot on target: %s", target)

    def previous_snapshot(self) -> None:
        """
        Change to the previous snapshot on the Helix device.
        """
        for target in self.targets:
            self.targets.system.send_cc(port=target, channel=0, control=69, value=9)
            logging.debug("Changed to previous snapshot on target: %s", target)

    def toggle_toe(self) -> None:
        """
        Toggles the toe switch on the Helix device.
        """
        for device in self.devices:
            self.devices.system.send_cc(port=device, channel=0, control=59, value=0)
            logging.debug("Toggled toe switch on device: %s", device)

    def toggle_tuner(self) -> None:
        """
        Toggles the tuner on the Helix device.
        """
        for device in self.devices:
            self.devices.system.send_cc(port=device, channel=0, control=68, value=0)
            logging.debug("Toggled tuner on device: %s", device)

targets = targets instance-attribute ¤

change_to_preset(preset_index) ¤

Change to a specific preset on the Helix device.

Parameters:

Name Type Description Default
preset_index int

The index of the preset to change to.

required
Source code in helixapi\midi.py
246
247
248
249
250
251
252
253
254
255
def change_to_preset(self, preset_index: int) -> None:
    """
    Change to a specific preset on the Helix device.

    Args:
        preset_index (int): The index of the preset to change to.
    """
    for target in self.targets:
        self.targets.system.send_pc(port=target, channel=0, program=preset_index)
        logging.debug("Changed to preset %d on target %s", preset_index, target)

change_to_setlist(setlist_index) ¤

Change to a specific setlist on the Helix device.

Parameters:

Name Type Description Default
setlist_index int

The index of the setlist to change to.

required
Source code in helixapi\midi.py
235
236
237
238
239
240
241
242
243
244
def change_to_setlist(self, setlist_index: int) -> None:
    """
    Change to a specific setlist on the Helix device.

    Args:
        setlist_index (int): The index of the setlist to change to.
    """
    for target in self.targets:
        self.targets.system.send_cc(port=target, channel=0, control=69, value=setlist_index)
        logging.debug("Changed to setlist %d on target %s", setlist_index, target)

change_to_snapshot(snapshot_index) ¤

Change to a specific snapshot on the Helix device.

Parameters:

Name Type Description Default
snapshot_index int

The index of the snapshot to change to.

required
Source code in helixapi\midi.py
257
258
259
260
261
262
263
264
265
266
def change_to_snapshot(self, snapshot_index: int) -> None:
    """
    Change to a specific snapshot on the Helix device.

    Args:
        snapshot_index (int): The index of the snapshot to change to.
    """
    for target in self.targets:
        self.targets.system.send_cc(port=target, channel=0, control=69, value=snapshot_index)
        logging.debug("Changed to snapshot %d on target %s", snapshot_index, target)

next_preset() ¤

Change to the next preset on the Helix device.

Source code in helixapi\midi.py
268
269
270
271
272
273
274
def next_preset(self) -> None:
    """
    Change to the next preset on the Helix device.
    """
    for target in self.targets:
        self.targets.system.send_cc(port=target, channel=0, control=72, value=64)
        logging.debug("Changed to next preset on target: %s", target)

next_snapshot() ¤

Change to the next snapshot on the Helix device.

Source code in helixapi\midi.py
284
285
286
287
288
289
290
def next_snapshot(self) -> None:
    """
    Change to the next snapshot on the Helix device.
    """
    for target in self.targets:
        self.targets.system.send_cc(port=target, channel=0, control=69, value=8)
        logging.debug("Changed to next snapshot on target: %s", target)

previous_preset() ¤

Change to the previous preset on the Helix device.

Source code in helixapi\midi.py
276
277
278
279
280
281
282
def previous_preset(self) -> None:
    """
    Change to the previous preset on the Helix device.
    """
    for target in self.targets:
        self.targets.system.send_cc(port=target, channel=0, control=72, value=0)
        logging.debug("Changed to previous preset on target: %s", target)

previous_snapshot() ¤

Change to the previous snapshot on the Helix device.

Source code in helixapi\midi.py
292
293
294
295
296
297
298
def previous_snapshot(self) -> None:
    """
    Change to the previous snapshot on the Helix device.
    """
    for target in self.targets:
        self.targets.system.send_cc(port=target, channel=0, control=69, value=9)
        logging.debug("Changed to previous snapshot on target: %s", target)

toggle_toe() ¤

Toggles the toe switch on the Helix device.

Source code in helixapi\midi.py
300
301
302
303
304
305
306
def toggle_toe(self) -> None:
    """
    Toggles the toe switch on the Helix device.
    """
    for device in self.devices:
        self.devices.system.send_cc(port=device, channel=0, control=59, value=0)
        logging.debug("Toggled toe switch on device: %s", device)

toggle_tuner() ¤

Toggles the tuner on the Helix device.

Source code in helixapi\midi.py
308
309
310
311
312
313
314
def toggle_tuner(self) -> None:
    """
    Toggles the tuner on the Helix device.
    """
    for device in self.devices:
        self.devices.system.send_cc(port=device, channel=0, control=68, value=0)
        logging.debug("Toggled tuner on device: %s", device)

System ¤

System class for managing MIDI output ports and sending messages.

Note

While this class is mostly for internal use, it can be used to list MIDI output ports and send messages. Most users should use the Commands class instead.

Source code in helixapi\midi.py
 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
class System:
    """
    System class for managing MIDI output ports and sending messages.

    !!! note

        While this class is mostly for internal use, it can be used to list MIDI output ports and send messages.
        Most users should use the Commands class instead.
    """
    def __init__(self) -> None:
        self._available_ports = mido.get_output_names()

    @property
    def ports(self) -> List[str]:
        """
        Return a list of available MIDI output ports.

        Returns:
            List[str]: A list of available MIDI output ports.
        """
        logging.debug("Available MIDI ports: %s", self._available_ports)
        return self._available_ports

    def send_cc(self, port: str, channel: int, control: int, value: int) -> None:
        """
        Send a Control Change (CC) message to a MIDI target.

        Args:
            port (str): The name of the MIDI output port.
            channel (int): The MIDI channel to send the message on.
            control (int): The control number.
            value (int): The value to set the control to.
        """
        message = self._create_cc_message(channel, control, value)
        logging.debug("Sending CC message: %s", message)
        self._send_message(port, message)

    def send_pc(self, port: str, channel: int, program: int) -> None:
        """
        Send a Program Change (PC) message to a MIDI target.

        Args:
            port (str): The name of the MIDI output port.
            channel (int): The MIDI channel to send the message on.
            program (int): The program number to change to.
        """
        message = self._create_pc_message(channel, program)
        logging.debug("Sending PC message: %s", message)
        self._send_message(port, message)

    def send_ccpc(self, port: str, cc_channel: int, cc_control: int, cc_value: int, pc_channel: int, pc_program: int) -> None:
        """
        Send both Control Change (CC) and Program Change (PC) messages to a MIDI target.

        Args:
            port (str): The name of the MIDI output port.
            cc_channel (int): The MIDI channel to send the CC message on.
            cc_control (int): The control number for the CC message.
            cc_value (int): The value for the CC message.
            pc_channel (int): The MIDI channel to send the PC message on.
            pc_program (int): The program number for the PC message.
        """
        cc_message = self._create_cc_message(cc_channel, cc_control, cc_value)
        pc_message = self._create_pc_message(pc_channel, pc_program)
        logging.debug("Sending CC message: %s", cc_message)
        logging.debug("Sending PC message: %s", pc_message)
        self._send_message(port, cc_message)
        self._send_message(port, pc_message)

    def _create_cc_message(self, channel: int, control: int, value: int) -> mido.Message:
        """
        Create a Control Change (CC) message.

        Args:
            channel (int): The MIDI channel to send the message on.
            control (int): The control number.
            value (int): The value to set the control to.

        Returns:
            mido.Message: The created CC message.
        """
        return mido.Message('control_change', channel=channel, control=control, value=value)

    def _create_pc_message(self, channel: int, program: int) -> mido.Message:
        """
        Create a Program Change (PC) message.

        Args:
            channel (int): The MIDI channel to send the message on.
            program (int): The program number to change to.

        Returns:
            mido.Message: The created PC message.
        """
        return mido.Message('program_change', channel=channel, program=program)

    def _send_message(self, port: str, message: mido.Message) -> None:
        """
        Send a MIDI message to a specific MIDI target.

        Args:
            port (str): The name of the MIDI output port.
            message (mido.Message): The MIDI message to send.
        """
        with mido.open_output(port) as output:
            output.send(message)
            logging.debug("Sent message: %s to target: %s", message, port)

ports: List[str] property ¤

Return a list of available MIDI output ports.

Returns:

Type Description
List[str]

List[str]: A list of available MIDI output ports.

send_cc(port, channel, control, value) ¤

Send a Control Change (CC) message to a MIDI target.

Parameters:

Name Type Description Default
port str

The name of the MIDI output port.

required
channel int

The MIDI channel to send the message on.

required
control int

The control number.

required
value int

The value to set the control to.

required
Source code in helixapi\midi.py
59
60
61
62
63
64
65
66
67
68
69
70
71
def send_cc(self, port: str, channel: int, control: int, value: int) -> None:
    """
    Send a Control Change (CC) message to a MIDI target.

    Args:
        port (str): The name of the MIDI output port.
        channel (int): The MIDI channel to send the message on.
        control (int): The control number.
        value (int): The value to set the control to.
    """
    message = self._create_cc_message(channel, control, value)
    logging.debug("Sending CC message: %s", message)
    self._send_message(port, message)

send_ccpc(port, cc_channel, cc_control, cc_value, pc_channel, pc_program) ¤

Send both Control Change (CC) and Program Change (PC) messages to a MIDI target.

Parameters:

Name Type Description Default
port str

The name of the MIDI output port.

required
cc_channel int

The MIDI channel to send the CC message on.

required
cc_control int

The control number for the CC message.

required
cc_value int

The value for the CC message.

required
pc_channel int

The MIDI channel to send the PC message on.

required
pc_program int

The program number for the PC message.

required
Source code in helixapi\midi.py
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
def send_ccpc(self, port: str, cc_channel: int, cc_control: int, cc_value: int, pc_channel: int, pc_program: int) -> None:
    """
    Send both Control Change (CC) and Program Change (PC) messages to a MIDI target.

    Args:
        port (str): The name of the MIDI output port.
        cc_channel (int): The MIDI channel to send the CC message on.
        cc_control (int): The control number for the CC message.
        cc_value (int): The value for the CC message.
        pc_channel (int): The MIDI channel to send the PC message on.
        pc_program (int): The program number for the PC message.
    """
    cc_message = self._create_cc_message(cc_channel, cc_control, cc_value)
    pc_message = self._create_pc_message(pc_channel, pc_program)
    logging.debug("Sending CC message: %s", cc_message)
    logging.debug("Sending PC message: %s", pc_message)
    self._send_message(port, cc_message)
    self._send_message(port, pc_message)

send_pc(port, channel, program) ¤

Send a Program Change (PC) message to a MIDI target.

Parameters:

Name Type Description Default
port str

The name of the MIDI output port.

required
channel int

The MIDI channel to send the message on.

required
program int

The program number to change to.

required
Source code in helixapi\midi.py
73
74
75
76
77
78
79
80
81
82
83
84
def send_pc(self, port: str, channel: int, program: int) -> None:
    """
    Send a Program Change (PC) message to a MIDI target.

    Args:
        port (str): The name of the MIDI output port.
        channel (int): The MIDI channel to send the message on.
        program (int): The program number to change to.
    """
    message = self._create_pc_message(channel, program)
    logging.debug("Sending PC message: %s", message)
    self._send_message(port, message)

Targets ¤

Targets class for managing desired MIDI output ports.

"Targets" are the MIDI output ports you want commands to be sent to. Target names are saved in and loaded from the settings.yaml file.

Source code in helixapi\midi.py
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
class Targets:
    """
    Targets class for managing desired MIDI output ports.

    "Targets" are the MIDI output ports you want commands to be sent to.
    Target names are saved in and loaded from the settings.yaml file.
    """
    def __init__(self, system) -> None:
        self._settings = Settings()
        self._system = system
        self._items = self._load_targets()

    def _load_targets(self) -> List[str]:
        """
        Load targets from settings if they match available ports.

        Returns:
            List[str]: A list of matched MIDI targets.
        """
        saved_targets = self._settings.midi_targets
        logging.debug("Saved MIDI targets: %s", saved_targets)

        matched_targets = []
        for target in saved_targets:
            if target in self._system.ports:
                matched_targets.append(target)
            else:
                logging.warning("MIDI target '%s' not matched to any available port.", target)
        return matched_targets

    def __getitem__(self, index):
        return self._items[index]

    def __setitem__(self, index, value):
        self._items[index] = value

    def __len__(self):
        return len(self._items)

    def __iter__(self):
        return iter(self._items)

    def __contains__(self, item):
        return item in self._items

    def save(self) -> None:
        """
        Save the current list of MIDI targets to the settings.
        """
        settings_file = os.path.abspath(os.path.join(os.path.dirname(__file__), 'settings.yaml'))
        with open(settings_file, 'w') as file:
            yaml.safe_dump(self._items, file)
        logging.debug("MIDI targets saved: %s", self._items)

    def add(self, target_name: str) -> None:
        """
        Add a MIDI target to the list of targets if it is not already present and is available.

        Args:
            target_name (str): The name of the MIDI target to add.
        """
        if target_name in self._system.ports:
            if target_name not in self._items:
                self._items.append(target_name)
                self.save()
                logging.debug("Added MIDI target: %s", target_name)
        else:
            logging.warning("Cannot add MIDI target '%s': not available.", target_name)

    def remove(self, target_name: str) -> None:
        """
        Remove a MIDI target from the list of targets if it is present.

        Args:
            target_name (str): The name of the MIDI target to remove.
        """
        if target_name in self._items:
            self._items.remove(target_name)
            self.save()
            logging.debug("Removed MIDI target: %s", target_name)

add(target_name) ¤

Add a MIDI target to the list of targets if it is not already present and is available.

Parameters:

Name Type Description Default
target_name str

The name of the MIDI target to add.

required
Source code in helixapi\midi.py
198
199
200
201
202
203
204
205
206
207
208
209
210
211
def add(self, target_name: str) -> None:
    """
    Add a MIDI target to the list of targets if it is not already present and is available.

    Args:
        target_name (str): The name of the MIDI target to add.
    """
    if target_name in self._system.ports:
        if target_name not in self._items:
            self._items.append(target_name)
            self.save()
            logging.debug("Added MIDI target: %s", target_name)
    else:
        logging.warning("Cannot add MIDI target '%s': not available.", target_name)

remove(target_name) ¤

Remove a MIDI target from the list of targets if it is present.

Parameters:

Name Type Description Default
target_name str

The name of the MIDI target to remove.

required
Source code in helixapi\midi.py
213
214
215
216
217
218
219
220
221
222
223
def remove(self, target_name: str) -> None:
    """
    Remove a MIDI target from the list of targets if it is present.

    Args:
        target_name (str): The name of the MIDI target to remove.
    """
    if target_name in self._items:
        self._items.remove(target_name)
        self.save()
        logging.debug("Removed MIDI target: %s", target_name)

save() ¤

Save the current list of MIDI targets to the settings.

Source code in helixapi\midi.py
189
190
191
192
193
194
195
196
def save(self) -> None:
    """
    Save the current list of MIDI targets to the settings.
    """
    settings_file = os.path.abspath(os.path.join(os.path.dirname(__file__), 'settings.yaml'))
    with open(settings_file, 'w') as file:
        yaml.safe_dump(self._items, file)
    logging.debug("MIDI targets saved: %s", self._items)