Konwersja z 48 na 44,1 kHz: aliasing, utrata wysokich tonów i szczyty w swr i soxr, pomiar

Spis treści
- Jak wykonano pomiar
- Pasmo przepustowe: domyślne ustawienie ffmpeg tłumi już poniżej 20 kHz
- Powyżej 22,05 kHz: aliasing od −9,5 do poniżej −180 dB
- Szczyty: true peak pozostał, sample peak wzrósł nawet o 1,3 dB
- Pre-ringing i czas obliczeń: niewielkie różnice
- Co z tego wynika dla eksportu
- Kontekst i ograniczenia
- Pytania i odpowiedzi
- Źródła
FL Studio eksportuje z częstotliwością próbkowania projektu. Okno eksportu nie ma do tego własnego ustawienia; według podręcznika to ustawienie znajduje się w Audio Settings. Gdy projekt działa z 48 kHz, a potrzebny jest plik 44,1 kHz, resampler przelicza próbki. Przy obniżaniu częstotliwości próbkowania musi najpierw usunąć to, co leży powyżej połowy nowej częstotliwości, czyli przy 44,1 kHz wszystko powyżej 22,05 kHz: Julius O. Smith opisuje, że granica filtra dolnoprzepustowego przesuwa się w tym celu poniżej połowy nowej, niższej częstotliwości próbkowania. To, co pozostaje powyżej, odbija się jako aliasing w zakres poniżej.
Pomiar porównuje dwa resamplery dostępne w ffmpeg: własny swr z trzema długościami filtra, w tym domyślną, oraz SoX Resampler soxr w dwóch poziomach jakości. Zmierzono tony sinusoidalne, pojedynczy impuls i dwa głośne mastery z miksu testowego z pomiaru True peak po kodowaniu, tym razem wygenerowane przy 48 kHz.

