Skip to content

How to Cut and Trim MP3 Files in Python

Learn how to trim, extract, and manipulate MP3 files in Python using pydub with precise time-based slicing, fade effects, and batch processing.

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 pydub

You must also have FFmpeg installed on your system:

sudo apt install ffmpeg

brew install ffmpeg

Basic 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.

Navigation