A complete guide to configuring FreeBSD as an audiophile audio server: setting up system and audio subsystem parameters, real-time operation, bit-perfect signal processing, and the best methods for enabling and parameterising the system graphic equalizer (equalizer) and high-quality audio equalization with FFmpeg filters. Linux users will also find useful information, especially in the context of configuring and personalising the MPD player and filters.

 

→ tłumaczenie: polski

 

With a love of music, I have had a hobby interest in digital audio processing solutions for over 20 years. I have used Linux and its underlying tools in the role of decoder, player and transport for external digital-to-analog converters (hereafter: DACs). Until I became seriously interested in FreeBSD.

 

FreeBSD, bitperfect, realtime, equalizer

 

FreeBSD as part of a hi-fi audiophile audio system

What, in my opinion, makes FreeBSD superior to Linux is the ability to precisely track the parameters of the audio device along with the system kernel parameters and modify them. We are, of course, only talking about the processing of the audio by the driver at the operating system level (i.e. by OSS/sound(4) in FreeBSD and ALSA in Linux) and configuring the system in such a way that the data is processed only at the hardware level of the listening device in bit-perfect mode, i.e.: no resampling, routing or channel mixing on the way to the external DAC device or sound card. Therefore, I naturally omit the use and configuration of additional audio layers in the form of a Jack server, PulseAudio or the unfortunate PipeWire from RedHat. Of course, there is still the question of a software signal decoder, but about that later in the article.

An additional advantage of using FreeBSD is the fact that it provides better support for real-time operating system (hereafter: RTOS) and real-time programs. Better does not mean perfect, but Linux is much further behind in this respect. It is only since 2024 that Real-Time Linux (PREEMPT_RT) has become an equal part of the kernel and its main software line.

 

What is a real-time system and why is it so important in audio processing

An RTOS is a specialised operating system designed to handle time-critical tasks with precision and reliability. Unlike general-purpose operating systems, a real-time system is designed to respond to events and process data within the strictest, smallest possible timeframe.

A key feature of RTOS systems is their predictable operation, which means that critical tasks are guaranteed to be completed within a set time. It is often mistakenly assumed that real-time systems run faster. In reality, however, it is not about speed, but about reliability and predictability. It is precisely these characteristics that make RTOS applicable in areas where time is of the essence, such as: industrial automation systems, aerospace equipment, medical devices or precisely in the field of sound processing.

Running the audio server and player in real-time system mode gives us the awareness and confidence of superior processing quality. So if we’re looking to build an audiophile system without compromise, FreeBSD would be an excellent choice. In the context of our solution, we are talking about a system operating as a transport or stereo player. We are not talking about studio applications, where mixing channels or, for example, interfacing with a MIDI interface, puts a different purpose to using an RTOS.

 

Audio quality in FreeBSD and Linux – a comparison

The many hours of listening tests I conducted showed that FreeBSD and Linux systems configured in bit-perfect mode provide the same level of audio device performance. However, what speaks in favour of FreeBSD is the precise control of all parameters of the hardware handling process at the operating system level and the ability to adjust them, giving us an almost ultimate level of oversight and knowledge.

ALSA – the Linux sound handling system – mostly adjusts all parameters automatically, so it is questionable whether the bit-perfect mode enabled by the interface (or rather protocol) hw:0,0 is what we expect. In FreeBSD, it is not just about the intuitive dev.pcm.%d.bitperfect parameter in the sound(4) driver configuration, but also about the rest of the configuration possibilities and full transparency.

 

FreeBSD, Linux, audio comparison

 

Audio hardware support in FreeBSD and Linux

