""" TouchOSC Midi Remote Script Designed by ST8 """ import Live import RemixNet import OSC import re import os from Logger import Logger class TouchOSC: __module__ = __name__ __doc__ = "TouchOSC Midi Remote Script" # Enable Logging _LOG = 0 # Track offset tos = 7 def __init__(self, c_instance): self.c_instance = c_instance self.logger = self._LOG and Logger() or 0 self.log("Logging Enabled") local = RemixNet.get_ip() self.log("Ableton IP: " + str(local)) # Init all listeners self.cc = [] self.cache = [] config = open(os.path.expanduser('~') + '/touchosc_config.txt', 'r') first = 0 for line in config: line = line.rstrip() # First line is remote ip address if first == 0: remote = line self.oscServer = RemixNet.OSCServer(remote, 5001, local, 5000) self.callbackManager = self.oscServer.callbackManager self.oscServer.sendOSC('/touchosc/startup', 1) first = 1 else: if re.search("xy", line): self.cc.append(line) self.cc.append(line) self.cache.append(0) self.cache.append(0) else: self.cc.append(line) self.cache.append(0) self.callbackManager.add(self.callback, line) config.close() self.c_instance.show_message("TouchOSC > Server Started on " + str(local) + ", sending data to: " + str(remote)) #self.song().add_current_song_time_listener(self.oscServer.processIncomingUDP) ###################################################################### def disconnect(self): self.oscServer.sendOSC('/touchosc/shutdown', 1) self.oscServer.shutdown() def connect_script_instances(self, instanciated_scripts): return def is_extension(self): return False def request_rebuild_midi_map(self): return def build_midi_map(self, midi_map_handle): for i in range(0,127): Live.MidiMap.forward_midi_cc(self.handle(), midi_map_handle, 0, i) def send_midi(self, midi_bytes): self.c_instance.send_midi(midi_bytes) def receive_midi(self, bytes): cc = self.cc[bytes[1]] val = float(bytes[2])/float(127) if re.search("xy", cc): self.cache[bytes[1]] = bytes[2] xy1 = self.tuple_idx(self.cc, cc) if bytes[1] == xy1: val2 = float(self.cache[bytes[1] + 1])/float(127) self.oscServer.sendOSC(str(self.cc[bytes[1]]), (val, val2)) else: val2 = float(self.cache[bytes[1] - 1])/float(127) self.oscServer.sendOSC(str(self.cc[bytes[1]]), (val2, val)) self.log("cc: " + str(bytes[1]) + " val: " + str(val) + " cc2: " + str((bytes[1] - 1)) + " val2: " + str(val2) + " control: " + str(self.cc[bytes[1]])) else: self.log("cc: " + str(bytes[1]) + " val: " + str(bytes[2]) + " control: " + str(self.cc[bytes[1]])) self.oscServer.sendOSC(str(self.cc[bytes[1]]), val) def can_lock_to_devices(self): return False def suggest_input_port(self): return '' def suggest_output_port(self): return '' def suggest_map_mode(self, cc_no, channel): return Live.MidiMap.MapMode.absolute def __handle_display_switch_ids(self, switch_id, value): pass ###################################################################### def update_display(self): if self.oscServer: try: self.oscServer.processIncomingUDP() except: pass def refresh_state(self): return ###################################################################### # Helpers def song(self): return self.c_instance.song() def handle(self): return self.c_instance.handle() def log(self, msg): if self._LOG == 1: self.logger.log(str(msg)) def tuple_idx(self, tuple, obj): for i in xrange(0,len(tuple)): if (tuple[i] == obj): return i ###################################################################### # Main Touch OSC Functions def callback(self, msg): # Sends handler if re.search("/3/multitoggle1/", msg[0]): ids = msg[0].split('/') ret = 5 - int(ids[3]) sid = int(ids[4]) - 1 if sid >= ret: sid = sid + 1 self.log("row: " + str(ret) + " col:" + str(sid)) track = self.song().return_tracks[ret] track.mixer_device.sends[sid].value = msg[2] elif re.search("/3/push", msg[0]): id = int(msg[0].replace("/3/push", "")) - 1 tr = (id % 6) + self.tos sid = (id / 6) track = self.song().tracks[tr] track.mixer_device.sends[sid].value = msg[2] elif re.search("/3/toggle", msg[0]): id = int(msg[0].replace("/3/toggle", "")) - 1 tr = (id % 6) + self.tos sid = (id / 6) + 2 self.log("tr: " + str(tr) + " send: " + str(sid)) track = self.song().tracks[tr] # Sends track.mixer_device.sends[sid].value = msg[2] tot = 0 for s in range(2, len(track.mixer_device.sends)): tot += track.mixer_device.sends[s].value if tot > 0: track.mixer_device.volume.value = 0 else: track.mixer_device.volume.value = 0.85 elif re.search("xy", msg[0]): cc = self.tuple_idx(self.cc, msg[0]) val = int(msg[2] * 127) val2 = int(msg[3] * 127) if abs(self.cache[cc] - val) > 0: self.c_instance.send_midi((0xb0, cc, val)) self.cache[cc] = val self.log(str(msg[0]) + " cc: " + str(cc) + " val: " + str(val)) if abs(self.cache[cc+1] - val2) > 0: self.c_instance.send_midi((0xb0, cc + 1, val2)) self.log(str(msg[0]) + " cc2: " + str(cc+1) + " val2: " + str(val2)) self.cache[cc+1] = val2 else: cc = self.tuple_idx(self.cc, msg[0]) val = int(msg[2] * 127) self.c_instance.send_midi((0xb0, cc, val)) self.log(str(msg[0]) + " cc: " + str(cc) + " val: " + str(val))