Claude
Skills
Sign in
Back

podcast-production

Included with Lifetime
$97 forever

Podcast production patterns and workflows. Use when recording podcasts, editing audio, transcribing episodes, generating show notes, RSS feed management, or podcast distribution.

Image & Video

What this skill does


# Podcast Production Patterns

Best practices for podcast production, editing, and distribution.

## Recording Setup

### Audio Configuration

```python
from dataclasses import dataclass
from typing import Optional, List

@dataclass
class AudioSettings:
    sample_rate: int = 48000  # Hz
    bit_depth: int = 24
    channels: int = 1  # Mono per track
    format: str = "wav"  # Lossless for recording

@dataclass
class RecordingTrack:
    name: str
    input_device: str
    settings: AudioSettings
    file_path: str


class RecordingSession:
    def __init__(self, project_name: str, output_dir: str):
        self.project_name = project_name
        self.output_dir = output_dir
        self.tracks: List[RecordingTrack] = []

    def add_track(self, name: str, input_device: str) -> RecordingTrack:
        """Add recording track for participant."""
        settings = AudioSettings()
        file_path = f"{self.output_dir}/{self.project_name}_{name}.wav"

        track = RecordingTrack(
            name=name,
            input_device=input_device,
            settings=settings,
            file_path=file_path
        )
        self.tracks.append(track)
        return track
```

### Remote Recording

```python
import asyncio
import websockets
from dataclasses import dataclass

@dataclass
class RemoteParticipant:
    name: str
    connection_url: str
    local_recording: bool = True  # Record locally for best quality


class RemoteRecordingSession:
    """Coordinate remote podcast recording."""

    def __init__(self):
        self.participants: List[RemoteParticipant] = []
        self.sync_server = None

    async def start_sync_server(self, port: int = 8765):
        """Start sync server for coordinating recording."""
        async def handler(websocket, path):
            async for message in websocket:
                if message == "SYNC":
                    # Broadcast sync signal to all participants
                    await asyncio.gather(*[
                        ws.send("START") for ws in self.connected_clients
                    ])

        self.sync_server = await websockets.serve(handler, "0.0.0.0", port)

    def generate_recording_instructions(self) -> str:
        """Generate instructions for remote participants."""
        return """
## Remote Recording Setup

### Equipment
- Use a USB microphone or audio interface
- Wear headphones to prevent echo
- Choose a quiet room with minimal echo

### Software
- Use Audacity, GarageBand, or similar
- Settings: 48kHz sample rate, 24-bit
- Record in WAV format (not MP3)

### Before Recording
1. Test audio levels (peaks around -12dB)
2. Disable notifications
3. Close unnecessary applications

### During Recording
- Wait for sync signal before speaking
- Clap at start for sync alignment
- Note any interruptions

### After Recording
- Export as WAV
- Upload to shared folder: {upload_link}
- Name file: {episode}_YourName.wav
        """
```

## Audio Editing

### FFmpeg Audio Processing

```bash
# Normalize audio levels
ffmpeg -i input.wav -af "loudnorm=I=-16:TP=-1.5:LRA=11" output.wav

# Remove background noise (using noise profile)
ffmpeg -i input.wav -af "afftdn=nf=-25" cleaned.wav

# Apply compression for consistent levels
ffmpeg -i input.wav -af "acompressor=threshold=-20dB:ratio=4:attack=5:release=50" compressed.wav

# Apply podcast EQ
ffmpeg -i input.wav -af "equalizer=f=100:t=h:w=200:g=-3,equalizer=f=3000:t=h:w=1000:g=2,equalizer=f=8000:t=h:w=2000:g=1" eq.wav

# High-pass filter (remove low rumble)
ffmpeg -i input.wav -af "highpass=f=80" filtered.wav

# De-ess (reduce sibilance)
ffmpeg -i input.wav -af "adeclick=w=55:o=50" deessed.wav

# Complete podcast processing chain
ffmpeg -i input.wav -af "\
    highpass=f=80,\
    afftdn=nf=-25,\
    acompressor=threshold=-20dB:ratio=4:attack=5:release=50,\
    equalizer=f=100:t=h:w=200:g=-3,\
    equalizer=f=3000:t=h:w=1000:g=2,\
    loudnorm=I=-16:TP=-1.5:LRA=11\
" processed.wav
```

