Changeset - e993c5e1df1a
[Not reviewed]
default
0 2 0
Drew Perttula - 8 years ago 2017-05-24 08:27:47
drewp@bigasterisk.com
fix effecteval to drop notes into new-style timeline
Ignore-this: 57cae41f60447d55bffc8d59b84bb230
2 files changed with 51 insertions and 4 deletions:
0 comments (0 inline, 0 general)
bin/effecteval
Show inline comments
 
#!bin/python
 
from __future__ import division
 
from run_local import log
 
from twisted.internet import reactor
 
from twisted.internet.defer import inlineCallbacks, returnValue
 
import cyclone.web, cyclone.websocket, cyclone.httpclient
 
import sys, optparse, logging, subprocess, json, itertools
 
from rdflib import URIRef, Literal
 

	
 
sys.path.append('/usr/lib/pymodules/python2.7/') # for numpy, on rpi
 
sys.path.append('/usr/lib/python2.7/dist-packages') # For numpy
 
from light9 import networking, showconfig
 
from light9.effecteval.effect import EffectNode
 
from light9.effect.edit import getMusicStatus, songEffectPatch
 
from light9.effect.edit import getMusicStatus, songNotePatch
 
from light9.effecteval.effectloop import makeEffectLoop
 
from light9.greplin_cyclone import StatsForCyclone
 
from light9.namespaces import L9
 
from light9.rdfdb.patch import Patch
 
from light9.rdfdb.syncedgraph import SyncedGraph
 
from greplin import scales
 

	
 
from lib.cycloneerr import PrettyErrorHandler
 

	
 
class EffectEdit(PrettyErrorHandler, cyclone.web.RequestHandler):
 
    def get(self):
 
        self.set_header('Content-Type', 'text/html')        
 
        self.write(open("light9/effecteval/effect.html").read())
 
    def delete(self):
 
        graph = self.settings.graph
 
        uri = URIRef(self.get_argument('uri'))
 
        with graph.currentState(tripleFilter=(None, L9['effect'], uri)) as g:
 
            song = ctx = list(g.subjects(L9['effect'], uri))[0]
 
        self.settings.graph.patch(Patch(delQuads=[
 
            (song, L9['effect'], uri, ctx),
 
            ]))
 
        
 
@inlineCallbacks
 
def currentSong():
 