It must be said, however, that there is one very important difference between FreeBSD and Linux. While in Linux, even in bit-perfect mode (hw:0,0) virtually every built-in sound card or USB DAC works correctly, the same cannot be said for FreeBSD. It happens that the enabled parameter dev.pcm.%d.bitperfect=1 implies problems. For example, one of these is the failure to properly recognise the PCM format descriptors supported by the device (especially true for XMOS communication chips). Any forcing of the parameter, including by dev.pcm.%d.play.vchanformat=s16le:2.0 does not have the desired effect. This was the case with the Presonus Audiobox iOne series devices I tested. The bit-perfect mode should be switched off, in which case a fixed resampling of each data source at 48 kHz is automatically enabled. However, under Linux control, the units work fine.

In addition, out of chronic duty, one more problem should be mentioned, especially for hardware configurations using USB DAC devices – random, once in a dozen minutes interference, audible clicks during playback. Although there is no rule here – in one hardware specification everything will be OK, in another not so much. This is a subject for a separate article, but if the problem has appeared, despite lengthy attempts with different delay parameters, buffers, debugging PCM devices and studying the mutual interference of individual components, I have so far not found a solution.

Fortunately, in most cases it is possible to configure the audio device as expected in FreeBSD. Quite simply, most parameters are selected by the system out of the box.

 

FreeBSD and audio subsystem configuration

Let’s move on to configuring the parameters of FreeBSD and its audio subsystem. The settings are for the latest version, FreeBSD 14.2, which from 2024 brings many new features to the audio stack after several years of stagnation, and according to the FreeBSD Foundation, work will continue.

The role of audio server and player is performed by the MPD (Music Player Daemon – named as mpd in Linux and musicpd(1) in FreeBSD). The MPD server interfaces are ncmpcpp(1) and mpc (musicpc(1) in FreeBSD).

Listening system specification:

  • Computer: Lenovo ThinkCentre M600 Tiny Thin Client N3010 2×1.04GHz 4GB 16GB SSD
  • Storage: Seagate Expansion SSD 2TB USB
  • DAC: Cambridge Audio DacMagic Plus (new capacitor path: Panasonic FM, ELNA for Audio; Tomanek power supply)
  • USB cable: WireWorld ULTRAVIOLET 8
  • Headphone amplifier: Forum608 IV Dual Mono (Class A)
  • RCA Interconnect: Audioquest Goldengate 0,6m
  • Headphones: Beyerdynamic 990 Pro 250 Ohm, 990 Edition 600 Ohm

Most listened albums:

  • Iron Maiden – Fear Of The Dark
  • McIntosh Audiophile Test Reference
  • Alan Parson Project – Stereotomy
  • The WHO – Quadrophenia
  • Depeche Mode – Violator
  • HD Audiophile Speaker Set-Up (192-24)
  • TOOL – Lateralus

 

FreeBSD configuration files

Essentially, the main and most important part of the FreeBSD system configuration is based on three configuration files: /boot/loader.conf, /etc/sysctl.conf, /etc/rc.conf. Below are items that are relevant in the context of bit-perfect audio and system operation in the RTOS role.

 

/boot/loader.conf

sysctlinfo_load="YES" 
mac_priority_load="YES" 
#hint.pcm.5.eq=1 
  • Adding the sysctlinfo(4) module, which is responsible for extended process communication with individual kernel sysctl states and MIB tree components. Not required, but the interface is used by some applications, e.g. mixertui(8).
  • The mac_priority(4) module establishes permission scheduling rules so that privileged users can use the rtprio(1) tool to run processes with real-time priority.
  • This parameter is responsible for enabling the graphic equalizer (equalizer) for the dev.pcm.5 device (in the specification given above, this is the USB DAC device). We omit it from the bit-perfect configuration, as discussed further in the section Graphic Equalizer in FreeBSD..

 

/etc/sysctl.conf

kern.timecounter.alloweddeviation=0 
hw.usb.uaudio.buffer_ms=2 
hw.snd.latency=0 
dev.pcm.5.play.vchans=0 
dev.pcm.5.bitperfect=1 
hw.snd.default_unit=5 
#hw.snd.vpc_0db=80 
#dev.pcm.5.eq_preamp=-5 
  • Quite an important parameter indicating an increase in the precision of the software clocks used to synchronise process wake-up, minimising the number of times the processor is forced to perform a relatively expensive operation to enter and exit idle states. For a deeper understanding of process wake-up latency and the impact of system clock frequency on this latency, I recommend Paul Herman’s article, where the benchmark source code is available in addition to the test results. To visualise the effect of the kern.timecounter.alloweddeviation parameter on latency, below are the results of the test on my system:
# ./wakeup_latency
0.007341
0.014410
0.037370
0.037336
0.037375
0.037345
0.037356
...
# sysctl kern.timecounter.alloweddeviation=0
kern.timecounter.alloweddeviation: 5 -> 0

# ./wakeup_latency
0.000061
0.000095
0.000077
0.000093
0.000096
0.000090
0.000062
...
  • Driver parameter snd_uaudio(4) for USB audio devices (the system loads the module when it detects a compatible device). Defines the data range specified in ms reported for processing. Shorter times, mean lower data latency, but it is worth experimenting with the parameter.
  • The data transfer latency, unless the software (e.g. the player) for some reason changes this value to a more favourable one.
  • Number of virtual playback/recording channels. We only care about playback from one source, so disable virtual channels. In addition, this option is required to enable bit-perfect mode.
  • Enabling bit-perfect mode, while disabling virtual channels, results in bypassing system DSP, frequency shifting / resampling, equalizer equalization, etc.). The pure PCM data stream is routed directly to the audio end device.
  • In the hardware specification shown above, the audio device is a USB DAC, visible in the system as dev.pcm.5 – we set this as the default.
  • Relative volume level parameter for the audio driver, which defaults to 45. Negligible in bit-perfect mode, but significant in the configuration of the system graphic equaliser (equalizer), negligible in configuration and bit-perfect mode.
  • Similar to the above, a relative volume level parameter, but here in relation to the operation of the system graphic equaliser (default +0.0db), negligible in bit-perfect mode. For more on the meaning of the parameters dev.pcm.%d.eq_preamp and hw.snd.vpc_0db, see Graphic equalizer in FreeBSD.

 

/etc/rc.conf

musicpd_enable="YES" 
  • In our configuration, we use the Music Player Daemon (MPD) server as the player – we turn it on during system startup in normal mode. In the rest of the configuration, we start musicpd(1) with real-time priority.

 

FreeBSD commands to help investigate the status of drivers, kernel parameters (sysctl) and the audio subsystem

Using the following command, we can display a list of loaded kernel modules and ensure that the components we have added to it are present:

# kldstat

The result should be close to the following:

Id Refs Address                Size Name
 1   43 0xffffffff80200000  1f3c6c0 kernel
 2    1 0xffffffff8213d000     3368 sysctlbyname_improved.ko
 3    1 0xffffffff82142000     77d8 cryptodev.ko
 4    1 0xffffffff8214a000     5b18 sysctlinfo.ko
 5    1 0xffffffff82150000     3c48 mac_priority.ko
 6    1 0xffffffff82154000   5da658 zfs.ko
 7    1 0xffffffff83020000     3390 acpi_wmi.ko
 8    1 0xffffffff83024000     4250 ichsmb.ko
 9    1 0xffffffff83029000     2178 smbus.ko
10    1 0xffffffff8302c000     e5b0 snd_uaudio.ko
11    1 0xffffffff8303b000     2a68 mac_ntpd.ko
12    1 0xffffffff8303e000     3560 fdescfs.ko
13    1 0xffffffff83042000    1aec0 ext2fs.ko

 

The following command will indicate the audio devices installed on the computer:

# cat /dev/sndstat

Example of a list of audio devices detected by the system:

Installed devices:
pcm0: <Realtek ALC233 (Analog 2.0+HP/2.0)> (play/rec)
pcm1: <Realtek ALC233 (Analog)> (play/rec)
pcm2: <Intel Braswell (HDMI/DP 8ch)> (play)
pcm3: <Intel Braswell (HDMI/DP 8ch)> (play)
pcm4: <Intel Braswell (HDMI/DP 8ch)> (play)
pcm5: <Cambridge Audio Cambridge Audio USB Audio 2.0> (play) default
No devices installed from userspace.

 

The kernel parameter hw.snd.verbose defaults to 0. By setting it higher, we increase the amount of available information obtained through the ioctl interface:

# sysctl hw.snd.verbose=4
# cat /dev/sndstat

 

The next command displays more details about the audio devices (only the device of interest is shown in the listing):

...
pcm5:  on uaudio0 (1p:0v/0r:0v) default
        snddev flags=0x3e7<SIMPLEX,AUTOVCHAN,SOFTPCMVOL,BUSY,MPSAFE,REGISTERED,BITPERFECT,VPC>
        [dsp5.play.0]: spd 44100, fmt 0x00201000, flags 0x2000012c, 0x00000001, pid 1059 (musicpd)
                interrupts 45405, underruns 0, feed 45404, ready 8192
                [b:5648/2824/2|bs:8192/2048/4]
                channel flags=0x2000012c<RUNNING,TRIGGERED,SLEEPING,BUSY,BITPERFECT>
                {userland} -> feeder_root(0x00201000) -> {hardware}
...

 

The status of the communication interface of a specific USB device is invoked with the command usbconfig(8) (in this case, the physical address ugen0.3 corresponds to the dev.pcm.5 represented in the system):

# usbconfig -d ugen0.3 dump_device_desc

 

Detailed interface data of the USB device of interest:

ugen0.3:  at usbus0, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=ON (2mA)

  bLength = 0x0012
  bDescriptorType = 0x0001
  bcdUSB = 0x0200
  bDeviceClass = 0x00ef  <Miscellaneous device>
  bDeviceSubClass = 0x0002
  bDeviceProtocol = 0x0001
  bMaxPacketSize0 = 0x0040
  idVendor = 0x22e8
  idProduct = 0xdac2
  bcdDevice = 0x0326
  iManufacturer = 0x0001  <Cambridge Audio >
  iProduct = 0x0002  <Cambridge Audio USB Audio 2.0>
  iSerialNumber = 0x0003  <0000>
  bNumConfigurations = 0x0002

 

Parameters of the sysctl interface connecting the sound(4) driver to the PCM driver of the audio device:

# sysctl hw.snd

The result should be similar to the following:

hw.snd.maxautovchans: 16
hw.snd.default_unit: 5
hw.snd.default_auto: 0
hw.snd.verbose: 0
hw.snd.vpc_mixer_bypass: 0
0hw.snd.feeder_rate_quality: 1
hw.snd.feeder_rate_round: 25
hw.snd.feeder_rate_max: 2016000
hw.snd.feeder_rate_min: 1
hw.snd.feeder_rate_polyphase_max: 183040
hw.snd.feeder_rate_presets: 100:8:0.85 100:36:0.92 100:164:0.97
hw.snd.feeder_eq_exact_rate: 0
hw.snd.feeder_eq_presets: PEQ:16000,0.2500,62,0.2500:-9,9,1.0:44100,48000,88200,96000,176400,192000
hw.snd.basename_clone: 1
hw.snd.compat_linux_mmap: 0
hw.snd.syncdelay: -1
hw.snd.usefrags: 0
hw.snd.vpc_reset: 0
hw.snd.vpc_0db: 45
hw.snd.vpc_autoreset: 1
hw.snd.timeout: 5
hw.snd.latency_profile: 1
hw.snd.latency: 0
hw.snd.report_soft_matrix: 1
hw.snd.report_soft_formats: 1

 

Status and driver data of the selected audio device:

# sysctl dev.pcm.5

The following listing assures us, among other things, that bit-perfect mode is definitely enabled (the correct parameters for this mode: dev.pcm.%d.bitperfect=1, dev.pcm.%d.play.vchans=0) and currently processing 44098 MHz data:

dev.pcm.5.feedback_rate: 44098
dev.pcm.5.mode: 3
dev.pcm.5.bitperfect: 1
dev.pcm.5.buffersize: 0
dev.pcm.5.play.vchans: 0
dev.pcm.5.hwvol_mixer: vol
dev.pcm.5.hwvol_step: 5
dev.pcm.5.%iommu:
dev.pcm.5.%parent: uaudio0
dev.pcm.5.%pnpinfo:
dev.pcm.5.%location:
dev.pcm.5.%driver: pcm
dev.pcm.5.%desc: Cambridge Audio Cambridge Audio USB Audio 2.0

 

Running the MPD music player in FreeBSD real-time mode

In the FreeBSD and audio subsystem configuration section, we prepared the system to run as a real-time system, that is, we loaded the mac_priority(4) module and minimised process processing delays using the kern.timecounter.alloweddeviation parameter. Starting the server and MPD (Music Player Daemon) in the system’s real-time scheduler is accomplished using the rtprio(1) command. Before doing so, however, we must disable the musicpd(1) service that is started during system start-up:

# service musicpd stop
# rtprio 0 musicpd /usr/local/etc/musicpd.conf

In FreeBSD, the highest real-time priority is 0. Priorities are numbered from 0 to RTP_PRIO_MAX (usually 31), where a lower value indicates a higher priority.

To verify that the MPD server is running in real time and with the correct priority, we browse with ps the list of processes, narrowing the response result to the musicpd(1) process:

# ps -o rtprio -axl | grep [m]usicpd

The response of the ps command should look like this:

real:0 137 1146 1 0 -52 0 415080 214420 select I<s - 0:06.55 musicpd /usr/local/etc/musicpd.conf

Another way to check the correct launch of musicpd(1) in real time using the top(1) command:

# top -p `pgrep -d "," musicpd`
last pid:  1162;  load averages:  0.03,  0.07,  0.04              up 0+12:05:50  21:38:34
50 processes:  2 running, 46 sleeping, 2 waiting
CPU: 50.0% user,  0.0% nice, 50.0% system,  0.0% interrupt,  0.0% idle
Mem: 497M Active, 64M Inact, 998M Wired, 49M Buf, 2267M Free
ARC: 85M Total, 27M MFU, 55M MRU, 514K Header, 1935K Other
     66M Compressed, 153M Uncompressed, 2.32:1 Ratio
Swap: 2048M Total, 2048M Free

  PID USERNAME    THR PRI NICE   SIZE    RES STATE    C   TIME    WCPU COMMAND
 1146 mpd           8 -52   r0   605M   227M select   0   0:12   0.00% musicpd

 

 

Additional commands in FreeBSD to help with debugging and troubleshooting the USB audio device

 

