AutoSyncHost/ashost.py
2024-06-26 15:02:12 +02:00

162 lines
4.6 KiB
Python

#!/usr/bin/env python3
### Copyright 2024 Thomas Herrmann
### Released under GPL v3
import time
import mido
def match_device_name(input_name, output_list):
# Function to match device names flexibly
for device in output_list:
if any(substring in device for substring in input_name.split()):
return device
return None
def determine_host(devices_in):
master = None
"""
Determine the host by listening for 'start' messages on input ports.
Args:
- devices_in (list of str): The names of the MIDI input ports to listen to.
Returns:
- str: The name of the input port that received the 'start' message.
"""
# Open all the input ports
inports = [mido.open_input(device) for device in devices_in]
# Create a MultiPort to listen on all input ports
#ports = MultiPort(inports, True)
print("Listening for messages...")
try:
while not master:
for port in inports:
for message in port.iter_pending():
#print(f"Received message: ({port.name}, {message})")
if 'start' in str(message):
master = port.name
break
except KeyboardInterrupt:
print("Interrupted by user.")
finally:
# Ensure all ports are closed
for port in inports:
port.close()
print("Closed all input ports.")
if master:
return master
def relay_midi_host_to_out(host_name, devices_out):
"""
Relay MIDI messages from a specific input port to all specified output ports.
Args:
- host_name (str): The name of the MIDI input port to listen to.
- devices_out (list of str): The names of the MIDI output ports to send messages to.
"""
#host_name = f'{host_name}'
reset = False
# Open the input port
print("Opening Input ffsk", host_name)
input_port = mido.open_input(host_name)
output_ports = [mido.open_output(device) for device in devices_out]
print(f"Listening for messages on {host_name} and relaying to {devices_out}")
recent_messages = []
try:
print(reset)
while not reset:
# Process all pending messages
#print("Entering loop", input_port.iter_pending() )
for message in input_port.iter_pending():
read_message = str(message)
#spread_the_word = MultiPort(output_ports)
#print(read_message)
if 'start' in read_message or 'stop' in read_message:
for dev in output_ports:
dev.send(message)
recent_messages.append(read_message)
#print("SS")
elif 'clock' in read_message:
for dev in output_ports:
dev.send(message)
#print("clock")
# Keep only the last 3 messages
if len(recent_messages) > 3:
recent_messages.pop(0)
# Check if the last 3 messages are all 'stop'
if recent_messages[-3:] == ['stop time=0', 'stop time=0', 'stop time=0']:
#print("Received 'stop' three times in a row")
# Perform the desired action when 'stop' is received three times in a row
# For example, resetting the list
recent_messages.clear()
reset = True
break
except KeyboardInterrupt:
# Handle user interrupt (e.g., Ctrl+C)
print("MIDI relay interrupted by user.")
finally:
# Close all ports
input_port.close()
print(input_port)
for port in output_ports:
#port.reset()
port.close()
print(port)
print("Closed all MIDI ports.")
#Repeat host detection a nd main loop
time.sleep(1)
main_run()
def main_run():
# Retrieve the list of available input devices
devices_in = mido.get_input_names()
devices_out = mido.get_output_names()
print("Available MIDI input devices:", devices_in)
# Call the function to start receiving messages from all devices
midi_host_in = determine_host(devices_in)
print(midi_host_in)
# Find and remove the matching output device to avoid feedback
matching_output_device = match_device_name(midi_host_in, devices_out)
if matching_output_device:
devices_out.remove(matching_output_device)
print(devices_out)
#time.sleep(3)
if midi_host_in:
relay_midi_host_to_out(midi_host_in, devices_out)
print("mido died")
main_run()