Mercurial > code > home > repos > light9
changeset 2458:0e27ba33118c default tip
better blender<->asco playback cooperation. still no play support in blender; only seek
author | drewp@bigasterisk.com |
---|---|
date | Tue, 20 May 2025 16:25:06 -0700 |
parents | d94480bfb179 |
children | |
files | blender/time_sync/time_from_graph.py src/light9/ascoltami/main.py src/light9/ascoltami/play_state.py |
diffstat | 3 files changed, 28 insertions(+), 18 deletions(-) [+] |
line wrap: on
line diff
--- a/blender/time_sync/time_from_graph.py Tue May 20 13:48:07 2025 -0700 +++ b/blender/time_sync/time_from_graph.py Tue May 20 16:25:06 2025 -0700 @@ -3,7 +3,6 @@ import time from typing import Coroutine -from attr import dataclass from rdfdb.patch import Patch from rdfdb.syncedgraph.syncedgraph import SyncedGraph from rdflib import Literal @@ -35,6 +34,8 @@ def __init__(self): # main thread + + # one mutable instance; modified by bg thread self.ascoPlayState = AscoPlayState(None, None, False, False, 1.0) self.blenderTime = BlenderTime(self.onBlenderEvent, self.ascoPlayState) self.blenderTime.start() @@ -69,25 +70,19 @@ # bg thread with self.lock: asco = L9['ascoltami'] - + self.ascoPlayState.wallStartTime = typedValue(float | None, self.graph, asco, L9['wallStartTime']) self.ascoPlayState.pausedSongTime = typedValue(float | None, self.graph, asco, L9['pausedSongTime']) self.ascoPlayState.duration = typedValue(float | None, self.graph, asco, L9['duration']) or 1.0 - self.blenderTime.durationDirty = True # todo: called too often + self.blenderTime.durationDirty = True # todo: called too often self.ascoPlayState.playing = typedValue(bool | None, self.graph, asco, L9['playing']) or False self.ascoPlayState.endOfSong = typedValue(bool | None, self.graph, asco, L9['endOfSong']) or False log.info(f'🍇 syncFromGraph {self.ascoPlayState=}') self.blenderTime.curFrameDirty = True - async def setGraphPlaying(self, isBlenderPlaying: bool): - return - # bg thread - log.info(f'set graph playing to {isBlenderPlaying}') - self.graph.patchObject(self.ctx, L9['ascoltami'], L9['playing'], Literal(isBlenderPlaying)) - async def setInGraph(self, t: float, isBlenderPlaying: bool): # bg thread - log.info(f'set graph time to {t:.2f} {isBlenderPlaying=}') + log.debug(f'set graph time to {t:.2f} {isBlenderPlaying=}') p = Patch() if isBlenderPlaying: p = p.update(self.graph.getObjectPatch(self.ctx, L9['ascoltami'], L9['playing'], Literal(True))) @@ -100,5 +95,4 @@ if p.isEmpty(): return - log.info(f'setInGraph {p.shortSummary()}') await self.graph.patch(p)
--- a/src/light9/ascoltami/main.py Tue May 20 13:48:07 2025 -0700 +++ b/src/light9/ascoltami/main.py Tue May 20 16:25:06 2025 -0700 @@ -1,22 +1,21 @@ import logging -from typing import cast from rdfdb.syncedgraph.syncedgraph import SyncedGraph from rdflib import ConjunctiveGraph, Literal, URIRef - from starlette.applications import Starlette from starlette.routing import Route from starlette_exporter import PrometheusMiddleware, handle_metrics from light9 import networking, showconfig from light9.ascoltami import webapp +from light9.ascoltami.graph_context import ascoltamiContext from light9.ascoltami.import_gst import Gst from light9.ascoltami.player import Player, PlayerState from light9.ascoltami.playlist import NoSuchSong, Playlist from light9.namespaces import L9 from light9.newtypes import decimalLiteral from light9.run_local import log -from light9.ascoltami.graph_context import ascoltamiContext +from light9.typedgraph import typedValue class Ascoltami: @@ -30,12 +29,14 @@ self.playerState = PlayerState() self.playlist = Playlist(graph, show) + self.graph.addHandler(self.updateStateFromGraph) + def onStateChange(self, s: PlayerState): g = self.stateAsGraph(s) self.graph.patchSubgraph(newGraph=g, context=self.ctx) self.playerState = s - def stateAsGraph(self, s): + def stateAsGraph(self, s: PlayerState): g = ConjunctiveGraph() asc = L9['ascoltami'] if s.song: @@ -53,6 +54,23 @@ g.add((asc, L9['endOfSong'], Literal(s.endOfSong), self.ctx)) return g + def updateStateFromGraph(self): + """react to graph changes, probably from blender. Not all predicates will correctly adjust the player""" + log.info('outside graph change') + asco = L9['ascoltami'] + pausedSongTime = typedValue(float | None, self.graph, asco, L9['pausedSongTime']) + if pausedSongTime is not None and pausedSongTime != self.playerState.pausedSongTime and self.player.getSong() is not None: + log.info(f'graph says {pausedSongTime=} , playerState has {self.playerState.pausedSongTime}. seeking to {pausedSongTime}') + self.player.seek(pausedSongTime) + # self.playerState.wallStartTime = typedValue(float | None, self.graph, asco, L9['wallStartTime']) or 0.0 + # self.playerState.duration = typedValue(float | None, self.graph, asco, L9['duration']) or 1.0 # song & duration are not editable from outside asco + # self.playerState.playing = typedValue(bool | None, self.graph, asco, L9['playing']) or False + # self.playerState.endOfSong = typedValue(bool | None, self.graph, asco, L9['endOfSong']) or False + log.info(f'🍇 syncFromGraph {self.playerState=}') + + # s = self.playerState + # s.song = self.playlist.songFromUri(g.value(L9['ascoltami'], L9['song'])) + def getPlayerState(self) -> PlayerState: return self.playerState
--- a/src/light9/ascoltami/play_state.py Tue May 20 13:48:07 2025 -0700 +++ b/src/light9/ascoltami/play_state.py Tue May 20 16:25:06 2025 -0700 @@ -1,4 +1,3 @@ - from dataclasses import dataclass import time from light9.run_local import log @@ -6,7 +5,6 @@ @dataclass class AscoPlayState: - # one mutable instance; modified by bg thread wallStartTime: float | None pausedSongTime: float | None playing: bool @@ -19,5 +17,5 @@ return time.time() - self.wallStartTime if self.pausedSongTime is not None: return self.pausedSongTime - log.warn('no time data') + log.warning('no time data') return None