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.900Here, 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.profFinally, 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
- A few examples in the main repository
- SoX tricks
- A fork on GitHub
- Supported features and formats
- A C# example
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.