source: trunk/LiveOSC/LiveOSC.py @ 63

Revision 63, 28.1 KB checked in by st8, 9 months ago (diff)

Fixed color variable name. color_index -> color

Line 
1"""
2# Copyright (C) 2007 Nathan Ramella (nar@remix.net)
3#
4# This library is free software; you can redistribute it and/or
5# modify it under the terms of the GNU Lesser General Public
6# License as published by the Free Software Foundation; either
7# version 2.1 of the License, or (at your option) any later version.
8#
9# This library is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12# Lesser General Public License for more details.
13#
14# You should have received a copy of the GNU Lesser General Public
15# License along with this library; if not, write to the Free Software
16# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17#
18# For questions regarding this module contact
19# Nathan Ramella <nar@remix.net> or visit http://www.remix.net
20
21This script is based off the Ableton Live supplied MIDI Remote Scripts, customised
22for OSC request delivery and response. This script can be run without any extra
23Python libraries out of the box.
24
25This is the second file that is loaded, by way of being instantiated through
26__init__.py
27
28"""
29
30import Live
31import LiveOSCCallbacks
32import RemixNet
33import OSC
34import LiveUtils
35from Logger import Logger
36
37class LiveOSC:
38    __module__ = __name__
39    __doc__ = "Main class that establishes the LiveOSC Component"
40   
41    # Enable Logging
42    _LOG = 0
43   
44    prlisten = {}
45    plisten = {}
46    dlisten = {}
47    clisten = {}
48    slisten = {}
49    mlisten = { "solo": {}, "mute": {}, "arm": {}, "panning": {}, "volume": {}, "sends": {}, "name": {} }
50    rlisten = { "solo": {}, "mute": {}, "panning": {}, "volume": {}, "sends": {}, "name": {} }
51    masterlisten = { "panning": {}, "volume": {}, "crossfader": {} }
52    scenelisten = {}
53    scene = 0
54
55    def __init__(self, c_instance):
56        self._LiveOSC__c_instance = c_instance
57     
58        self.basicAPI = 0       
59        self.oscServer = RemixNet.OSCServer('localhost')
60        self.oscServer.sendOSC('/remix/oscserver/startup', 1)
61       
62        self.logger = self._LOG and Logger() or 0
63        self.log("Logging Enabled")
64       
65        # Visible tracks listener
66        if self.song().visible_tracks_has_listener(self.refresh_state) != 1:
67            self.song().add_visible_tracks_listener(self.refresh_state)
68       
69######################################################################
70# Standard Ableton Methods
71
72    def connect_script_instances(self, instanciated_scripts):
73        """
74        Called by the Application as soon as all scripts are initialized.
75        You can connect yourself to other running scripts here, as we do it
76        connect the extension modules
77        """
78        return
79
80    def is_extension(self):
81        return False
82
83    def request_rebuild_midi_map(self):
84        """
85        To be called from any components, as soon as their internal state changed in a
86        way, that we do need to remap the mappings that are processed directly by the
87        Live engine.
88        Dont assume that the request will immediately result in a call to
89        your build_midi_map function. For performance reasons this is only
90        called once per GUI frame.
91        """
92        return
93   
94    def update_display(self):
95        """
96        This function is run every 100ms, so we use it to initiate our Song.current_song_time
97        listener to allow us to process incoming OSC commands as quickly as possible under
98        the current listener scheme.
99        """
100        ######################################################
101        # START OSC LISTENER SETUP
102             
103        if self.basicAPI == 0:
104            # By default we have set basicAPI to 0 so that we can assign it after
105            # initialization. We try to get the current song and if we can we'll
106            # connect our basicAPI callbacks to the listener allowing us to
107            # respond to incoming OSC every 60ms.
108            #
109            # Since this method is called every 100ms regardless of the song time
110            # changing, we use both methods for processing incoming UDP requests
111            # so that from a resting state you can initiate play/clip triggering.
112           
113            try:
114                doc = self.song()
115            except:
116                return
117            try:
118                self.basicAPI = LiveOSCCallbacks.LiveOSCCallbacks(self._LiveOSC__c_instance, self.oscServer)
119                # Commented for stability
120                #doc.add_current_song_time_listener(self.oscServer.processIncomingUDP)
121                self.oscServer.sendOSC('/remix/echo', 'basicAPI setup complete')
122            except:
123                return
124           
125            # If our OSC server is listening, try processing incoming requests.
126            # Any 'play' initiation will trigger the current_song_time listener
127            # and bump updates from 100ms to 60ms.
128           
129        if self.oscServer:
130            try:
131                self.oscServer.processIncomingUDP()
132            except:
133                pass
134           
135        # END OSC LISTENER SETUP
136        ######################################################
137
138    def send_midi(self, midi_event_bytes):
139        """
140        Use this function to send MIDI events through Live to the _real_ MIDI devices
141        that this script is assigned to.
142        """
143        pass
144
145    def receive_midi(self, midi_bytes):
146        return
147
148    def can_lock_to_devices(self):
149        return False
150
151    def suggest_input_port(self):
152        return ''
153
154    def suggest_output_port(self):
155        return ''
156
157    def __handle_display_switch_ids(self, switch_id, value):
158        pass
159   
160   
161######################################################################
162# Useful Methods
163
164    def getOSCServer(self):
165        return self.oscServer
166   
167    def application(self):
168        """returns a reference to the application that we are running in"""
169        return Live.Application.get_application()
170
171    def song(self):
172        """returns a reference to the Live Song that we do interact with"""
173        return self._LiveOSC__c_instance.song()
174
175    def handle(self):
176        """returns a handle to the c_interface that is needed when forwarding MIDI events via the MIDI map"""
177        return self._LiveOSC__c_instance.handle()
178    def log(self, msg):
179        if self._LOG == 1:
180            self.logger.log(msg) 
181           
182    def getslots(self):
183        tracks = self.song().visible_tracks
184
185        clipSlots = []
186        for track in tracks:
187            clipSlots.append(track.clip_slots)
188        return clipSlots
189
190    def trBlock(self, trackOffset, blocksize):
191        block = []
192        tracks = self.song().visible_tracks
193       
194        for track in range(0, blocksize):
195            block.extend([str(tracks[trackOffset+track].name)])                           
196        self.oscServer.sendOSC("/live/name/trackblock", block)       
197
198######################################################################
199# Used Ableton Methods
200
201    def disconnect(self):
202        self.rem_clip_listeners()
203        self.rem_mixer_listeners()
204        self.rem_scene_listeners()
205        self.rem_tempo_listener()
206        self.rem_overdub_listener()
207        self.rem_tracks_listener()
208        self.rem_device_listeners()
209       
210        self.song().remove_visible_tracks_listener(self.refresh_state)
211       
212        self.oscServer.sendOSC('/remix/oscserver/shutdown', 1)
213        self.oscServer.shutdown()
214           
215    def build_midi_map(self, midi_map_handle):
216        self.refresh_state()           
217           
218    def refresh_state(self):
219        self.add_clip_listeners()
220        self.add_mixer_listeners()
221        self.add_scene_listeners()
222        self.add_tempo_listener()
223        self.add_overdub_listener()
224        self.add_tracks_listener()
225        self.add_device_listeners()
226
227        trackNumber = 0
228        clipNumber = 0
229        for track in self.song().visible_tracks:
230            self.oscServer.sendOSC("/live/name/track", (trackNumber, str(track.name)))
231           
232            for clipSlot in track.clip_slots:
233                if clipSlot.clip != None:
234                    self.oscServer.sendOSC("/live/name/clip", (trackNumber, clipNumber, str(clipSlot.clip.name), clipSlot.clip.color))
235                clipNumber = clipNumber + 1
236            clipNumber = 0
237            trackNumber = trackNumber + 1
238
239        self.trBlock(0, len(self.song().visible_tracks))
240
241######################################################################
242# Add / Remove Listeners   
243    def add_scene_listeners(self):
244        self.rem_scene_listeners()
245   
246        if self.song().view.selected_scene_has_listener(self.scene_change) != 1:
247            self.song().view.add_selected_scene_listener(self.scene_change)
248
249    def rem_scene_listeners(self):
250        if self.song().view.selected_scene_has_listener(self.scene_change) == 1:
251            self.song().view.remove_selected_scene_listener(self.scene_change)
252
253    def scene_change(self):
254        selected_scene = self.song().view.selected_scene
255        scenes = self.song().scenes
256        index = 0
257        selected_index = 0
258        for scene in scenes:
259            index = index + 1       
260            if scene == selected_scene:
261                selected_index = index
262               
263        if selected_index != self.scene:
264            self.scene = selected_index
265            self.oscServer.sendOSC("/live/scene", (selected_index))
266       
267    def add_tempo_listener(self):
268        self.rem_tempo_listener()
269   
270        print "add tempo listener"
271        if self.song().tempo_has_listener(self.tempo_change) != 1:
272            self.song().add_tempo_listener(self.tempo_change)
273       
274    def rem_tempo_listener(self):
275        if self.song().tempo_has_listener(self.tempo_change) == 1:
276            self.song().remove_tempo_listener(self.tempo_change)
277   
278    def tempo_change(self):
279        tempo = LiveUtils.getTempo()
280        self.oscServer.sendOSC("/live/tempo", (tempo))
281       
282    def add_overdub_listener(self):
283        self.rem_overdub_listener()
284   
285        if self.song().overdub_has_listener(self.overdub_change) != 1:
286            self.song().add_overdub_listener(self.overdub_change)
287           
288    def rem_overdub_listener(self):
289        if self.song().overdub_has_listener(self.overdub_change) == 1:
290            self.song().remove_overdub_listener(self.overdub_change)
291           
292    def overdub_change(self):
293        overdub = LiveUtils.getSong().overdub
294        self.oscServer.sendOSC("/live/overdub", (int(overdub) + 1))
295       
296    def add_tracks_listener(self):
297        self.rem_tracks_listener()
298   
299        if self.song().tracks_has_listener(self.tracks_change) != 1:
300            self.song().add_tracks_listener(self.tracks_change)
301   
302    def rem_tracks_listener(self):
303        if self.song().tracks_has_listener(self.tempo_change) == 1:
304            self.song().remove_tracks_listener(self.tracks_change)
305   
306    def tracks_change(self):
307        self.oscServer.sendOSC("/live/refresh", (1))
308
309    def rem_clip_listeners(self):
310        self.log("** Remove Listeners **")
311   
312        for slot in self.slisten:
313            if slot != None:
314                if slot.has_clip_has_listener(self.slisten[slot]) == 1:
315                    slot.remove_has_clip_listener(self.slisten[slot])
316   
317        self.slisten = {}
318       
319        for clip in self.clisten:
320            if clip != None:
321                if clip.playing_status_has_listener(self.clisten[clip]) == 1:
322                    clip.remove_playing_status_listener(self.clisten[clip])
323               
324        self.clisten = {}
325       
326    def add_clip_listeners(self):
327        self.rem_clip_listeners()
328   
329        tracks = self.getslots()
330        for track in range(len(tracks)):
331            for clip in range(len(tracks[track])):
332                c = tracks[track][clip]
333                if c.clip != None:
334                    self.add_cliplistener(c.clip, track, clip)
335                    self.log("ClipLauncher: added clip listener tr: " + str(track) + " clip: " + str(clip));
336               
337                self.add_slotlistener(c, track, clip)
338       
339    def add_cliplistener(self, clip, tid, cid):
340        cb = lambda :self.clip_changestate(clip, tid, cid)
341       
342        if self.clisten.has_key(clip) != 1:
343            clip.add_playing_status_listener(cb)
344            self.clisten[clip] = cb
345       
346    def add_slotlistener(self, slot, tid, cid):
347        cb = lambda :self.slot_changestate(slot, tid, cid)
348       
349        if self.slisten.has_key(slot) != 1:
350            slot.add_has_clip_listener(cb)
351            self.slisten[slot] = cb   
352           
353   
354    def rem_mixer_listeners(self):
355        # Master Track
356        for type in ("volume", "panning", "crossfader"):
357            for tr in self.masterlisten[type]:
358                if tr != None:
359                    cb = self.masterlisten[type][tr]
360               
361                    test = eval("tr.mixer_device." + type+ ".value_has_listener(cb)")
362               
363                    if test == 1:
364                        eval("tr.mixer_device." + type + ".remove_value_listener(cb)")
365
366        # Normal Tracks
367        for type in ("arm", "solo", "mute"):
368            for tr in self.mlisten[type]:
369                if tr != None:
370                    cb = self.mlisten[type][tr]
371                   
372                    if type == "arm":
373                        if tr.can_be_armed == 1:
374                            if tr.arm_has_listener(cb) == 1:
375                                tr.remove_arm_listener(cb)
376                               
377                    else:
378                        test = eval("tr." + type+ "_has_listener(cb)")
379               
380                        if test == 1:
381                            eval("tr.remove_" + type + "_listener(cb)")
382               
383        for type in ("volume", "panning"):
384            for tr in self.mlisten[type]:
385                if tr != None:
386                    cb = self.mlisten[type][tr]
387               
388                    test = eval("tr.mixer_device." + type+ ".value_has_listener(cb)")
389               
390                    if test == 1:
391                        eval("tr.mixer_device." + type + ".remove_value_listener(cb)")
392         
393        for tr in self.mlisten["sends"]:
394            if tr != None:
395                for send in self.mlisten["sends"][tr]:
396                    if send != None:
397                        cb = self.mlisten["sends"][tr][send]
398
399                        if send.value_has_listener(cb) == 1:
400                            send.remove_value_listener(cb)
401                       
402                       
403        for tr in self.mlisten["name"]:
404            if tr != None:
405                cb = self.mlisten["name"][tr]
406
407                if tr.name_has_listener(cb) == 1:
408                    tr.remove_name_listener(cb)
409                   
410        # Return Tracks               
411        for type in ("solo", "mute"):
412            for tr in self.rlisten[type]:
413                if tr != None:
414                    cb = self.rlisten[type][tr]
415               
416                    test = eval("tr." + type+ "_has_listener(cb)")
417               
418                    if test == 1:
419                        eval("tr.remove_" + type + "_listener(cb)")
420               
421        for type in ("volume", "panning"):
422            for tr in self.rlisten[type]:
423                if tr != None:
424                    cb = self.rlisten[type][tr]
425               
426                    test = eval("tr.mixer_device." + type+ ".value_has_listener(cb)")
427               
428                    if test == 1:
429                        eval("tr.mixer_device." + type + ".remove_value_listener(cb)")
430         
431        for tr in self.rlisten["sends"]:
432            if tr != None:
433                for send in self.rlisten["sends"][tr]:
434                    if send != None:
435                        cb = self.rlisten["sends"][tr][send]
436               
437                        if send.value_has_listener(cb) == 1:
438                            send.remove_value_listener(cb)
439
440        for tr in self.rlisten["name"]:
441            if tr != None:
442                cb = self.rlisten["name"][tr]
443
444                if tr.name_has_listener(cb) == 1:
445                    tr.remove_name_listener(cb)
446                   
447        self.mlisten = { "solo": {}, "mute": {}, "arm": {}, "panning": {}, "volume": {}, "sends": {}, "name": {} }
448        self.rlisten = { "solo": {}, "mute": {}, "panning": {}, "volume": {}, "sends": {}, "name": {} }
449        self.masterlisten = { "panning": {}, "volume": {}, "crossfader": {} }
450   
451   
452    def add_mixer_listeners(self):
453        self.rem_mixer_listeners()
454       
455        # Master Track
456        tr = self.song().master_track
457        for type in ("volume", "panning", "crossfader"):
458            self.add_master_listener(0, type, tr)
459       
460        # Normal Tracks
461        tracks = self.song().visible_tracks
462        for track in range(len(tracks)):
463            tr = tracks[track]
464
465            self.add_trname_listener(track, tr, 0)
466           
467            for type in ("arm", "solo", "mute"):
468                if type == "arm":
469                    if tr.can_be_armed == 1:
470                        self.add_mixert_listener(track, type, tr)
471                else:
472                    self.add_mixert_listener(track, type, tr)
473               
474            for type in ("volume", "panning"):
475                self.add_mixerv_listener(track, type, tr)
476               
477            for sid in range(len(tr.mixer_device.sends)):
478                self.add_send_listener(track, tr, sid, tr.mixer_device.sends[sid])
479       
480        # Return Tracks
481        tracks = self.song().return_tracks
482        for track in range(len(tracks)):
483            tr = tracks[track]
484
485            self.add_trname_listener(track, tr, 1)
486           
487            for type in ("solo", "mute"):
488                self.add_retmixert_listener(track, type, tr)
489               
490            for type in ("volume", "panning"):
491                self.add_retmixerv_listener(track, type, tr)
492           
493            for sid in range(len(tr.mixer_device.sends)):
494                self.add_retsend_listener(track, tr, sid, tr.mixer_device.sends[sid])
495       
496   
497    # Add track listeners
498    def add_send_listener(self, tid, track, sid, send):
499        if self.mlisten["sends"].has_key(track) != 1:
500            self.mlisten["sends"][track] = {}
501                   
502        if self.mlisten["sends"][track].has_key(send) != 1:
503            cb = lambda :self.send_changestate(tid, track, sid, send)
504           
505            self.mlisten["sends"][track][send] = cb
506            send.add_value_listener(cb)
507   
508    def add_mixert_listener(self, tid, type, track):
509        if self.mlisten[type].has_key(track) != 1:
510            cb = lambda :self.mixert_changestate(type, tid, track)
511           
512            self.mlisten[type][track] = cb
513            eval("track.add_" + type + "_listener(cb)")
514           
515    def add_mixerv_listener(self, tid, type, track):
516        if self.mlisten[type].has_key(track) != 1:
517            cb = lambda :self.mixerv_changestate(type, tid, track)
518           
519            self.mlisten[type][track] = cb
520            eval("track.mixer_device." + type + ".add_value_listener(cb)")
521
522    # Add master listeners
523    def add_master_listener(self, tid, type, track):
524        if self.masterlisten[type].has_key(track) != 1:
525            cb = lambda :self.mixerv_changestate(type, tid, track, 2)
526           
527            self.masterlisten[type][track] = cb
528            eval("track.mixer_device." + type + ".add_value_listener(cb)")
529           
530           
531    # Add return listeners
532    def add_retsend_listener(self, tid, track, sid, send):
533        if self.rlisten["sends"].has_key(track) != 1:
534            self.rlisten["sends"][track] = {}
535                   
536        if self.rlisten["sends"][track].has_key(send) != 1:
537            cb = lambda :self.send_changestate(tid, track, sid, send, 1)
538           
539            self.rlisten["sends"][track][send] = cb
540            send.add_value_listener(cb)
541   
542    def add_retmixert_listener(self, tid, type, track):
543        if self.rlisten[type].has_key(track) != 1:
544            cb = lambda :self.mixert_changestate(type, tid, track, 1)
545           
546            self.rlisten[type][track] = cb
547            eval("track.add_" + type + "_listener(cb)")
548           
549    def add_retmixerv_listener(self, tid, type, track):
550        if self.rlisten[type].has_key(track) != 1:
551            cb = lambda :self.mixerv_changestate(type, tid, track, 1)
552           
553            self.rlisten[type][track] = cb
554            eval("track.mixer_device." + type + ".add_value_listener(cb)")     
555
556
557    # Track name listener
558    def add_trname_listener(self, tid, track, ret = 0):
559        cb = lambda :self.trname_changestate(tid, track, ret)
560
561        if ret == 1:
562            if self.rlisten["name"].has_key(track) != 1:
563                self.rlisten["name"][track] = cb
564       
565        else:
566            if self.mlisten["name"].has_key(track) != 1:
567                self.mlisten["name"][track] = cb
568       
569        track.add_name_listener(cb)
570           
571
572######################################################################
573# Listener Callbacks
574       
575    # Clip Callbacks
576    def slot_changestate(self, slot, tid, cid):
577        tmptrack = LiveUtils.getTrack(tid)
578        armed = tmptrack.arm and 1 or 0
579       
580        # Added new clip
581        if slot.clip != None:
582            self.add_cliplistener(slot.clip, tid, cid)
583           
584            playing = 1
585            if slot.clip.is_playing == 1:
586                playing = 2
587           
588            if slot.clip.is_triggered == 1:
589                playing = 3
590           
591            length =  slot.clip.loop_end - slot.clip.loop_start
592           
593            self.oscServer.sendOSC('/live/track/info', (tid, armed, cid, playing, length))
594            self.oscServer.sendOSC('/live/name/clip', (tid, cid, str(slot.clip.name), slot.clip.color))
595        else:
596            if self.clisten.has_key(slot.clip) == 1:
597                slot.clip.remove_playing_status_listener(self.clisten[slot.clip])
598           
599            self.oscServer.sendOSC('/live/track/info', (tid, armed, cid, 0, 0.0))
600            self.oscServer.sendOSC('/live/clip/info', (tid, cid, 0))
601               
602        #self.log("Slot changed" + str(self.clips[tid][cid]))
603   
604    def clip_changestate(self, clip, x, y):
605        self.log("Listener: x: " + str(x) + " y: " + str(y));
606
607        playing = 1
608       
609        if clip.is_playing == 1:
610            playing = 2
611           
612        if clip.is_triggered == 1:
613            playing = 3
614           
615        self.oscServer.sendOSC('/live/clip/info', (x, y, playing))
616       
617        #self.log("Clip changed x:" + str(x) + " y:" + str(y) + " status:" + str(playing))
618       
619       
620    # Mixer Callbacks
621    def mixerv_changestate(self, type, tid, track, r = 0):
622        val = eval("track.mixer_device." + type + ".value")
623        types = { "panning": "pan", "volume": "volume", "crossfader": "crossfader" }
624       
625        if r == 2:
626            self.oscServer.sendOSC('/live/master/' + types[type], (float(val)))
627        elif r == 1:
628            self.oscServer.sendOSC('/live/return/' + types[type], (tid, float(val)))
629        else:
630            self.oscServer.sendOSC('/live/' + types[type], (tid, float(val)))       
631       
632    def mixert_changestate(self, type, tid, track, r = 0):
633        val = eval("track." + type)
634       
635        if r == 1:
636            self.oscServer.sendOSC('/live/return/' + type, (tid, int(val)))
637        else:
638            self.oscServer.sendOSC('/live/' + type, (tid, int(val)))       
639   
640    def send_changestate(self, tid, track, sid, send, r = 0):
641        val = send.value
642       
643        if r == 1:
644            self.oscServer.sendOSC('/live/return/send', (tid, sid, float(val)))   
645        else:
646            self.oscServer.sendOSC('/live/send', (tid, sid, float(val)))   
647
648
649    # Track name changestate
650    def trname_changestate(self, tid, track, r = 0):
651        if r == 1:
652            self.oscServer.sendOSC('/live/name/return', (tid, str(track.name)))
653        else:
654            self.oscServer.sendOSC('/live/name/track', (tid, str(track.name)))
655            self.trBlock(0, len(LiveUtils.getTracks()))
656           
657    # Device Listeners
658    def add_device_listeners(self):
659        self.rem_device_listeners()
660   
661        self.do_add_device_listeners(self.song().tracks,0)
662        self.do_add_device_listeners(self.song().return_tracks,1)
663        self.do_add_device_listeners([self.song().master_track],2)
664           
665    def do_add_device_listeners(self, tracks, type):
666        for i in range(len(tracks)):
667            self.add_devicelistener(tracks[i], i, type)
668       
669            if len(tracks[i].devices) >= 1:
670                for j in range(len(tracks[i].devices)):
671                    self.add_devpmlistener(tracks[i].devices[j])
672               
673                    if len(tracks[i].devices[j].parameters) >= 1:
674                        for k in range (len(tracks[i].devices[j].parameters)):
675                            par = tracks[i].devices[j].parameters[k]
676                            self.add_paramlistener(par, i, j, k, type)
677           
678    def rem_device_listeners(self):
679        for pr in self.prlisten:
680            ocb = self.prlisten[pr]
681            if pr != None:
682                if pr.value_has_listener(ocb) == 1:
683                    pr.remove_value_listener(ocb)
684       
685        self.prlisten = {}
686       
687        for tr in self.dlisten:
688            ocb = self.dlisten[tr]
689            if tr != None:
690                if tr.view.selected_device_has_listener(ocb) == 1:
691                    tr.view.remove_selected_device_listener(ocb)
692                   
693        self.dlisten = {}
694       
695        for de in self.plisten:
696            ocb = self.plisten[de]
697            if de != None:
698                if de.parameters_has_listener(ocb) == 1:
699                    de.remove_parameters_listener(ocb)
700                   
701        self.plisten = {}
702
703    def add_devpmlistener(self, device):
704        cb = lambda :self.devpm_change()
705       
706        if self.plisten.has_key(device) != 1:
707            device.add_parameters_listener(cb)
708            self.plisten[device] = cb
709   
710    def devpm_change(self):
711        self.refresh_state()
712       
713    def add_paramlistener(self, param, tid, did, pid, type):
714        cb = lambda :self.param_changestate(param, tid, did, pid, type)
715       
716        if self.prlisten.has_key(param) != 1:
717            param.add_value_listener(cb)
718            self.prlisten[param] = cb
719           
720    def param_changestate(self, param, tid, did, pid, type):
721        if type == 2:
722            self.oscServer.sendOSC('/live/master/device/param', (did, pid, param.value, str(param.name)))
723        elif type == 1:
724            self.oscServer.sendOSC('/live/return/device/param', (tid, did, pid, param.value, str(param.name)))
725        else:
726            self.oscServer.sendOSC('/live/device/param', (tid, did, pid, param.value, str(param.name)))
727       
728    def add_devicelistener(self, track, tid, type):
729        cb = lambda :self.device_changestate(track, tid, type)
730       
731        if self.dlisten.has_key(track) != 1:
732            track.view.add_selected_device_listener(cb)
733            self.dlisten[track] = cb
734       
735    def device_changestate(self, track, tid, type):
736        did = self.tuple_idx(track.devices, track.view.selected_device)
737       
738        if type == 2:
739            self.oscServer.sendOSC('/live/master/devices/selected', (did))
740        elif type == 1:
741            self.oscServer.sendOSC('/live/return/device/selected', (tid, did))
742        else:
743            self.oscServer.sendOSC('/live/device/selected', (tid, did))       
744       
745    def tuple_idx(self, tuple, obj):
746        for i in xrange(0,len(tuple)):
747            if (tuple[i] == obj):
748                return i
Note: See TracBrowser for help on using the repository browser.