### Python Audio Processing

```python
import subprocess
from dataclasses import dataclass
from typing import List, Optional

@dataclass
class AudioEdit:
    """Represents an audio edit operation."""
    start_time: float  # seconds
    end_time: float
    operation: str  # cut, silence, crossfade


class PodcastEditor:
    def __init__(self, input_file: str):
        self.input_file = input_file
        self.edits: List[AudioEdit] = []

    def cut(self, start: float, end: float):
        """Mark section for removal."""
        self.edits.append(AudioEdit(start, end, "cut"))

    def silence(self, start: float, end: float):
        """Replace section with silence."""
        self.edits.append(AudioEdit(start, end, "silence"))

    def process_edits(self, output_file: str):
        """Apply all edits and export."""
        # Sort edits by start time
        self.edits.sort(key=lambda e: e.start_time)

        # Build filter complex for cuts
        if not self.edits:
            subprocess.run([
                "ffmpeg", "-i", self.input_file,
                "-c:a", "copy", output_file
            ])
            return

        # Generate segments to keep
        segments = []
        current_time = 0

        for edit in self.edits:
            if edit.operation == "cut" and edit.start_time > current_time:
                segments.append((current_time, edit.start_time))
            current_time = edit.end_time

        # Add final segment
        segments.append((current_time, None))

        # Build FFmpeg filter
        filter_parts = []
        for i, (start, end) in enumerate(segments):
            if end:
                filter_parts.append(f"[0:a]atrim=start={start}:end={end},asetpts=PTS-STARTPTS[a{i}]")
            else:
                filter_parts.append(f"[0:a]atrim=start={start},asetpts=PTS-STARTPTS[a{i}]")

        # Concatenate segments
        concat_inputs = "".join(f"[a{i}]" for i in range(len(segments)))
        filter_complex = ";".join(filter_parts) + f";{concat_inputs}concat=n={len(segments)}:v=0:a=1[out]"

        subprocess.run([
            "ffmpeg", "-i", self.input_file,
            "-filter_complex", filter_complex,
            "-map", "[out]",
            output_file
        ])

    def normalize(self, output_file: str):
        """Apply loudness normalization."""
        subprocess.run([
            "ffmpeg", "-i", self.input_file,
            "-af", "loudnorm=I=-16:TP=-1.5:LRA=11",
            output_file
        ])

    def add_intro_outro(
        self,
        intro_file: str,
        outro_file: str,
        output_file: str
    ):
        """Add intro and outro music."""
        subprocess.run([
            "ffmpeg",
            "-i", intro_file,
            "-i", self.input_file,
            "-i", outro_file,
            "-filter_complex",
            "[0:a][1:a][2:a]concat=n=3:v=0:a=1[out]",
            "-map", "[out]",
            output_file
        ])

    def mix_background_music(
        self,
        music_file: str,
        output_file: str,
        music_volume: float = 0.1
    ):
        """Mix background music under voice."""
        subprocess.run([
            "ffmpeg",
            "-i", self.input_file,
            "-i", music_file,
            "-filter_complex",
            f"[1:a]volume={music_volume}[music];[0:a][music]amix=inputs=2:duration=first[out]",
            "-map", "[out]",
            output_file
        ])
```

## Transcription

### Whisper Transcription

```python
import whisper
from dataclasses import dataclass
from typing import List, Optional

@dataclass
class TranscriptSegment:
    start: float
    end: float
    text: str
    speaker: Optional[str] = None


class PodcastTranscriber:
    def __init__(self, model_size: str = "medium"):
        self.model = whisper.load_model(model_size)

    def transcribe(
        self,
        audio_file: str,
        language: str = "en"
    ) -> List[TranscriptSegment]:
        """Transcribe audio file."""
        result = self.model.transcribe(
            audio_fi

Related in Image & Video