⚠ UNDER CONSTRUCTION ⚠ this personal prototypical project is perpetually a work in progress ⚠ UNDER CONSTRUCTION ⚠
← back to all posts

"No excuse besides being bad at the game"


UNBEATABLE's latest patch notes have a bit in them that I love. The usual process, apparently, is that Jeff writes the post and RJ does a pass over it. This time RJ stopped halfway down to go off on a tangent about one line: ASIO support. "ASIO is so much faster than the standard audio support. It's, like, what my DAW uses." And then the kicker -- if you've got an ASIO-capable audio interface and a monitor made this decade, "you really have no excuse now besides just being bad at the game."

I have an ASIO-capable interface. A Yamaha AG06MK2 sits on my desk doing exactly nothing special, because I play UNBEATABLE on Linux, through Proton, and Proton doesn't do ASIO. There's no driver for it. The option in the menu is just a switch connected to nothing.

So of COURSE I decided to spend a couple of hours fixing that. How hard would it be??

Making it exist

ASIO is a Windows thing. A program asks for an ASIO driver, the driver talks to the hardware, and everything in between gets out of the way. Under Wine, the long-standing answer has been WineASIO, which pretends to be an ASIO driver and passes the audio on to JACK. The trouble is that Proton runs games inside Valve's Steam Runtime container, and that container doesn't ship JACK. WineASIO loads, reaches for JACK, finds nothing, and falls over.

PipeASIO is a fork of WineASIO that skips JACK and talks to PipeWire directly, which the container does have. It's young -- the README says it's been verified with FL Studio and a test utility, and nothing else -- but it's built for exactly this situation.

Getting it going was mostly a matter of putting things where Proton can see them. You build it into your home folder (Proton can't see the system's Wine libraries, so the AUR package is no use here), register it inside the game's Proton prefix, and add a launch option telling Proton where its Linux half lives. The registration step was the only bit that fought back. PipeASIO's docs say to run it through umu-launcher, so it goes through the same Proton the game uses, and to point it at the game's prefix. Do exactly that and umu decides the prefix is brand new, then helpfully creates a folder called pfx inside pfx that's actually a symlink back to itself. The registration still landed in the right place, so it is survivable, but you do then have to delete a symlink that points at your entire game prefix and try very very hard not to type rm -r.

Then I opened the game, went to the audio settings, and there it was: output device, pipeasio. The game made noise, and that was that.

And then nothing

I played yeah yeah yeah with ASIO on, then turned it off and played it again, recording both. Then I watched them back.

I couldn't tell them apart. Not in the recording, not in my hands. I scored better on the ASIO run, but one attempt each can't tell you anything about that.

There are a couple of reasonable explanations for that. One is that I'm bad at the game, which RJ has already accounted for. Another is that a few milliseconds is genuinely hard to feel, and you adapt to whatever latency you're playing at within a couple of minutes anyway. But the real reason turned out to be much less interesting than either of those.

1024

PipeWire comes with a tool called pw-top, which shows every audio stream on your system and the buffer size -- the quantum -- each one is running at. Normally PipeWire runs the whole graph at the smallest quantum anything asks for. Vesktop was asking for 512. The game's normal, non-ASIO output was asking for 256.

My audio interface was running at 1024.

PipeASIO forces its own buffer size onto the entire graph, so that the ASIO side of things gets exactly what it asked for. That's a reasonable design. But with no config file, it asks for 1024 frames, which is 21.3 milliseconds per cycle. And the config file doesn't exist until you make one. So the moment the game opened PipeASIO, every bit of audio on my machine dropped to 1024 -- including the game's own non-ASIO output, which was still open alongside it.

My A/B test had been comparing 1024 with 1024. Of course they felt the same.

Turning it down

The fix is one line in ~/.config/pipeasio/config.ini:

[pipeasio]
buffer_size=256

The catch is that smaller isn't free. PipeASIO runs in lockstep with the rest of the graph, so if the game is ever late handing over a buffer, that cycle is just lost, and you get a gap. pw-top counts these in its ERR column, so the test became: note the number, play a two-minute song, see how much it went up.

Buffer Per cycle OBS running Errors per song
128 2.7 ms yes ~570
128 2.7 ms no ~250
256 5.3 ms no ~60

128 was a mess. Recording with OBS doubled it, because OBS's capture streams run in the same graph, at the same tiny buffer. Without OBS it was still about two dropouts a second. 256 is a quarter of what I started with and mostly holds, though "mostly" is doing some work there. Sixty is too many to wave away, and I don't yet know whether they're spread through the song or bunched up while the chart loads and the results screen appears. Only one of those matters.

So, is it faster?

Not a flipping clue mate.

There's a decent argument that it should be. The game's normal output doesn't go straight into PipeWire. It goes through Unity's own buffer, then Wine's imitation of the Windows audio system, then Wine's PulseAudio driver, then PipeWire's PulseAudio layer, and only then the graph. The 256 that pw-top shows for it is only the last of those. That stream never reports a single error, and that isn't because it's well-behaved. It's because there's so much buffering ahead of it that nothing ever gets close to a deadline, and buffering is latency.

PipeASIO skips ALL of that crud and sits directly in the graph, so on paper even a fairly large ASIO buffer could beat it.

But "on paper" is how I spent my first test playing at 1024 without knowing it. The numbers to compare are sitting in pactl and on the game's results screen, which reports an average delay in milliseconds, but I actually dont think i can be arsed to compare them..

What I'll say for now is that RJ is probably right about Windows. On Windows, ASIO replaces a shared mixer that's known for adding latency, and the difference is real. On Linux the gap might be smaller than the patch notes suggest, and the default settings can quietly make things worse rather than better. If you set this up and it feels the same, open pw-top before you decide that you're just bad at the game.

If you want to try it yourself, I've written the whole process up step by step as a Steam guide, including the symlink cleanup and how to back it all out again.

Thank you for reading :)

- Dia

Responses (what's this?)


Send a response

Leave a comment

Commenting is disabled on beta; Discord sign-in returns to the live site. Comment on the live post.

Leave a mention

Sending is disabled on beta; the form targets the live post, so a mention sent from here would land on diaduck.xyz. Send it from the live post.