Keep in mind that configuring low latency with Pipewire still requires some significant knowledge, particularly with USB devices.
Another aspect that is rather complex is to configure systemic-latency. For jackd those are simply command-line options -d alsa -I <num> -O <num>
. and jack_iodelay directly suggests those.
You will notice that when recording overdubs in Ardour. They won’t align with pipewire. The solution here is to first measure the round-trip latency (using jack_iodelay
).
Then you have to find the Node-ID of the device in pipewire, and set the ProcessLatency parameter. This is done by running pw-cli
then call list-objects
search the relevant Node, and then set-param <Node-ID> ProcessLatency {rate: <THE-MEASURED-SYSTEMIC-LATENCY>}
e.g.
$ pw-cli
Welcome to PipeWire version 0.3.53. Type 'help' for usage.
pipewire-0>> list-objects
[..snip..]
id 50, type PipeWire:Interface:Node/3
object.serial = "50"
object.path = "alsa:pcm:1:front:1:playback"
factory.id = "18"
client.id = "32"
device.id = "44"
priority.session = "945"
priority.driver = "945"
node.description = "EDIROL UA-25 Analog Stereo"
node.name = "alsa_output.usb-Roland_EDIROL_UA-25-00.analog-stereo"
node.nick = "UA-25"
media.class = "Audio/Sink"
id 51, type PipeWire:Interface:Node/3
object.serial = "51"
object.path = "alsa:pcm:1:front:1:capture"
factory.id = "18"
client.id = "32"
device.id = "44"
priority.session = "1945"
priority.driver = "1945"
node.description = "EDIROL UA-25 Analog Stereo"
node.name = "alsa_input.usb-Roland_EDIROL_UA-25-00.analog-stereo"
node.nick = "UA-25"
media.class = "Audio/Source"
[..snip..]
Here Node IDs are 50 for playback, and 51 for capture. We can query information:
pipewire-0>> info 50
[..snip..]
* params: (8)
* 3 (Spa:Enum:ParamId:EnumFormat) r-
* 1 (Spa:Enum:ParamId:PropInfo) r-
* 2 (Spa:Enum:ParamId:Props) rw
* 4 (Spa:Enum:ParamId:Format) -w
* 10 (Spa:Enum:ParamId:EnumPortConfig) r-
* 11 (Spa:Enum:ParamId:PortConfig) rw
* 15 (Spa:Enum:ParamId:Latency) rw
* 16 (Spa:Enum:ParamId:ProcessLatency) rw
[..snip..]
and then set the ProcessLatency to e.g. 544 samples:
pipewire-0>> set-param 50 ProcessLatency {rate: 544}
Object: size 32, type Spa:Pod:Object:Param:ProcessLatency (262156), id Spa:Enum:ParamId:ProcessLatency (16)
Prop: key Spa:Pod:Object:Param:ProcessLatency:rate (2), flags 00000000
Int 544
Now one can inspect the value
pipewire-0>> enum-params 50 Spa:Enum:ParamId:Latency
remote 0 object 50 param 15 index 54
Object: size 176, type Spa:Pod:Object:Param:Latency (262155), id Spa:Enum:ParamId:Latency (15)
Prop: key Spa:Pod:Object:Param:Latency:direction (1), flags 00000000
Id 0 (Spa:Enum:Direction:Input)
Prop: key Spa:Pod:Object:Param:Latency:minQuantum (2), flags 00000000
Float 1.000000
Prop: key Spa:Pod:Object:Param:Latency:maxQuantum (3), flags 00000000
Float 1.000000
Prop: key Spa:Pod:Object:Param:Latency:minRate (4), flags 00000000
Int 544
Prop: key Spa:Pod:Object:Param:Latency:maxRate (5), flags 00000000
Int 544
Prop: key Spa:Pod:Object:Param:Latency:minNs (6), flags 00000000
Long 0
Prop: key Spa:Pod:Object:Param:Latency:maxNs (7), flags 00000000
Long 0
And finally then the same for the capture device:
pipewire-0>> set-param 51 ProcessLatency {rate: 544}
Object: size 32, type Spa:Pod:Object:Param:ProcessLatency (262156), id Spa:Enum:ParamId:ProcessLatency (16)
Prop: key Spa:Pod:Object:Param:ProcessLatency:rate (2), flags 00000000
Int 544
Last but not least you can check with pw-jack jack_lsp -l
that it worked
$ pw-jack jack_lsp -l
EDIROL UA-25 Analog Stereo:capture_FL
port playback latency = [ 0 0 ] frames
port capture latency = [ 1568 1568 ] frames
EDIROL UA-25 Analog Stereo:capture_FR
port playback latency = [ 0 0 ] frames
port capture latency = [ 1568 1568 ] frames
EDIROL UA-25 Analog Stereo:playback_FL
port playback latency = [ 1568 1568 ] frames
port capture latency = [ 0 0 ] frames
EDIROL UA-25 Analog Stereo:playback_FR
port playback latency = [ 1568 1568 ] frames
The latency reported by PW-JACK is now 1568 This is the sum of the nominal buffer-size 1024 + the configured systemic latency of 544.
In Ardour with the ALSA backend you can just use the built int “Calibrate Audio” feature and use the GUI. That is a lot easier if you ask me.