Haskell bindings to libcdio

One of my coworkers loves reading YA fantasy, and I canʼt say I blame her. An idea from one of the stories she read, Dragon Slippers has stuck with her: dragons with highly diverse hoards, not (necessarily) of gold or jewels, but of wineglasses, or flowering plants, or books, or the titular slippers. The question of what each of us would hoard were we dragons has become a means of getting to know new hires better. As for myself, my hoard would be music. There are currently somewhere in the high thirties of stations on Pandora which I actively switch between. My saved music library got badly hit when my last hard drive crashed, but I had collected over eight thousand song files between digital albums, free demo/hobby tracks, and fair‐use personal backups. I give CDs for every birthday and Christmas gift, and have frequently baffled people with the number and variety of obscure bands I can recommend offhand.

The standard software—iTunes, Amarok, cmus—begins to fail when faced with such a hoard. Why should a song be listed twice (each with their own separate tags which need to be kept in sync) just because it appears on both a compilation album and the original release, to say nothing of a lossless file for archival and lossy for on the go? Surely thereʼs a better way to tie an instrumental version to its full recording, or to see everything by a single artist even as they jump between bands? What about retrieving a single track from a disc ripped into a single file, while keeping its specific metadata from polluting the rest of the album? My needs in library management are not particularly compatible with the pick‐and‐choose, 99¢‐a‐song modern buying habits that most databases are built around.

And so, like a good hacker, I have plans for making my own suite of programs tailored to my own particular needs (which hopefully will be useful to at least a few other people). The pipeline underlying that suite starts with a disc ripper, and one of the best libraries on Linux seemed to be libcdio. Unfortunately, the only way to interface with it in Haskell would be through calling the prebuilt programs via System.Process or similar, and trying to parse the human‐oriented output. So, as a first step, I instead took a detour through writing bindings to be able to interface with the C headers directly.

Design

The original library is a reasonably good showcase of all the points where the C programming style conflicts with that of Haskell: pointers being liberally passed around, some enums representing actual enumerations (complete with meta‐values indicating some combination of their siblings) and others being keys into bit arrays, requiring at least three different functions for manually freeing memory… Using its model for the bindings might not be physically painful in the Haskell context, but it would be anything but comfortable. But, before whatever native interface I would wind up turning it into, the FFI already requires a one‐to‐one association between functions at some level, so rather than squirreling it away into the dark backend, I figured I may as well do what I could to polish it up, and release it anyway for those few who might be more used to the C way of doing things; this was likely inspired by pycdio.

Therefore, this package is really two distinct but conjoined bindings to libcdio. I strongly recommend working in Sound.Libcdio for seemingly‐pure functions and monadic type safety. If any quality‐of‐life improvements are made on top of the library, that is the interface where the appear. If, however, you have used libcdio in the past, or if you are following a guide or other instructions for how to use the library, you will finde the Foreign.Libcdio to require less mental translation between what you expect and what these bindings provide.

Due to Cabal's lack of ability to pin a external library to a specific version, but Haskell's emphasis on predictability, the bindings are designed to be compatible with a broad range of underlying versions; if the system libcdio is too early to support something, the function remains to be called, but will always return a default value, often Nothing; similarly, any enum types are modified to always have the same constructors, even if their numeric representations change.

Installation

While these Haskell bindings are hosted on the standard package repositories, they require the original C libcdio to installed before they are built. For that reason, if you have the option to install hscdio through your standard package manager intead, do so; I have provided build scripts for both Arch (untested) and Gentoo Linux. The official source tarballs are linked below if you want to write your own for whatever distribution you yourself use. Documentation for the most recent version is hosted on this website (links are in the sidebar); documentation for older versions may be found on both Hackage and Stackage, and anywhere else which pulls information from either location.