tags: #python #tourbox #osc ## Osc to Midi This takes in osc messages on a specified port, and for those matching the signals my TourBoxToOsc script generates, outputs a midi cc with value 127 and the cc number based on which knob or button the event came from. The commented out code in the middle is there to facilitate creating the ableton.txt file by pressing each button in order. ```python #!/usr/bin/env python3 import sys, os from rtmidi import MidiIn, MidiOut from pythonosc.osc_message import OscMessage from datetime import datetime import socket def get_ip(): # workaround since reaper doesn't receive packets if sent to localhost rather than 192.168.0.x s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.settimeout(0) try: # doesn't even have to be reachable s.connect(('10.254.254.254', 1)) IP = s.getsockname()[0] except Exception: IP = '127.0.0.1' finally: s.close() return IP def dump(*xs): print(f"dump {xs}") def main(): port = int(os.getenv("port",7001)) host = os.getenv("host","localhost") if host == "localhost": host = get_ip() midiout = MidiOut() ports = midiout.get_ports() for i,x in enumerate(ports): if "ableton_control_1" in x: midiout.open_port(i) print(f"Opened {i}: {x}") break else: print(f"Didn't find Ableton port") exit(1) ableton = Ableton(midiout) print(f"{host=} {port=}") #i = 0 #d = set() #m = [] with socket.socket(socket.AF_INET,socket.SOCK_DGRAM) as s: s.bind((host,port)) while True: #i += 1 #if i > 60: # break data = s.recv(256*1024) now = datetime.now().strftime("%c") l = len(data) print(f"{now} : {l} bytes received") message = OscMessage(data) address = message.address params = message.params #if not address in d: # d.add(address) # m.append(address) print(f"{address=} {params=}") ableton(address,params) print() #with open("ableton.txt","wt") as f: # f.write("\n".join(m)) def fmt(x): 'turn numbers into strings, and add "quotes" to strings' if type(x) in (int,float): return str(x) elif type(x) is str: if '"' in x and not "'" in x: return f"'{x}'" else: x = x.replace('"',r'\"') return f'"{x}"' def dump(*xs): print(xs) return n,*ys = xs print(f"{n}: {', '.join(map(fmt,ys))}") class Ableton: def __init__(self,midiout): self.midiout = midiout with open("ableton.txt") as f: a = f.read().rstrip().splitlines() self.d = {} for i,line in enumerate(a): self.d[line] = i def __call__(self,address,params): print(f"{address}: {', '.join(map(fmt,params))}") if address in self.d: i = self.d[address] a = [ 0xB0, i, 0x7F ] print(f"Sending {i=} {a=}") a = bytes(a) self.midiout.send_message(a) if __name__ == "__main__": main() ``` ableton.txt ``` tour/knob/cw tour/knob/ccw tour/dial/cw tour/dial/ccw tour/vdial/cw tour/vdial/ccw tour/dpad/up tour/dpad/down tour/dpad/right tour/dpad/left tour/button/2a tour/button/00 tour/button/03 tour/button/23 tour/button/22 tour/button/02 tour/button/01 ```