· 6 MIN READ

程序化音效:用噪聲做出風

音訊工程

程序化音效:用噪聲做出風 封面插圖
圖 — 程序化音效:用噪聲做出風

一個十四秒的開場,配樂版權要錢,音效檔要流量,兩者都要維護。但仔細想開場需要什麼聲音:風、紙的拍打、城市的低頻、收尾的一口氣——全部是噪聲加濾波。Web Audio 一個採樣都不用存。

風 = 白噪聲 + 追隨速度的帶通#

底層是一個長 2 秒的白噪聲 buffer 無縫循環(循環點用 crossfade 避免「哒哒」聲),過一個 Q 值 1.4 的 bandpass。中频心頻隨飛機速度從 220Hz 掃到 900Hz——風切聲的音高就是速度的函數,這個映射是整個音效設計裡最值钱的一行:

const noise = ctx.createBufferSource();
noise.buffer = whiteNoise(2);
noise.loop = true;
const bp = ctx.createBiquadFilter();
bp.type = 'bandpass';
bp.Q.value = 1.4;
// 每幀:
bp.frequency.setTargetAtTime(220 + speed * 680, ctx.currentTime, 0.08);
gain.gain.setTargetAtTime(0.05 + speed * 0.25, ctx.currentTime, 0.12);

注意 setTargetAtTime 而不是直接賦值:濾波參數瞬變會咔擦,0.08 秒的時間常數剛好讓掃頻「吹」出來而不是「切」出來。

紙拍 = 極短的帶通爆音#

飛機抖機翼時,疊一層 30ms 的噪聲 burst,bandpass 中心 1.8kHz、Q 3, Attack 2ms、decay 28ms。單聽像開關聲,疊在風上面、每 0.6–1.4 秒隨機 trigger 一次,聽起來就是紙在撲稜。訣竅是每次的 Q 和中心頻隨機 ±15%——完全相同的爆音重複四次,腦子就從「聽素材」切換到「聽重複」。

城市不是靜音,是 60Hz#

黃昏天臺的底噪是一個 60Hz 正弦疊 90Hz、音量壓到 -32dB,加一層低通 120Hz 的粉噪。單獨聽完全不存在,一旦被抽掉(進室內鏡頭、或收尾),耳朵立刻知道「場景變了」。底噪的價值就在這裡:它不表達什麼,它定義「其他一切發生在哪裡」。

收尾 whoosh + shimmer#

降落前 1.5 秒,把風切帶通反過來掃回 200Hz,同時疊一個低通 400Hz 的 noise swell(0.8 秒淡入)——這是 whoosh。著地瞬間切掉所有低频,留一個 highshelf +6dB 的高頻閃爍(shimmer),0.4 秒衰減。心理聲學的順序是:低频撤退=空間打開,高頻閃爍=光進來。和畫面轉場對齊,聽者會覺得是「聲音把畫面帶過去的」。

預設靜音不是妥協,是設計#

自動播放政策下,音訊本來就要使用者手勢才能啟動。把靜音鍵做成 UI 的一等公民(右上 SKIP 旁邊),第一次點擊解鎖 AudioContext——這反而過濾掉了不想被打擾的人,願意開聲音的人預設期待是「這裡有聲音設計」,同一套音效在兩種期待下評分差一截。

visibilitychange 時 suspend context,回到頁面再 resume。讓風在背景標籤頁吹十分鐘,是對電池的挑釁。

全部程式碼大約一百二十行,零資產,總流量 0 byte。音檔是上一個時代的格式——不是說它不好,是說噪聲加濾波已經夠好,而且不要錢。