Claude
Skills
Sign in
Back

pydub-automation

Included with Lifetime
$97 forever

Automate repetitive audio tasks with Python using PyDub for batch processing, format conversion, normalization, and content assembly. Use when: Processing large numbers of audio files consistently; Converting between audio formats at scale; Normalizing loudness across a batch of files; Assembling intros/outros automatically to episodes; Trimming silence or extracting segments programmatically

Ads & Marketing

What this skill does


# PyDub Audio Automation

> Automate repetitive audio tasks with Python using PyDub for batch processing, format conversion, normalization, and content assembly.

## When to Use This Skill

- Processing large numbers of audio files consistently
- Converting between audio formats at scale
- Normalizing loudness across a batch of files
- Assembling intros/outros automatically to episodes
- Trimming silence or extracting segments programmatically
- Building audio pipelines for content production

## Methodology Foundation

**Source**: PyDub Library (James Robert) + Python Audio Processing

**Core Principle**: "Audio operations that take hours manually can run in minutes with code." PyDub provides a high-level interface that abstracts FFmpeg's complexity, making common operations accessible to non-audio engineers.

**Why This Matters**: Content teams producing regular podcasts, courses, or video content spend significant time on repetitive audio tasks. Automation enables consistent quality at scale while freeing humans for creative work.


## What Claude Does vs What You Decide

| Claude Does | You Decide |
|-------------|------------|
| Structures production workflow | Final creative direction |
| Suggests technical approaches | Equipment and tool choices |
| Creates templates and checklists | Quality standards |
| Identifies best practices | Brand/voice decisions |
| Generates script outlines | Final script approval |

## What This Skill Does

1. **Batch processes audio files** - Apply same operations to hundreds of files
2. **Converts formats** - MP3, WAV, FLAC, OGG, and more
3. **Normalizes loudness** - Consistent levels across episodes
4. **Assembles content** - Concatenate intros, content, outros
5. **Extracts segments** - Trim, split, and slice audio programmatically

## How to Use

### Generate Processing Script
```
Help me write a PyDub script to [describe task].
Input files: [format, location]
Output requirements: [format, specs]
```

### Create Batch Workflow
```
Create a Python script that processes all audio files in a folder:
- Input: [source folder, file type]
- Operations: [what to do]
- Output: [destination, naming convention]
```

### Debug Audio Script
```
This PyDub script isn't working as expected:
[paste code]
Expected: [what you want]
Actual: [what's happening]
```

## Instructions

When automating audio with PyDub, follow this methodology:

### Step 1: Setup and Prerequisites

```python
## Installation

# Install PyDub
pip install pydub

# FFmpeg is required (PyDub uses it under the hood)
# macOS:
brew install ffmpeg

# Ubuntu/Debian:
sudo apt-get install ffmpeg

# Windows:
# Download from ffmpeg.org, add to PATH
```

```python
## Basic Imports

from pydub import AudioSegment
from pydub.effects import normalize, compress_dynamic_range
from pydub.silence import detect_silence, split_on_silence
import os
from pathlib import Path
```

---

### Step 2: Core Operations

```python
## Loading and Saving Audio

# Load audio file (format auto-detected from extension)
audio = AudioSegment.from_file("input.mp3")
audio = AudioSegment.from_file("input.wav", format="wav")

# Save audio file
audio.export("output.mp3", format="mp3", bitrate="192k")
audio.export("output.wav", format="wav")

# Export with metadata
audio.export(
    "output.mp3",
    format="mp3",
    bitrate="192k",
    tags={"artist": "Brand Name", "album": "Podcast"}
)
```

```python
## Basic Properties

print(f"Duration: {len(audio)} ms")
print(f"Channels: {audio.channels}")
print(f"Frame rate: {audio.frame_rate} Hz")
print(f"Sample width: {audio.sample_width} bytes")
print(f"dBFS: {audio.dBFS}")  # Volume level
```

---

### Step 3: Volume and Normalization

```python
## Volume Adjustments

# Increase volume by 6 dB
louder = audio + 6

# Decrease volume by 3 dB
quieter = audio - 3

# Normalize to target level (0 dB = maximum)
normalized = normalize(audio)

# Normalize to specific headroom
def normalize_to_target(audio, target_dBFS=-16):
    """Normalize audio to target loudness."""
    change_in_dBFS = target_dBFS - audio.dBFS
    return audio.apply_gain(change_in_dBFS)

normalized = normalize_to_target(audio, target_dBFS=-16)
```

