source: trunk/LiveOSC/LiveOSC.py @ 68

Revision 68, 34.2 KB checked in by st8, 6 months ago (diff)

LiveControl: Added Clip sequencer application, doubled resolution of device control. LiveOSC: Added toggles for meter/clip listeners, added transport listener

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    pplisten = {}
50    cnlisten = {}
51    cclisten = {}
52   
53    mlisten = { "solo": {}, "mute": {}, "arm": {}, "panning": {}, "volume": {}, "sends": {}, "name": {}, "oml": {}, "omr": {} }
54    rlisten = { "solo": {}, "mute": {}, "panning": {}, "volume": {}, "sends": {}, "name": {} }
55    masterlisten = { "panning": {}, "volume": {}, "crossfader": {} }
56    scenelisten = {}
57   
58    scene = 0
59    track = 0
60
61    def __init__(self, c_instance):
62        self._LiveOSC__c_instance = c_instance
63     
64        self.basicAPI = 0       
65        self.oscServer = RemixNet.OSCServer('localhost')
66        self.oscServer.sendOSC('/remix/oscserver/startup', 1)
67       
68        self.logger = self._LOG and Logger() or 0
69        self.log("Logging Enabled")
70       
71        # Visible tracks listener
72        if self.song().visible_tracks_has_listener(self.refresh_state) != 1:
73            self.song().add_visible_tracks_listener(self.refresh_state)
74       
75######################################################################
76# Standard Ableton Methods
77
78    def connect_script_instances(self, instanciated_scripts):
79        """
80        Called by the Application as soon as all scripts are initialized.
81        You can connect yourself to other running scripts here, as we do it
82        connect the extension modules
83        """
84        return
85
86    def is_extension(self):
87        return False
88
89    def request_rebuild_midi_map(self):
90        """
91        To be called from any components, as soon as their internal state changed in a
92        way, that we do need to remap the mappings that are processed directly by the
93        Live engine.
94        Dont assume that the request will immediately result in a call to
95        your build_midi_map function. For performance reasons this is only
96        called once per GUI frame.
97        """
98        return
99   
100    def update_display(self):
101        """
102        This function is run every 100ms, so we use it to initiate our Song.current_song_time
103        listener to allow us to process incoming OSC commands as quickly as possible under
104        the current listener scheme.
105        """
106        ######################################################
107        # START OSC LISTENER SETUP
108             
109        if self.basicAPI == 0:
110            # By default we have set basicAPI to 0 so that we can assign it after
111            # initialization. We try to get the current song and if we can we'll
112            # connect our basicAPI callbacks to the listener allowing us to
113            # respond to incoming OSC every 60ms.
114            #
115            # Since this method is called every 100ms regardless of the song time
116            # changing, we use both methods for processing incoming UDP requests
117            # so that from a resting state you can initiate play/clip triggering.
118           
119            try:
120                doc = self.song()
121            except:
122                return
123            try:
124                self.basicAPI = LiveOSCCallbacks.LiveOSCCallbacks(self._LiveOSC__c_instance, self.oscServer)
125                # Commented for stability
126                #doc.add_current_song_time_listener(self.oscServer.processIncomingUDP)
127                self.oscServer.sendOSC('/remix/echo', 'basicAPI setup complete')
128            except:
129                return
130           
131            # If our OSC server is listening, try processing incoming requests.
132            # Any 'play' initiation will trigger the current_song_time listener
133            # and bump updates from 100ms to 60ms.
134           
135        if self.oscServer:
136            try:
137                self.oscServer.processIncomingUDP()
138            except:
139                pass
140           
141        # END OSC LISTENER SETUP
142        ######################################################
143
144    def send_midi(self, midi_event_bytes):
145        """
146        Use this function to send MIDI events through Live to the _real_ MIDI devices
147        that this script is assigned to.
148        """
149        pass
150
151    def receive_midi(self, midi_bytes):
152        return
153
154    def can_lock_to_devices(self):
155        return False
156
157    def suggest_input_port(self):
158        return ''
159
160    def suggest_output_port(self):
161        return ''
162
163    def __handle_display_switch_ids(self, switch_id, value):
164        pass
165   
166   
167######################################################################
168# Useful Methods
169
170    def getOSCServer(self):
171        return self.oscServer
172   
173    def application(self):
174        """returns a reference to the application that we are running in"""
175        return Live.Application.get_application()
176
177    def song(self):
178        """returns a reference to the Live Song that we do interact with"""
179        return self._LiveOSC__c_instance.song()
180
181    def handle(self):
182        """returns a handle to the c_interface that is needed when forwarding MIDI events via the MIDI map"""
183        return self._LiveOSC__c_instance.handle()
184    def log(self, msg):
185        if self._LOG == 1:
186            self.logger.log(msg) 
187           
188    def getslots(self):
189        tracks = self.song().visible_tracks
190
191        clipSlots = []
192        for track in tracks:
193            clipSlots.append(track.clip_slots)
194        return clipSlots
195
196    def trBlock(self, trackOffset, blocksize):
197        block = []
198        tracks = self.song().visible_tracks
199       
200        for track in range(0, blocksize):
201            block.extend([str(tracks[trackOffset+track].name)])                           
202        self.oscServer.sendOSC("/live/name/trackblock", block)       
203
204######################################################################
205# Used Ableton Methods
206
207    def disconnect(self):
208        self.rem_clip_listeners()
209        self.rem_mixer_listeners()
210        self.rem_scene_listeners()
211        self.rem_tempo_listener()
212        self.rem_overdub_listener()
213        self.rem_tracks_listener()
214        self.rem_device_listeners()
215        self.rem_transport_listener()
216       
217        self.song().remove_visible_tracks_listener(self.refresh_state)
218       
219        self.oscServer.sendOSC('/remix/oscserver/shutdown', 1)
220        self.oscServer.shutdown()
221           
222    def build_midi_map(self, midi_map_handle):
223        self.refresh_state()           
224           
225    def refresh_state(self):
226        self.add_clip_listeners()
227        self.add_mixer_listeners()
228        self.add_scene_listeners()
229        self.add_tempo_listener()
230        self.add_overdub_listener()
231        self.add_tracks_listener()
232        self.add_device_listeners()
233        self.add_transport_listener()
234
235        trackNumber = 0
236        clipNumber = 0
237        for track in self.song().visible_tracks:
238            self.oscServer.sendOSC("/live/name/track", (trackNumber, str(track.name)))
239           
240            for clipSlot in track.clip_slots:
241                if clipSlot.clip != None:
242                    self.oscServer.sendOSC("/live/name/clip", (trackNumber, clipNumber, str(clipSlot.clip.name), clipSlot.clip.color))
243                clipNumber = clipNumber + 1
244            clipNumber = 0
245            trackNumber = trackNumber + 1
246
247        self.trBlock(0, len(self.song().visible_tracks))
248
249######################################################################
250# Add / Remove Listeners   
251    def add_scene_listeners(self):
252        self.rem_scene_listeners()
253   
254        if self.song().view.selected_scene_has_listener(self.scene_change) != 1:
255            self.song().view.add_selected_scene_listener(self.scene_change)
256
257        if self.song().view.selected_track_has_listener(self.track_change) != 1:
258            self.song().view.add_selected_track_listener(self.track_change)
259
260    def rem_scene_listeners(self):
261        if self.song().view.selected_scene_has_listener(self.scene_change) == 1:
262            self.song().view.remove_selected_scene_listener(self.scene_change)
263           
264        if self.song().view.selected_track_has_listener(self.track_change) == 1:
265            self.song().view.remove_selected_track_listener(self.track_change)
266
267    def track_change(self):
268        selected_track = self.song().view.selected_track
269        tracks = self.song().visible_tracks
270        index = 0
271        selected_index = 0
272        for track in tracks:
273            index = index + 1       
274            if track == selected_track:
275                selected_index = index
276               
277        if selected_index != self.track:
278            self.track = selected_index
279            self.oscServer.sendOSC("/live/track", (selected_index))
280
281    def scene_change(self):
282        selected_scene = self.song().view.selected_scene
283        scenes = self.song().scenes
284        index = 0
285        selected_index = 0
286        for scene in scenes:
287            index = index + 1       
288            if scene == selected_scene:
289                selected_index = index
290               
291        if selected_index != self.scene:
292            self.scene = selected_index
293            self.oscServer.sendOSC("/live/scene", (selected_index))
294       
295    def add_tempo_listener(self):
296        self.rem_tempo_listener()
297   
298        print "add tempo listener"
299        if self.song().tempo_has_listener(self.tempo_change) != 1:
300            self.song().add_tempo_listener(self.tempo_change)
301       
302    def rem_tempo_listener(self):
303        if self.song().tempo_has_listener(self.tempo_change) == 1:
304            self.song().remove_tempo_listener(self.tempo_change)
305   
306    def tempo_change(self):
307        tempo = LiveUtils.getTempo()
308        self.oscServer.sendOSC("/live/tempo", (tempo))
309       
310    def add_transport_listener(self):
311        if self.song().is_playing_has_listener(self.transport_change) != 1:
312            self.song().add_is_playing_listener(self.transport_change)
313           
314    def rem_transport_listener(self):
315        if self.song().is_playing_has_listener(self.transport_change) == 1:
316            self.song().remove_is_playing_listener(self.transport_change)   
317   
318    def transport_change(self):
319        self.oscServer.sendOSC("/live/play", (self.song().is_playing and 2 or 1))
320   
321    def add_overdub_listener(self):
322        self.rem_overdub_listener()
323   
324        if self.song().overdub_has_listener(self.overdub_change) != 1:
325            self.song().add_overdub_listener(self.overdub_change)
326           
327    def rem_overdub_listener(self):
328        if self.song().overdub_has_listener(self.overdub_change) == 1:
329            self.song().remove_overdub_listener(self.overdub_change)
330           
331    def overdub_change(self):
332        overdub = LiveUtils.getSong().overdub
333        self.oscServer.sendOSC("/live/overdub", (int(overdub) + 1))
334       
335    def add_tracks_listener(self):
336        self.rem_tracks_listener()
337   
338        if self.song().tracks_has_listener(self.tracks_change) != 1:
339            self.song().add_tracks_listener(self.tracks_change)
340   
341    def rem_tracks_listener(self):
342        if self.song().tracks_has_listener(self.tempo_change) == 1:
343            self.song().remove_tracks_listener(self.tracks_change)
344   
345    def tracks_change(self):
346        self.oscServer.sendOSC("/live/refresh", (1))
347
348    def rem_clip_listeners(self):
349        self.log("** Remove Listeners **")
350   
351        for slot in self.slisten:
352            if slot != None:
353                if slot.has_clip_has_listener(self.slisten[slot]) == 1:
354                    slot.remove_has_clip_listener(self.slisten[slot])
355   
356        self.slisten = {}
357       
358        for clip in self.clisten:
359            if clip != None:
360                if clip.playing_status_has_listener(self.clisten[clip]) == 1:
361                    clip.remove_playing_status_listener(self.clisten[clip])
362               
363        self.clisten = {}
364
365        for clip in self.pplisten:
366            if clip != None:
367                if clip.playing_position_has_listener(self.pplisten[clip]) == 1:
368                    clip.remove_playing_position_listener(self.pplisten[clip])
369               
370        self.pplisten = {}
371
372        for clip in self.cnlisten:
373            if clip != None:
374                if clip.name_has_listener(self.cnlisten[clip]) == 1:
375                    clip.remove_name_listener(self.cnlisten[clip])
376               
377        self.cnlisten = {}
378
379        for clip in self.cclisten:
380            if clip != None:
381                if clip.color_has_listener(self.cclisten[clip]) == 1:
382                    clip.remove_color_listener(self.cclisten[clip])
383               
384        self.cclisten = {}
385       
386    def add_clip_listeners(self):
387        self.rem_clip_listeners()
388   
389        tracks = self.getslots()
390        for track in range(len(tracks)):
391            for clip in range(len(tracks[track])):
392                c = tracks[track][clip]
393                if c.clip != None:
394                    self.add_cliplistener(c.clip, track, clip)
395                    self.log("ClipLauncher: added clip listener tr: " + str(track) + " clip: " + str(clip));
396               
397                self.add_slotlistener(c, track, clip)
398       
399    def add_cliplistener(self, clip, tid, cid):
400        cb = lambda :self.clip_changestate(clip, tid, cid)
401       
402        if self.clisten.has_key(clip) != 1:
403            clip.add_playing_status_listener(cb)
404            self.clisten[clip] = cb
405           
406        cb2 = lambda :self.clip_position(clip, tid, cid)
407        if self.pplisten.has_key(clip) != 1:
408            clip.add_playing_position_listener(cb2)
409            self.pplisten[clip] = cb2
410           
411        cb3 = lambda :self.clip_name(clip, tid, cid)
412        if self.cnlisten.has_key(clip) != 1:
413            clip.add_name_listener(cb3)
414            self.cnlisten[clip] = cb3
415
416        if self.cclisten.has_key(clip) != 1:
417            clip.add_color_listener(cb3)
418            self.cclisten[clip] = cb3
419       
420    def add_slotlistener(self, slot, tid, cid):
421        cb = lambda :self.slot_changestate(slot, tid, cid)
422       
423        if self.slisten.has_key(slot) != 1:
424            slot.add_has_clip_listener(cb)
425            self.slisten[slot] = cb   
426           
427   
428    def rem_mixer_listeners(self):
429        # Master Track
430        for type in ("volume", "panning", "crossfader"):
431            for tr in self.masterlisten[type]:
432                if tr != None:
433                    cb = self.masterlisten[type][tr]
434               
435                    test = eval("tr.mixer_device." + type+ ".value_has_listener(cb)")
436               
437                    if test == 1:
438                        eval("tr.mixer_device." + type + ".remove_value_listener(cb)")
439
440        # Normal Tracks
441        for type in ("arm", "solo", "mute"):
442            for tr in self.mlisten[type]:
443                if tr != None:
444                    cb = self.mlisten[type][tr]
445                   
446                    if type == "arm":
447                        if tr.can_be_armed == 1:
448                            if tr.arm_has_listener(cb) == 1:
449                                tr.remove_arm_listener(cb)
450                               
451                    else:
452                        test = eval("tr." + type+ "_has_listener(cb)")
453               
454                        if test == 1:
455                            eval("tr.remove_" + type + "_listener(cb)")
456               
457        for type in ("volume", "panning"):
458            for tr in self.mlisten[type]:
459                if tr != None:
460                    cb = self.mlisten[type][tr]
461               
462                    test = eval("tr.mixer_device." + type+ ".value_has_listener(cb)")
463               
464                    if test == 1:
465                        eval("tr.mixer_device." + type + ".remove_value_listener(cb)")
466         
467        for tr in self.mlisten["sends"]:
468            if tr != None:
469                for send in self.mlisten["sends"][tr]:
470                    if send != None:
471                        cb = self.mlisten["sends"][tr][send]
472
473                        if send.value_has_listener(cb) == 1:
474                            send.remove_value_listener(cb)
475                       
476                       
477        for tr in self.mlisten["name"]:
478            if tr != None:
479                cb = self.mlisten["name"][tr]
480
481                if tr.name_has_listener(cb) == 1:
482                    tr.remove_name_listener(cb)
483
484        for tr in self.mlisten["oml"]:
485            if tr != None:
486                cb = self.mlisten["oml"][tr]
487
488                if tr.output_meter_left_has_listener(cb) == 1:
489                    tr.remove_output_meter_left_listener(cb)
490
491        for tr in self.mlisten["omr"]:
492            if tr != None:
493                cb = self.mlisten["omr"][tr]
494
495                if tr.output_meter_right_has_listener(cb) == 1:
496                    tr.remove_output_meter_right_listener(cb)
497                   
498        # Return Tracks               
499        for type in ("solo", "mute"):
500            for tr in self.rlisten[type]:
501                if tr != None:
502                    cb = self.rlisten[type][tr]
503               
504                    test = eval("tr." + type+ "_has_listener(cb)")
505               
506                    if test == 1:
507                        eval("tr.remove_" + type + "_listener(cb)")
508               
509        for type in ("volume", "panning"):
510            for tr in self.rlisten[type]:
511                if tr != None:
512                    cb = self.rlisten[type][tr]
513               
514                    test = eval("tr.mixer_device." + type+ ".value_has_listener(cb)")
515               
516                    if test == 1:
517                        eval("tr.mixer_device." + type + ".remove_value_listener(cb)")
518         
519        for tr in self.rlisten["sends"]:
520            if tr != None:
521                for send in self.rlisten["sends"][tr]:
522                    if send != None:
523                        cb = self.rlisten["sends"][tr][send]
524               
525                        if send.value_has_listener(cb) == 1:
526                            send.remove_value_listener(cb)
527
528        for tr in self.rlisten["name"]:
529            if tr != None:
530                cb = self.rlisten["name"][tr]
531
532                if tr.name_has_listener(cb) == 1:
533                    tr.remove_name_listener(cb)
534                   
535        self.mlisten = { "solo": {}, "mute": {}, "arm": {}, "panning": {}, "volume": {}, "sends": {}, "name": {}, "oml": {}, "omr": {} }
536        self.rlisten = { "solo": {}, "mute": {}, "panning": {}, "volume": {}, "sends": {}, "name": {} }
537        self.masterlisten = { "panning": {}, "volume": {}, "crossfader": {} }
538   
539   
540    def add_mixer_listeners(self):
541        self.rem_mixer_listeners()
542       
543        # Master Track
544        tr = self.song().master_track
545        for type in ("volume", "panning", "crossfader"):
546            self.add_master_listener(0, type, tr)
547       
548        self.add_meter_listener(0, tr, 2)
549       
550        # Normal Tracks
551        tracks = self.song().visible_tracks
552        for track in range(len(tracks)):
553            tr = tracks[track]
554
555            self.add_trname_listener(track, tr, 0)
556           
557            if tr.has_audio_output:
558                self.add_meter_listener(track, tr)
559           
560            for type in ("arm", "solo", "mute"):
561                if type == "arm":
562                    if tr.can_be_armed == 1:
563                        self.add_mixert_listener(track, type, tr)
564                else:
565                    self.add_mixert_listener(track, type, tr)
566               
567            for type in ("volume", "panning"):
568                self.add_mixerv_listener(track, type, tr)
569               
570            for sid in range(len(tr.mixer_device.sends)):
571                self.add_send_listener(track, tr, sid, tr.mixer_device.sends[sid])
572       
573        # Return Tracks
574        tracks = self.song().return_tracks
575        for track in range(len(tracks)):
576            tr = tracks[track]
577
578            self.add_trname_listener(track, tr, 1)
579            self.add_meter_listener(track, tr, 1)
580           
581            for type in ("solo", "mute"):
582                self.add_retmixert_listener(track, type, tr)
583               
584            for type in ("volume", "panning"):
585                self.add_retmixerv_listener(track, type, tr)
586           
587            for sid in range(len(tr.mixer_device.sends)):
588                self.add_retsend_listener(track, tr, sid, tr.mixer_device.sends[sid])
589       
590   
591    # Add track listeners
592    def add_send_listener(self, tid, track, sid, send):
593        if self.mlisten["sends"].has_key(track) != 1:
594            self.mlisten["sends"][track] = {}
595                   
596        if self.mlisten["sends"][track].has_key(send) != 1:
597            cb = lambda :self.send_changestate(tid, track, sid, send)
598           
599            self.mlisten["sends"][track][send] = cb
600            send.add_value_listener(cb)
601   
602    def add_mixert_listener(self, tid, type, track):
603        if self.mlisten[type].has_key(track) != 1:
604            cb = lambda :self.mixert_changestate(type, tid, track)
605           
606            self.mlisten[type][track] = cb
607            eval("track.add_" + type + "_listener(cb)")
608           
609    def add_mixerv_listener(self, tid, type, track):
610        if self.mlisten[type].has_key(track) != 1:
611            cb = lambda :self.mixerv_changestate(type, tid, track)
612           
613            self.mlisten[type][track] = cb
614            eval("track.mixer_device." + type + ".add_value_listener(cb)")
615
616    # Add master listeners
617    def add_master_listener(self, tid, type, track):
618        if self.masterlisten[type].has_key(track) != 1:
619            cb = lambda :self.mixerv_changestate(type, tid, track, 2)
620           
621            self.masterlisten[type][track] = cb
622            eval("track.mixer_device." + type + ".add_value_listener(cb)")
623           
624           
625    # Add return listeners
626    def add_retsend_listener(self, tid, track, sid, send):
627        if self.rlisten["sends"].has_key(track) != 1:
628            self.rlisten["sends"][track] = {}
629                   
630        if self.rlisten["sends"][track].has_key(send) != 1:
631            cb = lambda :self.send_changestate(tid, track, sid, send, 1)
632           
633            self.rlisten["sends"][track][send] = cb
634            send.add_value_listener(cb)
635   
636    def add_retmixert_listener(self, tid, type, track):
637        if self.rlisten[type].has_key(track) != 1:
638            cb = lambda :self.mixert_changestate(type, tid, track, 1)
639           
640            self.rlisten[type][track] = cb
641            eval("track.add_" + type + "_listener(cb)")
642           
643    def add_retmixerv_listener(self, tid, type, track):
644        if self.rlisten[type].has_key(track) != 1:
645            cb = lambda :self.mixerv_changestate(type, tid, track, 1)
646           
647            self.rlisten[type][track] = cb
648            eval("track.mixer_device." + type + ".add_value_listener(cb)")     
649
650
651    # Track name listener
652    def add_trname_listener(self, tid, track, ret = 0):
653        cb = lambda :self.trname_changestate(tid, track, ret)
654
655        if ret == 1:
656            if self.rlisten["name"].has_key(track) != 1:
657                self.rlisten["name"][track] = cb
658       
659        else:
660            if self.mlisten["name"].has_key(track) != 1:
661                self.mlisten["name"][track] = cb
662       
663        track.add_name_listener(cb)
664       
665    # Output Meter Listeners
666    def add_meter_listener(self, tid, track, r = 0):
667        cb = lambda :self.meter_changestate(tid, track, 0, r)
668
669        if self.mlisten["oml"].has_key(track) != 1:
670            self.mlisten["oml"][track] = cb
671
672        track.add_output_meter_left_listener(cb)
673
674        cb = lambda :self.meter_changestate(tid, track, 1, r)
675
676        if self.mlisten["omr"].has_key(track) != 1:
677            self.mlisten["omr"][track] = cb
678
679        track.add_output_meter_right_listener(cb)
680
681######################################################################
682# Listener Callbacks
683       
684    # Clip Callbacks
685    def clip_name(self, clip, tid, cid):
686        self.oscServer.sendOSC('/live/name/clip', (tid, cid, str(clip.name), clip.color))
687   
688    def clip_position(self, clip, tid, cid):
689        if self.check_md(1):
690            if clip.is_playing:
691                self.oscServer.sendOSC('/live/clip/position', (tid, cid, clip.playing_position, clip.length, clip.loop_start, clip.loop_end))
692   
693    def slot_changestate(self, slot, tid, cid):
694        tmptrack = LiveUtils.getTrack(tid)
695        armed = tmptrack.arm and 1 or 0
696       
697        # Added new clip
698        if slot.clip != None:
699            self.add_cliplistener(slot.clip, tid, cid)
700           
701            playing = 1
702            if slot.clip.is_playing == 1:
703                playing = 2
704           
705            if slot.clip.is_triggered == 1:
706                playing = 3
707           
708            length =  slot.clip.loop_end - slot.clip.loop_start
709           
710            self.oscServer.sendOSC('/live/track/info', (tid, armed, cid, playing, length))
711            self.oscServer.sendOSC('/live/name/clip', (tid, cid, str(slot.clip.name), slot.clip.color))
712        else:
713            if self.clisten.has_key(slot.clip) == 1:
714                slot.clip.remove_playing_status_listener(self.clisten[slot.clip])
715               
716            if self.pplisten.has_key(slot.clip) == 1:
717                slot.clip.remove_playing_position_listener(self.pplisten[slot.clip])
718
719            if self.cnlisten.has_key(slot.clip) == 1:
720                slot.clip.remove_name_listener(self.cnlisten[slot.clip])
721
722            if self.cclisten.has_key(slot.clip) == 1:
723                slot.clip.remove_color_listener(self.cclisten[slot.clip])
724           
725            self.oscServer.sendOSC('/live/track/info', (tid, armed, cid, 0, 0.0))
726            self.oscServer.sendOSC('/live/clip/info', (tid, cid, 0))
727               
728        #self.log("Slot changed" + str(self.clips[tid][cid]))
729   
730    def clip_changestate(self, clip, x, y):
731        self.log("Listener: x: " + str(x) + " y: " + str(y));
732
733        playing = 1
734       
735        if clip.is_playing == 1:
736            playing = 2
737           
738        if clip.is_triggered == 1:
739            playing = 3
740           
741        self.oscServer.sendOSC('/live/clip/info', (x, y, playing))
742       
743        #self.log("Clip changed x:" + str(x) + " y:" + str(y) + " status:" + str(playing))
744       
745       
746    # Mixer Callbacks
747    def mixerv_changestate(self, type, tid, track, r = 0):
748        val = eval("track.mixer_device." + type + ".value")
749        types = { "panning": "pan", "volume": "volume", "crossfader": "crossfader" }
750       
751        if r == 2:
752            self.oscServer.sendOSC('/live/master/' + types[type], (float(val)))
753        elif r == 1:
754            self.oscServer.sendOSC('/live/return/' + types[type], (tid, float(val)))
755        else:
756            self.oscServer.sendOSC('/live/' + types[type], (tid, float(val)))       
757       
758    def mixert_changestate(self, type, tid, track, r = 0):
759        val = eval("track." + type)
760       
761        if r == 1:
762            self.oscServer.sendOSC('/live/return/' + type, (tid, int(val)))
763        else:
764            self.oscServer.sendOSC('/live/' + type, (tid, int(val)))       
765   
766    def send_changestate(self, tid, track, sid, send, r = 0):
767        val = send.value
768       
769        if r == 1:
770            self.oscServer.sendOSC('/live/return/send', (tid, sid, float(val)))   
771        else:
772            self.oscServer.sendOSC('/live/send', (tid, sid, float(val)))   
773
774
775    # Track name changestate
776    def trname_changestate(self, tid, track, r = 0):
777        if r == 1:
778            self.oscServer.sendOSC('/live/name/return', (tid, str(track.name)))
779        else:
780            self.oscServer.sendOSC('/live/name/track', (tid, str(track.name)))
781            self.trBlock(0, len(LiveUtils.getTracks()))
782           
783    # Meter Changestate
784    def meter_changestate(self, tid, track, lr, r = 0):
785        if r == 2:
786            if self.check_md(2):
787                if lr == 0:
788                    self.oscServer.sendOSC('/live/master/meter', (0, float(track.output_meter_left)))
789                else:
790                    self.oscServer.sendOSC('/live/master/meter', (1, float(track.output_meter_right)))
791        elif r == 1:
792            if self.check_md(3):
793                if lr == 0:
794                    self.oscServer.sendOSC('/live/return/meter', (tid, 0, float(track.output_meter_left)))
795                else:
796                    self.oscServer.sendOSC('/live/return/meter', (tid, 1, float(track.output_meter_right)))       
797        else:
798            if self.check_md(4):
799                if lr == 0:
800                    self.oscServer.sendOSC('/live/track/meter', (tid, 0, float(track.output_meter_left)))
801                else:
802                    self.oscServer.sendOSC('/live/track/meter', (tid, 1, float(track.output_meter_right)))
803   
804    def check_md(self, param):
805        devices = self.song().master_track.devices
806       
807        if len(devices) > 0:
808            if devices[0].parameters[param].value > 0:
809                return 1
810            else:
811                return 0
812        else:
813            return 0
814   
815    # Device Listeners
816    def add_device_listeners(self):
817        self.rem_device_listeners()
818   
819        self.do_add_device_listeners(self.song().tracks,0)
820        self.do_add_device_listeners(self.song().return_tracks,1)
821        self.do_add_device_listeners([self.song().master_track],2)
822           
823    def do_add_device_listeners(self, tracks, type):
824        for i in range(len(tracks)):
825            self.add_devicelistener(tracks[i], i, type)
826       
827            if len(tracks[i].devices) >= 1:
828                for j in range(len(tracks[i].devices)):
829                    self.add_devpmlistener(tracks[i].devices[j])
830               
831                    if len(tracks[i].devices[j].parameters) >= 1:
832                        for k in range (len(tracks[i].devices[j].parameters)):
833                            par = tracks[i].devices[j].parameters[k]
834                            self.add_paramlistener(par, i, j, k, type)
835           
836    def rem_device_listeners(self):
837        for pr in self.prlisten:
838            ocb = self.prlisten[pr]
839            if pr != None:
840                if pr.value_has_listener(ocb) == 1:
841                    pr.remove_value_listener(ocb)
842       
843        self.prlisten = {}
844       
845        for tr in self.dlisten:
846            ocb = self.dlisten[tr]
847            if tr != None:
848                if tr.view.selected_device_has_listener(ocb) == 1:
849                    tr.view.remove_selected_device_listener(ocb)
850                   
851        self.dlisten = {}
852       
853        for de in self.plisten:
854            ocb = self.plisten[de]
855            if de != None:
856                if de.parameters_has_listener(ocb) == 1:
857                    de.remove_parameters_listener(ocb)
858                   
859        self.plisten = {}
860
861    def add_devpmlistener(self, device):
862        cb = lambda :self.devpm_change()
863       
864        if self.plisten.has_key(device) != 1:
865            device.add_parameters_listener(cb)
866            self.plisten[device] = cb
867   
868    def devpm_change(self):
869        self.refresh_state()
870       
871    def add_paramlistener(self, param, tid, did, pid, type):
872        cb = lambda :self.param_changestate(param, tid, did, pid, type)
873       
874        if self.prlisten.has_key(param) != 1:
875            param.add_value_listener(cb)
876            self.prlisten[param] = cb
877           
878    def param_changestate(self, param, tid, did, pid, type):
879        if type == 2:
880            self.oscServer.sendOSC('/live/master/device/param', (did, pid, param.value, str(param.name)))
881        elif type == 1:
882            self.oscServer.sendOSC('/live/return/device/param', (tid, did, pid, param.value, str(param.name)))
883        else:
884            self.oscServer.sendOSC('/live/device/param', (tid, did, pid, param.value, str(param.name)))
885       
886    def add_devicelistener(self, track, tid, type):
887        cb = lambda :self.device_changestate(track, tid, type)
888       
889        if self.dlisten.has_key(track) != 1:
890            track.view.add_selected_device_listener(cb)
891            self.dlisten[track] = cb
892       
893    def device_changestate(self, track, tid, type):
894        did = self.tuple_idx(track.devices, track.view.selected_device)
895       
896        if type == 2:
897            self.oscServer.sendOSC('/live/master/devices/selected', (did))
898        elif type == 1:
899            self.oscServer.sendOSC('/live/return/device/selected', (tid, did))
900        else:
901            self.oscServer.sendOSC('/live/device/selected', (tid, did))       
902       
903    def tuple_idx(self, tuple, obj):
904        for i in xrange(0,len(tuple)):
905            if (tuple[i] == obj):
906                return i
Note: See TracBrowser for help on using the repository browser.