[Android Software Development] chdloc:
Real-world Filter Examples - Part 1: Apple Earpods

In this post I will be detailing the design process for the current Apple earpods. Note that the resulting design just serves as an example and is only meant as a starting point for your own designs and is by no means "optimal". A possible compensation filter design for the Sennheiser IE80 IEMs is detailed here.

Before we start, let me get this out of the way:

I highly suggest you not "go crazy" with the compensation filters as the danger of introducing distortion is high if you don't know what you are doing. I rather see the option to apply hardware filtering as a fine tuning tool. If your headphones are lacking quality I'd highly recommend finding headphones whose "sound signature" you like out-of-the-box. Filtering will not magically make make $5 headphones sound like $100 ones. Design flaws cannot be compensated for by filters. Also, please read posts #1 and #2 for some general information, prerequisites, and the current incompatibility of this approach with hotword detection.

Step 1: Find/measure the frequency response of the headphones you'd like to equalize

If you cannot find frequency responses of your headphones online and have no means to measure it (see here for a suggestion on how to make relative measurements), trust your ears and experiment.

There are plenty of measurements available for the Apple earpods, and I measured them myself with a lab-grade sound recording device.

Below is the resulting measurement.

[IMG="Measured Free-Field Response of (current) Apple Earpods"]http://dl-1.va.us.xda-developers.com/thumbs/3/2/8/4/9/3/2/3284932.jpg[/IMG]

Note that there is virtually no signal being visible below 1 kHz. The reason for this is that I simply held the microphone of my recording device very close to one of the earbuds. Earbuds and in-ear-monitors (IEMs) rely on the fact that they sit either in the ear or in the ear canal which will provide some level of seal that helps with amplifying the low frequencies that cannot be measured in "free-field". Hence, low frequency response is critically dependent on the eartips used. When listening to these earpods I noticed some harshness which I attribute to the two peaks (resonances) at around 2 kHz and 6.5 kHz. I will be addressing these two "shortcomings" with the below filter design.

Step 2: Design the biquads

You will either need to have Matlab (somewhat unlikely as it is very expensive for non-students) or Octave (see previous post) installed.

I will be showing the process with Matlab, but the commands for Octave are identical. The plots are formatted slightly different, though.

Step 2.1: First biquad - notch filter to reduce the gain around 6.5 kHz by 6 dB

Type

help wcd93xx_sos

to learn about the options that the biquad design tool offers.

A possible way to design the notch filter is

[biquad1, SOS1]=wcd93xx_sos(6500,3,-6,48000,7);

The design tool check for filter stability (should always be) and minimum phase and returns the result on the command line. A filter that is not minimum phase may introduce artifacts to the audio, see e.g. here.

The resulting filter that is returned by the design tool is shown below

[IMG="Biquad notch filter to reduce gain around 6.5 kHz"]http://dl-1.va.us.xda-developers.com/thumbs/3/2/8/4/9/3/3/3284933.jpg[/IMG]

You can see that, indeed, the biquad attenuates signals around 6.5 kHz. The width of the "cone" can be controlled by the Q-factor, which is the second input parameter to the wcd93xx_sos function (chosen to be 3 in this example). This plot also shows how the phase of a signal traveling through this filter will be modified. Phase modifications are less audible than amplitude modifications, and I do not expect this particular filter having much audible effect due to it modifying the phase.

Step 2.2: Second biquad - notch filter to reduce the gain around 2 kHz by 3 dB

Similarly to the above steps, this biquad can be designed with

[biquad2, SOS2]=wcd93xx_sos(2000,3,-3,48000,7);

and the resulting filter is shown below

[IMG="Biquad notch filter to reduce gain around 2 kHz"]http://dl-1.va.us.xda-developers.com/thumbs/3/2/8/4/9/3/4/3284934.jpg[/IMG]

Step 2.3-2.5: third-to-fifth biquad - any additional designs

This particular example does not have any additional filters, but up to three more biquads can be incorporated. Make sure that you call them with the following command as the output parameters have to have a specified name (biquad and SOS)

[biquadN, SOSN]=wcd93xx_sos(F0,Q,AdB,fs,type);

where N={3,4,5}.

