음성 해설 및 TTS
음성 해설은 타임라인을 주도합니다. 비주얼을 구축하기 전에 생성하세요.
엔진 선택
| 엔진 | 위치 | 강점 | 주의사항 |
|---|---|---|---|
| ElevenLabs | 클라우드 API | 최고의 자연스러움, 음성 복제 | 유료, 동의 없이 복제 금지 |
| OpenAI TTS | 클라우드 API | 간단하고 일관된 | 제한된 음성 선택 |
| Kokoro | 로컬 | 무료, 고품질, 오프라인 | Python 설정 필요 |
| Piper | 로컬 | 빠름, CPU에서 실행 | 덜 표현력 있음 |
| 녹음된 인간 | 마이크 | 가장 자연스러움 | 정리 필요 |
API 키는 환경 변수 또는 git에서 무시되는 .env 파일에 보관하세요. 절대 출력하거나 커밋하지 마세요.
음성용 스크립트 준비
- 숫자, 단위 및 약어는 발음대로 작성: "이천이십육", "A P I" (철자할 경우), "기가바이트".
- 쉼표는 숨쉬기용, 마침표는 멈춤용으로 사용; 괄호는 피하세요.
- 어려운 이름은 발음 목록에 넣고 짧은 샘플로 먼저 테스트하세요.
- 장면당 하나의 파일(
audio/scene-01.mp3)로 분할하세요. 장면별 파일을 사용하면 한 줄만 다시 녹음하고 타이밍을 유연하게 조정할 수 있습니다.
생성 (예시, ElevenLabs REST)
import os, requests, pathlib
def tts(text: str, voice_id: str, out: pathlib.Path) -> None:
r = requests.post(
f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}",
headers={"xi-api-key": os.environ["ELEVENLABS_API_KEY"], "Accept": "audio/mpeg"},
json={"text": text, "model_id": "eleven_multilingual_v2",
"voice_settings": {"stability": 0.5, "similarity_boost": 0.75}},
timeout=120,
)
r.raise_for_status()
out.write_bytes(r.content)
모델 이름과 엔드포인트는 변경될 수 있습니다. 사용 전에 제공자의 최신 문서를 확인하세요.
측정 및 속도 조절
ffprobe -v error -show_entries format=duration -of default=nw=1:nk=1 audio/scene-01.mp3
- 분당 140~160 단어를 목표로 하세요 (단어 / 초 * 60). 장면이 분당 180단어를 초과하면 약간 다른 전달로 다시 생성하거나 텍스트를 줄이세요. 너무 빠르게 들릴 수 있습니다.
- 음성을 10% 이상 시간 압축하지 마세요. 인공적으로 들립니다. 대신 다시 작성하세요.
녹음된 음성 정리
# 하이패스, 부드러운 잡음 감소, 압축, 음량
ffmpeg -i raw.wav -af "highpass=f=80,afftdn=nf=-25,acompressor=threshold=-18dB:ratio=3:attack=5:release=80,loudnorm=I=-16:TP=-1.5:LRA=11" -ar 48000 clean.wav
시작과 끝의 침묵 제거:
ffmpeg -i in.wav -af "silenceremove=start_periods=1:start_threshold=-45dB,areverse,silenceremove=start_periods=1:start_threshold=-45dB,areverse" out.wav
조립
# 장면 파일을 0.4초 간격으로 결합
python - <<'PY'
import subprocess, pathlib
files = sorted(pathlib.Path("audio").glob("scene-*.mp3"))
parts = []
for i, f in enumerate(files):
parts += ["-i", str(f)]
n = len(files)
filt = "".join(f"[{i}:a]apad=pad_dur=0.4[a{i}];" for i in range(n)) + "".join(f"[a{i}]" for i in range(n)) + f"concat=n={n}:v=0:a=1[out]"
subprocess.run(["ffmpeg", "-y", *parts, "-filter_complex", filt, "-map", "[out]", "voiceover.mp3"], check=True)
PY
그런 다음 audio-mixing에서 음악과 믹싱하고 captions-subtitles를 사용하여 자막을 추가하세요.
윤리 및 권리
- 화자의 명시적 허가가 있을 때만 음성을 복제하세요.
- 플랫폼 규칙이나 법률에서 요구하는 경우 합성 음성을 공개하세요.
- 상업적 사용을 위해 TTS 제공자의 라이선스를 확인하세요.