AI 辅助和弦进行推荐让非专业用户也能快速构建和声一、懂和弦的写不出旋律会写旋律的不懂和弦这是独立音乐制作人最常见的困境。和弦进行Chord Progression是音乐的情绪骨架——同样的旋律搭不同的和弦快乐能变悲伤。但非专业用户面对 7 个基本和弦×12 个调性的组合空间往往无从下手。市面上大部分和弦推荐工具只是一个和弦库查询器给出一个列表让用户自己试这不是推荐是扔了一本和弦字典。真正的 AI 和弦推荐应该做到用户输入一段旋律MIDI 或哼唱系统自动分析旋律中的音符分布和节拍重音推荐合理的和弦进行并给出至少 3 种风格化的变体爵士、流行、古典。我们的方案基于和弦功能理论 Transformer 模型做上下文感知推荐。二、从旋律到和弦的推理链路graph TD A[输入: MIDI 旋律] -- B[音符分析br/- 音高分布br/- 节拍重音br/- 乐句分段] B -- C[调性检测br/Krumhansl-Schmucklerbr/调性分析算法] C -- D[和弦候选生成br/- 按调性筛选br/- 按功能分类br/(T/S/D)] D -- E[Transformer 推荐br/- 上下文和弦关系建模br/- 风格向量注入] E -- F[候选排序br/- 声部进行平滑度br/- 风格匹配度br/- 多样性评分] F -- G[输出: 风格化变体br/- 爵士: 7/9/13 和弦br/- 流行: 三和弦为主br/- 古典: 严格声部进行] style A fill:#4A90D9,color:#fff style C fill:#F5A623,color:#000 style E fill:#50B86C,color:#fff style G fill:#FF6B6B,color:#fff关键设计调性检测前置在推荐和弦前先确定旋律的调性。Krumhansl-Schmuckler 算法的基本思路是将旋律中出现的音高频率分布与 24 个12 大调 12 小调标准调性模板做相关性计算相关性最高的即为旋律的调性。和弦功能约束和弦进行不是随机排列。功能和声理论中和弦分 T主功能、稳定、S下属功能、推进、D属功能、紧张→需解决经典的 I-IV-V-I 进行就是 T-S-D-T。在生成候选时用功能约束过滤掉不合理的和弦序列如两个属和弦连续出现。风格向量注入在 Transformer 的输入层将风格标签jazz/pop/classical作为额外的 Embedding 向量与和弦 Token 的 Embedding 相加让模型学会在不同风格下生成不同的和弦排列。三、生产级和弦推荐系统实现调性检测模块import numpy as np from typing import List, Tuple from dataclasses import dataclass dataclass class KeyDetectionResult: key: str # C | Am | F# ... mode: str # major | minor confidence: float # 0-1 class KeyDetector: 基于 Krumhansl-Schmuckler 算法的调性检测 # 12 个大调的标准音高分布模板 # 数值来自 Krumhansl Kessler (1982) 的心理学实验 # 受试者听一个调性上下文后对 12 个音做出适配度评分 MAJOR_PROFILE np.array([ 6.35, 2.23, 3.48, 2.33, 4.38, 4.09, 2.52, 5.19, 2.39, 3.66, 2.29, 2.88 ]) # 小调模板用相对大调的平移 MINOR_PROFILE np.array([ 6.33, 2.68, 3.52, 5.38, 2.60, 3.53, 2.54, 4.75, 3.98, 2.69, 3.34, 3.17 ]) NOTE_NAMES [C, C#, D, D#, E, F, F#, G, G#, A, A#, B] def detect(self, midi_pitch_counts: List[int]) - KeyDetectionResult: 输入12 维向量每个位置是该音高的出现次数 输出最可能的调性、调式和置信度 histogram np.array(midi_pitch_counts, dtypefloat) # 避免除零加 1 平滑 histogram histogram 1 # 归一化各音高比例而非绝对次数 histogram histogram / histogram.sum() best_corr -1 best_key_idx 0 best_mode major # 遍历 24 个调性12 个大调 12 个小调 for key_idx in range(12): # 将模板旋转到当前调性 # 如 C 大调的模板是 [C, C#, D, ...]D 大调是 [D, D#, E, ...] major_rotated np.roll(self.MAJOR_PROFILE, key_idx) minor_rotated np.roll(self.MINOR_PROFILE, key_idx) # Pearson 相关系数衡量匹配度 # 使用相关性而非欧氏距离绝对数值大小不重要 # 重要的是哪些音该多的分布形状 major_corr np.corrcoef(histogram, major_rotated)[0, 1] minor_corr np.corrcoef(histogram, minor_rotated)[0, 1] if major_corr best_corr: best_corr major_corr best_key_idx key_idx best_mode major if minor_corr best_corr: best_corr minor_corr best_key_idx key_idx best_mode minor return KeyDetectionResult( keyself.NOTE_NAMES[best_key_idx], modebest_mode, confidencefloat(best_corr), )和弦功能分类与候选生成from enum import Enum class ChordFunction(Enum): TONIC T # 主功能稳定、起点/终点 SUBDOMINANT S # 下属功能推进、发展 DOMINANT D # 属功能紧张、需要解决到主 # 大调中的和弦功能映射 # 为什么只有 T/S/D 三个分类 # 和声功能理论的精髓是将 7 个自然和弦归为三类 # 同类和弦可以互相替换如 vi 可以替代 I 作主功能 MAJOR_FUNCTION_MAP { I: ChordFunction.TONIC, iii: ChordFunction.TONIC, vi: ChordFunction.TONIC, IV: ChordFunction.SUBDOMINANT, ii: ChordFunction.SUBDOMINANT, V: ChordFunction.DOMINANT, vii°: ChordFunction.DOMINANT, } # 功能进行规则允许的功能转换 # T→S→D→T 是经典进行模式 ALLOWED_PROGRESSIONS { # (当前功能, 下一个): 权重越高越推荐 (ChordFunction.TONIC, ChordFunction.SUBDOMINANT): 0.9, (ChordFunction.TONIC, ChordFunction.DOMINANT): 0.8, (ChordFunction.TONIC, ChordFunction.TONIC): 0.4, # 不推荐连续主功能 (ChordFunction.SUBDOMINANT, ChordFunction.DOMINANT): 0.9, (ChordFunction.SUBDOMINANT, ChordFunction.TONIC): 0.7, (ChordFunction.SUBDOMINANT, ChordFunction.SUBDOMINANT): 0.3, # 不推荐连续下属 (ChordFunction.DOMINANT, ChordFunction.TONIC): 1.0, # 强烈推荐 D→T 解决 (ChordFunction.DOMINANT, ChordFunction.SUBDOMINANT): 0.5, (ChordFunction.DOMINANT, ChordFunction.DOMINANT): 0.1, # 不推荐连续属 } class ChordProgressionGenerator: 基于功能约束生成候选和弦进行 def __init__(self, key_detector: KeyDetector, model_path: str): self.key_detector key_detector # 加载微调过的 Transformer 模型 self.model self._load_model(model_path) def generate( self, melody_midi: List[Tuple[int, float, float]], # (pitch, start_time, duration) style: str pop, # pop | jazz | classical num_variants: int 3, ) - List[dict]: 生成和弦推荐 返回 num_variants 个风格化变体每个包含 - chords: [(chord_name, start_bar), ...] - style: 风格标签 - score: 推荐度评分 # Step 1: 统计旋律音高分布 pitch_counts self._count_pitch_occurrences(melody_midi) # Step 2: 调性检测 key_result self.key_detector.detect(pitch_counts) if key_result.confidence 0.3: raise ValueError(无法确定旋律调性音高信息不足) # Step 3: 按乐句分段每段分配和弦 phrases self._segment_phrases(melody_midi) bar_chords self._assign_chords_to_phrases( phrases, key_result, style, num_variants ) return bar_chords def _count_pitch_occurrences(self, melody): 统计 12 个音高类别的出现频次 counts [0] * 12 for pitch, _, duration in melody: pitch_class pitch % 12 # 用时长加权长音符比短音符更能体现调性 counts[pitch_class] duration return counts def _segment_phrases(self, melody, min_bars4): 按休止符和长音切分乐句 # 简化的乐句分段逻辑 pass def _assign_chords_to_phrases(self, phrases, key, style, variants): 使用 Transformer 模型为每段乐句匹配和弦 pass def _load_model(self, path): pass四、AI 和弦推荐的边界缺点调性检测在转调段落失效Krumhansl-Schmuckler 算法假设旋律调性不变。如果旋律中途转调需要滑动窗口分段检测但转调点的和弦推荐置信度会显著下降。风格化依赖训练数据爵士风格的和弦排列规律如 ii-V-I 进行、三全音替代远比流行复杂模型训练数据中爵士的比例往往不够。好听的主观性和弦推荐的目标函数声部平滑度、功能正确性与用户主观感受可能不一致。需要 AB 测试量表化反馈。禁用场景无调性/实验音乐功能理论和声在此完全不适用。旋律太短 4 小节统计信息不足调性检测不可靠。五、总结AI 辅助和弦推荐的核心链路调性检测→和弦功能约束→Transformer 风格化推荐。Krumhansl-Schmuckler 算法通过相关性计算确定调性功能分类T/S/D约束生成空间Transformer 在约束空间内做上下文感知的排列生成。生产落地时调性检测的置信度阈值和风格化训练数据的质量和覆盖面是决定推荐质量的两个关键变量。