The Sennheiser HD558 “foam mod”, so called

If you have a pair of Sennheiser HD558 headphones, and you spend any time at all around the forums where audiophiles gather, then you’ve probably heard of the “foam mod”, which purports to render your HD558s indistinguishable from HD598s (which retail at twice the price) by spending a few minutes peeling sticky-backed foam out of the cans.

On the up side, the mod really is as trivial as its proponents suggest: it takes ten minutes with screwdriver, tweezers, and steady hands. The adhesive used on the foam is pretty robust stuff, but since the foam is attached to the inside of the hexagonal grid which makes up the back of the cans, most of the adhesive isn’t actually stuck to anything and the foam is very easy to remove. You’ll want to watch out a little with the left-hand side, since the wire from the driver to the cord socket PCB is fine and short enough to be imperiled by careless handling, but that’s as close as anything comes to a real risk of damage; this is a modification which a bright ten-year-old could make.

Inside the HD558's left earpiece. Note in particular the lead from the cord socket PCB (bottom) to the driver (right).

Inside the HD558′s left earpiece. Note in particular the lead from the cord socket PCB to the driver.

On the down side, I haven’t been able to perceive any slightest difference in the sound of my HD558s before and after the change. Even those who do claim to notice a difference say it’s a subtle one; assuming there actually is a difference, it’s evidently too subtle for my untutored peasant’s ears. You may of course find a different result, and given the simplicity of the mod, it’s not as though there’s a high bar to entry.

Since I don’t notice a difference, and since the foam from my ‘phones is safely stuck to the inside of a Zip-loc bag which should preserve the adhesive just fine, I figure I’ll leave things as they are until the next time I pop the pads off to clean them, and will put the foam back in then. More specifically, I’ll put the foam back in on one side, leave it out on the other, and try again to see if I can notice a difference — I doubt very much that I will, but it’s worth a shot nonetheless.

So much for foobar2000, then

I never could solve the foobar2000 TLS problem; even after adding the relevant CA cert to the Windows certificate store, I couldn’t get foobar2000 to accept a self-signed certificate as valid. Since, as previously detailed, Comcast insists on throttling upstream MP3 traffic to death, this made it effectively impossible to use foobar2000 as a streaming player for the music I have at home.

So, in the end, I’ve given up on foobar2000, at least remotely; I still use it when I’m actually at home, of course, but on my Mac laptop, I’ve found Nightingale an acceptable solution; it’s a fork of a dead Mozilla project to build a music player on top of Gecko/XULRunner, which of course makes it rather flaky and bizarre, but it can import M3U playlists downloaded from my music server, and it can deal with self-signed certificates and stream via TLS, so for my relatively simple purposes I am finding it quite satisfactory.

(Oh, and now that my bytes are coming over a TLS socket instead of being naked to the world and particularly to Comcast’s packet inspection tools, my music plays back without the slightest hiccup! Imagine that.)

Replacing Audiobox.fm with lighttpd and Perl CGI

You may remember from my earlier post on Audiobox.fm’s uselessness that I was looking for something with which to replace it. Well, I didn’t have a lot of luck finding a similar service which I could stand to use, and I have a long-standing partiality for foobar2000, which doesn’t interoperate with any of the “cloud sharing” services anyway.

(Sennheisers and foobar2000 and USB DACs? Good God, I am an audiophile!)

Anyway, this being the case, I decided it was time to start hacking at the problem for myself. I knew that foobar2000 can play remotely hosted files via HTTP, and that M3U playlists can contain URLs to such files, as well as paths to local files. Why not expose ~/music via HTTP, with an M3U generator to produce playlists of a directory’s worth of files at a time? Most all my music is organized in a directory per album, so that should cover ca. 90% of my needs, with only a little manularity required to handle the rest. How hard could it be?

Turns out it’s actually not all that hard.

I chose lighttpd for my HTTP daemon, because my home box is a Windows machine with Cygwin, and while Apache can be made to work under Cygwin, I saw no need for anything so heavyweight. (I have a couple of Linux VMs on that box, one for Emacs and one for general-purpose hackery, but I try to avoid using them for stuff like this when I can, because it’s just another layer of indirection — and because they have passphrase-less SSH keys granting access to my account on the host machine, something I’m really not inclined to risk exposing to the web.)

