diff --git a/DECISIONS.md b/DECISIONS.md index 0cbe3d9..74978ea 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -1,5 +1,63 @@ # Decisions +## 2026-08-20 – Input denoising was deployed to a path PipeWire never reads + +- **Who**: Dominik, ClaudeCode +- **Why**: The Arch machine runs RNNoise input denoising, and the config for it + lives in the shared tree as + `defaults/xdg/pipewire/pipewire.conf.d/99-input-denoising.conf`. It was in + `modules/desktop.nix` too, in the generic sweep to `/etc/xdg/` — and inert + there. PipeWire resolves its config directory from `$PIPEWIRE_CONFIG_DIR`, + then `$XDG_CONFIG_HOME/pipewire` or `$HOME/.config/pipewire`, then the + compiled-in `/etc/pipewire`; `XDG_CONFIG_DIRS` appears nowhere in + `src/pipewire/conf.c`. On Arch the file works because `post-install.sh` seeds + it into the home directory. Same class as the swaylock config on 2026-08-18: a + file installed to a plausible path that the program does not read. +- **Tradeoffs**: (1) **Which option** — the module accepts both + `services.pipewire.extraConfig.pipewire.` (Nix attributes, rendered to + JSON) and `services.pipewire.configPackages` (a package carrying + `share/pipewire/pipewire.conf.d/*.conf`); both end up in the same merged + directory (`pipewire.nix:59-75`). The NixOS wiki uses `extraConfig` for its + examples, which are written by hand and have no file behind them. Taking that + route here would mean translating the shared file into Nix and maintaining the + VAD values in two places, so `configPackages` was chosen — which is also what + the module's own option documentation shows for a conf.d file + (`pipewire.nix:258-279`). (2) **The plugin path** — the file names the plugin + as `librnnoise_ladspa`, resolved through `LADSPA_PATH`, which is + `/usr/lib/ladspa` on Arch and does not exist here. There is no LADSPA + counterpart to `services.pipewire.extraLv2Packages`, so the absolute store + path is substituted into the file, the same treatment the wallpaper paths get. +- **How**: `denoisingConfig` via `runCommand` + `substitute`, handed to + `services.pipewire.configPackages`. The `xdg/pipewire/` entry in + `environment.etc` is removed rather than kept for layout parity — after the + swaylock case, an inert copy is a liability. Verified by building the package: + the conf.d file is there, the plugin line points at + `rnnoise-plugin-1.10/lib/ladspa/librnnoise_ladspa.so`, and that file exists. +- **Note**: the filter chain shows up as a separate "Noise Canceling source" + input. It does not replace the raw microphone; applications have to select it. + +## 2026-08-20 – Steam, Bitwig and rtkit belong to the desktop alone + +- **Who**: Dominik, ClaudeCode +- **Why**: Both programs are wanted on the desktop and on no other machine, so + they go into `hosts/desktop/default.nix` rather than the shared module every + host imports. +- **Tradeoffs**: (1) **Steam** — `pkgs.steam` in `systemPackages` is the wrong + handle: the module wraps the binary in an FHS environment and turns on + `hardware.graphics.enable32Bit` itself (`nixos/modules/programs/steam.nix:215-218`), + which the bare package would leave off. (2) **Bitwig** — the `bitwig-studio` + attribute currently resolves to `bitwig-studio6-6.0.11`; `bitwig-studio5` + (5.3.13) exists as a separate attribute if a downgrade is ever needed. + Dominik chose 6. (3) **Realtime** — `security.rtkit.enable` was off. The + rlimits the PipeWire module installs (`rtprio` 95, `nice` -19, `memlock`) + apply to members of the `pipewire` group, and the account is in + `networkmanager wheel video input plugdev docker` only, so a DAW had no path + to realtime scheduling at all. Enabled on this host, where the DAW is. +- **How**: `programs.steam.enable`, `security.rtkit.enable` and + `environment.systemPackages = [ pkgs.bitwig-studio ]` in the host file. + Verified by evaluating both hosts: on `desktop` all three are set and 32-bit + graphics came along; on `thinkpad` Steam and rtkit stay `false`. + ## 2026-08-20 – The browser is LibreWolf from nixpkgs, not a self-packaged Waterfox - **Who**: Dominik, ClaudeCode diff --git a/hosts/desktop/default.nix b/hosts/desktop/default.nix index d91f5f6..cbeff79 100644 --- a/hosts/desktop/default.nix +++ b/hosts/desktop/default.nix @@ -109,6 +109,20 @@ # the shared module sets it unconditionally. services.fwupd.enable = lib.mkForce false; + # --- Applications, this machine only --- + # + # Steam comes as a module rather than a package: it wraps the binary in an FHS + # environment and turns on 32-bit graphics for the drivers, which the package + # alone would not do. + programs.steam.enable = true; + + # Lets audio applications ask for realtime scheduling, which Bitwig does. The + # rlimits the PipeWire module sets (rtprio 95, memlock) apply to members of + # the pipewire group only, and this account is not one. + security.rtkit.enable = true; + + environment.systemPackages = [ pkgs.bitwig-studio ]; + nix.settings.experimental-features = [ "nix-command" "flakes" ]; nixpkgs.config.allowUnfree = true; diff --git a/modules/desktop.nix b/modules/desktop.nix index 025318f..dae8a76 100644 --- a/modules/desktop.nix +++ b/modules/desktop.nix @@ -36,6 +36,24 @@ let --replace-fail /usr/share/moonarch/wallpaper-blur.jpg ${wallpaperBlur} ''; + # PipeWire searches $PIPEWIRE_CONFIG_DIR, then $XDG_CONFIG_HOME/pipewire, then + # its compiled-in /etc/pipewire — never /etc/xdg (verified in PipeWire's + # src/pipewire/conf.c). The shared file therefore cannot be deployed the way + # the other XDG configs are; it goes through the module's configPackages, + # which is what its own option documentation shows for a conf.d file. + # + # The file names the plugin as `librnnoise_ladspa`, resolved through + # LADSPA_PATH — /usr/lib/ladspa on Arch, nothing here. Substituted to the + # store path, like the wallpaper paths above. LADSPA has no counterpart to + # services.pipewire.extraLv2Packages, so the path belongs in the file. + denoisingConfig = pkgs.runCommand "moonarch-pipewire-denoising" { } '' + mkdir -p "$out/share/pipewire/pipewire.conf.d" + substitute ${xdg}/pipewire/pipewire.conf.d/99-input-denoising.conf \ + "$out/share/pipewire/pipewire.conf.d/99-input-denoising.conf" \ + --replace-fail "plugin = librnnoise_ladspa" \ + "plugin = ${pkgs.rnnoise-plugin}/lib/ladspa/librnnoise_ladspa.so" + ''; + # zsh/newuser runs its setup wizard on every interactive login for as long as # the user has none of .zshenv, .zprofile, .zshrc or .zlogin — the whole # configuration living in /etc/zshrc does not count. Seeded below to stop @@ -74,8 +92,9 @@ in "xdg/qt6ct/qt6ct.conf".source = "${xdg}/qt6ct/qt6ct.conf"; "xdg/gtk-3.0/settings.ini".source = "${xdg}/gtk-3.0/settings.ini"; "xdg/gtk-4.0/settings.ini".source = "${xdg}/gtk-4.0/settings.ini"; - "xdg/pipewire/pipewire.conf.d/99-input-denoising.conf".source = - "${xdg}/pipewire/pipewire.conf.d/99-input-denoising.conf"; + # No xdg/pipewire/ entry: PipeWire does not read /etc/xdg, so the file was + # deployed and inert. It goes through services.pipewire.configPackages + # below instead. # Kept for layout parity with the Arch package; waypaper itself only reads # the copy in the home directory, seeded below. "xdg/waypaper/config.ini".source = waypaperConfig; @@ -202,6 +221,13 @@ in openmoji-color ]; + # --- Audio --- + # + # RNNoise input denoising, from the shared config. The filter chain appears as + # a separate "Noise Canceling source" input; it does not replace the raw + # microphone, so applications have to select it. + services.pipewire.configPackages = [ denoisingConfig ]; + # --- Printing --- # # Driverless only, and no printer is declared here. Asked over IPP, the