Skip to content

Commit

Permalink
Set.scan() automatic checks for set changes; tracebacks on errors dur…
Browse files Browse the repository at this point in the history
…ing OSC callback
  • Loading branch information
ideoforms committed May 17, 2014
1 parent c7bf67b commit dfb52b2
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 12 deletions.
6 changes: 6 additions & 0 deletions live/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def __init__(self, set, track_index, group_index, name):
self.index = track_index
self.indent = 1
self.name = name
self.group = None
self.tracks = []
self.clips = []

Expand Down Expand Up @@ -55,6 +56,11 @@ def play_clip(self, clip_index):
""" Start playing group clip. """
self.set.play_clip(self.track_index, clip_index)

def stop(self):
""" Immediately stop group from playing. """
self.playing = False
self.set.stop_track(self.track_index)

@property
def active_clips(self):
""" Return a dictionary of all non-empty clipslots: { index : Clip, ... } """
Expand Down
18 changes: 12 additions & 6 deletions live/object.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import live

class LoggingObject(object):
""" Helper superclass for objects which wish to generate debugging output
with hierachical indentation.
Expand All @@ -15,15 +17,19 @@ def __init__(self):
self.logger = logging.getLogger(__name__)
print "created logger: %s" % __name__

def trace(self, msg = ""):
def trace(self, msg = None, *args):
if msg:
msg = msg % args
print "%s[%s] %s" % (" " * 3 * self.indent, self, msg)

def warn(self, msg = ""):
print "[%s] !!! warning: %s !!!" % (self, msg)
def warn(self, msg, *args):
msg = msg % args
print "[%s] [WARN] %s !!!" % (self, msg)

def debug(self, msg = ""):
if self.debug:
print "[%s] !!! debug: %s !!!" % (self, msg)
def debug(self, msg, *args):
msg = msg % args
if live.debug:
print "[%s] [DEBUG] %s" % (self, msg)

def name_cache(fn):
""" Decorator enabling pairs of set_XX/get_XX methods to cache their
Expand Down
12 changes: 9 additions & 3 deletions live/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,12 @@ def __init__(self, address = ("localhost", 9000), listen_port = 9001):
self.osc_address = address
self.osc_client = OSCClient()
self.osc_client.connect(address)
self.osc_server = OSCServer(("localhost", self.listen_port))
self.osc_server_thread = None
try:
self.osc_server = OSCServer(("localhost", self.listen_port))
self.osc_server.print_tracebacks = True
self.osc_server_thread = None
except:
"Couldn't connect to Live (is another process already connected?)"
self.osc_read_event = None
self.osc_timeout = 5

Expand Down Expand Up @@ -106,6 +110,7 @@ def cmd(self, msg, *args):

msg = OSCMessage(msg)
msg.extend(list(args))
self.debug("OSC: %s %s", msg, args)
try:
self.osc_client.send(msg)
except OSCClientError:
Expand Down Expand Up @@ -144,6 +149,7 @@ def query(self, msg, *args, **kwargs):

msg = OSCMessage(msg)
msg.extend(list(args))
self.debug("OSC: %s %s", msg, args)
try:
self.osc_client.send(msg)
except OSCClientError:
Expand All @@ -167,7 +173,7 @@ def query_one(self, msg, *args):
return rv[0]

def handler(self, address, tags, data, source):
# print "handler: %s %s" % (address, data)
self.debug("OSC: %s %s" % (address, data))
#------------------------------------------------------------------------
# Execute any callbacks that have been registered for this message
#------------------------------------------------------------------------
Expand Down
22 changes: 19 additions & 3 deletions live/set.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ class Set (live.LoggingObject):

def __init__(self, address = ("localhost", 9000)):
self.indent = 0
self.groups = []
self.tracks = []
self.scenes = []
self.group_re = re.compile("^(\d+)\. (\S.+)")
self.scanned = False

Expand All @@ -52,6 +49,12 @@ def __init__(self, address = ("localhost", 9000)):

self.beat_event = threading.Event()
self.startup_event = threading.Event()
self.reset()

def reset(self):
self.groups = []
self.tracks = []
self.scenes = []

def open(self, filename, wait = True):
""" Open an Ableton project, either by the path to the Project directory or
Expand Down Expand Up @@ -532,6 +535,7 @@ def scan(self, group_re = None, scan_scenes = False, scan_devices = False, scan_
scan_devices -- queries tracks for devices and their corresponding parameters
scan_clip_names -- queries clips for their human-readable names
"""
print "group_re = %s" % group_re

track_count = self.num_tracks
if not track_count:
Expand Down Expand Up @@ -577,6 +581,12 @@ def scan(self, group_re = None, scan_scenes = False, scan_devices = False, scan_
current_group = group
self.groups.append(group)

#------------------------------------------------------------------------
# we also need to add this group to the tracks list, as live's events
# assume that groups are tracks and address their indices accordingly.
#------------------------------------------------------------------------
self.tracks.append(group)

else:
# TODO: consistence between Group and Track constructors
track_info = self.get_track_info(track_index)
Expand Down Expand Up @@ -674,7 +684,12 @@ def load_or_scan(self, filename = "set", **kwargs):
""" From from file; if file does not exist, scan, then save. """
try:
self.load(filename)
if len(self.tracks) != self.num_tracks:
print "Loaded %d tracks, but found %d - looks like set has changed" % (len(self.tracks), self.num_tracks)
self.reset()
raise Exception
except:

self.scan(**kwargs)
self.save(filename)

Expand Down Expand Up @@ -772,6 +787,7 @@ def _update_tempo(self, tempo):
def _update_clip_state(self, track_index, clip_index, state):
if not self.scanned:
return
print "updating clip state for track %d (count %d)" % (track_index, len(self.tracks))
track = self.tracks[track_index]

# can get a clip_info for clips outside of our clip range
Expand Down

0 comments on commit dfb52b2

Please sign in to comment.