If you’ve used lighttpd, you know how easy it is to get up and going with it, and I found it likewise. Once I had it running, the next trick was to write the M3U generator, which took about eighty lines of Perl, and worked nicely with a URL rewrite in lighttpd.conf, such that I can visit e.g. /Miscellaneous/Sousa Marches/ to browse the directory, or /Miscellaneous/Sousa Marches.m3u to download a freshly autogenerated M3U playlist of all the FLAC, Ogg, and/or MP3 files in that directory. Having a working knowledge of RFC 2616 makes it really easy to write basic CGI scripts, as for example one which presents a file of a given format for download; just a Content-Type: audio/x-mpegurl header and a Content-Disposition: attachment; filename=$DIR.m3u header and spit out the M3U text, and you’re done and dusted.

But I didn’t want to have to hand-hack URLs in the browser, and the stock lighttpd directory-index generator isn’t configurable enough for me to have it present a “Download .m3u” link when browsing a directory containing files eligible for appearance in an M3U. So I wrote my own one of those, too, which hews closely to the format which the lighttpd stock generator uses. Mine’s a little niftier, though; it uses /bin/file to find out file types, which means they’re a lot more detailed than you get from stock lighttpd, and it generates a couple of <abbr> tags per row, where they do the most good. Its output looks roughly like this, which I grabbed out of the listing for a recording of the Brandenburg Concerti which I purchased years back from eClassical — so far back, in fact, that they didn’t yet offer FLAC. The styling isn’t the same, but the content is, and here’s how it looks:

Name Last Modified Size Type
Parent Directory 2013-11-30 06:41:15 Directory
Bach – Brandenburg Concerto no. 1 in F Maj – 1 – Allegro.mp3 2013-04-04 01:03:09 6.2M Audio file…
Bach – Brandenburg Concerto no. 1 in F Maj – 2 – Adagio.mp3 2013-04-04 01:03:24 5.7M Audio file…
Bach – Brandenburg Concerto no. 1 in F Maj – 3 – Allegro.mp3 2013-04-04 01:03:40 6.1M Audio file…
Bach – Brandenburg Concerto no. 1 in F Maj – 4 – Menuet-Trio-Menuet-Polonaise-Menuet-Trio-Menuet.mp3 2013-04-04 01:04:14 12M Audio file…
Bach – Brandenburg Concerto no. 2 in F Maj – 1 – Allegro.mp3 2013-04-04 01:04:34 7.3M Audio file…
Bach – Brandenburg Concerto no. 2 in F Maj – 2 – Andante.mp3 2013-04-04 01:04:46 5.5M Audio file…
Bach – Brandenburg Concerto no. 2 in F Maj – 3 – Allegro assai.mp3 2013-04-04 01:04:57 4.2M Audio file…
Bach – Brandenburg Concerto no. 3 in G Maj – 1 – Allegro.mp3 2013-04-04 01:05:20 8.6M Audio file…
Bach – Brandenburg Concerto no. 3 in G Maj – 2 – Adagio.mp3 2013-04-04 01:05:21 591.9K Audio file…
Bach – Brandenburg Concerto no. 3 in G Maj – 3 – Allegro.mp3 2013-04-04 01:05:42 7.7M Audio file…
Bach – Brandenburg Concerto no. 4 in G Maj – 1 – Allegro.mp3 2013-04-04 01:06:11 10.3M Audio file…
Bach – Brandenburg Concerto no. 4 in G Maj – 2 – Andante.mp3 2013-04-04 01:06:22 4.6M Audio file…
Bach – Brandenburg Concerto no. 4 in G Maj – 3 – Presto.mp3 2013-04-04 01:06:42 7.3M Audio file…
Bach – Brandenburg Concerto no. 5 in D Maj – 1 – Allegro.mp3 2013-04-04 01:07:21 14.9M Audio file…
Bach – Brandenburg Concerto no. 5 in D Maj – 2 – Affettuoso.mp3 2013-04-04 01:07:41 7.4M Audio file…
Bach – Brandenburg Concerto no. 5 in D Maj – 3 – Allegro.mp3 2013-04-04 01:08:01 7.9M Audio file…
Bach – Brandenburg Concerto no. 6 in B-Flat Maj – 1 – Allegro.mp3 2013-04-04 01:08:26 8.8M Audio file…
Bach – Brandenburg Concerto no. 6 in B-Flat Maj – 2 – Adagio ma non tanto.mp3 2013-04-04 01:08:44 6.7M Audio file…
Bach – Brandenburg Concerto no. 6 in B-Flat Maj – 3 – Allegro.mp3 2013-04-04 01:09:04 8.1M Audio file…
Bach-EC11169-Toccata_and_Fuge_in_D_min.mp3 2013-04-04 01:09:38 12.8M Audio file…

(No, those aren’t real links to the audio files, and you don’t have the right credentials anyway. Nice try.)

