把写歌用的鼓组采样按音色归堆,我用一个笨脚本干完了

我的动机库里有 1200 多个鼓组采样,来自几个不同时期下载的免费包和几套买的。文件名基本没有规律,有的写 kick_01.wav,有的写 001.wav,还有一堆带空格和中文的。想找“一个偏闷的底鼓”时只能一个个点开听,这件事拖了快两年。

上个月我写了个脚本,不再试图理解文件名,改成按声音本身归堆。环境是 macOS,Python 3.11,依赖 librosa 和 soundfile,跑 1200 个文件大概六七分钟。核心就三步:读音频、算特征、聚类。

import librosa, numpy as np, soundfile as sf
from sklearn.cluster import KMeans

def feat(p):
    y, sr = librosa.load(p, sr=22050, mono=True)
    y = y[:sr]  # 只取前 1 秒
    cent = librosa.feature.spectral_centroid(y=y, sr=sr).mean()
    roll = librosa.feature.spectral_rolloff(y=y, sr=sr, roll_percent=0.85).mean()
    zcr = librosa.feature.zero_crossing_rate(y).mean()
    dur = librosa.get_duration(y=y, sr=sr)
    return [cent, roll, zcr, dur]

X = np.array([feat(p) for p in paths])
X = (X - X.mean(0)) / X.std(0)
label = KMeans(n_clusters=12, n_init=10).fit_predict(X)

然后按 label 建子文件夹,把文件复制进去。我发现的第一个问题是 dur 这一维把底鼓和军鼓分开了,但把镲片和长音效混在一起,因为 1 秒截断让长音效的时长全一样。砍掉 dur 之后,聚类结果贴合“音色”本身,代价是军鼓和短音效会串。

为什么用谱质心加滚降:这两个数字大致就是“亮度”,底鼓偏暗、镲片偏亮,比 MFCC 直观,出了问题我能看懂。代价是它分不出“同一个鼓不同力度”和“两个不同的鼓”,因为力度主要影响能量,不影响亮度。我接受这个代价,因为我要的是找东西快,不是做分类器。

哪里会失效:静音几乎的空文件会算出离谱的质心,得先过滤掉 RMS 低于阈值的;48kHz 和 44.1kHz 混着放没问题,但别把立体声和单声道混在一起算 zcr,我第一版就栽在这,同一组底鼓被劈成两堆。还有一点点:KMeans 的簇数是我手调的,12 这个数字只是对我这批文件合适,换一批包就得重新试。

现在我的流程是:要底鼓就去标着“暗”的那几个文件夹里翻,翻不到再全库搜。它没让我变得更有创造力,只是把找声音的时间从二十分钟压到两分钟。

你们归堆采样时是按文件名、按来源包,还是也按声音特征?有没有人试过用手动打标签配合这个,我觉得纯自动的簇名还是太抽象。

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

0 条评论

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

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