Skip to content

Commit

Permalink
next sleep app
Browse files Browse the repository at this point in the history
  • Loading branch information
mariusandra committed Jun 23, 2024
1 parent 8490be9 commit d895deb
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 33 deletions.
5 changes: 2 additions & 3 deletions frameos/src/apps/data/localImage/app.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ type
AppConfig* = object
path*: string
order*: string
seconds*: float
counterStateKey*: string

App* = ref object
Expand Down Expand Up @@ -47,10 +46,10 @@ proc getImagesInFolder(folder: string): seq[string] =
return images

proc log*(self: App, message: string) =
self.scene.logger.log(%*{"event": &"{self.nodeId}:log", "message": message})
self.scene.logger.log(%*{"event": &"localImage:log", "message": message})

proc error*(self: App, context: ExecutionContext, message: string): Image =
self.scene.logger.log(%*{"event": &"{self.nodeId}:error", "error": message})
self.scene.logger.log(%*{"event": &"localImage:error", "error": message})
return renderError(
if context.hasImage: context.image.width else: self.frameConfig.renderWidth(),
if context.hasImage: context.image.height else: self.frameConfig.renderHeight(),
Expand Down
2 changes: 1 addition & 1 deletion frameos/src/apps/data/openaiImage/app.nim
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ proc get*(self: App, context: ExecutionContext): Image =
if imageUrl == "":
return self.error(context, "No image URL returned from OpenAI.")
var client2 = newHttpClient(timeout = 60000)
let imageData = client2.request(imageUrl, httpMethod = HttpGet)
defer: client2.close()
let imageData = client2.request(imageUrl, httpMethod = HttpGet)
if imageData.code != Http200:
return self.error(context, "Error fetching image " & $imageData.status)
result = decodeImage(imageData.body)
Expand Down
2 changes: 1 addition & 1 deletion frameos/src/apps/data/unsplash/app.nim
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ proc get*(self: App, context: ExecutionContext): Image =
if imageUrl == "":
return self.error(context, "No image URL returned from Unsplash.")
var client2 = newHttpClient(timeout = 60000)
defer: client2.close()
let realImageUrl = &"{imageUrl}&w={width}&h={height}&fit=crop&crop=faces,edges"
if self.frameConfig.debug:
self.log(&"Downloading image: {realImageUrl}")
let imageData = client2.request(realImageUrl, httpMethod = HttpGet)
defer: client2.close()
if imageData.code != Http200:
return self.error(context, &"Error {imageData.status} fetching image")
result = decodeImage(imageData.body)
Expand Down
27 changes: 27 additions & 0 deletions frameos/src/apps/logic/nextSleepDuration/app.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import json, options
import frameos/types

type
AppConfig* = object
duration*: float

App* = ref object
nodeId*: NodeId
scene*: FrameScene
appConfig*: AppConfig
frameConfig*: FrameConfig

proc init*(nodeId: NodeId, scene: FrameScene, appConfig: AppConfig): App =
result = App(
nodeId: nodeId,
scene: scene,
appConfig: appConfig,
frameConfig: scene.frameConfig,
)

proc log*(self: App, message: string) =
self.scene.logger.log(%*{"event": "setNextSleep:log", "message": message})

proc run*(self: App, context: ExecutionContext) =
context.nextSleep = self.appConfig.duration
self.log("Set sleep duration between renders to " & $context.nextSleep & " seconds")
14 changes: 14 additions & 0 deletions frameos/src/apps/logic/nextSleepDuration/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "Next sleep duration",
"description": "Override the delay between renders",
"category": "logic",
"version": "1.0.0",
"fields": [
{
"name": "duration",
"type": "float",
"required": true,
"label": "Duration in seconds"
}
]
}
6 changes: 5 additions & 1 deletion frameos/src/apps/render/split/app.nim
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,14 @@ proc render*(self: App, context: ExecutionContext, image: var Image) =
payload: context.payload,
parent: context,
loopIndex: row * columns + column,
loopKey: context.loopKey & "/" & $(row * columns + column)
loopKey: context.loopKey & "/" & $(row * columns + column),
nextSleep: context.nextSleep
)
self.scene.execNode(renderer, cellContext)
if cellContext.nextSleep != context.nextSleep:
context.nextSleep = cellContext.nextSleep
image.draw(cellContext.image, translate(vec2(cellX, cellY)))

cellX += cellWidth.toFloat + gapHorizontal
if column == columns - 1:
cellY += cellHeight.toFloat + gapVertical
Expand Down
2 changes: 1 addition & 1 deletion frameos/src/apps/render/text/app.nim
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import pixie, options, json, unicode
import pixie, options, unicode

import frameos/types
import frameos/config
Expand Down
53 changes: 27 additions & 26 deletions frameos/src/frameos/runner.nim
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ var

proc setLastImage(image: Image) =
withLock lastImageLock:
if lastImage.width != image.width or lastImage.height != image.height:
lastImage = newImage(image.width, image.height)
lastImage.draw(image)
lastImage = copy(image)
lastImagePresent = true

