JMM’s notes on

PipeWire

Programs

Command Line

Creating Nodes

Here’s how to create a pipewire node:

pw-cli create-node adapter '{ factory.name=support.null-audio-sink node.name=Mixed-Input node.description="Mixed Input" media.class=Audio/Source/Virtual object.linger=true audio.position=FL,FR }'

The object.linger=true is pretty important here. If you don’t include it, it won’t show up on qpwgraph. I’m guessing it’s because objects that aren’t set to linger are automatically cleaned up when not connected to anything.

Note that you probably want to actually configure this with something like WirePlumber, but I haven’t gotten around to that as of March 2024.

My NixOS Settings

Here’s my pipewire settings for NixOS. It’s pretty outdated.

{ config, pkgs, lib, ... }:

{
  # sound.enable = false;
  hardware.pulseaudio.enable = false;
  security.rtkit.enable = true;
  environment.sessionVariables.LD_LIBRARY_PATH = lib.mkForce "${config.services.pipewire.package.jack}/lib";
  services.pipewire = {
    enable = true;
    alsa.enable = true;
    alsa.support32Bit = true;
    pulse.enable = true;
    # Jack support works, but it weirdly breaks GTK Webkit
    # https://github.com/NixOS/nixpkgs/issues/110468
    jack.enable = true;
    # See the workaround up ahead

    # use the example session manager (no others are packaged yet so this is enabled by default,
    # no need to redefine it in your config for now)
    #media-session.enable = true;

    # config.pipewire doesn't work now.  TODO: I'll need to make these another way. 2023-12-07
    # config.pipewire = {
    #   "context.objects" = [
    #     {
    #       # A default dummy driver. This handles nodes marked with the "node.always-driver"
    #       # property when no other driver is currently active. JACK clients need this.
    #       factory = "spa-node-factory";
    #       args = {
    #         "factory.name"     = "support.node.driver";
    #         "node.name"        = "Dummy-Driver";
    #         "priority.driver"  = 8000;
    #       };
    #     }
    #     {
    #       factory = "adapter";
    #       args = {
    #         "factory.name"     = "support.null-audio-sink";
    #         "node.name"        = "Mixed-Input";
    #         "node.description" = "Mixed Input";
    #         "media.class"      = "Audio/Source/Virtual";
    #         "audio.position"   = "FL,FR";
    #       };
    #     }
    #     {
    #       factory = "adapter";
    #       args = {
    #         "factory.name"     = "support.null-audio-sink";
    #         "node.name"        = "Microphone-Two";
    #         "node.description" = "Microphone Two";
    #         "media.class"      = "Audio/Source/Virtual";
    #         "audio.position"   = "MONO";
    #       };
    #     }
    #     {
    #       factory = "adapter";
    #       args = {
    #         "factory.name"     = "support.null-audio-sink";
    #         "node.name"        = "Copy-Output";
    #         "node.description" = "Copy Output";
    #         "media.class"      = "Audio/Sink";
    #         "audio.position"   = "FL,FR";
    #       };
    #     }
    #   ];
    # };
  };

  environment.systemPackages = with pkgs; [
    alsaUtils # Sometimes needed for changing the volume on things
    pavucontrol
    qjackctl
    calf
    # pulseeffects-pw # Not found in 2023-12-07
    carla
    zynaddsubfx
    sorcer
    speech-denoiser
    # talentedhack
    artyFX
    # ardour
    # rnnoise
  ];

  # TODO: Add the following environment variables in a better, more stateless way
  # (Maybe use an absolute path instead?)
  environment.shellInit = ''
    export VST_PATH=/run/current-system/sw/lib/vst:~/.vst
    export LXVST_PATH=/run/current-system/sw/lib/lxvst:~/.lxvst
    export LADSPA_PATH=/run/current-system/sw/lib/ladspa:~/.ladspa
    export LV2_PATH=/run/current-system/sw/lib/lv2:~/.lv2
    export DSSI_PATH=/run/current-system/sw/lib/dssi:~/.dssi
  '';
}