求可将音频文件转换为Hz数组的函数及简易音符检测方法
简便的音频基频提取与音符判断方法
不用绕mel频谱图,直接提取音频的基频(Hz值)就能判断是否为标准音符,给你两个实用方案:
方案1:用Librosa的PYIN基频检测(无需mel频谱图)
Librosa自带的pyin算法专门做基频提取,直接输出每个时间帧的Hz值,不用先做mel频谱图,抗噪性不错,适合大多数单音乐器或人声场景。
示例代码:
import librosa import numpy as np # 加载音频文件(采样率设为22050足够) y, sr = librosa.load("your_audio.wav", sr=22050) # 提取基频f0,返回每个时间点的Hz值 f0, voiced_flag, voiced_probs = librosa.pyin(y, fmin=librosa.note_to_hz('C2'), fmax=librosa.note_to_hz('C7')) # 过滤掉无声音帧,只保留有效基频值 valid_f0 = f0[~np.isnan(f0)] # 对比标准音符:允许±1Hz的误差 standard_notes = { 'C4': 261.63, 'D4': 293.66, 'E4': 329.63, 'F4': 349.23, 'G4': 392.00, 'A4': 440.00, 'B4': 493.88, 'C5': 523.25 } # 检查每个基频是否匹配标准音符 for freq in valid_f0: for note, std_freq in standard_notes.items(): if abs(freq - std_freq) < 1: print(f"检测到标准音符:{note},实际频率:{freq:.2f}Hz") break
方案2:用FFT直接计算频谱峰值(适合纯净单音)
如果你的音频是纯净的单音(比如无伴奏乐器),直接用快速傅里叶变换(FFT)找频谱峰值对应的频率,步骤更直接,仅依赖numpy和scipy。
示例代码:
import numpy as np from scipy.io import wavfile # 读取WAV格式音频 sr, audio = wavfile.read("your_audio.wav") # 转为单声道(如果是立体声) if len(audio.shape) > 1: audio = audio.mean(axis=1) # 归一化 audio = audio / np.max(np.abs(audio)) # 做FFT计算频谱 n = len(audio) freqs = np.fft.fftfreq(n, 1/sr) fft_vals = np.abs(np.fft.fft(audio)) # 只取正频率部分 positive_freq_idx = freqs >= 0 freqs_pos = freqs[positive_freq_idx] fft_vals_pos = fft_vals[positive_freq_idx] # 找到频谱峰值对应的频率 peak_freq = freqs_pos[np.argmax(fft_vals_pos)] # 对比标准音符 standard_a4 = 440.0 if abs(peak_freq - standard_a4) < 1: print(f"检测到标准音符A4,实际频率:{peak_freq:.2f}Hz") else: print(f"未检测到标准音符,实际频率:{peak_freq:.2f}Hz")
补充说明
- 多音叠加的音频(比如和弦)只能提取主音基频,要识别多个音符需要更复杂的频谱分解,但单音场景足够用。
- 标准音符频率可通过公式生成:
f(n) = 440 * 2^((n-49)/12),其中n是MIDI音符编号(A4对应n=69),方便生成完整的标准频率表。
内容的提问来源于stack exchange,提问作者Efrat Epstein
相关产品推荐
相关产品推荐