So that’s pleasant and workable, and I can grab a playlist of any directory I like and point foobar2000 at it. So far, so good.

Then I started running into problems — three major ones, in fact, two of which I was able to resolve, the third of which still tasks me.

The first problem revolved around HTTP authentication. I don’t want half the Internet gorging itself on my music collection, so credentials are needed to access the site. But foobar2000 has no mechanism for presenting such credentials. I solved this one by means of a cheap trick I’m not going to tell you about; suffice to say that the trick I used works, and doesn’t open quite as gaping a hole as you probably think it does.

The second problem revolved around getting foobar2000 to recognize and correctly interpret UTF-8 strings in playlist files, which matters a lot because most of my music is very well tagged, and UTF-8 is the only sensible string encoding to use for such matters. (Or any others, actually. Sure, I could’ve gotten away with sticking to Latin-1 for most of it, but why?) If you’ve been following the back numbers of this aperiodic little periodical of mine, then you know how I solved that one. (If not, suffice to say, it involved some tearing of hair.)

And then there’s the third problem, the one I still have, which is that foobar2000 is incredibly picky about the TLS certificates it will honor, and has no mechanism to allow its user to override or ignore a failed certificate check. Try to fob it off with a self-signed cert, like any reasonable person would first try to do, and it stubbornly spits up “Unable to open item for playback (Security error)” and goes and sits in the corner and sulks.

“Well,” says I, “I know how to solve this one, don’t I? Foobar2000 is a Windows-native application, which means that, if it’s doing certificate checks and insisting on a trusted root CA cert, it’s using the Windows certificate store as its source for said CA certs, right? Same as Internet Explorer does. So all I should have to do is to generate my own CA, root cert and all, then generate a CSR and sign it with my CA; if I then add my CA’s root cert to the Windows trusted root CA store, and tell lighttpd to present the site cert I signed with it, then I should be all set! Foobar2000 will see a chain of trust, and it’ll no longer feel any need to complain.”

Makes sense, right? I thought so, too. So I did all this, and it worked out fine, and once I’d added the CA root cert to the certificate store, Internet Explorer no longer pitched a fit about “untrusted site” when I pointed it at my music server. Importing the root CA into Firefox quelled its complaints about the site cert, too, and between the two of them both behaving as expected, I figured I must’ve got it right, and that foobar2000 would be just as satisfied.

If only. No, foobar2000 still pitches a fit when I try to play music via HTTPS, and I can’t understand why, because it doesn’t seem to be keeping its own certificate store anywhere, and everything it can see in the Windows cert store is telling it that my self-signed cert is every bit as hunky-dory as one purchased straight from Verisign.

Unfortunately, foobar2000 is also closed-source (its one true flaw), which means that, short of installing Visual Studio and its associated debugger, attaching the latter to the foobar2000 process, and trying to pick my way through what a stripped binary is doing on a platform where I’ve never compiled so much as a native “Hello World”, I’m pretty much SOL unless and until the developer either gives foobar2000 a prompt to override the cert check, or extends the foobar2000 SDK so I can build a component myself which does the same. (The feature’s been requested before, but there’s no telling when, or if, it’ll ever be added.) In the meantime, I’m considering either wrapping the connection in TLS via an stunnel instance at either end, so that foobar2000 doesn’t have to deal with that side of things at all, or running an actual VPN endpoint on my home box, which seems like taking more effort to set up but less to actually use.

All that’s for later, though; right now, I’m actually pretty well satisfied with how this is working out, and it only took me a few hours, silly problems included, to hack the whole thing together. Eventually, I’ll clean up my little Perl scripts and put them up on my Github account, and I’ll link them here when I do. In the meantime, Nonexistent Reader, here’s hoping something in this post has been of use to you.

New toys!

I had some Christmas money this year (thanks, Mom! ❤), and I decided to spend it on making my ears happy. Thus:

hd558

That’s a pair of Sennheiser HD-558 headphones, which for my money are about the best you can find under say four hundred dollars or so, and a Fiio E10 USB DAC/headphone amp to go with them; an amp isn’t strictly required with the HD-558s, but given their 50Ω impedance, an amp definitely helps to get the best sound out of them.

And, especially in comparison with my previous pair of HD 280 Pros, they are amazing. Wide-open soundstage, clear and precise detail retrieval, and they’re as close to neutral as anything I’ve ever heard — clear sweet highs, a nimble mid-range, and bass that’s right where it’s supposed to be, all harmoniously balanced to produce a clean sound which represents the source well with no need to EQ. In particular, both highs and lows are clearer and stronger than with the HD 280s; I can see how that makes sense for the highs, the HD-558s being open-back and the HD 280s being closed, but I’d have expected precisely the opposite difference in bass presence. Go figure; I’m happy in any case.