# sysctl hw.usb.debug=1
# tail -f /var/log/messages
...
Jan 21 21:55:44 freebsd kernel: usbd_pipe_enter: enter
Jan 21 21:55:44 freebsd kernel: usbd_transfer_done: err=USB_ERR_NORMAL_COMPLETION
Jan 21 21:55:44 freebsd kernel: usbd_callback_wrapper_sub: xfer=0xfffffe007c950278 endpoint=0xfffff800038ad968 sts=0 alen=2816, slen=2816, afrm=64, nfrm=64
Jan 21 21:55:44 freebsd kernel: usbd_pipe_start: start
Jan 21 21:55:44 freebsd kernel: usbd_transfer_submit: xfer=0xfffffe007c950278, endpoint=0xfffff800038ad968, nframes=64, dir=write
Jan 21 21:55:44 freebsd kernel: usb_dump_endpoint: endpoint=0xfffff800038ad968 edesc=0xfffff800056d6491 isoc_next=11268 toggle_next=0 bEndpointAddress=0x01
Jan 21 21:55:44 freebsd kernel: usb_dump_queue: endpoint=0xfffff800038ad968 xfer:
Jan 21 21:55:44 freebsd kernel: usbd_pipe_enter: enter
Jan 21 21:55:44 freebsd kernel: usbd_transfer_done: err=USB_ERR_NORMAL_COMPLETION
Jan 21 21:55:44 freebsd kernel: usbd_callback_wrapper_sub: xfer=0xfffffe007c950148 endpoint=0xfffff800038ad968 sts=0 alen=2824, slen=2824, afrm=64, nfrm=64
Jan 21 21:55:44 freebsd kernel: usbd_pipe_start: start
Jan 21 21:55:44 freebsd kernel: usbd_transfer_submit: xfer=0xfffffe007c950148, endpoint=0xfffff800038ad968, nframes=64, dir=write
Jan 21 21:55:44 freebsd kernel: usb_dump_endpoint: endpoint=0xfffff800038ad968 edesc=0xfffff800056d6491 isoc_next=11332 toggle_next=0 bEndpointAddress=0x01
Jan 21 21:55:44 freebsd kernel: usb_dump_queue: endpoint=0xfffff800038ad968 xfer:
...
# sysctl hw.usb.uaudio.debug=1
# tail -f /var/log/messages
...
Jan 21 21:53:43 freebsd kernel: uaudio_chan_play_sync_callback: Value = 0x00058330
Jan 21 21:53:43 freebsd kernel: uaudio_chan_play_sync_callback: Comparing 44099 Hz :: 44100 Hz
Jan 21 21:53:44 freebsd kernel: uaudio_chan_play_sync_callback: Value = 0x00058330
Jan 21 21:53:44 freebsd kernel: uaudio_chan_play_sync_callback: Comparing 44099 Hz :: 44100 Hz
Jan 21 21:53:45 freebsd kernel: uaudio_chan_play_sync_callback: Value = 0x00058330
Jan 21 21:53:45 freebsd kernel: uaudio_chan_play_sync_callback: Comparing 44099 Hz :: 44100 Hz
Jan 21 21:53:46 freebsd kernel: uaudio_chan_play_sync_callback: Value = 0x00058330
Jan 21 21:53:46 freebsd kernel: uaudio_chan_play_sync_callback: Comparing 44099 Hz :: 44100 Hz
Jan 21 21:53:47 freebsd kernel: uaudio_chan_play_sync_callback: Value = 0x00058330
Jan 21 21:53:47 freebsd kernel: uaudio_chan_play_sync_callback: Comparing 44099 Hz :: 44100 Hz
Jan 21 21:53:48 freebsd kernel: uaudio_chan_play_sync_callback: Value = 0x00058330
Jan 21 21:53:48 freebsd kernel: uaudio_chan_play_sync_callback: Comparing 44099 Hz :: 44100 Hz
...

 

Graphic equalizer in FreeBSD

A simple, software-based graphic equalizer (equalizer) has been implemented in the FreeBSD system’s sound driver (sound(4)), which allows real-time adjustment of bass and treble. The default kernel compilation assumes adjustment for frequencies: 62 Hz and 16 kHz, we can change these by compiling the kernel with other parameters. To enable the equaliser, set the hint.pcm.%d.eq parameter in the /boot/loader.conf file (a system reload is required):

#/boot/loader.conf
...
hint.pcm.5.eq=1

Enabling the equalizer with hint.pcm.%d.eq will make additional controls for bass and treble appear in the mixer applications. We can parameterise these with the visual application mixertui(1) or with the system application mixer(1), for example:

mixer -f /dev/mixer5 vol=0.75 pcm=0.75 bass=0.82 treble=0.76

In response, receiving the set values and their status:

vol.volume: 0.75:0.75 -> 0.75:0.75
pcm.volume: 0.75:0.75 -> 0.75:0.75
bass.volume: 0.82:0.82 -> 0.82:0.82
treble.volume: 0.76:0.76 -> 0.76:0.76
pcm5:mixer:  on uaudio0 (play)
    vol       = 0.75:0.75     pbk
    bass      = 0.82:0.82     pbk
    treble    = 0.76:0.76     pbk
    pcm       = 0.75:0.75     pbk

 

