The pydub library provides an intuitive interface for audio manipulation, treating audio files like Python sequences. It wraps FFmpeg to handle various audio formats including MP3, WAV, and FLAC.
Installation and Setup
Install pydub from PyPI:
pip install pydubYou must also have FFmpeg installed on your system:
sudo apt install ffmpeg
brew install ffmpegBasic Trimming Operations
Pydub uses milliseconds for all time values. Audio segments support Python slice notation:
from pydub import AudioSegment
song = AudioSegment.from_mp3("input.mp3")
duration_ms = len(song)
print(f"Duration: {duration_ms / 1000:.2f} seconds")
first_10_sec = song[:10000]
last_5_sec = song[-5000:]
without_intro = song[3000:]
first_10_sec.export("trimmed.mp3", format="mp3")Extracting a Middle Section
Use slice notation with start and end positions:
from pydub import AudioSegment
song = AudioSegment.from_mp3("podcast.mp3")
start_ms = 30 * 1000
end_ms = 60 * 1000
clip = song[start_ms:end_ms]
clip.export("clip.mp3", format="mp3")Helper Function for Time Conversion
Working with minutes and seconds is more intuitive than raw milliseconds:
from pydub import AudioSegment
def time_to_ms(minutes=0, seconds=0, milliseconds=0):
"""Convert time to milliseconds."""
return (minutes * 60 * 1000) + (seconds * 1000) + milliseconds
def ms_to_time(ms):
"""Convert milliseconds to (minutes, seconds, milliseconds)."""
minutes = ms // 60000
seconds = (ms % 60000) // 1000
remaining_ms = ms % 1000
return minutes, seconds, remaining_ms
def extract_segment(audio_path, start_time, end_time, output_path):
"""
Extract a segment from an audio file.
Times can be tuples of (minutes, seconds) or milliseconds.
"""
song = AudioSegment.from_file(audio_path)
if isinstance(start_time, tuple):
start_ms = time_to_ms(minutes=start_time[0], seconds=start_time[1])
else:
start_ms = start_time
if isinstance(end_time, tuple):
end_ms = time_to_ms(minutes=end_time[0], seconds=end_time[1])
else:
end_ms = end_time
clip = song[start_ms:end_ms]
clip.export(output_path, format="mp3")
return len(clip)
duration = extract_segment(
"song.mp3",
start_time=(1, 30),
end_time=(2, 45),
output_path="excerpt.mp3"
)
print(f"Extracted {duration / 1000:.2f} seconds")Adding Fade Effects
Smooth transitions with fade in and fade out:
from pydub import AudioSegment
song = AudioSegment.from_mp3("track.mp3")
clip = song[30000:60000]
clip_with_fades = clip.fade_in(2000).fade_out(3000)
clip_with_fades.export("clip_faded.mp3", format="mp3")Concatenating Audio Segments
Combine multiple clips into a single file:
from pydub import AudioSegment
song = AudioSegment.from_mp3("full_song.mp3")
intro = song[:15000]
chorus = song[60000:90000]
outro = song[-20000:]
compilation = intro + chorus + outro
from functools import reduce
segments = [intro, chorus, outro]
compilation = reduce(lambda a, b: a + b, segments)
compilation.export("highlights.mp3", format="mp3")Removing a Section from Audio
Remove unwanted portions like advertisements:
from pydub import AudioSegment
podcast = AudioSegment.from_mp3("podcast.mp3")
ad_start = 5 * 60 * 1000 # 5 minutes
ad_end = 6 * 60 * 1000 # 6 minutes
before_ad = podcast[:ad_start]
after_ad = podcast[ad_end:]
clean_podcast = before_ad + after_ad
clean_podcast.export("podcast_clean.mp3", format="mp3")Splitting Audio into Equal Parts
Divide a file into multiple segments:
from pydub import AudioSegment
import math
def split_audio(audio_path, segment_length_sec, output_prefix):
"""Split audio into segments of specified length."""
audio = AudioSegment.from_file(audio_path)
segment_length_ms = segment_length_sec * 1000
total_segments = math.ceil(len(audio) / segment_length_ms)
segments = []
for i in range(total_segments):
start = i * segment_length_ms
end = min((i + 1) * segment_length_ms, len(audio))
segment = audio[start:end]
output_path = f"{output_prefix}_part{i + 1:03d}.mp3"
segment.export(output_path, format="mp3")
segments.append(output_path)
print(f"Created: {output_path} ({len(segment) / 1000:.2f}s)")
return segments
parts = split_audio("long_recording.mp3", 300, "recording")Adjusting Export Quality
Control bitrate and other export parameters:
from pydub import AudioSegment
song = AudioSegment.from_mp3("input.mp3")
clip = song[:30000]
clip.export(
"high_quality.mp3",
format="mp3",
bitrate="320k"
)
clip.export(
"compressed.mp3",
format="mp3",
bitrate="128k"
)
clip.export("lossless.wav", format="wav")
clip.export(
"with_tags.mp3",
format="mp3",
bitrate="256k",
tags={
"artist": "Artist Name",
"title": "Track Title",
"album": "Album Name"
}
)Error Handling
Robust implementation with proper error handling:
from pydub import AudioSegment
from pydub.exceptions import CouldntDecodeError
from pathlib import Path
def safe_trim_audio(input_path, start_ms, end_ms, output_path):
"""Safely trim audio with error handling."""
input_file = Path(input_path)
if not input_file.exists():
raise FileNotFoundError(f"Input file not found: {input_path}")
try:
audio = AudioSegment.from_file(input_path)
except CouldntDecodeError as e:
raise ValueError(f"Could not decode audio file: {e}")
duration = len(audio)
if start_ms < 0:
start_ms = 0
if end_ms > duration:
end_ms = duration
if start_ms >= end_ms:
raise ValueError(f"Invalid time range: {start_ms}ms to {end_ms}ms")
clip = audio[start_ms:end_ms]
output_format = Path(output_path).suffix.lstrip('.') or 'mp3'
clip.export(output_path, format=output_format)
return {
"duration_ms": len(clip),
"output_path": output_path,
"format": output_format
}
try:
result = safe_trim_audio("song.mp3", 10000, 40000, "clip.mp3")
print(f"Created {result['duration_ms'] / 1000:.2f}s clip")
except (FileNotFoundError, ValueError) as e:
print(f"Error: {e}")Batch Processing Multiple Files
Process multiple audio files with the same trimming:
from pydub import AudioSegment
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
def trim_file(input_path, output_dir, start_ms, end_ms):
"""Trim a single file and save to output directory."""
try:
audio = AudioSegment.from_file(input_path)
clip = audio[start_ms:end_ms]
output_path = Path(output_dir) / f"trimmed_{Path(input_path).name}"
clip.export(str(output_path), format="mp3")
return str(output_path), None
except Exception as e:
return None, str(e)
def batch_trim(input_files, output_dir, start_ms, end_ms):
"""Trim multiple files in parallel."""
Path(output_dir).mkdir(exist_ok=True)
with ThreadPoolExecutor(max_workers=4) as executor:
futures = [
executor.submit(trim_file, f, output_dir, start_ms, end_ms)
for f in input_files
]
results = []
for future, input_file in zip(futures, input_files):
output, error = future.result()
results.append({
"input": input_file,
"output": output,
"error": error
})
return results
input_files = list(Path("music").glob("*.mp3"))
results = batch_trim(input_files, "trimmed", 0, 30000)
for r in results:
if r["error"]:
print(f"Failed: {r['input']} - {r['error']}")
else:
print(f"Success: {r['output']}")Slice Syntax Reference
| Goal | Syntax | Example |
|---|---|---|
| First N seconds | audio[:N*1000] |
song[:10000] |
| Last N seconds | audio[-N*1000:] |
song[-5000:] |
| Skip first N seconds | audio[N*1000:] |
song[3000:] |
| Middle section | audio[start:end] |
song[30000:60000] |
| Every other second | audio[::2000] |
Creates choppy effect |
Pydub's slice-based approach makes audio editing intuitive for Python developers. Combined with FFmpeg's format support, it handles most common audio manipulation tasks efficiently.