把 68 張現場專輯的掌聲段落標出來:我用音訊能量曲線找段落邊界

这篇内容暂时只有 繁體中文 版本,以下是原文。

手上有 68 張現場專輯,多數是 2014 到 2022 年間的 bootleg,格式從 16/44.1 FLAC 到 24/48 都有,總大小約 41 GB。我想做的不是剪掉掌聲,而是把每首歌「前奏進來前」和「尾奏結束後」的觀眾聲標成可跳過的區段,這樣在手機上聽時可以一鍵跳到下一首,不用每次手動拖。

先說做法。我用 ffmpeg 先把每首轉成 8 kHz 單聲道 wav,只為了算能量,不碰原始檔:

ffmpeg -i input.flac -ac 1 -ar 8000 -f wav tmp.wav

再用 Python 讀波形,切成 100 ms 的窗,算 RMS,然後把整首的 RMS 做一次滑動中位數平滑(窗寬 5),避免單一鼓點造成誤判。接著我用一個很笨的規則:從頭往後找第一個「連續 1.5 秒 RMS 高於全曲中位數 1.8 倍」的位置,當作音樂起點;從尾往前找同樣條件,當作音樂終點。中間的區段就是我要標的。

import numpy as np, soundfile as sf
x, sr = sf.read('tmp.wav')
win = int(sr * 0.1)
rms = np.array([np.sqrt(np.mean(x[i:i+win]**2)) for i in range(0, len(x)-win, win)])
sm = np.convolve(rms, np.ones(5)/5, mode='same')
thr = np.median(sm) * 1.8

為什麼這樣做:現場錄音的觀眾聲通常是寬頻、低能量、沒有明顯節奏的底噪,而樂器進來時 RMS 會突然抬升。用中位數當基準比用平均值穩,因為平均值會被副歌拉高,導致安靜的段落被誤判成觀眾聲。代價是這個方法對「安靜的開場」很敏感,例如鋼琴獨奏的前幾秒可能被當成觀眾聲。我自己就踩過:一張 2017 年的爵士現場,第一首是鋼琴獨奏進場,結果前 12 秒被標成可跳過,播的時候直接從第 13 秒開始,聽起來像被切掉。

失效邊界很明確:一是觀眾合唱很大聲的段落,會被誤判成音樂;二是樂器持續低音鋪底的曲子,整首 RMS 都很平,閾值抓不到邊界;三是掌聲中夾雜喊叫聲時,RMS 會抖動,平滑窗太小就失效。我後來把平滑窗從 5 加到 9,並且對「音樂起點」額外要求前後 3 秒內不能再次掉回閾值以下,才比較穩。

目前 68 張裡有 9 張需要手動修,多數是安靜開場或全場合唱。剩下的我還沒把握,想問:你們遇到觀眾合唱蓋過樂器的現場,是直接放棄自動標,還是有別的特徵(例如頻譜平坦度)可以區分人聲和樂器?

0
赞同度 100% · 0 条评论 · 3 阅读

0 条评论

支持 Markdown · 回复会实时推送给对方

还没有评论,写下第一条。