Jak wykonano pomiar
- Metody: ffmpeg 7.1.5, filtr aresample z wyjściem 44,1 kHz w 32-bitowym formacie zmiennoprzecinkowym. swr z filter_size 16, 32 (domyślnie) i 128, soxr z precision 20 (domyślnie, według dokumentacji „High Quality” SoX) i 28 („Very High Quality”). Granica filtra wszędzie pozostała domyślna: w swr 0,97 połowy częstotliwości próbkowania jako punkt −6 dB, w soxr 0,91 jako punkt 0 dB.
- Kontrole:
-ar 44100bez dalszych opcji dało te same wartości próbek co aresample z ustawieniami domyślnymi. Bez procedur NEON komputera ARM (-cpuflags 0) największe odchylenie w swr leżało 131 dB poniżej poziomu tonów, w soxr nie było żadnego. - Tony sinusoidalne: każdy przez sekundę z −6 dBFS przy 48 kHz, analizowane w środkowej połowie sekundy metodą najmniejszych kwadratów. Tony od 1 do 22 kHz pokazują poziom w paśmie przepustowym. Tony od 22,5 do 23,9 kHz leżą powyżej nowej częstotliwości Nyquista 22,05 kHz; zmierzono, co z nich dociera przy 44,1 kHz minus częstotliwość tonu.
- Pojedynczy impuls: czas trwania pre-ringingu przed głównym szczytem do −60 i −100 dB.
- Mastery: miks testowy, wygenerowany ponownie przy 48 kHz, raz z limiterem na −9 LUFS i −1 dBTP, raz twardo obcięty przy −1 dBFS do −8 LUFS. Hi-haty z filtrowanego szumu sięgają 24 kHz; udział powyżej 20 kHz leżał 28,5 i 27,3 dB poniżej całkowitej energii. True peak według ITU-R BS.1770-5 i pomiar kontrolny 16-krotny, do tego sample peak i liczba próbek powyżej 0 dBFS.
- Czas obliczeń: master z limiterem przekonwertowany trzy razy każdą metodą na Raspberry Pi 4, liczony najkrótszy czas łącznie z odczytem i zapisem plików.
Pasmo przepustowe: domyślne ustawienie ffmpeg tłumi już poniżej 20 kHz
| Metoda | 18 kHz | 19 kHz | 20 kHz | 20,5 kHz | 21 kHz |
|---|---|---|---|---|---|
| swr, filter_size 16 | −0,81 dB | −1,67 dB | −3,03 dB | −3,95 dB | −5,04 dB |
| swr, domyślnie (filter_size 32) | −0,01 dB | −0,22 dB | −1,28 dB | −2,43 dB | −4,18 dB |
| swr, filter_size 128 | 0,00 dB | 0,00 dB | 0,00 dB | 0,00 dB | −1,01 dB |
| soxr, domyślnie (precision 20) | 0,00 dB | 0,00 dB | −0,01 dB | −0,07 dB | −3,75 dB |
| soxr, precision 28 | 0,00 dB | 0,00 dB | 0,00 dB | −0,03 dB | −4,06 dB |
Z ustawieniami domyślnymi swr stracił 0,22 dB przy 19 kHz i 1,28 dB przy 20 kHz, z filter_size 16 przy 20 kHz było to już 3,03 dB. Z filter_size 128 i z oboma poziomami soxr poziom pozostał do 20 kHz w granicach 0,01 dB, a do 20,5 kHz w granicach 0,07 dB; gwałtowny spadek zaczyna się dopiero powyżej.
Powyżej 22,05 kHz: aliasing od −9,5 do poniżej −180 dB
| Metoda | Ton 22,5 kHz, alias przy 21,6 kHz | Ton 23 kHz, alias przy 21,1 kHz | Ton 23,5 kHz, alias przy 20,6 kHz | Ton 23,9 kHz, alias przy 20,2 kHz |
|---|---|---|---|---|
| swr, filter_size 16 | −9,5 dB | −11,5 dB | −13,8 dB | −15,8 dB |
| swr, domyślnie (filter_size 32) | −14,3 dB | −19,9 dB | −27,1 dB | −34,4 dB |
| swr, filter_size 128 | −96,2 dB | −94,7 dB | −104,0 dB | −97,9 dB |
| soxr, domyślnie (precision 20) | −136,6 dB | −148,6 dB | −141,6 dB | −162,2 dB |
| soxr, precision 28 | poniżej −180 dB | poniżej −180 dB | poniżej −180 dB | poniżej −180 dB |
Ton 22,5 kHz nie mieści się w zakresie pliku 44,1 kHz; jeśli pozostanie, pojawia się odbity przy 21,6 kHz. Domyślny swr stłumił go tylko o 14,3 dB, filter_size 16 o 9,5 dB. Dopiero dalej od częstotliwości Nyquista tłumienie rosło, w ustawieniu domyślnym do 34,4 dB dla 23,9 kHz. swr z filter_size 128 osiągnął od 94,7 do 104,0 dB, soxr od 136,6 do 162,2 dB, a z precision 28 ponad 180 dB. Smith wskazuje cenę stromych filtrów: przy danym tłumieniu zaporowym filtr dolnoprzepustowy potrzebuje mniej więcej dwa razy więcej obliczeń na próbkę przy każdym zmniejszeniu pasma przejściowego o połowę.
Szczyty: true peak pozostał, sample peak wzrósł nawet o 1,3 dB
| Master | True peak 4-krotnie | True peak 16-krotnie | Sample peak | Próbki powyżej 0 dBFS |
|---|---|---|---|---|
| Limiter, −9 LUFS, −1 dBTP: Master przy 48 kHz | −1,05 dBTP | −0,79 dBTP | −2,31 dBFS | 0 |
| Limiter: swr, filter_size 16 | −1,16 dBTP | −1,07 dBTP | −1,53 dBFS | 0 |
| Limiter: swr, domyślnie (filter_size 32) | −1,03 dBTP | −0,96 dBTP | −1,44 dBFS | 0 |
| Limiter: swr, filter_size 128 | −1,04 dBTP | −0,98 dBTP | −1,35 dBFS | 0 |
| Limiter: soxr, domyślnie (precision 20) | −1,05 dBTP | −0,95 dBTP | −1,40 dBFS | 0 |
| Limiter: soxr, precision 28 | −1,05 dBTP | −0,95 dBTP | −1,41 dBFS | 0 |
| Twarde obcinanie przy −1 dBFS, −8 LUFS: Master przy 48 kHz | +0,38 dBTP | +0,72 dBTP | −1,00 dBFS | 0 |
| Twarde obcinanie przy −1 dBFS: swr, filter_size 16 | +0,28 dBTP | +0,38 dBTP | +0,01 dBFS | 2 |
| Twarde obcinanie przy −1 dBFS: swr, domyślnie (filter_size 32) | +0,41 dBTP | +0,54 dBTP | +0,18 dBFS | 18 |
| Twarde obcinanie przy −1 dBFS: swr, filter_size 128 | +0,47 dBTP | +0,64 dBTP | +0,27 dBFS | 41 |
| Twarde obcinanie przy −1 dBFS: soxr, domyślnie (precision 20) | +0,45 dBTP | +0,64 dBTP | +0,26 dBFS | 42 |
| Twarde obcinanie przy −1 dBFS: soxr, precision 28 | +0,44 dBTP | +0,64 dBTP | +0,26 dBFS | 44 |
Głośność pozostała przy wszystkich konwersjach taka sama (rozdzielczość 0,1 LU). True peak mierzony 4-krotnie zmienił się najwyżej o 0,11 dB, w pomiarze kontrolnym 16-krotnym spadł o 0,08 do 0,34 dB, najbardziej z filter_size 16, który najmocniej tłumi wysokie tony. Próbki natomiast trafiały po konwersji w inne miejsca przebiegu. W masterze z limiterem sample peak wzrósł z −2,31 nawet do −1,35 dBFS. Twardo obcięty master nie miał przy 48 kHz żadnej próbki powyżej −1,00 dBFS, a po konwersji od 2 do 44 próbek leżało powyżej 0 dBFS, z soxr 42 i 44. W pliku 16- lub 24-bitowym takie wartości zostają obcięte. Granica na próbkach przy 48 kHz nie chroni więc pliku 44,1 kHz; true peak pliku 48 kHz pokazał natomiast już wcześniej, jak wysoko mogą sięgać wartości.
Pre-ringing i czas obliczeń: niewielkie różnice
| Metoda | Czas obliczeń dla 32 s stereo | szybciej niż w czasie rzeczywistym | Pre-ringing do −60 dB | do −100 dB |
|---|---|---|---|---|
| swr, filter_size 16 | 0,50 s | 64-krotnie | 0,14 ms | 0,18 ms |
| swr, domyślnie (filter_size 32) | 0,55 s | 58-krotnie | 0,27 ms | 0,36 ms |
| swr, filter_size 128 | 0,81 s | 39-krotnie | 0,68 ms | 1,41 ms |
| soxr, domyślnie (precision 20) | 0,70 s | 46-krotnie | 0,98 ms | 1,93 ms |
| soxr, precision 28 | 0,79 s | 40-krotnie | 1,32 ms | 2,27 ms |
Przy wszystkich pięciu metodach drgania przed impulsem i po nim trwały tak samo długo, jak w filtrach o fazie liniowej. Do −60 dB pre-ringing trwał od 0,14 ms z filter_size 16 do 1,32 ms z soxr i precision 28, do −100 dB najwyżej 2,27 ms. Dokładniejsze metody kosztowały na Raspberry Pi 4 niewiele czasu: 32 sekundy stereo zajęły z domyślnym swr 0,55 s, z soxr 0,70 s, a z precision 28 0,79 s, za każdym razem łącznie z odczytem i zapisem plików.
Co z tego wynika dla eksportu
- Dla pliku 44,1 kHz z eksportu 48 kHz
-af aresample=44100:resampler=soxrzmienił poziom do 20 kHz najwyżej o 0,01 dB i stłumił składowe powyżej 22,05 kHz o co najmniej 137 dB;:precision=28kosztowało 0,1 s więcej. - Samo
-ar 44100korzysta z domyślnego swr: 1,3 dB mniej przy 20 kHz i tylko 14 dB tłumienia dla składowych tuż powyżej 22,05 kHz. W obrębie swr filter_size=128 obniżył odchylenie do 20 kHz poniżej 0,01 dB, a tłumienie podniósł do 95–104 dB. - Dla szczytów po konwersji miarodajny jest true peak pliku 48 kHz, a nie jego sample peak. Miernik LUFS i true peak mierzy oba w przeglądarce.
- Konwersja do 16 bitów z ditheringiem następuje jako ostatni krok po konwersji częstotliwości próbkowania; opisuje to artykuł Dither przy eksporcie do 16 bitów.
- Tę samą zasadę opisuje podręcznik FL Studio dla interpolacji przy transpozycji sampli: interpolacja liniowa może wywołać aliasing, a do finalnego renderu podręcznik zaleca ustawienia powyżej 64-point Sinc, jeśli przy prostszych metodach aliasing jest słyszalny. Ustawienie omawia poradnik masteringu w FL Studio.
Kontekst i ograniczenia
Pomiar objął resamplery w ffmpeg, a nie konwersję w FL Studio ani w innych programach. Miks testowy jest syntetyczny; jego hi-haty z filtrowanego szumu sięgają 24 kHz, a wiele nagrań zawiera powyżej 20 kHz mniej. Test odsłuchowy nie był częścią pomiaru: odbite składowe trafiają między 20,2 a 21,6 kHz, a to, czy są tam słyszalne, zależy od materiału, słuchu i odtwarzania. Czasy obliczeń dotyczą Raspberry Pi 4 użytego do pomiaru; na innym sprzęcie wartości bezwzględne będą inne.
Pytania i odpowiedzi
Dlaczego to właśnie dokładniejszy resampler daje w twardo obciętym masterze więcej próbek powyżej 0 dBFS?
Bo wierniej odtwarza przebieg między próbkami. Twarde obcinanie przy −1 dBFS tworzy krawędzie ze składowymi sięgającymi górnej granicy pasma, a przebieg opisany przez te próbki wychyla się między nimi ponad próg obcinania: true peak pliku 48 kHz wyniósł w pomiarze 16-krotnym +0,72 dBTP, choć żadna próbka nie przekroczyła −1,00 dBFS.
Resampler oblicza nowe próbki w innych chwilach, odczytuje więc ten przebieg w nowych miejscach i trafia przy tym także w punkty bliskie szczytom. Im bardziej płaskie jest jego pasmo przepustowe, tym więcej zostaje wysokich tonów, z których biorą się te wychylenia. filter_size 16 tłumi już przy 20 kHz o 3,03 dB, wygładza tym samym szczyty i dał 2 próbki powyżej 0 dBFS; soxr i filter_size 128 zostawiają górę pasma i dały od 41 do 44.
Problem tkwi więc w masterze, a nie w resamplerze. Miarodajny jest true peak pliku 48 kHz: jeśli plik zostanie obniżony tak, by jego true peak leżał z niewielkim zapasem poniżej 0 dBTP, albo jeśli ograniczanie nastąpi dopiero po konwersji, próbki pliku 44,1 kHz pozostaną poniżej 0 dBFS, także przy 16 lub 24 bitach.
Czy aliasing swr da się usunąć niższą częstotliwością graniczną zamiast większego filter_size?
Tylko kosztem góry pasma. Częstotliwość graniczna, w swr punkt −6 dB przy 0,97 połowy częstotliwości próbkowania, czyli około 21,4 kHz, wyznacza położenie pasma przejściowego; filter_size wyznacza jego szerokość. Przy domyślnej wartości 32 jest ono tak szerokie, że sięga zarazem poniżej 20 kHz i powyżej 22,05 kHz: stąd strata 1,28 dB przy 20 kHz i tylko 14,3 dB tłumienia przy 22,5 kHz.
Niższa częstotliwość graniczna jedynie przesuwa to szerokie pasmo w dół. Tłumienie tuż powyżej 22,05 kHz wtedy rośnie, ale jednocześnie rośnie strata poniżej 20 kHz; tego nie mierzono, wynika to z położenia pasma przejściowego. Węższe przejście daje dopiero dłuższy filtr, i dokładnie to opisuje reguła Smitha: każde zmniejszenie pasma przejściowego o połowę kosztuje mniej więcej dwa razy więcej obliczeń na próbkę. Na Raspberry Pi użytym do pomiaru ta cena była niewielka: filter_size 128 potrzebował 0,81 zamiast 0,55 s na 32 sekundy stereo.
Czy ma znaczenie, czy konwersja do 16 bitów następuje przed konwersją do 44,1 kHz, czy po niej?
Tak. Resampler oblicza nowe próbki, które nie leżą już na siatce 16 bitów, więc jego wynik trzeba zaokrąglić drugi raz, bez pasującego ditheringu albo z drugą warstwą szumu. Dochodzą do tego próbki powyżej 0 dBFS, które mogą powstać przy konwersji i które plik 16-bitowy obcina. Dlatego konwersja do 16 bitów z ditheringiem jest ostatnim krokiem.
Źródła
- FFmpeg Resampler Documentation
- ffmpeg Documentation
- Implementation – Digital Audio Resampling Home Page (Julius O. Smith III)
- Theory of Ideal Bandlimited Interpolation – Digital Audio Resampling Home Page (Julius O. Smith III)
- Exporting Audio & MIDI – FL Studio Online Manual
- ITU-R BS.1770: Algorithms to measure audio programme loudness and true-peak audio level