From 406acb3dafc5b2e1218fd7895d2efd91d6579eb0 Mon Sep 17 00:00:00 2001 From: Geir Okkenhaug Jerstad Date: Wed, 18 Jun 2025 21:46:31 +0200 Subject: [PATCH] fix: improve voice quality and add distortion troubleshooting - Fix RNNoise configuration: use mono instead of stereo, increase VAD threshold to 95% - Adjust quantum settings: increase min-quantum to 64 for stability - Add comprehensive voice distortion troubleshoot script - Create optional disable-auto-rnnoise.nix for problematic setups - The automatic RNNoise filter can cause artifacts, script helps diagnose and fix --- modules/sound/disable-auto-rnnoise.nix | 25 ++ modules/sound/pipewire.nix | 13 +- .../sound/troubleshoot-voice-distortion.sh | 285 ++++++++++++++++++ 3 files changed, 318 insertions(+), 5 deletions(-) create mode 100644 modules/sound/disable-auto-rnnoise.nix create mode 100755 modules/sound/troubleshoot-voice-distortion.sh diff --git a/modules/sound/disable-auto-rnnoise.nix b/modules/sound/disable-auto-rnnoise.nix new file mode 100644 index 0000000..43d6080 --- /dev/null +++ b/modules/sound/disable-auto-rnnoise.nix @@ -0,0 +1,25 @@ +{ + config, + lib, + pkgs, + ... +}: { + # Optional configuration to disable automatic RNNoise filter + # This can be imported if the automatic filter causes distortion + + services.pipewire = { + extraConfig.pipewire."15-disable-auto-rnnoise" = { + "context.modules" = [ + # Commenting out the automatic RNNoise filter + # Users should use EasyEffects for manual noise suppression instead + # { + # name = "libpipewire-module-filter-chain"; + # args = { + # "node.description" = "Noise Canceling Source"; + # # ... rest of RNNoise config + # }; + # } + ]; + }; + }; +} diff --git a/modules/sound/pipewire.nix b/modules/sound/pipewire.nix index ea50a81..15f1b0b 100644 --- a/modules/sound/pipewire.nix +++ b/modules/sound/pipewire.nix @@ -24,8 +24,8 @@ "context.properties" = { "default.clock.rate" = 48000; "default.clock.quantum" = 1024; - "default.clock.min-quantum" = 32; - "default.clock.max-quantum" = 2048; + "default.clock.min-quantum" = 64; + "default.clock.max-quantum" = 8192; }; "context.modules" = [ @@ -40,10 +40,10 @@ type = "ladspa"; name = "rnnoise"; plugin = "${pkgs.rnnoise-plugin}/lib/ladspa/librnnoise_ladspa.so"; - label = "noise_suppressor_stereo"; + label = "noise_suppressor_mono"; control = { - "VAD Threshold (%)" = 50.0; - "VAD Grace Period (ms)" = 200; + "VAD Threshold (%)" = 95.0; + "VAD Grace Period (ms)" = 100; "Retroactive VAD Grace (ms)" = 0; }; } @@ -84,6 +84,9 @@ # Validation script (writeShellScriptBin "validate-audio" (builtins.readFile ./validate-audio.sh)) + + # Troubleshoot script for voice distortion + (writeShellScriptBin "troubleshoot-voice-distortion" (builtins.readFile ./troubleshoot-voice-distortion.sh)) # Optional: Professional audio tools # qjackctl # JACK control GUI (for JACK applications) diff --git a/modules/sound/troubleshoot-voice-distortion.sh b/modules/sound/troubleshoot-voice-distortion.sh new file mode 100755 index 0000000..2cf1a70 --- /dev/null +++ b/modules/sound/troubleshoot-voice-distortion.sh @@ -0,0 +1,285 @@ +#!/usr/bin/env bash + +# Voice Distortion Troubleshoot Script +# This script helps diagnose and fix voice distortion issues in PipeWire + +set -euo pipefail + +echo "🎤 Voice Distortion Troubleshoot Tool" +echo "====================================" +echo "" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +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}" +} + +highlight() { + echo -e "${CYAN}🔧 $1${NC}" +} + +echo "Let's diagnose your voice distortion issue step by step..." +echo "" + +# 1. Check current audio settings +echo "1. Current Audio Configuration" +echo "==============================" + +if command -v wpctl >/dev/null 2>&1; then + echo "Default devices:" + wpctl status | head -20 + echo "" + + # Get default source + DEFAULT_SOURCE=$(wpctl inspect @DEFAULT_AUDIO_SOURCE@ 2>/dev/null | grep "node.name" | head -1 | sed 's/.*"\(.*\)".*/\1/' || echo "unknown") + info "Current default source: $DEFAULT_SOURCE" + + # Check sample rate + CURRENT_RATE=$(pw-metadata -n settings | grep "clock.rate" | awk '{print $3}' || echo "unknown") + info "Current sample rate: $CURRENT_RATE Hz" + + # Check buffer size + CURRENT_QUANTUM=$(pw-metadata -n settings | grep "clock.quantum" | awk '{print $3}' || echo "unknown") + info "Current buffer size: $CURRENT_QUANTUM samples" + +else + error "wpctl not available" +fi + +echo "" + +# 2. Check for common distortion causes +echo "2. Distortion Diagnosis" +echo "======================" + +# Check if using RNNoise filter +if pw-dump 2>/dev/null | jq -r '.[] | select(.info.props."node.name" == "rnnoise_source")' | grep -q "rnnoise"; then + warning "You're using the RNNoise filter chain - this might be causing distortion" + echo " The automatic filter chain can sometimes cause artifacts" +else + info "Not using automatic RNNoise filter" +fi + +# Check for high CPU usage +if command -v pw-top >/dev/null 2>&1; then + highlight "Checking PipeWire performance (5 seconds)..." + timeout 5 pw-top --batch-mode 2>/dev/null | tail -10 || warning "Could not check performance" +fi + +# Check input levels +if command -v wpctl >/dev/null 2>&1; then + echo "" + echo "Current microphone volume levels:" + wpctl get-volume @DEFAULT_AUDIO_SOURCE@ || warning "Could not get volume info" +fi + +echo "" + +# 3. Quick fixes +echo "3. Quick Fixes to Try" +echo "====================" +echo "" + +echo "Choose a solution to try:" +echo "" +echo "A) Disable automatic RNNoise filter (recommended first step)" +echo "B) Lower microphone input gain" +echo "C) Reduce buffer size for lower latency" +echo "D) Use EasyEffects instead of filter chain" +echo "E) Reset to safe audio settings" +echo "F) Test different sample rates" +echo "G) Monitor audio in real-time" +echo "H) All of the above (comprehensive fix)" +echo "" + +read -p "Enter your choice (A-H): " choice + +case $choice in + A|a) + echo "" + highlight "Disabling automatic RNNoise filter..." + if pw-dump 2>/dev/null | jq -r '.[] | select(.info.props."node.name" == "rnnoise_source") | .id' | while read id; do + echo "Removing filter node $id" + pw-cli destroy "$id" 2>/dev/null || warning "Could not remove filter $id" + done; then + success "RNNoise filter disabled" + echo "Try speaking now. If distortion is gone, use EasyEffects for noise suppression instead." + else + warning "Could not disable RNNoise filter automatically" + fi + ;; + + B|b) + echo "" + highlight "Lowering microphone input gain to 50%..." + wpctl set-volume @DEFAULT_AUDIO_SOURCE@ 50% + success "Microphone gain reduced to 50%" + echo "Test your voice now. Adjust further if needed with: wpctl set-volume @DEFAULT_AUDIO_SOURCE@ X%" + ;; + + C|c) + echo "" + highlight "Setting lower buffer size for reduced latency..." + pw-metadata -n settings 0 clock.force-quantum 512 + success "Buffer size set to 512 samples" + echo "This should reduce latency but may increase CPU usage" + ;; + + D|d) + echo "" + highlight "Launching EasyEffects for manual noise suppression..." + if command -v easyeffects >/dev/null 2>&1; then + easyeffects & + success "EasyEffects launched" + echo "" + echo "In EasyEffects:" + echo "1. Go to 'Input' tab" + echo "2. Add 'RNNoise' effect" + echo "3. Set 'VAD Threshold' to 95% (very conservative)" + echo "4. Set 'Wet' signal to 50-70% (not 100%)" + echo "5. Disable any other aggressive processing" + else + error "EasyEffects not available" + fi + ;; + + E|e) + echo "" + highlight "Resetting to safe audio settings..." + # Reset quantum + pw-metadata -n settings 0 clock.force-quantum 0 + # Reset rate + pw-metadata -n settings 0 clock.force-rate 0 + # Set reasonable volume + wpctl set-volume @DEFAULT_AUDIO_SOURCE@ 70% + # Restart audio services + systemctl --user restart pipewire pipewire-pulse wireplumber + success "Audio settings reset to defaults" + echo "Wait 5 seconds for services to restart, then test your voice" + ;; + + F|f) + echo "" + highlight "Testing different sample rates..." + echo "Current rate: $(pw-metadata -n settings | grep clock.rate | awk '{print $3}' || echo 'default')" + echo "" + echo "Trying 44100 Hz..." + pw-metadata -n settings 0 clock.force-rate 44100 + sleep 2 + echo "Test your voice now. Press Enter to continue..." + read + echo "Trying 48000 Hz..." + pw-metadata -n settings 0 clock.force-rate 48000 + sleep 2 + echo "Test your voice now. Press Enter to continue..." + read + echo "Back to automatic rate..." + pw-metadata -n settings 0 clock.force-rate 0 + success "Rate testing complete" + ;; + + G|g) + echo "" + highlight "Starting real-time audio monitoring..." + echo "Press Ctrl+C to stop monitoring" + echo "" + if command -v pw-top >/dev/null 2>&1; then + pw-top + else + echo "Monitoring with wpctl status (updating every 2 seconds):" + while true; do + clear + echo "=== PipeWire Status ===" + wpctl status + echo "" + echo "=== Microphone Volume ===" + wpctl get-volume @DEFAULT_AUDIO_SOURCE@ + echo "" + echo "Press Ctrl+C to stop" + sleep 2 + done + fi + ;; + + H|h) + echo "" + highlight "Running comprehensive fix..." + + # Step 1: Disable RNNoise filter + echo "1/6: Disabling automatic RNNoise filter..." + pw-dump 2>/dev/null | jq -r '.[] | select(.info.props."node.name" == "rnnoise_source") | .id' | while read id; do + pw-cli destroy "$id" 2>/dev/null || true + done + + # Step 2: Reset audio settings + echo "2/6: Resetting audio settings..." + pw-metadata -n settings 0 clock.force-quantum 0 + pw-metadata -n settings 0 clock.force-rate 0 + + # Step 3: Set conservative volume + echo "3/6: Setting conservative microphone gain..." + wpctl set-volume @DEFAULT_AUDIO_SOURCE@ 60% + + # Step 4: Restart services + echo "4/6: Restarting audio services..." + systemctl --user restart pipewire pipewire-pulse wireplumber + + # Step 5: Wait for restart + echo "5/6: Waiting for services to stabilize..." + sleep 5 + + # Step 6: Launch EasyEffects + echo "6/6: Launching EasyEffects for manual control..." + if command -v easyeffects >/dev/null 2>&1; then + easyeffects & + success "Comprehensive fix applied!" + echo "" + echo "Next steps:" + echo "1. Test your voice without any effects first" + echo "2. In EasyEffects, gradually add noise suppression:" + echo " - Start with RNNoise at 50% wet signal" + echo " - Use VAD threshold of 95% or higher" + echo " - Avoid aggressive compression or EQ" + echo "3. If still distorted, try lowering input gain further" + else + warning "EasyEffects not available for manual control" + fi + ;; + + *) + error "Invalid choice" + ;; +esac + +echo "" +echo "🎯 Additional Tips to Prevent Distortion:" +echo "=========================================" +echo "" +echo "• Keep microphone gain below 80% to avoid clipping" +echo "• Use RNNoise conservatively (50-70% wet signal, not 100%)" +echo "• Check for background applications using audio" +echo "• Ensure your microphone hardware supports 48kHz" +echo "• Consider using a better quality microphone" +echo "• Avoid stacking multiple noise reduction effects" +echo "" + +echo "Run this script again anytime with: troubleshoot-voice-distortion"