Mercurial > code > home > repos > light9
view blender/time_sync/time_from_graph.py @ 2455:2d454737a916
split blender code to new file
author | drewp@bigasterisk.com |
---|---|
date | Tue, 20 May 2025 09:24:35 -0700 |
parents | 405abed9a45c |
children | d94480bfb179 |
line wrap: on
line source
import asyncio import threading import time from typing import Coroutine from rdfdb.patch import Patch from rdfdb.syncedgraph.syncedgraph import SyncedGraph from rdflib import Literal from light9 import networking, showconfig from light9.ascoltami.graph_context import ascoltamiContext from light9.namespaces import L9 from light9.newtypes import decimalLiteral from light9.run_local import log from light9.typedgraph import typedValue from ..asyncio_thread import startLoopInThread from .blender_time import ( BlenderTime, PausedGotoTime, PlayingGotoTime, SceneLoaded, _TimeEvent, ) class Sync: """asco is the authority on playback status. Sync maintains a copy of the state""" lock = threading.Lock() # these are written ONLY by bg thread duration: float = 1 wallStartTime: float | None = None pausedSongTime: float | None = None latestSongTime: float playing = False def __init__(self): # main thread self.blenderTime = BlenderTime(self.onEvent) self.blenderTime.start() self.ctx = ascoltamiContext(showconfig.showUri()) log.debug('🚋3 startLoopInThread') self._loop = startLoopInThread(self.connectGraph()) log.info('🚋10 Sync initd') def onEvent(self, event: _TimeEvent): # main thread match event: case SceneLoaded(): if hasattr(self, "latestSongTime"): self.blenderTime.setBlenderTime(self.latestSongTime, self.duration) case PausedGotoTime(t): self.runInBackgroundLoop(self.setInGraph(t, False)) case PlayingGotoTime(t): self.runInBackgroundLoop(self.setInGraph(t, True)) def runInBackgroundLoop(self, f: Coroutine): # main thread asyncio.run_coroutine_threadsafe(f, self._loop) async def connectGraph(self): # bg thread log.info('🚋11 start SyncedGraph') self.graph = SyncedGraph(networking.rdfdb.url, "time_sync") self.graph.addHandler(self.syncFromGraph) def syncFromGraph(self): # bg thread with self.lock: asco = L9['ascoltami'] self.wallStartTime = typedValue(float | None, self.graph, asco, L9['wallStartTime']) self.pausedSongTime = typedValue(float | None, self.graph, asco, L9['pausedSongTime']) self.duration = typedValue(float | None, self.graph, asco, L9['duration']) or 1.0 self.playing = typedValue(bool | None, self.graph, asco, L9['playing']) or False def currentTime(self) -> float | None: if self.wallStartTime is not None: return time.time() - self.wallStartTime if self.pausedSongTime is not None: return self.pausedSongTime log.warn('no time data') return None async def setGraphPlaying(self, isBlenderPlaying: bool): # 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=}') p = Patch() if isBlenderPlaying: p = p.update(self.graph.getObjectPatch(self.ctx, L9['ascoltami'], L9['playing'], Literal(True))) p = p.update(self.graph.getObjectPatch(self.ctx, L9['ascoltami'], L9['wallStartTime'], decimalLiteral(round(time.time() - t, 1)))) p = p.update(self.graph.getObjectPatch(self.ctx, L9['ascoltami'], L9['pausedSongTime'], None)) else: p = p.update(self.graph.getObjectPatch(self.ctx, L9['ascoltami'], L9['playing'], Literal(False))) p = p.update(self.graph.getObjectPatch(self.ctx, L9['ascoltami'], L9['wallStartTime'], None)) p = p.update(self.graph.getObjectPatch(self.ctx, L9['ascoltami'], L9['pausedSongTime'], decimalLiteral(round(t, 1)))) if p.isEmpty(): return log.info(f'setInGraph {p.shortSummary()}') await self.graph.patch(p)