Skip to content

recipe: trim audio silence, lossless  #419

Open
@atomGit

Description

@atomGit

i think quite a few people, myself included, are looking for a clean and lossless method to trim excess silence from only the beginning and end of an audio file, particularly music files, leaving a set amount of silence

while this is possible with ffmpeg and ffprobe, the process involves decoding the audio, reversing it, and decoding again so it's all quite slow

i found this on stack and modified it a bit to make a (sorta) working example, but i see this solution as a very dirty way to accomplish the task, however it is the only thing i was able to hack together after a LOT of searching and reading over the course of several days

#!/bin/bash

#rm -r OUTPUT 2>/dev/null
#rm -r LOSSLESS 2>/dev/null
#rm -r TEMP 2>/dev/null

mkdir TEMP
mkdir OUTPUT
mkdir LOSSLESS

ffmpeg -hide_banner -nostdin -loglevel warning -y -i test.mp3 -vn -af silenceremove=1:0:-70dB TEMP/begincut.mp3
ffmpeg -hide_banner -nostdin -loglevel warning -y -i TEMP/begincut.mp3 -vn -af areverse TEMP/reversed.mp3
ffmpeg -hide_banner -nostdin -loglevel warning -y -i TEMP/reversed.mp3 -vn -af silenceremove=1:0:-70dB TEMP/revcut.mp3
ffmpeg -hide_banner -nostdin -loglevel warning -y -i TEMP/revcut.mp3   -vn -af areverse TEMP/finished.mp3

cp "TEMP/finished.mp3" "OUTPUT/test.mp3"

ORGLENG=$( ffprobe -v warning -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 test.mp3 )
BEGINCT=$( ffprobe -v warning -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 TEMP/begincut.mp3 )
FINLENG=$( ffprobe -v warning -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 TEMP/finished.mp3 )
STARTSILENCE=$( echo "${ORGLENG} ${BEGINCT}" | awk '{printf $1 - $2}' )
ENDSILENCE=$( echo "${BEGINCT} ${FINLENG}" | awk '{printf $1 - $2}' )

echo "ORGLENG=${ORGLENG}"
echo "BEGINCT=${BEGINCT}"
echo "FINLENG=${FINLENG}"
echo "STARTSILENCE=${STARTSILENCE}"
echo "ENDSILENCE=${ENDSILENCE}"

echo "${STARTSILENCE}" | grep -q 'e' && STARTSILENCE="0.0"

# extract framelength in seconds
OFFSET=$( ffprobe test.mp3 -show_frames 2>/dev/null | grep pkt_duration_time | head -n1 | awk -F= '{print $2}' )
# distract frame rate to make sure it is cut in the silence
STARTSILENCE=$( echo "${STARTSILENCE} ${OFFSET}" | awk '{printf $1 - $2}' )
# if it is negative, make it 0
echo "${STARTSILENCE}" | grep -q '-' && STARTSILENCE="0.0"
# add the distracted size to the length
FINLENG=$( echo "${FINLENG} ${OFFSET}" | awk '{printf $1 + $2}' )

echo "test.mp3 = ${ORGLENG} seconds with ${STARTSILENCE}s silence at start and ${ENDSILENCE}s at end. Result is ${FINLENG}s"
echo "Offset = ${OFFSET}"

ffmpeg -hide_banner -nostdin -loglevel warning -y -i test.mp3 -ss ${STARTSILENCE} -t ${FINLENG} -vn -c:a copy LOSSLESS/test.mp3

note that -nostdin seems to be required else funny things seem to happen happen, like chopping off a portion of the audio that contains detectable audio

trivial considering this request, but the script also causes an error when i open the file in Kwave (similar to Audacity):

An error occurred while decoding the file:
'File contains invalid data',
at position 1,044.

related: #367

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions