Noise Reduction with SoX

SoX

SoX is a tool for editing audio files, available on GNU/Linux, macOS, and Windows. You can also use it on Android inside the termux environment.

In this post, we will first use SoX to reduce noise in an audio file, and then examine a script for noise reduction in audio and video files using SoX and FFmpeg.

Noise Reduction with SoX

If we have an audio file called audio.wav that has a small section of silence — or more accurately, ambient noise — recorded at the beginning, we can extract that section using SoX:

# sox in.ext out.ext trim {start: s.ms} {duration: s.ms}
sox audio.wav noise.wav trim 0 0.900

Here, SoX takes audio.wav as input, extracts the first 0.9 seconds of it, and saves it as noise.wav.

Now we use this section to create a noise profile file called noise.prof:

sox noise.wav -n noiseprof noise.prof

Finally, we perform noise reduction based on the generated profile. A sensitivity factor is used to control the amount of noise reduction; according to this source, a value between 0.2 and 0.3 produces the best results:

sox audio.wav audio-clean.wav noisered noise.prof 0.21

A Script for Noise Reduction in Audio and Video Files with FFmpeg and SoX

This script takes two paths — first the input file, then the output file ($1 and $2). If the input file is a video, it uses FFmpeg to extract the audio. It then reduces noise in the audio file as described above, and finally, if the input was a video, uses FFmpeg again to merge the audio and video back together.

#!/usr/bin/sh

usage ()
{
    printf "Usage : noisereduce <input video file> <output video file>\n"
    exit
}

# Tests for requirements
ffmpeg -version >/dev/null || { echo >&2 "We require 'ffmpeg' but it's not installed. Install it by 'sudo apt-get install ffmpeg' Aborting."; exit 1; }
sox --version >/dev/null || { echo >&2 "We require 'sox' but it's not installed. Install it by 'sudo apt-get install sox' Aborting."; exit 1; }

if [ "$#" -ne 2 ]
then
  usage
fi

if [ ! -e "$1" ]
then
    printf "File not found: %s\n" "$1"
    exit
fi

if [ -e "$2" ]
then
    printf "File %s already exists, overwrite? [y/N]\n: " "$2"
    read -r yn
    case $yn in
        [Yy]* ) ;;
        * ) exit;;
    esac
fi

inBasename=$(basename "$1")
inExt="${inBasename##*.}"

isVideoStr=$(ffprobe -v warning -show_streams "$1" | grep codec_type=video)
if [ -n "$isVideoStr" ]
then
    isVideo=1
    printf "Detected %s as a video file\n" "$inBasename"
else
    isVideo=0
    printf "Detected %s as an audio file\n" "$inBasename"
fi

printf "Sample noise start time [00:00:00]: "
read -r sampleStart
if [ -z "$sampleStart" ] ; then sampleStart="00:00:00"; fi
printf "Sample noise end time [00:00:00.900]: "
read -r sampleEnd
if [ -z "$sampleEnd" ] ; then sampleEnd="00:00:00.900"; fi
printf "Noise reduction amount [0.21]: "
read -r sensitivity
if [ -z "$sensitivity" ] ; then sensitivity="0.21"; fi


tmpVidFile="/tmp/noiseclean_tmpvid.$inExt"
tmpAudFile="/tmp/noiseclean_tmpaud.wav"
noiseAudFile="/tmp/noiseclean_noiseaud.wav"
noiseProfFile="/tmp/noiseclean_noise.prof"
tmpAudCleanFile="/tmp/noiseclean_tmpaud-clean.wav"

printf "Cleaning noise on %s...\n" "$1"

if [ $isVideo -eq "1" ]; then
    ffmpeg -v warning -y -i "$1" -qscale:v 0 -vcodec copy -an "$tmpVidFile"
    ffmpeg -v warning -y -i "$1" -qscale:a 0 "$tmpAudFile"
else
    cp "$1" "$tmpAudFile"
fi
ffmpeg -v warning -y -i "$1" -vn -ss "$sampleStart" -t "$sampleEnd" "$noiseAudFile"
sox "$noiseAudFile" -n noiseprof "$noiseProfFile"
sox "$tmpAudFile" "$tmpAudCleanFile" noisered "$noiseProfFile" "$sensitivity"
if [ $isVideo -eq "1" ]; then
    ffmpeg -v warning -y -i "$tmpAudCleanFile" -i "$tmpVidFile" -vcodec copy -qscale:v 0 -qscale:a 0 "$2"
else
    cp "$tmpAudCleanFile" "$2"
fi

printf "Done"

More Links

If you prefer watching a tutorial video or want to hear the difference between the input and output:

Comments

You can view the comments for this post on Mastodon here . Click the link below to write a comment.

Write a comment

View comments