Changeset - 74ec008aee56
[Not reviewed]
default
0 1 0
Drew Perttula - 7 years ago 2018-06-03 11:35:06
drewp@bigasterisk.com
big sequencer speedup: only rebuild notes in the changed song
Ignore-this: 7d4f16423727daa90eb61518a41f57d3
1 file changed with 17 insertions and 10 deletions:
0 comments (0 inline, 0 general)
light9/effect/sequencer.py
Show inline comments
 
@@ -17,25 +17,26 @@ from light9 import networking
 
from light9.namespaces import L9, RDF
 
from light9.vidref.musictime import MusicTime
 
from light9.effect import effecteval
 
from light9.effect.settings import DeviceSettings
 
from light9.effect.simple_outputs import SimpleOutputs
 

	
 
from greplin import scales
 
from txzmq import ZmqEndpoint, ZmqFactory, ZmqPushConnection
 

	
 
log = logging.getLogger('sequencer')
 
stats = scales.collection('/sequencer/',
 
                          scales.PmfStat('update'),
 
                          scales.PmfStat('compile'),
 
                          scales.PmfStat('compileGraph'),
 
                          scales.PmfStat('compileSong'),
 
                          scales.DoubleStat('recentFps'),
 
)
 

	
 
_zmqClient=None
 
class TwistedZmqClient(object):
 
    def __init__(self, service):
 
        zf = ZmqFactory()
 
        e = ZmqEndpoint('connect', 'tcp://%s:%s' % (service.host, service.port))
 
        self.conn = ZmqPushConnection(zf, e)
 
        
 
    def send(self, msg):
 
        self.conn.push(msg)
 
@@ -155,54 +156,60 @@ class CodeWatcher(object):
 
        def go():
 
            log.info("reload effecteval")
 
            reload(effecteval)
 
            self.onChange()
 
        # in case we got an event at the start of the write
 
        reactor.callLater(.1, go) 
 
    
 
        
 

	
 
class Sequencer(object):
 
    def __init__(self, graph, sendToCollector, fps=30):
 
        self.graph = graph
 
        self.fps = 30
 
        self.fps = 60
 
        self.sendToCollector = sendToCollector
 
        self.music = MusicTime(period=.2, pollCurvecalc=False)
 

	
 
        self.recentUpdateTimes = []
 
        self.lastStatLog = 0
 
        self._compileGraphCall = None
 
        self.notes = {} # song: [notes]
 
        self.simpleOutputs = SimpleOutputs(self.graph)
 
        self.graph.addHandler(self.compileGraph)
 
        self.update()
 

	
 
        self.codeWatcher = CodeWatcher(
 
            onChange=lambda: self.graph.addHandler(self.compileGraph))
 

	
 
    @stats.compile.time()
 
    @stats.compileGraph.time()
 
    def compileGraph(self):
 
        """rebuild our data from the graph"""
 
        log.info('compileGraph start')
 
        t1 = time.time()
 
        g = self.graph
 

	
 
        for song in g.subjects(RDF.type, L9['Song']):
 
            # ideally, wrap this (or smaller) in a sub-handler to run less on each patch
 
            self.notes[song] = []
 
            for note in g.objects(song, L9['note']):
 
                self.notes[song].append(Note(g, note, effecteval,
 
                                             self.simpleOutputs))
 
        log.info('compileGraph done %.2f ms', 1000 * (time.time() - t1))
 
            self.graph.addHandler(lambda song=song: self.compileSong(song))
 
        log.info('compileGraph took %.2f ms', 1000 * (time.time() - t1))
 
        
 
    @stats.compileSong.time()
 
    def compileSong(self, song):
 
        t1 = time.time()
 

	
 
        self.notes[song] = []
 
        for note in self.graph.objects(song, L9['note']):
 
            self.notes[song].append(Note(self.graph, note, effecteval,
 
                                         self.simpleOutputs))
 
        log.info('  compile %s took %.2f ms', song, 1000 * (time.time() - t1))
 

	
 
        
 
    @stats.update.time()
 
    def update(self):
 
        now = time.time()
 
        self.recentUpdateTimes = self.recentUpdateTimes[-20:] + [now]
 
        stats.recentFps = len(self.recentUpdateTimes) / (self.recentUpdateTimes[-1] - self.recentUpdateTimes[0] + .0001)
 
        if now > self.lastStatLog + 10:
 
            log.info("%.2f fps", stats.recentFps)
 
            self.lastStatLog = now
 
        
 
        reactor.callLater(1 / self.fps, self.update)
 

	
 
        musicState = self.music.getLatest()
0 comments (0 inline, 0 general)