/tinyletter

The Programs of the First Week of October

This Weak Program: Oct 2 - Oct 6

Do you see it? This email’s easter egg? It’s my clever joke.

Oh hi friends thank you for reading about my esoteric program. Yes I’m still working on it. This is the hardest side project in the world to describe.

This week I continued to make progress on my Racket bindings for the multimedia C framework that will power my live coding environment for live streaming video. Cool, right? The coolest?

708d000d47a170587698132f8e3bc6705743d5c1

I continue my build-out of Racket classes that delegate to GObjects. Here’s pipeline%, which is the piece of the puzzle that lets me finally actually make video.

12b0b1150879f77db81931407ed7ee4e40dcdd87

Now that I’m pulling these pieces together in a cohesive manner, I can do some patterns I didn’t think about doing before, like wrapping last week’s bin%-compose in a pipeline% object. pipeline%-compose let’s me quickly create a GStreamer pipeline.

So I can do something like this:

(pipeline%-compose "borat-voice:my-pipes"
    (element-factory%-make "videotestsrc")
    (element-factory%-make "osxvideosink")

This makes a pipeline, and then I can play it! Simple as pie(-pline).

b1a4f8929ee6e8ec7b2ef42148d600647d952483

I rename the introspection functions is-a? and is-a?/c to is-gtype? and is-gtype/c?. The latter forms are more descriptive about what’s actually being checked and they don’t conflict with identifiers from racket/class. I think I might end up renaming or removing a bunch of functionality in ffi/unsafe/introspection so that there are no conflicts with racket/class at all. Now that I have gobject<%>, I think I’ve done enough real-world programming to show how the world of Racket OOP and GIR can coexist.

6d67c6fd2012a960af220c53c5c94cc4faf78c27

Everybody get on the bus%! Here I’m reworking how I can pull messages from a pipeline off a FIFO queue. 🚌

1871749bee5035dbf43f751bf3d3d54613b31ec3

Here’s a couple of handy functions for working with the generic gobject interface I set up a few weeks ago (the same one that all of these gobject% subclasses implement). gobject-ptr will extract a gtype-instance pointer out of anything that implements prop:gobject, and gobject/c is a contract similar to is-gtype?/c, but accepts gobject values. I’ll use these later to have the make-bus-channel a little cleaner and able to operate on any Bus derivative.

b92404cc4b71e6addf69f081995646a7d161e09b

A couple of more helpers for working with GIR bitmasks. A bitmask is a special case of gi-enum, and these functions just help me clarify some contracts for working with them.

ef257cd9ccf67a85d9cebf86e95984f19b6b2fe2

Some more refinements to working with GStreamer buses and messages. When a bus channel gets an end of stream or error message, it should close down. The internal implementation of these channels utilize Racket places. A place is something between a thread, a CSP routine, and a fork of the Racket process. I don’t want it to utilize system resources when it’s not being used, mostly because I have no idea what system resources are being utilized when a Place exists. The output of the place has been a message from the bus, which I wrap and cast into the right kind of interface. But now I do a select kind of operation to see if there’s a message waiting or if the place has closed down. The function to do this select (that terminology should be familiar to Golang fans) is called choice-evt, and one of the choices is place-dead-evt. This is a Racket event that can be synchronized when a place has terminated.

Now make-bus-channel returns a channel that has three kinds of results when synchronized (with sync, naturally):

  • A message from the bus
  • #f (that’s false) when there’s a NULL pointer (to be expected with the particulars of the underlying bus operation).
  • The place-dead-evt, which can be checked with evt?, for when the bus channel has closed down. Once the channel has closed, this will always be the synchronization result and doing a sync won’t ever block.

One of these days I’ll write a big blog post (or something) about thinking in CSP across various languages (Clojure with core.async, my limited understanding of Go routines, and Racket). It’s a dope way of managing concurrent operations. Would you be interested in something like that?

With this week’s contribution, I can now begin closing out the gstreamer module with some final utility functions and structures and a whole bunch of documentation. Feels like a good week!

🍂 Mark