Important NOTE: be very careful if you decide to choose AdB>0, i.e. if you want to apply gain to the signal. It is important to understand that music material is mastered to take advantage of the entire (well, at least the top-end of the) dynamic range. This means that loud sections of music will be very close to digital full-scale which will "max out" the digital representation of the signal. Any further digital amplification of these signals will invariably lead to clipping, which in turn will introduce non-linear distortions. This problem is precisely the reason why I typically avoid any type of sound "enhancement" apps/libraries. If you do feel that amplification of certain frequencies or ranges of frequencies is warranted, then you should appropriately lower the input gain of the IIR filter, i.e. the mixer setting "IIRx INP1 Volume" where x={1,2} in your mixer_paths.xml. The neutral gain setting, i.e. 0 dB, is 84. Each "tick" corresponds to 1 dB. For instance, setting this parameter to 78 will lower the gain by 6 dB while setting this parameter to 90 will increase the gain by 6 dB.

UPDATE: please read this post on limitations of the IIR filter gain, i.e. "IIR1/2 INP1 Volume" as specified in mixer_paths.xml

Step 3: Get overall filter and coefficients suitable for the Qualcomm codec

Within the same Matlab/Octave session, type

wcd93xx_filter

You will be asked how many biquads you have designed. In this example the answer would be two and the script plots the overall filter (cascade of two biquads):

[IMG="Overall compensation filter for Apple's earpods"]http://dl-1.va.us.xda-developers.com/thumbs/3/2/8/4/9/3/5/3284935.jpg[/IMG]

The script also prints a series of mixer settings which should be copied to an executable shell script, e.g. /data/local/tmp/apply_filter.sh

tinymix "IIR1 Enable Band1" 0
tinymix "IIR1 Enable Band2" 0
tinymix "IIR1 Enable Band3" 0
tinymix "IIR1 Enable Band4" 0
tinymix "IIR1 Enable Band5" 0
tinymix "IIR2 Enable Band1" 0
tinymix "IIR2 Enable Band2" 0
tinymix "IIR2 Enable Band3" 0
tinymix "IIR2 Enable Band4" 0
tinymix "IIR2 Enable Band5" 0
tinymix "IIR1 Band1" 248299376 772991194 207835511 772991194 187699432
tinymix "IIR1 Band2" 264612186 580454136 246076806 580454136 242253536
tinymix "IIR1 Band3" 268435456 0 0 0 0
tinymix "IIR1 Band4" 268435456 0 0 0 0
tinymix "IIR1 Band5" 268435456 0 0 0 0
tinymix "IIR2 Band1" 248299376 772991194 207835511 772991194 187699432
tinymix "IIR2 Band2" 264612186 580454136 246076806 580454136 242253536
tinymix "IIR2 Band3" 268435456 0 0 0 0
tinymix "IIR2 Band4" 268435456 0 0 0 0
tinymix "IIR2 Band5" 268435456 0 0 0 0
tinymix "IIR1 Enable Band1" 1
tinymix "IIR1 Enable Band2" 1
tinymix "IIR1 Enable Band3" 1
tinymix "IIR1 Enable Band4" 1
tinymix "IIR1 Enable Band5" 1
tinymix "IIR2 Enable Band1" 1
tinymix "IIR2 Enable Band2" 1
tinymix "IIR2 Enable Band3" 1
tinymix "IIR2 Enable Band4" 1
tinymix "IIR2 Enable Band5" 1

Now you can run the script (or multiple ones if you want to do A/B comparisons, a script for passthrough mode can be obtained from the OP) while audio is playing through your headphones. Note, that you will need to have IIR filtering enabled by having copied the modified "headphones" section to your mixer_paths.xml, see OP. Note also that the posted "headphones" section is taken from the Nexus 5. I do expect other phones have very similar if not identical "headphones" sections.

I applied this example filter to the Apple earpods and measured the resulting frequency response, which is shown as the blue curve in the first plot of this post. Personally, I believe this filter removes some of the harshness in the sound signature of these headphones.

Step 4: Hardcode your final filter design

Once you are happy with the filters you have designed you need to copy the coefficients to your mixer_paths.xml file and reboot, so they are applied whenever audio is playing.