You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python从音频计算谐波序列以求解Brightness(亮度)?

基于MIDI-DDSP定义的音频Brightness计算实现方案

步骤1:加载音频

先用librosa加载目标音频,获取波形数据y和采样率sr:

import librosa
import numpy as np

# 替换为你的音频文件路径
y, sr = librosa.load("audio.wav", sr=None)

步骤2:估计基频与提取谐波序列

MIDI-DDSP中的谐波分布基于音频的基频(f0),先估计每帧的基频,再提取对应谐波的幅值:

2.1 估计基频f0

用librosa的PYIN算法(适用于浊音基频估计):

# 配置基频范围(可根据音频类型调整,这里是C2到C7)
f0, voiced_flag, _ = librosa.pyin(
    y, 
    fmin=librosa.note_to_hz('C2'), 
    fmax=librosa.note_to_hz('C7'),
    frame_length=2048,  # 帧长
    hop_length=512      # 帧移,控制时间分辨率
)

2.2 提取谐波分布h(k,i)

先计算音频的STFT幅值谱,再为每个浊音帧提取60次谐波的幅值(对应MIDI-DDSP中|h|=60):

n_fft = 2048
# 计算STFT幅值谱与频率轴
D = librosa.stft(y, n_fft=n_fft, hop_length=512)
mag_spectrum = np.abs(D)
freq_axis = librosa.fft_frequencies(sr=sr, n_fft=n_fft)

n_harmonics = 60
# 初始化谐波分布矩阵(行数:谐波次数,列数:帧数)
harmonic_dist = np.zeros((n_harmonics, len(f0)))

for frame_idx in range(len(f0)):
    if not voiced_flag[frame_idx]:
        continue  # 非浊音帧谐波幅值设为0
    current_f0 = f0[frame_idx]
    # 生成1~60次谐波的频率
    harmonic_freqs = current_f0 * np.arange(1, n_harmonics + 1)
    # 找到每个谐波频率对应的最接近的频谱bin索引
    bin_indices = np.argmin(np.abs(freq_axis[:, np.newaxis] - harmonic_freqs), axis=0)
    # 提取对应幅值作为h(k,i)
    harmonic_dist[:, frame_idx] = mag_spectrum[bin_indices, frame_idx]

步骤3:计算Brightness(亮度)

根据MIDI-DDSP的定义,Brightness是谐波分布的频谱质心(以bin数为单位),公式为:

Brightness(i) = (Σ(k * h_k(i))) / (Σ(h_k(i)))
其中k∈[1,60],i为时间帧索引

代码实现:

brightness = np.zeros(len(f0))

for frame_idx in range(len(f0)):
    mags = harmonic_dist[:, frame_idx]
    total_mag = np.sum(mags)
    if total_mag == 0:
        brightness[frame_idx] = 0.0  # 非浊音帧亮度设为0
        continue
    # 计算加权和:谐波次数(1~60)乘以对应幅值
    weighted_sum = np.sum(np.arange(1, n_harmonics + 1) * mags)
    brightness[frame_idx] = weighted_sum / total_mag

关于求和方式的说明

你提到的(100*1 + 200*2 + 400*4...)本质就是上述公式中的分子部分——各谐波幅值乘以对应谐波次数的加权求和。除以总幅值后得到的归一化值,就是MIDI-DDSP定义的Brightness,它能反映谐波能量在高频段的分布比例,值越大表示音频越明亮。

注意事项

  • 基频估计的准确性直接影响谐波序列的提取,若PYIN效果不佳,可尝试调整frame_length或改用librosa.piptrack。
  • 若谐波频率超过采样率的一半(Nyquist频率),对应幅值会自动为0,无需额外处理。
  • 帧长和帧移的选择需平衡时间与频率分辨率,音乐类音频可尝试hop_length=256。

内容的提问来源于stack exchange,提问作者Megan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 19:27:34