WAV-Audio in Python mit Pydub und FFmpeg als MP3 codieren
Konvertieren Sie eine Aufnahme oder einen Stapel WAV-Dateien mit einem Python-Skript in MP3s. Es meldet erfolgreiche Konvertierungen und gibt einen Fehler-Exit-Status zurück, sobald eine Konvertierung fehlschlägt. Das folgende Beispiel nutzt Pydub und FFmpeg, lässt Ihre Quelldateien unverändert und überschreibt keine vorhandenen Ausgabedateien.
Diese Anleitung verwendet Bash unter Linux und lokale Mono- oder Stereoaufnahmen im WAV-Format. Jede Ausgabe ist eine MP3 mit 192 kbps bei 44,1 kHz und derselben Kanalanzahl wie die Quelle. Pydub hält decodierte Audiodaten im Arbeitsspeicher. Verarbeiten Sie Dateien daher nacheinander und verwenden Sie Aufnahmen, die in den RAM passen. Dies ist ein lokales Konvertierungsskript, kein Upload-Dienst oder Streaming-Encoder.
Umgebung einrichten
Das Beispiel wurde mit Python 3.14.7, Pydub 0.25.1, audioop-lts 0.2.2 und FFmpeg 9.0.1 unter Linux getestet. Die Befehle verwenden explizit eine virtuelle Umgebung, die Sie daher nicht aktivieren müssen.
FFmpeg installieren
Installieren Sie Python mit Unterstützung für virtuelle Umgebungen sowie FFmpeg und ffprobe. Unter Ubuntu:
sudo apt-get update &&
sudo apt-get install -y python3 python3-venv ffmpeg
Andere Linux-Distributionen bieten eigene Pakete an. Die
FFmpeg-Downloadseite verlinkt auf Distributionspakete. Prüfen Sie,
ob Ihr Build den Encoder libmp3lame enthält:
ffmpeg -version &&
ffprobe -version &&
ffmpeg -hide_banner -encoders
Suchen Sie in der Encoder-Liste nach libmp3lame.
Die Installation von Pydub installiert FFmpeg nicht mit.
Pydub installieren
Erstellen Sie ein neues Verzeichnis aus dem übergeordneten Verzeichnis heraus. Wenn
audio-encoding bereits existiert, wählen Sie einen anderen Namen.
Die Befehlskette mit && stoppt die Einrichtung, bevor sie etwas in
einem vorhandenen Projekt installieren kann.
mkdir audio-encoding &&
cd audio-encoding &&
python3 -m venv .venv &&
.venv/bin/python -m pip install 'pydub==0.25.1' 'audioop-lts==0.2.2; python_version >= "3.13"'
Bleiben Sie für die restlichen Befehle in dieser Shell im Verzeichnis
audio-encoding. Python hat
audioop in 3.13 entfernt, doch Pydub 0.25.1
importiert es weiterhin. Die bedingte Abhängigkeit installiert
audioop-lts unter Python 3.13 und neuer.
Python 3.12 verwendet sein Modul aus der Standardbibliothek. Ein Paket zur Audiowiedergabe
ist nicht erforderlich.
Konverter speichern
Speichern Sie das vollständige Skript unten als encode_audio.py. WAV ist ein
Container: Seine Samples können Ganzzahlen oder Gleitkommawerte sein. Das Skript lässt FFmpeg
zunächst in vorzeichenbehaftetes 16-Bit-PCM decodieren und übergibt diese bekannte Darstellung
anschließend an Pydub. So ist es nicht auf den
WAV-Schnellpfad von Pydub 0.25.1 angewiesen,
der nicht alle Sample-Typen von Extensible WAV unterscheidet. Höhere Bittiefen werden für diesen
MP3-Workflow auf 16 Bit reduziert. Behalten Sie die WAV-Quelldatei als Master.
Das MP3-Encoding erfolgt in einem temporären Verzeichnis neben dem Ziel. Erst nach abgeschlossenem Encoding wird die Datei über einen Hardlink bereitgestellt. Dieser Vorgang schlägt fehl, wenn das Ziel bereits existiert. Verwenden Sie ein lokales Dateisystem, das Hardlinks unterstützt. Dateien aus erfolgreichen Konvertierungen bleiben erhalten, wenn eine andere Eingabe fehlschlägt.
import argparse
import os
from pathlib import Path
import shutil
import subprocess
import sys
from tempfile import TemporaryDirectory
from pydub import AudioSegment
from pydub.exceptions import CouldntDecodeError, CouldntEncodeError
def convert_one(source, output_dir, ffmpeg, fade_ms):
if source.suffix.lower() != '.wav' or not source.is_file():
raise ValueError('Expected an existing WAV file')
destination = output_dir / (source.stem + '.mp3')
if os.path.lexists(destination):
raise FileExistsError(f'Output already exists: {destination}')
with TemporaryDirectory(prefix='.encode-', dir=output_dir) as work:
decoded = Path(work) / 'decoded.wav'
encoded = Path(work) / 'encoded.mp3'
subprocess.run(
[ffmpeg, '-nostdin', '-hide_banner', '-v', 'error', '-xerror',
'-f', 'wav', '-i', str(source.resolve(strict=True)),
'-map', '0:a:0', '-c:a', 'pcm_s16le', '-ar', '44100', str(decoded)],
check=True, stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL,
)
audio = AudioSegment.from_wav(decoded)
if audio.channels not in (1, 2) or len(audio) == 0:
raise ValueError('Expected nonempty mono or stereo audio')
if fade_ms > len(audio):
raise ValueError('The fade must not exceed the recording length')
if fade_ms:
audio = audio.fade_in(fade_ms).fade_out(fade_ms)
audio.export(encoded, format='mp3', codec='libmp3lame', bitrate='192k').close()
os.link(encoded, destination)
return destination
def main():
parser = argparse.ArgumentParser(description='Convert WAV recordings to MP3')
parser.add_argument('--out-dir', type=Path, required=True)
parser.add_argument('--fade-ms', type=int, default=0)
parser.add_argument('inputs', type=Path, nargs='+')
args = parser.parse_args()
if args.fade_ms < 0:
parser.error('--fade-ms must be zero or greater')
ffmpeg = shutil.which('ffmpeg')
if ffmpeg is None:
parser.error('ffmpeg is missing from PATH')
AudioSegment.converter = ffmpeg
try:
output_dir = args.out_dir.resolve()
output_dir.mkdir(parents=True, exist_ok=True)
except OSError as error:
parser.exit(2, f'Cannot prepare output directory: {error}\n')
failed = 0
for source in args.inputs:
try:
destination = convert_one(source, output_dir, ffmpeg, args.fade_ms)
except (OSError, ValueError, subprocess.CalledProcessError,
CouldntDecodeError, CouldntEncodeError) as error:
failed += 1
print(f'FAILED {source}: {error}', file=sys.stderr)
else:
print(f'OK {source} -> {destination}')
print(f'{len(args.inputs) - failed} converted, {failed} failed')
return 1 if failed else 0
if __name__ == '__main__':
sys.exit(main())
Die Option -xerror von FFmpeg sorgt dafür,
dass die Konvertierung bei gemeldeten Decodierungsfehlern fehlschlägt. Das erfasst beschädigte
Eingaben, die FFmpeg andernfalls möglicherweise teilweise wiederherstellen würde. Es ist kein
Nachweis dafür, dass jede Aufnahme vollständig ist: Hören Sie wichtige Ausgaben an und vergleichen
Sie ihre Dauer mit der erwarteten Aufnahmelänge.
Eine Aufnahme konvertieren
Verwenden Sie Ihre eigene Datei input.wav oder erzeugen Sie einen Testton
von drei Sekunden. Das Flag -n verhindert das Überschreiben einer
vorhandenen Datei:
ffmpeg -nostdin -hide_banner -v error -n -f lavfi \
-i 'sine=frequency=440:sample_rate=44100:duration=3' -c:a pcm_s16le input.wav
Führen Sie den Konverter aus dem Verzeichnis audio-encoding aus:
.venv/bin/python encode_audio.py --out-dir mp3 -- input.wav
Er gibt eine Zeile mit OK sowie 1 converted, 0 failed aus
und endet mit dem Status 0. Die Datei lautet
mp3/input.mp3. Wenn Sie den Befehl erneut ausführen, meldet er einen Fehler
wegen der vorhandenen Ausgabe, endet mit dem Status 1 und lässt
die Bytes der ersten MP3 unverändert. Wählen Sie für ein neues Encoding ein anderes
Ausgabeverzeichnis.
Audiodateien im Stapel verarbeiten
Erstellen Sie ein Verzeichnis namens wav_files und legen Sie Ihre
WAV-Aufnahmen darin ab. Übergeben Sie diese dann an dasselbe Skript:
.venv/bin/python encode_audio.py --out-dir mp3-batch -- wav_files/*.wav
Bash expandiert dieses Glob-Muster für Dateien direkt im Verzeichnis, ohne Rekursion. Es erfasst
Namen mit der kleingeschriebenen Endung .wav. Dateien mit der
großgeschriebenen Endung .WAV müssen Sie explizit übergeben. Gibt es
keine Treffer, erreicht das Muster das Skript als Literal und löst einen Fehler wegen einer
fehlenden Eingabe aus. Setzen Sie einzelne Pfade mit Leerzeichen in Anführungszeichen. Das
Trennzeichen -- erlaubt auch Eingabenamen, die mit einem Bindestrich
beginnen.
Jede Eingabe erhält eine Zeile mit OK oder
FAILED. Ein gemischter Stapel behält gültige MP3s bei, setzt die Verarbeitung
nach einer beschädigten Datei fort und endet mit dem Status 1.
Zwei Eingaben wie a/interview.wav und b/interview.wav ergeben
denselben Ausgabenamen: Die erste erfolgreiche Konvertierung belegt ihn, die zweite wird als
Fehler gemeldet. Deshalb meldet auch die erneute Ausführung eines abgeschlossenen Stapels Fehler,
statt Dateien stillschweigend zu überspringen oder zu ersetzen.
| Exit-Status | Bedeutung |
|---|---|
0 | Jede angeforderte Eingabe wurde konvertiert. |
1 | Mindestens eine Eingabe ist fehlgeschlagen, auch bei einem bereits vorhandenen Ziel. |
2 | Argument- oder Einrichtungsfehler, etwa eine fehlende ausführbare FFmpeg-Datei oder ein unbrauchbares Ausgabeverzeichnis. |
Gezielt ein- und ausblenden
Um die ersten und letzten 100 Millisekunden sanfter zu gestalten, verwenden Sie ein neues Ausgabeverzeichnis:
.venv/bin/python encode_audio.py --out-dir mp3-faded --fade-ms 100 -- input.wav
Ohne diese Option wendet das Skript weder Ein- und Ausblenden noch Verstärkung, Normalisierung oder Dynamikkompression an. Eine höhere MP3-Bitrate stellt keine Informationen wieder her, die in der Quelle fehlen. Hören Sie die Aufnahme an, bevor Sie Pegel ändern. Eine Spitzenpegelnormalisierung mit anschließender Lautstärkeanhebung kann das Audio übersteuern. Informationen zu Verstärkung sowie Ein- und Ausblenden finden Sie in der Pydub-API.
Ausgabe prüfen
Untersuchen Sie die erste MP3 und decodieren Sie sie vollständig:
ffprobe -v error -select_streams a:0 \
-show_entries stream=codec_name,sample_rate,channels,bit_rate:format=duration \
-of json mp3/input.mp3 &&
ffmpeg -nostdin -v error -xerror -i mp3/input.mp3 -f null -
Beim Testton sollte codec_name den Wert mp3 haben
und sample_rate den Wert 44100. Erwarten Sie einen
Kanal und eine Dauer von etwa drei Sekunden. Padding bei MP3-Frames kann die gemeldete Dauer
leicht verlängern. Der Decodierungsbefehl sollte erfolgreich und ohne Fehlermeldungen enden.
Metadaten und Decodierbarkeit sind nützliche Prüfkriterien, belegen aber nicht die wahrgenommene
Audioqualität.
Häufige Probleme beheben
No module named 'audioop'oder'pyaudioop': Führen Sie die Paketinstallation mit den festgelegten Versionen erneut aus. Verwenden Sie dazu.venv/bin/python -m pipinnerhalb des Projekts und schließen Sie die bedingte Abhängigkeitaudioop-ltsein.- FFmpeg oder
Unknown encoder 'libmp3lame'fehlt: Prüfen Sie die ausführbare Datei und die Encoder-Liste aus der Einrichtung. Das Python-Paket und der System-Encoder werden separat installiert. - Beschädigte oder fehlende Eingabe: Lesen Sie die Zeile mit
FAILEDund alle vorangehenden FFmpeg-Diagnosemeldungen. Wenn das Decodieren oder Codieren fehlschlägt, wird keine neue MP3 bereitgestellt. Ein bereits vorhandenes Ziel bleibt unverändert. - Hardlink- oder Berechtigungsfehler: Verwenden Sie ein beschreibbares lokales Ausgabeverzeichnis mit Hardlink-Unterstützung. Das Skript entfernt sein temporäres Arbeitsverzeichnis bei gewöhnlichen Fehlern und ersetzt niemals ein Ziel, um einen Dateisystemfehler zu umgehen.
Bewahren Sie die Originalaufnahmen auf und verwenden Sie ein neues Ausgabeverzeichnis, wenn Sie Encoding-Einstellungen ändern. Wenn die Konvertierung nicht mehr in Ihrem lokalen Python-Prozess stattfinden soll, entdecken Sie unseren Audio-Encoding-Dienst.
