Ali Akber
Ali Akber

Reputation: 3800

How to detect the silence at the end of an audio file?

I am trying to detect silence at the end of an audio file.
I have made some progress with ffmpeg library. Here I used silencedetect to list all the silences in an audio file.

ffmpeg -i audio.wav -af silencedetect=n=-50dB:d=0.5 -f null - 2> /home/aliakber/log.txt

Here is the output of the command:

--With silence at the front and end of the audio file--

[silencedetect @ 0x1043060] silence_start: 0.484979
[silencedetect @ 0x1043060] silence_end: 1.36898 | silence_duration: 0.884
[silencedetect @ 0x1043060] silence_start: 2.57298
[silencedetect @ 0x1043060] silence_end: 3.48098 | silence_duration: 0.908
[silencedetect @ 0x1043060] silence_start: 4.75698
size=N/A time=00:00:05.56 bitrate=N/A

--Without silence at the front and end of the audio file--

[silencedetect @ 0x106fd60] silence_start: 0.353333
[silencedetect @ 0x106fd60] silence_end: 1.25867 | silence_duration: 0.905333
[silencedetect @ 0x106fd60] silence_start: 2.46533
[silencedetect @ 0x106fd60] silence_end: 3.37067 | silence_duration: 0.905333
size=N/A time=00:00:04.61 bitrate=N/A

But I want something more flexible so that I can manipulate the output and do further task depending on the result.
I want to get the output something like true or false. If there is a certain period of silence exists at the end of the audio file it will return true and false otherwise.

Can someone suggest me an easy way to achieve this?

Upvotes: 10

Views: 17059

Answers (3)

danilo
danilo

Reputation: 9325

Improving Tarwirdur Turon's answer, now in 2024 it doesn't work for me, apparently the syntax changed a little bit

ffmpeg -i audio.mp3 -af silencedetect=noise=-50dB:d=0.5 -f null - 2>&1 | grep "silence_end" | tail -n 1 | wc -l

This command detect silence at the beginning or at the end, or in both.

Output:

1 - there is silence
0 - there is no silence

Upvotes: 1

lumpidu
lumpidu

Reputation: 759

The answer from @tarwirdur-turon doesn't work for me (in 2023 and ffmpeg version 5.1.2).

I came up with a somewhat convoluted script to do it. Convoluted, because it does error checking.

It uses 2 calls: ffprobe + ffmpeg to find reliably the duration of the audio file and tests it against the last silence_end by divison of the found values, which should be very close to 1.00. You can change the scale for calculating the division and various other values at the beginning of the script.

#! /bin/bash
set -e

INPUT="$1"
NOISE_FLOOR="-60db"
MIN_DUR=0.1
SCALE=2

[ -z "$INPUT" ] && echo "Needs audio file !" && exit 1

echo -n "$INPUT ends with silence: "

dur=$(ffprobe -i $INPUT -show_entries format=duration -v quiet -of csv="p=0" 2>&1)
if [ -z "$dur" ]; then
    echo "FALSE" && exit 1
fi

# xargs alone trims spaces
last_silence_end=$(ffmpeg -i $INPUT -af silencedetect=noise=$NOISE_FLOOR:d=$MIN_DUR -f null - 2>&1 | grep silence_end | tail -n 1 | cut -d ' ' -f 5)
if [ -z "$last_silence_end" ]; then
    echo "FALSE" && exit 0
fi

factor=$(bc <<<"scale=$SCALE; $dur / $last_silence_end")
if [ "$factor" == "1.00" ]; then
    echo "TRUE"
else
    echo "FALSE"
fi
exit 0

Upvotes: 0

Tarwirdur Turon
Tarwirdur Turon

Reputation: 781

Try this:

ffmpeg -i audio.wav -af silencedetect=n=-50dB:d=0.5 -f null - 2>&1 | grep -Eo "silence_(start|end)" | tail -n 1 | grep "start" | wc -l

Output:

  • 1 - there is silence at the end
  • 0 - there is no silence at the end

Explanation: As I see in the silence case there is no silence_end at the end of log.

  1. 2>&1 - redirect stderr to stdin
  2. grep -Eo "silence_(start|end)" - filter log and keep only silence_start and silence_end from log. Each by new line.
  3. tail -n 1 - get last line. (if it is. So now we there are 3 cases of state: 'silence_start', 'silence_end', <empty>)
  4. grep "start" - keep line only if it contains start (2 cases: 'silence_start', <empty>)
  5. wc -l - get number of lines. (1 in 'silence_start' and 0 in <empty> case)

Upvotes: 12

Related Questions