nixos-config/machines/vm-audio.nix

245 lines
5.7 KiB
Nix
Raw Normal View History

2025-04-16 15:35:45 +02:00
{
lib,
pkgs,
config,
...
}:
{
imports = [
# Import environment
./vm-base.nix
];
config = {
# Machine hostname
networking.hostName = "vm-audio";
# Enabled modules
modules = {
2025-04-16 17:15:33 +02:00
pipewire.enable = true;
2025-04-17 18:19:48 +02:00
spotifyd.enable = true;
};
2025-04-16 17:15:33 +02:00
# Install system packages
environment.systemPackages = with pkgs; [
carla
2025-04-17 23:58:45 +02:00
xpra
2025-04-17 19:44:46 +02:00
alsa-utils
pulsemixer
2025-04-18 10:02:16 +02:00
adwaita-icon-theme
2025-04-18 21:49:10 +02:00
open-stage-control
carla_osc_bridge
2025-04-17 04:27:10 +02:00
# Add LV2 plugins
2025-04-17 03:52:48 +02:00
lsp-plugins
2025-04-17 04:27:10 +02:00
airwindows-lv2
2025-04-17 13:30:03 +02:00
distrho-ports
cardinal
2025-04-23 15:13:51 +02:00
calf
2025-04-16 17:15:33 +02:00
];
2025-04-18 15:19:27 +02:00
# Setup firewall
networking.firewall = {
2025-04-18 17:34:36 +02:00
allowedTCPPorts = [
2025-04-18 21:50:14 +02:00
8080
2025-04-24 14:38:30 +02:00
10402
2025-04-18 17:34:36 +02:00
15151
2025-04-18 21:50:14 +02:00
22752
2025-04-18 17:34:36 +02:00
];
allowedUDPPorts = [
2025-04-18 21:50:14 +02:00
8080
2025-04-24 14:38:30 +02:00
10402
2025-04-18 17:34:36 +02:00
15151
2025-04-18 21:50:14 +02:00
22752
2025-04-18 17:34:36 +02:00
];
2025-04-18 15:19:27 +02:00
};
2025-04-17 03:04:54 +02:00
# Setup dependencies
2025-04-17 03:10:32 +02:00
environment.variables.LD_LIBRARY_PATH = lib.mkForce "${lib.makeLibraryPath (
2025-04-17 03:04:54 +02:00
with pkgs;
[
cairo
2025-04-17 03:10:32 +02:00
pipewire.jack
2025-04-17 03:04:54 +02:00
]
)}";
2025-04-24 10:48:17 +02:00
qt = {
enable = true;
style = "adwaita";
};
2025-04-18 10:02:16 +02:00
xdg.icons = {
enable = true;
fallbackCursorThemes = [ "Adwaita" ];
};
2025-04-24 17:58:04 +02:00
hardware.graphics.enable = true;
2025-04-17 03:04:54 +02:00
2025-04-16 15:23:22 +02:00
# User for audio mixing
users.users.mixer = {
2025-04-16 15:43:58 +02:00
isNormalUser = true;
2025-04-16 15:23:22 +02:00
group = "mixer";
2025-04-16 15:58:48 +02:00
extraGroups = [ "systemd-journal" ];
2025-04-16 17:04:16 +02:00
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKKxoQSxfYqf9ITN8Fhckk8WbY4dwtBAXOhC9jxihJvq jan@bulthuis.dev"
];
2025-04-16 15:23:22 +02:00
};
2025-04-16 15:24:55 +02:00
users.groups.mixer = { };
2025-04-16 21:35:26 +02:00
users.groups.audio = {
members = [
"mixer"
];
};
2025-04-26 00:50:43 +02:00
users.groups.bluetooth = {
members = [
"mixer"
];
};
2025-04-16 15:23:22 +02:00
2025-04-18 17:34:36 +02:00
# Xpra service
systemd.user.services.xpra = {
description = "Xpra Service";
wantedBy = [ "default.target" ];
after = [
"network.target"
];
unitConfig = {
ConditionUser = "mixer";
};
serviceConfig = {
ExecStart = "${pkgs.xpra}/bin/xpra start :7 --bind-tcp=0.0.0.0:15151 --daemon=no";
Restart = "always";
RestartSec = 5;
};
};
2025-04-18 15:12:08 +02:00
# Carla service
systemd.user.services.carla = {
description = "Carla Service";
wantedBy = [ "default.target" ];
after = [
"network.target"
"sound.target"
];
2025-04-18 17:34:36 +02:00
requires = [
"xpra.service"
];
2025-04-18 15:12:08 +02:00
unitConfig = {
ConditionUser = "mixer";
};
serviceConfig = {
2025-04-24 16:50:31 +02:00
ExecStart = "${pkgs.carla}/bin/carla /home/mixer/Default.carxp -platform xcb";
2025-04-18 17:41:01 +02:00
Environment = "\"DISPLAY=:7\"";
2025-04-18 15:12:08 +02:00
Restart = "always";
RestartSec = 5;
};
};
# Carla service
systemd.user.services.carla-bridge = {
description = "Carla OSC Bridge";
wantedBy = [ "default.target" ];
after = [
"network.target"
"sound.target"
];
requires = [
"carla.service"
];
unitConfig = {
ConditionUser = "mixer";
};
serviceConfig = {
2025-04-24 15:29:36 +02:00
ExecStart = "${pkgs.carla_osc_bridge}/bin/carla_osc_bridge --clients \"127.0.0.1:8080\"";
Restart = "always";
RestartSec = 5;
};
};
2025-04-18 21:49:10 +02:00
# Open stage control service
systemd.user.services.osc = {
description = "OSC Service";
wantedBy = [ "default.target" ];
after = [
"network.target"
];
requires = [
"carla.service"
];
unitConfig = {
ConditionUser = "mixer";
};
serviceConfig = {
ExecStart = "${pkgs.open-stage-control}/bin/open-stage-control --no-gui --send 127.0.0.1:10402 --load /home/mixer/open-stage-control/session.json --theme /home/mixer/open-stage-control/theme.css";
2025-04-18 21:49:10 +02:00
Environment = "\"ELECTRON_RUN_AS_NODE=1\"";
Restart = "always";
RestartSec = 5;
};
};
2025-04-26 00:30:17 +02:00
# Create bluetooth A2DP source
hardware.bluetooth = {
enable = true;
2025-04-26 13:31:01 +02:00
disabledPlugins = [ "hostname" ];
2025-04-26 00:30:17 +02:00
settings.General = {
2025-04-26 13:04:51 +02:00
Name = "Linox";
Class = "0x240414";
DiscoverableTimeout = 0;
AlwaysPairable = true;
PairableTimeout = 0;
FastConnectable = true;
2025-04-26 13:49:33 +02:00
JustWorksRepairing = "always";
2025-04-26 00:30:17 +02:00
};
};
2025-04-26 13:31:01 +02:00
services.pipewire.wireplumber.extraConfig."50-bluetooth-a2dp" = {
"monitor.bluez.properties" = {
"bluez5.roles" = [ "a2dp_source" ];
};
};
2025-04-26 00:30:17 +02:00
2025-04-18 15:12:08 +02:00
# Create null sinks
2025-04-17 19:44:46 +02:00
services.pipewire.extraConfig.pipewire."91-null-sinks" = {
"context.objects" = [
2025-04-23 15:13:51 +02:00
{
factory = "adapter";
args = {
"factory.name" = "support.null-audio-sink";
"node.name" = "Speaker-Proxy";
"node.description" = "Proxy for Speaker Output";
"media.class" = "Audio/Sink";
"audio.position" = "L,R";
};
}
{
factory = "adapter";
args = {
"factory.name" = "support.null-audio-sink";
"node.name" = "Headphone-Proxy";
"node.description" = "Proxy for Headphone Output";
"media.class" = "Audio/Sink";
"audio.position" = "L,R";
};
}
2025-04-17 19:44:46 +02:00
{
factory = "adapter";
args = {
"factory.name" = "support.null-audio-sink";
"node.name" = "SpotifyD-Proxy";
"node.description" = "Proxy for SpotifyD";
"media.class" = "Audio/Sink";
2025-04-23 15:13:51 +02:00
"audio.position" = "L,R";
2025-04-17 19:44:46 +02:00
};
}
{
factory = "adapter";
args = {
"factory.name" = "support.null-audio-sink";
"node.name" = "AnalogIn-Proxy";
"node.description" = "Proxy for the analog input";
"media.class" = "Audio/Source/Virtual";
2025-04-23 15:13:51 +02:00
"audio.position" = "L,R";
2025-04-17 19:44:46 +02:00
};
}
];
};
};
}