@@ -45,49 +45,49 @@ class SongEffects(PrettyErrorHandler, cy
 
    def wideOpenCors(self):
 
        self.set_header('Access-Control-Allow-Origin', '*')
 
        self.set_header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS')
 
        self.set_header('Access-Control-Max-Age', '1000')
 
        self.set_header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With')
 
    
 
    def options(self):
 
        self.wideOpenCors()
 
        self.write('')
 

	
 
    @inlineCallbacks
 
    def post(self):
 
        self.wideOpenCors()
 
        dropped = URIRef(self.get_argument('drop'))
 

	
 
        try:
 
            song = URIRef(self.get_argument('uri'))
 
        except Exception: # which?
 
            song = yield currentSong()
 

	
 
        event = self.get_argument('event', default='default')
 
            
 
        log.info("adding to %s", song)
 

	
 
        p = yield songEffectPatch(self.settings.graph, dropped, song, event, ctx=song)
 
        p = yield songNotePatch(self.settings.graph, dropped, song, event, ctx=song)
 
        self.settings.graph.patch(p)
 
        self.settings.graph.suggestPrefixes({'song': URIRef(song + '/')})
 
        
 
class SongEffectsUpdates(cyclone.websocket.WebSocketHandler):
 
    def connectionMade(self, *args, **kwargs):
 
        self.graph = self.settings.graph
 
        self.graph.addHandler(self.updateClient)
 
        
 
    def updateClient(self):
 
        # todo: abort if client is gone
 
        playlist = self.graph.value(showconfig.showUri(), L9['playList'])
 
        songs = list(self.graph.items(playlist))
 
        out = []
 
        for s in songs:
 
            out.append({'uri': s, 'label': self.graph.label(s)})
 
            out[-1]['effects'] = [{'uri': uri, 'label': self.graph.label(uri)} for uri in sorted(self.graph.objects(s, L9['effect']))]
 
        self.sendMessage({'songs': out})
 
        
 
        
 
class EffectUpdates(cyclone.websocket.WebSocketHandler):
 
    """
 
    stays alive for the life of the effect page
 
    """
 
    def connectionMade(self, *args, **kwargs):
light9/effect/edit.py
Show inline comments
 
import json
 
import cyclone.httpclient
 
from twisted.internet.defer import inlineCallbacks, returnValue
 
from rdflib import URIRef, Literal
 

	
 
from light9 import networking
 
from light9.namespaces import L9, RDF, RDFS
 
from light9.rdfdb.patch import Patch
 
from light9.curvecalc.curve import CurveResource
 

	
 
def clamp(x, lo, hi):
 
    return max(lo, min(hi, x))
 

	
 

	
 
@inlineCallbacks
 
def getMusicStatus():
 
    returnValue(json.loads((yield cyclone.httpclient.fetch(
 
        networking.musicPlayer.path('time'), timeout=.5)).body))
 

	
 
@inlineCallbacks
 
def songEffectPatch(graph, dropped, song, event, ctx):
 
    """
 
    some uri was 'dropped' in the timeline. event is 'default' or 'start' or 'end'.
 
    some uri was 'dropped' in the curvecalc timeline. event is 'default' or 'start' or 'end'.
 
    """
 
    with graph.currentState(
 
            tripleFilter=(dropped, None, None)) as g:
 
        droppedTypes = list(g.objects(dropped, RDF.type))
 
        droppedLabel = g.label(dropped)
 
        droppedCodes = list(g.objects(dropped, L9['code']))
 

	
 
    quads = []
 
    fade = 2 if event == 'default' else 0
 

	
 
    if _songHasEffect(graph, song, dropped):
 
        # bump the existing curve
 
        pass
 
    else:
 
        effect, q = _newEffect(graph, song, ctx)
 
        quads.extend(q)
 

	
 
        curve = graph.sequentialUri(song + "/curve-")
 
        yield _newEnvelopeCurve(graph, ctx, curve, droppedLabel, fade)
 
        quads.extend([
 
            (song, L9['curve'], curve, ctx),
 
            (effect, RDFS.label, droppedLabel, ctx),
 
            (effect, L9['code'], Literal('env = %s' % curve.n3()), ctx),
 
            ])
 

	
 
        if L9['EffectClass'] in droppedTypes:
 
            quads.extend([
 
                (effect, RDF.type, dropped, ctx),
 
                ] + [(effect, L9['code'], c, ctx) for c in droppedCodes])
 
        elif L9['Submaster'] in droppedTypes:
 
            quads.extend([
 
                (effect, L9['code'], Literal('out = %s * env' % dropped.n3()),
 
                 ctx),
 
                ])
 
        else:
 
            raise NotImplementedError(
 
                "don't know how to add an effect from %r (types=%r)" %
 
                (dropped, droppedTypes))
 

	
 
        _maybeAddMusicLine(quads, effect, song, ctx)
 

	
 
    print "adding"
 
    for qq in quads:
 
        print qq
 
    returnValue(Patch(addQuads=quads))
 

	
 
@inlineCallbacks
 
def songNotePatch(graph, dropped, song, event, ctx):
 
    """
 
    drop into effectsequencer timeline
 

	
 
    ported from timeline.coffee makeNewNote
 
    """
 
    with graph.currentState(
 
            tripleFilter=(dropped, None, None)) as g:
 
        droppedTypes = list(g.objects(dropped, RDF.type))
 
        droppedLabel = g.label(dropped)
 

	
 
    quads = []
 
    fade = 2 if event == 'default' else 0
 

	
 
    print 'droppedTypes', droppedTypes
 
    if L9['Effect'] in droppedTypes:
 
        musicStatus = yield getMusicStatus()
 
        songTime = musicStatus['t']
 
        note = graph.sequentialUri(song + '/n')
 
        curve = graph.sequentialUri(note + 'c')
 
        quads.extend([
 
            (song, L9['note'], note, ctx),
 
            (note, RDF.type, L9['Note'], ctx),
 
            (note, L9['curve'], curve, ctx),
 
            (note, L9['effectClass'], dropped, ctx),
 
            (note, L9['originTime'], Literal(songTime), ctx),
 
            (curve, RDF.type, L9['Curve'], ctx),
 
            (curve, L9['attr'], L9['strength'], ctx),
 
            ])
 
        if event == 'default':
 
            coords = [(0 - fade, 0), (0, 1), (20, 1), (20 + fade, 0)]
 
        elif event == 'start':
 
            coords = [(0 - fade, 0), (0, 1), (20, 1), (20 + fade, 0)]
 
        elif event == 'end':
 
            raise
 
        else:
 
            raise NotImplementedError(event)
 
        for t,v in coords:
 
            pt = graph.sequentialUri(curve + 'p')
 
            quads.extend([
 
                (curve, L9['point'], pt, ctx),
 
                (pt, L9['time'], Literal(t), ctx),
 
                (pt, L9['value'], Literal(v), ctx),
 
                ])
 
    
 

	
 
    returnValue(Patch(addQuads=quads))
 
    
 
    
 
def _songHasEffect(graph, song, uri):
 
    """does this song have an effect of class uri or a sub curve for sub
 
    uri? this should be simpler to look up."""
 
    return False # todo
 

	
 
def musicCurveForSong(uri):
 
    return URIRef(uri + 'music')
 
    
 
def _newEffect(graph, song, ctx):
 
    effect = graph.sequentialUri(song + "/effect-")
 
    quads = [
 
        (song, L9['effect'], effect, ctx),
 
        (effect, RDF.type, L9['Effect'], ctx),
 
    ]
 
    print "_newEffect", effect, quads
 
    return effect, quads
 
    
 
@inlineCallbacks
 
def _newEnvelopeCurve(graph, ctx, uri, label, fade=2):
 
    """this does its own patch to the graph"""
 
    
 
    cr = CurveResource(graph, uri)
 
    cr.newCurve(ctx, label=Literal(label))
0 comments (0 inline, 0 general)