|
|
FishC 分析乐音方案
要实现从钢琴曲录音提取乐谱,可以使用 Python 的 librosa、crepe 和 pydub 等库。基本流程如下:
- 读取音频文件,转换为单声道(mono)。
- 进行短时傅里叶变换(STFT),得到频谱图。
- 使用常数Q变换(CQT)或简单音高估计算法(如自相关、YIN算法)提取每个时间帧的音高。
- 对音高序列进行平滑、去除倍频错误。
- 检测音符 onset(起始点),通过能量变化或频谱差异分割音符。
- 将每个音符的音高映射到 MIDI 编号,时值量化(四分音符、八分音符等)。
- 生成 MIDI 文件或文本形式的简谱。
示例代码(核心部分)
- import librosa
- import numpy as np
- # 1. 读取音频
- y, sr = librosa.load('piano.wav', sr=44100, mono=True)
- # 2. 提取 onset 和音高
- onset_frames = librosa.onset.onset_detect(y=y, sr=sr)
- pitches, magnitudes = librosa.piptrack(y=y, sr=sr)
- # 3. 将上一步的 onset_frames 转化为时间
- onset_times = librosa.frames_to_time(onset_frames, sr=sr)
- # 4. 在每个 onset 区间内取平均音高
- notes = []
- for i in range(len(onset_times)-1):
- start, end = onset_times[i], onset_times[i+1]
- # 找到对应时间范围
- start_frame = librosa.time_to_frames(start, sr=sr)
- end_frame = librosa.time_to_frames(end, sr=sr)
- # 取该区间内 energy 最大的音高
- idx = np.argmax(np.mean(magnitudes[:, start_frame:end_frame], axis=1))
- freq = pitches[idx, (start_frame+end_frame)//2]
- midi = librosa.hz_to_midi(freq)
- duration = end - start
- notes.append((midi, duration))
- # 5. 输出简谱(简化:只显示音高和时值)
- for midi, dur in notes:
- note_name = librosa.midi_to_note(midi)
- print(f'音符: {note_name}, 时值: {dur:.2f}秒')
复制代码
注意事项
- 上述代码仅为教学演示,实际音乐中可能有和弦(多个同时音)、踏板延音、泛音干扰,需要更高级算法(如神经网络音高检测、和弦识别)。
- 推荐使用 basic-pitch(Google Magenta)或 pypianoroll 进行多音高提取。
- 时值量化需结合节拍追踪(librosa.beat.tempo)来假设节拍速度。
最终输出乐谱形式
- MIDI 文件:使用 mido 库写入,可以在 DAW 中打开。
- 文本乐谱:如 ABC notation、MusicXML(需专用库)。
- 简谱(数字谱):将 MIDI 编号映射为简谱数字和八度。
建议学习路线
1. 先掌握 librosa 基础操作(加载、STFT、onset detect)。
2. 深入学习音高估计(pitch tracking)。
3. 研究音乐理论(时值、节拍、调式)以优化量化算法。
4. 尝试使用现成的音符转写模型(如 Onsets and Frames 演示模型)。
有任何细节问题,可以继续追问,我会尽力帮你拆解。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 |
|