<?xml version="1.0" encoding="utf-8"?>
<!-- If you are running a bot please visit this policy page outlining rules you must respect. http://www.livejournal.com/bots/ -->
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:lj="http://www.livejournal.com">
  <id>urn:lj:livejournal.com:atom1:ahefner</id>
  <title>Informal Methods</title>
  <subtitle>ahefner</subtitle>
  <author>
    <name>ahefner</name>
  </author>
  <link rel="alternate" type="text/html" href="http://ahefner.livejournal.com/"/>
  <link rel="self" type="text/xml" href="http://ahefner.livejournal.com/data/atom"/>
  <updated>2012-02-07T15:14:14Z</updated>
  <lj:journal userid="14248520" username="ahefner" type="personal"/>
  <link rel="service.feed" type="application/x.atom+xml" href="http://ahefner.livejournal.com/data/atom" title="Informal Methods"/>
  <entry>
    <id>urn:lj:livejournal.com:atom1:ahefner:20528</id>
    <link rel="alternate" type="text/html" href="http://ahefner.livejournal.com/20528.html"/>
    <link rel="self" type="text/xml" href="http://ahefner.livejournal.com/data/atom/?itemid=20528"/>
    <title>Fun with Lisp: Programming the NES</title>
    <published>2012-02-06T19:52:24Z</published>
    <updated>2012-02-07T15:14:14Z</updated>
    <category term="lisp"/>
    <category term="hacks"/>
    <category term="programming"/>
    <category term="8-bit"/>
    <category term="music"/>
    <content type="html">&lt;p&gt;"Low-level programming is good for the programmer's soul." -John Carmack&lt;/p&gt;

&lt;p&gt;When the complexity of modern computing gets fatiguing, I look back to
the simpler machines of my childhood. I grew up surrounded by various
8-bit and 16-bit machines (most of them already a few years outdated
at the time), but my favorite of the bunch is the &lt;a href="http://en.wikipedia.org/wiki/Nintendo_Entertainment_System" rel="nofollow"&gt;Nintendo
Entertainment System&lt;/a&gt;. It's a small machine, even by '80s
standards:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;6502 CPU at 1.79 MHz&lt;/li&gt;
&lt;li&gt;2 Kilobytes of RAM for the CPU&lt;/li&gt;
&lt;li&gt;2 Kilobytes of RAM for the PPU (video)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tiny RAM was augmented by relatively massive amounts of ROM (and
sometimes additional RAM) in each cartridge. Typical software ranged
in size from 40KB (Super Mario Bros.) to 384 KB (Super Mario Bros. 3),
with a few outliers on each end.&lt;/p&gt;

&lt;p&gt;When the mood strikes, I'll variously elect to work on my emulator or
tinker with EPROM carts and code. The siren call of 6502 assembly
language beckoned, so I dusted off the assembler I'd written in Lisp a
few years prior. After a little time spent polishing the code, I wanted to
write something cool to show it off; so far, I'd mostly written fairly
boring experiments and tests such as the following:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://vintage-digital.com/hefner/misc/nes/nes-lisp-alien.jpg" alt="boring!"&gt;&lt;/p&gt;

&lt;p&gt;I can do better than that.&lt;/p&gt;

&lt;p&gt;The 6502 is a great processor to write an assembler for, with a
compact and regularly-encoded instruction set. Simple hardware and no
external constraints (as might be imposed by operating systems,
library code, compilers, coworkers, etc.) make an ideal playground to
&lt;a href="http://www.youtube.com/watch?v=7fbHOAbOcNI" rel="nofollow"&gt;do your own thing&lt;/a&gt;. My
assembler is minimalistic, but not minimal: 570 lines at the core,
split evenly between infrastructure and definitions of the 6502
architecture. It's embedded in CL, rather than operating as a
standalone language processor, so typical assembly source code is
really a series of lisp function calls, each emitting an
instruction. I'll say a little more about the design.&lt;/p&gt;

&lt;p&gt;The job of an assembler is simple enough: to translate a description
of data and machine instructions to an output file (an executable,
object file, or raw binary data) which can be loaded in memory on the
target machine. Machine code is just another kind of data, for which
mnemonic assembly language is syntactic sugar, and so knowledge of a
particular instruction set can be considered a layer of drudgery built
on top of a very simple foundation, with three essential tasks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Accumulate an output vector.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remember the current assembly position, in terms of the target's address space.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Maintain a mapping of symbolic names to locations so that
self-referential structures can be assembled, including forward
references.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My assembler bundles these responsibilities into an object I'll call
the assembly context, implementing the following protocol:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defgeneric context-emit (context vector)
  (:documentation "Emit a vector of bytes into the assembly context"))

(defgeneric context-address (context)
  (:documentation "Returns current virtual address of the context"))

(defgeneric (setf context-address) (address context)
  (:documentation "Set the current virtual address of the context"))

(defgeneric context-find-label (context symbol)
  (:documentation "Returns the address of a label, or nil."))

(defgeneric context-set-label (context symbol &amp;amp;optional address)
  (:documentation "Set the address of a label. If not supplied, the current address is used."))

