The Slackware Music Box

Originally: Intel Pentium 233mmx cpu, 64MB ram, 40gig IBM Travelstar notebook hard drive, Creative Soundblaster Audigy, powered by an AC inverter in the car
Currently: VIA EPIA ME6000 motherboard with built-in 600MHz VIA cpu, 128MB ram, 40 gig IBM Travelstar notebook hard drive, on-board AC'97 audio chip, and powered by an internal DC power supply
System Cost:
$60: old Pentium computer I already had ($0) and an AC inverter to power it ($60)
-- or --
$290: VIA EPIA ME6000 all-in-one motherboard ($120) plus RAM ($40) plus DC power supply ($60) plus custom-made case ($70)
Parts cost:
$120: 40 gig IBM Travelstar notebook hard drive
$100: Gyration wireless radio small black keyboard (way overpriced because had to buy it with the mouse)
$35: LCD screen
$60: cheap UPS from which I removed the battery to use to help power the system

Here's how I set up my Slackware Linux 8.1 box to be my dedicated music playing machine.  There's a boot/os partition, a music partition, and a small /tmp partition that holds the current playlist and song.  All partitions are mounted read-only except for /tmp.

One of the big reasons for this project is so I can have a LOT of music instantly available -- namely, so that all of my 300-400 CDs are available to play.  That means I need a big hard drive; 8 or 10 or 20 gigabytes is too small.  A 40gig drive can be used on an older system, but in order to get the system to recognize the drive's full capacity, you need a "drive translation" or "disk overlay" program.  This needs to be installed on the hard drive before the operating system, because in order to access the full capacity of the drive, the OS needs to go "through" this overlay program, and not through the motherboard's BIOS (which is the source of the limitation that prevents old boards from working with big hard drives).

