Mercurial > code > home > repos > light9
comparison blender/time_sync/time_from_graph.py @ 2457:d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
author | drewp@bigasterisk.com |
---|---|
date | Tue, 20 May 2025 13:48:07 -0700 |
parents | 2d454737a916 |
children | 0e27ba33118c |
comparison
equal
deleted
inserted
replaced
2456:917bc2eaf4f4 | 2457:d94480bfb179 |
---|---|
1 import asyncio | 1 import asyncio |
2 import threading | 2 import threading |
3 import time | 3 import time |
4 from typing import Coroutine | 4 from typing import Coroutine |
5 | 5 |
6 from attr import dataclass | |
6 from rdfdb.patch import Patch | 7 from rdfdb.patch import Patch |
7 from rdfdb.syncedgraph.syncedgraph import SyncedGraph | 8 from rdfdb.syncedgraph.syncedgraph import SyncedGraph |
8 from rdflib import Literal | 9 from rdflib import Literal |
9 | 10 |
10 from light9 import networking, showconfig | 11 from light9 import networking, showconfig |
11 from light9.ascoltami.graph_context import ascoltamiContext | 12 from light9.ascoltami.graph_context import ascoltamiContext |
13 from light9.ascoltami.play_state import AscoPlayState | |
12 from light9.namespaces import L9 | 14 from light9.namespaces import L9 |
13 from light9.newtypes import decimalLiteral | 15 from light9.newtypes import decimalLiteral |
14 from light9.run_local import log | 16 from light9.run_local import log |
15 from light9.typedgraph import typedValue | 17 from light9.typedgraph import typedValue |
16 | 18 |
22 SceneLoaded, | 24 SceneLoaded, |
23 _TimeEvent, | 25 _TimeEvent, |
24 ) | 26 ) |
25 | 27 |
26 | 28 |
27 | |
28 | |
29 | |
30 class Sync: | 29 class Sync: |
31 """asco is the authority on playback status. Sync maintains a copy of the state""" | 30 """asco is the authority on playback status. Sync maintains a copy of the state""" |
32 lock = threading.Lock() | 31 lock = threading.Lock() |
33 | 32 |
34 # these are written ONLY by bg thread | 33 # this is edited ONLY by bg thread |
35 duration: float = 1 | 34 ascoPlayState: AscoPlayState |
36 wallStartTime: float | None = None | |
37 pausedSongTime: float | None = None | |
38 latestSongTime: float | |
39 playing = False | |
40 | 35 |
41 def __init__(self): | 36 def __init__(self): |
42 # main thread | 37 # main thread |
43 self.blenderTime = BlenderTime(self.onEvent) | 38 self.ascoPlayState = AscoPlayState(None, None, False, False, 1.0) |
39 self.blenderTime = BlenderTime(self.onBlenderEvent, self.ascoPlayState) | |
44 self.blenderTime.start() | 40 self.blenderTime.start() |
45 | 41 |
46 self.ctx = ascoltamiContext(showconfig.showUri()) | 42 self.ctx = ascoltamiContext(showconfig.showUri()) |
47 log.debug('🚋3 startLoopInThread') | 43 log.debug('🚋3 startLoopInThread') |
48 self._loop = startLoopInThread(self.connectGraph()) | 44 self._loop = startLoopInThread(self.connectGraph()) |
49 log.info('🚋10 Sync initd') | 45 log.info('🚋10 Sync initd') |
50 | 46 |
51 def onEvent(self, event: _TimeEvent): | 47 def onBlenderEvent(self, event: _TimeEvent): |
52 # main thread | 48 # main thread |
53 match event: | 49 match event: |
54 case SceneLoaded(): | 50 case SceneLoaded(): |
55 if hasattr(self, "latestSongTime"): | 51 self.blenderTime.setRange(self.ascoPlayState.duration) |
56 self.blenderTime.setBlenderTime(self.latestSongTime, self.duration) | 52 self.blenderTime.setCurrentTime(self.ascoPlayState.getCurrentSongTime() or 0.0) |
57 case PausedGotoTime(t): | 53 case PausedGotoTime(t): |
58 self.runInBackgroundLoop(self.setInGraph(t, False)) | 54 self.runInBackgroundLoop(self.setInGraph(t, False)) |
59 case PlayingGotoTime(t): | 55 case PlayingGotoTime(t): |
60 self.runInBackgroundLoop(self.setInGraph(t, True)) | 56 self.runInBackgroundLoop(self.setInGraph(t, True)) |
61 | 57 |
71 | 67 |
72 def syncFromGraph(self): | 68 def syncFromGraph(self): |
73 # bg thread | 69 # bg thread |
74 with self.lock: | 70 with self.lock: |
75 asco = L9['ascoltami'] | 71 asco = L9['ascoltami'] |
76 self.wallStartTime = typedValue(float | None, self.graph, asco, L9['wallStartTime']) | 72 |
77 self.pausedSongTime = typedValue(float | None, self.graph, asco, L9['pausedSongTime']) | 73 self.ascoPlayState.wallStartTime = typedValue(float | None, self.graph, asco, L9['wallStartTime']) |
78 self.duration = typedValue(float | None, self.graph, asco, L9['duration']) or 1.0 | 74 self.ascoPlayState.pausedSongTime = typedValue(float | None, self.graph, asco, L9['pausedSongTime']) |
79 self.playing = typedValue(bool | None, self.graph, asco, L9['playing']) or False | 75 self.ascoPlayState.duration = typedValue(float | None, self.graph, asco, L9['duration']) or 1.0 |
80 | 76 self.blenderTime.durationDirty = True # todo: called too often |
81 def currentTime(self) -> float | None: | 77 self.ascoPlayState.playing = typedValue(bool | None, self.graph, asco, L9['playing']) or False |
82 if self.wallStartTime is not None: | 78 self.ascoPlayState.endOfSong = typedValue(bool | None, self.graph, asco, L9['endOfSong']) or False |
83 return time.time() - self.wallStartTime | 79 log.info(f'🍇 syncFromGraph {self.ascoPlayState=}') |
84 if self.pausedSongTime is not None: | 80 self.blenderTime.curFrameDirty = True |
85 return self.pausedSongTime | |
86 log.warn('no time data') | |
87 return None | |
88 | 81 |
89 async def setGraphPlaying(self, isBlenderPlaying: bool): | 82 async def setGraphPlaying(self, isBlenderPlaying: bool): |
83 return | |
90 # bg thread | 84 # bg thread |
91 log.info(f'set graph playing to {isBlenderPlaying}') | 85 log.info(f'set graph playing to {isBlenderPlaying}') |
92 self.graph.patchObject(self.ctx, L9['ascoltami'], L9['playing'], Literal(isBlenderPlaying)) | 86 self.graph.patchObject(self.ctx, L9['ascoltami'], L9['playing'], Literal(isBlenderPlaying)) |
93 | 87 |
94 async def setInGraph(self, t: float, isBlenderPlaying: bool): | 88 async def setInGraph(self, t: float, isBlenderPlaying: bool): |