Blogshit

Nice blog where can I subscribe

Remapping left channel ONLY from a stereo source to mono in PipeWire

17 July 2021

I recently upgraded to Fedora 34, which meant switching from PulseAudio to PipeWire (precisely the reason I kept putting the upgrade off).

I have a certain circumstance in my audio setup: my audio interface has two inputs (for microphones, instruments, etc.) which are recognized by ALSA as a single stereo input. I want a mono input that only has my microphone on it and not the second channel. Granted, the second channel is almost always empty, but mixing stereo to mono involves something called the pan law (which isn’t a law, just an audio engineering convention), which, to make a long story short, ends up reducing my microphone’s maximum volume by up to 6 decibels as it gets downmixed to mono.

In PulseAudio I did this with the following line in ~/.config/pulse/default.pa: pactl load-module module-remap-source master=alsa_input.usb-BEHRINGER_UMC204HD_192k-00.analog-stereo master_channel_map=front-left channel_map=mono rate=48000 format=s24le

This would create a virtual microphone device that only had the left channel of input on it, and avoided the -6dB pan “law” effect.

Enter PipeWire

Doing this on PipeWire was a little harder, because the PipeWire documentation is… well, let’s say it’s a work in progress. I did not want to use the PulseAudio compatibility functionality of PipeWire (which would let me just use the Pulse command from above) because I suspect it has worse performance than the native PipeWire solution, and instead wanted to use the native solution.

Reading the relevant PipeWire documentation on Virtual Devices I managed to do something like what I wanted with the following command:

pw-loopback --capture-props='audio.position=[FL, FL]' --playback-props='media.class=Audio/Source node.name=testsource audio.position=[mono]'

However, this had two issues: (1) it did not persist through restarts, and (2) if I selected the virtual interface as my default input, PipeWire would try to be smart and re-link it to itself, causing it to stop working. This is to my understanding not a bug but a feature, as the documentation page says:

Streams are normally automatically linked to devices by the session manager. This means that coupled streams don’t need any manual intervention to get linked and can also be moved around with tools like pavucontrol or pw-metadata.

I wanted a solution that persisted through restarts, and one that I could just set as my system-wide default microphone input and forget about.

The solution

First, copy a default PipeWire session manager config file to your ~/.config (or under /etc/pipewire/ if you want it to be system-wide):

cp /usr/share/pipewire/media-session.d/media-session.conf ~/.config/pipewire/media-session.d

Then, open up that config file and insert the following at the bottom of the context.modules section. Mind your braces and square brackets; humans are second-class citizens in the PipeWire config format.

    {   name = libpipewire-module-loopback
            args = {
                capture.props = {
                    audio.position = [FL, FL]
                    node.target = alsa_input.usb-BEHRINGER_UMC204HD_192k-00.analog-stereo
                }
                playback.props = {
                    media.class = Audio/Source
                    node.name = mono-microphone
                    node.description = "Behringer Left"
                    audio.position = [mono]
                }
            }
    }

This must go in the session manager config (something that took me a long time to figure out), and PipeWire is very fussy about the parameters; specifying media.class for the capture.props section will break everything, as does node.name and what have you.

The configuration here works for me, and I hope it works for the future me who came back here to remind himself of how to configure this, and I hope it works for you. If it doesn’t, god help you (or me).

Configure mouse thumb buttons as F13 in Linux

13 February 2021

Like most people, I have a mouse with thumb buttons on it. Mouse designers of the late 90s and early 00s decided to call these buttons “Back” and “Forward” and make them navigate backwards and forwards in web browsers and such. Not a feature I use very much.

What I do use a lot is VoIP communications software, where I use push-to-talk bound to one of these thumb buttons. Therein lies the problem: whenever I press push-to-talk with my web browser active, it takes me off the page I was on and onto the previous page I was on. I don’t want that to happen.

Browser designers clearly don’t relate to this issue, so there’s no easy, universal way to disable this backwards-forwards functionality of the thumb buttons. And even if I did disable it in Firefox, my file browser would still use them for navigation, and if I disabled it there, there’d still be some app out there that insists on using these buttons for this purpose. It’s a battle I can’t win.

Some years ago I discovered a great solution for this. My Logitech mouse allows rebinding the mouse buttons to arbitrary keyboard buttons, so why don’t I just change it to some keyboard button I almost never use like the Pause button? Even better, the F-keys that normally run from F1 to F12 actually run all the way up to F24. Modern keyboards obviously never go that high, but due to legacy reasons operating systems still support these “high F” keys.

So I opened the Logitech Control Panel on Windows, entered the key binding interface and… wait, I can’t actually input F13 in here. How do I do it? I’ll spare you the suspense and say that I did it with a simple AutoHotKey script that sent the F13 keystroke which the Logitech software happily accepted. I don’t have that script anymore because I don’t use Windows, but it was a oneliner so you’ll figure it out. I’m counting on you.

But then I switched to Linux, and the Logitech Control Panel doesn’t work on Linux and unfortunately, the forwards/backwards buttons do. What now?