Good Lord, I’m talking like an audiophile, aren’t I? Fear not, Nonexistent Reader; I haven’t gone insane, and I’m not going to be buying chips of magic wood for my speakers or special cable stands to get just the right turning radius. But I’m willing to spend money where it matters, to get a real benefit, and if you want to get the best headphone sound you can for around two hundred dollars, the HD-558/Fiio E10 combo is a real contender.

Sennheiser HD-558: $150 at Amazon. Fiio E10: $75 at Amazon.

UTF-8 playlists in foobar2000

foobar2000 is a popular music player among audiophiles, of whom I am not (too much of) one, but I like it anyway for its configurability and broad encoding format support. Unfortunately, that broad support collapses almost completely when it comes to M3U playlists encoded in UTF-8.

In theory, you’re supposed to use the file extension .m3u8 for such playlists, but foobar2000 ignores that entirely, and tries to interpret the contents of a playlist as Latin-1, thus completely scrambling any string which contains characters at code points above U+007F.

After an hour and a half of incredible frustration, I finally encountered this post on the HydrogenAudio forums, in which an extremely helpful poster states:

When I prepend the bytes EF BB BF to a UTF-8 encoded .m3u8 file, then open the file in foobar2000, the non-ASCII paths are loaded properly into foobar’s playlist, as long as they exist on disk.

Those three bytes are the UTF-8 representation of a Unicode byte order mark. It should be unnecessary to prepend a BOM to a file encoded in UTF-8, since byte order has no meaning there; while the Unicode spec allows the presence of a BOM in UTF-8, it doesn’t suggest including one:

Use of a BOM is neither required nor recommended for UTF-8, but may be encountered in contexts where UTF-8 data is converted from other encoding forms that use a BOM or where the BOM is used as a UTF-8 signature[.]“

Evidently it’s that signature which foobar2000 needs, because its presence solved my problem; with it there, foobar2000 correctly interprets UTF-8 strings, and is thus able to resolve pathnames in my M3U playlists and show composer names and track titles correctly. It still doesn’t care either way about the file extension, but I don’t care about that; so long as I can feed foobar2000 my playlists and get music out of it, I’m happy.

upside-down.el: ɔⵑƃɐɯ uoⵑsɹǝʌuⵑ ʇxǝʇ

Websites such as FileFormat.info’s Unicode Upside-Down Converter establish a mapping between a range of Unicode characters (usually alphanumerics and a selected set of punctuation) and characters which resemble their upside-down versions, and use it to transform a given string of text into its visually inverted version. I saw no reason not to do something similar in Emacs. This is that thing.

Oh God, Javascript. Oh God.

I saw Armin Ronacher’s article entitled “Stop Being Cute and Clever”, which discussed at length the pitfalls inherent in being a smart-assed Javascript hacker. Among Mr. Ronacher’s claims I found, more or less as an aside, this:

Not many languages manages to implement map in a way that ["1", "2", "3"].map(parseInt) would result in [1, NaN, NaN].

“Surely not!” I exclaimed. I know better than to exclaim things like this when I see a superficially remarkable claim, such as that Javascript map could possibly be as stupid as that. I know this, because I know better than to assume someone has made a claim, which if erroneous would embarrass the hell out of him, without first making sure seven ways from Sunday that it is indeed accurate.

But I had to see this for myself, so I fired up my trusty Javascript shell and fed it the construct in question.

 >> ["1", "2", "3"].map(parseInt)
 => 1,NaN,NaN

Sure enough, map is broken. But how? I don’t often attempt to write Javascript in a functional style, because the language’s syntax doesn’t really seem to lend itself to such usage, and I don’t recall ever having passed a map callback I didn’t write myself, or which took more than one argument. Could it be that parseInt takes more than one argument? I mean, it shouldn’t matter whether it does or not, because it should only be getting one, but I’ve just got this feeling…

Huh! It does. Who knew? So what happens if I try…

 >> ["1", "2", "3"].map(function (n) { 
  -   return parseInt(n, 10) 
  - })
 => 1,2,3

…okay, but a map callback shouldn’t be getting more than one argument in any case, right? What exactly is map passing its callback?

 >> ["1", "2", "3"].map(function () {
  -   print(JSON.stringify(arguments)) 
  - })
 => {"0":"1","1":0,"2":["1","2","3"]}
  - {"0":"2","1":1,"2":["1","2","3"]}
  - {"0":"3","1":2,"2":["1","2","3"]}

Oh God!

