Rather than a single program that does this for you I have a combination that can do it for you. The combination is:
- Python - Programming Language Download and install from https://www.python.org/downloads/ selecting Python 3.6 or later and selecting "Add to Path" during the install.
- Numpy - Numeric Library Once you have installed Python you can install from the command prompt with
pip install numpy
- MoviePy - Video Editing in Python Once you have installed Python you can install from the command prompt with
pip install moviepy
- FFMPEG - Media Processing Tools Automatically downloaded and installed by MoviePy on first use.
Note that this process was inspired by this blog post which automatically clips the highlights of football matches based on the average audio levels.
You can then put together a python script something like the following:
import os # Pythons default library for OS operations
import glob # Pythons default library for file pattern matching
import numpy as np # for numerical operations
from moviepy.editor import AudioFileClip
def find_silences(audio):
""" Find the silences in an audio clip """
cut = lambda i: audio.subclip(i,i+1).to_soundarray(fps=22000) # get one sec of audio as an array
volume = lambda array: np.sqrt(((1.0*array)**2).mean()) # RMS of Array
# Use the above to get a list of the volumes per second
volumes = [volume(cut(i)) for i in range(0,int(sound.duration-1))]
# Get the times when the volume is zero
zero_secs = [i for i, v in enumerate(volumes) if v == 0.0]
def process_file(fname):
""" Process a file """
audio = AudioFileClip(filename=files[0])
silences = find_silences(audio)
two_secs = [s for s, i in silences[:-1] if s+1 == silences[i+1]]
if len(two_secs) == 0:
print(fname, "no two second silence found!")
else: # We have at least one 2 sec silence
clipped = audio.subclip(0, two_secs[0]) # Clip to that length
clipped.to_audiofile('temp.mp3') # Save to a temp name
os.rename(fname, fname+".orig") # keep the old just in case
os.rename('temp.mp3', fname) # rename temp to original name
if __name__ == "__main__":
for FNAME in glob.glob("*.mp3"): # All the MP3 files in the current directory
process_file(FNAME)
Note that the above code is very rough & ready but should get you started.