Add comprehensive PipeWire audio configuration with noise suppression
- Add modules/sound/pipewire.nix with full PipeWire stack - Include RNNoise AI-powered noise suppression - Add EasyEffects with pre-configured presets for mic and speakers - Include multiple GUI applications (pavucontrol, helvum, qpwgraph, pwvucontrol) - Add helper scripts: audio-setup, microphone-test, validate-audio - Optimize for low-latency real-time audio processing - Enable auto-start and desktop integration - Remove duplicate PipeWire configs from hardware-co.nix and users/common.nix - Import sound module through desktop/common.nix for all desktop machines
This commit is contained in:
parent
54e80f5c13
commit
9c9dcdc196
8 changed files with 1416 additions and 13 deletions
|
@ -19,10 +19,4 @@
|
||||||
|
|
||||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||||
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||||
# Audio system (PipeWire)
|
|
||||||
services.pipewire = {
|
|
||||||
enable = true;
|
|
||||||
alsa.enable = true;
|
|
||||||
pulse.enable = true;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,10 @@
|
||||||
pkgs,
|
pkgs,
|
||||||
...
|
...
|
||||||
}: {
|
}: {
|
||||||
|
imports = [
|
||||||
|
../sound/pipewire.nix
|
||||||
|
];
|
||||||
|
|
||||||
# Common desktop configuration shared across all environments
|
# Common desktop configuration shared across all environments
|
||||||
|
|
||||||
# XDG Portal configuration for Wayland/X11 compatibility
|
# XDG Portal configuration for Wayland/X11 compatibility
|
||||||
|
|
273
modules/sound/README.md
Normal file
273
modules/sound/README.md
Normal file
|
@ -0,0 +1,273 @@
|
||||||
|
# PipeWire with WirePlumber Configuration
|
||||||
|
|
||||||
|
This module provides a comprehensive PipeWire setup with WirePlumber session management, noise suppression, and GUI tools for audio management.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### Core Audio Stack
|
||||||
|
|
||||||
|
- **PipeWire**: Modern audio server with low latency
|
||||||
|
- **WirePlumber**: Session manager for device management and routing
|
||||||
|
- **ALSA/PulseAudio/JACK Compatibility**: Works with all major audio APIs
|
||||||
|
- **Real-time Processing**: RTKit integration for optimal performance
|
||||||
|
|
||||||
|
### Noise Suppression
|
||||||
|
|
||||||
|
- **RNNoise Plugin**: AI-powered noise suppression for microphones
|
||||||
|
- **EasyEffects Integration**: GUI for managing audio effects
|
||||||
|
- **Automatic Filter Chain**: Pre-configured noise suppression pipeline
|
||||||
|
|
||||||
|
### GUI Applications Included
|
||||||
|
|
||||||
|
- **EasyEffects**: Modern audio effects processor with noise suppression
|
||||||
|
- **PulseAudio Volume Control (pavucontrol)**: Volume and device management
|
||||||
|
- **Helvum**: Graphical PipeWire patchbay for routing
|
||||||
|
- **qpwgraph**: Qt-based PipeWire graph manager
|
||||||
|
- **pwvucontrol**: Native PipeWire volume control
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Import the Module
|
||||||
|
|
||||||
|
Add to your NixOS configuration:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
imports = [
|
||||||
|
./modules/sound/pipewire.nix
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Rebuild System
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo nixos-rebuild switch
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Verify Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check if PipeWire is running
|
||||||
|
systemctl --user status pipewire
|
||||||
|
|
||||||
|
# Launch the audio setup helper
|
||||||
|
audio-setup
|
||||||
|
|
||||||
|
# Test microphone with noise suppression
|
||||||
|
microphone-test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using Noise Suppression
|
||||||
|
|
||||||
|
### Method 1: EasyEffects (Recommended)
|
||||||
|
|
||||||
|
1. Launch EasyEffects: `easyeffects` or use the application menu
|
||||||
|
2. Go to the "Input" tab
|
||||||
|
3. Load the pre-configured "Microphone_Noise_Suppression" preset
|
||||||
|
4. Enable the RNNoise effect
|
||||||
|
5. Adjust the "VAD Threshold" (Voice Activity Detection) as needed
|
||||||
|
|
||||||
|
### Method 2: PipeWire Filter Chain (Automatic)
|
||||||
|
|
||||||
|
The configuration includes an automatic RNNoise filter chain that creates a "Noise Canceling Source" device. This appears as a separate microphone input in audio applications.
|
||||||
|
|
||||||
|
## GUI Applications Usage
|
||||||
|
|
||||||
|
### EasyEffects
|
||||||
|
|
||||||
|
- **Purpose**: Real-time audio effects and noise suppression
|
||||||
|
- **Launch**: `easyeffects` or from application menu
|
||||||
|
- **Features**: RNNoise, equalizer, compressor, limiter, gate
|
||||||
|
- **Auto-start**: Configured to start with desktop session
|
||||||
|
|
||||||
|
### Volume Controls
|
||||||
|
|
||||||
|
- **pavucontrol**: Traditional PulseAudio-style interface
|
||||||
|
- **pwvucontrol**: Native PipeWire interface
|
||||||
|
- **Usage**: Control volumes, switch devices, manage streams
|
||||||
|
|
||||||
|
### Audio Routing
|
||||||
|
|
||||||
|
- **Helvum**: Visual patchbay for connecting audio streams
|
||||||
|
- **qpwgraph**: Advanced graph-based routing interface
|
||||||
|
- **Usage**: Route audio between applications and devices
|
||||||
|
|
||||||
|
## Command-Line Tools
|
||||||
|
|
||||||
|
### System Status
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# PipeWire status overview
|
||||||
|
wpctl status
|
||||||
|
|
||||||
|
# Real-time monitoring
|
||||||
|
pw-top
|
||||||
|
|
||||||
|
# Inspect audio objects
|
||||||
|
pw-dump | jq '.'
|
||||||
|
|
||||||
|
# Show metadata
|
||||||
|
pw-metadata
|
||||||
|
```
|
||||||
|
|
||||||
|
### Device Management
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List devices
|
||||||
|
wpctl status
|
||||||
|
|
||||||
|
# Set default sink
|
||||||
|
wpctl set-default SINK_ID
|
||||||
|
|
||||||
|
# Set volume
|
||||||
|
wpctl set-volume SOURCE_ID 80%
|
||||||
|
|
||||||
|
# Mute/unmute
|
||||||
|
wpctl set-mute SOURCE_ID toggle
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test microphone
|
||||||
|
microphone-test
|
||||||
|
|
||||||
|
# Record and playback test
|
||||||
|
arecord -d 5 -f cd test.wav && aplay test.wav
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration Details
|
||||||
|
|
||||||
|
### Audio Quality Settings
|
||||||
|
|
||||||
|
- **Sample Rate**: 48kHz (professional audio standard)
|
||||||
|
- **Buffer Size**: 1024 samples (balanced latency/stability)
|
||||||
|
- **Resampling Quality**: High (level 4)
|
||||||
|
- **Channels**: Stereo support with spatial audio capabilities
|
||||||
|
|
||||||
|
### Noise Suppression Settings
|
||||||
|
|
||||||
|
- **RNNoise VAD Threshold**: 50% (adjustable)
|
||||||
|
- **VAD Grace Period**: 200ms
|
||||||
|
- **Noise Reduction**: 80% wet signal
|
||||||
|
- **Processing**: Real-time with minimal latency
|
||||||
|
|
||||||
|
### Performance Optimizations
|
||||||
|
|
||||||
|
- **Real-time Scheduling**: RTKit enabled
|
||||||
|
- **Memory Locking**: Enabled for critical processes
|
||||||
|
- **CPU Affinity**: Configurable per audio thread
|
||||||
|
- **Quantum Settings**: Optimized for low latency
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
#### No Audio Output
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check PipeWire is running
|
||||||
|
systemctl --user restart pipewire pipewire-pulse wireplumber
|
||||||
|
|
||||||
|
# Check default devices
|
||||||
|
wpctl status
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Microphone Not Working
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test microphone detection
|
||||||
|
arecord -l
|
||||||
|
|
||||||
|
# Check permissions
|
||||||
|
groups $USER | grep audio
|
||||||
|
```
|
||||||
|
|
||||||
|
#### High CPU Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Monitor PipeWire performance
|
||||||
|
pw-top
|
||||||
|
|
||||||
|
# Check buffer settings
|
||||||
|
pw-metadata | grep quantum
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Noise Suppression Not Working
|
||||||
|
|
||||||
|
1. Verify RNNoise plugin is loaded: `ladspa-ls | grep -i noise`
|
||||||
|
2. Check EasyEffects preset is loaded
|
||||||
|
3. Ensure correct input device is selected
|
||||||
|
4. Adjust VAD threshold in EasyEffects
|
||||||
|
|
||||||
|
### Reset Configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Reset user PipeWire configuration
|
||||||
|
rm -rf ~/.config/pipewire ~/.config/easyeffects
|
||||||
|
systemctl --user restart pipewire pipewire-pulse wireplumber
|
||||||
|
```
|
||||||
|
|
||||||
|
## Advanced Configuration
|
||||||
|
|
||||||
|
### Custom Filter Chains
|
||||||
|
|
||||||
|
Edit `/etc/pipewire/pipewire.conf.d/10-noise-suppression.conf` to modify the RNNoise filter chain parameters.
|
||||||
|
|
||||||
|
### Device-Specific Settings
|
||||||
|
|
||||||
|
Add rules to `/etc/wireplumber/wireplumber.conf.d/51-noise-suppression.conf` for specific audio devices.
|
||||||
|
|
||||||
|
### EasyEffects Presets
|
||||||
|
|
||||||
|
Custom presets are stored in `/etc/easyeffects/` and can be modified or extended.
|
||||||
|
|
||||||
|
## Integration with Applications
|
||||||
|
|
||||||
|
### Discord/Zoom/Teams
|
||||||
|
|
||||||
|
1. Set default microphone to "Noise Canceling Source" in application settings
|
||||||
|
2. Or use EasyEffects on the regular microphone input
|
||||||
|
3. Adjust noise gate and compressor settings as needed
|
||||||
|
|
||||||
|
### OBS Studio
|
||||||
|
|
||||||
|
1. Add "Application Audio Capture" source
|
||||||
|
2. Select the noise-suppressed microphone device
|
||||||
|
3. Or use OBS's built-in noise suppression with the processed audio
|
||||||
|
|
||||||
|
### Music Production (JACK)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Start JACK mode if needed
|
||||||
|
pw-jack your-daw-application
|
||||||
|
```
|
||||||
|
|
||||||
|
## Updates and Maintenance
|
||||||
|
|
||||||
|
### Updating Configuration
|
||||||
|
|
||||||
|
After modifying the Nix configuration:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo nixos-rebuild switch
|
||||||
|
systemctl --user restart pipewire pipewire-pulse wireplumber
|
||||||
|
```
|
||||||
|
|
||||||
|
### Monitoring Performance
|
||||||
|
|
||||||
|
Regular checks recommended:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Weekly performance check
|
||||||
|
pw-top
|
||||||
|
|
||||||
|
# Monthly configuration review
|
||||||
|
audio-setup
|
||||||
|
```
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [PipeWire Documentation](https://docs.pipewire.org/)
|
||||||
|
- [WirePlumber Documentation](https://pipewire.pages.freedesktop.org/wireplumber/)
|
||||||
|
- [EasyEffects Documentation](https://github.com/wwmm/easyeffects)
|
||||||
|
- [RNNoise Project](https://jmvalin.ca/demo/rnnoise/)
|
212
modules/sound/audio-desktop-integration.nix
Normal file
212
modules/sound/audio-desktop-integration.nix
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
# Desktop entries for quick audio management access
|
||||||
|
environment.etc = {
|
||||||
|
# Desktop entry for EasyEffects
|
||||||
|
"xdg/autostart/easyeffects.desktop".text = ''
|
||||||
|
[Desktop Entry]
|
||||||
|
Name=EasyEffects
|
||||||
|
Comment=Audio effects for PipeWire applications
|
||||||
|
Icon=easyeffects
|
||||||
|
Exec=easyeffects --gapplication-service
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
Categories=AudioVideo;Audio;
|
||||||
|
StartupNotify=true
|
||||||
|
X-GNOME-Autostart-enabled=true
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Custom desktop entry for audio control center
|
||||||
|
"applications/audio-control-center.desktop".text = ''
|
||||||
|
[Desktop Entry]
|
||||||
|
Version=1.0
|
||||||
|
Type=Application
|
||||||
|
Name=Audio Control Center
|
||||||
|
Comment=Centralized audio management
|
||||||
|
Icon=audio-volume-high
|
||||||
|
Categories=AudioVideo;Audio;Settings;
|
||||||
|
Keywords=audio;sound;volume;pipewire;pulseaudio;
|
||||||
|
StartupNotify=true
|
||||||
|
Terminal=false
|
||||||
|
Exec=sh -c 'if command -v easyeffects >/dev/null 2>&1; then easyeffects; elif command -v pavucontrol >/dev/null 2>&1; then pavucontrol; elif command -v pwvucontrol >/dev/null 2>&1; then pwvucontrol; else helvum; fi'
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Create a script for easy audio management
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
(writeShellScriptBin "audio-setup" ''
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "🎵 Audio Control Center"
|
||||||
|
echo "======================"
|
||||||
|
echo ""
|
||||||
|
echo "Available audio applications:"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if command -v easyeffects >/dev/null 2>&1; then
|
||||||
|
echo " 1. EasyEffects - Audio effects and noise suppression"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v pavucontrol >/dev/null 2>&1; then
|
||||||
|
echo " 2. PulseAudio Volume Control - Volume and device management"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v pwvucontrol >/dev/null 2>&1; then
|
||||||
|
echo " 3. PipeWire Volume Control - Native PipeWire control"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v helvum >/dev/null 2>&1; then
|
||||||
|
echo " 4. Helvum - PipeWire patchbay"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v qpwgraph >/dev/null 2>&1; then
|
||||||
|
echo " 5. qpwgraph - Qt PipeWire graph manager"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo " 🔧 Audio Tools:"
|
||||||
|
echo " • pw-top - Monitor PipeWire performance"
|
||||||
|
echo " • pw-dump - Inspect PipeWire objects"
|
||||||
|
echo " • pw-metadata - View/set PipeWire metadata"
|
||||||
|
echo " • wpctl - WirePlumber control utility"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "Choose an option (1-5) or press Enter for EasyEffects:"
|
||||||
|
read -r choice
|
||||||
|
|
||||||
|
case $choice in
|
||||||
|
1|"")
|
||||||
|
if command -v easyeffects >/dev/null 2>&1; then
|
||||||
|
echo "Starting EasyEffects..."
|
||||||
|
easyeffects
|
||||||
|
else
|
||||||
|
echo "EasyEffects not found!"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
if command -v pavucontrol >/dev/null 2>&1; then
|
||||||
|
echo "Starting PulseAudio Volume Control..."
|
||||||
|
pavucontrol
|
||||||
|
else
|
||||||
|
echo "pavucontrol not found!"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
if command -v pwvucontrol >/dev/null 2>&1; then
|
||||||
|
echo "Starting PipeWire Volume Control..."
|
||||||
|
pwvucontrol
|
||||||
|
else
|
||||||
|
echo "pwvucontrol not found!"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
4)
|
||||||
|
if command -v helvum >/dev/null 2>&1; then
|
||||||
|
echo "Starting Helvum..."
|
||||||
|
helvum
|
||||||
|
else
|
||||||
|
echo "Helvum not found!"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
5)
|
||||||
|
if command -v qpwgraph >/dev/null 2>&1; then
|
||||||
|
echo "Starting qpwgraph..."
|
||||||
|
qpwgraph
|
||||||
|
else
|
||||||
|
echo "qpwgraph not found!"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Invalid choice"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
'')
|
||||||
|
|
||||||
|
(writeShellScriptBin "microphone-test" ''
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "🎤 Microphone Test & Setup"
|
||||||
|
echo "=========================="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check if PipeWire is running
|
||||||
|
if ! pgrep -x pipewire >/dev/null; then
|
||||||
|
echo "❌ PipeWire is not running!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ PipeWire is running"
|
||||||
|
|
||||||
|
# Check for RNNoise
|
||||||
|
if ls /nix/store/*/lib/ladspa/librnnoise_ladspa.so >/dev/null 2>&1; then
|
||||||
|
echo "✅ RNNoise plugin is available"
|
||||||
|
else
|
||||||
|
echo "⚠️ RNNoise plugin not found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# List audio sources
|
||||||
|
echo ""
|
||||||
|
echo "📺 Available audio sources:"
|
||||||
|
wpctl status | grep -A 20 "Audio Sources"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "🔊 Available audio sinks:"
|
||||||
|
wpctl status | grep -A 20 "Audio Sinks"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Would you like to:"
|
||||||
|
echo " 1. Test microphone input"
|
||||||
|
echo " 2. Open EasyEffects for noise suppression setup"
|
||||||
|
echo " 3. Show detailed audio device information"
|
||||||
|
echo " 4. Monitor audio levels"
|
||||||
|
echo ""
|
||||||
|
read -p "Choose an option (1-4): " choice
|
||||||
|
|
||||||
|
case $choice in
|
||||||
|
1)
|
||||||
|
echo "Recording 5 seconds of audio for playback test..."
|
||||||
|
echo "Speak into your microphone now!"
|
||||||
|
if command -v arecord >/dev/null 2>&1 && command -v aplay >/dev/null 2>&1; then
|
||||||
|
arecord -d 5 -f cd /tmp/mic_test.wav && echo "Playing back recording..." && aplay /tmp/mic_test.wav
|
||||||
|
rm -f /tmp/mic_test.wav
|
||||||
|
else
|
||||||
|
echo "❌ ALSA utilities not available"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
if command -v easyeffects >/dev/null 2>&1; then
|
||||||
|
echo "Opening EasyEffects..."
|
||||||
|
easyeffects &
|
||||||
|
else
|
||||||
|
echo "❌ EasyEffects not found"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
echo ""
|
||||||
|
echo "🔍 Detailed audio information:"
|
||||||
|
echo ""
|
||||||
|
pw-dump | jq '.[] | select(.info.props."media.class" == "Audio/Source" or .info.props."media.class" == "Audio/Sink") | {id: .id, name: .info.props."node.name", description: .info.props."node.description", class: .info.props."media.class"}'
|
||||||
|
;;
|
||||||
|
4)
|
||||||
|
echo "Monitoring audio levels (Ctrl+C to stop)..."
|
||||||
|
if command -v pw-top >/dev/null 2>&1; then
|
||||||
|
pw-top
|
||||||
|
else
|
||||||
|
echo "Monitoring with wpctl..."
|
||||||
|
while true; do
|
||||||
|
clear
|
||||||
|
wpctl status
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Invalid choice"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
'')
|
||||||
|
];
|
||||||
|
}
|
546
modules/sound/easyeffects-presets.nix
Normal file
546
modules/sound/easyeffects-presets.nix
Normal file
|
@ -0,0 +1,546 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
# Create EasyEffects configuration directory and presets
|
||||||
|
environment.etc = {
|
||||||
|
# Input preset for microphone noise suppression
|
||||||
|
"easyeffects/input/Microphone_Noise_Suppression.json".text = builtins.toJSON {
|
||||||
|
input = {
|
||||||
|
blocklist = [];
|
||||||
|
equalizer = {
|
||||||
|
balance = 0.0;
|
||||||
|
bypass = false;
|
||||||
|
input-gain = 0.0;
|
||||||
|
left = {
|
||||||
|
band0 = {
|
||||||
|
frequency = 29.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band1 = {
|
||||||
|
frequency = 59.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band2 = {
|
||||||
|
frequency = 119.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band3 = {
|
||||||
|
frequency = 237.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band4 = {
|
||||||
|
frequency = 474.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band5 = {
|
||||||
|
frequency = 947.0;
|
||||||
|
gain = 2.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band6 = {
|
||||||
|
frequency = 1889.0;
|
||||||
|
gain = 1.5;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band7 = {
|
||||||
|
frequency = 3770.0;
|
||||||
|
gain = 1.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band8 = {
|
||||||
|
frequency = 7523.0;
|
||||||
|
gain = 0.5;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band9 = {
|
||||||
|
frequency = 15011.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
mode = "IIR";
|
||||||
|
num-bands = 10;
|
||||||
|
output-gain = 0.0;
|
||||||
|
pitch-left = 0.0;
|
||||||
|
pitch-right = 0.0;
|
||||||
|
right = {
|
||||||
|
band0 = {
|
||||||
|
frequency = 29.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band1 = {
|
||||||
|
frequency = 59.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band2 = {
|
||||||
|
frequency = 119.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band3 = {
|
||||||
|
frequency = 237.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band4 = {
|
||||||
|
frequency = 474.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band5 = {
|
||||||
|
frequency = 947.0;
|
||||||
|
gain = 2.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band6 = {
|
||||||
|
frequency = 1889.0;
|
||||||
|
gain = 1.5;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band7 = {
|
||||||
|
frequency = 3770.0;
|
||||||
|
gain = 1.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band8 = {
|
||||||
|
frequency = 7523.0;
|
||||||
|
gain = 0.5;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band9 = {
|
||||||
|
frequency = 15011.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
split-channels = false;
|
||||||
|
};
|
||||||
|
filter = {
|
||||||
|
balance = 0.0;
|
||||||
|
bypass = false;
|
||||||
|
frequency = 2000.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "12dB/oct Highpass";
|
||||||
|
quality = 0.7071;
|
||||||
|
slope = "x1";
|
||||||
|
};
|
||||||
|
gate = {
|
||||||
|
attack = 20.0;
|
||||||
|
bypass = false;
|
||||||
|
curve-threshold = -24.0;
|
||||||
|
curve-zone = 2.0;
|
||||||
|
hpf-frequency = 10.0;
|
||||||
|
hpf-mode = "12dB/oct Highpass";
|
||||||
|
input-gain = 0.0;
|
||||||
|
knee = 2.5;
|
||||||
|
lpf-frequency = 20000.0;
|
||||||
|
lpf-mode = "12dB/oct Lowpass";
|
||||||
|
makeup = 0.0;
|
||||||
|
ratio = 2.0;
|
||||||
|
release = 250.0;
|
||||||
|
sidechain = {
|
||||||
|
lookahead = 0.0;
|
||||||
|
mode = "RMS";
|
||||||
|
preamp = 0.0;
|
||||||
|
reactivity = 10.0;
|
||||||
|
source = "Middle";
|
||||||
|
};
|
||||||
|
threshold = -18.0;
|
||||||
|
};
|
||||||
|
limiter = {
|
||||||
|
alr = false;
|
||||||
|
alr-attack = 5.0;
|
||||||
|
alr-knee = 0.0;
|
||||||
|
alr-release = 50.0;
|
||||||
|
attack = 5.0;
|
||||||
|
bypass = false;
|
||||||
|
dithering = "None";
|
||||||
|
external-sidechain = false;
|
||||||
|
gain-boost = true;
|
||||||
|
input-gain = 0.0;
|
||||||
|
lookahead = 5.0;
|
||||||
|
mode = "Herm Thin";
|
||||||
|
output-gain = 0.0;
|
||||||
|
oversampling = "None";
|
||||||
|
release = 5.0;
|
||||||
|
sidechain-preamp = 0.0;
|
||||||
|
stereo-link = 100.0;
|
||||||
|
threshold = 0.0;
|
||||||
|
};
|
||||||
|
plugins_order = [
|
||||||
|
"filter"
|
||||||
|
"gate"
|
||||||
|
"equalizer"
|
||||||
|
"rnnoise"
|
||||||
|
"limiter"
|
||||||
|
];
|
||||||
|
rnnoise = {
|
||||||
|
bypass = false;
|
||||||
|
enable-vad = true;
|
||||||
|
input-gain = 0.0;
|
||||||
|
model-path = "";
|
||||||
|
output-gain = 0.0;
|
||||||
|
release = 20.0;
|
||||||
|
vad-thres = 50.0;
|
||||||
|
wet = 80.0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Output preset for speakers/headphones
|
||||||
|
"easyeffects/output/Speakers_Enhanced.json".text = builtins.toJSON {
|
||||||
|
output = {
|
||||||
|
blocklist = [];
|
||||||
|
equalizer = {
|
||||||
|
balance = 0.0;
|
||||||
|
bypass = false;
|
||||||
|
input-gain = 0.0;
|
||||||
|
left = {
|
||||||
|
band0 = {
|
||||||
|
frequency = 29.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band1 = {
|
||||||
|
frequency = 59.0;
|
||||||
|
gain = 1.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band2 = {
|
||||||
|
frequency = 119.0;
|
||||||
|
gain = 0.5;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band3 = {
|
||||||
|
frequency = 237.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band4 = {
|
||||||
|
frequency = 474.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band5 = {
|
||||||
|
frequency = 947.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band6 = {
|
||||||
|
frequency = 1889.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band7 = {
|
||||||
|
frequency = 3770.0;
|
||||||
|
gain = 1.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band8 = {
|
||||||
|
frequency = 7523.0;
|
||||||
|
gain = 2.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band9 = {
|
||||||
|
frequency = 15011.0;
|
||||||
|
gain = 1.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
mode = "IIR";
|
||||||
|
num-bands = 10;
|
||||||
|
output-gain = 0.0;
|
||||||
|
pitch-left = 0.0;
|
||||||
|
pitch-right = 0.0;
|
||||||
|
right = {
|
||||||
|
band0 = {
|
||||||
|
frequency = 29.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band1 = {
|
||||||
|
frequency = 59.0;
|
||||||
|
gain = 1.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band2 = {
|
||||||
|
frequency = 119.0;
|
||||||
|
gain = 0.5;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band3 = {
|
||||||
|
frequency = 237.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band4 = {
|
||||||
|
frequency = 474.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band5 = {
|
||||||
|
frequency = 947.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band6 = {
|
||||||
|
frequency = 1889.0;
|
||||||
|
gain = 0.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band7 = {
|
||||||
|
frequency = 3770.0;
|
||||||
|
gain = 1.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band8 = {
|
||||||
|
frequency = 7523.0;
|
||||||
|
gain = 2.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
band9 = {
|
||||||
|
frequency = 15011.0;
|
||||||
|
gain = 1.0;
|
||||||
|
mode = "RLC (BT)";
|
||||||
|
mute = false;
|
||||||
|
q = 4.36;
|
||||||
|
slope = "x1";
|
||||||
|
solo = false;
|
||||||
|
type = "Bell";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
split-channels = false;
|
||||||
|
};
|
||||||
|
limiter = {
|
||||||
|
alr = false;
|
||||||
|
alr-attack = 5.0;
|
||||||
|
alr-knee = 0.0;
|
||||||
|
alr-release = 50.0;
|
||||||
|
attack = 5.0;
|
||||||
|
bypass = false;
|
||||||
|
dithering = "None";
|
||||||
|
external-sidechain = false;
|
||||||
|
gain-boost = true;
|
||||||
|
input-gain = 0.0;
|
||||||
|
lookahead = 5.0;
|
||||||
|
mode = "Herm Thin";
|
||||||
|
output-gain = 0.0;
|
||||||
|
oversampling = "None";
|
||||||
|
release = 5.0;
|
||||||
|
sidechain-preamp = 0.0;
|
||||||
|
stereo-link = 100.0;
|
||||||
|
threshold = -1.0;
|
||||||
|
};
|
||||||
|
plugins_order = [
|
||||||
|
"equalizer"
|
||||||
|
"limiter"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
177
modules/sound/pipewire.nix
Normal file
177
modules/sound/pipewire.nix
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
imports = [
|
||||||
|
./easyeffects-presets.nix
|
||||||
|
./audio-desktop-integration.nix
|
||||||
|
];
|
||||||
|
# Enable PipeWire with full audio stack
|
||||||
|
services.pipewire = {
|
||||||
|
enable = true;
|
||||||
|
alsa.enable = true;
|
||||||
|
alsa.support32Bit = true;
|
||||||
|
pulse.enable = true;
|
||||||
|
jack.enable = true;
|
||||||
|
|
||||||
|
# Enable WirePlumber session manager
|
||||||
|
wireplumber.enable = true;
|
||||||
|
|
||||||
|
# Add noise suppression and audio processing packages
|
||||||
|
extraPackages = with pkgs; [
|
||||||
|
rnnoise-plugin # RNNoise noise suppression
|
||||||
|
easyeffects # Modern audio effects and filters
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Install audio management and GUI applications
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
# Audio control and monitoring
|
||||||
|
pavucontrol # PulseAudio volume control (works with PipeWire)
|
||||||
|
helvum # Graphical patchbay for PipeWire
|
||||||
|
qpwgraph # Qt-based PipeWire graph manager
|
||||||
|
easyeffects # Audio effects and noise suppression GUI
|
||||||
|
pwvucontrol # Native PipeWire volume control
|
||||||
|
|
||||||
|
# Audio utilities
|
||||||
|
wireplumber # WirePlumber session manager
|
||||||
|
pipewire-pulse # PulseAudio compatibility
|
||||||
|
pipecontrol # PipeWire control utility
|
||||||
|
alsa-utils # ALSA utilities for testing
|
||||||
|
|
||||||
|
# Validation script
|
||||||
|
(writeShellScriptBin "validate-audio" (builtins.readFile ./validate-audio.sh))
|
||||||
|
|
||||||
|
# Optional: Professional audio tools
|
||||||
|
# qjackctl # JACK control GUI (for JACK applications)
|
||||||
|
# carla # Audio plugin host
|
||||||
|
];
|
||||||
|
|
||||||
|
# System-wide PipeWire configuration
|
||||||
|
environment.etc = {
|
||||||
|
# Main PipeWire configuration
|
||||||
|
"pipewire/pipewire.conf.d/10-noise-suppression.conf".text = ''
|
||||||
|
context.properties = {
|
||||||
|
default.clock.rate = 48000
|
||||||
|
default.clock.quantum = 1024
|
||||||
|
default.clock.min-quantum = 32
|
||||||
|
default.clock.max-quantum = 2048
|
||||||
|
}
|
||||||
|
|
||||||
|
context.modules = [
|
||||||
|
{
|
||||||
|
name = libpipewire-module-filter-chain
|
||||||
|
args = {
|
||||||
|
node.description = "Noise Canceling Source"
|
||||||
|
media.name = "Noise Canceling Source"
|
||||||
|
filter.graph = {
|
||||||
|
nodes = [
|
||||||
|
{
|
||||||
|
type = ladspa
|
||||||
|
name = rnnoise
|
||||||
|
plugin = ${pkgs.rnnoise-plugin}/lib/ladspa/librnnoise_ladspa.so
|
||||||
|
label = noise_suppressor_stereo
|
||||||
|
control = {
|
||||||
|
"VAD Threshold (%)" = 50.0
|
||||||
|
"VAD Grace Period (ms)" = 200
|
||||||
|
"Retroactive VAD Grace (ms)" = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
capture.props = {
|
||||||
|
node.name = "capture.rnnoise_source"
|
||||||
|
node.passive = true
|
||||||
|
audio.rate = 48000
|
||||||
|
}
|
||||||
|
playback.props = {
|
||||||
|
node.name = "rnnoise_source"
|
||||||
|
media.class = "Audio/Source"
|
||||||
|
audio.rate = 48000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
'';
|
||||||
|
|
||||||
|
# WirePlumber configuration for noise suppression
|
||||||
|
"wireplumber/wireplumber.conf.d/51-noise-suppression.conf".text = ''
|
||||||
|
monitor.alsa.rules = [
|
||||||
|
{
|
||||||
|
matches = [
|
||||||
|
{
|
||||||
|
device.name = "~alsa_card.*"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
actions = {
|
||||||
|
update-props = {
|
||||||
|
device.profile-set = "auto"
|
||||||
|
device.auto-profile = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
monitor.bluez.rules = [
|
||||||
|
{
|
||||||
|
matches = [
|
||||||
|
{
|
||||||
|
device.name = "~bluez_card.*"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
actions = {
|
||||||
|
update-props = {
|
||||||
|
bluez5.auto-connect = [ "hfp_hf" "hsp_hs" "a2dp_sink" ]
|
||||||
|
bluez5.hw-volume = [ "hfp_hf" "hsp_hs" "a2dp_sink" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Audio quality and latency optimization
|
||||||
|
"pipewire/pipewire-pulse.conf.d/10-audio-quality.conf".text = ''
|
||||||
|
pulse.properties = {
|
||||||
|
pulse.min.req = 32/48000
|
||||||
|
pulse.default.req = 1024/48000
|
||||||
|
pulse.min.quantum = 32/48000
|
||||||
|
pulse.max.quantum = 2048/48000
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.properties = {
|
||||||
|
node.latency = 1024/48000
|
||||||
|
resample.quality = 4
|
||||||
|
channelmix.normalize = false
|
||||||
|
channelmix.mix-lfe = false
|
||||||
|
session.suspend-timeout-seconds = 0
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Enable real-time audio processing
|
||||||
|
security.rtkit.enable = true;
|
||||||
|
|
||||||
|
# Audio group for users
|
||||||
|
users.groups.audio = {};
|
||||||
|
|
||||||
|
# Set environment variables for better audio performance
|
||||||
|
environment.variables = {
|
||||||
|
# PipeWire environment variables
|
||||||
|
PIPEWIRE_LATENCY = "1024/48000";
|
||||||
|
# Ensure applications use PipeWire
|
||||||
|
PULSE_RUNTIME_PATH = "/run/user/$UID/pulse";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Enable additional audio-related services
|
||||||
|
services = {
|
||||||
|
# Enable udev rules for audio devices
|
||||||
|
udev.packages = with pkgs; [
|
||||||
|
alsa-utils
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# User session configuration for audio
|
||||||
|
systemd.user.services.pipewire-pulse.wantedBy = ["default.target"];
|
||||||
|
}
|
204
modules/sound/validate-audio.sh
Executable file
204
modules/sound/validate-audio.sh
Executable file
|
@ -0,0 +1,204 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Audio Configuration Validation Script
|
||||||
|
# This script helps validate that PipeWire with noise suppression is working correctly
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "🎵 PipeWire Audio Configuration Validator"
|
||||||
|
echo "========================================"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
success() {
|
||||||
|
echo -e "${GREEN}✅ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
warning() {
|
||||||
|
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
error() {
|
||||||
|
echo -e "${RED}❌ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
info() {
|
||||||
|
echo -e "${BLUE}ℹ️ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if PipeWire is running
|
||||||
|
echo "1. Checking PipeWire service status..."
|
||||||
|
if systemctl --user is-active pipewire >/dev/null 2>&1; then
|
||||||
|
success "PipeWire service is running"
|
||||||
|
else
|
||||||
|
error "PipeWire service is not running"
|
||||||
|
echo " Try: systemctl --user start pipewire"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check WirePlumber
|
||||||
|
echo ""
|
||||||
|
echo "2. Checking WirePlumber session manager..."
|
||||||
|
if systemctl --user is-active wireplumber >/dev/null 2>&1; then
|
||||||
|
success "WirePlumber is running"
|
||||||
|
else
|
||||||
|
warning "WirePlumber is not running"
|
||||||
|
echo " Try: systemctl --user start wireplumber"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check PipeWire-Pulse
|
||||||
|
echo ""
|
||||||
|
echo "3. Checking PipeWire-Pulse compatibility..."
|
||||||
|
if systemctl --user is-active pipewire-pulse >/dev/null 2>&1; then
|
||||||
|
success "PipeWire-Pulse is running"
|
||||||
|
else
|
||||||
|
warning "PipeWire-Pulse is not running"
|
||||||
|
echo " Try: systemctl --user start pipewire-pulse"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for RNNoise plugin
|
||||||
|
echo ""
|
||||||
|
echo "4. Checking for RNNoise noise suppression plugin..."
|
||||||
|
if find /nix/store -name "librnnoise_ladspa.so" 2>/dev/null | head -1 | grep -q .; then
|
||||||
|
success "RNNoise plugin found"
|
||||||
|
RNNOISE_PATH=$(find /nix/store -name "librnnoise_ladspa.so" 2>/dev/null | head -1)
|
||||||
|
info "Located at: $RNNOISE_PATH"
|
||||||
|
else
|
||||||
|
error "RNNoise plugin not found"
|
||||||
|
echo " This might indicate the package is not installed correctly"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check audio devices
|
||||||
|
echo ""
|
||||||
|
echo "5. Checking available audio devices..."
|
||||||
|
if command -v wpctl >/dev/null 2>&1; then
|
||||||
|
SOURCES=$(wpctl status | grep -A 10 "Audio Sources" | grep -c "│" || echo "0")
|
||||||
|
SINKS=$(wpctl status | grep -A 10 "Audio Sinks" | grep -c "│" || echo "0")
|
||||||
|
|
||||||
|
if [ "$SOURCES" -gt 0 ]; then
|
||||||
|
success "Found $SOURCES audio source(s)"
|
||||||
|
else
|
||||||
|
warning "No audio sources found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$SINKS" -gt 0 ]; then
|
||||||
|
success "Found $SINKS audio sink(s)"
|
||||||
|
else
|
||||||
|
warning "No audio sinks found"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
error "wpctl command not found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for GUI applications
|
||||||
|
echo ""
|
||||||
|
echo "6. Checking GUI audio applications..."
|
||||||
|
|
||||||
|
if command -v easyeffects >/dev/null 2>&1; then
|
||||||
|
success "EasyEffects available"
|
||||||
|
else
|
||||||
|
warning "EasyEffects not found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v pavucontrol >/dev/null 2>&1; then
|
||||||
|
success "PulseAudio Volume Control available"
|
||||||
|
else
|
||||||
|
warning "pavucontrol not found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v helvum >/dev/null 2>&1; then
|
||||||
|
success "Helvum patchbay available"
|
||||||
|
else
|
||||||
|
warning "Helvum not found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check configuration files
|
||||||
|
echo ""
|
||||||
|
echo "7. Checking configuration files..."
|
||||||
|
|
||||||
|
CONFIG_FILES=(
|
||||||
|
"/etc/pipewire/pipewire.conf.d/10-noise-suppression.conf"
|
||||||
|
"/etc/wireplumber/wireplumber.conf.d/51-noise-suppression.conf"
|
||||||
|
"/etc/pipewire/pipewire-pulse.conf.d/10-audio-quality.conf"
|
||||||
|
)
|
||||||
|
|
||||||
|
for config in "${CONFIG_FILES[@]}"; do
|
||||||
|
if [ -f "$config" ]; then
|
||||||
|
success "$(basename "$config") exists"
|
||||||
|
else
|
||||||
|
warning "$(basename "$config") not found"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check for noise canceling source
|
||||||
|
echo ""
|
||||||
|
echo "8. Checking for noise canceling source..."
|
||||||
|
if command -v pw-dump >/dev/null 2>&1; then
|
||||||
|
if pw-dump | jq -r '.[] | select(.info.props."node.name" == "rnnoise_source") | .info.props."node.description"' 2>/dev/null | grep -q "Noise Canceling"; then
|
||||||
|
success "Noise Canceling Source device found"
|
||||||
|
else
|
||||||
|
warning "Noise Canceling Source device not found"
|
||||||
|
info "This is normal if no microphone is connected"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warning "pw-dump not available, cannot check for noise canceling source"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Performance check
|
||||||
|
echo ""
|
||||||
|
echo "9. Checking audio performance..."
|
||||||
|
if command -v pw-top >/dev/null 2>&1; then
|
||||||
|
info "You can monitor real-time performance with: pw-top"
|
||||||
|
else
|
||||||
|
warning "pw-top not available for performance monitoring"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
echo ""
|
||||||
|
echo "🎯 Quick Start Commands:"
|
||||||
|
echo "========================"
|
||||||
|
echo ""
|
||||||
|
echo "Start audio setup wizard: audio-setup"
|
||||||
|
echo "Test microphone: microphone-test"
|
||||||
|
echo "Launch EasyEffects: easyeffects"
|
||||||
|
echo "Control volumes: pavucontrol"
|
||||||
|
echo "Audio routing: helvum"
|
||||||
|
echo "Monitor performance: pw-top"
|
||||||
|
echo "Device status: wpctl status"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check if user wants to run a test
|
||||||
|
echo "Would you like to run a quick microphone test? (y/N)"
|
||||||
|
read -r response
|
||||||
|
if [[ "$response" =~ ^[Yy]$ ]]; then
|
||||||
|
echo ""
|
||||||
|
info "Starting microphone test..."
|
||||||
|
if command -v microphone-test >/dev/null 2>&1; then
|
||||||
|
microphone-test
|
||||||
|
else
|
||||||
|
echo "Recording 3 seconds of audio..."
|
||||||
|
if command -v arecord >/dev/null 2>&1 && command -v aplay >/dev/null 2>&1; then
|
||||||
|
arecord -d 3 -f cd /tmp/audio_test.wav 2>/dev/null && \
|
||||||
|
echo "Playing back..." && \
|
||||||
|
aplay /tmp/audio_test.wav 2>/dev/null && \
|
||||||
|
rm -f /tmp/audio_test.wav
|
||||||
|
success "Microphone test completed"
|
||||||
|
else
|
||||||
|
error "Audio testing tools not available"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
success "Audio configuration validation completed!"
|
||||||
|
echo ""
|
||||||
|
info "If you encounter issues, try:"
|
||||||
|
echo " • systemctl --user restart pipewire pipewire-pulse wireplumber"
|
||||||
|
echo " • Check the README.md for detailed troubleshooting"
|
||||||
|
echo " • Run 'audio-setup' for interactive configuration"
|
|
@ -69,13 +69,6 @@
|
||||||
X11Forwarding = true; # For GUI applications over SSH
|
X11Forwarding = true; # For GUI applications over SSH
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# Enable sound
|
|
||||||
pipewire = {
|
|
||||||
enable = true;
|
|
||||||
alsa.enable = true;
|
|
||||||
pulse.enable = true;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# XDG portal for desktop integration
|
# XDG portal for desktop integration
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue