diff --git a/bin/effecteval b/bin/effecteval --- a/bin/effecteval +++ b/bin/effecteval @@ -63,12 +63,18 @@ class SongEffects(PrettyErrorHandler, cy song = yield currentSong() event = self.get_argument('event', default='default') - + + note = self.get_argument('note', default=None) + if note is not None: + note = URIRef(note) + log.info("adding to %s", song) - p = yield songNotePatch(self.settings.graph, dropped, song, event, ctx=song) + note, p = yield songNotePatch(self.settings.graph, dropped, song, event, ctx=song, note=note) + self.settings.graph.patch(p) self.settings.graph.suggestPrefixes({'song': URIRef(song + '/')}) + self.write(json.dumps({'note': note})) class SongEffectsUpdates(cyclone.websocket.WebSocketHandler): def connectionMade(self, *args, **kwargs): diff --git a/light9/effect/edit.py b/light9/effect/edit.py --- a/light9/effect/edit.py +++ b/light9/effect/edit.py @@ -68,7 +68,7 @@ def songEffectPatch(graph, dropped, song returnValue(Patch(addQuads=quads)) @inlineCallbacks -def songNotePatch(graph, dropped, song, event, ctx): +def songNotePatch(graph, dropped, song, event, ctx, note=None): """ drop into effectsequencer timeline @@ -79,40 +79,66 @@ def songNotePatch(graph, dropped, song, droppedTypes = list(g.objects(dropped, RDF.type)) quads = [] - fade = 2 if event == 'default' else 0 + fade = 2 if event == 'default' else 0.1 - if L9['Effect'] in droppedTypes: + if note: 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 + _finishCurve(graph, note, quads, ctx, songTime) + else: + if L9['Effect'] in droppedTypes: + musicStatus = yield getMusicStatus() + songTime = musicStatus['t'] + note = _makeNote(graph, song, note, quads, ctx, dropped, songTime, event, fade) 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), - ]) + raise NotImplementedError + + returnValue((note, Patch(addQuads=quads))) + + +def _point(ctx, uri, t, v): + return [ + (uri, L9['time'], Literal(round(t, 3)), ctx), + (uri, L9['value'], Literal(round(v, 3)), ctx) + ] + +def _finishCurve(graph, note, quads, ctx, songTime): + with graph.currentState() as g: + origin = g.value(note, L9['originTime']).toPython() + curve = g.value(note, L9['curve']) + + pt2 = graph.sequentialUri(curve + 'p') + pt3 = graph.sequentialUri(curve + 'p') + quads.extend( + [(curve, L9['point'], pt2, ctx)] + _point(ctx, pt2, songTime - origin, 1) + + [(curve, L9['point'], pt3, ctx)] + _point(ctx, pt3, songTime - origin + .5, 0) + ) - returnValue(Patch(addQuads=quads)) - + +def _makeNote(graph, song, note, quads, ctx, dropped, songTime, event, fade): + 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), ] + elif event == 'end': # probably unused- goes to _finishCurve instead + coords = [(20, 1), (20 + fade, 0)] + else: + raise NotImplementedError(event) + for t,v in coords: + pt = graph.sequentialUri(curve + 'p') + quads.extend([(curve, L9['point'], pt, ctx)] + _point(ctx, pt, t, v)) + return note def _songHasEffect(graph, song, uri): """does this song have an effect of class uri or a sub curve for sub diff --git a/light9/subserver/effects.coffee b/light9/subserver/effects.coffee --- a/light9/subserver/effects.coffee +++ b/light9/subserver/effects.coffee @@ -33,18 +33,23 @@ model.addToCurrentSong = (e) -> data: {drop: e.uri} }) +lastMomentaryNote = null + model.addMomentary = (e) -> $.ajax({ type: 'POST' url: '/effectEval/songEffects' data: {drop: e.uri, event: 'start'} + success: (data) -> + lastMomentaryNote = JSON.parse(data)['note'] + }) model.addMomentaryUp = (e) -> $.ajax({ type: 'POST' url: '/effectEval/songEffects' - data: {drop: e.uri, event: 'end'} + data: {drop: e.uri, event: 'end', note: lastMomentaryNote} }) diff --git a/light9/web/timeline/timeline.coffee b/light9/web/timeline/timeline.coffee --- a/light9/web/timeline/timeline.coffee +++ b/light9/web/timeline/timeline.coffee @@ -463,8 +463,10 @@ Polymer screenPts = ($V([@zoomInX(pt.e(1)), @offsetTop + (1 - pt.e(2)) * @offsetHeight]) for pt in @worldPts) @dia.setNote(@uri, screenPts, effect) - leftX = Math.max(2, screenPts[1].e(1) + 5) - rightX = screenPts[2].e(1) - 5 + leftX = Math.max(2, screenPts[Math.min(1, screenPts.length - 1)].e(1) + 5) + rightX = screenPts[Math.min(2, screenPts.length - 1)].e(1) - 5 + if screenPts.length < 3 + rightX = leftX + 120 w = 114 h = 80 @inlineRect = { @@ -475,7 +477,7 @@ Polymer display: if rightX - leftX > w then 'block' else 'none' } - if screenPts[3].e(1) - screenPts[0].e(1) < 100 + if screenPts[screenPts.length - 1].e(1) - screenPts[0].e(1) < 100 @clearAdjusters() # also kill their connectors return