How to split an mp3 file by detecting silent parts?

11,488

Solution 1

You can do this manually with ffmpeg, and of course it can all be scripted if you prefer.

Get silent timestamps

Get silence with the silencedetect filter:

ffmpeg -i input.mp3 -af silencedetect -f null -
  • Note the default minimum length for silence is set to 2 seconds, but it can be adjusted. See ffmpeg -h filter=silencedetect.

  • There is also a silenceremove filter.

Example output using awk:

$ ffmpeg -i input.mp3 -af silencedetect=d=0.5 -f null - |& awk '/silencedetect/ {print $4,$5}'
silence_start: 1.20837
silence_end: 1.92546
silence_start: 3.51778
silence_end: 4.0881
silence_start: 6.40315
silence_end: 7.7922

Split

There are a few methods to split.

segment muxer

Example of splitting with the segment muxer:

ffmpeg -i input.mp3 -f segment -segment_times 1.20837,1.92546,3.51778,4.0881,6.40315,7.7922 -reset_timestamps 1 -map 0:a -c:a copy output_%03d.mp3
  • You will need to delete the silent segments. You could perform a Bash loop on the output files, use silencedetect to find these segments, then delete/move them if you want to script that process.

  • Note the use of -c:a copy which enables stream copy mode so your MP3 does not get re-encoded to avoid generation loss.

-ss and -t or -to

Using these options will omit the silent segments but is more work to make the commands:

ffmpeg -i input.mp3 -to 1.20837 -c copy output_01.mp3
ffmpeg -i input.mp3 -ss 1.92546 -to 3.51778 -c copy output_02.mp3

…and so on.

Or do it in one command:

ffmpeg -i input.mp3 -to 1.20837 -c copy output_01.mp3 -ss 1.92546 -to 3.51778 -c copy output_02.mp3

As in the segment muxer command this also uses stream copy.

Solution 2

You will likely not get a ready-to-go solution but will need to create a script yourself. pydub is made for this (it uses ffmpeg or libav internally) and it has a functions called split_on_silence() with some settings like keep_silence=100.

Some references from stackoverflow that have examples: 37725416 and 45526996 And from the creator of pydub.

From the 1st link the interesting part:

# Load your audio.
song = AudioSegment.from_mp3("your_audio.mp3")

chunks = split_on_silence (
   # Use the loaded audio. 
   song, 
   # Specify that a silent chunk must be at least 2 seconds or 2000 ms long.
   min_silence_len = 2000,
   # Consider a chunk silent if it's quieter than -16 dBFS.
   # (You may want to adjust this parameter.)
   silence_thresh = -16
)

Solution 3

mp3splt is a command for splitting mp3s and I believe mp3splt has a silence detector (among other methods of detection)... without re-encoding. To install:

sudo apt install mp3splt

Usage using Silence mode (-s):

mp3splt -s your.mp3

Mp3splt will try to automatically detect splitpoints with silence detection and will split all tracks found with default parameters.

Or

mp3splt -s -p th=-50,nt=10 your.mp3

passing desired parameters, splitting 10 tracks (or less if too much) with the most probable silence points at a threshold of -50 dB.

Solution 4

Get the timings by playing clip that you want to cut, I generally do long video clips that I want to trim or to cut out parts of the clip. It can be trimed by using video editing software, but these will typically also recompress the file on export. This reduces the quality of the video, and it also takes a long time. a solution is to perform zero loss cutting is there in ubuntu, in ubuntu there is a way to do this with FFmpeg :

example :

ffmpeg -i Myclip.mp4 -ss 00:15:10 -to 00:09:10 -c:v copy -c:a copy output.mp4

above will cut clip from about 0h10min10s to 0h09min0s, and this takes few seconds to complete.

Share:
11,488
Drimades Boy
Author by

Drimades Boy

Updated on September 18, 2022

Comments

  • Drimades Boy
    Drimades Boy over 1 year

    I have a big mp3 file including more songs. Is there any way to split the file by detecting silent parts? I would prefer a command line tool (e.g. ffmpeg).

    Tried:

    youtube-dl --ignore-errors --format bestaudio --extract-audio --audio-format mp3 --audio-quality 160K --output "%(title)s.%(ext)s" --yes-playlist

  • muru
    muru almost 4 years
    Please include an example usage of the command showing this silence detection.
  • leftaroundabout
    leftaroundabout almost 4 years
    It's a valid point about avoiding re-encoding, though the problem is actually often exaggerated and zero-conversion cutting has its own problem, namely that you can only split at block boundaries – which may result in the cuts being not quite in silence. Seeing as the input files are in the outdated MP3 format, I'd actually rather exact-cut them in plain PCM (what ffmpeg does by default, baring -c copy) and then re-compress in a more modern&efficient codec such as OPUS, which could give significantly smaller output files without making the quality notably worse than the original MP3 input.
  • Crates
    Crates almost 4 years
    I really like your answer, dude! One question, though: if you're going to use awk to print out the silent segments, why not pipe that right back into sed so you can rewrite this into the command you finish with? Then you would have a one-liner that works for everyone without any manual rework, and can even be saved as a script that does this task for anyone else who comes across this page.
  • llogan
    llogan almost 4 years
    @Crates The awk example was a lazy afterthought. I almost didn't even include it. The main purpose of my answer was only to provide the step-by-step ffmpeg commands. It didn't seem like the question asker was looking for a turnkey script so I didn't spend the extra time making one.
  • Thalis K.
    Thalis K. over 3 years
    Excellent answer. Worked like a charm. Kudos!!
  • Pablo Bianchi
    Pablo Bianchi about 3 years
    To get just hh:mm:ss timestamps of silence_end: ffmpeg -i input.mp3 -af silencedetect=d=0.1 -f null - |& awk '/silence_end/ {print $4,$5}' | awk '{S=$2;printf "%d:%02d:%02d\n",S/(60*60),S%(60*60)/60,S%60}' (this to get the album)