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.
This evening's hack was to write a FUSE filesystem in my NES emulator. I've made it export a virtual filesystem that gives you files for the various RAM and ROM areas of the machine, and you can read and write to them. This could be useful for debugging my homebrew stuff. You can also point a hex editor at the 6502's RAM and edit bytes to cheat, dd /dev/urandom into video ram to glitch the display, etc. Surely peering inside applications through the filesystem is an extension of the Unix way. Here's what you get:
I suppose I could fix the other fields in the stat structure. This is the first time I've done an ls -l here to notice. The FUSE examples I started from didn't bother. :)
This will appear in the next version of my NES emulator, although I can't say when that will be. Until I feel like spending an unpleasant hour or several learning to do merging with Git, probably.
hefner@lightworks:~$ ls -l /tmp/nesfs total 0 -rw-rw-rw- 1 root root 8192 Dec 31 1969 chr-rom -rw-rw-rw- 1 root root 256 Dec 31 1969 oam -rw-rw-rw- 1 root root 32768 Dec 31 1969 prg-rom -rw-rw-rw- 1 root root 2048 Dec 31 1969 ram -r--r--r-- 1 root root 22 Dec 31 1969 rom-filename -r--r--r-- 1 root root 15 Dec 31 1969 rom-hash -rw-rw-rw- 1 root root 8192 Dec 31 1969 sram -rw-rw-rw- 1 root root 16384 Dec 31 1969 vram
I suppose I could fix the other fields in the stat structure. This is the first time I've done an ls -l here to notice. The FUSE examples I started from didn't bother. :)
This will appear in the next version of my NES emulator, although I can't say when that will be. Until I feel like spending an unpleasant hour or several learning to do merging with Git, probably.
I had a silly idea tonight that for a game like Super Mario Bros. where the scrolling follows the player, and the player is usually in the center of the screen, collecting a single column of the screen per frame and combining them horizontally would produce a sort of timelapse image where the player would be seen as a blurred stripe moving through the scenery, which would be stretched or squashed according to the player's speed. I think I've seen something like this before, but in this era of information overload and the futility of trying to find anything in Google, I figured I'd just go ahead and hack it into my emulator rather than searching for prior art. Here's an example from Super Mario 3:

It's a bit rough (and that's one of the better portions), but you can see the path of Mario hopping from point to point. I tried this with several games: Super Mario Bros. 1, Super Mario Bros. 3, Duck Tales, and Life Force. In the latter case the game scrolls at a fixed rate, so you get a sort of shabby automap.

