Mercurial > code > home > repos > light9
diff src/light9/blender/time_sync/time_from_graph.py @ 2432:b8a408caf115
start blender sync
author | drewp@bigasterisk.com |
---|---|
date | Tue, 28 May 2024 15:35:12 -0700 |
parents | |
children | ffa69645e9dc |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/light9/blender/time_sync/time_from_graph.py Tue May 28 15:35:12 2024 -0700 @@ -0,0 +1,100 @@ +import threading +import time + +import bpy # type: ignore +from bpy.app.handlers import persistent # type: ignore +from light9.typedgraph import typedValue +from rdfdb.syncedgraph.syncedgraph import SyncedGraph +from rdflib import URIRef + +from light9 import networking +from light9.blender.asyncio_thread import startLoopInThread +from light9.namespaces import L9 +from light9.run_local import log + + +def clamp(lo, hi, x): + return max(lo, min(hi, x)) + + +def floatValue(graph: SyncedGraph, s: URIRef, p: URIRef) -> float | None: + return typedValue(float | None, graph, s, p) + + +UPDATE_PERIOD = 1 / 20 + + +class Sync: + lock = threading.Lock() + duration: float = 1 + wallStartTime: float | None = None + pausedSongTime: float | None = None + playing=False + latestTime: float + + def __init__(self): + # main thread + self.lastSetFrame = -1 + self.lastGraphFrame = -1 + self.frameSetBy = 'init' + startLoopInThread(self.task()) + bpy.app.timers.register(self.update) + bpy.app.handlers.frame_change_post.append(self.on_frame_change_post) + + ## read from graph + + async def task(self): + # bg thread with asyncio loop + 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 = floatValue(self.graph, asco, L9['wallStartTime']) + self.pausedSongTime = floatValue(self.graph, asco, L9['pausedSongTime']) + self.duration = floatValue(self.graph, asco, L9['duration']) or 1.0 + self.playing = typedValue(bool, self.graph, asco, L9['playing']) + + 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 + + ## graph time -> blender time + + @persistent + def update(self): + # main thread? wherever blender runs timers + if self.playing: + with self.lock: + t = self.currentTime() + if t is not None: + self.setBlenderTime(t, self.duration) + return UPDATE_PERIOD + + def setBlenderTime(self, t: float, duration: float): + scene = bpy.context.scene + fps = scene.render.fps + scene.frame_start = 0 + scene.frame_end = int(duration * fps) + fr = int(clamp(t, 0, duration) * fps) + self.lastSetFrame = fr + scene.frame_set(fr) + + ## blender time -> graph time + + @persistent + def on_frame_change_post(self, scene, deps): + if scene.frame_current != self.lastSetFrame: + # self.setGraphTime(scene.frame_current / scene.render.fps, self.duration) + self.lastSetFrame = scene.frame_current + t = scene.frame_current / scene.render.fps + self.setInGraph(t) + + def setInGraph(self, t: float): + log.warning(f'todo: set graph to {t}') \ No newline at end of file