proc getLastImagePng*(): string =
Expand Down Expand Up @@ -122,37 +120,38 @@ proc getFirstSceneId*(): SceneId =
return key
return "".SceneId

proc renderSceneImage*(self: RunnerThread, exportedScene: ExportedScene, scene: FrameScene): Image =
proc renderSceneImage*(self: RunnerThread, exportedScene: ExportedScene, scene: FrameScene): (Image, float) =
let sceneTimer = epochTime()
let requiredWidth = self.frameConfig.renderWidth()
let requiredHeight = self.frameConfig.renderHeight()
self.logger.log(%*{"event": "render", "width": requiredWidth, "height": requiredHeight})

try:
var context = ExecutionContext(
scene: scene,
event: "render",
payload: %*{},
image: case self.frameConfig.rotate:
of 90, 270: newImage(self.frameConfig.height, self.frameConfig.width)
else: newImage(self.frameConfig.width, self.frameConfig.height),
hasImage: true,
loopIndex: 0,
loopKey: "."
)
var context = ExecutionContext(
scene: scene,
event: "render",
payload: %*{},
image: case self.frameConfig.rotate:
of 90, 270: newImage(self.frameConfig.height, self.frameConfig.width)
else: newImage(self.frameConfig.width, self.frameConfig.height),
hasImage: true,
loopIndex: 0,
loopKey: ".",
nextSleep: -1
)

try:
let image = exportedScene.render(scene, context)
if image.width != requiredWidth or image.height != requiredHeight:
let resizedImage = newImage(requiredWidth, requiredHeight)
resizedImage.fill(scene.backgroundColor)
scaleAndDrawImage(resizedImage, image, self.frameConfig.scalingMode)
setLastImage(resizedImage)
result = resizedImage.rotateDegrees(self.frameConfig.rotate)
result = (resizedImage.rotateDegrees(self.frameConfig.rotate), context.nextSleep)
else:
setLastImage(image)
result = image.rotateDegrees(self.frameConfig.rotate)
result = (image.rotateDegrees(self.frameConfig.rotate), context.nextSleep)
except Exception as e:
result = renderError(requiredWidth, requiredHeight, &"Error: {$e.msg}\n{$e.getStackTrace()}")
result = (renderError(requiredWidth, requiredHeight, &"Error: {$e.msg}\n{$e.getStackTrace()}"), context.nextSleep)
self.logger.log(%*{"event": "render:error", "error": $e.msg, "stacktrace": e.getStackTrace()})
self.lastRenderAt = epochTime()
self.logger.log(%*{"event": "render:done", "ms": round((epochTime() - sceneTimer) * 1000, 3)})
Expand Down Expand Up @@ -193,7 +192,7 @@ proc startRenderLoop*(self: RunnerThread): Future[void] {.async.} =
self.triggerRenderNext = false # used to debounce render events received while rendering

let interval = currentScene.refreshInterval
let lastRotatedImage = self.renderSceneImage(exportedScene, currentScene)
let (lastRotatedImage, nextSleep) = self.renderSceneImage(exportedScene, currentScene)
if interval < 1:
let now = epochTime()
if now >= nextServerRenderAt:
Expand All @@ -213,7 +212,7 @@ proc startRenderLoop*(self: RunnerThread): Future[void] {.async.} =
except Exception as e:
self.logger.log(%*{"event": "render:driver:error", "error": $e.msg, "stacktrace": e.getStackTrace()})

if interval < 1:
if interval < 1 or (nextSleep > 0 and nextSleep < interval):
let now = epochTime()
if now - timer < FAST_SCENE_CUTOFF_SECONDS:
fastSceneCount += 1
Expand Down Expand Up @@ -248,11 +247,12 @@ proc startRenderLoop*(self: RunnerThread): Future[void] {.async.} =
self.triggerRenderNext = false
continue

# Sleep until the next frame
sleepDuration = max((interval - (epochTime() - timer)) * 1000, 0.1)
# No sleep duration provided by the scene, calculate based on the interval

sleepDuration = if nextSleep >= 0: nextSleep * 1000
else: max((interval - (epochTime() - timer)) * 1000, 0.1)
self.logger.log(%*{"event": "sleep", "ms": round(sleepDuration, 3)})
# Calculate once more to subtract the time it took to log the message
sleepDuration = max((interval - (epochTime() - timer)) * 1000, 0.1)

let future = sleepAsync(sleepDuration)
self.sleepFuture = some(future)
await future
Expand All @@ -278,7 +278,8 @@ proc dispatchSceneEvent*(self: RunnerThread, sceneId: Option[SceneId], event: st
payload: payload,
hasImage: false,
loopIndex: 0,
loopKey: "."
loopKey: ".",
nextSleep: -1
)
exportedScene.runEvent(context)
if event == "setSceneState":
Expand Down
1 change: 1 addition & 0 deletions frameos/src/frameos/types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ type
parent*: ExecutionContext
loopIndex*: int
loopKey*: string
nextSleep*: float

StateField* = ref object
name*: string
Expand Down

0 comments on commit d895deb

Please sign in to comment.