/tinyletter

The Programs of the Week I Had Jury Duty

This Week’s Program: Apr 10 - Apr 14

This week, I fulfilled my civic obligation. I was selected as an alternate juror in a civil case that ended up being settled out of court. I feel proud knowing that I played my part in the administration of justice, and prouder having committed code from the jury assembly room in the New York County Supreme Court Building.

DUN DUN

Over the weekend, when I normally do not like to program, I did some programming. Or at least, I did some programming with Automator and Workflow — two tools that don’t involve code but nevertheless compose program parts together into larger programs. I love these tools. In Automator I made two macOS Services. Both are useful front-ends to the Keybase command line interface for signing and verifying textual messages. You can find both of these in my Keybase public folder. See my toot on Mastodon for some additional context and an animated gif of the signing Service in action. In Workflow, I made a thing so that I can subscribe to RSS feeds in Feed Wrangler quickly on my iPad. I’ll share that out if anyone is interested. Mastodon has given me some good old school web vibes and inspired me to stitch these small programs together.

Let’s talk about Overscan.

Overscan

I think the last few letters of mine have been difficult to follow. This project is a study in Yak Shaving.

Here’s a review:

  • I am learning the Racket programming language. This will be my third Lisp (after learning just enough Emacs Lisp to be productive and building sonic-sketches in Clojure).
  • The project I’m writing in Racket is overscan, a live-coding environment for broadcasting video. The idea is to build an environment like Overtone or Extempore but focused on streaming live video to platforms like Twitch or Facebook Live: evaluate a sexp and change the broadcast.
  • To start, I’m going to be writing some Racket bindings to the GStreamer multimedia framework, written in C and GLib.
  • Instead of writing a bunch of FFI bindings manually for GStreamer (aka GST), I decided to use GObject Introspection (aka GIR). GIR provides a bridge between a GLib library and another language by exposing an API to read metadata from the library and dynamically construct bindings.
  • There already is a GIR package for Racket, but it hasn’t been updated or maintained in nearly a year, and I’ve found numerous inconsistent and buggy behaviors with it. I’ve decided to write my own GIR bindings in Racket to use as a basis for my GST integration. That’s where I am now.

So now you’re caught up on what exactly I’m doing with all this Racket↔C interop. Soon, I’ll pop out of this level of the stack and get to GStreamer and maybe actually producing a video. I’ve cleared a lot of the way through my GObject Introspection bindings and have an API that I’m feeling better about and refining along the way.

The last real major hurdle to go here is to represent the most relevant binding: bindings for GObjects. Once those are in place I will be able to move on to integrating GStreamer.

Here are some highlights…

acd9682ad477723de02c11a208314903dac5b8fb

I create a new struct, gtype-instance, which represent C pointers to GTypes. Racket’s FFI library has some ingenious ways of dealing with C values, and my favorite is the cpointer construct. These represent pointers that have a tag associated with them, and when going from Racket to C, if that tag is not present Racket will error out. When creating C Types with Racket FFI, you provide two functions: A Racket → C function that will coerce a Racket value into the appropriate representation, and a C → Racket function that takes that representation and returns a suitable value.

So what I’ve done here is create a C Type that will be converted into an instance of gtype-instance when used within Racket, but will be coerced back into a pointer for use in C. It’s really easy to coerce back into a pointer form, because Racket structs can behave like C pointers when they have the prop:cpointer property.

a9092e219acb4230981f76cf0016df4e1950da56

This is exploited here, where I create a sub-struct of gtype-instance, gstruct-instance. This is effectively a decorator around a pointer to a C Struct, but when used in Racket you can observe the fields as a list. gstruct-instance also behaves like a procedure, and so you can call it like one to invoke methods on the struct.

d3cdba396060e83b971852ebb9cb7f0b0f1159e1

Enums are the next C type to get bindings. When used in C, these are effectively longs. When coerced into Racket, that long is used to lookup the symbol value. So when you call a C function that returns an Enum, what you get back is a symbol of the value of that enum! Making these C Types within Racket is neat!

Also, see that git commit message?

I’m committing this from the NY County Supreme Court because I’m in Jury Duty!

I am a cool dude.

There’s a bunch more commits but they’re iterations on a lot of the concepts I’ve laid out already. I make sure that type information and conversions are conserved when converting from one of my home-rolled C Types to the types that are represented in the Type Union used when invoking functions. I move the file into its final position: ffi/unsafe/introspection.rkt. I create an abstraction for something that occurs again and again in GIR, building up a list of items from two functions: one that returns the number of items and the other that returns the item at a given index:

(define (gi-build-list info numproc getter)
  (build-list (numproc info)
              (curry getter info)))

I make sure that gi-base-info base info values are always deallocated appropriately. And finally I convert the overscan package to be a “multi” collection in Racket’s package management parlance.

Next week, GObjects and signals, API hardening, and documentation.

DUN DUN

👩‍⚖️ Mark