```python
## Batch Normalization

def normalize_folder(input_dir, output_dir, target_dBFS=-16):
    """Normalize all audio files in a folder."""
    input_path = Path(input_dir)
    output_path = Path(output_dir)
    output_path.mkdir(exist_ok=True)

    for file in input_path.glob("*.mp3"):
        audio = AudioSegment.from_file(file)
        normalized = normalize_to_target(audio, target_dBFS)

        output_file = output_path / file.name
        normalized.export(output_file, format="mp3", bitrate="192k")
        print(f"Processed: {file.name}")

# Usage
normalize_folder("raw_episodes/", "processed_episodes/", target_dBFS=-16)
```

---

### Step 4: Concatenation and Assembly

```python
## Basic Concatenation

intro = AudioSegment.from_file("intro.mp3")
content = AudioSegment.from_file("episode.mp3")
outro = AudioSegment.from_file("outro.mp3")

# Concatenate (+ operator)
full_episode = intro + content + outro

# Add silence between segments
silence = AudioSegment.silent(duration=2000)  # 2 seconds
full_episode = intro + silence + content + silence + outro

full_episode.export("final_episode.mp3", format="mp3")
```

```python
## Podcast Assembly Script

def assemble_episode(
    content_file,
    intro_file="assets/intro.mp3",
    outro_file="assets/outro.mp3",
    output_file=None,
    intro_fade_ms=500,
    outro_fade_ms=500
):
    """
    Assemble podcast episode with intro and outro.
    Includes crossfade for professional sound.
    """
    intro = AudioSegment.from_file(intro_file)
    content = AudioSegment.from_file(content_file)
    outro = AudioSegment.from_file(outro_file)

    # Apply fade out to intro, fade in to content
    intro = intro.fade_out(intro_fade_ms)
    content = content.fade_in(intro_fade_ms).fade_out(outro_fade_ms)
    outro = outro.fade_in(outro_fade_ms)

    # Crossfade join
    episode = intro.append(content, crossfade=intro_fade_ms)
    episode = episode.append(outro, crossfade=outro_fade_ms)

    # Generate output filename if not provided
    if output_file is None:
        output_file = content_file.replace(".mp3", "_final.mp3")

    episode.export(output_file, format="mp3", bitrate="192k")
    print(f"Assembled: {output_file} ({len(episode)/1000:.1f}s)")
    return output_file

# Usage
assemble_episode("episode_042_raw.mp3")
```

---

### Step 5: Trimming and Splitting

```python
## Time-Based Trimming

# Extract segment (milliseconds)
# audio[start:end]
first_30_seconds = audio[:30000]
last_minute = audio[-60000:]
middle_section = audio[60000:120000]

# Remove first 5 seconds (skip intro)
without_intro = audio[5000:]
```

```python
## Silence-Based Operations

from pydub.silence import detect_silence, split_on_silence

# Detect silence regions
# Returns list of [start, end] in milliseconds
silence_ranges = detect_silence(
    audio,
    min_silence_len=1000,  # Minimum 1 second silence
    silence_thresh=-40     # dB threshold for "silence"
)

# Split on silence (useful for chapter markers)
chunks = split_on_silence(
    audio,
    min_silence_len=500,
    silence_thresh=-40,
    keep_silence=250  # Keep 250ms of silence on each side
)

# Export chunks
for i, chunk in enumerate(chunks):
    chunk.export(f"segment_{i:03d}.mp3", format="mp3")
```

```python
## Trim Silence from Start/End

def trim_silence(audio, silence_thresh=-50, chunk_size=10):
    """Remove silence from beginning and end of audio."""

    # Find first non-silent moment
    start_trim = 0
    for i in range(0, len(audio), chunk_size):
        if audio[i:i+chunk_size].dBFS > silence_thresh:
            start_trim = max(0, i - 100)  # Keep 100ms before
            break

    # Find last non-silent moment
    end_trim = len(audio)
    for i in range(len(audio), 0, -chunk_size):
        if audio[i-chunk_size:i].dBFS > silence_thresh:
            

Related in Ads & Marketing