FreeBSD, equalizer, mixer, mixertui

 

Switching on and operating the graphic equaliser parameters obviously involves interference with the audio signal. Therefore, when the equalizer is switched on, bitperfect mode will automatically be switched off by the audio driver:

# sysctl dev.pcm.5 | grep bitperfect

Result:

dev.pcm.5.bitperfect: 0

Audio equalization has the potential to introduce some distortion or risk of audio degradation, especially if used in excess. To prevent this, two parameters are available in the FreeBSD sound driver: hw.snd.vpc_0db and dev.pcm.%d.eq_preamp (not yet described in the official documentation). Both parameters set the relative volume level to “zero” for the sound driver and equalizer respectively. In general, they give more room for the equalisation calculation to run without distortion:

  • hw.snd.vpc_0db – is enabled by default with a value of 45. Increasing this parameter (i.e. lowering the volume level) gives a larger range for the frequencies processed after correction.
  • dev.pcm.%d.eq_preamp – defaults to 0, with a range of -9 dB to +9 dB. For example, setting the level to -5 will first attenuate the entire audio stream to -5 dB (minus +max dB), and further amplification is a process relative to this point (0 dB). This will result in a lower volume from the listener’s perspective, but as above, provides a greater opportunity to compensate for any artefacts resulting from processing frequencies over-amplified by equalization.

The parameters are best used interchangeably and are specified in the /etc/sysctl.conf file, but can also be entered at runtime.

Examples:

# sysctl hw.snd.vpc_0db=80
hw.snd.vpc_0db: 45 -> 80
# sysctl dev.pcm.5.eq_preamp=-5
dev.pcm.5.eq_preamp: +0.0dB -> -5.0dB

 

High-quality equalizer – FFmpeg filters

The use of an audio equalizer in a hi-fi audio system, is a subject that raises different opinions among audiophiles. On the one hand, we have the purist approach, in which the sound should be reproduced as naturally as possible and without any modifications. On the other hand, the practical approach suggests using a graphic equalizer and adjusting the sound to one’s preferences, the acoustic conditions of the room or compensating for imperfections in the audio equipment.
We can also compromise, i.e. use the equalizer in moderation, trying to find the golden mean between natural sound and adjusting the sound to our needs. A suitable graphic equalizer can improve listening quality without introducing significant distortion.

Such are the excellent advanced filters of the libavfilter library of the FFmpeg project. We can easily implement them in the MPD player, where FFmpeg also plays the role of signal decoder. The MPD available in the FreeBSD ports repository has libavfilter libraries built in. In Debian 12, the MPD needs to be updated from the backports repository.

Of course, using an equalizer, we cannot talk about full bitperfect mode, but in our configuration, the bitperfect signal is passed in the data chain to the FFmpeg decoder and delivered to the DAC device or sound card via libavfilter. This type of graphic equalizer is sonically much better than the system audio driver equalizer implemented in the sound(4) driver of FreeBSD and the alsaequal plugin in Linux..

Before implementing FFmpeg filters on FreeBSD and Linux, it is also worth remembering to disable the system equalizer.

 

MPD configuration using FFmpeg filters

Using FFmpeg and the libavfilter library in the role of the MPD player’s graphic equalizer, we are most interested in the filters: bass, treble and anequalizer. In this way, we will realise a high-quality software equalizer not only in FreeBSD, but also in Linux. Furthermore, in addition to their sonic qualities, FFmpeg filters will also be useful in an MPD-based streaming system.

To enable the filter, we add a new section filter {} in the MPD configuration file musicpd.conf, which contains the definition of the filter (or filters), and add a filter in the audio_output {} section. Furthermore, we make sure that the mixer_type and replay_gain_handler parameters have the correct parameters for bit-perfect mode. We leave the system configuration to the scenario outlined in Configuring FreeBSD and the audio subsystem.

 

