Hems

A WEFT program is a pure signal graph, without side effects or mutations. However a real patch needs to touch the outside world through camera feeds, outputs, parameters, mics, etc. Something has to wire those up without messing up the signal graph.

I’m calling these hems for now (they’re where the signal graph starts and ends). A hem declares how a signal connects to the runtime. The format is

# <signal name> = <hem operator> (<parameters>)

The syntax mirrors regular WEFT definitions, but preceeded by a # (and the hem operators use named parameters with colons). For example:

#cam1[3] = camera(device: "FaceTime HD", width: 1920, height: 1080)
#freq = slider(default:440, min:20, max:20000)
#song1 = audioFile(path:"Downloads/song.mp3")

After this, cam1, freq, and song1 are just regular signals. The signal graph doesn’t know or care where they came from, or the fact that they’re not pure.

Outputs are also hems. display and play used to be magic reserved names for output signals, but there’s no reason they need to be. Instead, we can use the videoOut and audioOut hems:

#coolVisual[3] = videoOut(monitor: 1, width: 1920, height: 1080)
#sound = audioOut(device: "leos airpods", rate: 44100)

The videoOut and audioOut operators carry the semantics of evaluating the signal and rendering it. The name (coolVisual or sound) are just how you reference it in the signal graph. This means you can also have multiple outputs, named whatever you want.

The weirdest hem operator is history, which indicates to the runtime the maximum size of a feedback buffer. If you have a signal foo where {@t = @t - 0.1}, the runtime knows that you only need 0.1 seconds of history, and can allocate an appropriately sized buffer. However, if you had something like foo where {@t = @t - bar}, the runtime doesn’t know the size of bar, so it doesn’t know how big of a buffer to allocate. In this case, you have to use a hem:

#foo = history(depth: 5, units: "seconds")
foo = foo where {@t = @t - bar};

This assures the runtime that the offset (provided by bar) will never get larger than 5 seconds, so the runtime can allocate a buffer accordingly.

A signal can have multiple hems. For example, if we need both a camera input and we want that camera input from a variable number of frames ago, we can write:

#cam1[3] = camera(device: "FaceTime HD", width: 1920, height: 1080)
#cam1 = history(depth: 60, units: "frames")

Taken together, the hems at the top of a file form a complete picture of everything a WEFT program touches. Every input, output, parameter, etc.