Александр Иванов – Python для творческих. Звук на твоей стороне. (страница 8)
"""Подгоняет пиковую громкость к заданному уровню."""
current_peak = np.max(np.abs(y))
if current_peak == 0:
return y
gain = target_peak / current_peak
return y * gain
# Нормализуем все части
intro = normalize_volume(intro, 0.9)
voice = normalize_volume(voice, 0.9)
outro = normalize_volume(outro, 0.9)
После такого выравнивания все три части будут иметь одинаковый пиковый уровень, и слушателю не придётся тянуться к регулятору громкости.
Собираем готовый эпизод подкаста
Теперь давайте соберём всё вместе в один большой скрипт, который принимает набор файлов и выдаёт готовый смонтированный эпизод. Этот скрипт можно будет использовать для каждого выпуска подкаста, меняя только имена файлов.
python
import librosa
import numpy as np
import soundfile as sf
def build_podcast(intro_file, voice_file, outro_file, output_file,
trim_start=180, trim_end=10,
silence_between=1.0,
target_sr=22050,
target_peak=0.9):
"""
Собирает эпизод подкаста из трёх файлов.
trim_start - сколько секунд отрезать от начала голосовой дорожки
trim_end - сколько секунд отрезать от конца голосовой дорожки
silence_between - длина паузы между частями в секундах
"""
print("=== Сборка эпизода ===")
# Загружаем
print("Загружаю файлы...")
intro, _ = librosa.load(intro_file, sr=target_sr)
voice, _ = librosa.load(voice_file, sr=target_sr)
outro, _ = librosa.load(outro_file, sr=target_sr)
# Обрезаем голос
start_sample = int(trim_start * target_sr)
end_sample = len(voice) - int(trim_end * target_sr)
voice = voice[start_sample:end_sample]
print(f"Голос после обрезки: {len(voice) / target_sr:.1f} сек")
# Нормализуем громкость
for arr in [intro, voice, outro]:
peak = np.max(np.abs(arr))
if peak > 0:
arr *= target_peak / peak
# Создаём паузу
silence = np.zeros(int(target_sr * silence_between))
# Склеиваем
final = np.concatenate([intro, silence, voice, silence, outro])
print(f"Финальная длина: {len(final) / target_sr:.1f} сек")
# Сохраняем
sf.write(output_file, final, target_sr)
print(f"Сохранено: {output_file}")
print("Готово!")
# Запускаем
build_podcast(
intro_file='intro.wav',
voice_file='raw_voice.wav',
outro_file='outro.wav',
output_file='episode_ready.wav',
trim_start=180,
trim_end=10,
silence_between=1.0
)
Запустите этот скрипт, указав свои файлы. Если у вас нет готовых джинглов для интро и аутро, не беда — можете пока использовать любые музыкальные фрагменты или даже тишину. Главное — понять процесс. Когда появятся настоящие джинглы, вы просто подставите их в скрипт, и всё будет работать.
Пакетная обработка: монтируем много файлов сразу