Mercurial > code > home > repos > light9
diff 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 |
line wrap: on
line diff
--- a/blender/time_sync/blender_time.py Tue May 20 09:25:18 2025 -0700 +++ b/blender/time_sync/blender_time.py Tue May 20 13:48:07 2025 -0700 @@ -5,6 +5,7 @@ from bpy.app.handlers import persistent from light9.run_local import log +from light9.ascoltami.play_state import AscoPlayState UPDATE_PERIOD = 1 / 20 @@ -31,12 +32,23 @@ t: float +@dataclass +class BlenderPlayState: + isAnimationPlaying: bool + isScrubbing: bool + + class BlenderTime: """all methods to run in main thread""" - def __init__(self, onEvent: Callable[[_TimeEvent], None]): + def __init__(self, onEvent: Callable[[_TimeEvent], None], ascoltamiPlayStateRO: AscoPlayState): + self.ascoltamiPlayStateRO = ascoltamiPlayStateRO self._onEvent = onEvent self.lastSetFrame = -1 + self.lastPlayState = BlenderPlayState(False, False) + self.loaded = False + self.curFrameDirty = True + self.durationDirty = True def start(self): bpy.app.handlers.load_post.append(self._on_load_post) @@ -44,11 +56,13 @@ # need persistent because `blender --addons ...` seems to start addon # before loading scene. - bpy.app.timers.register(self.update, persistent=True) + bpy.app.timers.register(self._update, persistent=True) - self.emitEvent(SceneLoaded()) + self._emitEvent(SceneLoaded()) def setSceneDuration(self, duration: float): + if not self.loaded: + return self.duration = duration scene = bpy.context.scene fps = scene.render.fps @@ -56,6 +70,7 @@ scene.frame_end = int(duration * fps) def frameDuration(self): + """press Home on the timeline to frame the whole range""" return # todo: need to be in screen context or something context_override = bpy.context.copy() @@ -64,44 +79,55 @@ bpy.ops.action.view_all() def setCurrentTime(self, t: float): + if not self.loaded: + return scene = bpy.context.scene fps = scene.render.fps - fr = int(clamp(t, 0, self.duration) * fps) + fr = int(clamp(t * fps, 0, scene.frame_end)) self.lastSetFrame = fr scene.frame_set(fr) - def setBlenderTime(self, t: float, duration: float): - log.info(f'set blender time to {t:.2f}') + def setRange(self, duration: float): self.setSceneDuration(duration) self.frameDuration() - self.setCurrentTime(t) - def emitEvent(self, event: _TimeEvent): - log.info(f'🌹 emitEvent {event}') + def _emitEvent(self, event: _TimeEvent): + # log.info(f'🌹 emitEvent {event}') self._onEvent(event) @persistent - def update(self): - if 0: - if self.playing: - with self.lock: - t = self.currentTime() - if t is not None: - self.blenderTime.setBlenderTime(t, self.duration) + def _update(self): + if self.curFrameDirty or self.ascoltamiPlayStateRO.playing: + self._followAscoTime() + self.curFrameDirty=False + if self.durationDirty: + if (d := self.ascoltamiPlayStateRO.duration) is not None: + self.setRange(d) + self.durationDirty = False + # # todo: playing in blender should start ascoltami playback + # cur = BlenderPlayState(bpy.context.screen.is_animation_playing, bpy.context.screen.is_scrubbing) + return UPDATE_PERIOD + def _followAscoTime(self): + if (t := self.ascoltamiPlayStateRO.getCurrentSongTime()) is not None: + self.setCurrentTime(t) + @persistent def _on_load_post(self, scene, deps): - self.emitEvent(SceneLoaded()) + self._emitEvent(SceneLoaded()) + self.loaded = True + self.curFrameDirty = True @persistent def _on_frame_change_post(self, scene, deps): - # if scene.frame_current == self.lastSetFrame: - # return + # log.info(f' _on_frame_change_post {self.lastPlayState}') + if scene.frame_current == self.lastSetFrame: + return # blender requested this frame change, either playing or paused (scrubbing timeline) self.lastSetFrame = scene.frame_current t = round(scene.frame_current / scene.render.fps, 3) - if bpy.context.screen.is_animation_playing and not bpy.context.screen.is_scrubbing: - self.emitEvent(PlayingGotoTime(t=t)) + if self.lastPlayState.isAnimationPlaying and not self.lastPlayState.isScrubbing: + self._emitEvent(PlayingGotoTime(t=t)) else: - self.emitEvent(PausedGotoTime(t=t)) + self._emitEvent(PausedGotoTime(t=t))