Previously I mentioned my simple music player in CL, Shuffletron. Shuffletron uses save-lisp-and-die on SBCL or save-application on CCL to create a standalone executable, and is launched by a wrapper script that invokes it with rlwrap when available. It depends on several foreign libraries (more than I expected, in fact), and there were an alarming number of problems with the binaries I'd originally posted, all related to these library dependencies. I think I've solved them, though not necessarily in an optimal way.
The first problem, observed and fixed before the publically released binaries, was an issue where cffi-grovel (on behalf of Osicat) created a shared library with some auto-generated C wrappers for various functions, which the saved executable now expected to reopen at startup. I didn't realize this until my first user reported it dying at startup with an error about not finding /home/hefner/clbuild/source/osicat/posix/w
The next problem was simple - on machines without the libc6 development package installed, the program failed at startup, unable to load librt. This was a simple matter of Osicat not using the best choice of name by which to load the library, a problem which has since been fixed. To be doubly certain, I modified the build script to close this library before saving the executable, because I wasn't using any functions from it anyway.
The most aggravating problems I encountered were with the libmpg123 library. Some users reported "undefined alien function" errors whenever they tried to play a song. Others reported a scary error about stack alignment as soon as the problem started. To some extent I haven't solved these (in the sense that Mixalot users and people building from source may still get bitten by them) so much as hacked around them for the sake of the binary release. There were two basic problems:
- On 32-bit Linux, with newer versions of libmpg123 than my Debian-running laptop happens to have, the compile-time choice of large file support breaks binary compatibility with the libmpg123 library, wreaking havoc with the FFI bindings. Specifically, if large file support is enabled, a number of symbols change names, e.g., mpg123_open becomes mpg123_open_64. This is irritating and not how I'd have done it (for instance, I don't think the version number of the shared library changes to indicate the break in compatibility), but I could've easily worked around it in mpg123-ffi by detecting which version is present at the time the library is initialized. I very nearly did so, were it not for the following problem:
- On 32-bit Linux, due to the desire to have properly aligned data when using SSE instructions, recent versions of GCC provide support for aligning stack frames along larger boundaries, such as 16 bytes. The mpg123 developers seem to take this support as sufficient justification to ignore the platform ABI, introducing dubious stack alignment checks at every entry point to the library. This is not something I know how to work around from the CFFI binding in a reasonable fashion, so for the time being I've given up on adapting to such hostile versions of the library. Fortunately, I've absorbed enough trivia eavesdropping on the SBCL hackers on IRC to know that Darwin uses 16 byte alignment for precisely the same reason, so SBCL must support it, and after a few minutes searching I hacked the align-stack-pointer macro in SBCL's x86 backend to enable the 16 byte alignment on Linux as well, which appears to work around the problem (at the cost of my build environment getting even stranger). I also rebuilt the libmpg123 library with --disable-largefile and, just to be thorough, --disable-aligncheck, and set my CFLAGS to -mstackrealign, two measures which I think should've sufficed to solve the issue even without a hacked SBCL.
The 32-bit Linux/x86 binary now includes a rebuilt version of libmpg123, renamed libmixalot-mpg123, with these changes. The 64-bit binary doesn't have any of these problems, and should Just Work, but you have to provide your own libmpg123 as before. My mistake, of course, was using libmpg123, but I wasn't aware of libmad when I made that choice, and I'm not enthusiastic about rewriting otherwise perfectly working code on account of these issues (although I probably will, sooner or later). My current binaries, in conjunction with Shuffletron 0.0.3 (featuring various minor improvements), should be free of these problems, but still haven't been as widely tested as I'd like. The lesson to me, obvious in retrospect, is to test these things on a more diverse set of configurations than my own machines (particularly when they all run the same release of Debian), even when it seems so simple that nothing could go wrong.
- Music:Gorillaz, "Kids with Guns"
Here's a few things I've been working on lately which may be of broader interest:
Bordeaux-FFT is a small library for computing the FFT/IFFT on complex data, originally written by Robert Strandh (and/or Sylvain Marchand and Martin Raspaud), with contributions by Paul Khuong and myself. Last summer I did some audio processing experiments, originally using the FFT code from Sapaclisp. Robert helpfully volunteered his FFT implementation, which I cleaned up slightly and have been cheerfully employing in various audio hacks ever since. Several versions have changed hands through email, lisppaste, and my web server, so I've finally come around to collecting the changes, writing a brief manual, and tarring up a release. It's surprisingly fast, particularly with Paul Khuong's recent work on SBCL, although I don't know how it stacks up against some of the highly tuned assembly language implementations out there. I use it along with my fledgling task queuing code to grind out batches of FFTs across four CPU cores.
Shuffletron is a simple music player in CL, with a few interesting features. I've been running this program full time for several weeks now as my preferred music player. It snuck on to the lisp subreddit before I really announced it, and I'm sure folks on IRC are already sick of hearing about it, so I won't say much. I began with plans for a much more ambitious player, with a fancy graphical interface, and wrote the first version of this one Saturday realizing I needed something simple to put the audio code through its paces while I wrote the full player, intending to include this one as an example program with Mixalot. It worked better than expected, so I ended up fleshing out the feature set instead and decided that it was really all I needed. The code is lean and mean.
I've had a number of problems trying to produce redistributable binaries of this which I believe I've finally solved (although new binaries are forthcoming). I hope to write about these later.
Bordeaux-FFT is a small library for computing the FFT/IFFT on complex data, originally written by Robert Strandh (and/or Sylvain Marchand and Martin Raspaud), with contributions by Paul Khuong and myself. Last summer I did some audio processing experiments, originally using the FFT code from Sapaclisp. Robert helpfully volunteered his FFT implementation, which I cleaned up slightly and have been cheerfully employing in various audio hacks ever since. Several versions have changed hands through email, lisppaste, and my web server, so I've finally come around to collecting the changes, writing a brief manual, and tarring up a release. It's surprisingly fast, particularly with Paul Khuong's recent work on SBCL, although I don't know how it stacks up against some of the highly tuned assembly language implementations out there. I use it along with my fledgling task queuing code to grind out batches of FFTs across four CPU cores.
Shuffletron is a simple music player in CL, with a few interesting features. I've been running this program full time for several weeks now as my preferred music player. It snuck on to the lisp subreddit before I really announced it, and I'm sure folks on IRC are already sick of hearing about it, so I won't say much. I began with plans for a much more ambitious player, with a fancy graphical interface, and wrote the first version of this one Saturday realizing I needed something simple to put the audio code through its paces while I wrote the full player, intending to include this one as an example program with Mixalot. It worked better than expected, so I ended up fleshing out the feature set instead and decided that it was really all I needed. The code is lean and mean.
I've had a number of problems trying to produce redistributable binaries of this which I believe I've finally solved (although new binaries are forthcoming). I hope to write about these later.
Mixalot is the audio back-end of Shuffletron, factored into its own system(s) because it might be useful for other purposes. It includes a mixer which pulls audio from any number of streamer objects and outputs them to ALSA. It also includes FFI definitions for libmpg123 with some helpers for decoding MP3 files and reading ID3 tags, and a streamer class for decoding and playing MP3 files in real time. The libmpg123 portions are usable independently of the audio mixing/output code.
Lately I've done some programming in Factor, and one feature I've grown fond of is that integers are considered sequences, usable with map and other combinators. As an excuse to take the extensible sequences protocol for a spin, I implemented this in CL (or really SBCL, since I don't think any other implementations have implemented extensible sequences).
The extensible sequences protocol requires that sequences be subtypes of the SEQUENCE class. I didn't like this at first, wanting to implement sequences directly on integers, but soon decided that wrapping things up in a class wasn't so bad - I can just write (below n) instead of n, and it suggested that I go a little further and implement intervals as sequences. Using the constructors below and interval, I can write the following:
(map 'vector 'list #(a b c d e) (below 3)) => #((A 0) (B 1) (C 2))
(map 'list '1+ (interval 20 25)) => (21 22 23 24 25)
Only a few definitions are needed to make this work:
An odd bit above is the notion of uninitialized sequences (where length is known, but not the minimum) and the behavior of (setf elt). Intervals are considered immutable, but (setf elt) is permitted provided it would not change the sequence. It is also permitted when minimum is unset, in which case it completes initialization by setting minimum to (- newvalue index). Intended to support initialization of intervals by map, this allows a neat trick:
(map 'interval-sequence (lambda (x) (+ x 7)) (below 5)) => #<INTERVAL-SEQUENCE [7,12)>
I thought there was some chance that remove would just work in the case where the element is on an end of the interval. It doesn't. The reason is that generic remove is implementing by calling delete on a copy of the sequence. As there is no way to distinguish destructive operations on a full copy during initialization from any other time, it seems like any immutable sequence has a bit more work to do in implementing the (non-destructive) utility functions.
I've filed my implementation away here in case anyone is interested.
The extensible sequences protocol requires that sequences be subtypes of the SEQUENCE class. I didn't like this at first, wanting to implement sequences directly on integers, but soon decided that wrapping things up in a class wasn't so bad - I can just write (below n) instead of n, and it suggested that I go a little further and implement intervals as sequences. Using the constructors below and interval, I can write the following:
(map 'vector 'list #(a b c d e) (below 3)) => #((A 0) (B 1) (C 2))
(map 'list '1+ (interval 20 25)) => (21 22 23 24 25)
Only a few definitions are needed to make this work:
;;; Interval sequence class
(defclass interval-sequence (sequence standard-object)
((minimum :reader minimum :initform 0 :initarg :minimum)
(length :reader sequence:length :initarg :length)))
;;; Constructors
(defun below (n)
(unless (>= n 0)
(error 'type-error
:datum n
:expected-type '(integer 0)))
(make-instance 'interval-sequence :length n))
(defun interval (min max)
(unless (<= min max)
(error "Interval minimum must be less than or equal to maximum"))
(make-instance 'interval-sequence :minimum min :length (- max min)))
;;; Core sequence protocol
(defmethod sequence:elt ((interval interval-sequence) index)
(with-slots (minimum length) interval
(unless minimum
(error "Attempt to read from an uninitialized interval"))
(when (or (< index 0) (>= index length))
(error 'type-error
:datum index
:expected-type `(integer 0 ,(1- length))))
(+ index minimum)))
(defmethod (setf sequence:elt) (new-value
(interval interval-sequence)
index)
(with-slots (minimum length) interval
(cond
((or (< index 0) (>= index length))
(error 'type-error
:datum index
:expected-type `(integer 0 ,(1- length))))
((null minimum)
(setf minimum (- new-value index))
new-value)
((/= new-value (+ minimum index))
(error "Incompatible setf of interval element - expected ~A, got ~A"
(+ minimum index) new-value))
(t new-value))))
(defmethod sequence:adjust-sequence ((interval interval-sequence) length
&key initial-element initial-contents)
(declare (ignore interval length initial-element initial-contents))
(error "Interval sequences are immutable"))
(defmethod sequence:make-sequence-like
((interval interval-sequence) length
&key (initial-element nil iep) (initial-contents nil icp))
(declare (ignore initial-element initial-contents))
(when (or iep icp)
(error "Can't create intervals using initial-element/initial-contents."))
(make-instance 'interval-sequence :minimum nil :length length))
An odd bit above is the notion of uninitialized sequences (where length is known, but not the minimum) and the behavior of (setf elt). Intervals are considered immutable, but (setf elt) is permitted provided it would not change the sequence. It is also permitted when minimum is unset, in which case it completes initialization by setting minimum to (- newvalue index). Intended to support initialization of intervals by map, this allows a neat trick:
(map 'interval-sequence (lambda (x) (+ x 7)) (below 5)) => #<INTERVAL-SEQUENCE [7,12)>
I thought there was some chance that remove would just work in the case where the element is on an end of the interval. It doesn't. The reason is that generic remove is implementing by calling delete on a copy of the sequence. As there is no way to distinguish destructive operations on a full copy during initialization from any other time, it seems like any immutable sequence has a bit more work to do in implementing the (non-destructive) utility functions.
I've filed my implementation away here in case anyone is interested.
- Music:Milky, "The Emperor of Oranges"
CL-USER> (defun ~ (name) (merge-pathnames name (user-homedir-pathname))) ~ CL-USER> (~ "foo") #P"/home/hefner/foo" CL-USER> (~"cl/foo/myhack.lisp") #P"/home/hefner/cl/foo/myhack.lisp" CL-USER>
Not as nice as Zach Beane's approach, of course.
Ruby continues to close the gap with lisp - Dwemthy's Array combines the taste and sophistication of defclass* with the clarity and convenience of MOP hackery (and a touch of the exuberant insanity evident in Casting SPELs in Lisp). Spotted on Planet Smalltalk, where Nicholas Chen inexpicably plays along.
- Music:Letters To Cleo, "I'm A Fool"
I'm not a big fan of subpixel antialiased text, but it is technically neat and not difficult to implement, so for fun I started adding it to McCLIM's mcclim-truetype package. Since mcclim-truetype doesn't do hinting, the fonts are considerably more blurry, albeit less distorted, than what you get from libfreetype (and consequently mcclim-freetype). I thought subpixel AA might be of particular help due to this.
I hacked up a quick version which rendered the glyphs at 3x the normal horizontal resolution, filtered the resulting alpha mask to reduce color fringing, then combined triplets of pixels into a component alpha mask to use with Xrender. This didn't look bad - softer but more clearly defined.
Shortly thereafter I encountered this page suggesting that the subpixels of an LCD panel are not evenly spaced, but instead grouped together with a slight gap between the RGB triplets. If that's true, such a display must distort the image compared to my expectations, pinching together the triplets of subpixels. I tried to verify this on my Thinkpad's display - I think the grouping is visible, but my camera lens wasn't really up to it.

This suggests we do things slightly differently:

With that in mind, I hacked in a second mode which renders at 4x the original width, filters the result, and maps the first three of every four alpha pixels to an LCD subpixel (discarding the fourth). This should (I hope) provide less distortion in the mapping from the coordinate system of our glyphs to the physical display. This approach also looks pretty good, and it's sharper than the previous approach due to the filter width effectively shrinking by 3/4 on account of the higher resolution. I can't say either approach is clearly better.
Here are all three for comparison:


For whatever reason, the character spacing gets thrown a bit out of whack (in addition to our already not bothering to use the kerning tables). Figuring this out is next on the agenda.
I hacked up a quick version which rendered the glyphs at 3x the normal horizontal resolution, filtered the resulting alpha mask to reduce color fringing, then combined triplets of pixels into a component alpha mask to use with Xrender. This didn't look bad - softer but more clearly defined.
Shortly thereafter I encountered this page suggesting that the subpixels of an LCD panel are not evenly spaced, but instead grouped together with a slight gap between the RGB triplets. If that's true, such a display must distort the image compared to my expectations, pinching together the triplets of subpixels. I tried to verify this on my Thinkpad's display - I think the grouping is visible, but my camera lens wasn't really up to it.
This suggests we do things slightly differently:
With that in mind, I hacked in a second mode which renders at 4x the original width, filters the result, and maps the first three of every four alpha pixels to an LCD subpixel (discarding the fourth). This should (I hope) provide less distortion in the mapping from the coordinate system of our glyphs to the physical display. This approach also looks pretty good, and it's sharper than the previous approach due to the filter width effectively shrinking by 3/4 on account of the higher resolution. I can't say either approach is clearly better.
Here are all three for comparison:
- Music:Devo, "Time Out For Fun"
While grepping my way around cl-opengl to write some simple test code, I've stopped to reflect on the various CL OpenGL bindings over the years. There have been at least three, not including the GLX protocol implementation in telent CLX, each with slightly different interfaces.
Ages ago (2002), I used a set of OpenGL bindings for CMUCL, converted from Allegro, with a dubious non-commercial use license. A simple function to draw a white circle might look like the following:
..Although given the name prefixes, I could've imported the GL package with no worries.
Several years later, I played around with CL-SDL, which includes its own GL package. It named things a bit differently, making them slightly lispier without really deviating from the C API. Translated for these bindings, the snippet above should look something like this:
I've never used the GL support provided by CLX, but it looks like the above would work there too. I'm not sure if there was any conscious effort to model one after the other - which came first?
In 2008 we have cl-opengl. It provides a considerably lispier interface, handling the argument types itself, and using keywords in place of bitmasks (with compiler macros to optimize the helpfulness away).
Hopefully this is the last set of OpenGL bindings I'll have to learn. I'm not sure which style I prefer - cl-opengl is undeniably more pretty, while the old Allegro/CMUCL bindings have a nice 1:1 mapping with C code (you shouldn't ever have to grep around to verify what things are named), and the clx/cl-sdl style is somewhere in the middle.
A comparison of the half dozen or so Gtk bindings might be more interesting, since Gtk is considerably more intricate.
Incidentally, does anyone know the origin of the term "binding" for such a library interface?
Ages ago (2002), I used a set of OpenGL bindings for CMUCL, converted from Allegro, with a dubious non-commercial use license. A simple function to draw a white circle might look like the following:
(gl:glClearColor 0.3 0.0 0.0 0.3)
(gl:glClear gl:GL_COLOR_BUFFER_BIT)
(gl:glColor3f 1.0 1.0 1.0)
(gl:glBegin gl:GL_TRIANGLE_FAN)
(loop for theta from 0.0 by (/ pi 0.5 64)
repeat 64
do (gl:glVertex2f (float (+ -1.0 (* 2.0 x) (* radius (sin theta))) 0.0f0)
(float (+ 1.0 (* -2.0 y) (* radius (cos theta))) 0.0f0)))
(gl:glEnd)
..Although given the name prefixes, I could've imported the GL package with no worries.
Several years later, I played around with CL-SDL, which includes its own GL package. It named things a bit differently, making them slightly lispier without really deviating from the C API. Translated for these bindings, the snippet above should look something like this:
(gl:clear-color 0.3 0.0 0.0 0.3)
(gl:clear gl:+color-buffer-bit+)
(gl:color-3f 1.0 1.0 1.0)
(gl:begin gl:+triangle-fan+)
(loop for theta from 0.0 by (/ pi 0.5 64)
repeat 64
do (gl:vertex-2f (float (+ -1.0 (* 2.0 x) (* radius (sin theta))) 0.0f0)
(float (+ 1.0 (* -2.0 y) (* radius (cos theta))) 0.0f0)))
(gl:end)
I've never used the GL support provided by CLX, but it looks like the above would work there too. I'm not sure if there was any conscious effort to model one after the other - which came first?
In 2008 we have cl-opengl. It provides a considerably lispier interface, handling the argument types itself, and using keywords in place of bitmasks (with compiler macros to optimize the helpfulness away).
(gl:clear-color 0.3 0.0 0.0 0.3)
(gl:clear :color-buffer-bit)
(gl:color 1.0 1.0 1.0)
(gl:begin :triangle-fan)
(loop for theta from 0.0 by (/ pi 0.5 64)
repeat 64
do (gl:vertex (+ -1.0 (* 2.0 x) (* radius (sin theta)))
(+ 1.0 (* -2.0 y) (* radius (cos theta)))))
(gl:end)
Hopefully this is the last set of OpenGL bindings I'll have to learn. I'm not sure which style I prefer - cl-opengl is undeniably more pretty, while the old Allegro/CMUCL bindings have a nice 1:1 mapping with C code (you shouldn't ever have to grep around to verify what things are named), and the clx/cl-sdl style is somewhere in the middle.
A comparison of the half dozen or so Gtk bindings might be more interesting, since Gtk is considerably more intricate.
Incidentally, does anyone know the origin of the term "binding" for such a library interface?
- Music:The Clash
Found this lying around..
(defun file (filename)
(with-open-file (in filename)
(with-standard-io-syntax ()
(let ((*read-eval* nil))
(read in)))))
(defsetf file (filename) (object)
`(with-open-file (out ,filename
:direction :output
:if-exists :supersede
:if-does-not-exist :create)
(with-standard-io-syntax ()
(pprint ,object out))))
If I put this in my init file, what are the odds I'll use it more than once?
