如何用music21实现和弦的平滑声部连接(最小化声部距离)
基于music21实现和弦声部平滑连接的解决方案
要实现和弦间声部路径最短的转位优化,核心思路是为每个和弦生成所有合理的转位+八度移位变体,计算每个变体与前序和弦的声部距离总和,选择距离最小的变体作为最终使用的和弦。
具体实现步骤
- 先生成初始的原位和弦流,保留每个和弦的罗马数字标识与调式信息,用于后续生成变体
- 定义声部距离计算函数:将两个和弦的音按MIDI编号排序,对齐声部后计算对应音高差值的绝对值之和,总和越小代表声部移动越平滑
- 为每个和弦生成所有合理变体:包含原位、第一转位、第二转位,以及每个转位上下1-2个八度的移位版本(控制声部在合理音域内)
- 遍历和弦序列,从第一个和弦开始,为每个后续和弦筛选出与前一个选定和弦距离最小的变体,构建最终的平滑和弦流
完整代码示例
from music21 import stream, roman, key, chord def calculate_voice_distance(chord1, chord2): # 将两个和弦的音按MIDI编号排序,对齐声部计算距离总和 notes1 = sorted(n.midi for n in chord1.pitches) notes2 = sorted(n.midi for n in chord2.pitches) return sum(abs(n1 - n2) for n1, n2 in zip(notes1, notes2)) def generate_chord_variants(roman_numeral, target_key): # 生成当前罗马数字和弦的所有合理转位与八度移位变体 variants = [] # 遍历所有转位(0=原位,1=第一转位,2=第二转位) for inversion in [0, 1, 2]: base_chord = roman.RomanNumeral(roman_numeral, target_key).transpose(0) inverted_chord = base_chord.invert(inversion) # 生成上下1-2个八度的移位版本,控制音域在MIDI 40-80之间 for octave_shift in [-12, 0, 12]: shifted_chord = inverted_chord.transpose(octave_shift) # 检查和弦最低音和最高音是否在合理范围 min_midi = min(n.midi for n in shifted_chord.pitches) max_midi = max(n.midi for n in shifted_chord.pitches) if 40 <= min_midi and max_midi <= 80: variants.append(shifted_chord) return variants # 初始罗马数字序列 numeral_list = ['i', 'vi', 'I', '#iii', '#iii', 'V', 'i', 'vii', 'I', 'I', 'vi', 'vii'] target_key = key.Key('C') # 初始化最终流,第一个和弦用原位 final_stream = stream.Stream() prev_chord = roman.RomanNumeral(numeral_list[0], target_key) final_stream.append(prev_chord) # 遍历后续和弦,选择最优变体 for numeral in numeral_list[1:]: variants = generate_chord_variants(numeral, target_key) # 计算每个变体与前一个和弦的距离,选最小的 min_distance = float('inf') best_variant = None for variant in variants: distance = calculate_voice_distance(prev_chord, variant) if distance < min_distance: min_distance = distance best_variant = variant # 将最优变体加入流,并更新前一个和弦 final_stream.append(best_variant) prev_chord = best_variant # 展示结果 final_stream.show()
代码说明
calculate_voice_distance函数:通过对齐两个和弦的声部排序,确保声部对应关系合理,计算移动距离总和generate_chord_variants函数:生成所有可能的转位和八度移位,同时过滤掉音域不合理的和弦,避免声部过高或过低- 主逻辑:从第一个原位和弦开始,逐个为后续和弦筛选出移动距离最小的变体,实现平滑的声部连接
内容的提问来源于stack exchange,提问作者Jorvdp
相关产品推荐
相关产品推荐

