Luau Bindings — audio

The require("audio") script API — system audio for scripts. The concrete device today is the buzzer (namespaced audio.buzzer, since it won't be the only audio device); the wider audio system — sampled playback, the Tempest voices, Pulse synthesis — will join the top-level `audio.namespace as it reaches scripting. Every function is **[antos]`*. Design & native core: antos_audio.

local audio = require("audio")
audio.buzzer(440, 200)          -- queue A4 for 200 ms
audio.buzzer(880, 100, true)    -- interrupt: play A5 immediately

The buzzer

One call queues or plays a buzzer tone (or a default chirp). Non-blocking — tones queue and play in the background. On the CM5 the timing is Clicky's: DeMon sends the tone, Clicky bit-bangs it (DeMon has no buzzer driver of its own).

audio.buzzer([freq [, ms [, now]]]) — all three arguments optional:

  • freq — frequency in Hz. Omit for a default chip (a short chirp); 0 is a rest.
  • ms — duration. Omit for a short default.
  • now — true flushes the queue and plays immediately (interrupt); omit or false queues it behind whatever's already playing.
Call Plays
audio.buzzer() a default chirp — short, queued
audio.buzzer(440) 440 Hz, short, queued
audio.buzzer(440, 200) 440 Hz for 200 ms, queued
audio.buzzer(880, 100, true) 880 Hz for 100 ms, immediately
audio.buzzer(0, 50) a 50 ms rest, queued
Function Behaviour
audio.buzzerClear() Clear the buzzer queue / stop.
audio.buzzerReady() Is the buzzer up?

Why audio.buzzer, not audio.tone? The buzzer is one device, not the whole of audio. Namespacing its calls keeps the bare audio.* surface free for the Ant64's real audio — sampled playback and the Tempest/Pulse voices — which will land as audio.* calls of their own rather than fighting the buzzer for names.

Stage-synced cues

Schedule playback on the stage tick, so sound locks to animation — the audio cousin of timeline. The trigger is tick-locked (deterministic); the output is real-time. Design: antos_audio.

Call Does
audio.cue(sound, opts?) schedule sound (a buzzer tone spec today, a sample later) at { at = tick } or { beat = n }; fires on that frame. opts.loop repeats
audio.tempo(bpm) set the beat clock, counted in stage ticks
audio.beat(handler) call handler(n) on each beat — rhythm sync
audio.uncue(handle) cancel a scheduled cue
local audio = require("audio")
audio.tempo(120)
audio.beat(function(n) if n % 4 == 0 then audio.buzzer(880, 40) end end)   -- a click every bar
-- a hit-sound locked to the frame a punch lands:
timeline.new():add(motion.play(fist, jab$)):call(function() audio.cue({ 220, 60 }) end):play()

Related

Important: The Ant64 family of home computers are at early design/prototype stage, everything you see here is subject to change.