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.
-
Current development
-
darcs pull https://darcs.eitilt.life/hscdio/
-