Kompletny przewodnik na temat konfiguracji FreeBSD w roli audiofilskiego serwera audio: ustawienia parametrów systemu i podsystemu dźwięku, praca w trybie czasu rzeczywistego, przetwarzania sygnału bit-perfect oraz najlepsze metody na włączenie i parametryzację systemowego korektora graficznego (equalizera) oraz wysokiej jakości korekcję dźwięku za pomocą filtrów FFmpeg. Użytkownicy Linuxa również znajdą przydatne informacje, szczególnie w kontekście konfiguracji i personalizacji odtwarzacza MPD i filtrów.
Z zamiłowania do muzyki, od ponad 20 lat hobbystycznie interesuję się cyfrowymi rozwiązaniami przetwarzania dźwięku. Wykorzystywałem system Linux i bazujące na nim narzędzia w roli dekodera, odtwarzacza oraz transportu dla zewnętrznych przetworników cyfrowo-analogowych (ang. digital-to-analog converter, dalej: DAC). Do momentu, kiedy na poważnie zainteresowałem się FreeBSD.
FreeBSD jako element audiofilskiego systemu hi-fi audio
Tym, czym w mojej opinii FreeBSD góruje nad Linuxem jest możliwość precyzyjnego śledzenia parametrów pracy urządzenia audio wraz parametrami jądra systemu oraz ich modyfikacji. Mówimy tu oczywiście wyłącznie o przetwarzaniu dźwięku przez sterownik na poziomie systemu operacyjnego (tj. przez OSS/sound(4)
we FreeBSD i ALSA w Linuxie) oraz takiej konfiguracji systemu, by dane przetwarzane były wyłącznie na poziomie sprzętowym urządzenia odsłuchowego w trybie bit-perfect, czyli: bez resamplingu, routingu czy miksowania kanałów na drodze do zewnętrznego urządzenia DAC lub karty dźwiękowej. Dlatego też, w naturalny sposób pomijam użycie i konfigurację dodatkowych warstw audio w postaci serwera Jack, PulseAudio czy nieszczęsnego PipeWire od RedHata. Oczywiście pozostaje jeszcze kwestia programowego dekodera sygnału, ale o tym w dalszej części artykułu.
Dodatkowym atutem wykorzystania FreeBSD jest fakt lepszego wsparcia dla pracy systemu w czasie rzeczywistym (tzw. Real-Time Operating System, dalej: RTOS) i programów działających w czasie rzeczywistym. Lepszego nie znaczy, że idealnego, ale Linux ma w tej kwestii o wiele większe zaległości. Dopiero od 2024 roku, niemal po 20 latach Real-Time Linux (PREEMPT_RT) stał się równoprawnym elementem jądra i jego głównej linii programowej.
Czym jest system czasu rzeczywistego i dlaczego jest tak ważny w procesie przetwarzania dźwięku
RTOS to specjalistyczny system operacyjny zaprojektowany do obsługi zadań o krytycznym znaczeniu czasowym, zapewniający precyzję i niezawodność działania. W przeciwieństwie do systemów operacyjnych ogólnego przeznaczenia, system czasu rzeczywistego jest stworzony z myślą o reagowaniu na zdarzenia oraz przetwarzaniu danych w ściśle określonych, najmniejszych możliwych ramach czasowych.
Kluczową cechą systemów RTOS jest ich przewidywalne działanie, co oznacza gwarancję wykonania krytycznych zadań w ustalonym czasie. Często błędnie zakłada się, że systemy czasu rzeczywistego pracują szybciej. W rzeczywistości chodzi jednak nie o szybkość, lecz o niezawodność i przewidywalność. To właśnie te cechy sprawiają, że RTOS znajduje zastosowanie w obszarach, gdzie czas odgrywa kluczową rolę, takich jak np.: systemy automatyki przemysłowej, sprzęt lotniczy, urządzenia medyczne czy właśnie w zakresie przetwarzania dźwięku.
Uruchomienie serwera audio i odtwarzacza w trybie pracy systemu czasu rzeczywistego daje nam świadomość i pewność najwyższej jakości przetwarzania. Więc jeśli zależy nam na budowie audiofilskiego systemu bez kompromisów, to FreeBSD będzie doskonałym wyborem. W kontekście naszego rozwiązania mówimy o systemie działającym jako transport lub odtwarzacz dźwięku stereo. Nie chodzi tu o zastosowania studyjne, gdzie miksowanie kanałów czy np. współpraca z interfejsem MIDI stawia inny cel wykorzystania RTOS.
Jakość dźwięku we FreeBSD i Linuxie – porównanie
Wielogodzinne testy odsłuchowe jakie prowadziłem wykazały, że systemy FreeBSD i Linux skonfigurowane w trybie bit-perfect zapewniają ten sam poziom jakości brzmienia urządzenia audio. Jednak tym, co przemawia na korzyść FreeBSD jest precyzyjna kontrola wszelkich parametrów procesu obsługi sprzętu na poziomie systemu operacyjnego oraz możliwość ich korekty, dająca nam niemal ostateczny poziom nadzoru i wiedzy.
ALSA – system obsługi dźwięku w Linuxie – w większości dopasowuje wszystkie parametry automatycznie, stąd też można wysnuć wątpliwość, czy tryb bit-perfect włączony interfejsem (lub raczej protokołem) hw:0,0
jest tym, czego oczekujemy. We FreeBSD nie chodzi tylko o intuicyjny parametr dev.pcm.%d.bitperfect
w konfiguracji sterownika dźwięku sound(4)
, ale również pozostałą część możliwości konfiguracyjnych i pełną transparentność.
Obsługa sprzętu audio we FreeBSD i Linuxie
Trzeba jednak przyznać, że jest pomiędzy FreeBSD i Linuxem jest jedna, bardzo istotna różnica. O ile w Linuxie, nawet w trybie bit-perfect (hw:0,0
) praktycznie każda wbudowana karta dźwiękowa lub DAC na USB pracują prawidłowo, nie można tego samego powiedzieć o FreeBSD. Zdarza się, że włączony parametr dev.pcm.%d.bitperfect=1
implikuje problemy. Na przykład jednym z nich jest brak właściwego rozpoznania deskryptorów formatów PCM obsługiwanych przez urządzenie (szczególnie dotyczy układów komunikacji XMOS). Jakiekolwiek wymuszenie parametru, w tym przez dev.pcm.%d.play.vchanformat=s16le:2.0
nie przynosi żądanych efektów. Tak się działo w przypadku testowanego przeze mnie urządzenia Presonus Audiobox iOne. Należy wyłączyć tryb bit-perfect, zostanie wtedy włączony automatycznie stały resampling każdego źródła danych na poziomie 48 kHz. Jednak pod kontrolą Linuxa urządzenia pracują prawidłowo.
Ponadto, z kronikarskiego obowiązku należy wspomnieć o jeszcze jednym problemie, szczególnie dla konfiguracji sprzętowych wykorzystujących urządzenia DAC na USB – losowo, raz na kilkanaście minut pojawiające się zakłócenia, słyszalne kliknięcia podczas odtwarzania. Chociaż nie ma tu reguły – w jednej specyfikacji sprzętowej wszystko będzie OK, w innej już nie. To temat na osobny artykuł, ale jeśli problem się pojawił, to mimo długotrwałych prób z różnymi parametrami opóźnień, buforów, debugowania urządzeń PCM i badania wzajemnej interferencji poszczególnych komponentów, rozwiązania jak na razie nie znalazłem.
Na szczęście, w większości przypadków udaje się we FreeBSD skonfigurować urządzenie audio zgodnie z oczekiwaniami. Mało tego, większość parametrów dobieranych jest przez system out of the box.
Konfiguracja FreeBSD i podsystemu audio
Przejdźmy do konfiguracji ustawień parametrów systemu FreeBSD i jego podsystemu audio. Ustawienia dotyczą najnowszej wersji, czyli FreeBSD 14.2, która od 2024 r. po kilku latach stagnacji wnosi wiele nowości w stosie audio i według zapewnień Fundacji FreeBSD, prace będą kontynuowane.
Rolę serwera audio i odtwarzacza pełni MPD (Music Player Daemon – nazwany jako mpd
w Linuxie i musicpd(1)
we FreeBSD). Interfejsy obsługi serwera MPD to: ncmpcpp(1)
i mpc
(musicpc(1)
we FreeBSD).
Specyfikacja systemu odsłuchowego:
- Komputer: Lenovo ThinkCentre M600 Tiny Thin Client N3010 2×1.04GHz 4GB 16GB SSD
- Dysk: Seagate Expansion SSD 2TB USB
- DAC: Cambridge Audio DacMagic Plus (nowy tor kondensatorów: Panasonic FM, ELNA for Audio; zasilacz Tomanek)
- Kabel USB: WireWorld ULTRAVIOLET 8
- Wzmacniacz słuchawkowy: Forum608 IV Dual Mono (Klasa A)
- Interkonekt RCA: Audioquest Goldengate 0,6m
- Słuchawki: Beyerdynamic 990 Pro 250 Ohm, 990 Edition 600 Ohm
Najczęściej odsłuchiwane płyty:
- Iron Maiden – Fear Of The Dark
- McIntosh Audiophile Test Reference
- Alan Parson Project – Stereotomy
- The WHO – Quadrophenia
- Opeth – Ghost Reveries
- HD Audiophile Speaker Set-Up (192-24)
- TOOL – Lateralus
Pliki konfiguracyjne FreeBSD
Zasadniczo, główna i najważniejsza część konfiguracji systemu FreeBSD oparta jest na trzech plikach konfiguracyjnych: /boot/loader.conf
, /etc/sysctl.conf
, /etc/rc.conf
. Poniżej pozycje, które mają znaczenie w kontekście bit-perfect audio oraz pracy systemu w roli RTOS.
/boot/loader.conf
sysctlinfo_load="YES" mac_priority_load="YES" #hint.pcm.5.eq=1
- Dodanie modułu
sysctlinfo(4)
odpowiedzialnego za rozszerzoną komunikację procesów z poszczególnymi stanami sysctl jądra oraz komponentami drzewa MIB. Nie jest wymagany, jednak z interfejsu korzystają niektóre aplikacje, np.mixertui(8)
. - Moduł
mac_priority(4)
ustanawia zasady planowania uprawnień, dzięki czemu uprzywilejowani użytkownicy mogą korzystać z narzędziartprio(1)
do uruchamiania procesów z priorytetem czasu rzeczywistego. - Parametr odpowiedzialny za włączenie korektora graficznego (equalizera) dla urządzenia
dev.pcm.5
(w podanej wyżej specyfikacji jest to urządzenie USB DAC). Pomijamy go w konfiguracji bit-perfect, o czym dalej, w sekcji Korektor graficzny we 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
- Dość istotny parametr wskazujący na zwiększenie precyzji zegarów programowych używanych do synchronizacji wybudzania procesów, minimalizując liczbę przypadków, w których procesor jest zmuszony do wykonywania stosunkowo kosztownej operacji wchodzenia i wychodzenia ze stanów bezczynności. Dla głębszego zrozumienia faktu opóźnień w wybudzaniu procesów oraz wpływu częstotliwości zegara systemowego na te opóźnienia polecam artykuł Paula Hermana, gdzie oprócz wyników badań dostępny jest również kod źródłowy benchmarku. Aby unaocznić wpływ parametru
kern.timecounter.alloweddeviation
na opóźnienia, poniżej wyniki testu w moim systemie:
# ./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 ...
- Parametr sterownika
snd_uaudio(4)
dla urządzeń USB audio (system ładuje moduł kiedy wykryje kompatybilne urządzenie). Definiuje zakres danych określony w ms zgłoszonych do przetwarzania. Krótsze czasy, oznaczają mniejsze opóźnienia w dostarczaniu danych, jednak z parametrem warto eksperymentować. - Opóźnienie przesyłu danych, o ile program (np. odtwarzacz) z jakichś powodów nie zmieni tej wartości na bardziej korzystną.
- Liczba wirtualnych kanałów odtwarzania / nagrywania. Zależy nam wyłącznie na odtwarzaniu z jednego źródła dlatego wyłączmy wirtualne kanały. Ponadto, opcja ta jest wymagana do włączenia trybu bit-perfect.
- Włączenie trybu bit-perfect, przy jednoczesnym wyłączeniu kanałów wirtualnych, skutkuje pominięciem systemowego układu DSP, zmiany częstotliwości / resamplingu, korekcji equalizera itd.). Czysty strumień danych PCM kierowany jest wprost do urządzenia końcowego audio.
- W przedstawionej specyfikacji sprzętowej urządzeniem audio jest DAC USB, w systemie widoczne jako dev.pcm.5 – ustawiamy je jako domyślne.
- Relatywny parametr poziomu głośności dla sterownika dźwięku, który domyślnie wynosi 45. Pomijalny w trybie bit-perfect, ale znaczący w konfiguracji systemowego korektora graficznego (equalizera), pomijalny w konfiguracji i trybie bit-perfect.
- Pobobnie jak wyżej, relatywny parametr poziomu głośności, tu jednak w odniesieniu do pracy systemowego korektora graficznego (domyślnie +0.0db), pomijalny w trybie bit-perfect. Więcej o znaczeniu parametrów
dev.pcm.%d.eq_preamp
orazhw.snd.vpc_0db
więcej w sekcji Korektor graficzny we FreeBSD.
/etc/rc.conf
musicpd_enable="YES"
- W naszej konfiguracji jako odtwarzacz wykorzystujemy serwer Music Player Daemon (MPD) – włączamy go podczas startu systemu w normalnym trybie. W dalszej części konfiguracji uruchamiamy
musicpd(1)
z priorytetem czasu rzeczywistego.
Polecenia FreeBSD pomocne w badaniu stanu sterowników, parametrów jądra (sysctl) oraz podsystemu audio
Za pomocą poniższej komendy możemy wyświetlić listę załadowanych modułów jądra i upewnić się, że są na niej dopisane przez nas komponenty:
# kldstat
Wynik powinien być zbliżony do poniższego:
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
Poniższe polecenie wskaże zainstalowane w komputerze urządzenia audio:
# cat /dev/sndstat
Przykład listy urządzeń audio wykrytych przez 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.
Paramter jądra hw.snd.verbose
domyślnie przyjmuje wartość 0, ustawiając go na wyższy, zwiększamy liczbę dostępnych informacji uzyskanych poprzez interfejs ioctl:
# sysctl hw.snd.verbose=4
# cat /dev/sndstat
Kolejne polecenie wyświetla więcej szczegółów na temat urządzeń audio (na listingu przedstawione tylko interesujące nas urządzenie):
... 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} ...
Status interfejsu komunikacyjnego konkretnego urządzenia USB wywołamy poleceniem usbconfig(8)
(w tym przypadku fizyczny adres ugen0.3
odpowiada reprezentowanemu w systemie dev.pcm.5
):
# usbconfig -d ugen0.3 dump_device_desc
Szczegółowe dane interfejsu interesującego nas urządzenia USB:
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
Parametry sysctl interfejsu łączącego sterownik sound(4)
ze sterownikiem PCM urządzenia audio:
# sysctl hw.snd
Wynik powinien być podobny do poniższego:
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 i dane sterownika wybranego urządzenia audio:
# sysctl dev.pcm.5
Poniższy listing zapewnia nas, między innymi o tym, że tryb bit-perfect jest na pewno włączony (właściwe dla tego trybu parametry: dev.pcm.%d.bitperfect=1
, dev.pcm.%d.play.vchans=0
) oraz aktualnie przetwarzanych danych o częstotliwości 44098 MHz:
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
Uruchomienie odtwarzacza muzycznego MPD czasie rzeczywistym systemu FreeBSD
W sekcji Konfiguracja FreeBSD i podsystemu audio przygotowaliśmy system do pracy jako system czasu rzeczywistego, tzn. załadowany został moduł mac_priority(4)
oraz zminimalizowane do minimum opóźnienia przetwarzania procesów wykorzystując parametr kern.timecounter.alloweddeviation
. Uruchomienie serwera i odtwarzacza MPD (Music Player Daemon) w harmonogramie czasu rzeczywistego systemu realizujemy za pomocą polecenia rtprio(1)
. Wcześniej jednak, musimy wyłączyć usługę musicpd(1)
uruchamianą w trakcie startu systemu:
# service musicpd stop
# rtprio 0 musicpd /usr/local/etc/musicpd.conf
W systemie FreeBSD najwyższy priorytet czasu rzeczywistego ma wartość 0. Priorytety są numerowane od 0 do RTP_PRIO_MAX (zwykle 31), gdzie niższa wartość oznacza wyższy priorytet.
Aby zweryfikować, czy serwer MPD działa w czasie rzeczywistym i z właściwym priorytetem, przeglądamy za pomocą ps
listę procesów, zawężając wynik odpowiedzi do procesu musicpd(1)
:
# ps -o rtprio -axl | grep [m]usicpd
Odpowiedź polecenia ps
powinna wyglądać tak:
real:0 137 1146 1 0 -52 0 415080 214420 select I<s - 0:06.55 musicpd /usr/local/etc/musicpd.conf
Inny sposób na sprawdzenie poprawnego uruchomienia musicpd(1)
w czasie rzeczywistym z użyciem komendy top(1)
:
# 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
Dodatkowe polecenia we FreeBSD pomocne przy debugowaniu i rozwiązywaniu problemów z urządzeniem USB audio
# 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 ...
Korektor graficzny (equalizer) we FreeBSD
W sterowniku dźwięku systemu FreeBSD (sound(4)
) zimplementowano prosty, programowy korektor graficzny (equalizer), który w czasie rzeczywistym umożliwia regulację tonów niskich i wysokich. Domyślna kompilacja jądra zakłada regulację dla częstotliwości: 62 Hz i 16 kHz, możemy je zmienić kompilując jądro z innymi parametrami. Aby włączyć korektor, ustawiamy parametr hint.pcm.%d.eq
w pliku /boot/loader.conf
(wymagane jest przeładowanie systemu):
#/boot/loader.conf ... hint.pcm.5.eq=1
Włączenie equalizera za pomocą opcji hint.pcm.%d.eq
sprawi, że w aplikacjach miksera pojawią się dodatkowe kontrolki dla tonów niskich i wysokich. Możemy je parametryzować za pomocą wizualnej aplikacji mixertui(1)
lub za pomocą systemowej mixer(1)
, np.:
mixer -f /dev/mixer5 vol=0.75 pcm=0.75 bass=0.82 treble=0.76
W odpowiedzi otrzymując zadane wartości i ich 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
Włączenie i operowanie parametrami korektora graficznego wiąże się oczywiście z ingerencją w sygnał audio. Dlatego po włączeniu equalizera tryb bitperfect zostanie automatycznie wyłączony przez sterownik dźwięku:
# sysctl dev.pcm.5 | grep bitperfect
Wynik:
dev.pcm.5.bitperfect: 0
Korekcja dźwięku może potencjalnie wprowadzać pewne zakłócenia lub ryzyko degradacji dźwięku, szczególnie jeśli stosowana jest w nadmiarze. Aby temu zapobiec, dostępne są w sterowniku dźwięku FreeBSD dwa parametry: hw.snd.vpc_0db
oraz dev.pcm.%d.eq_preamp
(nie opisany jeszcze w oficjalnej dokumentacji). Oba parametry ustawiają relatywny poziom głośności na poziom “zero”, odpowiednio dla sterownika dźwięku i equalizera. Ogólnie rzecz biorąc, dają więcej przestrzeni na obliczenia korekcji dźwięku, tak by przebiegała bez zakłóceń:
hw.snd.vpc_0db
– domyślnie włączony z wartością 45. Zwiększanie tego parametru (czyli obniżenie poziomu głośności) daje większy zakres dla przetwarzanych po korekcji częstotliwości.dev.pcm.%d.eq_preamp
– domyślnie przyjmuje wartość 0, z zakresem od -9 dB do +9 dB. Przykładowo, ustawienie poziomu -5 sprawi, że najpierw cały strumień audio zostanie stłumiony do -5 dB (minus +max dB), a dalsze wzmocnienie jest procesem względem tego punktu (0 dB). Spowoduje to obniżenie głośności z perspektywy słuchacza, jednak jak wyżej, daje większą możliwość kompensacji ewentaulnych artefaktów wynikających z przetwarzania nadmiernie wzmocnionych przez korekcję częstotliwości.
Parametry najlepiej stosować zamiennie, podajemy je w pliku /etc/sysctl.conf
, ale możemy również wprowadzić w czasie rzeczywistym.
Przykłady:
# 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
Wysokiej jakości equalizer – filtry FFmpeg
Korzystanie z equalizera dźwięku w systemie audio hi-fi, jest tematem, który budzi różne opinie wśród audiofilów. Mamy z jednej strony purystyczne podejście, w którym dźwięk powinien być odtwarzany w jak najbardziej naturalny sposób i bez żadnych modyfikacji. Z kolei praktyczne podejście sugeruje użycie korektora graficznego i dostosowanie dźwięku do swoich preferencji, warunków akustycznych pomieszczenia czy niwelujące niedoskonałości sprzętu audio.
Możemy również pójść na kompromis, czyli wykorzystać equalizer z umiarem, starając się znaleźć złoty środek między naturalnym brzmieniem a dostosowaniem dźwięku do swoich potrzeb. Odpowiedniej jakości korektor graficzny może poprawić jakość odsłuchu bez wprowadzania znaczących zniekształceń.
Takim rozwiązaniem są doskonałej jakości zaawansowane filtry bibliotki libavfilter projektu FFmpeg. Łatwo możemy je zaimplementować w odtwarzaczu MPD, gdzie rolę dekodera sygnału również pełni FFmpeg. MPD dostępne w repozytorium portów FreeBSD posiada wbudowane biblioteki filtrów libavfilter. W systemie Debian 12, należy uaktualnić MPD z repozytorium backports
.
Oczywiście, wykorzystując equalizer nie możemy mówić o pełnym trybie bitperfect, ale w naszej konfiguracji sygnał bitperfect przekazujemy w łańcuchu danych do dekodera FFmpeg i przez filtry libavfilter dostarczamy do urządzenia DAC lub karty dźwiękowej. Ten rodzaj korektora graficznego pod względem brzmieniowym jest znacznie lepszym rozwiązaniem niż systemowy equalizer sterownika dźwięku zaimplementowany w sterowniku sound(4)
FreeBSD i wtyczce alsaequal
w Linuxie.
Przed wdrożeniem filtrów FFmpeg we FreeBSD i Linuxie, warto również pamiętać o wyłączeniu systemowego equalizera.
Konfiguracja MPD z wykorzystaniem filtórw FFmpeg
Wykorzystując FFmpeg i bibliotekę libavfilter w roli korektora graficznego odtwarzacza MPD, najbardziej interesują nas filtry: bass
, treble
i anequalizer
. W ten sposób zrealizujemy wysokiej jakości programowy equalizer nie tylko w systemie FreeBSD, ale również w Linuxie. Ponadto, oprócz walorów brzmieniowych, filtry FFmpeg będą również przydatne w systemie streamingowym na bazie MPD.
Aby włączyć filtr dopisujemy w pliku konfiguracji MPD musicpd.conf
nową sekcję filter {}
, która zawiera definicję filtra (lub filtrów) oraz dodajemy filtr w sekcji audio_output {}
. Ponadto, upewniamy się, że parametry mixer_type
i replay_gain_handler
mają właściwe dla trybu bit-perfect parametry. Konfigurację systemu pozostawiamy według scenariusza przedstawionego w części Konfiguracja FreeBSD i podsystemu audio.
FFmpeg – filtry bass i treble
Przykład łączonych filtrów bass
i treble
:
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" }
Opis filtrów:
bass
– częstotliwość 62 Hz na szerokości 120 Hz wzmacniamy o 10 punktów stosując precyzję zmiennoprzecinkową operując na danych 64 bitowych;treble
– częstotliwość 16 kHz wzmacniamy o 3 punkty na szerokości 8 kHz stosując precyzję zmiennoprzecinkową operując na danych 64 bitowych.
n
, który odpowiada za normalizację sygnału. Najprościej mówiąc, w czasie rzeczywistym automatycznie obniża amplitudę sygnału (głośność), dając większy zakres obliczeniom unikając zniekształceń i artefaktów.Wizualizacja charakterystyki częstotliwościowej na podstawie powyższych filtów:
FFmpeg – filtr anequalizer
Jeszcze jeden filtr biblioteki FFmpeg wart jest uwagi, mianowicie anequalizer
. To wielokanałowy, parametryczny korektor dźwięku oparty na analogowych filtrach Czebyszewa i Butterwortha (sugerowany w zastosowaniach audio ze względu na mniej zniekształcony sygnał w paśmie przepustowym). Współczynniki filtra anequalizer
są obliczalne w kategoriach częstotliwości środkowej, zysku szczytowego, szerokości pasma i zysku szerokości pasma.
Definicja charakterystyki przedstawionej powyżej z użyciem filtrów bass
i treble
zbudowana za pomocą anequalizer
dla MPD, będzie wyglądać tak:
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" }
Jak widać, za pomocą filtra anequalizer
możemy budować niemal dowolną charakterystrykę korektora graficznego. Z jednym zastrzeżeniem – brakuje tu opcji normalizacji przetwarzanego sygnału, wykluczającej zniekształcenia wynikające z jego przetwarzania przez filtr. A te słychać na poziomie 3 wzmocnienia parametru g
. Nie mają tu zastosowania parametry sterownika dźwięku, np. hw.snd.vpc_0db
, ponieważ amplituda sygnału będzie zmniejszona przez sterownik dopiero po procesie filtrowania. Jedynym rozwiązaniem, jest użycie programowego miksera głośności w MPD. Przy wartości 40% zniekształcenia nie są słyszalne, nawet przy wartości g=10
, chociaż nie jest to najlepszy sposób uzyskania idealnego brzmienia.
Programowy mixer głośności w MPD ustawiamy za pomocą parametru mixer_type
, jak poniżej:
mixer_type "software"
Projektowanie charakterystyki filtra anequalizer
Przebieg charakterystyki filtra anequalizer
i jego parametrów możemy zaprojektować oraz zwizualizować za pomocą edytora DSP fimy Intona.
Odpowiednikiem definicji:
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"
będzie w aplikacji DSP:
peq 62Hz q0.51 10dB peq 16kHz q2 3dB
Parametr q
(Q factor) względem podanego w definicji w
wyznaczamy z zależności:
Zachęcam do zaprojektowania korektora graficznego odpowiadającego własnym preferencjom.
W artykule poruszyłem takie tematy jak: konfiguracja systemu FreeBSD i jego podsystemu audio dla uzyskania najlepszej jakości dźwięku, omówiłem kilka aspektów architektury procesów w tym harmonogramu czasu rzeczywistego systemu FreeBSD, tryb bit-perfect sygnału, a także jak włączyć systemowy equalizer i poprawnie go skonfigurować pod kątem jakości przetwarzania audio. Na koniec przedstawiłem realizację wysokiej jakości korektora graficznego w odtwarzaczu MPD za pomocą filtrów FFmpeg (rozdział ten polecam również użytkownikom Linuxa). Końcowy etap toru audio i jakości uzyskanego dźwięku zależy już od specyfikacji sprzętowej: karty muzycznej, przetwornika DAC, słuchawek, wzmacniacza, kolumn itd. Wiec można powiedzieć, że w tym miejscu przygodę z dźwiękiem rozpoczynamy od nowa 😉