Trim multiple mp3 files at once
So, I have hundreds of .mp3 files in a folder. Almost each of them has a period of silence before you can hear a sound. And the periods are of the different size.
The same is with the end of the files.
Is there any application (free, if possible) by which I could trim all the files at once, so that each of them has equal time of silence ( for example five seconds) before and at the end of song.
Or, maybe a mp3 player which can adjust the silence of each song at the described way.
Also, If I must cut all the files one by one, which application is mostu sutable (i.e. speed enough) for this task)?
I know four methods: mp3DirectCut, Mp3splt-GTK, Mp3splt or ffmpeg
mp3DirectCut (GUI version, best choice for quick results)
- After starting, go to File » Batch processing
-
Add your mp3 folder, select Auto crop and press Start
Hints
- Choose a different folder as output to test some result files. After verifying, rerun it and choose Overwrite originals. You should be done in a couple of seconds since the program doesn't re-encode your mp3 files
- You probably want to enable Settings » Keep date on overwriting source files
Mp3splt-gtk (GUI version, available for all major OS platforms)
- Download $ start the program, click on Batch & automatic split
-
Select Trim using silence detection and press Batch split
mp3splt (Command Line version, available for all major OS platforms)
Download mp3splt, open your PowerShell ISE, change both paths and run the following code:
$files = Get-ChildItem "C:\my\musicfolder" -Recurse -Include *.mp3,*.ogg,*.flac
$exe = "C:\path\to\mp3splt.exe"
ForEach ($file in $files) {
If ($file.BaseName -notmatch "_trimmed$" ) {
$newFile = $file.DirectoryName + "\" + $file.BaseName + "_trimmed" + $file.Extension
If (Test-Path $newFile) {Remove-Item $newFile }
& $exe -r -p "th=-48,min=2" `"$file`" | Out-Null
Remove $file.Fullname
Rename $($file.DirectoryName + "\" + $file.BaseName + "_trimmed" + $file.Extension) $file.Fullname
}
}
Hints
-
-r -p th=-48, min=2
is the option to remove silence at the start/end of your file.th
defines the threshold level in dB. Everything below is considered as silence.min=2
sets the minimum silence in seconds. Only silence longer then 2 seconds will be truncated - You could pretend a test run by adding an uppercase
-P
at the end of mp3splt command. It outputs errors or says everything went well. If used, comment outRemove
andRename
since no new files are created to process them -
For testing, you could also use
-d FOLDERPATH
to choose a single output folder and-o@f
to use the original filename as output (otherwise_trimmed
will be appended)Documentation explaining all available options
FFmpeg (Command Line version, available for all major OS platforms)
FFmpeg's audio filter -af silenceremove
should not be used since it always re-encodes your files and you cannot for gods sake keep the same audio quality as your input file. -acodec copy
can not be used here. You can only choose one fixed bit rate even if you process multiple files with different qualities.
However, there is another ffmpeg option: -af silencedetect
. The theory is already explained at StackOverflow. I adopted it to Windows and PowerShell.
Download ffmpeg, open your PowerShell ISE, change both paths and run the following code:
$files = Get-ChildItem "C:\path\to\musicfolder" -Recurse -Include *.mp3,*.ogg,*.flac
$ffmpeg = "C:\path\to\ffmpeg.exe"
ForEach ($file in $files) {
If ($file.BaseName -notmatch "_trimmed$" ) {
# Detect silence with ffmpeg and "silencedetect". Save the complete output to variable $log
$log = & $ffmpeg -hide_banner -i `"$file`" -af "silencedetect=duration=1:noise=-50dB" -f null - 2>&1
$totalLength = [string]$log | where {$_ -match '(?<= Duration:.*)[\d:\.]+' } | % {$matches[0]}
$totalLength = ([TimeSpan]::Parse($totalLength)).TotalSeconds
# Use regex to search all numbers after string "silence_end". Save them as string array in the format XXX.XXX
# Check if any 'silence_end' was found. If yes, save the first silence ending time as mp3 start time
[string[]]$silenceEnd = $log | where {$_ -match '(?<=silence_end: )[-\d\.]+' } | % {$matches[0]}
If ($silenceEnd.count -gt 0 -And [double]$silenceEnd[0] -lt $totalLength/2) {
[double]$trackStart = $silenceEnd[0]
} else {
[double]$trackStart = 0
}
# Do the same again but for silence starting times. Save the last one as mp3 end time
[string[]]$silenceStart = $log | where {$_ -match '(?<=silence_start: )[-\d\.]+' } | % {$matches[0]}
If ($silenceStart.count -gt 0 -And $silenceStart[$silenceStart.count-1] -gt $totalLength/2) {
[double]$trackEnd = $silenceStart[$silenceStart.count-1]
} else {
[double]$trackEnd = $totalLength
}
# calculate duration since ffmpeg's -t option wants a duration and not a timestamp
$duration = $trackEnd - $trackStart
# Put together the new file name. If file already exists from previous run, delete it
$newFile = $file.DirectoryName + "\" + $file.BaseName + "_trimmed" + $file.Extension
If (Test-Path $newFile) {Remove-Item $newFile }
# Run ffmpeg with our calculated start and duration times to remove silence at start and end
write-host "$ffmpeg -i `"$file`" -ss $trackStart -t $duration -acodec copy `"$newFile`" 2>&1"
& $ffmpeg -i `"$file`" -ss $trackStart -t $duration -acodec copy `"$newFile`" 2>&1
# Delete the original mp3 file and rename the new mp3 file to the original name
Remove-Item $file.Fullname
Rename-Item $newFile $file.Fullname
}
}