| 1 | """ |
|---|
| 2 | TouchOSC Midi Remote Script |
|---|
| 3 | Designed by ST8 |
|---|
| 4 | """ |
|---|
| 5 | |
|---|
| 6 | import Live |
|---|
| 7 | import RemixNet |
|---|
| 8 | import OSC |
|---|
| 9 | import re |
|---|
| 10 | import os |
|---|
| 11 | from Logger import Logger |
|---|
| 12 | |
|---|
| 13 | class TouchOSC: |
|---|
| 14 | __module__ = __name__ |
|---|
| 15 | __doc__ = "TouchOSC Midi Remote Script" |
|---|
| 16 | |
|---|
| 17 | # Enable Logging |
|---|
| 18 | _LOG = 0 |
|---|
| 19 | |
|---|
| 20 | # Track offset |
|---|
| 21 | tos = 7 |
|---|
| 22 | |
|---|
| 23 | def __init__(self, c_instance): |
|---|
| 24 | self.c_instance = c_instance |
|---|
| 25 | |
|---|
| 26 | self.logger = self._LOG and Logger() or 0 |
|---|
| 27 | self.log("Logging Enabled") |
|---|
| 28 | |
|---|
| 29 | local = RemixNet.get_ip() |
|---|
| 30 | self.log("Ableton IP: " + str(local)) |
|---|
| 31 | |
|---|
| 32 | # Init all listeners |
|---|
| 33 | self.cc = [] |
|---|
| 34 | self.cache = [] |
|---|
| 35 | |
|---|
| 36 | config = open(os.path.expanduser('~') + '/touchosc_config.txt', 'r') |
|---|
| 37 | |
|---|
| 38 | first = 0 |
|---|
| 39 | for line in config: |
|---|
| 40 | line = line.rstrip() |
|---|
| 41 | |
|---|
| 42 | # First line is remote ip address |
|---|
| 43 | if first == 0: |
|---|
| 44 | remote = line |
|---|
| 45 | self.oscServer = RemixNet.OSCServer(remote, 5001, local, 5000) |
|---|
| 46 | self.callbackManager = self.oscServer.callbackManager |
|---|
| 47 | self.oscServer.sendOSC('/touchosc/startup', 1) |
|---|
| 48 | |
|---|
| 49 | first = 1 |
|---|
| 50 | else: |
|---|
| 51 | if re.search("xy", line): |
|---|
| 52 | self.cc.append(line) |
|---|
| 53 | self.cc.append(line) |
|---|
| 54 | self.cache.append(0) |
|---|
| 55 | self.cache.append(0) |
|---|
| 56 | else: |
|---|
| 57 | self.cc.append(line) |
|---|
| 58 | self.cache.append(0) |
|---|
| 59 | |
|---|
| 60 | self.callbackManager.add(self.callback, line) |
|---|
| 61 | |
|---|
| 62 | config.close() |
|---|
| 63 | |
|---|
| 64 | self.c_instance.show_message("TouchOSC > Server Started on " + str(local) + ", sending data to: " + str(remote)) |
|---|
| 65 | |
|---|
| 66 | #self.song().add_current_song_time_listener(self.oscServer.processIncomingUDP) |
|---|
| 67 | |
|---|
| 68 | ###################################################################### |
|---|
| 69 | |
|---|
| 70 | def disconnect(self): |
|---|
| 71 | self.oscServer.sendOSC('/touchosc/shutdown', 1) |
|---|
| 72 | self.oscServer.shutdown() |
|---|
| 73 | |
|---|
| 74 | def connect_script_instances(self, instanciated_scripts): |
|---|
| 75 | return |
|---|
| 76 | |
|---|
| 77 | def is_extension(self): |
|---|
| 78 | return False |
|---|
| 79 | |
|---|
| 80 | def request_rebuild_midi_map(self): |
|---|
| 81 | return |
|---|
| 82 | |
|---|
| 83 | def build_midi_map(self, midi_map_handle): |
|---|
| 84 | for i in range(0,20): |
|---|
| 85 | Live.MidiMap.forward_midi_cc(self.handle(), midi_map_handle, 0, i) |
|---|
| 86 | |
|---|
| 87 | def send_midi(self, midi_bytes): |
|---|
| 88 | self.c_instance.send_midi(midi_bytes) |
|---|
| 89 | |
|---|
| 90 | def receive_midi(self, bytes): |
|---|
| 91 | cc = self.cc[bytes[1]] |
|---|
| 92 | val = float(bytes[2])/float(127) |
|---|
| 93 | |
|---|
| 94 | if re.search("xy", cc): |
|---|
| 95 | self.cache[bytes[1]] = bytes[2] |
|---|
| 96 | xy1 = self.tuple_idx(self.cc, cc) |
|---|
| 97 | |
|---|
| 98 | if bytes[1] == xy1: |
|---|
| 99 | val2 = float(self.cache[bytes[1] + 1])/float(127) |
|---|
| 100 | self.oscServer.sendOSC(str(self.cc[bytes[1]]), (val, val2)) |
|---|
| 101 | else: |
|---|
| 102 | val2 = float(self.cache[bytes[1] - 1])/float(127) |
|---|
| 103 | self.oscServer.sendOSC(str(self.cc[bytes[1]]), (val2, val)) |
|---|
| 104 | |
|---|
| 105 | self.log("cc: " + str(bytes[1]) + " val: " + str(val) + " cc2: " + str((bytes[1] - 1)) + " val2: " + str(val2) + " control: " + str(self.cc[bytes[1]])) |
|---|
| 106 | |
|---|
| 107 | else: |
|---|
| 108 | self.log("cc: " + str(bytes[1]) + " val: " + str(bytes[2]) + " control: " + str(self.cc[bytes[1]])) |
|---|
| 109 | self.oscServer.sendOSC(str(self.cc[bytes[1]]), val) |
|---|
| 110 | |
|---|
| 111 | def can_lock_to_devices(self): |
|---|
| 112 | return False |
|---|
| 113 | |
|---|
| 114 | def suggest_input_port(self): |
|---|
| 115 | return '' |
|---|
| 116 | |
|---|
| 117 | def suggest_output_port(self): |
|---|
| 118 | return '' |
|---|
| 119 | |
|---|
| 120 | def suggest_map_mode(self, cc_no, channel): |
|---|
| 121 | return Live.MidiMap.MapMode.absolute |
|---|
| 122 | |
|---|
| 123 | def __handle_display_switch_ids(self, switch_id, value): |
|---|
| 124 | pass |
|---|
| 125 | |
|---|
| 126 | ###################################################################### |
|---|
| 127 | |
|---|
| 128 | def update_display(self): |
|---|
| 129 | if self.oscServer: |
|---|
| 130 | try: |
|---|
| 131 | self.oscServer.processIncomingUDP() |
|---|
| 132 | except: |
|---|
| 133 | pass |
|---|
| 134 | |
|---|
| 135 | def refresh_state(self): |
|---|
| 136 | return |
|---|
| 137 | |
|---|
| 138 | ###################################################################### |
|---|
| 139 | # Helpers |
|---|
| 140 | def song(self): |
|---|
| 141 | return self.c_instance.song() |
|---|
| 142 | |
|---|
| 143 | def handle(self): |
|---|
| 144 | return self.c_instance.handle() |
|---|
| 145 | |
|---|
| 146 | def log(self, msg): |
|---|
| 147 | if self._LOG == 1: |
|---|
| 148 | self.logger.log(str(msg)) |
|---|
| 149 | |
|---|
| 150 | def tuple_idx(self, tuple, obj): |
|---|
| 151 | for i in xrange(0,len(tuple)): |
|---|
| 152 | if (tuple[i] == obj): |
|---|
| 153 | return i |
|---|
| 154 | |
|---|
| 155 | ###################################################################### |
|---|
| 156 | # Main Touch OSC Functions |
|---|
| 157 | def callback(self, msg): |
|---|
| 158 | # Sends handler |
|---|
| 159 | if re.search("/3/multitoggle1/", msg[0]): |
|---|
| 160 | ids = msg[0].split('/') |
|---|
| 161 | |
|---|
| 162 | ret = 5 - int(ids[3]) |
|---|
| 163 | sid = int(ids[4]) - 1 |
|---|
| 164 | |
|---|
| 165 | if sid >= ret: |
|---|
| 166 | sid = sid + 1 |
|---|
| 167 | |
|---|
| 168 | self.log("row: " + str(ret) + " col:" + str(sid)) |
|---|
| 169 | |
|---|
| 170 | track = self.song().return_tracks[ret] |
|---|
| 171 | track.mixer_device.sends[sid].value = msg[2] |
|---|
| 172 | |
|---|
| 173 | |
|---|
| 174 | elif re.search("/3/push", msg[0]): |
|---|
| 175 | id = int(msg[0].replace("/3/push", "")) - 1 |
|---|
| 176 | |
|---|
| 177 | tr = (id % 6) + self.tos |
|---|
| 178 | sid = (id / 6) |
|---|
| 179 | |
|---|
| 180 | track = self.song().tracks[tr] |
|---|
| 181 | track.mixer_device.sends[sid].value = msg[2] |
|---|
| 182 | |
|---|
| 183 | elif re.search("/3/toggle", msg[0]): |
|---|
| 184 | id = int(msg[0].replace("/3/toggle", "")) - 1 |
|---|
| 185 | |
|---|
| 186 | tr = (id % 6) + self.tos |
|---|
| 187 | sid = (id / 6) + 2 |
|---|
| 188 | |
|---|
| 189 | self.log("tr: " + str(tr) + " send: " + str(sid)) |
|---|
| 190 | |
|---|
| 191 | track = self.song().tracks[tr] |
|---|
| 192 | |
|---|
| 193 | # Sends |
|---|
| 194 | track.mixer_device.sends[sid].value = msg[2] |
|---|
| 195 | |
|---|
| 196 | tot = 0 |
|---|
| 197 | for s in range(2, len(track.mixer_device.sends)): |
|---|
| 198 | tot += track.mixer_device.sends[s].value |
|---|
| 199 | |
|---|
| 200 | if tot > 0: |
|---|
| 201 | track.mixer_device.volume.value = 0 |
|---|
| 202 | else: |
|---|
| 203 | track.mixer_device.volume.value = 0.85 |
|---|
| 204 | |
|---|
| 205 | elif re.search("xy", msg[0]): |
|---|
| 206 | cc = self.tuple_idx(self.cc, msg[0]) |
|---|
| 207 | |
|---|
| 208 | val = int(msg[2] * 127) |
|---|
| 209 | val2 = int(msg[3] * 127) |
|---|
| 210 | |
|---|
| 211 | if abs(self.cache[cc] - val) > 0: |
|---|
| 212 | self.c_instance.send_midi((0xb0, cc, val)) |
|---|
| 213 | self.cache[cc] = val |
|---|
| 214 | |
|---|
| 215 | self.log(str(msg[0]) + " cc: " + str(cc) + " val: " + str(val)) |
|---|
| 216 | |
|---|
| 217 | if abs(self.cache[cc+1] - val2) > 0: |
|---|
| 218 | self.c_instance.send_midi((0xb0, cc + 1, val2)) |
|---|
| 219 | self.log(str(msg[0]) + " cc2: " + str(cc+1) + " val2: " + str(val2)) |
|---|
| 220 | |
|---|
| 221 | self.cache[cc+1] = val2 |
|---|
| 222 | |
|---|
| 223 | else: |
|---|
| 224 | cc = self.tuple_idx(self.cc, msg[0]) |
|---|
| 225 | val = int(msg[2] * 127) |
|---|
| 226 | |
|---|
| 227 | self.c_instance.send_midi((0xb0, cc, val)) |
|---|
| 228 | |
|---|
| 229 | self.log(str(msg[0]) + " cc: " + str(cc) + " val: " + str(val)) |
|---|
| 230 | |
|---|