Python对比MIDI文件:如何获取原始与生成文件的相似度百分比
Python对比MIDI文件相似度:没有现成函数,但可自定义实现
不存在直接返回MIDI文件相似度百分比的开箱即用Python函数——因为“MIDI相似度”没有统一标准:你可能关注旋律匹配、节奏一致性、音符重叠度,甚至轨道结构或音色,不同需求的计算逻辑差异极大。不过借助专业MIDI处理库,你可以根据场景自定义相似度计算逻辑。
常用MIDI处理库
pretty_midi:解析MIDI的音符、节拍、乐器信息,适合基础数据提取music21:侧重音乐理论分析,支持旋律、和声的深度处理midiutil:轻量级MIDI读写工具,适合简单场景
实现思路与示例
1. 基础音符重叠度(简单版)
统计两个文件中相同音高+时间范围的音符占比,适合快速验证音符重合度:
先安装依赖:
pip install pretty_midi
代码实现:
import pretty_midi def extract_notes(midi_path): # 提取非鼓组的音符数据(音高、起始/结束时间) midi_data = pretty_midi.PrettyMIDI(midi_path) notes = [] for instr in midi_data.instruments: if not instr.is_drum: for note in instr.notes: # 时间保留两位小数避免精度误差 notes.append((note.pitch, round(note.start, 2), round(note.end, 2))) return notes def calc_note_similarity(original_notes, generated_notes): original_set = set(original_notes) generated_set = set(generated_notes) common_notes = len(original_set & generated_set) avg_total = (len(original_set) + len(generated_set)) / 2 return (common_notes / avg_total) * 100 if avg_total > 0 else 0 # 调用示例 original_notes = extract_notes("original.mid") generated_notes = extract_notes("generated.mid") similarity = calc_note_similarity(original_notes, generated_notes) print(f"音符重叠相似度:{similarity:.2f}%")
2. 旋律序列相似度(精准版)
提取旋律的音高序列,用编辑距离(Levenshtein Distance)计算序列匹配度,适合关注旋律走向的场景:
安装依赖:
pip install music21 python-Levenshtein
代码实现:
from music21 import converter import Levenshtein def extract_melody_pitches(midi_path): # 提取第一个轨道的音高序列(假设为主旋律轨道) midi_stream = converter.parse(midi_path) melody_part = midi_stream.parts[0] pitches = [] for elem in melody_part.flat.notes: if hasattr(elem, 'pitch'): pitches.append(str(elem.pitch)) # 用音高字符串(如C4)比数字更直观 return pitches def calc_melody_similarity(original_seq, generated_seq): max_len = max(len(original_seq), len(generated_seq)) if max_len == 0: return 100.0 edit_distance = Levenshtein.distance(original_seq, generated_seq) return (1 - edit_distance / max_len) * 100 # 调用示例 original_melody = extract_melody_pitches("original.mid") generated_melody = extract_melody_pitches("generated.mid") melody_similarity = calc_melody_similarity(original_melody, generated_melody) print(f"旋律相似度:{melody_similarity:.2f}%")
3. 节奏相似度(进阶版)
如果关注节拍和音符间隔,可以提取每个音符的时间间隔序列,再用统计方法(如余弦相似度)对比分布:
import numpy as np from scipy.spatial.distance import cosine def extract_rhythm_intervals(notes): # 提取音符的时间间隔序列(相邻音符的起始时间差) if len(notes) < 2: return [] intervals = [] prev_start = notes[0][1] for _, start, _ in notes[1:]: intervals.append(start - prev_start) prev_start = start return np.array(intervals) def calc_rhythm_similarity(original_intervals, generated_intervals): # 用余弦相似度计算节奏匹配度 if len(original_intervals) == 0 or len(generated_intervals) == 0: return 0.0 # 统一序列长度(截断或补0) min_len = min(len(original_intervals), len(generated_intervals)) orig_trim = original_intervals[:min_len] gen_trim = generated_intervals[:min_len] # 余弦相似度转百分比 similarity = 1 - cosine(orig_trim, gen_trim) return similarity * 100
总结
没有通用的“MIDI相似度百分比”函数,但通过上述库和逻辑,你可以针对自己的核心需求(旋律/节奏/音符)定制计算规则。不同的计算方式得到的百分比会有差异,建议根据生成MIDI的目标场景调整逻辑。
内容的提问来源于stack exchange,提问作者Cliffhanger
相关产品推荐
相关产品推荐

