FFMPEG / Разделить, а потом склеить

У меня есть длинный аудио-файл, мне надо разбить его на меньшие куски. Я делаю это с помощью FFMPEG. Разделение происходит в месте пауз длинной не менее 1,5 секунды. И с этим проблем нет. Проблема начинается потом — по какой-то странной причине, совокупная длина всех отрезков, созданных из длинного файла — не соответствую продолжительности (длине) этого самого исходного файла. Где я ошибся?

Прилагаю код, с которым я работаю:

import subprocess
import os
from pydub import AudioSegment

# Путь к исходному WAV-файлу и каталогу для выходных файлов
input_wav_file = "/content/drive/MyDrive/RVC/Audios/pinochet/Pinochet.wav"
cut_wav_dir = "/content/drive/MyDrive/RVC/Audios/pinochet/cut"

# Убедитесь, что каталог для выходных файлов существует
os.makedirs(cut_wav_dir, exist_ok=True)

# Загрузка аудиофайла
audio = AudioSegment.from_wav(input_wav_file)

# Настройка параметров для обнаружения тишины
min_silence_duration = 1.5  # Минимальная продолжительность тишины между фрагментами в секундах

# Команда для разделения аудиофайла на фрагменты с помощью FFMPEG
ffmpeg_command = [
    "ffmpeg",
    "-i", input_wav_file,
    "-af", f"silencedetect=noise=-30dB:d={min_silence_duration}",
    "-f", "null", "-"
]

# Выполнение команды FFMPEG и захват вывода
print("Выполняется анализ аудиофайла на наличие тишины...")
output = subprocess.check_output(ffmpeg_command, stderr=subprocess.STDOUT).decode()
print("Анализ завершен.")

# Извлечение временных меток тишины из вывода
silence_timestamps = [float(line.split()[4]) for line in output.splitlines() if "silence_start" in line]

# Разделение аудиофайла на фрагменты с помощью FFMPEG и временных меток тишины
print("Выполняется разделение аудиофайла на фрагменты...")
for i, timestamp in enumerate(silence_timestamps):
    start_time = timestamp
    end_time = silence_timestamps[i + 1] if i + 1 < len(silence_timestamps) else None
    output_file = os.path.join(cut_wav_dir, f"chunk{i:03d}.wav")
    
    ffmpeg_split_command = [
        "ffmpeg",
        "-i", input_wav_file,
        "-ss", str(start_time),
        "-to", str(end_time) if end_time is not None else "",
        "-acodec", "copy",
        output_file
    ]
    
    print(f"Экспорт фрагмента {i + 1}/{len(silence_timestamps)}...")
    subprocess.run(ffmpeg_split_command)
print("Разделение завершено.")

# Вывод информации о длине исходного файла и совокупной длине всех файлов-отрезков
print(f"Длина исходного файла: {len(audio) / 1000} секунд")
total_duration_chunks = sum(end_time - start_time for start_time, end_time in zip(silence_timestamps, silence_timestamps[1:]))
print(f"Совокупная длина всех файлов-отрезков: {total_duration_chunks} секунд")

# Проверка соответствия длины исходного файла совокупной длине всех файлов-отрезков
if total_duration_chunks != len(audio) / 1000:
    print("Внимание: совокупная длина всех файлов-отрезков не соответствует длине исходного файла.")
else:
    print("Совокупная длина всех файлов-отрезков соответствует длине исходного файла.")

Ответы (1 шт):

Автор решения: Dmitry Aleshkovskiy

Решилось все c использованием split_on_silence и параметром keep_silence=True:

from pydub import AudioSegment
from pydub.silence import split_on_silence
import os

def split_audio(input_file, output_folder):
    # Загрузка аудиофайла
    if input_file.lower().endswith('.wav'):
        audio = AudioSegment.from_wav(input_file)
    elif input_file.lower().endswith('.mp3'):
        audio = AudioSegment.from_mp3(input_file)
    else:
        raise ValueError("Unsupported file format. Please use WAV or MP3.")

    # Разделение на фрагменты
    chunks = split_on_silence(audio, min_silence_len=1000, silence_thresh=audio.dBFS-14, keep_silence=True)

    # Создание папки для вывода, если она еще не существует
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)

    # Экспорт фрагментов
    total_length = 0
    for i, chunk in enumerate(chunks):
        chunk_file = os.path.join(output_folder, f"chunk{i}.mp3")
        chunk.export(chunk_file, format="mp3")
        total_length += len(chunk)

    # Проверка соответствия длительности
    original_length = len(audio)
    if original_length == total_length:
        print("Успех: Суммарная длительность фрагментов соответствует длительности исходного файла.")
    else:
        print("Предупреждение: Суммарная длительность фрагментов не соответствует длительности исходного файла.")


split_audio('path/to/your/audiofile.mp3', 'path/to/output/folder')

→ Ссылка