Audio Ducking:配音出現時自動降配樂——做出廣告級的旁白混音
用 Remotion 的 dynamic volume function 做 ducking。配音出現時 BGM 自動降下來、結束後彈回去,廣告/Podcast/YouTube 影片的標配技巧,幾行 interpolate 就搞定。
成品預覽
DAW 風格的混音介面,左到右掃描的播放頭碰到 voiceover clip 的瞬間,BGM 推桿明顯掉下來、波形變暗、彈出「DUCKING −12 dB」提示——這就是一個 volume 函式做出的廣告級混音技巧。
這篇會做出什麼
一個會自動 ducking 的雙軌音訊:
- BGM 軌:背景音樂全程播放
- VOICE 軌:配音 / 旁白出現在影片中段
- 自動 ducking:配音播放期間 BGM 音量降到 0.15,結束後再升回 0.5
整篇只教一個技術:<Audio volume={(frame) => …}> 的 dynamic volume function。
前置知識
- T8 Podcast 音波視覺化 — 熟悉
<Audio> - T13 影片剪輯 — 熟悉
<Sequence>包音訊
Step 1:把 BGM 跟 VOICE 兩軌都掛上去
Claude Code:
新增 Composition "DuckingDemo":
- 1920x1080 fps 30 durationInFrames 300(10 秒)
- 新建 src/compositions/DuckingDemo.tsx 並在 Root.tsx 註冊
元件內掛兩個 <Audio>:
1. BGM:<Audio src={staticFile("audio/bgm.mp3")} volume={0.5} />
2. VOICE:用 <Sequence from={105} durationInFrames={110}>
包 <Audio src={staticFile("audio/voiceover.mp3")} volume={1.0} />
播一次:聽起來糟糕——配音出來時 BGM 還是滿格音量,整個被蓋過去。這就是「沒做 ducking」的影片。
Step 2:把 BGM 的 volume 換成 function
這就是整篇的核心——把 volume 從一個固定數字改成一個 (frame) => number 的函式。
改寫 BGM 的 <Audio>:
const VOICE_START = 105;
const VOICE_END = 215;
const FADE = 12;
<Audio
src={staticFile("audio/bgm.mp3")}
volume={(frame) => {
if (frame > VOICE_START - FADE && frame < VOICE_END + FADE) {
return interpolate(
frame,
[
VOICE_START - FADE,
VOICE_START,
VOICE_END,
VOICE_END + FADE,
],
[0.5, 0.15, 0.15, 0.5],
);
}
return 0.5;
}}
/>
讀一下這個 function:
- 沒在 voice 期間 → 回傳
0.5(正常音量) - 進入 voice 前 12 幀 → 從
0.5線性下降到0.15(fade out) - voice 期間 → 維持
0.15(被 ducked) - voice 結束後 12 幀 → 從
0.15線性回升到0.5(fade in)
這個四點 interpolate pattern 是 Remotion ducking 的「武林絕學」——記住它,廣告影片、Podcast、YouTube 全部都用這個。
播一次:旁白出現時 BGM 自動讓出空間,結束後音量自然回來。聽起來瞬間升級。
💡 動態音量、
volume函式的完整簽名與更多 pattern 在 /docs/audio-volume。
Step 3:為什麼一定要 fade 邊界?
想偷懶寫成:
volume={(frame) => {
if (frame >= VOICE_START && frame <= VOICE_END) return 0.15;
return 0.5;
}}也會 work,但是聽起來會「卡」一下——0.5 → 0.15 是音量瞬間跳變,會聽到 click / pop 聲。
加上 12 幀(0.4 秒)的 fade 之後,聽起來像專業混音師在現場推 fader——這就是廣告質感的差別。
Step 4:抽成一個 helper(選擇性)
整支影片可能有十幾個 voice clip,每個都複製一遍 ducking 邏輯太累。抽成 helper:
// src/audio/ducking.ts
import { interpolate } from "remotion";
export type VoiceWindow = { start: number; end: number };
export const buildDuckingVolume = (
windows: VoiceWindow[],
baseVolume = 0.5,
duckedVolume = 0.15,
fade = 12
) => {
return (frame: number) => {
for (const w of windows) {
if (frame > w.start - fade && frame < w.end + fade) {
return interpolate(
frame,
[w.start - fade, w.start, w.end, w.end + fade],
[baseVolume, duckedVolume, duckedVolume, baseVolume]
);
}
}
return baseVolume;
};
};用法:
const VOICE_WINDOWS = [
{ start: 105, end: 215 },
{ start: 360, end: 510 },
{ start: 720, end: 900 },
];
<Audio
src={staticFile("audio/bgm.mp3")}
volume={buildDuckingVolume(VOICE_WINDOWS)}
/>整支 podcast 三段旁白只要列窗口,BGM 自己會在對的時間點 duck。
Step 5:渲染
渲染 DuckingDemo:
- 1920x1080 H.264
- 音訊 codec aac
- 音訊 bitrate 192k
- 輸出 out/audio-ducking.mp4
戴耳機聽——配音那一段你會清楚聽到 BGM 「往後退一步」讓出空間,這就是 ducking 在做的事。
完成!回顧學到的概念
| 概念 | 重點 |
|---|---|
<Audio volume> 接函式 | volume 可以是 number 或 (frame: number) => number |
四點 interpolate ducking pattern | [VS-FADE, VS, VE, VE+FADE] → [base, ducked, ducked, base] |
| 為什麼要 fade 邊界 | 避免音量瞬跳的 click pop |
| 抽 helper 管理多窗口 | 整支影片所有 voice clip 共用一條 ducking 規則 |
本篇涵蓋的官方文件
- /docs/audio-volume — 動態音量、
volume函式 - /docs/audio-details — 音訊處理進階細節
- /docs/audio-processing-order — 多軌音訊處理順序
常見問題
Q:可以對 voice 軌也做 ducking 嗎(讓 voice 在某個 SFX 出現時降下來)?
A:可以——volume 函式對任何 <Audio> 都成立。原則是「誰需要讓位給誰,誰就掛 ducking」。
Q:ducked volume 該設多少?
A:行業常用是把 BGM 降 1216 dB(線性大約 0.150.25)。太低會像「靜音」、太高蓋不住人聲。0.15 是廣告片常見值。
Q:fade 應該幾幀?
A:815 幀(30fps 下大約 0.250.5 秒)最自然。少於 5 幀會聽到 click,多於 20 幀會「拖泥帶水」。
Q:為什麼不用 ffmpeg 預先 ducking? A:可以——但 Remotion 的好處是 voice 窗口跟 React props 連動,你可以在同一份 code 裡同時控制畫面跟音訊(例如「字幕出來時降配樂」)。一個資料來源,一份真相。
Q:能不能做到「自動偵測 voice 在哪」自動 ducking?
A:用 getAudioDurationInSeconds + 一個外部 silence-detection 工具(例如 ffmpeg 的 silencedetect filter)取出 voice 起訖點,再丟進 VOICE_WINDOWS。完全自動化的 pipeline 是進階題。
下一步
- T18:Audio Pitch — 用 playbackRate 改音高 — 另一個音訊魔法
- T14:3D 特效與 Shader — 視覺的下一步升級
有問題歡迎到 FB 社群 討論!