import rtmidi import time class HostsSync: def __init__(self): self.host_id = None self.available_ports = None self.midi_out = rtmidi.MidiOut() self.opened_ports = [] def midi_input_callback(self, event, data_pack): message, deltatime = event status = message[0] host_id, midi_in = data_pack # Check if the status byte is 0xFA (250 in decimal) or 0xFF (255 in decimal), # which indicate MIDI Start and Stop messages respectively if status in [250, 255]: print(f"MIDI message received from device {host_id}: {message}") self.host_id = host_id self.midi_output_called(message) def midi_output_called(self, message): if self.host_id is None: return for i, port in enumerate(self.available_ports): if i != self.host_id: if i not in self.opened_ports: self.midi_out.open_port(i) self.opened_ports.append(i) print(f"Opened MIDI output port: {self.available_ports[i]}") self.midi_out.send_message(message) def main(self): midi_ins = [] self.available_ports = rtmidi.MidiIn().get_ports() if not self.available_ports: print("No MIDI input ports available.") return print("Available MIDI input ports:") for i, port in enumerate(self.available_ports): print(f"{i}: {port}") try: for i, port in enumerate(self.available_ports): midi_in = rtmidi.MidiIn() midi_in.open_port(i) midi_in.set_callback(self.midi_input_callback, (i, midi_in)) midi_ins.append(midi_in) print(f"Listening for MIDI messages on input port: {port}") # Keep the script running to listen for MIDI messages while True: time.sleep(1) except KeyboardInterrupt: print("\nExiting...") finally: for midi_in in midi_ins: midi_in.close_port() self.midi_out.close_port() if __name__ == "__main__": HostsSync().main()