Timing, Timers, and Synchronization
Clocks and timers in Lingo - milliseconds, ticks, the timer, timeout objects, idle, cue points, and frame-rate-independent animation.
The clocks
the milliseconds -- ms since player start (the modern choice)
the ticks -- 60ths of a second since player start
the timer -- resettable tick counter (startTimer resets)
the systemDate -- date object
the long time -- formatted time strings (classic)
_system.milliseconds -- MX 2004 facade for the same counterthe ticks (1/60s) is the Director-native unit; timeouts and click timings are documented in ticks. the milliseconds arrived later and dominates late-era code.
startTimer -- reset the timer
if the timer > 120 then ... -- 2 seconds elapsed (in ticks)Frame-rate-independent animation
The tempo channel gives frames-per-second, but real elapsed time varies; robust movies animate by clock:
property pLastMs
on beginSprite me
pLastMs = the milliseconds
end
on prepareFrame me
dt = the milliseconds - pLastMs
pLastMs = the milliseconds
sprite(me.spriteNum).locH = sprite(me.spriteNum).locH + pSpeed * dt / 1000.0
endEmulator note: content mixes clock-based and frame-based animation freely. Frame-based movies (move 5px per exitFrame at tempo 30) require honoring the authored tempo; clock-based movies require honest wall-clock properties. Neither can be faked from the other.
Timeout objects (MX 2004 timers)
The precise recurring-callback tool (full object treatment in Parent scripts and objects):
tm = timeout().new("anim", 100, #tick, me) -- every 100 ms -> onTick
timeout("anim").period = 250
timeout("anim").forget()
_movie.timeoutListDelivery model: single-threaded, between frame events, on schedule but never preempting a running handler. A timeout that comes due repeatedly while a handler blocks delivers once when the thread frees (no burst catch-up in practice; verify against target player when it matters).
The classic timeout mechanism (Director 4-6)
Older, global, and still functional in MX-era players (all names present in the native symbol registry):
the timeoutLength = 60 * 60 * 2 -- 2 minutes, in ticks
the timeoutScript = "onUserIdle" -- primary handler string
the timeoutLapsed -- ticks since last reset
the timeoutKeyDown = TRUE -- keystrokes reset the timeout
the timeoutMouse = TRUE -- clicks reset it
the timeoutPlay = FALSE -- play commands reset itOne global inactivity timer: when timeoutLapsed reaches timeoutLength, the timeOut event fires (routed like other primary events). Kiosk-era attract loops are built on this.
idle
on idle handlers (frame/movie scripts only) run while Director waits out the tempo between enterFrame and exitFrame. the idleHandlerPeriod (ticks) throttles delivery; 0 means continuous. Idle is where cooperative background work happened (network polling, resource loading via the idle-load APIs in Memory and streaming).
Waiting correctly
-- WRONG for anything over ~100ms: blocks everything
repeat while the milliseconds - t0 < 2000
nothing
end repeat
-- RIGHT: loop the playhead on a frame
on exitFrame
if the milliseconds - gT0 > 2000 then go "next"
else go the frame
end
-- Tempo channel wait states (authored): wait N sec, wait for click/key, wait for cue point
delay 120 -- legacy: block frame advance 2 sec (input still processed for wait-abort)Cue points and media sync
Sounds (AIFF/WAV/SWA) and QuickTime media carry named cue points:
on cuePassed me, channelID, cueNumber, cueName
if cueName = "Chorus" then startChorusAnimation
end
member("song").cuePointNames, member("song").cuePointTimes
isPastCuePoint(sound 1, 2)
the mostRecentCuePoint of sound 1cuePassed routes like a sprite/frame/movie event (the sprite form fires for sprite-attached media). The tempo channel's "Wait for Cue Point" blocks frame advance until a cue arrives: the authored lip-sync mechanism.
Sound scheduling API on channels: queue() + play() for gapless sequences, breakLoop() to exit a loop section, loopCount/loopStartTime/loopEndTime, and elapsedTime for progress. Gapless queueing matters: rhythm and karaoke titles depend on it.
Performance-related globals
the cpuHogTicks -- (classic Mac) yield granularity to the OS
the netThrottleTicks -- network servicing granularity (Mac)
the idleHandlerPeriod
the idleLoadPeriodThese tuned cooperative multitasking on 90s machines. Emulators can accept and ignore them, but should keep them readable/writable.
Emulator timing checklist
- One thread, no preemption: handlers always run to completion.
- Tempo governs head advance; handlers can only slow it (no frame skipping of logic).
the milliseconds/ticksadvance during blocking loops (they read the wall clock).- Timeout objects fire between frames; blocked thread delays them.
updateStage()renders mid-handler and triggersstepFrame(see Event lifecycle).delayblocks advance but keeps processing wait-abort input.- Cue points fire
cuePassedwith correct channel/name arguments and honor queue order.