Mercurial > code > home > repos > light9
annotate blender/time_sync/blender_time.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 |
rev | line source |
---|---|
2455 | 1 from dataclasses import dataclass |
2 from typing import Callable | |
2432 | 3 |
2455 | 4 import bpy |
5 from bpy.app.handlers import persistent | |
2432 | 6 |
7 from light9.run_local import log | |
2457
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
8 from light9.ascoltami.play_state import AscoPlayState |
2455 | 9 |
10 UPDATE_PERIOD = 1 / 20 | |
2432 | 11 |
12 | |
13 def clamp(lo, hi, x): | |
14 return max(lo, min(hi, x)) | |
15 | |
16 | |
2455 | 17 class _TimeEvent(): |
18 pass | |
19 | |
20 | |
21 class SceneLoaded(_TimeEvent): | |
22 pass | |
23 | |
24 | |
25 @dataclass | |
26 class PausedGotoTime(_TimeEvent): | |
27 t: float | |
2432 | 28 |
29 | |
2455 | 30 @dataclass |
31 class PlayingGotoTime(_TimeEvent): | |
32 t: float | |
33 | |
34 | |
2457
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
35 @dataclass |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
36 class BlenderPlayState: |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
37 isAnimationPlaying: bool |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
38 isScrubbing: bool |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
39 |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
40 |
2455 | 41 class BlenderTime: |
42 """all methods to run in main thread""" | |
2432 | 43 |
2457
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
44 def __init__(self, onEvent: Callable[[_TimeEvent], None], ascoltamiPlayStateRO: AscoPlayState): |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
45 self.ascoltamiPlayStateRO = ascoltamiPlayStateRO |
2455 | 46 self._onEvent = onEvent |
2432 | 47 self.lastSetFrame = -1 |
2457
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
48 self.lastPlayState = BlenderPlayState(False, False) |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
49 self.loaded = False |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
50 self.curFrameDirty = True |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
51 self.durationDirty = True |
2455 | 52 |
53 def start(self): | |
54 bpy.app.handlers.load_post.append(self._on_load_post) | |
55 bpy.app.handlers.frame_change_post.append(self._on_frame_change_post) | |
2454 | 56 |
2453
b23afde50bc2
blender addons get thier own pdm setup for now. fix time_from_graph startup race
drewp@bigasterisk.com
parents:
2436
diff
changeset
|
57 # need persistent because `blender --addons ...` seems to start addon |
b23afde50bc2
blender addons get thier own pdm setup for now. fix time_from_graph startup race
drewp@bigasterisk.com
parents:
2436
diff
changeset
|
58 # before loading scene. |
2457
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
59 bpy.app.timers.register(self._update, persistent=True) |
2432 | 60 |
2457
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
61 self._emitEvent(SceneLoaded()) |
2432 | 62 |
2455 | 63 def setSceneDuration(self, duration: float): |
2457
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
64 if not self.loaded: |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
65 return |
2455 | 66 self.duration = duration |
2432 | 67 scene = bpy.context.scene |
68 fps = scene.render.fps | |
69 scene.frame_start = 0 | |
70 scene.frame_end = int(duration * fps) | |
2455 | 71 |
72 def frameDuration(self): | |
2457
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
73 """press Home on the timeline to frame the whole range""" |
2455 | 74 return |
75 # todo: need to be in screen context or something | |
76 context_override = bpy.context.copy() | |
77 # context_override["selected_objects"] = list(context.scene.objects) | |
78 with bpy.context.temp_override(**context_override): | |
79 bpy.ops.action.view_all() | |
80 | |
81 def setCurrentTime(self, t: float): | |
2457
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
82 if not self.loaded: |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
83 return |
2455 | 84 scene = bpy.context.scene |
85 fps = scene.render.fps | |
2457
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
86 fr = int(clamp(t * fps, 0, scene.frame_end)) |
2432 | 87 self.lastSetFrame = fr |
88 scene.frame_set(fr) | |
89 | |
2457
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
90 def setRange(self, duration: float): |
2455 | 91 self.setSceneDuration(duration) |
92 self.frameDuration() | |
93 | |
2457
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
94 def _emitEvent(self, event: _TimeEvent): |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
95 # log.info(f'🌹 emitEvent {event}') |
2455 | 96 self._onEvent(event) |
2432 | 97 |
98 @persistent | |
2457
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
99 def _update(self): |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
100 if self.curFrameDirty or self.ascoltamiPlayStateRO.playing: |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
101 self._followAscoTime() |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
102 self.curFrameDirty=False |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
103 if self.durationDirty: |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
104 if (d := self.ascoltamiPlayStateRO.duration) is not None: |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
105 self.setRange(d) |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
106 self.durationDirty = False |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
107 # # todo: playing in blender should start ascoltami playback |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
108 # cur = BlenderPlayState(bpy.context.screen.is_animation_playing, bpy.context.screen.is_scrubbing) |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
109 |
2455 | 110 return UPDATE_PERIOD |
2432 | 111 |
2457
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
112 def _followAscoTime(self): |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
113 if (t := self.ascoltamiPlayStateRO.getCurrentSongTime()) is not None: |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
114 self.setCurrentTime(t) |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
115 |
2455 | 116 @persistent |
117 def _on_load_post(self, scene, deps): | |
2457
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
118 self._emitEvent(SceneLoaded()) |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
119 self.loaded = True |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
120 self.curFrameDirty = True |
2455 | 121 |
122 @persistent | |
123 def _on_frame_change_post(self, scene, deps): | |
2457
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
124 # log.info(f' _on_frame_change_post {self.lastPlayState}') |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
125 if scene.frame_current == self.lastSetFrame: |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
126 return |
2455 | 127 # blender requested this frame change, either playing or paused (scrubbing timeline) |
128 self.lastSetFrame = scene.frame_current | |
129 t = round(scene.frame_current / scene.render.fps, 3) | |
2457
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
130 if self.lastPlayState.isAnimationPlaying and not self.lastPlayState.isScrubbing: |
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
131 self._emitEvent(PlayingGotoTime(t=t)) |
2454 | 132 else: |
2457
d94480bfb179
more work on blender time sync. Might be working, aside from blender play-button
drewp@bigasterisk.com
parents:
2455
diff
changeset
|
133 self._emitEvent(PausedGotoTime(t=t)) |