숏폼 나레이션이 배속 재생처럼 빨라질 때 — 컷 길이를 말에 맞추기
컷 길이를 눈대중으로 정하면 나레이션이 컷을 넘쳐 말속도를 올려 욱여넣게 된다. 문장을 실제로 합성해 재서 컷 길이를 역산하는 방법과, 컷별로는 멀쩡한데 이어 읽으면 이상해지는 대본을 잡아내는 점검표.
🗺 시리즈: 네이버 클립 자동 제작 — 지금은 ④ 컷 길이를 말에 맞추기
← 이전 편: ③ 레퍼런스에서 내 나레이션 목소리 찾기
① 컷시트 렌더 엔진 · ② 한 글자씩 찍히는 타이핑 자막 · ③ 레퍼런스에서 내 나레이션 목소리 찾기 · ④ 컷 길이를 말에 맞추기 (현재 글)
지난 편에서 나레이션 목소리를 정했다. 그런데 붙여놓고 들어보니 말이 급했다.
22문장 중 17개가 속도 조절 없이 그대로 나가는 최종본
문제
나레이션은 컷 하나에 문장 하나씩 배치된다. 문장이 컷보다 길면 컷을 넘치니, 넘치는 만큼 말속도를 올려서 맞췄다.
1
2
3
4
5
6
7
001 | 1.80s → 2.02s | r=28 | 비 오면 여기로 가세요
002 | 4.80s → 1.82s | r=34 | 토요일에 비가 왔고
…
015 | 35.30s → 1.82s | r=55 | 1층 카트가 내려다보여요
018 | 42.20s → 2.14s | r=55 | 그 코인은 게임존 뽑기에 쓰고
019 | 44.40s → 2.02s | r=55 | 소꿉놀이방에서 안 나오더라고요
020 | 46.40s → 1.78s | r=55 | 비 와서 망한 줄 알았는데
r이 속도 증가율이다. 상한으로 걸어둔 +55%에 붙은 문장이 다섯 개. 1.55배는 사람 말이 아니라 배속 재생으로 들린다. 특히 마무리 문장이 급하면 영상 전체가 허둥댄 느낌으로 끝난다.
원인
컷 길이를 내가 눈대중으로 정했기 때문이다.
컷시트를 쓸 때는 “이 정도면 2초쯤” 하고 적는다. 그림만 볼 때는 맞는 감이다. 그런데 거기에 12음절짜리 문장을 얹으면 이야기가 달라진다. 한국어 뉴럴 음성으로 소꿉놀이방에서 안 나오더라고요를 읽으면 자연스러운 속도로 2.9초가 걸린다. 2초짜리 컷에 넣으려면 1.45배로 몰아야 한다.
문제는 음성이 아니라 컷이었다. 그런데 나는 음성 쪽 손잡이(속도)만 돌리고 있었다.
해결 과정
처음 시도 — 컷 경계를 조금 넘게 해줬다 (틀렸다)
“컷을 0.35초까지는 넘어가도 되게 하자”고 생각했다. 실제 영상에서도 나레이션이 컷을 살짝 타고 넘는다.
1
LIMIT=$(awk "BEGIN{printf \"%.2f\", $DUR+0.35-0.12}")
숫자상으로는 좋아졌다. r=55가 몇 개 사라졌다.
그런데 이건 틀린 완화였다. 컷마다 문장이 하나씩 있으니, 이 컷을 0.35초 넘긴다는 건 다음 문장이 시작한 뒤에도 앞 문장이 말하고 있다는 뜻이다. 두 목소리가 겹친다. 화면 자막은 이미 다음 문장인데 소리는 앞 문장을 마저 읽는다.
허용 시간을 “다음 문장이 시작할 때까지”로
경계를 컷이 아니라 다음 문장의 시작점으로 잡았다. 이러면 겹칠 일이 없고, 자막 없는 컷이 뒤따르거나 마지막 문장이면 그만큼 여유가 저절로 생긴다.
1
2
3
4
5
6
awk -F'\t' -v total="$T" '{st[NR]=$1; du[NR]=$2; tx[NR]=$3}
END{for(i=1;i<=NR;i++){
nx = (i<NR) ? st[i+1] : total; # 다음 문장 시작, 없으면 영상 끝
w = nx - st[i];
m = du[i] + 0.9; if (w > m) w = m; # 자막과 너무 어긋나지 않게 상한
printf "%s\t%.2f\t%s\n", st[i], w, tx[i]}}' lines.txt > win.txt
컷 길이 + 0.9초 상한을 둔 이유는, 여유가 아무리 많아도 자막이 바뀐 뒤까지 한 문장을 끌면 눈과 귀가 따로 놀기 때문이다.
이걸로 마지막 문장(여긴 추천합니다)은 r=55에서 r=0으로 떨어졌다. 뒤에 자막 없는 컷이 있어 여유가 생긴 것이다. 하지만 중간의 빡빡한 문장들은 그대로였다.
근본 해결 — 컷 길이를 문장에서 역산한다
방향을 뒤집었다. 컷 길이를 정하고 문장을 맞추는 게 아니라, 문장을 재고 컷 길이를 정한다.
문장 하나하나를 실제로 합성해 앞뒤 무음을 잘라낸 길이를 잰다. 그 값에 숨 쉴 여백을 더한 게 그 컷의 최소 길이다.
1
2
3
4
5
6
7
8
def spoken(text):
"""문장을 실제로 합성해 앞뒤 무음을 뺀 길이를 잰다."""
subprocess.run([EDGE, '--voice', VOICE, '--rate', '+35%', '--text', text,
'--write-media', mp3], check=True, capture_output=True)
subprocess.run(['ffmpeg','-y','-v','error','-i',mp3,'-af',TRIM,wav], check=True)
return probe(wav)
need = round(max(FLOOR, spoken(main) + MARGIN), 1) # FLOOR=2.0, MARGIN=0.35
두 값을 정했다.
- 최소 2.0초 — 이보다 짧으면 자막을 읽을 시간이 없다. 타이핑 자막이면 더욱 그렇다
- 여백 0.35초 — 문장 끝과 컷 끝이 딱 붙으면 숨 쉴 틈 없이 다음 컷으로 넘어간다
원본 영상이 모자랄 때
컷을 늘리려면 원본 영상에 그만큼 남아 있어야 한다. 4.5초짜리 영상의 3.0초 지점부터 2.9초를 쓸 수는 없다.
먼저 시작점을 앞으로 당겨보고, 그래도 모자라면 컷을 줄이되 경고를 남긴다.
1
2
3
4
5
6
7
8
st = float(start); avail = src_dur(src) - st - 0.08
if need > avail:
shift = min(st - 0.2, need - avail)
if shift > 0:
st = round(st - shift, 1); avail = src_dur(src) - st - 0.08
if need > avail:
log.append(f" ! {src} 원본이 짧다 → {need:.1f} 대신 {avail:.1f}초 [{main}]")
need = round(avail, 1)
경고를 조용히 삼키지 않는 게 중요하다. 그 컷만 말이 빨라지므로, 사람이 보고 “다른 소재로 바꿀지” 판단해야 한다. 실제로 이 경고가 뜬 컷 하나는 소재를 바꿀 수 없어서(그 장면이 그 영상에만 있었다) 감수하고 넘어갔다.
결과
| 고치기 전 | 고친 뒤 | |
|---|---|---|
| 속도 조절 없이 나가는 문장 | 3개 | 17개 |
| 상한(+55%)에 붙은 문장 | 5개 | 0개 |
| 최대 속도 증가율 | +55% | +19% |
| 영상 길이 | 51.7초 | 45.9초 |
영상이 오히려 짧아졌다. 컷을 문장에 맞추니 불필요하게 길게 잡아뒀던 컷들이 줄었기 때문이다. 말은 느려졌는데 영상은 짧아진 셈이다.
문장을 합쳐 한 트랙으로 만들 때 뒤로 갈수록 소리가 커지는 문제가 따로 있다 → ffmpeg amix로 합쳤더니 뒤로 갈수록 소리가 커진다
대본은 컷별로 보면 안 된다
여기까지가 시간 문제였다. 그런데 다 맞춰놓고 처음부터 들어보니 다른 종류의 문제가 드러났다.
컷시트는 한 줄씩 쓴다. 그래서 줄 단위로는 다 멀쩡한데 이어 읽으면 이상한 대본이 나온다. 다섯 가지가 걸렸다.
| 증상 | 실제로 있었던 것 |
|---|---|
| 소리 구멍 | 요금표 컷에 상단 배지만 넣고 본자막을 비웠다. 나레이션은 본자막에서 읽으므로 2.4초 동안 소리가 통째로 끊겼다 |
| 동선 왕복 | 안쪽엔 카트 트랙 → 테마존 옆이 게임존 → 2층. 안쪽까지 갔다가 도로 나와서 다시 올라간다 |
| 끊긴 전환 | 그 코인은 게임존 뽑기에 쓰고 → 소꿉놀이방에서 안 나오더라고요. 연결이 없어 뜬금없다 |
| 같은 단어 반복 | 무료가 세 번(게임기는 전부 무료래요 / (이것도 무료) / (여기도 전부 무료)) |
| 직전 컷과 중복 | 2층으로 올라가면 바로 뒤에 2층 사냥터에서… |
고친 방식은 이렇다.
- 소리 구멍 — 안내판이 화면을 꽉 채워 자막을 못 넣던 상황이었다. 안내판을 위쪽에 배치한 그림을 새로 만들어 아래를 비우고 자막을 넣었다. 배지는 나레이션으로 읽히지 않는다는 걸 몰랐던 게 원인이다
- 동선 왕복 — 공간 순서대로 재배열
- 끊긴 전환 —
정작 제일 오래 논 덴 소꿉놀이방으로 이어 붙였다 - 반복·중복 — 정보값이 낮은 쪽을 뺐다
이걸 잡으려고 대본을 시간순으로 출력해 소리 내어 이어 읽는 단계를 절차에 넣었다.
1
2
3
4
5
1.8초 비 오면 여기로 가세요
3.8초 토요일에 비가 왔고
5.8초 갈 데 찾다 들어온 월드킹
…
44.2초 여긴 추천합니다
그림 쪽 점검은 1편의 검수시트가, 말 쪽 점검은 위의 시간순 대본이 맡는다.
🧭 기획자·사업자라면 분량 산정을 감으로 하면 반드시 뒤에서 터진다. “이 정도면 2초쯤”이 틀린 게 아니라, 그 감이 그림 기준이었고 거기에 말이 얹히리라는 걸 계산에 안 넣었을 뿐이다. 제약이 둘 이상 얹히는 항목은 눈대중이 아니라 실측으로 역산해야 한다. 그리고 줄 단위 검수는 흐름을 못 잡는다. 항목별로는 다 통과하는데 이어 놓으면 이상한 산출물 — 페이지 단위로 리뷰한 사용자 흐름, 조항별로 검토한 계약서, 슬라이드별로 본 제안서가 다 같은 함정이다. 완성물을 처음부터 끝까지 한 번 통과시키는 단계를 절차에 따로 박아둬야 한다.
사용한 기술
- edge-tts +
silenceremove— 문장별 실제 발화 길이 측정. 앞뒤 무음을 빼야 정확하다 - awk 2패스 — 문장 목록을 훑어 “다음 문장 시작까지”의 창을 계산
- ffprobe — 원본 영상 길이를 재서 컷을 늘릴 여유가 있는지 확인
- 컷시트 제자리 수정 — 역산 결과를 컷시트에 바로 반영하고, 못 맞춘 컷은 경고로 남긴다
정리
- 말이 빠른 건 음성 설정 문제가 아니라 컷이 짧아서다. 속도 손잡이를 돌리기 전에 컷 길이를 문장에서 역산하라.
- “조금 넘쳐도 된다”는 완화는 위험하다. 컷당 문장이 하나면 그 넘침은 다음 문장과의 겹침이다. 경계는 컷이 아니라 다음 문장의 시작점으로 잡아야 한다.
- 컷별로 멀쩡한 대본이 이어 읽으면 이상할 수 있다. 소리 구멍·동선 왕복·끊긴 전환은 시간순으로 통째로 읽어야만 보인다.
시리즈는 여기까지다. 컷시트 한 장에서 시작해 자막이 찍히고 목소리가 얹히고 길이가 맞춰진 결과물이 이 클립이다.