(defgeneric context-emit-instruction (context vector)
  (:documentation "Emit an instruction into the assembly context. This
  is a hint, for contexts which want to handle instructions
  specially (e.g. cycle counting).")
  (:method (context vector) (context-emit context vector)))

(defgeneric link (context)
  (:documentation "Prepare and return final, assembled output."))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Handling forward references is the only tricky bit. Assemblers take
various approaches to this. Using delayed evaluation (in the fashion
of &lt;code&gt;force&lt;/code&gt; / &lt;code&gt;delay&lt;/code&gt;) seemed the simplest way to me - if an expression
(such as a call or branch target) involves a label that is not yet
defined, a &lt;code&gt;promise&lt;/code&gt; object is emitted into the output vector. When
&lt;code&gt;LINK&lt;/code&gt; is called on the context at the end of assembly, promises are
forced to evaluate. If they still can't be resolved, the problems are
collected and presented as an error.&lt;/p&gt;

&lt;p&gt;For brevity, the context is dynamically bound to the variable
&lt;code&gt;*context*&lt;/code&gt;. Instruction emitters use this implicitly, as do a number
of functions which provide a friendlier user interface to the
assembler:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;;;;; User interface:

(defvar *context* nil "Current assembly context")
(define-symbol-macro *origin* (context-address *context*))

(defun emit (bytes) (context-emit *context* bytes))

(defun db (&amp;amp;rest bytes)
  (dolist (byte bytes) (context-emit *context* (encode-byte byte))))

(defun dw (&amp;amp;rest words)
  (dolist (word words) (context-emit *context* (encode-word word))))

(defun advance-to (offset &amp;amp;optional (fill-byte #xFF))
  (let ((delta (- offset (context-address *context*))))
    (when (&amp;lt; offset 0)
      (error "Cannot advance to ~X, it is less than the current assembly address (~X)"
             offset (context-address *context*)))
    (context-emit *context* (make-array delta :initial-element fill-byte))))

(defun align (alignment &amp;amp;optional (fill-byte #xFF))
  (advance-to (* alignment (ceiling (context-address *context*) alignment)) fill-byte))

(defun label (name &amp;amp;key (offset 0) (context *context*))
  (assert (not (null context)))
  (delay name (offset)
    (+ offset
       (or (context-find-label context name)
           (error 'resolvable-condition
                  :path (format nil "Label ~A is undefined" name))))))

(defun set-label (name &amp;amp;optional (context *context*))
  (context-set-label context name)
  name)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You could define the simplest instruction emitters as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defun nop () (db #xEA))
(defun rti () (db #x40))
(defun rts () (db #x60))
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This leaves open the question of how to handle the more complicated
instructions which take an operand and support multiple addressing
modes. One possibility would be to indicate the addressing mode in the
function name, yielding &lt;code&gt;lda.imm&lt;/code&gt;, &lt;code&gt;lda.zp&lt;/code&gt;, &lt;code&gt;lda.mem&lt;/code&gt;, etc. I opted
for a different approach, where each addressing mode corresponds to a
class, and the instruction encoder can select the opcode according to
operand type. Worst case, you could define a generic function per
instruction mnemonic, with a method for each addressing mode. This
would be easy enough, but there's a better way.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.llx.com/~nparker/a2/opcodes.html" rel="nofollow"&gt;The 6502/65C02/65C816 Instruction Set Decoded&lt;/a&gt; describes how
the 6502 instruction set can be partitioned into three groups. Within
each group, addressing modes are expressed consistently by certain
patterns of bits within the opcode. With a handful of supporting
definitions, the assembler can exploit this knowledge to minimize the
manual labor required. For instance, my assembler defines the first
group of instructions as follows, with an extra &lt;code&gt;defmethod&lt;/code&gt; to handle
the lone exception to the pattern:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;;;; Group 1:
;;;        ORA     AND     EOR     ADC     STA     LDA     CMP     SBC
;;; (zp,X)  01      21      41      61      81      A1      C1      E1
;;; zp      05      25      45      65      85      A5      C5      E5
;;; #       09      29      49      69              A9      C9      E9
;;; abs     0D      2D      4D      6D      8D      AD      CD      ED
;;; (zp),Y  11      31      51      71      91      B1      D1      F1
;;; zp,X    15      35      55      75      95      B5      D5      F5
;;; abs,Y   19      39      59      79      99      B9      D9      F9
;;; abs,X   1D      3D      5D      7D      9D      BD      DD      FD

(defun group-1-addr-code (x)
  (typecase x
    (idxi #b000)  ;   (zero page,X)
    (zp   #b001)  ;   zero page
    (imm  #b010)  ;   #immediate
    (mem  #b011)  ;   absolute
    (indi #b100)  ;   (zero page),Y
    (zpx  #b101)  ;   zero page,X
    (aby  #b110)  ;   absolute,Y
    (abx  #b111)  ;   absolute,X
    (t (invalid-operand-error nil x))))

(defun group-1-asm (parameter opcode)
  (join-masks
   (join-masks (ash opcode 5)
               (ash (group-1-addr-code parameter) 2))
   #b01))

(def6502 ORA  group-1-asm #b000)
(def6502 ANDA group-1-asm #b001)
(def6502 EOR  group-1-asm #b010)
(def6502 ADC  group-1-asm #b011)
(def6502 STA  group-1-asm #b100)
(def6502 LDA  group-1-asm #b101)
(def6502 CMP  group-1-asm #b110)
(def6502 SBC  group-1-asm #b111)

(defmethod choose-opcode ((instruction (eql 'sta)) (operand imm))
  ;; One exception: STA with immediate destination makes no sense.
  (invalid-operand-error instruction operand))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With an assembler in Lisp, it's easy to define higher level control
structures. Here I define a conditional &lt;code&gt;ASIF&lt;/code&gt; and a simple looping
macro, &lt;code&gt;AS/UNTIL&lt;/code&gt; (the &lt;code&gt;AS&lt;/code&gt; prefix is chosen to distinguish them from
Lisp control structures, just as the &lt;code&gt;AND&lt;/code&gt; and &lt;code&gt;OR&lt;/code&gt; instructions are
renamed to &lt;code&gt;ANDA&lt;/code&gt; and &lt;code&gt;ORA&lt;/code&gt; above to avoid collision with the CL
operators of the same name):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defmethod condition-to-branch ((condition symbol))
  (or
   (cdr
    (assoc condition
           '((:positive    . bmi)
             (:negative    . bpl)
             (:carry       . bcc)
             (:no-carry    . bcs)
             (:zero        . bne)
             (:not-zero    . beq)
             (:equal       . bne)
             (:not-equal   . beq)
             (:overflow    . bvc)
             (:no-overflow . bvs))))
   (error "Unknown condition ~A" condition)))

(defun assemble-if (branch-compiler then-compiler &amp;amp;optional else-compiler)
  (let ((else-sym    (gensym "ELSE"))
        (finally-sym (gensym "FINALLY")))
    (funcall branch-compiler (rel else-sym))
    (funcall then-compiler)
    (when else-compiler (jmp (mem (label finally-sym))))
    (set-label else-sym)
    (when else-compiler (funcall else-compiler))
    (set-label finally-sym)))

(defmacro asif (condition &amp;amp;body statements)
  (let ((then statements)
        (else nil)
        (part (position :else statements)))
    (when part
      (setf then (subseq statements 0 part)
            else (subseq statements (1+ part) nil)))
    `(assemble-if
      ',(condition-to-branch condition)
      (lambda () ,@then)
      ,(and else `(lambda () ,@else)))))

(defmacro as/until (condition &amp;amp;body body)
  (let ((sym (gensym)))
    `(with-label ,sym
       ,@body
       (funcall (condition-to-branch ',condition) (rel ',sym)))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Another way to extend the assembler is by defining new types of
contexts. One obvious thing you'd want is a &lt;code&gt;local-context&lt;/code&gt; with its
own symbol table, for defining nested scopes. Using this, you can
define a cute &lt;code&gt;procedure&lt;/code&gt; macro, defining its name in the
surrounding context but enclosing the body in a local context:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defmacro procedure (name &amp;amp;body body)
  `(progn
     (set-label ',name)
     (let ((*context* (make-instance 'local-context :parent *context*)))
       ,@body)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A cooler trick is to define a &lt;code&gt;cycle-counting-context&lt;/code&gt;: by
specializing a method on &lt;code&gt;context-emit-instruction&lt;/code&gt;, we can peek at
each assembled instruction and tally up the number of cycles used in a
block of straight-line code:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defclass cycle-counting-context (delegate-code-vector
                                  delegate-symbol-lookup)
  ((cycle-count :initform 0 :accessor cycle-count :initarg :cycle-count)
   (precise-p   :initform t :accessor precise-p   :initarg :precise-p)))

(defmethod context-note-cycles ((context cycle-counting-context) num-cycles)
  (incf (cycle-count context) num-cycles))

(defmethod context-emit-instruction ((context cycle-counting-context) vector)
  (multiple-value-bind (cycles variable) (opcode-cycles (aref vector 0))
    (when variable (setf (precise-p context) nil))
    (if cycles
        (context-note-cycles context cycles)
        (warn "Don't know number of cycles for opcode ~X" (aref vector 0)))
    (call-next-method)))

(defmacro counting-cycles (&amp;amp;body body)
  `(let ((*context* (make-instance 'cycle-counting-context :parent *context*)))
     ,@body
     (cycle-count *context*)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Coupled with a utility function &lt;code&gt;emit-delay&lt;/code&gt;, this enables a macro
called &lt;code&gt;timed-section&lt;/code&gt; which can time a block of code and pad it out
to consume a specific number of cycles, for precise cycle-timed
loops. Here's a simple example from my test cart, using
&lt;code&gt;timed-section&lt;/code&gt; to produce a sawtooth wave through the 7-bit DAC,
timing the loop by dividing the clock rate of the system by the target
frequency (220 Hz) and the number of steps in the waveform (128):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(subprogram (sawtooth-220 "Sawtooth 220")
  (poke 0 +ppu-cr1+)                ; Disable NMI
  (poke 0 +ppu-cr2+)                ; Disable display
  (poke 0 +papu-control+)           ; Silence audio
  (ldy (imm 0))
  (timed-section ((round (/ +ntsc-clock-rate+ 220 128)) :loop t)
    (sty (mem +dmc-dac+))
    (iny)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I'll confess that &lt;code&gt;emit-delay&lt;/code&gt; and/or &lt;code&gt;counting-cycles&lt;/code&gt; aren't 100%
accurate, as I discovered when trying to wrap raster effect kernels
with them, but they work well enough for calibrating the pitch of
various audio hacks - most notably
&lt;a href="https://github.com/ahefner/asm6502/blob/master/hacks/music-demo.lisp" rel="nofollow"&gt;music-demo.lisp&lt;/a&gt;,
which streams a surprisingly high quality loop of music. I should
improve these.&lt;/p&gt;

&lt;p&gt;Most of my test programs were using character ROMs from commercial
games (appropriately, as my first MMC3 devcart still had the
original CHR ROM soldered to the board). Before uploading those to github,
I wanted to strip the graphics out. Since virtually all of the tools
for editing NES graphics run on Windows, I threw together some &lt;a href="https://github.com/ahefner/asm6502/blob/master/ichr.lisp" rel="nofollow"&gt;basic
functions&lt;/a&gt; for converting between GIF files (using the
&lt;a href="http://www.xach.com/lisp/skippy/" rel="nofollow"&gt;SKIPPY&lt;/a&gt; library) and 2-bit NES characters. This initiated a
sequence of events culminating in a nifty little graphics demo, which you can &lt;a href="http://www.youtube.com/watch?v=T8qEOG2KUQU" rel="nofollow"&gt;watch on Youtube.&lt;/a&gt;&lt;/p&gt;

&lt;lj-embed id="13" /&gt;

&lt;p&gt;With my newfound ability to convert graphics and display them on the
NES, I searched out a graphic online I could turn into another simple
example to put under the assembler's &lt;a href="https://github.com/ahefner/asm6502/tree/master/hacks" rel="nofollow"&gt;hacks directory&lt;/a&gt;. Typing
the name of the first artist I could think of into Google, I settled
on &lt;a href="http://www.markryden.com/index.html" rel="nofollow"&gt;Mark Ryden's&lt;/a&gt; &lt;a href="http://arrestedmotion.com/2009/01/release-mark-ryden-fur-girl-lithographic-poster/" rel="nofollow"&gt;"Fur Girl"&lt;/a&gt; - I hope he doesn't
mind. I wanted to run this on my real NES using the EPROM cart I made
from an old Gyromite board a few weeks ago, which constrained me to 32
KB for program data - more than enough - but only 8 KB graphics.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://vintage-digital.com/hefner/misc/nes/ryden-nes.jpg" alt="early screenshot"&gt;&lt;/p&gt;

&lt;p&gt;8 KB is enough for half a screen of unique graphics, but the NES
divides the ROM into two 4 KB pages, typically one for background and
another for sprites. I elected to fill the height of the screen and
tile the image horizontally, alternating the coloring. To use both
pages of ROM for background graphics, I have to hit one of the PPU
control registers ($2000) at the right time mid-frame to switch
pages. One glaring design flaw in the NES is the lack of a dedicated
scanline counter or horizontal blank interrupt. Some cartridges
rectify this with additional hardware that cleverly monitors the PPU
address lines, but the basic &lt;a href="http://wiki.nesdev.com/w/index.php/NROM" rel="nofollow"&gt;NROM&lt;/a&gt; board I used had no such
hardware. There are other techniques you might try, but the most basic
and broadly applicable solution is a delay loop after some reference
point (such as the beginning of the vertical blank) that spins until
the necessary time has elapsed.&lt;/p&gt;

&lt;p&gt;On top of the scrolling background image, I called the 64 sprites of
the NES into play. I believe the demoscene refers to these as
"sinebobs". Each sprite has a separate X and Y angle, indexing into a
sine table to determine its X/Y screen coordinates. These are
initialized to form a circle, and different methods of incrementing
the angle variables produce different patterns of motion on
screen. For instance, the effect of the circle splitting into four
pieces and recombining is achieved by the following code, which
increments the X angle only for every other group of 16 sprites:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(procedure split-by-4
  (jsr 'framestep)
  (ldx (imm 63))
  (as/until :negative
    (inc (abx table-y))
    (txa)
    (anda (imm 16))
    (lsr)
    (lsr)
    (lsr)
    (clc)
    (adc (abx table-x))
    (sta (abx table-x))
    (dex))
  (rts))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src="http://vintage-digital.com/hefner/misc/nes/dollhouse.jpg"&gt;&lt;/p&gt;

&lt;p&gt;Looking at the girl's hair in the image, I thought it would be cool to
try a wavy raster effect. This is done by reprogramming the
scroll/address registers during the horizontal blanking period between
scanlines, and is subject to the same timing constraints as changing
the character ROM bank mid-frame. In fact, the timing for this must be
tighter, because the visual glitch if you miss the timing window here
is much more visible. I don't manage to get it 100% right, but in
practice it looks pretty good. I do have a good excuse: nearly all of
the processing each frame occurs before the mid-frame split point and
must be written to execute in a constant number of CPU cycles. Even
so, there are a number of factors that complicate CPU/PPU
sychronization. Reading &lt;a href="http://wiki.nesdev.com/w/index.php/Consistent_frame_synchronization" rel="nofollow"&gt;Consistent frame synchronization&lt;/a&gt; on
the &lt;a href="http://wiki.nesdev.com/w/index.php/Nesdev_Wiki" rel="nofollow"&gt;Nesdev wiki&lt;/a&gt; might make your head explode.&lt;/p&gt;

&lt;p&gt;Timing all this caused a big problem for doing music: before coding
the wavy effect, I'd brought in some music I'd written several years
ago using the &lt;a href="http://woolyss.com/chipmusic-mml.php" rel="nofollow"&gt;MML/MCK&lt;/a&gt; toolchain, calling the playback routine
each frame after the screen split. At the time, there was nothing left
to do after the split but wait for the vertical blank interrupt, so it
was a perfect place to put the music and anything else that might take
a variable number of CPU cycles. After adding the wavy effect, there
was zero time left before the vertical blank. I ended up turning the
screen off a few scanlines early (necessary, otherwise you'd notice
the wave effect stop before reaching the bottom) and using that time
to update the sprite positions and run the code controlling the
overall sequence of patterns. There was no room there for the music.&lt;/p&gt;

&lt;p&gt;There's a neat trick you can do on the NES to eyeball (literally) the
amount of time a piece of code takes during the frame, by toggling the
color emphasis bits in register $2001 before and after. Before
removing the music, I timed the player in this way, illustrating its
wildly variable execution time - from virtually none upward to perhaps
20 scanlines per frame. If it had taken only a few scanlines to
execute, I'd have been okay turning the display off a little earlier
to make time, but reserving enough time to accomodate the
longest spikes would've seriously cut into the image.&lt;/p&gt;

&lt;p&gt;There were two mid-frame delay loops (before and after the screen
split) which could be shortened to provide plenty of time for music,
&lt;em&gt;if&lt;/em&gt; the player routine executes in a fixed number of machine
cycles. It took a couple days of head scratching and feet dragging
before I reduced my ambitions to nearly the simplest design imaginable
- compile the music all the way down to a sequence of sound register
writes. I defined a music 'frame' as sixteen address/value pairs (a
reasonable upper bound), and with the assumption that particular
frames would recur frequently, merged the duplicates and stored the
song as an array of pointers, one per 60 Hz tick, to the sixteen
memory writes performed for each frame.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://vintage-digital.com/hefner/misc/nes/devcarts.jpg"&gt;&lt;/p&gt;

&lt;p&gt;I realize now that I could've written the music using any of the
existing tools, easily converting it by modifying my emulator to log
all the sound register writes during playback. I'd spent enough time
initially considering more complicated player designs that the idea of
having to invent my own tools had already stuck. No matter, I'd have
probably done it this way regardless.&lt;/p&gt;

&lt;p&gt;I built a miniature embedded language for composing the music based on
the same ideas I used in my &lt;a href="http://ahefner.livejournal.com/19604.html" rel="nofollow"&gt;previous post&lt;/a&gt; playing with audio
synthesis: the ability to repeat and combine audio sequentially and in
parallel. This time around, rather than mixing audio samples, the
basic building blocks combine lists of sound register writes:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defun register (address value) (list value address))
(defun nop-write ()  (register #x0D 0)) ; Dummy write to unused register.

(defun pad-list (list padding desired-length)
  (assert (&amp;lt;= (length list) desired-length))
  (append list (loop repeat (- desired-length (length list)) collect padding)))

(defun pad-frame (frame)
  (pad-list frame (nop-write) 16))

(defun para (&amp;amp;rest args)
  (apply #'mapcar #'append
         (mapcar (lambda (x)
                   (pad-list x nil (reduce #'max args :key #'length)))
                 args)))

(defun seq (&amp;amp;rest args)
  (apply #'concatenate 'list args))

(defun repeat (n &amp;amp;rest args)
  (apply #'seq (mapcan #'copy-list (loop repeat n collect args))))

(defun segment (length list)
  (if (&amp;lt; (length list) length)
      (pad-list list nil length)
      (subseq list 0 length)))

(defun measure (&amp;amp;rest args)
  (segment 128 (apply 'para args)))

(defun rst (length) (segment length nil))    ; "Rest"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I then defined functions to control each sound channel. For instance,
the &lt;code&gt;NOISE&lt;/code&gt; function encodes its arguments as a set of writes to the
noise channel registers, upon which I've defined several percussive
sounds:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defun noise (length duration period &amp;amp;key short loop (env t) (vol 15))
  (check-type duration (integer 0 31))
  (check-type vol (integer 0 15))
  (check-type period (integer 0 15))
  (segment length
    (list
     (list
      (register #xC (logior (if loop #x20 0)
                            (if env 0 #x10)
                            vol))
      (register #xE (logior (if short #x80 0)
                            period))
      (register #xF (ash (translate-length duration) 3))))))

(defun kick (length)
  (noise length 8 15 :vol 1))

(defun snare (length &amp;amp;optional (variation 0))
  (noise length 8 (+ 10 variation) :vol 1))

(defun hat (length &amp;amp;optional (variation 0))
  (noise length 4 (+ variation 1) :vol 1))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To make certain it's clear, I'll give an example. Here I evaluate &lt;code&gt;(snare
8)&lt;/code&gt;, meaning I want a snare sound that consumes 8 frames (or 8/60 =
0.13s) of time:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;CL-USER&amp;gt; (write (dollhouse-demo::snare 8) :base 16)
(((1 C) (A E) (48 F)) NIL NIL NIL NIL NIL NIL NIL)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The outermost list is of length 8: each element is a list of memory
writes to be performed on a particular frame, in the form &lt;code&gt;(value
address)&lt;/code&gt;. Here, writes occur on the first frame, and the subsequent
frames (empty lists) pad the sequence out to the desired length. In
this way, rhythms can be built by concatenation. The address is taken
relative to $4000, where the NES sound registers begin. Comparing with
the list of &lt;a href="http://wiki.nesdev.com/w/index.php/APU_Noise" rel="nofollow"&gt;noise channel registers&lt;/a&gt;, the first frame of
writes can be interpreted as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store $1 to $400C: Set envelope length.&lt;/li&gt;
&lt;li&gt;Store $A to $400E: Set shift register period.&lt;/li&gt;
&lt;li&gt;Store $48 to $400F: Load note length counter and play.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I began building the song up as a series of local function
definitions. The &lt;code&gt;seq&lt;/code&gt; function combines its inputs sequentially. Here
are three half-bar phrases, &lt;code&gt;swagger&lt;/code&gt;, &lt;code&gt;stagger&lt;/code&gt;, and &lt;code&gt;jagger&lt;/code&gt;,
which I combine in different orders to form all the drum patterns:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(swagger ()
  (seq
    (kick 16)
    (hat 8)
    (hat 8)
    (snare 16)
    (hat 8)
    (hat 8 4)))

(stagger ()
  (seq
    (hat 8)
    (kick 8)
    (hat 8)
    (hat 8)
    (snare 16)
    (rst 16)))

(jagger ()
  (seq
    (shaker 8 15)
    (shaker 8 4)
    (shaker 8 8)
    (shaker 8 12)
    (shaker 8 15)
    (shaker 8 5)
    (shaker 8 11)
    (shaker 8 14)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Along with a &lt;code&gt;thump&lt;/code&gt; achieved by sweeping the pitch of the triangle
channel, specific drum patterns are built up by combining pieces in
series and parallel. The &lt;code&gt;measure&lt;/code&gt; function combines its arguments in
parallel, ensuring the resulting length is one measure (128 frames)
exactly. The drum patterns used in the first half of the music are
defined as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(four-on-the-floor ()
  (repeat 4 (thump 32 (et -24))))

(intro-beat ()
  (measure
    (four-on-the-floor)
    (seq
      (swagger)
      (swagger))))

(intro-fill-1 ()
  (measure
    (four-on-the-floor)
    (seq (swagger)
         (stagger))))

(intro-fill-2 ()
  (measure
    (four-on-the-floor)
    (seq (jagger)
         (jagger))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally, I've built up to defining the music. Here, the &lt;code&gt;para&lt;/code&gt;
(parallel) operator combines its two inputs: a four measure drum
pattern, constructed in an &lt;code&gt;AAAB&lt;/code&gt; pattern from &lt;code&gt;intro-beat&lt;/code&gt; and
&lt;code&gt;intro-fill-1&lt;/code&gt;, and a sequence of four arpeggiated chords, each one
measure long. This defines the first four measures of the music:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(para
  (phrase-aaab
    (intro-beat)
    (intro-fill-1))
  (seq
    (measure (fat-arp 128 '(0.00   0  3  7 11) :rate 4 :volume (volramp  8 -1/22)))
    (measure (fat-arp 128 '(0.00   0  2  5  8) :rate 4 :volume (volramp  8 -1/22)))
    (measure (fat-arp 128 '(0.00  -2  7  8 12) :rate 4 :volume (volramp  9 -1/20)))
    (measure (fat-arp 128 '(0.00  -1  2  3  7) :rate 4 :volume (volramp 10 -1/18)))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;My arpeggiator functions burn through a lot of space in the ROM, so I
was only able to fit a little over 30 seconds of music (which is just
fine with me, because I was getting impatient to finish this). You
could compress the music substantially, but I wasn't willing to
complicate the playback routine (including doing anything requiring
conditionals, for which I didn't feel like balancing the timing of
both branches). The short music loop is appropriate to the repetitive
visuals. Everything came together quickly, and I'm pleased with the
result.&lt;/p&gt;

&lt;p&gt;One idea I'm disappointed didn't work out was to gradually shift the
tuning of the music downward, so that at the end it could appear to
modulate upward to a higher key, but actually return to where it
started. I'd need a longer loop of music for this to work well. I
found I could only shift the tuning by one semitone over a thirty
second loop without it being distracting. I'm particularly
disappointed because the implementation was cute. Since the music is
constructed and concatenated piece by piece, the individual units have
no knowledge of where in the final timeline they will appear. This is
a problem, because if I'm shifting the tuning continually, pitch
becomes an implicit function of time. Since the pitches get encoded
into bitfields written to the hardware, it wasn't reasonable to just
do a final pass over the fully assembled music, shifting the pitches
down.&lt;/p&gt;

&lt;p&gt;I solved this by abusing the assembler's delayed evaluation
mechanism, modifying the function translating equal tempered pitch to
frequency, returning a &lt;code&gt;promise&lt;/code&gt; object rather than an
actual number. This &lt;code&gt;promise&lt;/code&gt; will only resolve if the
&lt;code&gt;*tuning-root*&lt;/code&gt; is bound in the dynamic environment. After assembling
the music, a final pass walks each frame of music, binding the
&lt;code&gt;*tuning-root*&lt;/code&gt; and forcing the promises to resolve (with a hack to
the delayed evaluation framework to stop it from memoizing results of
promises, in case a passage is repeated). This was relatively
unobtrusive - since CL doesn't transparently support delayed
evaluation, you do have to thread support through code that could
operate on a &lt;code&gt;promise&lt;/code&gt; value - but that only touched the pitch
translation and a few sound register functions. I'd like to revisit
this idea. It's the sort of neat trick that's usually too much hassle
to bother with when you're using conventional MIDI and DAW software. The
remains of the idea still exist in the &lt;a href="https://github.com/ahefner/asm6502/blob/master/hacks/music-test.lisp" rel="nofollow"&gt;music-test.lisp&lt;/a&gt;
sandbox, but I stripped it out of the final demo source code.&lt;/p&gt;

&lt;p&gt;Anyway, this stuff is a lot of fun.&lt;/p&gt;

&lt;p&gt;Links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;6502 Assembler &lt;a href="https://github.com/ahefner/asm6502" rel="nofollow"&gt;[github]&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dollhouse Demo &lt;a href="https://github.com/ahefner/asm6502/blob/master/hacks/dollhouse.lisp" rel="nofollow"&gt;[.lisp]&lt;/a&gt; &lt;a href="http://vintage-digital.com/hefner/misc/nes/dollhouse.nes" rel="nofollow"&gt;[.nes]&lt;/a&gt; &lt;a href="http://youtu.be/T8qEOG2KUQU" rel="nofollow"&gt;[youtube]&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Music Demo &lt;a href="https://github.com/ahefner/asm6502/blob/master/hacks/music-demo.lisp" rel="nofollow"&gt;[.lisp]&lt;/a&gt; &lt;a href="http://vintage-digital.com/hefner/misc/nes/music-demo.nes" rel="nofollow"&gt;[.nes]&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;NES Hacklets &lt;a href="https://github.com/ahefner/asm6502/blob/master/hacks/nes-hacklets.lisp" rel="nofollow"&gt;[.lisp]&lt;/a&gt; &lt;a href="http://vintage-digital.com/hefner/misc/nes/hacklets.nes" rel="nofollow"&gt;[.nes]&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:ahefner:19770</id>
    <link rel="alternate" type="text/html" href="http://ahefner.livejournal.com/19770.html"/>
    <link rel="self" type="text/xml" href="http://ahefner.livejournal.com/data/atom/?itemid=19770"/>
    <title>Piddling Plugins</title>
    <published>2012-01-23T12:15:37Z</published>
    <updated>2012-01-23T12:15:37Z</updated>
    <category term="lisp"/>
    <category term="shuffletron"/>
    <category term="hacks"/>
    <category term="coding"/>
    <content type="html">&lt;p&gt;The &lt;a href="https://github.com/ahefner/shuffletron" rel="nofollow"&gt;Shuffletron&lt;/a&gt; music player, in various branches, has accumulated some neat features (particularly &lt;a href="http://last.fm" rel="nofollow"&gt;last.fm&lt;/a&gt; scrobbling in &lt;a href="https://github.com/redline6561/shuffletron" rel="nofollow"&gt;Brit Butler's&lt;/a&gt; branch) that deserve merging, and ought to be cleanly separated from the core of the program. Leslie Polzer sent me a novel implementation early on which used generic functions for extensibility, adding/removing methods via the MOP as plugins load/unload. Clever as that was (and I'm impressed how little code is required, rereading the patch now), I wasn't comfortable with it, and the lack of a pressing need for a plugin interface let me put it off for a good long while.&lt;/p&gt;

&lt;p&gt;Building extensibility around generic functions seemed the right thing to do though, and a slightly different idea, of writing plugins in the style of mixins and calling CHANGE-CLASS to enable them at runtime, stuck in the back of my head until (with some prodding) I was motivated to try it out. It's hardly a new idea (both Gsharp and McCLIM contain implementations of similar ideas, as does the AMOP book, just to name a few examples), and a minimal implementation doesn't take much code at all:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(defvar *configurations* (make-hash-table :test 'equal))

(defun configuration (plugins)
  (or (gethash plugins *configurations*)
      (setf (gethash plugins *configurations*)
            (make-instance 'standard-class
                           :name (format nil "MY-APPLICATION~{/~A~}" plugins)
                           :direct-superclasses (cons (find-class 'my-application)
                                                      (mapcar #'find-class plugins))))))

(defun reconfigure (application plugins &amp;rest initargs)
  (apply #'change-class application (configuration plugins) initargs))

(defun active-plugins (instance)
  (mapcar #'class-name (rest (sb-mop:class-direct-superclasses (class-of instance)))))

(defun enable-plugin (application plugin &amp;rest initargs)
  (apply #'reconfigure application (adjoin plugin (active-plugins application)) initargs))

(defun disable-plugin (application plugin)
  (reconfigure application (remove plugin (active-plugins application))))

(defun make-application (&amp;rest initargs)
  (apply 'make-instance (configuration '()) initargs))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This isn't an ideal implementation, and there's a limit to how good it's going to get when CLOS doesn't fully support anonymous classes. However, a more serious attempt should work on arbitrary classes, provide a place to hang init/shutdown code for plugins, and the ability to list which plugins are enabled within an instance.&lt;/p&gt;

&lt;h2&gt;Piddling Plugins&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/ahefner/piddling-plugins" rel="nofollow"&gt;Piddling-plugins&lt;/a&gt; adds these features using only slightly more code than above, along with some superfluous macro magic for writing defun-style definitions that are extensible by plugins. I've made light use of it in a branch of Shuffletron, confirming to myself that it's a good fit.&lt;/p&gt;
&lt;p&gt;The code is tiny and self-explanatory, so I'll just post the examples from the README file for fun.&lt;/p&gt;

&lt;h2&gt;Examples&lt;/h2&gt;

&lt;p&gt;Imagine we have written a music player, looking something like this deliberately simplified code:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defclass music-player () ())

(defun run-music-player ()
  ;; You need to set or bind *application* to your application instance
  ;; if you use defun-extensible. It's a good idea even if you don't.
  (let ((*application* (make-instance 'music-player)))
    (init-audio)
    (init-library *application*)
    (loop (execute-command (read-line)))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Functions extensible by plugins can be defined using &lt;code&gt;DEFUN-EXTENSIBLE&lt;/code&gt;.
This is just syntactic sugar for defining a generic function specialized
on the application object, with a wrapper that passes in the value of &lt;code&gt;*APPLICATION*&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defun-extensible execute-command (command)
  ...)

(defun-extensible play-song (song)
  ...)

(defun-extensible song-finished (song)
  ...)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Plugins extend the behavior of the application by defining methods on the extensible functions (or rather the generic functions defined behind the scenes, which are prefixed by "EXTENDING-"):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defclass scrobbler ()
  ((auth-token :accessor auth-token)))

(defmethod plugin-enabled (app (plugin-name (eql 'scrobbler)) &amp;amp;key &amp;amp;allow-other-keys)
  (setf (auth-token app) (get-auth-token))
  (format t "~&amp;amp;Scrobbler enabled.~%"))

(defmethod plugin-disabled (app (plugin-name (eql 'scrobbler)))
  (format t "~&amp;amp;Scrobbler disabled.~%"))

(defmethod extending-song-finished :after ((plugin scrobbler) song)
  (scrobble song (auth-token plugin)))

(defclass status-bar () ())

(defmethod extending-play-song :after ((plugin status-bar) song)
  (redraw-status-bar))

(defmethod extending-execute-command :after ((plugin status-bar) command-line)
  (declare (ignore command-line))
  (redraw-status-bar))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To enable a plugin:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(enable-plugin *application* NAME [INITARGS...])
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To disable a plugin:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(disable-plugin *application* NAME)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To set precisely which plugins are enabled:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(reconfigure *application* LIST-OF-PLUGINS [INITARGS...])
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;References&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Strandh R., Hamer J., Baumann G. "Using Stealth Mixins to Achieve Modularity" (2007)
&lt;ul&gt;
&lt;li&gt;Implentation in Gsharp: &lt;a href="http://common-lisp.net/cgi-bin/gitweb.cgi?p=projects/gsharp/gsharp.git;a=blob;f=utilities.lisp" rel="nofollow"&gt;http://common-lisp.net/cgi-bin/gitweb.cgi?p=projects/gsharp/gsharp.git;a=blob;f=utilities.lisp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;"Modes" implementation in McCLIM's ESA framework (formerly part of Climacs)
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://git.boinkor.net/gitweb/mcclim.git/blob/HEAD:/ESA/utils.lisp#l446" rel="nofollow"&gt;http://git.boinkor.net/gitweb/mcclim.git/blob/HEAD:/ESA/utils.lisp#l446&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Throwaway classes (comp.lang.lisp): &lt;a href="http://groups.google.com/group/comp.lang.lisp/browse_thread/thread/78ef4a5fcd6a1661?pli=1" rel="nofollow"&gt;http://groups.google.com/group/comp.lang.lisp/browse_thread/thread/78ef4a5fcd6a1661?pli=1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The Art of the Metaobject Protocol, Section 2.4
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.foldr.org/~michaelw/lisp/amop-programmatic-class.lisp" rel="nofollow"&gt;http://www.foldr.org/~michaelw/lisp/amop-programmatic-class.lisp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;ContextL - &lt;a href="http://common-lisp.net/project/closer/contextl.html" rel="nofollow"&gt;http://common-lisp.net/project/closer/contextl.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dynamic Classes - &lt;a href="http://common-lisp.net/project/dynamic-classes/" rel="nofollow"&gt;http://common-lisp.net/project/dynamic-classes/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:ahefner:19604</id>
    <link rel="alternate" type="text/html" href="http://ahefner.livejournal.com/19604.html"/>
    <link rel="self" type="text/xml" href="http://ahefner.livejournal.com/data/atom/?itemid=19604"/>
    <title>Fun with Lisp: Just Intonation and Microtonality</title>
    <published>2012-01-17T08:18:57Z</published>
    <updated>2012-01-19T07:45:58Z</updated>
    <category term="lisp"/>
    <category term="hacks"/>
    <category term="coding"/>
    <category term="music"/>
    <content type="html">&lt;p&gt;If you're interested in &lt;a href="http://www.cliki.net/index" rel="nofollow"&gt;Lisp&lt;/a&gt;, audio/music hacking, &lt;a href="http://en.wikipedia.org/wiki/Just_intonation" rel="nofollow"&gt;just intonation&lt;/a&gt;,
or &lt;a href="http://en.wikipedia.org/wiki/Microtonality" rel="nofollow"&gt;microtonality&lt;/a&gt;, then this is the sort of thing you're interested in.&lt;/p&gt;

&lt;p&gt;First, we'll need a way to play audio. In the past, I dumped the
raw audio out to a file in /tmp and played it by shelling out to
SoX. These days I can just play it out of an array in memory using
my &lt;a href="http://vintage-digital.com/hefner/software/mixalot/mixalot.html" rel="nofollow"&gt;Mixalot library&lt;/a&gt; (of which this code requires the latest version, having only recently added support for playback of floating point vectors).&lt;/p&gt;
&lt;p&gt;Audio playback through Mixalot is straightforward:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(defparameter *mixer* (mixalot:create-mixer))

(defgeneric play (this))

(defun normalize (vector)
  (let ((rescale (/ (reduce #'max vector :key #'abs :initial-value 0.0d0))))
    (map-into vector (lambda (x) (* x rescale 0.8d0)) vector)))

(defmethod play ((this vector))
  (mixalot:mixer-add-streamer
   *mixer*
   (mixalot:make-vector-streamer-mono-double-float
    (normalize this))))
&lt;/pre&gt;&lt;/code&gt;
&lt;p&gt;Next, synthesis - we'll need some audio to play. I'll define a function of frequency called TONE that produces a buffer of audio:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(defparameter *len* 1 "Note length")

(deftype buffer () '(simple-array double-float 1))
(defun make-buffer (size) (make-array size :element-type 'double-float :adjustable nil :fill-pointer nil))

;;; Generate an audible tone.
(defun tone (freq &amp;key (duration 40000) (len *len*))
  (declare (optimize (speed 3)))
  (loop with nsamples = (round (* duration len))
        with output = (the buffer (make-buffer nsamples))
        with decay-rate = (expt 0.07 1/65000)
        with omega = (float (/ (* freq 2.0d0 pi) 44100.0d0) 0.0d0)
        for amp of-type double-float = 1.0d0 then (* amp decay-rate)
        for phase of-type double-float = 0.0d0 then (+ phase omega)
        for n from 0 below nsamples
        do (setf (aref output n)
                 (* amp
                    ;; A simple FM (PM) oscillator. Tweaking the magic
                    ;; numbers produces a variety of mostly chime-like
                    ;; timbres.
                    (sin (+ phase (* 1.5 (expt amp 2) (sin (* phase 5)))))))
        finally (return output)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next I'll define a simple language for constructing musical phrases
from the output of this function. There are two fundamental
building blocks:&lt;/p&gt;

&lt;p&gt;1. Sequencing of events serially in time:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(defun seq (&amp;rest args) (apply #'concatenate 'buffer args))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;..of which repetition is a special case:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(defun repeat (n &amp;rest args) (apply #'seq (mapcan #'copy-list (loop repeat n collect args))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;2. Events in parallel:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(defun para (&amp;rest args)
  (reduce (lambda (out in) (declare (type buffer out in)) (map-into out #'+ out in))
          args :initial-value (make-buffer (reduce #'max args :key #'length))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Originally I wrote a simpler definition for this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;(defun para (&amp;rest args) (apply #'map '(simple-array double-float 1) #'+ args))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This defintion has the disadvantage of truncating the output length to
that of the shortest component.  Also, using SBCL, it's much
slower.  &lt;code&gt;(apply #'map ...)&lt;/code&gt;  is a hairy expression that defied
optimization by the compiler, whereas it can inline the &lt;code&gt;map-into&lt;/code&gt;
operation. Combined with the type declaration, it expands to a
nice fast addition loop.&lt;/p&gt;

&lt;p&gt;Here's some syntactic sugar to make the pieces fit together more
nicely, and print some useful information to the REPL:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defmacro chord (properties &amp;body body) `(let ,properties (print :chord) (para ,@body)))

(defparameter *tonic* 261.0d0)          ; Middle C.

(defmacro just (numerators denominators &amp;rest args)
  `(progn
     ;; It's useful to see the both reduced fraction and its decimal representation:
     (print (list ',numerators ',denominators
                  (* ,@numerators (/ 1 ,@denominators))
                  (float (* ,@numerators (/ 1 ,@denominators)))))
     (tone (* *tonic* ,@numerators (/ 1 ,@denominators)) ,@args)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, to combine these tools to some musical end. First test: start with a major chord, invert the intervals each
way we can, then resolve down to an inversion of the original
chord. Note the two different senses of "invert".&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(play
 (seq
  (chord ()
   (just (1) (1))                       ; Root
   (just (5) (4))                       ; Major 3rd - 5:4
   (just (3) (2)))                      ; Fifth - 3:2
  (chord ()
   (just (1) (1))
   (just (4) (5))                       ; 5:4 becomes 4:5 - The major 3rd is reflected about the octave.
   (just (3) (2)))
  (chord ()
   (just (1) (1))
   (just (5) (4))
   (just (2) (3)))                      ; This time, the fifth.
  (chord ()
   (just (1) (1))
   (just (4) (5))                       ; - Now both are reflected.
   (just (2) (3)))                      ; -
  (chord ()                             ; Resolve down..
   (just (1) (1))
   (just (5) (4 2))
   (just (3) (2 2)))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here's a pair of chords used by &lt;a href="http://en.wikipedia.org/wiki/Harry_Partch" rel="nofollow"&gt;Harry Partch&lt;/a&gt; (see &lt;a href="http://en.wikipedia.org/wiki/Tonality_flux" rel="nofollow"&gt;http://en.wikipedia.org/wiki/Tonality_flux&lt;/a&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(let ((*tonic* 196.0)
      (*len* 3))
 (play
  (repeat 2
   (seq
    (chord ()
     (just (8)  (7))
     (just (10) (7))
     (just (12) (7)))
    (chord ()
     (just (7) (6))
     (just (7) (5))
     (just (7) (4)))))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See what he did there? The major chord, built starting 8/7 above
the tonic, is reflected around the octave.  I find it clearer to
consider the minor chord first, built upon an interval of 7/6
above the tonic, then interpret the major as as built
symmetrically downward from the next octave.&lt;/p&gt;

&lt;p&gt;It's clearer after rewriting the fractions without simplification
to separate the 8:7 and octave components from the intervals of
the chord:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(let ((*tonic* 196.0)
      (*len* 3))
 (play
  (repeat 2
   (seq
    (chord ()
     (just   (8 1) (1 7))               ;  8/7
     (just   (8 5) (4 7))               ; 10/7
     (just   (8 3) (2 7)))              ; 12/7
    (chord ()
     (just (2 7 1) (1 8 1))             ; 7/4, i.e. (2*7*1)/(1*8*1), if it isn't clear.
     (just (2 7 4) (5 8 1))             ; 7/5
     (just (2 7 2) (3 8 1)))))))        ; 7/6&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Applying that construction under equal temperament, the middle
notes of the chords would be the same. Since this is just-intoned,
the frequencies differ by about a third of a semitone, and we find
ourselves in the uncanny valley of microtonal voice leading.&lt;/p&gt;

&lt;p&gt;I've never developed an ear for microtonal music, so I'll run with
the idea of this pivoting around the octave and try something
conventional.  Take the same two chords, add a minor chord on the
tonic (without the 8/7 offset) before, and its reflection around
the next octave after. Then tack on a little ending to make a more
satisfying musical snippet: move down by a fourth, then back, with
a couple added notes for color.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(let ((*tonic* 196.0)
      (*len* 2))
  (play
   (seq
    (chord ()                           ; 1
      (just (1) (1))
      (just (6) (5))
      (just (3) (2)))
    (chord ()                           ; 2
      (just (8  ) (  7))
      (just (8 5) (4 7))
      (just (8 3) (2 7)))
    (chord ()                           ; 3: Built downward from next octave, symmetric with 2.
      (just (2 7 2) (3 8))
      (just (2 7 4) (5 8))
      (just (2 7 1) (1 8)))
    (chord ()                           ; 4: Built downward from next octave, symmetric with 1.
      (just (2  ) (1))
      (just (2 5) (6))
      (just (2 2) (3)))

    ;; Build and release tension.
    (chord ((*len* 3))
      (just (2 3  ) (  4))
      (just (2 3 4) (3 4))
      (just (2 3 3) (2 4)))
    (chord ((*len* 1))
      (just (2 3  )   (    4))
      (just (2 3 4)   (  3 4))
      (just (2 3 3)   (  2 4))
      (just (2 3 4 4) (3 3 4)))         ; 4/3*4/3, let's call it a dominant seventh.
    (chord ((*len* 4))
      (just (1) (1))
      (just (6) (5))
      (just (3) (2))
      (just (2) (1))
      (just (3) (1))))))                ; ..and that's a ninth. The 7th resolved here.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Stacking fourths:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(let ((*tonic* 262.0)
      (*len* 2))
  (play
   (seq
    (chord ()
      (just (1) (1))
      (just (4) (3)))
    (chord ()
      (just (   ) (   ))                ; Did I mention the ones are optional?
      (just (4  ) (  3))
      (just (4 4) (3 3)))
    (chord ()
      (just (     ) (     ))
      (just (4    ) (    3))
      (just (4 4  ) (  3 3))
      (just (4 4 4) (3 3 3)))
    (chord ()
      (just (       ) (       ))
      (just (4      ) (      3))
      (just (4 4    ) (    3 3))
      (just (4 4 4  ) (  3 3 3))
      (just (4 4 4 4) (3 3 3 3)))
    (chord ()
      (just (         ) (         ))
      (just (4        ) (        3))
      (just (4 4      ) (      3 3))
      (just (4 4 4    ) (    3 3 3))
      (just (4 4 4 4  ) (  3 3 3 3))
      (just (4 4 4 4 4) (3 3 3 3 3))))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Stacking fifths and fourths:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(let ((*tonic* 262.0)
      (*len* 1))
  (play
   (seq
    (chord ()
      (just (   ) (   ))
      (just (3  ) (  2))
      (just (3 4) (3 2)))
    (chord ()
      (just (   ) (   ))
      (just (4  ) (  3))
      (just (4 4) (3 3)))
    (chord ((*len* 2))
      (just (     ) (     ))
      (just (3    ) (    2))
      (just (3 3  ) (  4 2))
      (just (3 3 4) (3 4 2)))
    (chord ()
      (just (     ) (     ))
      (just (4    ) (    3))
      (just (4 4  ) (  3 3))
      (just (4 4 4) (3 3 3)))
    (chord ()
      (just (     ) (     ))
      (just (3    ) (    2))
      (just (3 4  ) (  3 2))
      (just (3 4 4) (3 3 2)))
    (chord ((*len* 4))
      (just (     ) (     ))
      (just (4    ) (    3))
      (just (4 3  ) (  2 3))
      (just (4 3 4) (3 2 3))))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Various ways to express the a major triad:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(play
 (seq
  (chord ()                             ; Three separate notes.
    (just (1) (1))
    (just (5) (4))
    (just (3) (2)))
  (chord ()
    (just (1    ) (    1))
    (just (1 5  ) (  4 1))              ; A major 3rd..
    (just (1 5 6) (5 4 1)))             ; ..and a minor 3rd on top of that.
  (chord ()
    (just (1    ) (    1))
    (just (1 3  ) (  2 1))              ; Or, you could nest the third inside
    (just (1 3 5) (6 2 1)))))           ; the fifth by a downward interval.&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The Tristan Chord (in equal temperament)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(play
 (chord ((*tonic* 349.0)                ; F
         (*len* 3))
   (tone (* *tonic* (print (expt 2.0  0/12))))
   (tone (* *tonic* (print (expt 2.0  6/12))))
   (tone (* *tonic* (print (expt 2.0 10/12))))
   (tone (* *tonic* (print (expt 2.0 15/12))))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Assume we're in A minor, and the chord is inverted such that the
root is B.  The tritone between B and F is problematic. It's an
unnatural interval in just-intonation, and there are various ways
to interpret it relative to the other notes.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(play
 (chord ((*tonic* 440.0)
         (*len* 3))
   (just (9    ) (    8))               ; B
   (just (9 5  ) (  4 8))               ; B * 5/4 = D#
   (just (9 5 4) (3 4 8))               ; D * 4/3 = G#

   ;; Now we need that F. Three ways to get there spring to mind:

   ;; 1. Two intervals of 3/4 downward from D#. Yields intervals of
   ;; 45/64, 9/16, and 27/64 versus the other notes in the chord, and
   ;; an ungainly 405/512 versus the tonic. The ratios are ugly, but
   ;; the sound is quite close.
   ;; (just (9 5 9) (16 4 8))

   ;; 2. An intervals of 5/9 downward from D# yields intervals of
   ;; 25/36, 5/9, and 5/12 versus the rest of the chord, and 25/32
   ;; against the tonic. The pitch ratios within the chord are mostly
   ;; nice and simple, but the F sounds oddly flat.
   ;; (just (9 5 5) (9 4 8))

   ;; 3. An interval of 7/10 downward from the root, yielding
   ;; intervals of 7/10, 14/25, and 21/50 versus the rest of the
   ;; chord, and 63/80 against the tonic. Constructing the F relative
   ;; to the root of the chord seems preferable, even if it introduces
   ;; a new factor of 7 into the ratios, which make the intervals
   ;; against D# and G# odd. Overall, I prefer the sound of this
   ;; one. The F is slightly flat compared to the equal-tempered
   ;; chord, but not unpleasantly so.
   (just (9 7) (10 8))))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you uncomment more than one of the above versions of 'F',
they're slightly detuned and beat against each other. This could be
a cool compositional device to highlight shifts in the tonality.
I'll try it with the two Partch chords:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(let ((*tonic* 196.0)
      (*len* 3))
 (play
  (repeat 2
    (seq
     (chord ()
       (just   (8 1) (1 7))
       (just   (8 5) (4 7))
       (just   (8 3) (2 7)))
     (chord ()
       (just   (8 1) (1 7))
       (just   (8 5) (4 7))
       (just (2 7 4) (5 8 1))           ; Presages the following chord..
       (just   (8 3) (2 7)))
     (chord ()
       (just (2 7 1) (1 8 1))
       (just (2 7 4) (5 8 1))
       (just (2 7 2) (3 8 1)))
     (chord ()
       (just (2 7 1) (1 8 1))
       (just (2 7 4) (5 8 1))
       (just   (8 5) (4 7))             ; And again..
       (just (2 7 2) (3 8 1)))))))&lt;/pre&gt;&lt;/code&gt;

&lt;p&gt;That suggests a more subtle trick. Rather than playing both tones
to mark the shift, replace one with the similar tone from the next
chord.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(let ((*tonic* 196.0)
      (*len* 3))
 (play
  (repeat 2
    (seq
     (chord ()
       (just   (8 1) (1 7))
       (just   (8 5) (4 7))
       (just   (8 3) (2 7)))
     (chord ()
       (just   (8 1) (1 7))
       (just (2 7 4) (5 8 1))           ; Replaced (8 5) (4 7) to lead into the next chord.
       (just   (8 3) (2 7)))
     (chord ()
       (just (2 7 1) (1 8 1))
       (just (2 7 4) (5 8 1))
       (just (2 7 2) (3 8 1)))
     (chord ()
       (just (2 7 1) (1 8 1))
       (just   (8 5) (4 7))             ; Likewise, replaced (2 7 4) (5 8 1)
       (just (2 7 2) (3 8 1)))))))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That's all for now. I've published the code on Github &lt;a href="https://gist.github.com/1625113" rel="nofollow"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Incidentally, I've concluded my world tour (my Thailand visa having expired, and an additional season of leisure and international intrigue being financially unwise), so if you're looking for a versatile young Lisp/C/C++ hacker with a background in computer/network security and an equal penchant for spiffy user interfaces and gritty low-level trawling around in debuggers and disassemblers, you could do worse than to &lt;a href="mailto:ahefner@gmail.com" rel="nofollow"&gt;get in touch&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:ahefner:17723</id>
    <link rel="alternate" type="text/html" href="http://ahefner.livejournal.com/17723.html"/>
    <link rel="self" type="text/xml" href="http://ahefner.livejournal.com/data/atom/?itemid=17723"/>
    <title>McPixel, a frivolous lisp hack.</title>
    <published>2010-01-31T07:26:03Z</published>
    <updated>2010-02-01T15:41:08Z</updated>
    <category term="lisp"/>
    <category term="inane"/>
    <category term="hacks"/>
    <category term="8-bit"/>
    <lj:music>De La Soul, "Breakadawn"</lj:music>
    <content type="html">Yesterday, I had the idea that it would be easy and entertaining to hack together a toy application for drawing and animating pixel art. Some hours later, &lt;a href="http://github.com/ahefner/McPixel" rel="nofollow"&gt;McPixel&lt;/a&gt; was born. It provides an editable grid of pixels, a color palette, and allows you to string sequences of images together into animations. It's a toy, but someone might find it amusing. Obligatory screenshot:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://vintage-digital.com/hefner/misc/McPixel-2.png" rel="nofollow"&gt;&lt;img alt="McPixel" src="http://vintage-digital.com/hefner/misc/McPixel-2-th.png" /&gt;&lt;br /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;Features:&lt;/div&gt;&lt;ul&gt;&lt;li&gt;80's retro McCLIM user interface.&lt;/li&gt;&lt;li&gt;No documentation or online help.&lt;/li&gt;&lt;li&gt;Maximally frustrating color sliders, using IHS colorspace.&lt;/li&gt;&lt;li&gt;Intuitive modeless drawing UI, achieved by including only a pencil tool.&lt;/li&gt;&lt;li&gt;Saves/loads files only in its own format, based on unportable s-expressions.&lt;/li&gt;&lt;li&gt;Requires X11 and SBCL with threads, to keep out the riffraff.&lt;/li&gt;&lt;li&gt;User-editable brush shape.&lt;/li&gt;&lt;li&gt;Remap Color and Silhouette commands, for tracing previous frames.&lt;/li&gt;&lt;li&gt;Realtime animated preview plays while you work.&lt;/li&gt;&lt;/ul&gt;I'm not sure I'll ever put this to productive use, if a productive use for such a thing even exists, but there you have it.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Update&lt;/strong&gt;:&amp;nbsp;I've added the ability to export an animated GIF file, using Xach Beane's &lt;a href="http://www.xach.com/lisp/skippy/" rel="nofollow"&gt;Skippy&lt;/a&gt; library. Here's the &amp;quot;turtle.anim&amp;quot; example file, exported as a GIF:&lt;br /&gt; &lt;img src="http://vintage-digital.com/hefner/misc/turtle.gif" alt="McTurtle" /&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:ahefner:17392</id>
    <link rel="alternate" type="text/html" href="http://ahefner.livejournal.com/17392.html"/>
    <link rel="self" type="text/xml" href="http://ahefner.livejournal.com/data/atom/?itemid=17392"/>
    <title>SDL Quake</title>
    <published>2010-01-11T11:27:57Z</published>
    <updated>2010-01-11T11:27:57Z</updated>
    <category term="quake"/>
    <category term="hacks"/>
    <category term="games"/>
    <category term="linux"/>
    <lj:music>Nine Inch Nails, "Down In It"</lj:music>
    <content type="html">Lately I've had a renewed interest in graphics programming, and I went back to basics, rereading everything I could find about the original Quake, and simultaneously brushing up on some (relatively speaking) more recent developments, like how to write shaders (via OpenGL's fragment program extension), normal mapping, etc. Inevitably the mood struck me to play the original Quake. All I have available to me at present is a laptop running Linux. Luckily, I still have the Linux version of Quake: The Offering (Quake 1 plus both mission packs) installed, passed along between successive Linux installs over the past decade, like a family heirloom. Of course none of the official binaries run anymore, binary compatibility on Linux being mostly nonexistent, so I set about finding a suitable engine port.&lt;br /&gt;&lt;br /&gt;I was surprised that a quick &amp;quot;apt-cache search&amp;quot; didn't find anything. Looking around the web, there are a number of interesting engine ports, but most of them looked undesirable from the perspective of someone wanting to play the game more or less as it was originally made, not with upgraded rendering technology, new models/textures, or the other cool things that most of the engine ports indulge in. New features thus became a turn-off, and I went for the most plain-sounding engine port I could, &lt;a href="http://www.libsdl.org/projects/quake/" rel="nofollow"&gt;SDLQuake&lt;/a&gt;.This had a few problems, which I fixed:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Autotools bit rot&lt;/li&gt;&lt;li&gt;Use SDL 1.2 (check for SDL 1.0.9 failed)&lt;/li&gt;&lt;li&gt;Fix config.cfg loading (it tried to reload from a different directory than it had been saved, losing my key bindings every time)&lt;/li&gt;&lt;li&gt;Fix garbled sound (set sample rate to 48 KHz by default - ALSA still sucks)&lt;/li&gt;&lt;li&gt;UDP&amp;nbsp;netcode seemed to be doing a blocking instead of non-blocking read.&lt;/li&gt;&lt;/ul&gt;Also a few gratuitious changes:&lt;ul&gt;&lt;li&gt;Start in fullscreen by default&lt;/li&gt;&lt;li&gt;+mlook at startup&lt;/li&gt;&lt;/ul&gt;If I spend any more time on this, there's a few more easy things left to do:&lt;ul&gt;&lt;li&gt;Compile a glquake executable (right now it's only compiling the software-rendered version)&lt;/li&gt;&lt;li&gt;Support for streaming the ripped soundtrack from .ogg or .mp3 files.&lt;/li&gt;&lt;/ul&gt;I'd have hacked the music code in immediately were it not for the small inconvenience of having to run the audio at 48 KHz instead of 44.1 KHz (the rate that songs ripped from the CD will be at) due to whatever ALSA&amp;nbsp;stupidity causes the audio to be corrupted on this machine (it's audible, but there's a lot of crackling, like samples are missing or clipped). While Quake is happy to put its 11 KHz sound effects through the grinder with no proper resampling (it upsamples using a fixed-point &amp;quot;nearest sample&amp;quot; approach), that would really make the music sound like crap. Of the decoder libraries I&amp;nbsp;know how to use off the top of my head, libmpg123's resampling sounds like garbage, and libvorbisfile doesn't offer it at all. I don't have a 44.1KHz -&amp;gt; 48KHz resampling routine lying around, and always make simple DSP code out to be harder than it really is, so I put off hacking in support from the music. The original SDL port&amp;nbsp; will play the music from CD, if you have it in your drive (I didn't, and found myself playing Quake to the soundtrack of a &amp;quot;Learn Thai Language&amp;quot; CD instead, which didn't fit very well). In other words, I'm lazy, and didn't want to spend a couple extra hours sorting the music out. Sorry!&lt;br /&gt;&lt;br /&gt;Anyway, maybe someone will find this useful - or, perhaps, someone will think I'm a moron for screwing with this instead of using one of the other Quake engine ports. Either way, I've thrown the code up on Github &lt;a href="http://github.com/ahefner/sdlquake" rel="nofollow"&gt;here&lt;/a&gt;.&lt;br /&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:ahefner:15783</id>
    <link rel="alternate" type="text/html" href="http://ahefner.livejournal.com/15783.html"/>
    <link rel="self" type="text/xml" href="http://ahefner.livejournal.com/data/atom/?itemid=15783"/>
    <title>Adventures in Lisp application deployment</title>
    <published>2009-07-05T11:28:41Z</published>
    <updated>2009-07-05T11:30:19Z</updated>
    <category term="lisp"/>
    <category term="hacks"/>
    <category term="oops"/>
    <lj:music>Gorillaz, "Kids with Guns"</lj:music>
    <content type="html">&lt;br /&gt;Previously I mentioned my simple music player in CL, &lt;a href="http://vintage-digital.com/hefner/software/shuffletron/" rel="nofollow"&gt;Shuffletron&lt;/a&gt;. Shuffletron uses &lt;a href="http://www.sbcl.org/manual/Saving-a-Core-Image.html#Saving-a-Core-Image" rel="nofollow"&gt;&lt;tt&gt;save-lisp-and-die&lt;/tt&gt;&lt;/a&gt; on &lt;a href="http://www.sbcl.org/" rel="nofollow"&gt;SBCL&lt;/a&gt; or &lt;a href="http://ccl.clozure.com/manual/chapter4.7.html" rel="nofollow"&gt;&lt;tt&gt;save-application&lt;/tt&gt;&lt;/a&gt; on &lt;a href="http://trac.clozure.com/openmcl" rel="nofollow"&gt;CCL&lt;/a&gt; to create a standalone executable, and is launched by a wrapper script that invokes it with &lt;a href="http://utopia.knoware.nl/~hlub/rlwrap/" rel="nofollow"&gt;&lt;tt&gt;rlwrap&lt;/tt&gt;&lt;/a&gt; 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.&lt;br /&gt;&lt;br /&gt;The first problem, observed and fixed before the publically released binaries, was an issue where &lt;a href="http://common-lisp.net/project/cffi/manual/html_node/The-Groveller.html" rel="nofollow"&gt;cffi-grovel&lt;/a&gt; (on behalf of &lt;a href="http://common-lisp.net/project/osicat/" rel="nofollow"&gt;Osicat&lt;/a&gt;) 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 &lt;tt&gt;/home/hefner/clbuild/source/osicat/posix/wrappers.so&lt;/tt&gt;, followed by &amp;quot;a lot of lisp-looking gook.&amp;quot; One solution would have been to include the library with the program and install it where SBCL could find it, but at the time I was opposed to including extra libraries with the program, so instead I took the C source to this library and linked it into SBCL's runtime executable. This has the unfortunate consequence that I have to build the binaries from a customized SBCL, but it solved the immediate problem.&lt;br /&gt;&lt;br /&gt;The next problem was simple - on machines without the libc6 development package installed, the program failed at startup, unable to load &lt;tt&gt;librt&lt;/tt&gt;. 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.&lt;br /&gt;&lt;br /&gt;The most aggravating problems I encountered were with the &lt;tt&gt;libmpg123&lt;/tt&gt; library. Some users reported &amp;quot;undefined alien function&amp;quot; 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:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;On 32-bit Linux, with newer versions of &lt;tt&gt;libmpg123&lt;/tt&gt; than my Debian-running laptop happens to have, the compile-time choice of large file support breaks binary compatibility with the &lt;tt&gt;libmpg123&lt;/tt&gt; library, wreaking havoc with the FFI bindings. Specifically, if large file support is enabled, a number of symbols change names, e.g., &lt;tt&gt;mpg123_open&lt;/tt&gt; becomes &lt;tt&gt;mpg123_open_64&lt;/tt&gt;. 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 &lt;tt&gt;mpg123-ffi&lt;/tt&gt; 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:&lt;/li&gt;&lt;br /&gt;&lt;li&gt;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 &lt;tt&gt;align-stack-pointer&lt;/tt&gt; 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 &lt;tt&gt;libmpg123&lt;/tt&gt; library with &lt;tt&gt;--disable-largefile&lt;/tt&gt; and, just to be thorough, &lt;tt&gt;--disable-aligncheck&lt;/tt&gt;, and set my &lt;tt&gt;CFLAGS&lt;/tt&gt; to &lt;tt&gt;-mstackrealign&lt;/tt&gt;, two measures which I think should've sufficed to solve the issue even without a hacked SBCL.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;The 32-bit Linux/x86 binary now includes a rebuilt version of &lt;tt&gt;libmpg123&lt;/tt&gt;, renamed &lt;tt&gt;libmixalot-mpg123&lt;/tt&gt;, 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 &lt;tt&gt;libmpg123&lt;/tt&gt; as before. My mistake, of course, was using &lt;tt&gt;libmpg123&lt;/tt&gt;, but I wasn't aware of &lt;tt&gt;libmad&lt;/tt&gt; 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.&lt;br /&gt;&lt;br /&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:ahefner:15501</id>
    <link rel="alternate" type="text/html" href="http://ahefner.livejournal.com/15501.html"/>
    <link rel="self" type="text/xml" href="http://ahefner.livejournal.com/data/atom/?itemid=15501"/>
    <title>Miscellaneous Lisp Hackery</title>
    <published>2009-07-01T07:09:24Z</published>
    <updated>2009-07-01T07:09:24Z</updated>
    <category term="lisp"/>
    <category term="audio"/>
    <category term="hacks"/>
    <category term="music"/>
    <content type="html">Here's a few things I've been working on lately which may be of broader interest:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://vintage-digital.com/hefner/software/bordeaux-fft/manual.html" rel="nofollow"&gt;Bordeaux-FFT&lt;/a&gt; is a small library for computing the FFT/IFFT&amp;nbsp;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&amp;nbsp;code from &lt;a href="http://common-lisp.net/project/sapaclisp/" rel="nofollow"&gt;Sapaclisp&lt;/a&gt;. Robert helpfully volunteered his FFT&amp;nbsp;implementation, which I cleaned up slightly and have been cheerfully employing in various audio hacks ever since. Several versions have changed hands through email, &lt;a href="http://paste.lisp.org/" rel="nofollow"&gt;lisppaste&lt;/a&gt;, 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 &lt;a href="http://www.pvk.ca/Blog/Lisp/SSE_complexes.html" rel="nofollow"&gt;recent work&lt;/a&gt; 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 &lt;a href="http://vintage-digital.com/hefner/software/message-queue.lisp" rel="nofollow"&gt;task queuing&lt;/a&gt; code to grind out batches of FFTs across four CPU&amp;nbsp;cores.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://vintage-digital.com/hefner/software/shuffletron/" rel="nofollow"&gt;Shuffletron&lt;/a&gt; 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 &lt;a href="http://www.reddit.com/r/lisp/" rel="nofollow"&gt;lisp subreddit&lt;/a&gt; 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&amp;nbsp;wrote the full player, intending to include this one as an example program with &lt;a href="http://vintage-digital.com/hefner/software/mixalot/mixalot.html" rel="nofollow"&gt;Mixalot&lt;/a&gt;. It worked better than expected, so I&amp;nbsp;ended up fleshing out the feature set instead and decided that it was really all I&amp;nbsp;needed. The code is lean and mean.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://vintage-digital.com/hefner/software/mixalot/mixalot.html" rel="nofollow"&gt;Mixalot&lt;/a&gt; is the audio back-end of &lt;a href="http://vintage-digital.com/hefner/software/shuffletron/" rel="nofollow"&gt;Shuffletron&lt;/a&gt;, 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.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:ahefner:14789</id>
    <link rel="alternate" type="text/html" href="http://ahefner.livejournal.com/14789.html"/>
    <link rel="self" type="text/xml" href="http://ahefner.livejournal.com/data/atom/?itemid=14789"/>
    <title>Emulator introspection with FUSE</title>
    <published>2009-05-20T05:49:27Z</published>
    <updated>2009-05-20T05:49:27Z</updated>
    <category term="nes"/>
    <category term="hacks"/>
    <category term="emulation"/>
    <category term="8-bit"/>
    <content type="html">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:&lt;br /&gt;&lt;pre&gt;

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
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;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. :)&lt;br /&gt;&lt;br /&gt;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.</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:ahefner:13165</id>
    <link rel="alternate" type="text/html" href="http://ahefner.livejournal.com/13165.html"/>
    <link rel="self" type="text/xml" href="http://ahefner.livejournal.com/data/atom/?itemid=13165"/>
    <title>NES Timelapse Hack</title>
    <published>2009-03-16T06:11:36Z</published>
    <updated>2009-03-16T06:12:47Z</updated>
    <category term="hacks"/>
    <category term="games"/>
    <category term="8-bit"/>
    <lj:music>Matti Raekallio, Prokofiev Piano Sonata No. 1</lj:music>
    <content type="html">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:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://vintage-digital.com/hefner/hacks/nes/stripe/stripe-smb3.png" rel="nofollow"&gt;&lt;img alt="" src="http://vintage-digital.com/hefner/hacks/nes/stripe/smb3-snippet.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;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:&amp;nbsp;&lt;a href="http://vintage-digital.com/hefner/hacks/nes/stripe/stripe-smb1.png" rel="nofollow"&gt;Super Mario Bros. 1&lt;/a&gt;, &lt;a href="http://vintage-digital.com/hefner/hacks/nes/stripe/stripe-smb3.png" rel="nofollow"&gt;Super Mario Bros. 3&lt;/a&gt;, &lt;a href="http://vintage-digital.com/hefner/hacks/nes/stripe/stripe-ducktales.png" rel="nofollow"&gt;Duck Tales&lt;/a&gt;, and &lt;a href="http://vintage-digital.com/hefner/hacks/nes/stripe/stripe-lifeforce.png" rel="nofollow"&gt;Life Force&lt;/a&gt;. In the latter case the game scrolls at a fixed rate, so you get a sort of shabby automap.&lt;br /&gt;&lt;br /&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:ahefner:12368</id>
    <link rel="alternate" type="text/html" href="http://ahefner.livejournal.com/12368.html"/>
    <link rel="self" type="text/xml" href="http://ahefner.livejournal.com/data/atom/?itemid=12368"/>
    <title>NES DAC Linearity, Part I</title>
    <published>2009-02-22T01:50:37Z</published>
    <updated>2009-02-22T01:50:37Z</updated>
    <category term="nes"/>
    <category term="hacks"/>
    <category term="8-bit"/>
    <content type="html">In my ongoing adventure tinkering with the NES, one thing I&amp;nbsp;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&amp;nbsp;noticed the audio was distorted, particularly audible in the cymbols. Once I&amp;nbsp;confirmed it wasn't just on my own emulator that it sounded distorted, I thought back to implementing my own NES&amp;nbsp;sound emulation, primarily using &lt;a href="http://nesdev.parodius.com/apu_ref.txt" rel="nofollow"&gt;apu_ref.txt&lt;/a&gt; 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&amp;nbsp;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. &lt;br /&gt;&lt;br /&gt;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&amp;nbsp;haven't tried this on a real NES yet, because it's bigger (256KB) than I&amp;nbsp;can conveniently program to an EPROM right now, and&amp;nbsp;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&lt;div style="text-align: left;"&gt;&amp;nbsp;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://vintage-digital.com/hefner/hacks/nes/audio-test-2-linear.nes" rel="nofollow"&gt;DAC&amp;nbsp;Music Loop Test (linear version)&lt;/a&gt;&lt;br /&gt;&lt;a href="http://vintage-digital.com/hefner/hacks/nes/audio-test-2-fancy.nes" rel="nofollow"&gt;DAC&amp;nbsp;Music Loop Test (adjusted version)&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;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&amp;nbsp;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).&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&amp;quot;Square rising edge&amp;quot; - a square wave at a few hundred&amp;nbsp;Hz (220?&amp;nbsp;440?&amp;nbsp;I forget.), increasing in amplitude each cycle from 0 to 127. I measured the height of the rising edge. I&amp;nbsp;let this repeat 29 times and averaged the results.&amp;nbsp;I&amp;nbsp;screwed the program up and only captured every other amplitude level (incrementing the amplitude variable on every clock edge instead of just one).&lt;/li&gt;&lt;li&gt;&amp;quot;Pulse 1&amp;quot; - Same idea, ramping up the amplitude of a brief pulse. I&amp;nbsp;measured the height of the largest rising (or rather falling) edge in the viscinity of the pulse. I&amp;nbsp;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.&lt;/li&gt;&lt;li&gt;&amp;quot;Pulse 2&amp;quot; - I&amp;nbsp;thought I'd try lengthening the pulse, hoping I&amp;nbsp;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&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://vintage-digital.com/hefner/hacks/nes/nes-dac-plot-2.png" rel="nofollow"&gt;&lt;img height="448" width="627" src="http://vintage-digital.com/hefner/hacks/nes/nes-dac-plot-2-small.png" alt="" /&gt;&lt;br /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&amp;nbsp;&lt;/div&gt;I&amp;nbsp;can imagine various sources of systematic error that invalidate these measurements, but (ignoring the screwy &amp;quot;Pulse 2&amp;quot;&amp;nbsp;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&amp;nbsp;input. &lt;br /&gt;&lt;br /&gt;I'd really hoped these measurements would agree, so that I&amp;nbsp;could divide out the affect of the mixer equation and have something like a definitive measurement of the DAC linearity which I&amp;nbsp;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&amp;nbsp;I&amp;nbsp;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 &lt;a href="http://vintage-digital.com/hefner/hacks/nes/test2-mmc3.nes" rel="nofollow"&gt;NES test cart image&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:ahefner:8029</id>
    <link rel="alternate" type="text/html" href="http://ahefner.livejournal.com/8029.html"/>
    <link rel="self" type="text/xml" href="http://ahefner.livejournal.com/data/atom/?itemid=8029"/>
    <title>XMMS, music players, and a lisp hack</title>
    <published>2008-09-04T11:27:21Z</published>
    <updated>2008-09-04T14:25:13Z</updated>
    <category term="hacks"/>
    <category term="linux"/>
    <category term="music"/>
    <lj:music>Tito Puente And His Latin Ensemble, "Giant Steps"</lj:music>
    <content type="html">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). &lt;br /&gt;&lt;br /&gt;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 &amp;quot;Add selected files&amp;quot; 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.&lt;br /&gt;&lt;br /&gt;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, &amp;quot;xmms2d&amp;quot; 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 &amp;quot;/usr/share/xmms2/mind.in.a.box-lament_snippet.ogg&amp;quot; very loudly, a noise so horrible and unexpected that I slammed the &amp;quot;kill window&amp;quot; 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.&lt;br /&gt;&lt;br /&gt;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,&amp;nbsp; 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 &amp;quot;Filesystem Browser&amp;quot; mode. &lt;br /&gt;&lt;br /&gt;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 &amp;quot;queue&amp;quot; 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).&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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 &lt;a href="http://vintage-digital.com/hefner/trivial-player.png" rel="nofollow"&gt;gui&lt;/a&gt;, 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 &amp;quot;value changed&amp;quot; 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&amp;nbsp;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&amp;nbsp;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.&amp;nbsp; 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.&lt;br /&gt;&lt;br /&gt;And now I'm off to compile xmms and see how many of the plugins I&amp;nbsp;can 1) locate and 2) succeed in compiling. &lt;br /&gt;&lt;br /&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:ahefner:1041</id>
    <link rel="alternate" type="text/html" href="http://ahefner.livejournal.com/1041.html"/>
    <link rel="self" type="text/xml" href="http://ahefner.livejournal.com/data/atom/?itemid=1041"/>
    <title>MCKC on Linux</title>
    <published>2007-11-28T07:40:26Z</published>
    <updated>2007-11-28T07:55:42Z</updated>
    <category term="hacks"/>
    <category term="emacs"/>
    <category term="8-bit"/>
    <category term="music"/>
    <lj:music>Ruxpin, "Ljufa Lif"</lj:music>
    <content type="html">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.&lt;br /&gt;&lt;br /&gt;(in file.c, mckc 0.25)&lt;br /&gt;&lt;pre&gt;
113c113
&amp;lt;       ptr = malloc( size );
---
&amp;gt;       ptr = malloc( size + 1);
&lt;/pre&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;pre&gt;
#!/bin/sh

rm -f make_nsf.nes
rm -f effect.h
rm -f songdata.h
./mckc songdata.mml &amp;gt;/tmp/mckc-out  # useless return code

if [[ -f songdata.h ]] 
then
 ./nesasm  -raw make_nsf.txt &amp;gt;&amp;gt;/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  &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp;
 xmessage -file /tmp/mckc-out
fi&lt;/pre&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;pre&gt;
(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/ &amp;&amp; /home/hefner/nerdly/mck/go.sh"))
&lt;/pre&gt;&lt;br /&gt;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.</content>
  </entry>
</feed>