FFmpeg – bass and treble filters

Example of combined bass and treble filters:

filter {
  plugin "ffmpeg"
  name "equalizer"
  graph "bass=f=62:t=h:w=120:g=10:n=1:r=f64, treble=f=16000:t=h:width=8000:g=2:n=1:r=f64"
}

audio_output {
  type "oss"
  name "OSS"
  mixer_type "hardware"
  replay_gain_handler "none"
  filters "equalizer"
}

Description of filters:

  • bass – raise the frequency of 62 Hz over a width of 120 Hz by 10 points using floating point precision operating on 64 bit data;
  • treble – raise the 16 kHz frequency by 3 points over a width of 8 kHz using floating point precision operating on 64 bit data.
Very important in both filters is the n parameter, which is responsible for normalising the signal. In simplest terms, it automatically lowers the signal amplitude (loudness) in real time, giving a wider range of calculations avoiding distortion and artefacts.

Visualisation of the frequency response based on the above filters:

FFmpeg

 

FFmpeg – filter anequalizer

One more filter of the FFmpeg library is worth noting, namely anequalizer. It’s a multi-channel parametric equalizer based on analog Chebyshev and Butterworth filters (suggested for audio applications due to a less distorted signal in the pass band). The coefficients of the anequalizer filter are calculable in terms of center frequency, peak gain, bandwidth and bandwidth gain.

The definition of the characteristics shown above with bass and treble filters built with anequalizer for MPD, would look like this:

filter {
    plugin "ffmpeg"
    name "equalizer"
    graph "anequalizer=c0 f=62 w=120 g=10 t=0|c1 f=62 w=120 g=10 t=0|c0 f=16000 w=8000 g=2 t=0|c1 f=16000 w=8000 g=2 t=0"
}

As you can see, with the anequalizer filter we can build almost any graphic equalizer characteristics. With one caveat – this lacks the option to normalize the processed signal, excluding distortions resulting from its processing by the filter. And these can be heard at gain level 3 of the g parameter. The parameters of the sound driver, such as hw.snd.vpc_0db, are not applicable here, because the amplitude of the signal will be reduced by the driver only after the filtering process. The only solution, is to use a software volume mixer in MPD. With a value of 40%, distortion is not audible, even with a value of g=10, although this is not the best way to get the ideal sound.

We set the software volume mixer in MPD using the mixer_type parameter, as below:

mixer_type "software"

 

Designing the characteristics of the anequalizer filter

The waveform of the characteristics of the anequalizer filter and its parameters can be designed and visualized using the Intona fima’s DSP editor.

The equivalent of the following filter definition:

graph "anequalizer=c0 f=62 w=120 g=10 t=0|c1 f=62 w=120 g=10 t=0|c0 f=16000 w=8000 g=2 t=0|c1 f=16000 w=8000 g=2 t=0"

will be in the DSP application:

peq 62Hz q0.51 10dB
peq 16kHz q2 3dB

The q parameter (Q factor) relative to the w given in the definition is determined from the relation:

q=fw w=fq

I encourage you to design a graphic equalizer that suits your own preferences.

 

Summary

In the article, I covered topics such as how to configure the FreeBSD system and its audio subsystem for the best audio quality, discussed several aspects of the process architecture including the FreeBSD system’s real-time scheduler, bit-perfect signal mode, and how to enable the system equalizer and configure it correctly for audio processing quality. Finally, I presented the implementation of a high-quality graphic equalizer in the MPD player using FFmpeg filters (I also recommend this chapter to Linux users). The final stage of the audio track and the quality of the resulting sound already depends on the hardware specifications: music card, DAC, headphones, amplifier, speakers, etc. So, you could say that this is where the audio adventure starts all over again 😉

2 Comments

    • Of course! While the DAC itself is equally important, the K702s will only show their full potential with a headphone amplifier. Good luck with your setup!

Leave a Reply

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

Post comment