Changeset - 86732ba7d9ae
[Not reviewed]
default
0 2 0
Drew Perttula - 11 years ago 2014-05-29 06:48:21
drewp@bigasterisk.com
curvecalc now gets its curves from the rdf graph, and can persist their points there too (save is still an explicit command)
Ignore-this: 541488a3f299d2ca77a993118e1b974
2 files changed with 75 insertions and 45 deletions:
0 comments (0 inline, 0 general)
bin/curvecalc
Show inline comments
 
@@ -335,32 +335,27 @@ class Main(object):
 
    def onZoomAll(self, item):
 
        dispatcher.send("show all")
 

	
 
    def onPlayPause(self, item):
 
        # since the X coord in a curveview affects the handling, one
 
        # of them may be able to pick this up
 
        results = dispatcher.send("onPlayPause")
 
        times = [t for listener, t in results if t is not None]
 
        self.music.playOrPause(t=times[0] if times else None)
 

	
 
    def onSave(self, *args):
 
        # only doing curves still. I hope to eliminate all this.
 
        with self.graph.currentState() as g:
 
            song = g.value(self.session, L9['currentSong'])
 

	
 
            log.info("saving curves for %r", song)
 
            self.curveset.save(basename=os.path.join(
 
                showconfig.curvesDir(),
 
                showconfig.songFilenameFromURI(song)))
 
            log.info("saved")
 
        log.info("saving curves")
 
        self.curveset.save()
 
        log.info("saved")
 

	
 
    def makeStatusLines(self, master):
 
        """various labels that listen for dispatcher signals"""
 
        for row, (signame, textfilter) in enumerate([
 
            ('input time', lambda t: "%.2fs"%t),
 
            ('output levels',
 
             lambda levels: textwrap.fill("; ".join(["%s:%.2f"%(n,v)
 
                                                     for n,v in
 
                                                     levels.items()[:2]
 
                                                     if v>0]),70)),
 
            ('update period', lambda t: "%.1fms"%(t*1000)),
 
            ('update status', lambda x: str(x)),
 
@@ -443,36 +438,25 @@ class MaxTime(object):
 

	
 
def launch(args, graph, session, opts, startTime, music):
 

	
 
    try:
 
        song = URIRef(args[0])
 
        graph.patchObject(context=session,
 
                          subject=session,
 
                          predicate=L9['currentSong'],
 
                          newObject=song)
 
    except IndexError:
 
        pass
 

	
 
    curveset = Curveset(sliders=opts.sliders)
 

	
 
    def curvesetReload():
 
        # not sure if this clears right or not yet
 
        song = graph.value(session, L9['currentSong'])
 
        if song is None:
 
            return
 
        curveset.load(basename=os.path.join(
 
            showconfig.curvesDir(),
 
            showconfig.songFilenameFromURI(song)),
 
                      skipMusic=opts.skip_music)
 
    graph.addHandler(curvesetReload)
 
    curveset = Curveset(graph=graph, session=session, sliders=opts.sliders)
 
        
 
    log.debug("startup: output %s", time.time() - startTime)
 

	
 
    mt = MaxTime(graph, session)
 
    dispatcher.connect(lambda: mt.get(), "get max time", weak=False)
 

	
 
    start = Main(graph, opts, session, curveset, music)
 
    out = Output(graph, session, music, curveset, start.currentSubterms)
 

	
 
    dispatcher.send("show all")
 
        
 
    if opts.startup_only:
 
@@ -495,26 +479,24 @@ def launch(args, graph, session, opts, s
 
                    return json.dumps({"song": song, "hoverTime" : times[0]})
 
            raise NotImplementedError()
 

	
 
    reactor.listenTCP(networking.curveCalc.port,
 
                      server.Site(Hover()))
 

	
 
def main():
 
    startTime = time.time()
 
    parser = optparse.OptionParser()
 
    parser.set_usage("%prog [opts] [songURI]")
 
    parser.add_option("--sliders", action='store_true',
 
                      help='use hardware sliders')
 
    parser.add_option("--skip-music", action='store_true',
 
                      help="ignore music and smooth_music curve files")
 
    parser.add_option("--debug", action="store_true",
 
                      help="log at DEBUG")
 
    parser.add_option("--reload", action="store_true",
 
                      help="live reload of themes and code")
 
    parser.add_option("--startup-only", action='store_true',
 
                      help="quit after loading everything (for timing tests)")
 
    clientsession.add_option(parser)
 
    opts, args = parser.parse_args()
 

	
 
    log.setLevel(logging.DEBUG if opts.debug else logging.INFO)
 

	
 
    log.debug("startup: music %s", time.time() - startTime)
light9/curvecalc/curve.py
Show inline comments
 
from __future__ import division
 
import glob, time, logging, ast
 
import glob, time, logging, ast, os
 
from bisect import bisect_left,bisect
 
import louie as dispatcher
 
from rdflib import Literal
 
from light9 import showconfig
 
from light9.namespaces import L9
 

	
 
from bcf2000 import BCF2000
 

	
 
log = logging.getLogger()
 
# todo: move to config, consolidate with ascoltami, musicPad, etc
 
introPad = 4
 
postPad = 4
 

	
 
class Curve(object):
 
    """curve does not know its name. see Curveset"""
 
    def __init__(self):
 
        self.points = [] # x-sorted list of (x,y)
 
@@ -40,26 +42,30 @@ class Curve(object):
 
            self.points.append((float(x), ast.literal_eval(y)))
 
        self.points.sort()
 
        dispatcher.send("points changed",sender=self)
 

	
 
    def set_from_string(self, pts):
 
        self.points[:] = []
 
        vals = pts.split()
 
        pairs = zip(vals[0::2], vals[1::2])
 
        for x, y in pairs:
 
            self.points.append((float(x), ast.literal_eval(y)))
 
        self.points.sort()
 
        dispatcher.send("points changed",sender=self)
 

	
 
    def points_as_string(self):
 
        return ' '.join("%s %r" % p for p in self.points)
 
        
 
    def save(self,filename):
 
        # this is just around for markers, now
 
        if filename.endswith('-music') or filename.endswith('_music'):
 
            print "not saving music track"
 
            return
 
        f = file(filename,'w')
 
        for p in self.points:
 
            f.write("%s %r\n" % p)
 
        f.close()
 

	
 
    def eval(self, t, allow_muting=True):
 
        if self.muted and allow_muting:
 
            return 0
 
        if not self.points:
 
@@ -143,86 +149,127 @@ class Sliders(BCF2000):
 
        self.knobCallback = knobCallback
 
        self.knobButtonCallback = knobButtonCallback
 
    def valueIn(self, name, value):
 
        if name.startswith("slider"):
 
            self.cb(int(name[6:]), value / 127)
 
        if name.startswith("knob"):
 
            self.knobCallback(int(name[4:]), value / 127)
 
        if name.startswith("button-knob"):
 
            self.knobButtonCallback(int(name[11:]))
 

	
 
        
 
class Curveset(object):
 
    
 
    curves = None # curvename : curve
 
    def __init__(self, sliders=False):
 
    def __init__(self, graph, session, sliders=False):
 
        """sliders=True means support the hardware sliders"""
 
        self.graph, self.session = graph, session
 

	
 
        self.currentSong = None
 
        self.curves = {} # name (str) : Curve
 
        self.curveName = {} # reverse
 
        
 
        self.sliderCurve = {} # slider number (1 based) : curve name
 
        self.sliderNum = {} # reverse
 
        if sliders:
 
            self.sliders = Sliders(self.hw_slider_in, self.hw_knob_in, 
 
                                   self.hw_knob_button)
 
            dispatcher.connect(self.curvesToSliders, "curves to sliders")
 
            dispatcher.connect(self.knobOut, "knob out")
 
            self.lastSliderTime = {} # num : time
 
            self.sliderSuppressOutputUntil = {} # num : time
 
            self.sliderIgnoreInputUntil = {}
 
        else:
 
            self.sliders = None
 
        self.markers = Markers()
 

	
 
    def sorter(self, name):
 
        return (not name in ['music', 'smooth_music'], name)
 
        graph.addHandler(self.loadCurvesForSong)
 

	
 
    def load(self,basename, skipMusic=False):
 
        """find all files that look like basename-curvename and add
 
        curves with their contents
 

	
 
    def loadCurvesForSong(self):
 
        """
 
        current curves will track song's curves.
 
        
 
        This fires 'add_curve' dispatcher events to announce the new curves.
 
        """
 
        log.info("Curveset.load %s", basename)
 
        log.info('loadCurvesForSong')
 
        dispatcher.send("clear_curves")
 
        self.curves.clear()
 
        self.curveName.clear()
 
        self.sliderCurve.clear()
 
        self.sliderNum.clear()
 
        self.markers = Markers()
 
        
 
        for filename in sorted(glob.glob("%s-*"%basename), key=self.sorter):
 
            curvename = filename[filename.rfind('-')+1:]
 
            if skipMusic and curvename in ['music', 'smooth_music']:
 
                continue
 
            c=Curve()
 
            c.load(filename)
 
            curvename = curvename.replace('-','_')
 
            self.add_curve(curvename,c)
 
        self.currentSong = self.graph.value(self.session, L9['currentSong'])
 
        if self.currentSong is None:
 
            return
 

	
 
        for uri in self.graph.objects(self.currentSong, L9['curve']):
 
            c = Curve()
 
            c.uri = uri
 
            pts = self.graph.value(uri, L9['points'])
 
            if pts is not None:
 
                c.set_from_string(pts)
 
                c.pointsStorage = 'graph'
 
            else:
 
                diskPts = self.graph.value(uri, L9['pointsFile'])
 
                c.load(os.path.join(showconfig.curvesDir(), diskPts))
 
                c.pointsStorage = 'file'
 

	
 
            curvename = self.graph.label(uri)
 
            if not curvename:
 
                raise ValueError("curve %r has no label" % uri)
 
            self.add_curve(curvename, c)
 

	
 
        basename = os.path.join(
 
            showconfig.curvesDir(),
 
            showconfig.songFilenameFromURI(self.currentSong))
 
        try:
 
            self.markers.load("%s.markers" % basename)
 
        except IOError:
 
            print "no marker file found"
 
            
 
    def save(self,basename):
 
    def save(self):
 
        """writes a file for each curve with a name
 
        like basename-curvename"""
 
        for name,cur in self.curves.items():
 
            cur.save("%s-%s" % (basename,name))
 
        like basename-curvename, or saves them to the rdf graph"""
 
        basename=os.path.join(
 
            showconfig.curvesDir(),
 
            showconfig.songFilenameFromURI(self.currentSong))
 

	
 
        patches = []
 
        for label, curve in self.curves.items():
 
            if curve.pointsStorage == 'file':
 
                log.warn("not saving file curves anymore- skipping %s" % label)
 
                #cur.save("%s-%s" % (basename,name))
 
            elif curve.pointsStorage == 'graph':
 
                ctx = self.currentSong
 
                patches.append(self.graph.getObjectPatch(
 
                    ctx,
 
                    subject=curve.uri,
 
                    predicate=L9['points'],
 
                    newObject=Literal(curve.points_as_string())))
 
            else:
 
                raise NotImplementedError(curve.pointsStorage)
 

	
 
        self.markers.save("%s.markers" % basename)
 
        # this will cause reloads that will clear our curve list
 
        for p in patches:
 
            self.graph.patch(p)
 

	
 
    def sorter(self, name):
 
        return (not name in ['music', 'smooth_music'], name)
 
        
 
    def curveNamesInOrder(self):
 
        return sorted(self.curves.keys(), key=self.sorter)
 
            
 
    def add_curve(self,name,curve):
 
    def add_curve(self, name, curve):
 
        # should be indexing by uri
 
        if isinstance(name, Literal):
 
            name = str(name) 
 
        if name in self.curves:
 
            raise ValueError("can't add a second curve named %r" % name)
 
        self.curves[name] = curve
 
        self.curveName[curve] = name
 

	
 
        if self.sliders and name not in ['smooth_music', 'music']:
 
            num = len(self.sliderCurve) + 1
 
            if num <= 8:
 
                self.sliderCurve[num] = name
 
                self.sliderNum[name] = num
 
@@ -243,24 +290,25 @@ class Curveset(object):
 
    def new_curve(self, name, renameIfExisting=True):
 
        if isinstance(name, Literal):
 
            name = str(name)
 
        if name=="":
 
            print "no name given"
 
            return
 
        if not renameIfExisting and name in self.curves:
 
            return
 
        while name in self.curves:
 
           name=name+"-1"
 

	
 
        c = Curve()
 
        # missing some new attrs here, uri pointsStorage
 
        s,e = self.get_time_range()
 
        c.points.extend([(s,0), (e,0)])
 
        self.add_curve(name,c)
 

	
 
    def hw_slider_in(self, num, value):
 
        try:
 
            curve = self.curves[self.sliderCurve[num]]
 
        except KeyError:
 
            return
 

	
 
        now = time.time()
 
        if now < self.sliderIgnoreInputUntil.get(num):
0 comments (0 inline, 0 general)