The actual solution

Enter libratbag, a community-maintained effort to enable features in modern mice (and a small handful of other peripherals) that would normally be accessed through the driver software, which is unfortunately typically exclusive to Windows.

It’s supposed to be a library/dbus daemon type thing to enable GUI frontends to access these devices, and it has a GUI frontend called Piper. Unfortunately, Piper doesn’t want to accept the F13 key.

Thankfully libratbag also comes with a command line utility called ratbagctl.

$ ratbagctl
singing-gundi:       Logitech MX518 Gaming Mouse  

When invoked, it shows us a list of supported devices along with a human-readable ID. In this case there’s only one supported device, “singing-gundi” the Logitech MX518 Gaming Mouse.

We read man ratbagctl like a good boy and piece together the following commands:

$ ratbagctl singing-gundi button 3 get
Button: 4 is mapped to 'button 4'

Button 3 is the first thumb button, the one closer to the user. We can see it’s currently bound to ‘button 4’, which is the default and not at all confusing (ratbag indexes the buttons from 0 while X11 – or whatever is handling the input – indexes from 1). We want to rebind it to F13.

The manpage specifies the command button N action set button B, but this is for setting it to mouse buttons, not keyboard keys, so we can’t rebind it to F13 this way. Instead we need to use

ratbagctl singing-gundi button 3 action set macro KEY_F13

The shell should be silent in response, which means the command succeeded. We can check that it worked with

$ ratbagctl singing-gundi button 3 get       
Button: 3 is mapped to macro '↕F13'

And that’s it! The first thumb button is now going to be sending the F13 keystroke, which X11 calls XF86Tools by the way. This should be recognized in pretty much any app or game as a keybinding, but browsers won’t go backwards when pressing it.

If you want to go back to the default, simply use

ratbagctl singing-gundi button 3 action set button 4

Better font rendering in Fedora

09 July 2020

I’ve used Fedora for many years now on my laptop, and the default font rendering has served me well there… but only because the laptop has a HiDPI screen which doesn’t need subpixel hinting as much as regular screens. Subpixel hinting, as it turns out, is patented by Microsoft (accursed software patents) so most Linux distributions don’t ship with it enabled, and its absence is painfully obvious on ye olde low-DPI screens especially when viewing light text on dark backgrounds.

Anyway, there’s a helpful COPR repository that fixes all of this. https://github.com/silenc3r/fedora-better-fonts (or more directly, https://copr.fedorainfracloud.org/coprs/dawid/better_fonts/).

Enable this repository and install the packages it offers and you’ll get prettier fonts, plus it installs replacements for a bunch of common Microsoft fonts, making web pages appear closer to what they do on Windows (if this is something you don’t want, I suppose you can just not install the fontconfig-font-replacements package.)

Installation instructions (as per the COPR repo page):

  1. Enable COPR repository with packages from this repo: dnf copr enable dawid/better_fonts

  2. Install packages: dnf install fontconfig-enhanced-defaults fontconfig-font-replacements

  3. Log out and log in again or restart computer to see the effect

Xorg, Nvidia and Custom Resolutions / Modes in 2020

05 July 2020

I have a now fairly old BenQ XL2420Z gaming monitor. It is a 144Hz refresh rate model and has strobing backlight functionality for motion blur reduction. However, I run it at 120Hz using some custom timings, because this reduces visual artifacting with the strobing backlight and makes the display brighter when the strobing is enabled. BlurBusters calls this the “1350 Vertical Total trick”, or something along those lines. The why and how of it is beyond me.

I had some issues setting this custom resolution up under Linux using Xorg and the proprietary Nvidia drivers. Someone at the BlurBusters forums created a guide which was helpful, but was missing some key details that were necessary to get this to work on my machine.

The configuration

Here’s the configuration for the impatient. If you have the exact same display I do, this may work for you. However, you may want to read on to see how this configuration came to be.

Save this into /etc/X11/xorg.conf.d/ with some descriptive filename. If you are unfamiliar with conf.d style configs, these loose files are read after the main Xorg.conf (which on modern systems often doesn’t even exist anymore) and any changes in them are applied in alphabetical order. In my case, this file is /etc/X11/xorg.conf.d/20-xl2420z-customres.conf.

Section "Monitor"
    Identifier     "xl2420z" #This identifier can be anything; it's just the name of this config block.
    #The next line defines the custom resolution.
    #The exact meaning of the magic numbers here is beyond the scope of this blog post.
    ModeLine       "1920x1080_120_vt1350" 336.96 1920 1968 2000 2080 1080 1083 1088 1350 +hsync -vsync 
EndSection

Section "Screen"
    Identifier     "Screen0"
    #The next line disables some safety checks imposed by the Nvidia driver
    #It uses the display's EDID so that they are only disabled for the XL2420Z and
    #not any other displays.
    #Without this line the custom resolution will be rejected as unsafe.
    Option         "ModeValidation" "DPY-EDID-edbe03be-f4a0-3a94-b9e8-00884a48f8f4: AllowNonEdidModes,NoMaxPClkCheck,NoEdidMaxPClkCheck,NoHorizSyncCheck"
    Monitor        "xl2420z" #This is important so that the monitor block above is actually used!
