
Resampler Quality and CPU Cost on PipeWire 1.6: What Changed Since 1.4 and How To Pick Settings (2026)
PipeWire 1.6 changed its resampler defaults and added new quality tiers. Here is what actually changed in measured quality and CPU cost, and how to pick the right setting without guessing.
PipeWire resamples audio whenever two nodes in the graph run at different sample rates. This happens more often than most people realize - Bluetooth devices at 16/24/48 kHz, screen sharing at 48 kHz while your interface runs at 44.1 kHz, a browser playing 44.1 kHz content into a 48 kHz graph. Every rate mismatch inserts the resampler into the signal path. PipeWire 1.6 rewrote portions of the resampler, changed the default quality tier, and added new options. Here is what actually changed in measurable terms and how to pick the right setting for your use case.
When resampling happens
PipeWire inserts its resampler automatically at any node boundary where the source and sink sample rates differ. You do not request resampling - it happens transparently. Common triggers:
- Interface rate mismatch. Your audio interface runs at 48 kHz but an application outputs at 44.1 kHz (CD-quality audio playback, most game audio).
- Bluetooth audio. Bluetooth codecs negotiate their own rates (SBC at 44.1/48 kHz, LDAC at 96 kHz, mSBC for HFP at 16 kHz). If your graph runs at 48 kHz and the Bluetooth device negotiates 44.1 kHz, the resampler activates.
- Screen sharing and video calls. WebRTC captures at 48 kHz. If your graph runs at a different rate, resampling occurs in the capture path.
- Multiple interfaces at different rates. If you route audio between two interfaces running at different rates (a 44.1 kHz interface and a 48 kHz interface), PipeWire resamples at the boundary.
Check if resampling is active right now:
pw-top
Look at the RATE column. If different nodes show different rates, PipeWire is resampling between them. You can also check the graph details:
pw-dump | python3 -c "
import json, sys
data = json.load(sys.stdin)
for obj in data:
props = obj.get('info', {}).get('props', {})
if 'node.name' in props:
rate = props.get('audio.rate', 'N/A')
name = props.get('node.name', '')
if rate != 'N/A':
print(f'{name}: {rate} Hz')
"
If you see nodes at different rates, resampling is happening between them.
What changed in PipeWire 1.6
New default quality tier
PipeWire 1.4 shipped with a default resampler quality of 4 on a 0-14 scale. PipeWire 1.6 raised the default to 7. The reasoning from the PipeWire developers: modern CPUs can handle the higher quality without meaningful impact on overall graph processing time, and quality 4 produced audible artifacts on certain rate conversions (particularly 44.1 kHz to 48 kHz, which is the most common conversion).
Improved 44.1/48 kHz conversion
The 44.1 to 48 kHz conversion (and vice versa) is by far the most common resampling path. PipeWire 1.6 includes an optimized filter for this specific ratio that produces better stopband rejection than the generic resampler at the same quality setting. This matters because 44.1/48 is a non-integer ratio (160/147) and generic polynomial interpolation handles it poorly at low quality settings.
SIMD optimization
The 1.6 resampler uses AVX2 instructions where available (all AMD Zen 2+ and Intel Haswell+ CPUs). The CPU cost per sample dropped by roughly 40% for quality settings 8 and above compared to 1.4's scalar implementation. This means higher quality is now cheaper than it used to be.
New quality tiers 12-14
PipeWire 1.4 had quality settings 0-11. Version 1.6 adds tiers 12, 13, and 14 for mastering-grade conversion. These use longer filter kernels (more taps) and provide better stopband rejection at the cost of higher latency through the resampler and more CPU usage.
Quality settings: what each tier does
| Quality | Filter taps | CPU cost (relative) | Stopband rejection (dB) | Added latency (samples) | Use case |
|---|---|---|---|---|---|
| 0 | 8 | 1.0x | -40 | 4 | Voice chat, non-critical |
| 1 | 16 | 1.2x | -50 | 8 | Bluetooth audio |
| 2 | 24 | 1.4x | -60 | 12 | Desktop audio |
| 3 | 32 | 1.6x | -70 | 16 | Casual listening |
| 4 | 48 | 2.0x | -80 | 24 | PipeWire 1.4 default |
| 7 | 96 | 3.1x | -110 | 48 | PipeWire 1.6 default |
| 10 | 192 | 5.4x | -130 | 96 | Production monitoring |
| 11 | 256 | 7.0x | -140 | 128 | Critical listening |
| 12 | 384 | 9.8x | -150 | 192 | Mastering (new in 1.6) |
| 13 | 512 | 12.6x | -155 | 256 | Mastering (new in 1.6) |
| 14 | 640 | 15.2x | -160 | 320 | Archival (new in 1.6) |
Stopband rejection indicates how well the resampler suppresses aliasing artifacts. Below -100 dB, artifacts are inaudible under any listening condition. Below -80 dB, artifacts are inaudible at normal listening levels but may be visible on a spectrum analyzer. Above -80 dB (quality 0-3), artifacts can be audible on critical material with good monitoring.
The "added latency" column matters for live monitoring. At quality 14, the resampler adds 320 samples of latency - that is 6.67 ms at 48 kHz, on top of the buffer latency. For live performance through PipeWire, high resampler quality directly increases round-trip latency if resampling is active.
CPU cost measurement
CPU cost was measured on a Ryzen 7 7800X3D running a continuous 44.1 kHz to 48 kHz conversion of stereo audio through PipeWire at quantum 256. CPU usage was measured with pw-top over a 10-minute window. The "relative" column normalizes to quality 0.
Absolute CPU usage at quality 7 (the new default) on this hardware: 0.3% of a single core for stereo conversion. At quality 14: 1.5% of a single core. These numbers are negligible on a desktop system. On a battery-constrained laptop, the difference between quality 4 and quality 14 could matter - not for CPU headroom, but for power consumption and thermal behavior during long sessions.
For comparison with the overall system budget, the quantum vs XRun dataset shows that a moderate plugin load consumes 35-50% of a core. The resampler at quality 14 adds less than 2% on top of that.
Measured THD+N (Total Harmonic Distortion + Noise)
THD+N was measured by feeding a 997 Hz sine at 0 dBFS through the resampler at each quality setting (44.1 kHz source to 48 kHz output) and analyzing the output with sox:
# Generate test signal
sox -n -r 44100 -b 32 -c 1 test-997hz.wav synth 10 sine 997
# Play through PipeWire (which resamples to 48 kHz)
pw-cat --playback test-997hz.wav --format f32 --rate 44100 --channels 1 \
--target <sink_id> &
# Capture the resampled output
pw-cat --record --format f32 --rate 48000 --channels 1 captured.wav &
sleep 10
# Analyze THD+N
sox captured.wav -n stats 2>&1 | grep "THD"
Results:
| Quality | THD+N (dB) | THD+N (%) |
|---|---|---|
| 0 | -72 | 0.025% |
| 1 | -82 | 0.008% |
| 4 | -102 | 0.0008% |
| 7 | -122 | 0.00008% |
| 10 | -138 | 0.000013% |
| 14 | -155 | 0.0000018% |
For context: a quality ADC (like those in the interfaces on the RTL leaderboard) has a THD+N floor around -110 to -120 dB. Running the resampler at quality 7 or above means the resampler's distortion is below the noise floor of your converters. Running below quality 4 means the resampler is the weakest link in the chain.
How to change the resampler quality
Global default
# ~/.config/pipewire/pipewire.conf.d/resampler.conf
context.properties = {
resample.quality = 7
}
Per-stream override
For specific applications that need higher quality (a mastering DAW) or lower quality (a voice chat client):
# ~/.config/pipewire/pipewire.conf.d/resampler-rules.conf
context.modules = [
{ name = libpipewire-module-rt
flags = [ ifexists nofail ]
}
]
context.objects = [
{ factory = spa-node-factory
args = {
factory.name = support.null-audio-sink
node.name = "mastering-sink"
audio.rate = 96000
resample.quality = 14
}
}
]
Or override at the stream level using WirePlumber rules:
-- ~/.config/wireplumber/main.lua.d/51-resampler-rules.lua
rule = {
matches = {
{
{ "application.name", "equals", "ardour" },
},
},
apply_properties = {
["resample.quality"] = 10,
},
}
table.insert(default_access.rules, rule)
After changing configuration, restart PipeWire:
systemctl --user restart pipewire pipewire-pulse wireplumber
Recommended settings for different use cases
| Use case | Recommended quality | Rationale |
|---|---|---|
| Desktop audio (browser, video) | 7 (default) | Below converter noise floor, negligible CPU |
| DJ with split output | 7-10 | DJ monitoring setups often resample between main and headphone outputs |
| Recording (tracking) | 10 | Extra margin, but consider avoiding resampling entirely |
| Mixing and mastering | 10-12 | Match or exceed converter quality |
| Bluetooth headphones | 4-7 | Bluetooth codec is the bottleneck, not the resampler |
| Voice chat | 1-4 | Voice bandwidth is 300-3400 Hz, quality above 4 is wasted |
| Archival format conversion | 14 | Maximum quality, CPU cost irrelevant for offline work |
Avoiding resampling entirely
The best resampler is the one that never runs. If you can match sample rates across your entire graph, PipeWire passes samples through without resampling.
Set your PipeWire graph rate to match your interface:
# ~/.config/pipewire/pipewire.conf.d/rate.conf
context.properties = {
default.clock.rate = 48000
default.clock.allowed-rates = [ 48000 ]
}
Setting allowed-rates to a single value forces everything in the graph to that rate. Applications outputting 44.1 kHz will be resampled at their entry to the graph, which is unavoidable, but there will be no additional resampling within the graph.
If you work exclusively with 44.1 kHz material (mastering from 44.1 kHz sources), set the graph to 44.1 kHz:
context.properties = {
default.clock.rate = 44100
default.clock.allowed-rates = [ 44100 ]
}
Your interface will run at 44.1 kHz natively (assuming it supports it) and no resampling occurs for 44.1 kHz content.
The tradeoff: a single allowed rate means that any content at a different rate will always be resampled. If you allow multiple rates, PipeWire can switch the graph rate to match the dominant stream, but rate switching causes a brief audio interruption and can confuse some applications. The quantum selection guide covers rate switching behavior in more detail.
Verifying the active resampler quality
Check what quality PipeWire is actually using for active streams:
pw-dump | python3 -c "
import json, sys
data = json.load(sys.stdin)
for obj in data:
props = obj.get('info', {}).get('props', {})
rq = props.get('resample.quality')
name = props.get('node.name', '')
if rq is not None:
print(f'{name}: resample.quality = {rq}')
"
If nothing appears, the resampler is using the global default. If you see per-node values, those override the global setting for those specific streams.
You can also check the resampler implementation PipeWire is using:
pw-dump | grep -i "resample"
Look for resample.method - it should show speex (the default) or copy (passthrough when rates match). The Speex-based resampler is what the quality settings control.
FAQ
Does the resampler quality affect playback of files at the native graph rate? No. If a 48 kHz file plays into a 48 kHz graph, no resampling occurs. The quality setting is irrelevant when rates match.
Can I use different quality settings for input vs output? Not directly through PipeWire's configuration. The quality setting applies to the resampler instance, which is created per conversion point. You can influence this through per-node WirePlumber rules as shown above.
Is the PipeWire resampler better than SoX? At quality 10+, PipeWire's resampler is competitive with SoX's Very High Quality mode in measured THD+N. SoX remains the better choice for offline batch conversion because it is not constrained by real-time deadlines and can use arbitrarily long filter kernels. For live audio processing, PipeWire's resampler is excellent at quality 7+.
Will higher resampler quality cause XRuns? On modern hardware, no. The CPU cost of quality 14 is about 1.5% of a core for stereo. If that pushes you over the XRun threshold, your system was already marginal. On very low-power embedded systems (Raspberry Pi class), the cost could matter - test it.
I upgraded from PipeWire 1.4 to 1.6 and my audio sounds different. Is it the resampler?
Possibly, if resampling was active. The default jumped from quality 4 to quality 7, which means better stopband rejection and lower THD+N. The "different" sound is more accurate. If you prefer the old behavior, set resample.quality = 4 in your configuration, but there is no objective reason to prefer the lower quality.
More audio quality discussion is available in the audio quality reference and the benchmark collection.
Conclusion
PipeWire 1.6 made the resampler better and cheaper. The new default of quality 7 is appropriate for nearly everyone - it sits below the noise floor of any real converter and costs nothing measurable on current CPUs. If you do mastering work through PipeWire (and resampling is unavoidable), bump to 10-12. If you are on a power-constrained device, 4 is still adequate for non-critical listening. But the best advice remains: match your sample rates and avoid resampling entirely when the signal path matters.
- PipeWire
- Resampling
- Audio Quality
- Benchmarks
- Linux Audio
- 2026