It's a bit rough (and that's one of the better portions), but you can see the path of Mario hopping from point to point. I tried this with several games: Super Mario Bros. 1, Super Mario Bros. 3, Duck Tales, and Life Force. In the latter case the game scrolls at a fixed rate, so you get a sort of shabby automap.
- Music:Matti Raekallio, Prokofiev Piano Sonata No. 1
In my ongoing adventure tinkering with the NES, one thing I had to try was playing some music through the built-in DAC. It's 7-bit, and you can get reasonable audio quality if you don't mind devoting the whole CPU (and quite a lot of memory) to it. I threw together a little demo that plays an 8 second music loop at around 30 KHz. Once the novelty of hearing it work wore off, I noticed the audio was distorted, particularly audible in the cymbols. Once I confirmed it wasn't just on my own emulator that it sounded distorted, I thought back to implementing my own NES sound emulation, primarily using apu_ref.txt as a reference. Toward the end of that document is an equation which models how the sound channels are mixed together, which is obviously not linear. Curious, I made a plot of DAC input versus mixer output (actually, I wrote a 6502 program which writes a ramp waveform to the DAC and captured the output). It's *extremely* bowed in the middle (see below), explaining the distortion. It was straightforward invert the curve and preprocess my audio accordingly, which improved the audio considerably.
I get the impression many emulators follow a curve similar to the one described in that document. I tried my test on Nestopia, FCEU, and (of course) my own emulator, and they behave similarly in this respect. On the other hand, Nintendulator seems to mix channels differently, because my original version of the audio test sounds better there. Unfortunately, I haven't tried this on a real NES yet, because it's bigger (256KB) than I can conveniently program to an EPROM right now, and I've have to build a new EPROM cart to host it even so (my current one only handles 64 KB). I should probably just buy a PowerPak and/or a CopyNES, but I'm still enjoying desoldering donor carts and playing with chips. =p
If I couldn't try the full music loop on a real NES, at least I could write some simpler test programs and run them from my EPROM cart. It also occured to me that aside from the nonlinearity due to the channel mixing, there might be some additional nonlinearity inherent in the DAC, significant enough for someone trying to get the best audio they could from the machine, and it'd be interesting to try and measure. For my first attempts at this, I took the approach of generating test signals in software from the NES, recording into my MOTU audio interface from the NES audio output, analyzing the resulting recordings with a little CL code, and finally plotting the results using Octave (shown below).
I can imagine various sources of systematic error that invalidate these measurements, but (ignoring the screwy "Pulse 2" measurements) there's a really interesting feature apparent. - namely, the jumps occuring around power of two transitions, most prominent in the three highest bits of the DAC input.
I'd really hoped these measurements would agree, so that I could divide out the affect of the mixer equation and have something like a definitive measurement of the DAC linearity which I could build into my emulator (and use to correct audio for playback on the real hardware). As it is, I'll have to try again. It would probably make a lot more sense to measure from the output pin on the NES CPU, rather than measuring after it has passed through the final mixing and filtering circuits, but I haven't tried this yet. Ideally I could program a DC level into the DAC and measure it on the output pin at my leisure. To this end I put together a little DAC test program which lets you select the output level and toggle the signal on and off. This program, along with various other hacks including the signal generators for the three tests above, is on my NES test cart image.
I get the impression many emulators follow a curve similar to the one described in that document. I tried my test on Nestopia, FCEU, and (of course) my own emulator, and they behave similarly in this respect. On the other hand, Nintendulator seems to mix channels differently, because my original version of the audio test sounds better there. Unfortunately, I haven't tried this on a real NES yet, because it's bigger (256KB) than I can conveniently program to an EPROM right now, and I've have to build a new EPROM cart to host it even so (my current one only handles 64 KB). I should probably just buy a PowerPak and/or a CopyNES, but I'm still enjoying desoldering donor carts and playing with chips. =p
If I couldn't try the full music loop on a real NES, at least I could write some simpler test programs and run them from my EPROM cart. It also occured to me that aside from the nonlinearity due to the channel mixing, there might be some additional nonlinearity inherent in the DAC, significant enough for someone trying to get the best audio they could from the machine, and it'd be interesting to try and measure. For my first attempts at this, I took the approach of generating test signals in software from the NES, recording into my MOTU audio interface from the NES audio output, analyzing the resulting recordings with a little CL code, and finally plotting the results using Octave (shown below).
- "Square rising edge" - a square wave at a few hundred Hz (220? 440? I forget.), increasing in amplitude each cycle from 0 to 127. I measured the height of the rising edge. I let this repeat 29 times and averaged the results. I screwed the program up and only captured every other amplitude level (incrementing the amplitude variable on every clock edge instead of just one).
- "Pulse 1" - Same idea, ramping up the amplitude of a brief pulse. I measured the height of the largest rising (or rather falling) edge in the viscinity of the pulse. I let this loop for 20 or 30 minutes, averaging out 1,440 samples per amplitude level. The individual ramps didn't look right, having a curious moire-like modulation as the energy of the pulse fell differently into samples, but it averaged out into a very nice curve. Unfortunately, it was different enough from the previous curve to bother me, although it shared some common features.
- "Pulse 2" - I thought I'd try lengthening the pulse, hoping I might get cleaner data. Instead I got the opposite - the resulting curve, even average over 1,300 samples per amplitude level, is extremely jagged and irregular. I haven't figured out what went wrong here
I'd really hoped these measurements would agree, so that I could divide out the affect of the mixer equation and have something like a definitive measurement of the DAC linearity which I could build into my emulator (and use to correct audio for playback on the real hardware). As it is, I'll have to try again. It would probably make a lot more sense to measure from the output pin on the NES CPU, rather than measuring after it has passed through the final mixing and filtering circuits, but I haven't tried this yet. Ideally I could program a DC level into the DAC and measure it on the output pin at my leisure. To this end I put together a little DAC test program which lets you select the output level and toggle the signal on and off. This program, along with various other hacks including the signal generators for the three tests above, is on my NES test cart image.
Funny me forgetting that Debian doesn't package xmms anymore. This is a shame, as I'm not aware of a superior alternative. As recently as a year or two ago, I was using packaged xmms and plugins, and everything was wonderful - there were plugins for all the oddball stuff, modules and half a dozen chiptune formats, and everything worked swimmingly. Lately, I'm stuck using half a dozen different players from the command line, usually through aoss, and some of them (such as adplay) stutter and spit unless the machine is otherwise completely idle (just clicking around in firefox is enough to glitch the audio, four cores or no).
Audacious - No, this one is a step backward. The file dialog (which I suppose is just the Gtk2 file dialog, tarted up with their obnoxious theme) is noticeably slower than the one you get in xmms (the old Gtk 1.2 file selector, which responds practically instantaneously under any reasonable circumstance), and the loss of the "Add selected files" button destroys the workflow - I'm not going to make ten round trips in and out of that dialog just to pick a handful of files in different directories. This program would be much more useful to me if this feature were restored.
xmms2 - Imagine my dismay when installing xmms2 didn't yield any UI except a command-line interface, and expected me to run a separate server process. A client/server music player? Thanks, but no thanks. Enough with the servers. Trying to be a good sport, I apt-got a graphical client, gxmms2, and attempted to play a song. Oops, "xmms2d" isn't running - why can't it start the goddamn thing itself? The UI is a bit clumsy, but I poked around and added an mp3 to the playlist, or so I thought. Upon hitting play, it instead played "/usr/share/xmms2/mind.in.a.box-lament_s nippet.ogg" very loudly, a noise so horrible and unexpected that I slammed the "kill window" shortcut as fast as I could and hastened to torch the whole mess. This is probably a great system for people who enjoy configuring sendmail.
iTunes style players - These don't really compete - the style of use is different. I often run Quod Libet and xmms at the same time, but most music is played through xmms, for at least two reasons - first, iTunes-alikes have large windows that deserve a whole desktop to themselves, whereas xmms is tiny and fits on whichever desktop I'm working without cluttering it, such that I use xmms just because it's closer. Second, having organized my music into a reasonable tree on the disk, I can find whatever I want just as quickly as you might using a fancy overengineered browser based on id3 tags, and without the headaches of bad or missing tags, multiple spellings of artists names (plus the mess of various artist + collaborator combinations), etc. Indeed, even in Quod Libet, I usually use the "Filesystem Browser" mode.
Although think Quod Libet is the most usable of the iTunes-style players, it's been a couple years since I last surveyed them and settled on it, and there are some very irritating things about the UI - that the volume and seek bars are hidden inside of little popup menus, or the height of the "queue" not being resizable (such that if you want to rearrange songs in the queue, you can only move them a few spaces at a time between scrolling, like some kind of goddamn bubble sort).
In fact, the whole reason I reached for xmms is because I'd been using Quod Libet on this machine to sort through some new music, but this particular instance of it frequently misbehaves such that I'd just prefer something simpler.
Search seems like a promising way to find files to play, but I haven't used a player that embraces this concept. I used the search in iTunes on occasion, but it was unnecessarily sluggish. Quod has a search feature too, but it's hidden in another tab with no obvious keyboard short cut, and is outrageously slow (many seconds to conduct a search). I never understood why this sort of thing should be anything less than instantaneous, even over many tens of thousands of files, so one day a couple years ago I quickly hacked together something in Lisp that used a Boyer-Moore search across the filenames and showed the matches interactively as you typed with a simple mcclim gui, and it didn't take more than a few hours of effort to get this fast enough to feel instantaneous, even running synchronously inside the text field's "value changed" event handler. So all the really fun stuff I imagined implementing, like doing the searching in a background thread, and pipelining the search to refine the results of previous searches as you continued to type (rather than searching the whole data set on every keystroke, as it currently does), turned out to be completely unnecessary! So you'd type, and as you did the matches would appear in a list below the search line, and you could click one to play it in xmms. Very simple. I used this on and off for a few weeks, and had some ambitions of turning it into a genuinely useful music player, but never got around to it due to short attention span and various mcclim issues which I am unable or unwilling to fix, such as the focus insanity and difficulty in establishling workable keyboard controls. I think I'll just wait until I have a better substrate for the UI. A fuller implementation would have to do several times as much work due to searching metadata in addition to filenames, but several times a small number might still be a fairly small number, so no problem. Anyway, with Lisp's reputation for being slow (or within the Lisp community, mcclim's reputation for being slow ;), maybe the authors of the more ambitious music players can be shamed into improving their search and making it fast.
And now I'm off to compile xmms and see how many of the plugins I can 1) locate and 2) succeed in compiling.
Audacious - No, this one is a step backward. The file dialog (which I suppose is just the Gtk2 file dialog, tarted up with their obnoxious theme) is noticeably slower than the one you get in xmms (the old Gtk 1.2 file selector, which responds practically instantaneously under any reasonable circumstance), and the loss of the "Add selected files" button destroys the workflow - I'm not going to make ten round trips in and out of that dialog just to pick a handful of files in different directories. This program would be much more useful to me if this feature were restored.
xmms2 - Imagine my dismay when installing xmms2 didn't yield any UI except a command-line interface, and expected me to run a separate server process. A client/server music player? Thanks, but no thanks. Enough with the servers. Trying to be a good sport, I apt-got a graphical client, gxmms2, and attempted to play a song. Oops, "xmms2d" isn't running - why can't it start the goddamn thing itself? The UI is a bit clumsy, but I poked around and added an mp3 to the playlist, or so I thought. Upon hitting play, it instead played "/usr/share/xmms2/mind.in.a.box-lament_s
iTunes style players - These don't really compete - the style of use is different. I often run Quod Libet and xmms at the same time, but most music is played through xmms, for at least two reasons - first, iTunes-alikes have large windows that deserve a whole desktop to themselves, whereas xmms is tiny and fits on whichever desktop I'm working without cluttering it, such that I use xmms just because it's closer. Second, having organized my music into a reasonable tree on the disk, I can find whatever I want just as quickly as you might using a fancy overengineered browser based on id3 tags, and without the headaches of bad or missing tags, multiple spellings of artists names (plus the mess of various artist + collaborator combinations), etc. Indeed, even in Quod Libet, I usually use the "Filesystem Browser" mode.
Although think Quod Libet is the most usable of the iTunes-style players, it's been a couple years since I last surveyed them and settled on it, and there are some very irritating things about the UI - that the volume and seek bars are hidden inside of little popup menus, or the height of the "queue" not being resizable (such that if you want to rearrange songs in the queue, you can only move them a few spaces at a time between scrolling, like some kind of goddamn bubble sort).
In fact, the whole reason I reached for xmms is because I'd been using Quod Libet on this machine to sort through some new music, but this particular instance of it frequently misbehaves such that I'd just prefer something simpler.
Search seems like a promising way to find files to play, but I haven't used a player that embraces this concept. I used the search in iTunes on occasion, but it was unnecessarily sluggish. Quod has a search feature too, but it's hidden in another tab with no obvious keyboard short cut, and is outrageously slow (many seconds to conduct a search). I never understood why this sort of thing should be anything less than instantaneous, even over many tens of thousands of files, so one day a couple years ago I quickly hacked together something in Lisp that used a Boyer-Moore search across the filenames and showed the matches interactively as you typed with a simple mcclim gui, and it didn't take more than a few hours of effort to get this fast enough to feel instantaneous, even running synchronously inside the text field's "value changed" event handler. So all the really fun stuff I imagined implementing, like doing the searching in a background thread, and pipelining the search to refine the results of previous searches as you continued to type (rather than searching the whole data set on every keystroke, as it currently does), turned out to be completely unnecessary! So you'd type, and as you did the matches would appear in a list below the search line, and you could click one to play it in xmms. Very simple. I used this on and off for a few weeks, and had some ambitions of turning it into a genuinely useful music player, but never got around to it due to short attention span and various mcclim issues which I am unable or unwilling to fix, such as the focus insanity and difficulty in establishling workable keyboard controls. I think I'll just wait until I have a better substrate for the UI. A fuller implementation would have to do several times as much work due to searching metadata in addition to filenames, but several times a small number might still be a fairly small number, so no problem. Anyway, with Lisp's reputation for being slow (or within the Lisp community, mcclim's reputation for being slow ;), maybe the authors of the more ambitious music players can be shamed into improving their search and making it fast.
And now I'm off to compile xmms and see how many of the plugins I can 1) locate and 2) succeed in compiling.
- Music:Tito Puente And His Latin Ensemble, "Giant Steps"
For fun, I decided to play with MCKC tonight. Luckily, NESASM (part of MagicKit) is already available for Linux, and MCKC 0.25 comes with C source code which compiles with no difficulty, saving me from the chore of running the software within Windows. Changing #define LANGUAGE from 0 to 1 in mckc.h and recompiling, I began picking apart the examples in the tutorial by Nullsleep, noted previously. Quickly tripping over and fixing a tiny bug (patch below, submitted to author), everything works as expected.
(in file.c, mckc 0.25)
In order to simplify my workflow, I put the sequence of commands to compile/assemble/play the mckc song into a shell script, go.sh:
I wanted to trigger this from emacs by a single key press, so I defined the following function which saves the MML buffer and runs the compile/play script. I seldom use elisp and had to dig around in apropos the find the functions I needed, but this seems to do the trick:
Binding that to F12, I can edit and hear the results with a single keystroke (versus the six and a half keystrokes it would take to save the file, switch to a terminal, recall/repeat the compile and play command, and switch back, but whatever, this way is more fun). Neat.
(in file.c, mckc 0.25)
113c113 < ptr = malloc( size ); --- > ptr = malloc( size + 1);
In order to simplify my workflow, I put the sequence of commands to compile/assemble/play the mckc song into a shell script, go.sh:
#!/bin/sh rm -f make_nsf.nes rm -f effect.h rm -f songdata.h ./mckc songdata.mml >/tmp/mckc-out # useless return code if [[ -f songdata.h ]] then ./nesasm -raw make_nsf.txt >>/tmp/mckc-out fi # neither mckc nor nesmasm appear to indicate failure # in their exit status. If we give xmms the name of a # nonexistant file, it will pop open its file dialog, # which is not helpful. To avoid this, check that the # output file was created, playing it if so, or show # the error output if not. if [[ -a make_nsf.nes ]] then xmms make_nsf.nes else play /usr/share/sounds/gnobots2/splat.wav vol 0.3 >/dev/null 2>&1 & xmessage -file /tmp/mckc-out fi
I wanted to trigger this from emacs by a single key press, so I defined the following function which saves the MML buffer and runs the compile/play script. I seldom use elisp and had to dig around in apropos the find the functions I needed, but this seems to do the trick:
(defun play-mck-songdata ()
(interactive)
(save-some-buffers
(list (find-buffer-visiting
"/home/hefner/nerdly/mck/songdata.mml")))
(call-process-shell-command
"cd /home/hefner/nerdly/mck/ && /home/hefner/nerdly/mck/go.sh"))
Binding that to F12, I can edit and hear the results with a single keystroke (versus the six and a half keystrokes it would take to save the file, switch to a terminal, recall/repeat the compile and play command, and switch back, but whatever, this way is more fun). Neat.
- Music:Ruxpin, "Ljufa Lif"