So, to set up my system to be a mobile mp3 playing musicbox, here's what I did.

  1. If your motherboard is older and doesn't recognize the full capacity of the hard drive you want to use, then download and install a disk manager before installing the operating system.

  2. Install the Slackware Linux 8.1 operating system.  When you install, choose only groups A, AP, D, L, and N (and K, if that option is there), and then choose do to the "full install" of those groups.  This is much quicker and less aggravating than trying to do the individual package selection, it ends up only being 750 MB, and it's even fast (25 minutes on my Pentium-I 233mmx system; 10 minutes on my Celeron 333 system).  This will install Perl v5.6.1, the Perl module Term::ReadKey v2.20, the rexima sound mixer, the Vim text editor v6.1.88, and mpg321 v0.59q.  (Note: I've created a Slackware v9.0 installation of the musicbox, and it comes with Perl v5.8.0, but it no longer comes with Term::ReadKey.  So I downloaded and installed that manually, but it didn't work!  v2.20 and v2.19 are both somehow broken under Perl v5.8.0.  I then installed v2.14 and that worked OK.  But at this point, I'm sticking with Slackware v8.1.)

    While installing Slackware, make sure to install Lilo as the boot manager.  And if you are using disk manager software, then install Lilo to the boot record on the root partition (probably /dev/hda1), NOT to the master boot record (MBR), because the disk manager lives in the MBR.

  3. Install a few programs:

    the Time::HiRes perl module

    lcd, the program that prints lines on the LCD screen (this is my modified version of a program originally found here)

    dsrmon, which monitors the car's ACC signal through the serial port, so it can signal the music script to shut the computer down when the car turns off (you can also get the source code if that binary doesn't run on your system)

    my perl script,, which is the heart of the system (it's named music.txt on the server; rename it to when you download it)

  4. Edit the music script and notice that near the top, there are bunch of variables labeled "user-definable."  edit those, including they key mappings if you wish, to suit your needs.

  5. Put, and the binaries for the lcd writer and dsrmon, at the root of your filesystem (so they're at /, /lcd and /dsrmon).  run the command chmod a+x / /lcd /dsrmon to make the files executable.

  6. Make a file called / that looks like this:
    # Anthony DiSante's musicbox startup script
    # 20030910-1648pm
    export PATH=$PATH:/sbin:/usr/sbin
    # My CMOS clock is being dumb, or else I just can't figure it out, but
    # in any case this makes it display the correct time through Linux.
    clock --hctosys &
    # drivers for my old setup (Creative Audigy in car system; fm801 in the
    # test system)
    #modprobe emu10k1
    #modprobe snd-fm801
    #modprobe snd-pcm-oss
    # Optional: if you have a USB keyboard but didn't compile USB
    # support into your kernel, then uncomment these lines:
    #modprobe -a usb-ohci &
    #modprobe -a keybdev &
    #modprobe -a hid &
    # Note: there are 3 sets of "new" drivers here, and all have crackley,
    # distorted sound on the ac97 chip on my EPIA ME6000 motherboard, unless
    # you turn the volume down to ~65%.  When you do that, they all seem to
    # be of similar good quality.  I have the script currently 
    # setting the volume to that level automatically.
    # new ones for ac97
    #modprobe snd-via82xx
    #modprobe snd-pcm-oss
    #modprobe snd-mixer-oss
    # another new one for ac97
    modprobe via82cxxx_audio
    # new OSS one (not free):
    # Give us a nice font for when we're debugging the system.
    setfont -v gr737b-8x11.psfu.gz &
    mount /proc /proc -t proc
    # Our playlist and other state files are going to be stored at /tmp.
    # Mount it with write-caching turned off (sync turned on).
    mount -o rw,sync /dev/hda3 /tmp
    # The music collection: mount it read-only.
    mount -o ro /dev/hda4 /mp3s
    # Make a ramdisk from which to play the mp3s, so they never skip.
    mke2fs -m 0 /dev/ram0 30000
    mount -o sync /dev/ram0 /tmp/ramdisk0
    # load the lmsensors modules so we can detect CPU temperature, etc.
    modprobe i2c-viapro
    modprobe i2c-isa
    modprobe eeprom
    modprobe vt1211
    /usr/local/bin/sensors -s
    # The initial call to the sensors program takes about 5 seconds
    # (subsequent calls are ~instant), so we'll call it once here to 
    # avoid getting that delay after the music script starts.
    sensors -f >/dev/null &
    # copy mpg321 to the ramdisk, so it executes faster.
    cp `which mpg321` /tmp/ramdisk0/mpg321
    chmod a+x /tmp/ramdisk0/mpg321
    # copy the lcdwriter program to the ramdisk, so it executes faster.
    cp /lcd /tmp/ramdisk0/
    chmod a+x /tmp/ramdisk0/lcd
    # Initialize the LCD screen.
    /tmp/ramdisk0/lcd --init
    # Run the music script.
    / --noramdisk
    Note that since we're mounting the ramdisk at /tmp/ramdisk0, you should make sure to create that directory now.

    Notes: emu10k1 is the driver for my Creative Audigy soundcard, and fm801/pcm-oss is the driver for an onboard soundcard in my test system.  Change these to match your soundcard.  The USB modprobes are there because I have a USB keyboard; alternately you can install the usb.i (or usb.s or usb2.s, for usb+scsi) kernel, and then you don't need these 3 modprobes.  And of course we're not using an actual monitor, so setfont seems out of place... but I put it there because when I'm debugging/upgrading the music script, it's nice to have a smaller font so I get more text on the screen.

    Optional: I have a network card in my system, as another option of keeping the music library in sync with my home library (in addition to just pulling out the hard drive and putting it into the home machine).  In the home machine, I have a D-Link DFE-530TX (not TX+) network card, and to make that work, I have a line in my /etc/modules.conf that just says alias eth0 via-rhine.  I have a Netgear NIC in my mobile machine, and to make that work, I have a line in my /etc/rc.d/rc.netdevice file that says /sbin/modprobe natsemi.  Note that neither of these cards are loaded normally on the musicbox system; they're only loaded when you boot with linux init= (init is null).  More details on that below.

  7. Edit /etc/lilo.conf so it looks like this:
    # Anthony DiSante's /etc/lilo.conf file for the musicbox
    # 20040329
    append="init=/bin/bash --init-file /"
    boot = /dev/hda1
    #### VESA framebuffer console @ 1024x768x256
    #vga = 773
    #### Normal VGA console
    vga = normal
    #### A nice mode, but may not be supported by your kernel:
    #vga = 0xf01
    image = /boot/vmlinuz
      root = /dev/hda1
      label = linux
    Notes: put "scsi.s" before "init=/bin/bash" if you have scsi drives or a PCI IDE controller.  And of course, your boot, image, and root lines may be different.

Note that since we're setting init=/bin/bash, that means that after loading the kernel, the computer does NOTHING except drop us at a shell prompt.  It doesn't ask us to log in, it doesn't start any programs/servers/daemons, it doesn't do any of the /etc/rc.d scripts, and it doesn't put itself into multi-user mode.  All it does it run our init-script.  So once you get this system all up and running, if at some point you'd like to make it boot normally and do all that stuff, just hold down the left-shift key while it boots, and Lilo will prompt you... type linux init= and press Enter.  By setting init to null, you get your "normal" computer back.

That's it.  Run lilo to update the configuration files, then reboot.  Now when you boot, instead of passing control to /etc/inittab and the scripts in /etc/rc.d, lilo will pass control to /bin/bash, which you use to call /, which does only what you need it to -- it mounts the filesystems, starts the soundcard, and runs the music script.

Note: here's my /etc/fstab:

# Anthony DiSante's fstab file from the musicbox
# 20030906-0340am

/dev/hda1        /                ext3        defaults,ro         1   1
/dev/hda3        /tmp             ext3        defaults,rw,sync    1   2
/dev/hda4        /mp3s            vfat        defaults,ro         1   2
none             /dev/pts         devpts      gid=5,mode=620   0   0
none             /proc            proc        defaults         0   0