Mercurial > code > home > repos > light9
annotate 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 |
rev | line source |
---|---|
2454 | 1 import asyncio |
2432 | 2 import threading |
3 import time | |
2455 | 4 from typing import Coroutine |
2432 | 5 |
2455 | 6 from rdfdb.patch import Patch |
2432 | 7 from rdfdb.syncedgraph.syncedgraph import SyncedGraph |
2455 | 8 from rdflib import Literal |
2432 | 9 |
2454 | 10 from light9 import networking, showconfig |
2455 | 11 from light9.ascoltami.graph_context import ascoltamiContext |
2432 | 12 from light9.namespaces import L9 |
2454 | 13 from light9.newtypes import decimalLiteral |
2432 | 14 from light9.run_local import log |
2453
b23afde50bc2
blender addons get thier own pdm setup for now. fix time_from_graph startup race
drewp@bigasterisk.com
parents:
2436
diff
changeset
|
15 from light9.typedgraph import typedValue |
2432 | 16 |
2455 | 17 from ..asyncio_thread import startLoopInThread |
18 from .blender_time import ( | |
19 BlenderTime, | |
20 PausedGotoTime, | |
21 PlayingGotoTime, | |
22 SceneLoaded, | |
23 _TimeEvent, | |
24 ) | |
2432 | 25 |
26 | |
2455 | 27 |
2432 | 28 |
29 | |
30 class Sync: | |
2455 | 31 """asco is the authority on playback status. Sync maintains a copy of the state""" |
2432 | 32 lock = threading.Lock() |
2455 | 33 |
34 # these are written ONLY by bg thread | |
2432 | 35 duration: float = 1 |
36 wallStartTime: float | None = None | |
37 pausedSongTime: float | None = None | |
2455 | 38 latestSongTime: float |
2433 | 39 playing = False |
2432 | 40 |
41 def __init__(self): | |
42 # main thread | |
2455 | 43 self.blenderTime = BlenderTime(self.onEvent) |
44 self.blenderTime.start() | |
45 | |
46 self.ctx = ascoltamiContext(showconfig.showUri()) | |
2454 | 47 log.debug('🚋3 startLoopInThread') |
2455 | 48 self._loop = startLoopInThread(self.connectGraph()) |
2454 | 49 log.info('🚋10 Sync initd') |
2432 | 50 |
2455 | 51 def onEvent(self, event: _TimeEvent): |
52 # main thread | |
53 match event: | |
54 case SceneLoaded(): | |
55 if hasattr(self, "latestSongTime"): | |
56 self.blenderTime.setBlenderTime(self.latestSongTime, self.duration) | |
57 case PausedGotoTime(t): | |
58 self.runInBackgroundLoop(self.setInGraph(t, False)) | |
59 case PlayingGotoTime(t): | |
60 self.runInBackgroundLoop(self.setInGraph(t, True)) | |
2432 | 61 |
2454 | 62 def runInBackgroundLoop(self, f: Coroutine): |
2455 | 63 # main thread |
2454 | 64 asyncio.run_coroutine_threadsafe(f, self._loop) |
65 | |
2455 | 66 async def connectGraph(self): |
67 # bg thread | |
2454 | 68 log.info('🚋11 start SyncedGraph') |
2432 | 69 self.graph = SyncedGraph(networking.rdfdb.url, "time_sync") |
70 self.graph.addHandler(self.syncFromGraph) | |
71 | |
72 def syncFromGraph(self): | |
73 # bg thread | |
74 with self.lock: | |
75 asco = L9['ascoltami'] | |
2433 | 76 self.wallStartTime = typedValue(float | None, self.graph, asco, L9['wallStartTime']) |
77 self.pausedSongTime = typedValue(float | None, self.graph, asco, L9['pausedSongTime']) | |
78 self.duration = typedValue(float | None, self.graph, asco, L9['duration']) or 1.0 | |
2436
e683b449506b
blender effect that sets lights to match blender lights
drewp@bigasterisk.com
parents:
2434
diff
changeset
|
79 self.playing = typedValue(bool | None, self.graph, asco, L9['playing']) or False |
2432 | 80 |
81 def currentTime(self) -> float | None: | |
82 if self.wallStartTime is not None: | |
83 return time.time() - self.wallStartTime | |
84 if self.pausedSongTime is not None: | |
85 return self.pausedSongTime | |
86 log.warn('no time data') | |
87 return None | |
88 | |
2455 | 89 async def setGraphPlaying(self, isBlenderPlaying: bool): |
90 # bg thread | |
91 log.info(f'set graph playing to {isBlenderPlaying}') | |
92 self.graph.patchObject(self.ctx, L9['ascoltami'], L9['playing'], Literal(isBlenderPlaying)) | |
2432 | 93 |
2454 | 94 async def setInGraph(self, t: float, isBlenderPlaying: bool): |
2455 | 95 # bg thread |
96 log.info(f'set graph time to {t:.2f} {isBlenderPlaying=}') | |
97 p = Patch() | |
2454 | 98 if isBlenderPlaying: |
2455 | 99 p = p.update(self.graph.getObjectPatch(self.ctx, L9['ascoltami'], L9['playing'], Literal(True))) |
100 p = p.update(self.graph.getObjectPatch(self.ctx, L9['ascoltami'], L9['wallStartTime'], decimalLiteral(round(time.time() - t, 1)))) | |
101 p = p.update(self.graph.getObjectPatch(self.ctx, L9['ascoltami'], L9['pausedSongTime'], None)) | |
2454 | 102 else: |
2455 | 103 p = p.update(self.graph.getObjectPatch(self.ctx, L9['ascoltami'], L9['playing'], Literal(False))) |
104 p = p.update(self.graph.getObjectPatch(self.ctx, L9['ascoltami'], L9['wallStartTime'], None)) | |
105 p = p.update(self.graph.getObjectPatch(self.ctx, L9['ascoltami'], L9['pausedSongTime'], decimalLiteral(round(t, 1)))) | |
2454 | 106 |
2455 | 107 if p.isEmpty(): |
108 return | |
109 log.info(f'setInGraph {p.shortSummary()}') | |
2454 | 110 await self.graph.patch(p) |