EndSection

Applying the configuration

Once you’ve saved the config to a valid path, reboot your computer (or restart X, but it’s safer and easier to reboot).

After the reboot, use the nvidia-settings GUI to enable the custom resolution. Select “X Server Display Configuration” from the list on the left, then select your monitor, switch to Advanced mode on the bottom right, and then set the correct resolution. It will unhelpfully be categorized by the refresh rate, so you might be in a situation where the right resolution is 1920x1080 120 Hz (1) or something. Just select the correct dimensions, and then scroll through the refresh rate selection until you see the correct Mode Name; that’s the resolution you want.

nvidia-settings GUI example 2

Once you’ve got the right resolution, click on Apply and then exit out of the GUI. The resolution should now be applied, and the drivers will load it automatically every boot, and you should be done! If not, read the debugging section below.

I’ve also seen the custom resolution defined in the config file directly using the MetaModes option, but I couldn’t get that to work either. Your mileage may vary.

How the configuration came to be

There are two key bits in this config that you may have to customize for your setup.

The first is the ModeLine, which is the set of magic numbers that defines our custom resolution. The ModeLine here is from the BlurBusters forum guide linked above and matches the timings I successfully used on Windows for many years on this monitor.

If you have to create your own ModeLine, this calculator may come in handy to calculate the various timings. I’m woefully clueless about the meaning of these values, but the calculator should help you if you’re just trying to recreate the settings given in some Windows-oriented guide.

Note that Windows-oriented guides often omit the Back Porch values. This is because those values can be inferred from the other values, and Windows tools like the Nvidia Control Panel and ToastyX Custom Resolution Utility do so. The back porch values are simply what’s left over after you subtract all the other values from the Horizontal or Vertical Total values. For instance for a Vertical Total of 1350, subtract the Resolution (1080), Front Porch (3) and Sync Pulse (5) values and you’re left with 262; that is the Back Porch value.

The second is the EDID used in the ModeValidation option. This is a unique ID for a specific monitor model (or maybe even a specific monitor; I don’t know). There are more generic identifiers available, but using this one ensures that the option is never applied to the wrong monitor.

The Nvidia drivers come with a tool called nvidia-settings which you can use to discover these identifiers. Use nvidia-settings -q dpys to list all the display devices on your system, and then look for the right monitor:

$ nvidia-settings -q dpys

9 Display Devices on kotenbu:0
[...]
    [7] kotenbu:0[dpy:7] (DP-4) (connected, enabled)

      Has the following names:
        DFP
        DFP-6
        DPY-EDID-edbe03be-f4a0-3a94-b9e8-00884a48f8f4
        DPY-7
        DP-4
        Connector-2
[...]

If you have a lot of monitors and aren’t quite sure which one is which, you can use either xrandr or the nvidia-settings GUI (just run nvidia-settings with no parameters) to find the short identifier of the display, which you can then match to the long EDID identifier in the output above:

nvidia-settings GUI example 1

Once you have the EDID, you can use that in the config.

Debugging

This can get frustrating if (or when) things go wrong. I had trouble getting Xorg to actually load the config and the custom mode. Increasing the Xorg logging verbosity can help here; this is done using the parameter -logverbose 6. 6 is the minimum level to display information on ModeLines and why they may or may not be loaded.

In my case the entire Monitor section was being ignored. The key to overcoming this was adding the Monitor "xl2420z" line into the Screen section. Another possible option is to use this feature, which should enable the Monitor section for only a specific device, but I couldn’t get this to work personally (quoting from man xorg.conf):

Option “Monitor-outputname” “monitorsection”

(for example, Option “Monitor-VGA” “VGA monitor” for a VGA output)

In the absence of specific association of monitor sections to outputs, if a monitor section is present the server will associate it with an output to preserve compatibility for previous single-head configurations.

Specifying video modes is optional because the server will use the DDC or other information provided by the monitor to automatically configure the list of modes available. When modes are specified explicitly in the Monitor section (with the Mode, ModeLine, or UseModes keywords), built-in modes with the same names are not included. Built-in modes with different names are, however, still implicitly included, when they meet the requirements of the monitor.

Good luck.

Alt+numberkey combination stop working in PuTTY (and maybe others) in Windows 10

19 May 2020

I use PuTTY to run Weechat (an IRC client) over SSH. Over the years I’ve noticed that the alt+numberkey combination suddenly stops working for no apparent reason, which is a bummer because that’s how you change channel windows in Weechat.

After figuring out the reason this happens, forgetting all about it, then figuring it out again, then forgetting it again, and then figuring it out once more, I figured that I should just write it down here.

It’s Photoshop. Yeah. I don’t know why or how, but Photoshop sometimes does this. It doesn’t always do it, but occasionally it does. And when it does, closing it immediately solves the issue (which, I guess, only makes sense). Anyway, go figure.

That’s all.