Room-Mode Correction for Squeezebox with ecasound

I play most of my music through a Logitech (née SlimDevices) Squeezebox.  It’s a networked music player that pulls audio files from a server running on a separate PC or NAS.  The player runs embedded linux and the server is open-source, so this system is eminently hackable.

By messing with the contents of custom-convert.conf on the server (it lives in /etc/squeezeboxserver on my Ubuntu machine) you can manipulate the audio signal before it goes to the player.  A popular use for this is to get BruteFIR to do “digital room correction”.

Digital Room Correction

I think room correction is a bad idea: it equalizes your speakers to a flat in-room frequency response (and optionally makes the system phase coherent).  Equalization seems like a great idea at first, but it ignores the profound role of our ears and brain, which provide their own room correction at a perceptual level.  Partly because of this, it’s well-established that loudspeakers sound best when equalized flat in anechoic conditions [1].  In fact designers go to considerable trouble and expense to do just this, but it’s all for nought if you then go and re-equalize your expensive speakers to a flat in-room response.

As for correcting phase distortion, it probably doesn’t hurt, but it probably doesn’t help either: we just don’t hear phase distortion except maybe with contrived signals (square waves and such).  The ear does a Fourier transform (mechanically!), throws away the phase response and forwards the magnitude response to the brain for our enjoyment [2].  Well, sort of.

However, it still makes sense to attenuate response peaks caused by vibrational modes of the room in the sub-200Hz range.  Here the acoustics and psycho-acoustics are fundamentally different.  Room resonances are real, sometimes quite ugly, and we don’t block them perceptually.  Toole and others suggest using a parametric equalizer to attenuate them.

So I thought I would implement a parametric eq with IIR digital filters inside the squeezebox audio chain.  Here’s one way to do it (at least on my Ubuntu system):

Basic Setup

You’ll need ecasound and some LADSPA plugins:

sudo apt-get install ecasound swh-plugins

Create a folder for the eq configuration and log files:

sudo mkdir /etc/squeezeboxserver/myeq

and copy the following into /etc/squeezeboxserver/myeq/myeq.ecs:

-i stdin
-eli:1204,0.0,4.8,0.5,-8.5,30.7,0.5,-11.5,45.5,0.12,-7.0,213.0,0.07,-0.8,200,0.5
-o stdout

This file defines the eq parameters; more on this later.  I put it in a separate file so I can tweak the parameters without restarting the server.  Finally, copy the following into /etc/squeezeboxserver/custom-convert.conf (create the file if it doesn’t exist):

flc flc * *
        # IFT:{START=trim %t}
        [sox] -q -t flac $FILE$ -t raw -L -c 2 -b 16 - $START$ rate -h 44100 dither -s 2> /etc/squeezeboxserver/myeq/sox.log | /usr/bin/ecasound -q -s:/etc/squeezeboxserver/myeq/myeq.ecs 2> /etc/squeezeboxserver/myeq/ecasound.log | [flac] --stdout --silent -0 --force-raw-format --endian=little --sign=signed --channels=2 --bps=16 --sample-rate=44100 - 2> /etc/squeezeboxserver/myeq/flac.log

mp3 flc * *
        # IFT:{START=trim %t}
        [sox] -q -t mp3 $FILE$ -t raw -L -c 2 -b 16 - $START$ rate -h 44100 dither -s 2> /etc/squeezeboxserver/myeq/sox.log | /usr/bin/ecasound -q -s:/etc/squeezeboxserver/myeq/myeq.ecs 2> /etc/squeezeboxserver/myeq/ecasound.log | [flac] --stdout --silent -0 --force-raw-format --endian=little --sign=signed --channels=2 --bps=16 --sample-rate=44100 - 2> /etc/squeezeboxserver/myeq/flac.log

(This looks more complicated than it is: squeezeboxserver comes with its own versions of sox and flac that only take long-form options; alas, most of these have to be set explicitly to make everything connect properly.)  I found I had to change ownership of some files before all this would work:

sudo chown -R squeezeboxserver.nogroup /etc/squeezeboxserver/*

Now squeezeboxserver should divert all the audio (at least from flac and mp3 sources) through the filters defined in myeq.ecs.  To check that it’s working, play some music and run top.  You should see ecasound using the cpu.

What does this do, exactly?  The definitions in custom-convert.conf cause squeezeboxserver to run sox, which decodes your flac or mp3 to stdout after converting to 16-bit/44.1kHz (I had to fix on a standard to make all the pieces come together; you can change this to something else, but you’ll need to tell ecasound about the format change).  Sox will add noise-shaped dither here if the format conversion causes a reduction in bit-depth.  The raw PCM data gets piped to ecasound, which loads a LADSPA plugin to apply the filters defined in myeq.ecs, then pipes its output to flac for lossless compression before it gets sent over the network to the squeezebox player.

Configuration

You’ll need to modify myeq.ecs to suit your room.  You really need to do this with acoustic measurements, but if you have the patience you can listen to sine sweeps and figure out by ear which frequencies activate room modes.  The format of the relevant line in myeq.ecs is

-eli:1204,g1,f1,b1,g2,f2,b2,g3,f3,b3,g4,f4,b4,g4,f5,b5

This loads Steve Harris‘s triple-band parametric eq with shelves (implemented as a cascade of biquads).  The parameters come in five triples (g,f,b) each of which defines a filter with gain g [dB], center frequency f [Hz] and half-bandwidth b [octaves] (this plays the role of Q).  The first and last triples set up low- and high-shelving filters (set their gains to 0 if you don’t want them); the middle three are peaking eq filters, and should have negative gains to set notches at the room modes.  That’s enough filters to clobber the three worst modes, plus fiddle with the overall bass level.  If you need more filters, you can add more lines like this:

-eli:1203,g,f,b

each of which will create its own single-band parametric eq.  You can have as many as your cpu can handle.  (Actually you can put other LADSPA plugins here too, so you can play Bach through a simulated Marshal stack and add some wah… or whatever floats your boat.)

This took me a while to get working, but it’s fairly stable — I’ve used it happily for two years, on both an SB3 and SB Touch.  If your player outputs silence, check the log files in /etc/squeezeboxserver/myeq and debug from there.  About once a month my squeezeboxserver crashes, or sometimes plays what sounds like white noise, I have no idea why.  Restarting the server gets things running again.  If you want to remove the eq entirely just remove custom-convert.conf and restart, or make myeq.ecs a symbolic link to something without any filters in it.

References

[1] Floyd Toole, “Sound Reproduction: The Acoustics and Psychoacoustics of Loudspeakers and Rooms”, Focal Press, 2008.

[2] Hermann Helmholtz, “On the Sensations of Tone”, 1863.

8 thoughts on “Room-Mode Correction for Squeezebox with ecasound

  1. Thanks for sharing! I’m wondering about the following: how much CPU power does ecasound need? I have a ReadyNAS Ultra with a single core Atom CPU (1.8 GHz). Do you think it will be able to handle ecasound?

    My second question regards a setup with several Squeezeboxes: will the same settings be applied to the all of them or can I, for example, configure ecasound in souch a way that it only processes the audio for one of them but not for the others?

    Thanks in advance for any assistance you might be able to give…

    • I’m sure that CPU could handle the load. On a raspberry pi rev.B I can get ecasound to process 6ch audio with dozens of filters, with only 50% cpu load. But it would depend on what load the squeezebox server itself puts on the system.

      I’m not sure about your multi-squeezebox. By default the SB server will process all audio the same way, regardless of which SB device the audio is going to. But their configuration is pretty flexible; maybe there’s a way to process the audio differently depending on which SB unit is connected. Sorry I don’t know.

      • Yepp, it works! I’ve got it set up and TOP gives me max 8-12 percent CPU usage for ecasound and sox combined (using the configuration in your instructions).

        There was one little hurdle I had to overcome when following your instructions and I’m mentioning it here for anyone who might run into the same problem: the user “squeezeboxserver:nogroup” does not exist on my ReadyNAS and I could not find out what the equivalent username might be. So I checked some of the pre-existing files in /etc/squeezeboxserver to see who owns them (using ls -l). It turns out to be uid 201 so I used chown -R 201:nogroup /etc/squeezeboxserver/* instead and that worked. Maybe I should have used chown -R 201:201 /etc/squeezeboxserver/* because that was the original configuration, but it seems to work fine with nogroup.

        The other thing was that that I had to restart the NAS in order for ecasound to work. Not sure if you took that for granted or if there was some other problem on my machine.

        What I’m trying to find out now is when exactly the .ecs file is being read (i.e. becomes effective). I have added a line -epp:100 (which should suppress the left channel completely) just to be sure that I hear when it takes effect, but I continue to hear full stereo and I’m not sure how to tell ecasound to take the new config into consideration. Neither do I understand how the ecasound interactive mode relates to this “static” setup. I will try to do some research on the ecasound website on this when time allows, but if you know the answer from the top of your head, it’d be much appreciated.

        • The .ecs file gets read by ecasound at run time. On the SB server that’s whenever audio starts playing. Unfortunately, changes to .ecs files don’t take effect in real time — at least I don’t know a way to tell ecasound to recognize changes on the fly. If you make a change, you’ll need to pause then resume the audio stream, so that ecasound reads the new config.

  2. Thanks Richard. Great stuff.
    I am about to try this out and I would like to understand the b specification. In the example you give the first eq is at 4.8 Hz. With b set to 0.5 octaves. What does this correspond to in terms of cut off frequency in Hz? (e.g. 3dB down point).

    I would like to compensate for my loudspeaker’s being soft at low and to some extent mid frequencies.

  3. Digital room correction is fantastic!! But, needs to be done right. First, if you need a lot of EQ you probably need bass traps. They enable the EQ’s to work, and do things the EQ’s can’t do like reduce nulls. Secondly, EQ for flat is a bad, bad idea. I like the Bruel & Kjaer curve. I usually EQ a sub to be tilted down about 1.25dB/octave between 20 Hz and 200 Hz. Thirdly, there are some great tools like Room EQ Wizard and OmniMic which can spit out digital EQ coefficients for miniDSP. Not sure how well they would work in this setup, but once I have my Squeezebox server working again I’ll let you know. 🙂 For a lot more help and ideas, visit the DIYAudio forums!

    • I haven’t tried it, so I really shouldn’t dismiss room correction out of hand, and I ought to demo someone else’s setup. But still… bass nulls are caused by standing waves. You can’t EQ or trap them away: if you have low-frequency sound in a room, you have standing waves. You can use room correction or speaker placement to keep the nulls away from one privileged listening position, use multiple subs to fill in nulls at some other positions, and use eq to level off the remaining peaks. But eq isn’t going to defeat the physics of the situation.

Leave a Reply

Your email address will not be published. Required fields are marked *