In order, that’s: the value of the current array cell, the index of the current array cell, and the entire array over which map is operating!

And, sure, it’s trivial to redefine map so it does anything remotely sane:

 >> Array.prototype.map = function(callback) {
  -   var r = [];
  -    for (i in this) {
  -      r[i] = callback(this[i]);
  -    };
  -    return r;
  -  }
 => function(callback) { ... }
 >> ["1", "2", "3"].map(parseInt)
 => 1,2,3

Which is just dandy, until you run across some brain-dead code which has been written, whether by accident or, worse, on purpose, to depend on this unspeakably broken behavior.

But, hey, that’s Javascript, right? I mean, nobody’d make a mistake like that today, but Brendan Eich, God bless him, wrote the whole thing in two weeks in 1995. You can’t blame him for not getting every little thing just so — wait, what?

Initial definition. Implemented in Javascript 1.6

Hm, that links to the standard:

Standard ECMA-262 5.1 Edition / June 2011

Ah.

Have I yet mentioned here my fondness for strong French apple brandy?

Calvados

I have no idea why that came so suddenly to mind.

Audiobox.fm is worthless

I have ca. 80 gigabytes of music. I want to listen to it at work as well as at home, but it’s far too much to carry around or to copy between machines. I spent a while looking for a good out-of-the-box streaming solution, and I eventually found Audiobox.fm. I’ve spent several months trying to use it, via the provided web player and the “Audiobox Desktop” sharing tool, with the following results:

  1. Columns can’t be resized in the web player; with long album names similar in their heads, this makes differentation impossible.
  2. Selecting tracks in the web player is fraught; sometimes it works and most of the time it doesn’t.
  3. Even when selecting tracks works, after dragging and dropping them onto a playlist, it often turns out that a completely different set of tracks got added to the playlist.
  4. Playback is flaky; it tends to terminate mid-track for no obvious reason. (The backhaul at the source end, while admittedly Comcast, has a reliable 5Mbps upload and surprisingly low latency/packet drop rates, which is to say “almost never”; the backhaul at the client side consists of several bonded T3s. This is not a connectivity issue.)
  5. The web player’s “Download M3U” option just flat doesn’t work, precluding possibilities such as using foobar2000, or some other reliable music player, to play back MP3s served via Audiobox.fm.
  6. The web player has an absurdly short (ca. < 0.1s) timeout when attempting to start streaming a track, with the result that the track immediately following the one which just finished always gets skipped in favor of the one following that. (That is, for any th ree given tracks, the player finishes track 1, instantly times out on track 2, and starts playing track 3. This happens every time a track finishes. “Annoying” doesn’t begin.)
  7. The Audiobox Desktop client sometimes loses connectivity with the service and can’t reestablish it, rendering the music library unavailable until I can get home and restart Audiobox Desktop by hand.
  8. Audiobox’s customer service is nonexistent, and their support documentation amounts to “Doesn’t work? That’s a shame.”

Lucky me, I had the sense to try Audiobox.fm’s free service before I started paying them; the pay tiers add the ability to play back music from a variety of other sources, as well as the ability to store music with Audiobox directly instead of simply using it as a crossbar. I can see how the direct hosting option might alleviate the timeout problems, and it’s theoretically possible that their paid customers get better support than we freeloaders do; on the other hand, it would do nothing to help the many deal-breaking flaws in the web player.

Given these problems, I can’t recommend anyone use Audiobox.fm’s services at any pricing tier, including free.

Unfortunately, I have nothing better to recommend; in terms of a way to reliably stream music from home (Windows/Linux) to work (OS X/iOS), without significant effort beyond initial setup, I’m pretty much back at square one. If you’ve got a suggestion, I’d love to hear about it! My email address is on the “About” page; drop me a line.

system-cores.el: expose your processor and core count in Emacs Lisp

Someone on Stack Overflow asked whether there was a
platform-independent method of finding out how many processors a
given machine has. It turns out there’s not, so I wrote one.

“Platform-independent” is stretching a point; the best I could come
up with was to define a function ‘system-cores’, which uses a
lookup table (‘system-cores-delegate-alist’), keyed by
‘system-type’ values, to find and invoke a function which knows how
to get the processor and core counts for a given platform. This
means that some platforms, namely those for which I was able to
find reliable instructions on how to obtain processor and core
counts, are supported quite well, while others aren’t supported at
all.

On the other hand, no truly platform-independent interface to
that information exists at any level, as far as I’ve been able to
find out, so this works about as well as I think anything could be
expected to do. (And if you use a system which isn’t supported,
feel free to write a delegate and submit a pull request on Github,
or email me a diff!)