my mpd setup

One of the hard things about getting started with mpd is that there seems to be little documentation about the details of how other people use it. Instead you're given a collection of great tools and an excellently designed system, and expected to build your own personal music playing setup out of them with little direction. So I thought I'd document mine.

There are several computers around the house that run mpd. One in my office, one has speakers in the bedroom. My laptop, of course. And I put a nslu2 in the living room in a fun lego case that embeds the little computer into a remote controlled speaker (photos when I find a camera). All of these machines have their music libraries synchronised using unison.

I use sonata as a graphical frontend and browser. I keep one instance of sonata running on my desktop in the office, so I can go there to change music if my laptop's not on. Also so guests can change the music.

(Update: ncmpc is also looking like a client I'll use frequently. The keystrokes were hard to learn, but once it's set up and learned, like many console clients, the work pays off in power and speed.)

I like to listen to whole albums at a time, and sonata doesn't make this especially easy in its user interface. I eventually realised that the best way to do it, for me, was to create a separate playlist for each album. Sonata does make it really easy to click on a playlist and start playing it. I wrote mpgenplaylists to automatically generate those playlists for me.

I wrote a set of commands that I can use to transfer state between my mpd daemons. The easiest to use and most useful of these is mpswap, which swaps the state of two daemons. Generally I only have one mpd playing at a time, and the others are paused, though it'll also swap the states of two running mpds. So if I run "mpswap dodo dragon", the music that had been playing in my bedroom starts coming out the speakers in the office. Same song, not a single missed note. That's pretty handy. Or I can run "mpswap dodo" to swap state with my laptop, and carry the music out of the house with me. (This would be more seamless if I carried some bluetooth wundergadget so my computers knew where I am, but I think I'll pass.)

Another tool I wrote is mpstore, which dumps the mpd daemon state out to stdout, so it can be saved to a file and later loaded with mpload. I use this when I'm listening to audiobooks, to store my place. Another one is mpfade, that can wake me up by slowly fading in music. Or slowly fade out and stop. Writing these little hacks is addictive, but I won't bore you with the rest.

On some of the servers I run mpd-dynamic, a daemon that watches the playlist and makes sure it always has 10 unplayed items in it, chosing new items at random. It also removes old played items from the playlist. This is nice if I want music going without the bother of picking what. I typically add some albums to the playlist, and then when they're done, it keeps playing random stuff until I manually add something else. I do want to find something that can more intelligently pick things to play. I tried lastfmpdqc, but didn't like its results.

Switching to mpd has meant that the filenames of mp3s matter again, since mpd UIs expose the filenames (a pity). I used exfalso to clean up all my file names based on the music's tags. I also added ReplayGain information to all my music so mpd can use it to normalise volume.

BTW, after all this, I'll probably still only listen to music for an average of 3 hours per week.


mpd-dynamic is in the Audio::MPD perl module.

mpdswap, mpdstore, mpfade, mpgenplaylists, and more are in mpdtoys.

discussion

Posted
lego vs programming

I spent about four hours this evening building something out of lego, something I'd not done seriously in a good many years.

I was suprised how much it felt like starting writing a program from scratch, and how many parallels I kept finding between snapping the bricks together and writing code. Here are just a few of them.

  • The first decision I made, and certianly the most important one, was how the legos were oriented. Were the pointy bits pointing up? (I chose a non-traditional pointy bits forward layout.) When starting a new program, the first and most important decision is which language to use. Both decisions, though crucial, tend to be made fairly arbitrarily.

  • I started putting blocks together with no clear picture of how everything was going to look in the end, though I knew the rough outlines. And it shows in some uglinesses aspects of the final piece. This happens in programming too. But sometimes, it's not worthwhile to figure everything out before you start.

  • The best building blocks are the simplest and plainest ones.

  • The first blocks I put together, I added more things on top of, and eventually the early first bits were found to be unncessary (everything held together without them) and removed. But if I hadn't put those blocks together to start with, I'd have had nothing to build on. When writing a program, I try not to write throwaway code. Instead, I write documentation first, and build the program from there.

  • There were some random accidents that ending up giving the piece personality and were retained.

  • Once I got in the zone, I wasn't just putting blocks together, I was juggling a lot of plans and desires and info in my head, and arranging for them to happen, while keeping everything solid and fitting together well. That's what coding is all about to me, not writing lines of text.

  • I built in all sorts of little features that you probably wouldn't notice if you looked at the piece, unless you used it in just the right way, or in a particular situation. I also built in one or two little in-jokes. My code is like that, too.

  • Deep inside my lego creation there's one really ugly hack. It wouldn't work without it, but it's something you shouldn't do with lego. Re: my code -- no comment.

discussion

Posted
lego nslu2 speaker

My speakers run Debian. And are made out of lego. Don't all point and say "geek!" at the same time, plz.

Details

Posted
if all you have is a hammer

David's post about programming languages and hand tools reminded me about the old saw about the hammer and the nail. The funny thing about that saying is that the hammer is actually one of the more versatile tools there is. A few things I've done or seen done with hammers:

  • Knap flint.
  • Pull nails. (Whoever added that ability to the stock hammer was a genious.)
  • Split fire wood with a wedge. (Axes are overrated in my experience.)
  • Pry under a board like a mini crowbar.
  • Pound on a crowbar to set it under a board. (One of my favorite tool combos.)
  • Chisel a stone sculpture.
  • Chisel a piece of wood to a custom fit rather than using a saw. (Thanks for teaching me how, Dad.)
  • Crack walnuts.
  • Knock on a wrench to loosen an over-tightened bolt.
  • Open the "eye" holes in a coconut, using a screwdriver.
  • Open the coconut the rest of the way (there's a trick to doing it with 3 firm taps, BTW).
  • Dig in the dirt. (Works better than you might think.)
  • Crack open a rock to look at the interesting fossils or geode inside.
  • Strike a tuning fork to tune a piano.
  • Oh, and pound nails.

So don't knock the hammer. Indeed it doesn't have the complexity of a programming language, but the variety of ways it can be used, number of varients that can be chosen for different purposes, and beauty of a well-designed one makes it at least comprable to a hash table, regexp engine, or the like.

Posted
sunny day

Yesterday was a nice sunny break in the mostly constant cloud cover. I went out to the Clinch Mtn and climbed up to the fire tower, it was very clear and I think I was able to see South Holston lake from there.

Posted
The Man from Earth

I turned this movie off because it became clear in the first few minutes that it was a very low budget movie shot in a hurry[1] with actors who reminded me of ones from not particularly awesome plays[2]. Then for some reason I went back to it.

And soon it got interesting. And then I got thuroughly sucked in. And then I was really sad that the storytelling was over. I think it's been a very long time since I was sad that a science fiction movie was over[3]. Maybe 1980?

This movie is set all in one room in a cabin, and has no higher technology in it than a cell phone, and yet it's amoung the top two purest peices of science fiction I've seen performed. And the lack of special effects, especially CGI[4], was a very nice change.

There's a good chance you'll not enjoy this movie, but I hope you get a chance to see it and find out. You won't find it in theaters, there's a DVD and it's on Netflix, or you can download it and paypal the director and cast a few bucks.


[1] In about a week as it turns out.
[2] Which is probably true of some of them. I only recognised one.
[3] Snip: silly-yet-true-analogy-between-typical-SF-movies-and-bags-of-potato-chips
[4] Snip: hating on most CGI

Posted
solstice

Good solstice party this year. It seems not long since the last one, and I thought about not going, but did in the end. (Anna, several people asked about you.) The bonfire was in the field at the top of Wortroot, and it was cold enough to be very nice to have a fire out there while some of Here's to the Long Haul played.

Down in the basement, watching contra dancers, I noticed that Klypso's muzzle has turned all white.

Posted
a hess holiday

On the Feast of the Radishes, we gathered at Heaven's Gate to eat mole and talk about comets.

discussion

Posted
haskell baby steps

Since early August, I had forgotten about my plan to learn haskell. Today I refreshed my memory from the docs I read back then, and started writing some very simple programs. Reading a lot of docs and letting it gel for a few months seems to have worked fairly well, I was able to throw this program together in short order, and I think it's not too horrible.

putStrs = putStr.unlines
x s n = unwords $ take n $ repeat s
plot x s = (take (x-1) s) ++ "  " ++ (drop (x+1) s)
f x = truncate(40 + 38 * sin(x / 9))
line = "JOEY HESS" `x` 8 
main = putStrs [ plot x line | x <- map f [1..]]

If you're wondering what it does, the equivilant perl is:

#!/usr/bin/perl -lisubstr($_,39+38*sin++$y/9,2)=$s
for($s='  '||McQ;$_='JOEY HESS 'x8;print){eval$^I}

I suppose both demonstrate features of their language to some extent.


At first I assumed haskell would automatically convert the floating point value coming out of sin and I got a nasty suprise:

    No instance for (Floating Int)
      arising from use of `f' at foo.hs:17:21-26
    Possible fix: add an instance declaration for (Floating Int)

Adding the truncate fixed that, but figuring that out from the above error message and google took longer than figuring out how to write the rest of the program. :-(

discussion

Posted