mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-10-29 18:16:06 +08:00
chore: release v1.0.1
This commit is contained in:
@@ -7,7 +7,7 @@ metadata:
|
||||
lime_when_to_use: 用户希望把现有文稿转成播客内容,但不要求你直接写主持稿。
|
||||
lime_version: 1.1.0
|
||||
lime_execution_mode: prompt
|
||||
lime_surface: creator
|
||||
lime_surface: workbench
|
||||
lime_category: media
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ metadata:
|
||||
lime_when_to_use: 用户明确要求“封面图”时使用,不要被普通配图任务替代。
|
||||
lime_version: 1.1.0
|
||||
lime_execution_mode: prompt
|
||||
lime_surface: creator
|
||||
lime_surface: workbench
|
||||
lime_category: media
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ metadata:
|
||||
lime_when_to_use: 用户需要普通配图、插图或概念图时使用;封面需求优先交给 cover_generate。
|
||||
lime_version: 1.1.0
|
||||
lime_execution_mode: prompt
|
||||
lime_surface: creator
|
||||
lime_surface: workbench
|
||||
lime_category: media
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ metadata:
|
||||
lime_when_to_use: 用户需要为当前内容补充外部素材资源时使用。
|
||||
lime_version: 1.1.0
|
||||
lime_execution_mode: prompt
|
||||
lime_surface: creator
|
||||
lime_surface: workbench
|
||||
lime_category: media
|
||||
---
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ metadata:
|
||||
lime_version: 1.4.0
|
||||
lime_execution_mode: workflow
|
||||
lime_workflow_ref: references/workflow.json
|
||||
lime_surface: creator
|
||||
lime_surface: workbench
|
||||
lime_category: social
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ metadata:
|
||||
lime_when_to_use: 用户希望提升文本可读性、结构清晰度、发布观感时使用。
|
||||
lime_version: 1.1.0
|
||||
lime_execution_mode: prompt
|
||||
lime_surface: creator
|
||||
lime_surface: workbench
|
||||
lime_category: writing
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ metadata:
|
||||
lime_when_to_use: 用户要求生成视频,或将现有文稿改编为短视频。
|
||||
lime_version: 1.1.0
|
||||
lime_execution_mode: prompt
|
||||
lime_surface: creator
|
||||
lime_surface: workbench
|
||||
lime_category: media
|
||||
---
|
||||
|
||||
|
||||
@@ -1,251 +0,0 @@
|
||||
{
|
||||
"meta": {
|
||||
"version": "1.0",
|
||||
"description": "和弦进行数据库 - 覆盖多种音乐风格的和弦进行模式",
|
||||
"created_for": "Musicify Music Theory Skill"
|
||||
},
|
||||
|
||||
"basic_progressions": {
|
||||
"pop_progressions": [
|
||||
{
|
||||
"name": "流行四和弦",
|
||||
"pattern": "vi-IV-I-V",
|
||||
"chords": ["Am", "F", "C", "G"],
|
||||
"roman_numeral": ["vi", "IV", "I", "V"],
|
||||
"emotion": "感人、朗朗上口",
|
||||
"difficulty": 1,
|
||||
"usage": "最常用的流行歌曲进行,适合主歌和副歌",
|
||||
"examples": ["《Someone Like You》", "《Let It Be》"],
|
||||
"variations": [
|
||||
{"pattern": "vi-V-IV-I", "description": "更加流畅的解决"},
|
||||
{"pattern": "vi-IV-I-V-vi", "description": "添加循环"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "卡农进行",
|
||||
"pattern": "I-V-vi-IV",
|
||||
"chords": ["C", "G", "Am", "F"],
|
||||
"roman_numeral": ["I", "V", "vi", "IV"],
|
||||
"emotion": "优美、经典、温暖",
|
||||
"difficulty": 1,
|
||||
"usage": "经典抒情歌曲,主歌部分特别适用",
|
||||
"examples": ["《Canon in D》", "《Five Hundred Miles》"],
|
||||
"variations": [
|
||||
{"pattern": "I-V-vi-iii-IV", "description": "加入三级和弦增加色彩"},
|
||||
{"pattern": "I-V-vi-IV-V", "description": "强调属功能"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "循环进行",
|
||||
"pattern": "I-V-vi-iii-IV-I-IV-V",
|
||||
"chords": ["C", "G", "Am", "Em", "F", "C", "F", "G"],
|
||||
"roman_numeral": ["I", "V", "vi", "iii", "IV", "I", "IV", "V"],
|
||||
"emotion": "流动、持续、丰富",
|
||||
"difficulty": 2,
|
||||
"usage": "适合较长的歌曲段落,创造持续的动力",
|
||||
"examples": ["《Autumn Leaves》", "《Fly Me to the Moon》"]
|
||||
}
|
||||
],
|
||||
|
||||
"rock_progressions": [
|
||||
{
|
||||
"name": "力量三和弦",
|
||||
"pattern": "I-♭VII-IV",
|
||||
"chords": ["C", "Bb", "F"],
|
||||
"roman_numeral": ["I", "♭VII", "IV"],
|
||||
"emotion": "有力、激昂、叛逆",
|
||||
"difficulty": 2,
|
||||
"usage": "摇滚歌曲副歌,营造强烈的推动力",
|
||||
"examples": ["《Sweet Caroline》", "《Free Fallin'》"],
|
||||
"guitar_tips": "使用强力和弦(power chords),强调根音和五度音"
|
||||
},
|
||||
{
|
||||
"name": "蓝调进行",
|
||||
"pattern": "I-I-I-I-IV-IV-I-I-V-IV-I-I",
|
||||
"chords": ["C7", "C7", "C7", "C7", "F7", "F7", "C7", "C7", "G7", "F7", "C7", "C7"],
|
||||
"roman_numeral": ["I7", "I7", "I7", "I7", "IV7", "IV7", "I7", "I7", "V7", "IV7", "I7", "I7"],
|
||||
"emotion": "忧郁、深沉、表达性强",
|
||||
"difficulty": 2,
|
||||
"usage": "12小节蓝调,摇滚和布鲁斯的基础",
|
||||
"examples": ["《Johnny B. Goode》", "《Stormy Monday》"]
|
||||
}
|
||||
],
|
||||
|
||||
"jazz_progressions": [
|
||||
{
|
||||
"name": "ii-V-I 进行",
|
||||
"pattern": "ii7-V7-Imaj7",
|
||||
"chords": ["Dm7", "G7", "Cmaj7"],
|
||||
"roman_numeral": ["ii7", "V7", "Imaj7"],
|
||||
"emotion": "成熟、精致、和谐",
|
||||
"difficulty": 3,
|
||||
"usage": "爵士乐最基本的进行,用于歌曲的解决",
|
||||
"examples": ["《All The Things You Are》", "《Autumn Leaves》"],
|
||||
"extensions": [
|
||||
{"pattern": "ii7(b5)-V7alt-i7", "description": "小调ii-V-i"},
|
||||
{"pattern": "IImaj7-V7-Imaj7", "description": "大二级替代"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Circle of Fifths",
|
||||
"pattern": "I-vi-ii-V",
|
||||
"chords": ["Cmaj7", "Am7", "Dm7", "G7"],
|
||||
"roman_numeral": ["Imaj7", "vi7", "ii7", "V7"],
|
||||
"emotion": "流动、自然、渐进",
|
||||
"difficulty": 3,
|
||||
"usage": "爵士标准曲常用,创造平滑的和声运动",
|
||||
"examples": ["《I Got Rhythm》", "《All of Me》"]
|
||||
}
|
||||
],
|
||||
|
||||
"chinese_style": [
|
||||
{
|
||||
"name": "五声音阶进行",
|
||||
"pattern": "I-III-vi-IV",
|
||||
"chords": ["C", "E", "Am", "F"],
|
||||
"roman_numeral": ["I", "III", "vi", "IV"],
|
||||
"emotion": "古典、东方韵味、祥和",
|
||||
"difficulty": 2,
|
||||
"usage": "中国风歌曲,古风音乐",
|
||||
"examples": ["《青花瓷》", "《菊花台》"],
|
||||
"scales": ["C-D-E-G-A (宫商角徵羽)"],
|
||||
"instruments": ["古筝", "二胡", "笛子", "琵琶"]
|
||||
},
|
||||
{
|
||||
"name": "宫调式进行",
|
||||
"pattern": "I-V-vi-IV-ii-V-I",
|
||||
"chords": ["C", "G", "Am", "F", "Dm", "G", "C"],
|
||||
"roman_numeral": ["I", "V", "vi", "IV", "ii", "V", "I"],
|
||||
"emotion": "庄重、典雅、传统",
|
||||
"difficulty": 2,
|
||||
"usage": "古风歌曲的主歌部分,营造古典氛围",
|
||||
"traditional_harmony": "以宫音为主,强调五度圈运动"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"advanced_techniques": {
|
||||
"chord_substitutions": [
|
||||
{
|
||||
"name": "三全音替代",
|
||||
"original": "V7",
|
||||
"substitute": "♭II7",
|
||||
"example": {"original": "G7", "substitute": "D♭7"},
|
||||
"effect": "增加色彩和张力",
|
||||
"usage": "爵士乐中常用,特别在ii-V-I进行中"
|
||||
},
|
||||
{
|
||||
"name": "相对和弦替代",
|
||||
"original": "I",
|
||||
"substitute": "vi",
|
||||
"example": {"original": "C", "substitute": "Am"},
|
||||
"effect": "从大调转向小调色彩",
|
||||
"usage": "营造忧郁或内省的情绪"
|
||||
},
|
||||
{
|
||||
"name": "二级和弦",
|
||||
"technique": "目标和弦前加入其二级和弦",
|
||||
"example": "C-Dm-G7-C (在G7前加入Dm)",
|
||||
"effect": "增强和声运动感",
|
||||
"usage": "增加进行的丰富性"
|
||||
}
|
||||
],
|
||||
|
||||
"modal_progressions": [
|
||||
{
|
||||
"mode": "Dorian",
|
||||
"characteristic": "自然六度,♭七度",
|
||||
"progression": "i-IV-♭VII-i",
|
||||
"chords": ["Dm", "G", "C", "Dm"],
|
||||
"emotion": "神秘、中性、民族色彩",
|
||||
"examples": ["《Scarborough Fair》", "《Eleanor Rigby》"]
|
||||
},
|
||||
{
|
||||
"mode": "Mixolydian",
|
||||
"characteristic": "♭七度",
|
||||
"progression": "I-♭VII-IV-I",
|
||||
"chords": ["G", "F", "C", "G"],
|
||||
"emotion": "开朗中带有忧郁",
|
||||
"examples": ["《Sweet Caroline》", "《Norwegian Wood》"]
|
||||
},
|
||||
{
|
||||
"mode": "Aeolian (Natural Minor)",
|
||||
"characteristic": "♭三度,♭六度,♭七度",
|
||||
"progression": "i-♭VII-♭VI-♭VII",
|
||||
"chords": ["Am", "G", "F", "G"],
|
||||
"emotion": "忧郁、深沉、戏剧性",
|
||||
"examples": ["《House of the Rising Sun》", "《Stairway to Heaven》"]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"rhythm_patterns": {
|
||||
"basic_strumming": [
|
||||
{
|
||||
"name": "基础4/4拍型",
|
||||
"pattern": "D-D-U-U-D-U",
|
||||
"notation": "下-下-上-上-下-上",
|
||||
"tempo": "适中速度 (120 BPM)",
|
||||
"usage": "最基础的吉他扫弦模式",
|
||||
"songs": ["《Hotel California》", "《Wonderwall》"]
|
||||
},
|
||||
{
|
||||
"name": "民谣分解",
|
||||
"pattern": "1-3-2-3-1-3-2-3",
|
||||
"fingers": "拇指-食指-中指-食指",
|
||||
"usage": "指弹民谣,抒情歌曲",
|
||||
"songs": ["《Dust in the Wind》", "《Blackbird》"]
|
||||
}
|
||||
],
|
||||
|
||||
"advanced_patterns": [
|
||||
{
|
||||
"name": "放克节奏",
|
||||
"pattern": "重音在16分音符的切分位置",
|
||||
"characteristic": "强调反拍,使用切音技巧",
|
||||
"instruments": ["电吉他", "贝斯", "鼓"],
|
||||
"examples": ["《Superstition》", "《I Want Your Love》"]
|
||||
},
|
||||
{
|
||||
"name": "雷鬼节奏",
|
||||
"pattern": "强调2、4拍的后半拍",
|
||||
"characteristic": "轻松摇摆,强调上拍",
|
||||
"tempo": "中慢速度 (70-90 BPM)",
|
||||
"examples": ["《No Woman No Cry》", "《Three Little Birds》"]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"song_structure_templates": {
|
||||
"pop_structure": {
|
||||
"sections": ["Intro", "Verse 1", "Pre-Chorus", "Chorus", "Verse 2", "Pre-Chorus", "Chorus", "Bridge", "Chorus", "Outro"],
|
||||
"chord_suggestions": {
|
||||
"Verse": "较为平静的进行,如 vi-IV-I-V",
|
||||
"Pre-Chorus": "建立张力,如 ii-V 或 IV-V",
|
||||
"Chorus": "强有力的进行,如 I-V-vi-IV",
|
||||
"Bridge": "对比性进行,可尝试不同调性"
|
||||
}
|
||||
},
|
||||
|
||||
"ballad_structure": {
|
||||
"sections": ["Intro", "Verse 1", "Chorus", "Verse 2", "Chorus", "Bridge", "Chorus", "Outro"],
|
||||
"dynamic": "从安静开始,逐渐建立到高潮",
|
||||
"chord_suggestions": {
|
||||
"Verse": "简单温柔的进行",
|
||||
"Chorus": "情感饱满的和弦"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"key_relationships": {
|
||||
"circle_of_fifths": {
|
||||
"major_keys": ["C", "G", "D", "A", "E", "B", "F#", "Db", "Ab", "Eb", "Bb", "F"],
|
||||
"relative_minors": ["Am", "Em", "Bm", "F#m", "C#m", "G#m", "D#m", "Bbm", "Fm", "Cm", "Gm", "Dm"],
|
||||
"modulation_techniques": [
|
||||
"共同和弦转调",
|
||||
"属和弦转调",
|
||||
"半音阶下行转调"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,266 +0,0 @@
|
||||
{
|
||||
"meta": {
|
||||
"version": "1.0",
|
||||
"description": "国风旋律模式库 - 定义情绪映射、结构差异和常用旋律模式",
|
||||
"created_for": "Musicify 国风旋律生成 Skill"
|
||||
},
|
||||
|
||||
"emotions": {
|
||||
"sorrowful": {
|
||||
"name": "忧伤",
|
||||
"preferredMode": "yu",
|
||||
"contour": "descending",
|
||||
"intervalRange": 3,
|
||||
"tempo": "慢板 (60-72 BPM)",
|
||||
"characteristics": [
|
||||
"多用下行旋律线",
|
||||
"羽调式为主,偶用商调式",
|
||||
"音程以级进为主,偶有小跳",
|
||||
"多用滑音和颤音装饰",
|
||||
"句尾常落在羽音(6)或商音(2)"
|
||||
],
|
||||
"typicalPatterns": ["weeping", "sighing"]
|
||||
},
|
||||
"joyful": {
|
||||
"name": "欢快",
|
||||
"preferredMode": "gong",
|
||||
"contour": "ascending",
|
||||
"intervalRange": 5,
|
||||
"tempo": "快板 (120-140 BPM)",
|
||||
"characteristics": [
|
||||
"多用上行旋律线",
|
||||
"宫调式为主,偶用徵调式",
|
||||
"音程跳进较多,节奏活泼",
|
||||
"装饰音轻快,多用波音",
|
||||
"句尾常落在宫音(1)或徵音(5)"
|
||||
],
|
||||
"typicalPatterns": ["celebration", "dance"]
|
||||
},
|
||||
"peaceful": {
|
||||
"name": "平静",
|
||||
"preferredMode": "jue",
|
||||
"contour": "stable",
|
||||
"intervalRange": 2,
|
||||
"tempo": "中板 (80-96 BPM)",
|
||||
"characteristics": [
|
||||
"旋律走向平稳",
|
||||
"角调式为主,音色空灵",
|
||||
"以级进为主,避免大跳",
|
||||
"装饰音少而精",
|
||||
"音域范围较窄"
|
||||
],
|
||||
"typicalPatterns": ["flowing", "meditation"]
|
||||
},
|
||||
"passionate": {
|
||||
"name": "激昂",
|
||||
"preferredMode": "zhi",
|
||||
"contour": "wave",
|
||||
"intervalRange": 6,
|
||||
"tempo": "快板 (116-132 BPM)",
|
||||
"characteristics": [
|
||||
"旋律起伏大,波浪式进行",
|
||||
"徵调式为主,热情奔放",
|
||||
"音程跳进多,张力强",
|
||||
"高音区使用频繁",
|
||||
"句尾常有力度强调"
|
||||
],
|
||||
"typicalPatterns": ["heroic", "climax"]
|
||||
},
|
||||
"nostalgic": {
|
||||
"name": "思念",
|
||||
"preferredMode": "shang",
|
||||
"contour": "wave",
|
||||
"intervalRange": 4,
|
||||
"tempo": "慢板 (66-80 BPM)",
|
||||
"characteristics": [
|
||||
"旋律婉转起伏",
|
||||
"商调式为主,深沉内敛",
|
||||
"上行后下行,欲言又止",
|
||||
"多用滑音表达情感",
|
||||
"句尾常有延长音"
|
||||
],
|
||||
"typicalPatterns": ["longing", "sighing"]
|
||||
},
|
||||
"ethereal": {
|
||||
"name": "空灵",
|
||||
"preferredMode": "jue",
|
||||
"contour": "ascending",
|
||||
"intervalRange": 5,
|
||||
"tempo": "自由节拍",
|
||||
"characteristics": [
|
||||
"旋律飘逸,多用高音区",
|
||||
"角调式为主,清新脱俗",
|
||||
"音符稀疏,留白较多",
|
||||
"颤音装饰增加空灵感",
|
||||
"节奏自由,不拘一格"
|
||||
],
|
||||
"typicalPatterns": ["floating", "meditation"]
|
||||
}
|
||||
},
|
||||
|
||||
"structures": {
|
||||
"verse": {
|
||||
"name": "主歌",
|
||||
"range": 6,
|
||||
"contour": "stable",
|
||||
"characteristics": [
|
||||
"音域较窄,一般在六度以内",
|
||||
"旋律平稳,以叙述为主",
|
||||
"节奏规整,便于歌词表达",
|
||||
"情感内敛,为副歌做铺垫"
|
||||
],
|
||||
"typicalStartNotes": [5, 3, 1],
|
||||
"typicalEndNotes": [1, 5, 6]
|
||||
},
|
||||
"chorus": {
|
||||
"name": "副歌",
|
||||
"range": 10,
|
||||
"contour": "wave",
|
||||
"characteristics": [
|
||||
"音域扩展,可达十度",
|
||||
"旋律起伏大,情感爆发",
|
||||
"常有高潮点设计",
|
||||
"节奏可更自由或更强烈"
|
||||
],
|
||||
"typicalStartNotes": [1, 5, 6],
|
||||
"typicalEndNotes": [1, 5]
|
||||
},
|
||||
"bridge": {
|
||||
"name": "桥段",
|
||||
"range": 8,
|
||||
"contour": "ascending",
|
||||
"characteristics": [
|
||||
"音域介于主歌和副歌之间",
|
||||
"旋律上行为主,推向高潮",
|
||||
"可转调或变化调式",
|
||||
"为副歌再现做准备"
|
||||
],
|
||||
"typicalStartNotes": [6, 3, 2],
|
||||
"typicalEndNotes": [5, 1]
|
||||
}
|
||||
},
|
||||
|
||||
"patterns": {
|
||||
"weeping": {
|
||||
"name": "哭腔模式",
|
||||
"sequence": [6, 5, 3, 2, 1, 6],
|
||||
"contour": "descending",
|
||||
"usage": "表达悲伤、哀怨情绪",
|
||||
"examples": ["《青花瓷》副歌", "《烟花易冷》"],
|
||||
"ornaments": ["滑音", "颤音"]
|
||||
},
|
||||
"sighing": {
|
||||
"name": "叹息模式",
|
||||
"sequence": [5, 6, 5, 3, 2],
|
||||
"contour": "wave",
|
||||
"usage": "表达思念、无奈情绪",
|
||||
"examples": ["《千里之外》", "《菊花台》"],
|
||||
"ornaments": ["滑音"]
|
||||
},
|
||||
"celebration": {
|
||||
"name": "欢庆模式",
|
||||
"sequence": [1, 3, 5, 6, 5, 3, 1],
|
||||
"contour": "ascending",
|
||||
"usage": "表达喜悦、庆祝情绪",
|
||||
"examples": ["《好日子》", "《恭喜发财》"],
|
||||
"ornaments": ["波音"]
|
||||
},
|
||||
"dance": {
|
||||
"name": "舞曲模式",
|
||||
"sequence": [5, 1, 3, 5, 6, 5],
|
||||
"contour": "wave",
|
||||
"usage": "活泼的舞蹈节奏",
|
||||
"examples": ["《最炫民族风》"],
|
||||
"ornaments": ["波音", "倚音"]
|
||||
},
|
||||
"flowing": {
|
||||
"name": "流水模式",
|
||||
"sequence": [3, 2, 1, 2, 3, 5],
|
||||
"contour": "stable",
|
||||
"usage": "平静、流畅的叙述",
|
||||
"examples": ["《高山流水》", "《渔舟唱晚》"],
|
||||
"ornaments": ["滑音"]
|
||||
},
|
||||
"meditation": {
|
||||
"name": "禅意模式",
|
||||
"sequence": [5, 3, 5, 6, 5],
|
||||
"contour": "stable",
|
||||
"usage": "空灵、冥想的意境",
|
||||
"examples": ["《大悲咒》", "《心经》"],
|
||||
"ornaments": ["颤音"]
|
||||
},
|
||||
"heroic": {
|
||||
"name": "英雄模式",
|
||||
"sequence": [5, 1, 5, 6, 1, 5],
|
||||
"contour": "ascending",
|
||||
"usage": "激昂、豪迈的情绪",
|
||||
"examples": ["《精忠报国》", "《男儿当自强》"],
|
||||
"ornaments": ["倚音"]
|
||||
},
|
||||
"climax": {
|
||||
"name": "高潮模式",
|
||||
"sequence": [1, 3, 5, 6, 1, 6, 5],
|
||||
"contour": "wave",
|
||||
"usage": "歌曲高潮部分",
|
||||
"examples": ["副歌高潮段落"],
|
||||
"ornaments": ["颤音", "滑音"]
|
||||
},
|
||||
"longing": {
|
||||
"name": "思念模式",
|
||||
"sequence": [2, 3, 5, 3, 2, 1, 2],
|
||||
"contour": "wave",
|
||||
"usage": "表达思念、期盼情绪",
|
||||
"examples": ["《但愿人长久》", "《明月几时有》"],
|
||||
"ornaments": ["滑音", "颤音"]
|
||||
},
|
||||
"floating": {
|
||||
"name": "飘逸模式",
|
||||
"sequence": [3, 5, 6, 5, 3],
|
||||
"contour": "ascending",
|
||||
"usage": "空灵、超脱的意境",
|
||||
"examples": ["《沧海一声笑》"],
|
||||
"ornaments": ["颤音"]
|
||||
}
|
||||
},
|
||||
|
||||
"references": {
|
||||
"classicSongs": [
|
||||
{
|
||||
"name": "青花瓷",
|
||||
"mode": "yu",
|
||||
"emotion": "nostalgic",
|
||||
"features": "羽调式为主,旋律婉转,多用下行和滑音"
|
||||
},
|
||||
{
|
||||
"name": "菊花台",
|
||||
"mode": "yu",
|
||||
"emotion": "sorrowful",
|
||||
"features": "羽调式,忧伤婉转,句尾多用延长音"
|
||||
},
|
||||
{
|
||||
"name": "千里之外",
|
||||
"mode": "shang",
|
||||
"emotion": "nostalgic",
|
||||
"features": "商调式,深沉内敛,旋律起伏适中"
|
||||
},
|
||||
{
|
||||
"name": "沧海一声笑",
|
||||
"mode": "zhi",
|
||||
"emotion": "passionate",
|
||||
"features": "徵调式,豪迈奔放,音域宽广"
|
||||
},
|
||||
{
|
||||
"name": "高山流水",
|
||||
"mode": "gong",
|
||||
"emotion": "peaceful",
|
||||
"features": "宫调式,典雅庄重,旋律流畅"
|
||||
},
|
||||
{
|
||||
"name": "茉莉花",
|
||||
"mode": "gong",
|
||||
"emotion": "peaceful",
|
||||
"features": "宫调式,清新优美,级进为主"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,251 +0,0 @@
|
||||
{
|
||||
"meta": {
|
||||
"version": "1.0",
|
||||
"description": "MIDI 解析规则库 - 定义音符映射、时值解析、节奏型识别和调式推断规则",
|
||||
"created_for": "Musicify 旋律风格学习 Skill"
|
||||
},
|
||||
|
||||
"noteMapping": {
|
||||
"midiToName": {
|
||||
"36": "C2", "37": "C#2", "38": "D2", "39": "D#2", "40": "E2", "41": "F2",
|
||||
"42": "F#2", "43": "G2", "44": "G#2", "45": "A2", "46": "A#2", "47": "B2",
|
||||
"48": "C3", "49": "C#3", "50": "D3", "51": "D#3", "52": "E3", "53": "F3",
|
||||
"54": "F#3", "55": "G3", "56": "G#3", "57": "A3", "58": "A#3", "59": "B3",
|
||||
"60": "C4", "61": "C#4", "62": "D4", "63": "D#4", "64": "E4", "65": "F4",
|
||||
"66": "F#4", "67": "G4", "68": "G#4", "69": "A4", "70": "A#4", "71": "B4",
|
||||
"72": "C5", "73": "C#5", "74": "D5", "75": "D#5", "76": "E5", "77": "F5",
|
||||
"78": "F#5", "79": "G5", "80": "G#5", "81": "A5", "82": "A#5", "83": "B5",
|
||||
"84": "C6", "85": "C#6", "86": "D6", "87": "D#6", "88": "E6", "89": "F6",
|
||||
"90": "F#6", "91": "G6", "92": "G#6", "93": "A6", "94": "A#6", "95": "B6"
|
||||
},
|
||||
"midiToJianpu": {
|
||||
"description": "基于 C 大调的简谱映射,实际使用时需根据调号偏移",
|
||||
"baseKey": "C",
|
||||
"mapping": {
|
||||
"0": "1", "2": "2", "4": "3", "5": "4", "7": "5", "9": "6", "11": "7"
|
||||
},
|
||||
"octaveMarkers": {
|
||||
"-2": ",,", "-1": ",", "0": "", "1": "'", "2": "''"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"durationMapping": {
|
||||
"ticksPerBeat": 480,
|
||||
"durationNames": {
|
||||
"1920": { "name": "全音符", "symbol": "○", "beats": 4 },
|
||||
"1440": { "name": "附点二分音符", "symbol": "●.", "beats": 3 },
|
||||
"960": { "name": "二分音符", "symbol": "●", "beats": 2 },
|
||||
"720": { "name": "附点四分音符", "symbol": "♩.", "beats": 1.5 },
|
||||
"480": { "name": "四分音符", "symbol": "♩", "beats": 1 },
|
||||
"360": { "name": "附点八分音符", "symbol": "♪.", "beats": 0.75 },
|
||||
"240": { "name": "八分音符", "symbol": "♪", "beats": 0.5 },
|
||||
"180": { "name": "附点十六分音符", "symbol": "♬.", "beats": 0.375 },
|
||||
"120": { "name": "十六分音符", "symbol": "♬", "beats": 0.25 },
|
||||
"160": { "name": "三连音(四分)", "symbol": "♩³", "beats": 0.333 },
|
||||
"80": { "name": "三连音(八分)", "symbol": "♪³", "beats": 0.167 }
|
||||
},
|
||||
"tolerancePercent": 10
|
||||
},
|
||||
|
||||
"rhythmPatterns": {
|
||||
"quarter": {
|
||||
"name": "四分音符型",
|
||||
"durations": [480],
|
||||
"description": "稳定的四分音符节奏,常用于叙述性段落",
|
||||
"category": "basic"
|
||||
},
|
||||
"eighth": {
|
||||
"name": "八分音符型",
|
||||
"durations": [240, 240],
|
||||
"description": "连续八分音符,增加流动感",
|
||||
"category": "basic"
|
||||
},
|
||||
"dotted_quarter_eighth": {
|
||||
"name": "附点四分+八分",
|
||||
"durations": [720, 240],
|
||||
"description": "附点节奏,增加推动力",
|
||||
"category": "dotted"
|
||||
},
|
||||
"eighth_dotted_quarter": {
|
||||
"name": "八分+附点四分",
|
||||
"durations": [240, 720],
|
||||
"description": "切分感的附点节奏",
|
||||
"category": "dotted"
|
||||
},
|
||||
"syncopation_basic": {
|
||||
"name": "基本切分",
|
||||
"durations": [240, 480, 240],
|
||||
"description": "基本切分节奏,强拍弱化",
|
||||
"category": "syncopation"
|
||||
},
|
||||
"syncopation_offbeat": {
|
||||
"name": "后半拍切分",
|
||||
"durations": [240, 240, 480],
|
||||
"description": "后半拍强调的切分",
|
||||
"category": "syncopation"
|
||||
},
|
||||
"triplet_quarter": {
|
||||
"name": "四分三连音",
|
||||
"durations": [160, 160, 160],
|
||||
"description": "三连音节奏,增加流畅感",
|
||||
"category": "triplet"
|
||||
},
|
||||
"long_short": {
|
||||
"name": "长短型",
|
||||
"durations": [960, 480],
|
||||
"description": "二分+四分,舒缓的节奏",
|
||||
"category": "basic"
|
||||
},
|
||||
"sixteenth_group": {
|
||||
"name": "十六分音符组",
|
||||
"durations": [120, 120, 120, 120],
|
||||
"description": "快速的十六分音符,增加紧张感",
|
||||
"category": "fast"
|
||||
}
|
||||
},
|
||||
|
||||
"modeDetection": {
|
||||
"description": "基于五声音阶特征音检测调式",
|
||||
"pentatonic": {
|
||||
"gong": {
|
||||
"name": "宫调式",
|
||||
"characteristicDegrees": [0, 2, 4, 7, 9],
|
||||
"rootDegree": 0,
|
||||
"endingNotes": [0, 7],
|
||||
"weight": { "root": 3, "fifth": 2, "others": 1 }
|
||||
},
|
||||
"shang": {
|
||||
"name": "商调式",
|
||||
"characteristicDegrees": [0, 2, 4, 7, 9],
|
||||
"rootDegree": 2,
|
||||
"endingNotes": [2, 0],
|
||||
"weight": { "root": 3, "fifth": 2, "others": 1 }
|
||||
},
|
||||
"jue": {
|
||||
"name": "角调式",
|
||||
"characteristicDegrees": [0, 2, 4, 7, 9],
|
||||
"rootDegree": 4,
|
||||
"endingNotes": [4, 2],
|
||||
"weight": { "root": 3, "fifth": 2, "others": 1 }
|
||||
},
|
||||
"zhi": {
|
||||
"name": "徵调式",
|
||||
"characteristicDegrees": [0, 2, 4, 7, 9],
|
||||
"rootDegree": 7,
|
||||
"endingNotes": [7, 9],
|
||||
"weight": { "root": 3, "fifth": 2, "others": 1 }
|
||||
},
|
||||
"yu": {
|
||||
"name": "羽调式",
|
||||
"characteristicDegrees": [0, 2, 4, 7, 9],
|
||||
"rootDegree": 9,
|
||||
"endingNotes": [9, 7],
|
||||
"weight": { "root": 3, "fifth": 2, "others": 1 }
|
||||
}
|
||||
},
|
||||
"keySignatures": {
|
||||
"C": 0, "C#": 1, "Db": 1, "D": 2, "D#": 3, "Eb": 3,
|
||||
"E": 4, "F": 5, "F#": 6, "Gb": 6, "G": 7, "G#": 8,
|
||||
"Ab": 8, "A": 9, "A#": 10, "Bb": 10, "B": 11
|
||||
}
|
||||
},
|
||||
|
||||
"trackMatching": {
|
||||
"vocalRangeMin": 48,
|
||||
"vocalRangeMax": 84,
|
||||
"vocalRangeDescription": "人声音域范围 C3(48) 到 C6(84)",
|
||||
"vocalRangeZones": {
|
||||
"belowVocal": { "min": 0, "max": 47, "description": "低于人声范围,可能是贝斯" },
|
||||
"vocalLow": { "min": 48, "max": 59, "description": "C3-B3,男声常用区" },
|
||||
"vocalMid": { "min": 60, "max": 71, "description": "C4-B4,男女声共用区" },
|
||||
"vocalHigh": { "min": 72, "max": 84, "description": "C5-C6,女声常用区" },
|
||||
"aboveVocal": { "min": 85, "max": 127, "description": "高于人声范围,可能是装饰音" }
|
||||
},
|
||||
"tolerancePercent": 15,
|
||||
"minVocalRangeOverlap": 0.5,
|
||||
"priorityKeywords": ["vocal", "melody", "voice", "lead", "主旋律", "人声"],
|
||||
"matchingRules": [
|
||||
{
|
||||
"rule": "keyword_match",
|
||||
"description": "音轨名称包含人声关键词时优先选择",
|
||||
"priority": 1,
|
||||
"scoreBonus": 30
|
||||
},
|
||||
{
|
||||
"rule": "note_count_match",
|
||||
"description": "音符数量与歌词字数最接近的音轨",
|
||||
"priority": 2,
|
||||
"maxScore": 40,
|
||||
"toleranceLevels": {
|
||||
"exact": { "tolerance": 0, "score": 40 },
|
||||
"close": { "tolerance": 0.05, "score": 35 },
|
||||
"acceptable": { "tolerance": 0.15, "score": 28 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"rule": "pitch_range_filter",
|
||||
"description": "过滤音域超出人声范围的音轨",
|
||||
"priority": 3,
|
||||
"maxScore": 30,
|
||||
"overlapScoring": {
|
||||
"full": { "minOverlap": 1.0, "score": 30 },
|
||||
"high": { "minOverlap": 0.75, "score": 22 },
|
||||
"medium": { "minOverlap": 0.5, "score": 15 },
|
||||
"low": { "minOverlap": 0, "score": 0 }
|
||||
}
|
||||
}
|
||||
],
|
||||
"confidenceThresholds": {
|
||||
"high": 90,
|
||||
"medium": 70,
|
||||
"low": 50
|
||||
},
|
||||
"confidenceDescriptions": {
|
||||
"high": "自动选择,无需确认",
|
||||
"medium": "建议选择,请求确认",
|
||||
"low": "需要用户手动确认",
|
||||
"noMatch": "不推荐,列出供参考"
|
||||
},
|
||||
"conflictResolution": {
|
||||
"scoreDifferenceThreshold": 5,
|
||||
"priorityOrder": ["keyword_match", "note_count_match", "pitch_range_filter"]
|
||||
}
|
||||
},
|
||||
|
||||
"intervalClassification": {
|
||||
"stepwise": {
|
||||
"name": "级进",
|
||||
"semitones": [1, 2],
|
||||
"description": "相邻音级的进行,旋律流畅"
|
||||
},
|
||||
"smallLeap": {
|
||||
"name": "小跳",
|
||||
"semitones": [3, 4],
|
||||
"description": "三度或四度跳进,增加起伏"
|
||||
},
|
||||
"largeLeap": {
|
||||
"name": "大跳",
|
||||
"semitones": [5, 6, 7, 8, 9, 10, 11, 12],
|
||||
"description": "五度及以上跳进,戏剧性强"
|
||||
}
|
||||
},
|
||||
|
||||
"contourAnalysis": {
|
||||
"ascending": {
|
||||
"name": "上行",
|
||||
"condition": "后一音高于前一音",
|
||||
"emotion": "积极、上升、期待"
|
||||
},
|
||||
"descending": {
|
||||
"name": "下行",
|
||||
"condition": "后一音低于前一音",
|
||||
"emotion": "忧伤、下沉、释放"
|
||||
},
|
||||
"stable": {
|
||||
"name": "平稳",
|
||||
"condition": "音高变化在二度以内",
|
||||
"emotion": "平静、叙述、稳定"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
{
|
||||
"meta": {
|
||||
"version": "1.0",
|
||||
"description": "五声音阶规则库 - 定义中国传统五声音阶的调式结构、装饰音和音程规则",
|
||||
"created_for": "Musicify 国风旋律生成 Skill"
|
||||
},
|
||||
|
||||
"scales": {
|
||||
"gong": {
|
||||
"name": "宫调式",
|
||||
"notes": [1, 2, 3, 5, 6],
|
||||
"root": 1,
|
||||
"characteristic": "以宫音(1)为主音,音阶明亮开阔,具有庄重典雅的特点",
|
||||
"emotion": "庄重、明亮、欢快、积极向上",
|
||||
"typicalCadence": [5, 1],
|
||||
"avoidNotes": [4, 7]
|
||||
},
|
||||
"shang": {
|
||||
"name": "商调式",
|
||||
"notes": [1, 2, 3, 5, 6],
|
||||
"root": 2,
|
||||
"characteristic": "以商音(2)为主音,音阶略带忧郁,具有深沉内敛的特点",
|
||||
"emotion": "深沉、内敛、略带忧郁、思念",
|
||||
"typicalCadence": [1, 2],
|
||||
"avoidNotes": [4, 7]
|
||||
},
|
||||
"jue": {
|
||||
"name": "角调式",
|
||||
"notes": [1, 2, 3, 5, 6],
|
||||
"root": 3,
|
||||
"characteristic": "以角音(3)为主音,音阶清新脱俗,具有空灵飘逸的特点",
|
||||
"emotion": "清新、空灵、飘逸、超脱",
|
||||
"typicalCadence": [2, 3],
|
||||
"avoidNotes": [4, 7]
|
||||
},
|
||||
"zhi": {
|
||||
"name": "徵调式",
|
||||
"notes": [1, 2, 3, 5, 6],
|
||||
"root": 5,
|
||||
"characteristic": "以徵音(5)为主音,音阶热情奔放,具有激昂豪迈的特点",
|
||||
"emotion": "热情、奔放、激昂、豪迈",
|
||||
"typicalCadence": [6, 5],
|
||||
"avoidNotes": [4, 7]
|
||||
},
|
||||
"yu": {
|
||||
"name": "羽调式",
|
||||
"notes": [1, 2, 3, 5, 6],
|
||||
"root": 6,
|
||||
"characteristic": "以羽音(6)为主音,音阶柔和婉转,具有忧伤哀怨的特点",
|
||||
"emotion": "忧伤、婉转、哀怨、柔美",
|
||||
"typicalCadence": [5, 6],
|
||||
"avoidNotes": [4, 7]
|
||||
}
|
||||
},
|
||||
|
||||
"ornaments": {
|
||||
"huayin": {
|
||||
"name": "滑音",
|
||||
"notation": "↗ 或 ↘",
|
||||
"description": "从一个音滑向另一个音,常用于表达情感的流动",
|
||||
"usage": "句尾延长音、情感转折处、模仿人声哭腔",
|
||||
"examples": ["5↗6", "3↘2"]
|
||||
},
|
||||
"chanyin": {
|
||||
"name": "颤音",
|
||||
"notation": "~",
|
||||
"description": "在主音上快速交替相邻音,增加音色的丰富性",
|
||||
"usage": "长音装饰、情感强调、模仿弦乐器效果",
|
||||
"examples": ["5~", "6~"]
|
||||
},
|
||||
"yiyin": {
|
||||
"name": "倚音",
|
||||
"notation": "小音符标记",
|
||||
"description": "在主音前快速演奏的装饰音,增加旋律的流畅性",
|
||||
"usage": "乐句开头、强拍装饰、增加韵味",
|
||||
"examples": ["(3)5", "(6)1"]
|
||||
},
|
||||
"boyin": {
|
||||
"name": "波音",
|
||||
"notation": "∿",
|
||||
"description": "主音与上方或下方相邻音快速交替一次",
|
||||
"usage": "轻快段落、活泼情绪、增加灵动感",
|
||||
"examples": ["5∿", "3∿"]
|
||||
}
|
||||
},
|
||||
|
||||
"intervals": {
|
||||
"allowed": [1, 2, 3, 4, 5],
|
||||
"preferred": [1, 2],
|
||||
"descriptions": {
|
||||
"1": "同度/八度 - 稳定、强调",
|
||||
"2": "二度 - 级进,最常用,流畅自然",
|
||||
"3": "三度 - 小跳进,增加起伏",
|
||||
"4": "四度 - 中跳进,增加张力",
|
||||
"5": "五度 - 大跳进,戏剧性强,慎用"
|
||||
},
|
||||
"rules": [
|
||||
"优先使用级进(二度)保持旋律流畅",
|
||||
"跳进后宜用级进反向进行",
|
||||
"避免连续大跳进",
|
||||
"句尾常用下行级进解决到主音"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
{
|
||||
"meta": {
|
||||
"version": "1.0",
|
||||
"description": "中文歌词押韵数据库 - 基于拼音和声调的押韵分析",
|
||||
"created_for": "Musicify Skill System"
|
||||
},
|
||||
|
||||
"rhyme_patterns": {
|
||||
"AABB": {
|
||||
"description": "两行一韵,连续押韵",
|
||||
"difficulty": 1,
|
||||
"usage": "适合流行歌曲,容易上口"
|
||||
},
|
||||
"ABAB": {
|
||||
"description": "交错押韵",
|
||||
"difficulty": 2,
|
||||
"usage": "增加节奏变化,适合抒情歌曲"
|
||||
},
|
||||
"ABCB": {
|
||||
"description": "隔行押韵",
|
||||
"difficulty": 2,
|
||||
"usage": "常用于民谣和说唱"
|
||||
},
|
||||
"AAAA": {
|
||||
"description": "通韵到底",
|
||||
"difficulty": 3,
|
||||
"usage": "适合短小精悍的段落"
|
||||
}
|
||||
},
|
||||
|
||||
"common_rhymes": {
|
||||
"爱情主题": [
|
||||
{"group": "ai", "words": ["爱", "在", "来", "开", "怀", "猜", "陪", "等待"]},
|
||||
{"group": "ing", "words": ["情", "心", "真", "深", "亲", "信", "认", "永恒"]},
|
||||
{"group": "ou", "words": ["走", "久", "守", "有", "后", "手", "温柔", "拥有"]},
|
||||
{"group": "an", "words": ["伴", "暖", "看", "汗", "伞", "岸", "陪伴", "温暖"]}
|
||||
],
|
||||
|
||||
"励志主题": [
|
||||
{"group": "eng", "words": ["梦", "能", "成", "风", "空", "勇", "冲", "成功"]},
|
||||
{"group": "iang", "words": ["想", "强", "光", "方", "向", "长", "希望", "力量"]},
|
||||
{"group": "u", "words": ["路", "步", "住", "哭", "努", "苦", "付出", "坚持"]},
|
||||
{"group": "i", "words": ["力", "立", "起", "地", "意", "义", "坚毅", "奇迹"]}
|
||||
],
|
||||
|
||||
"青春回忆": [
|
||||
{"group": "ian", "words": ["年", "天", "前", "甜", "变", "见", "青春", "遇见"]},
|
||||
{"group": "ao", "words": ["好", "老", "少", "跑", "闹", "笑", "美好", "年少"]},
|
||||
{"group": "ei", "words": ["美", "回", "累", "醉", "泪", "岁", "珍贵", "无悔"]},
|
||||
{"group": "ong", "words": ["梦", "中", "空", "痛", "重", "懂", "朦胧", "感动"]}
|
||||
],
|
||||
|
||||
"离别思念": [
|
||||
{"group": "ie", "words": ["别", "夜", "雪", "月", "切", "说", "离别", "永别"]},
|
||||
{"group": "iao", "words": ["远", "想", "飘", "桥", "料", "瞧", "思念", "遥远"]},
|
||||
{"group": "iu", "words": ["留", "久", "流", "愁", "求", "收", "停留", "不朽"]},
|
||||
{"group": "eng", "words": ["等", "朋", "冷", "疼", "能", "层", "等候", "心疼"]}
|
||||
],
|
||||
|
||||
"家乡故土": [
|
||||
{"group": "ang", "words": ["乡", "长", "方", "香", "窗", "望", "故乡", "远方"]},
|
||||
{"group": "ou", "words": ["家", "花", "话", "画", "挂", "牵挂", "变化"]},
|
||||
{"group": "i", "words": ["地", "里", "起", "记", "意", "立", "土地", "回忆"]},
|
||||
{"group": "an", "words": ["山", "田", "甘", "看", "暖", "伴", "青山", "温暖"]}
|
||||
]
|
||||
},
|
||||
|
||||
"emotion_vocabulary": {
|
||||
"欢快": {
|
||||
"adjectives": ["明亮", "轻快", "绚烂", "灿烂", "活泼", "欢乐", "愉悦", "畅快"],
|
||||
"verbs": ["跳跃", "飞扬", "奔跑", "舞蹈", "歌唱", "欢笑", "庆祝", "绽放"],
|
||||
"nouns": ["阳光", "彩虹", "花朵", "蝴蝶", "鸟儿", "春风", "笑声", "节拍"]
|
||||
},
|
||||
|
||||
"忧伤": {
|
||||
"adjectives": ["黯然", "凄凉", "孤独", "冷清", "沉重", "苦涩", "惆怅", "迷茫"],
|
||||
"verbs": ["凋零", "飘零", "消散", "哭泣", "叹息", "怀念", "失去", "离开"],
|
||||
"nouns": ["雨滴", "落叶", "寒风", "夜晚", "眼泪", "回忆", "阴霾", "孤影"]
|
||||
},
|
||||
|
||||
"温暖": {
|
||||
"adjectives": ["温柔", "暖和", "亲切", "慈爱", "安详", "舒适", "贴心", "甜蜜"],
|
||||
"verbs": ["拥抱", "守护", "陪伴", "关怀", "温暖", "照亮", "安慰", "包容"],
|
||||
"nouns": ["怀抱", "家", "母亲", "暖阳", "火炉", "热茶", "羽毛", "港湾"]
|
||||
},
|
||||
|
||||
"励志": {
|
||||
"adjectives": ["坚强", "勇敢", "坚定", "不屈", "执着", "顽强", "无畏", "坚毅"],
|
||||
"verbs": ["奋斗", "追求", "坚持", "突破", "攀登", "拼搏", "冲刺", "征服"],
|
||||
"nouns": ["梦想", "目标", "理想", "信念", "勇气", "力量", "意志", "希望"]
|
||||
},
|
||||
|
||||
"浪漫": {
|
||||
"adjectives": ["浪漫", "梦幻", "迷人", "优雅", "柔美", "诗意", "唯美", "动人"],
|
||||
"verbs": ["邂逅", "心动", "倾心", "眷恋", "凝视", "等候", "思念", "相拥"],
|
||||
"nouns": ["月光", "星空", "玫瑰", "诗歌", "约定", "信物", "回音", "倩影"]
|
||||
}
|
||||
},
|
||||
|
||||
"rhyme_quality_metrics": {
|
||||
"perfect_match": {
|
||||
"score": 95,
|
||||
"description": "完全押韵,音调和韵母都匹配"
|
||||
},
|
||||
"near_rhyme": {
|
||||
"score": 80,
|
||||
"description": "近似押韵,韵母相同音调略不同"
|
||||
},
|
||||
"assonance": {
|
||||
"score": 65,
|
||||
"description": "元音押韵,主要元音相同"
|
||||
},
|
||||
"consonance": {
|
||||
"score": 50,
|
||||
"description": "辅音押韵,结尾辅音相同"
|
||||
},
|
||||
"weak_rhyme": {
|
||||
"score": 30,
|
||||
"description": "弱押韵,仅部分音素相似"
|
||||
},
|
||||
"no_rhyme": {
|
||||
"score": 0,
|
||||
"description": "无押韵关系"
|
||||
}
|
||||
},
|
||||
|
||||
"songwriting_tips": {
|
||||
"rhyme_techniques": [
|
||||
{
|
||||
"name": "内部押韵",
|
||||
"description": "在同一行或相邻行的内部创造押韵效果",
|
||||
"example": "心中的梦想如星光闪亮"
|
||||
},
|
||||
{
|
||||
"name": "重复押韵",
|
||||
"description": "使用相同的韵脚增强记忆点",
|
||||
"example": "爱你的心永不改变,爱你到永远"
|
||||
},
|
||||
{
|
||||
"name": "多重押韵",
|
||||
"description": "在一行中使用多个押韵点",
|
||||
"example": "阳光灿烂照人间,温暖如春风拂面"
|
||||
}
|
||||
],
|
||||
|
||||
"rhythm_patterns": [
|
||||
{
|
||||
"name": "七字句",
|
||||
"pattern": "2-2-3",
|
||||
"example": "青春/如梦/多美好",
|
||||
"usage": "经典中文歌词节奏"
|
||||
},
|
||||
{
|
||||
"name": "五字句",
|
||||
"pattern": "2-3",
|
||||
"example": "思君/不见君",
|
||||
"usage": "古风歌曲常用"
|
||||
},
|
||||
{
|
||||
"name": "九字句",
|
||||
"pattern": "3-3-3",
|
||||
"example": "走过了/春夏秋冬/多少年",
|
||||
"usage": "适合叙事性歌曲"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"advanced_features": {
|
||||
"tone_analysis": {
|
||||
"first_tone": {"description": "阴平,高平调", "compatibility": ["first_tone", "second_tone"]},
|
||||
"second_tone": {"description": "阳平,中升调", "compatibility": ["first_tone", "second_tone"]},
|
||||
"third_tone": {"description": "上声,低降升调", "compatibility": ["third_tone", "fourth_tone"]},
|
||||
"fourth_tone": {"description": "去声,高降调", "compatibility": ["third_tone", "fourth_tone"]}
|
||||
},
|
||||
|
||||
"syllable_structure": {
|
||||
"monosyllabic": {"description": "单音节词", "usage": "适合快节奏部分"},
|
||||
"disyllabic": {"description": "双音节词", "usage": "最常用的词汇结构"},
|
||||
"trisyllabic": {"description": "三音节词", "usage": "适合慢节奏抒情"},
|
||||
"polysyllabic": {"description": "多音节词", "usage": "用于特殊效果"}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,367 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
MP3 转 MIDI 工具
|
||||
使用 Demucs 分离人声 + Basic Pitch 转换 MIDI
|
||||
|
||||
用法:
|
||||
python audio_to_midi.py <input_mp3> [output_dir]
|
||||
python audio_to_midi.py --check # 检查依赖和硬件
|
||||
|
||||
输出:
|
||||
JSON 格式的处理结果
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import subprocess
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def output_json(data):
|
||||
"""输出 JSON 格式结果"""
|
||||
print(json.dumps(data, ensure_ascii=False, indent=2))
|
||||
|
||||
|
||||
def detect_hardware():
|
||||
"""检测可用硬件加速"""
|
||||
try:
|
||||
import torch
|
||||
if torch.cuda.is_available():
|
||||
device_name = torch.cuda.get_device_name(0)
|
||||
return {
|
||||
"device": "cuda",
|
||||
"name": device_name,
|
||||
"description": f"NVIDIA GPU 加速 ({device_name})",
|
||||
"estimated_time": "1-2 分钟"
|
||||
}
|
||||
elif hasattr(torch.backends, 'mps') and torch.backends.mps.is_available():
|
||||
return {
|
||||
"device": "mps",
|
||||
"name": "Apple Silicon",
|
||||
"description": "Apple Silicon 加速 (MPS)",
|
||||
"estimated_time": "2-3 分钟"
|
||||
}
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
return {
|
||||
"device": "cpu",
|
||||
"name": "CPU",
|
||||
"description": "CPU 模式 (较慢)",
|
||||
"estimated_time": "8-15 分钟"
|
||||
}
|
||||
|
||||
|
||||
def check_dependencies():
|
||||
"""检查依赖是否安装"""
|
||||
dependencies = {
|
||||
"demucs": {"installed": False, "version": None},
|
||||
"basic_pitch": {"installed": False, "version": None},
|
||||
"torch": {"installed": False, "version": None},
|
||||
}
|
||||
|
||||
try:
|
||||
import demucs
|
||||
dependencies["demucs"]["installed"] = True
|
||||
dependencies["demucs"]["version"] = getattr(demucs, '__version__', 'unknown')
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
try:
|
||||
import basic_pitch
|
||||
dependencies["basic_pitch"]["installed"] = True
|
||||
dependencies["basic_pitch"]["version"] = getattr(basic_pitch, '__version__', 'unknown')
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
try:
|
||||
import torch
|
||||
dependencies["torch"]["installed"] = True
|
||||
dependencies["torch"]["version"] = torch.__version__
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
return dependencies
|
||||
|
||||
|
||||
def check_command_available(cmd):
|
||||
"""检查命令行工具是否可用"""
|
||||
return shutil.which(cmd) is not None
|
||||
|
||||
|
||||
def separate_vocals(input_mp3, output_dir, device="cpu"):
|
||||
"""
|
||||
使用 Demucs 分离人声
|
||||
|
||||
Args:
|
||||
input_mp3: 输入 MP3 文件路径
|
||||
output_dir: 输出目录
|
||||
device: 使用的设备 (cuda/mps/cpu)
|
||||
|
||||
Returns:
|
||||
vocals_path: 人声文件路径
|
||||
"""
|
||||
input_path = Path(input_mp3)
|
||||
output_path = Path(output_dir)
|
||||
|
||||
# 构建 demucs 命令
|
||||
cmd = [
|
||||
sys.executable, "-m", "demucs",
|
||||
"--two-stems=vocals", # 只分离人声和伴奏
|
||||
"-o", str(output_path),
|
||||
"--device", device if device != "mps" else "mps",
|
||||
]
|
||||
|
||||
# 添加输入文件
|
||||
cmd.append(str(input_path))
|
||||
|
||||
# 执行命令
|
||||
try:
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=1800 # 30 分钟超时
|
||||
)
|
||||
|
||||
if result.returncode != 0:
|
||||
return None, f"Demucs 执行失败: {result.stderr}"
|
||||
|
||||
# 查找输出的人声文件
|
||||
# Demucs 输出格式: output_dir/htdemucs/song_name/vocals.wav
|
||||
song_name = input_path.stem
|
||||
vocals_path = output_path / "htdemucs" / song_name / "vocals.wav"
|
||||
|
||||
if not vocals_path.exists():
|
||||
# 尝试其他可能的路径
|
||||
for model_dir in output_path.iterdir():
|
||||
if model_dir.is_dir():
|
||||
possible_path = model_dir / song_name / "vocals.wav"
|
||||
if possible_path.exists():
|
||||
vocals_path = possible_path
|
||||
break
|
||||
|
||||
if vocals_path.exists():
|
||||
return str(vocals_path), None
|
||||
else:
|
||||
return None, f"未找到人声文件,请检查 {output_path} 目录"
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
return None, "Demucs 处理超时 (超过 30 分钟)"
|
||||
except Exception as e:
|
||||
return None, f"Demucs 执行异常: {str(e)}"
|
||||
|
||||
|
||||
def convert_to_midi(vocals_wav, output_dir):
|
||||
"""
|
||||
使用 Basic Pitch 将人声转换为 MIDI
|
||||
|
||||
Args:
|
||||
vocals_wav: 人声 WAV 文件路径
|
||||
output_dir: 输出目录
|
||||
|
||||
Returns:
|
||||
midi_path: MIDI 文件路径
|
||||
"""
|
||||
vocals_path = Path(vocals_wav)
|
||||
output_path = Path(output_dir)
|
||||
|
||||
# 构建 basic-pitch 命令
|
||||
cmd = [
|
||||
sys.executable, "-m", "basic_pitch",
|
||||
str(output_path),
|
||||
str(vocals_path)
|
||||
]
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=300 # 5 分钟超时
|
||||
)
|
||||
|
||||
if result.returncode != 0:
|
||||
return None, f"Basic Pitch 执行失败: {result.stderr}"
|
||||
|
||||
# 查找输出的 MIDI 文件
|
||||
# Basic Pitch 输出格式: output_dir/vocals_basic_pitch.mid
|
||||
midi_name = vocals_path.stem + "_basic_pitch.mid"
|
||||
midi_path = output_path / midi_name
|
||||
|
||||
if midi_path.exists():
|
||||
return str(midi_path), None
|
||||
else:
|
||||
# 尝试查找任何 .mid 文件
|
||||
for f in output_path.glob("*.mid"):
|
||||
return str(f), None
|
||||
return None, f"未找到 MIDI 文件,请检查 {output_path} 目录"
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
return None, "Basic Pitch 处理超时 (超过 5 分钟)"
|
||||
except Exception as e:
|
||||
return None, f"Basic Pitch 执行异常: {str(e)}"
|
||||
|
||||
|
||||
def process_audio(input_mp3, output_dir=None):
|
||||
"""
|
||||
完整的音频处理流程
|
||||
|
||||
Args:
|
||||
input_mp3: 输入 MP3 文件路径
|
||||
output_dir: 输出目录 (默认为输入文件所在目录)
|
||||
|
||||
Returns:
|
||||
处理结果字典
|
||||
"""
|
||||
input_path = Path(input_mp3)
|
||||
|
||||
if not input_path.exists():
|
||||
return {
|
||||
"status": "error",
|
||||
"error": f"输入文件不存在: {input_mp3}"
|
||||
}
|
||||
|
||||
if output_dir is None:
|
||||
output_dir = input_path.parent
|
||||
|
||||
output_path = Path(output_dir)
|
||||
output_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# 检测硬件
|
||||
hardware = detect_hardware()
|
||||
|
||||
# 检查依赖
|
||||
deps = check_dependencies()
|
||||
missing_deps = [name for name, info in deps.items()
|
||||
if not info["installed"] and name != "torch"]
|
||||
|
||||
if missing_deps:
|
||||
return {
|
||||
"status": "error",
|
||||
"error": "缺少必要依赖",
|
||||
"missing_dependencies": missing_deps,
|
||||
"install_command": f"pip install {' '.join(missing_deps).replace('_', '-')}",
|
||||
"alternative": "或使用在线工具: https://basicpitch.spotify.com"
|
||||
}
|
||||
|
||||
result = {
|
||||
"status": "processing",
|
||||
"input_file": str(input_path),
|
||||
"output_dir": str(output_path),
|
||||
"hardware": hardware,
|
||||
"steps": []
|
||||
}
|
||||
|
||||
# Step 1: 分离人声
|
||||
result["steps"].append({
|
||||
"step": 1,
|
||||
"name": "分离人声",
|
||||
"status": "in_progress",
|
||||
"tool": "Demucs"
|
||||
})
|
||||
|
||||
vocals_path, error = separate_vocals(
|
||||
input_mp3,
|
||||
output_path,
|
||||
hardware["device"]
|
||||
)
|
||||
|
||||
if error:
|
||||
result["status"] = "error"
|
||||
result["steps"][-1]["status"] = "failed"
|
||||
result["steps"][-1]["error"] = error
|
||||
return result
|
||||
|
||||
result["steps"][-1]["status"] = "completed"
|
||||
result["steps"][-1]["output"] = vocals_path
|
||||
result["vocals_file"] = vocals_path
|
||||
|
||||
# Step 2: 转换为 MIDI
|
||||
result["steps"].append({
|
||||
"step": 2,
|
||||
"name": "转换 MIDI",
|
||||
"status": "in_progress",
|
||||
"tool": "Basic Pitch"
|
||||
})
|
||||
|
||||
midi_path, error = convert_to_midi(vocals_path, output_path)
|
||||
|
||||
if error:
|
||||
result["status"] = "error"
|
||||
result["steps"][-1]["status"] = "failed"
|
||||
result["steps"][-1]["error"] = error
|
||||
return result
|
||||
|
||||
result["steps"][-1]["status"] = "completed"
|
||||
result["steps"][-1]["output"] = midi_path
|
||||
result["midi_file"] = midi_path
|
||||
|
||||
# 重命名 MIDI 文件为更友好的名称
|
||||
final_midi_name = input_path.stem + ".mid"
|
||||
final_midi_path = output_path / final_midi_name
|
||||
|
||||
if str(midi_path) != str(final_midi_path):
|
||||
try:
|
||||
shutil.move(midi_path, final_midi_path)
|
||||
result["midi_file"] = str(final_midi_path)
|
||||
except Exception:
|
||||
pass # 保持原文件名
|
||||
|
||||
result["status"] = "success"
|
||||
result["message"] = "MP3 转 MIDI 完成"
|
||||
result["completed_at"] = datetime.now().isoformat()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
if len(sys.argv) < 2:
|
||||
output_json({
|
||||
"status": "error",
|
||||
"error": "缺少参数",
|
||||
"usage": "python audio_to_midi.py <input_mp3> [output_dir]",
|
||||
"examples": [
|
||||
"python audio_to_midi.py song.mp3",
|
||||
"python audio_to_midi.py song.mp3 ./output",
|
||||
"python audio_to_midi.py --check"
|
||||
]
|
||||
})
|
||||
sys.exit(1)
|
||||
|
||||
# 检查模式
|
||||
if sys.argv[1] == "--check":
|
||||
deps = check_dependencies()
|
||||
hardware = detect_hardware()
|
||||
|
||||
all_installed = all(
|
||||
info["installed"]
|
||||
for name, info in deps.items()
|
||||
if name != "torch"
|
||||
)
|
||||
|
||||
output_json({
|
||||
"status": "ready" if all_installed else "missing_dependencies",
|
||||
"dependencies": deps,
|
||||
"hardware": hardware,
|
||||
"install_command": "pip install demucs basic-pitch" if not all_installed else None,
|
||||
"online_alternative": "https://basicpitch.spotify.com"
|
||||
})
|
||||
sys.exit(0 if all_installed else 1)
|
||||
|
||||
# 处理模式
|
||||
input_mp3 = sys.argv[1]
|
||||
output_dir = sys.argv[2] if len(sys.argv) > 2 else None
|
||||
|
||||
result = process_audio(input_mp3, output_dir)
|
||||
output_json(result)
|
||||
|
||||
sys.exit(0 if result["status"] == "success" else 1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,677 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
MIDI 音乐分析器 - 专业级旋律风格分析
|
||||
从"太简单"的文件检查升级为专业 MIDI 分析和特征提取
|
||||
|
||||
支持功能:
|
||||
- 智能人声音轨识别
|
||||
- 深度旋律特征分析(节奏型、音程、调式)
|
||||
- 音乐理论分析(五声音阶、调式推断)
|
||||
- AI 风格学习准备
|
||||
"""
|
||||
|
||||
import sys
|
||||
import json
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Any, Optional, Tuple
|
||||
from dataclasses import dataclass, asdict
|
||||
import traceback
|
||||
|
||||
# 检查并导入依赖
|
||||
try:
|
||||
import mido
|
||||
import music21
|
||||
import numpy as np
|
||||
except ImportError as e:
|
||||
print(json.dumps({
|
||||
"status": "error",
|
||||
"error_type": "missing_dependency",
|
||||
"message": f"缺少必需的 Python 库: {str(e)}",
|
||||
"solution": "请安装依赖: pip install mido music21 numpy",
|
||||
"dependencies": {
|
||||
"mido": "MIDI 文件解析",
|
||||
"music21": "音乐理论分析",
|
||||
"numpy": "数值计算"
|
||||
}
|
||||
}, ensure_ascii=False, indent=2))
|
||||
sys.exit(1)
|
||||
|
||||
@dataclass
|
||||
class VocalTrackCandidate:
|
||||
"""人声音轨候选"""
|
||||
track_index: int
|
||||
track_name: str
|
||||
note_count: int
|
||||
note_range: Tuple[int, int] # (min_pitch, max_pitch)
|
||||
confidence_score: float
|
||||
reasons: List[str]
|
||||
|
||||
@dataclass
|
||||
class MelodyFeatures:
|
||||
"""旋律特征分析结果"""
|
||||
# 基本信息
|
||||
total_notes: int
|
||||
note_range: Tuple[int, int]
|
||||
duration_beats: float
|
||||
|
||||
# 节奏特征
|
||||
rhythm_complexity: float
|
||||
rhythm_patterns: Dict[str, float] # 节奏型分布
|
||||
syncopation_level: float
|
||||
|
||||
# 音程特征
|
||||
interval_distribution: Dict[str, float]
|
||||
stepwise_ratio: float
|
||||
leap_ratio: float
|
||||
|
||||
# 调式特征
|
||||
key_signature: str
|
||||
mode_analysis: Dict[str, float]
|
||||
scale_notes: List[str]
|
||||
|
||||
# 旋律轮廓
|
||||
contour_vector: List[int]
|
||||
phrase_structure: List[Tuple[int, int]]
|
||||
|
||||
class ProfessionalMidiAnalyzer:
|
||||
"""专业级 MIDI 分析器"""
|
||||
|
||||
def __init__(self):
|
||||
# 人声音域范围 (MIDI note numbers)
|
||||
self.vocal_range = (48, 84) # C3 to C6
|
||||
|
||||
# 五声音阶映射
|
||||
self.pentatonic_scales = {
|
||||
'C': [0, 2, 4, 7, 9], # C D E G A
|
||||
'G': [7, 9, 11, 2, 4], # G A B D E
|
||||
'D': [2, 4, 6, 9, 11], # D E F# A B
|
||||
'A': [9, 11, 1, 4, 6], # A B C# E F#
|
||||
'E': [4, 6, 8, 11, 1], # E F# G# B C#
|
||||
'B': [11, 1, 3, 6, 8], # B C# D# F# G#
|
||||
'F#': [6, 8, 10, 1, 3], # F# G# A# C# D#
|
||||
'Db': [1, 3, 5, 8, 10], # Db Eb F Ab Bb
|
||||
'Ab': [8, 10, 0, 3, 5], # Ab Bb C Eb F
|
||||
'Eb': [3, 5, 7, 10, 0], # Eb F G Bb C
|
||||
'Bb': [10, 0, 2, 5, 7], # Bb C D F G
|
||||
'F': [5, 7, 9, 0, 2] # F G A C D
|
||||
}
|
||||
|
||||
# 节奏模式识别
|
||||
self.rhythm_patterns = {
|
||||
'quarter': 480, # 四分音符
|
||||
'eighth': 240, # 八分音符
|
||||
'dotted_quarter': 720, # 附点四分音符
|
||||
'sixteenth': 120, # 十六分音符
|
||||
'triplet': 160 # 三连音
|
||||
}
|
||||
|
||||
def analyze_midi_file(self, midi_path: str, lyrics_path: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""分析 MIDI 文件的主入口"""
|
||||
try:
|
||||
# 基本文件检查
|
||||
if not Path(midi_path).exists():
|
||||
raise FileNotFoundError(f"MIDI 文件不存在: {midi_path}")
|
||||
|
||||
# 加载 MIDI 文件
|
||||
midi_file = mido.MidiFile(midi_path)
|
||||
|
||||
# 分析歌词信息
|
||||
lyrics_info = self._analyze_lyrics(lyrics_path) if lyrics_path else None
|
||||
|
||||
# 识别人声音轨
|
||||
vocal_candidates = self._identify_vocal_tracks(midi_file, lyrics_info)
|
||||
|
||||
if not vocal_candidates:
|
||||
return self._create_error_result("no_vocal_track", "未找到合适的人声音轨")
|
||||
|
||||
# 选择最佳人声音轨
|
||||
best_vocal = max(vocal_candidates, key=lambda x: x.confidence_score)
|
||||
|
||||
# 提取音轨的音符数据
|
||||
notes = self._extract_notes_from_track(midi_file, best_vocal.track_index)
|
||||
|
||||
if not notes:
|
||||
return self._create_error_result("no_notes", "人声音轨中未找到音符数据")
|
||||
|
||||
# 深度旋律特征分析
|
||||
melody_features = self._extract_melody_features(notes, midi_file)
|
||||
|
||||
# 生成创作模式推荐
|
||||
mode_recommendation = self.recommend_creation_mode(melody_features, lyrics_info)
|
||||
|
||||
# 构建分析结果
|
||||
result = {
|
||||
"status": "success",
|
||||
"analysis_type": "professional",
|
||||
"file_info": {
|
||||
"midi_path": midi_path,
|
||||
"lyrics_path": lyrics_path,
|
||||
"file_size": Path(midi_path).stat().st_size,
|
||||
"track_count": len(midi_file.tracks)
|
||||
},
|
||||
"vocal_track_analysis": {
|
||||
"selected_track": asdict(best_vocal),
|
||||
"all_candidates": [asdict(c) for c in vocal_candidates],
|
||||
"selection_confidence": best_vocal.confidence_score
|
||||
},
|
||||
"melody_features": asdict(melody_features),
|
||||
"lyrics_analysis": lyrics_info,
|
||||
"mode_recommendation": mode_recommendation, # NEW: 模式推荐信息
|
||||
"technical_info": {
|
||||
"ticks_per_beat": midi_file.ticks_per_beat,
|
||||
"total_time": sum(msg.time for track in midi_file.tracks for msg in track),
|
||||
"format_type": midi_file.type
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
return self._create_error_result(
|
||||
"analysis_error",
|
||||
f"分析过程中发生错误: {str(e)}",
|
||||
{"traceback": traceback.format_exc()}
|
||||
)
|
||||
|
||||
def _analyze_lyrics(self, lyrics_path: str) -> Optional[Dict[str, Any]]:
|
||||
"""分析歌词文件"""
|
||||
try:
|
||||
with open(lyrics_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
# 统计字数(排除标点符号)
|
||||
clean_text = ''.join(char for char in content if char.isalpha())
|
||||
|
||||
# 检测段落结构
|
||||
sections = []
|
||||
current_section = None
|
||||
|
||||
for line in content.split('\n'):
|
||||
line = line.strip()
|
||||
if line.startswith('[') and line.endswith(']'):
|
||||
if current_section:
|
||||
sections.append(current_section)
|
||||
current_section = {
|
||||
"name": line[1:-1],
|
||||
"lines": [],
|
||||
"char_count": 0
|
||||
}
|
||||
elif line and current_section:
|
||||
current_section["lines"].append(line)
|
||||
current_section["char_count"] += len([c for c in line if c.isalpha()])
|
||||
|
||||
if current_section:
|
||||
sections.append(current_section)
|
||||
|
||||
return {
|
||||
"total_chars": len(clean_text),
|
||||
"total_lines": len([line for line in content.split('\n') if line.strip() and not line.strip().startswith('[')]),
|
||||
"sections": sections,
|
||||
"has_structure_markers": any(line.startswith('[') for line in content.split('\n'))
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
return {"error": f"歌词分析失败: {str(e)}"}
|
||||
|
||||
def _identify_vocal_tracks(self, midi_file: mido.MidiFile, lyrics_info: Optional[Dict]) -> List[VocalTrackCandidate]:
|
||||
"""智能识别人声音轨"""
|
||||
candidates = []
|
||||
|
||||
for track_idx, track in enumerate(midi_file.tracks):
|
||||
notes = self._extract_notes_from_track(midi_file, track_idx)
|
||||
|
||||
if not notes:
|
||||
continue
|
||||
|
||||
# 计算基本信息
|
||||
pitches = [note['pitch'] for note in notes]
|
||||
min_pitch, max_pitch = min(pitches), max(pitches)
|
||||
note_count = len(notes)
|
||||
|
||||
# 评分系统
|
||||
score = 0.0
|
||||
reasons = []
|
||||
|
||||
# 1. 音轨名称匹配(30分)
|
||||
track_name = getattr(track, 'name', f'Track {track_idx}')
|
||||
vocal_keywords = ['vocal', 'voice', 'melody', 'lead', '主旋律', '人声']
|
||||
if any(keyword.lower() in track_name.lower() for keyword in vocal_keywords):
|
||||
score += 30
|
||||
reasons.append(f"音轨名包含人声关键词: {track_name}")
|
||||
|
||||
# 2. 音域匹配(25分)
|
||||
vocal_range_overlap = self._calculate_range_overlap(
|
||||
(min_pitch, max_pitch), self.vocal_range
|
||||
)
|
||||
if vocal_range_overlap > 0.7:
|
||||
score += 25
|
||||
reasons.append(f"音域高度匹配人声范围: {vocal_range_overlap:.1%}")
|
||||
elif vocal_range_overlap > 0.5:
|
||||
score += 15
|
||||
reasons.append(f"音域部分匹配人声范围: {vocal_range_overlap:.1%}")
|
||||
|
||||
# 3. 歌词字数匹配(20分)
|
||||
if lyrics_info and 'total_chars' in lyrics_info:
|
||||
lyrics_chars = lyrics_info['total_chars']
|
||||
if lyrics_chars > 0:
|
||||
ratio = abs(1 - note_count / lyrics_chars)
|
||||
if ratio < 0.1: # 10%内匹配
|
||||
score += 20
|
||||
reasons.append(f"音符数与歌词字数高度匹配: {note_count}≈{lyrics_chars}")
|
||||
elif ratio < 0.3: # 30%内匹配
|
||||
score += 10
|
||||
reasons.append(f"音符数与歌词字数基本匹配: {note_count}vs{lyrics_chars}")
|
||||
|
||||
# 4. 音符密度合理性(15分)
|
||||
if 20 <= note_count <= 200: # 合理的旋律长度
|
||||
score += 15
|
||||
reasons.append(f"音符数量合理: {note_count}")
|
||||
elif note_count > 10:
|
||||
score += 5
|
||||
reasons.append(f"音符数量可接受: {note_count}")
|
||||
|
||||
# 5. 旋律特征(10分)
|
||||
interval_variety = self._calculate_interval_variety(notes)
|
||||
if interval_variety > 0.3: # 有合理的音程变化
|
||||
score += 10
|
||||
reasons.append(f"音程变化丰富: {interval_variety:.2f}")
|
||||
|
||||
candidates.append(VocalTrackCandidate(
|
||||
track_index=track_idx,
|
||||
track_name=track_name,
|
||||
note_count=note_count,
|
||||
note_range=(min_pitch, max_pitch),
|
||||
confidence_score=score,
|
||||
reasons=reasons
|
||||
))
|
||||
|
||||
# 按置信度排序
|
||||
return sorted(candidates, key=lambda x: x.confidence_score, reverse=True)
|
||||
|
||||
def _extract_notes_from_track(self, midi_file: mido.MidiFile, track_idx: int) -> List[Dict]:
|
||||
"""从指定音轨提取音符信息"""
|
||||
track = midi_file.tracks[track_idx]
|
||||
notes = []
|
||||
current_time = 0
|
||||
active_notes = {} # pitch -> start_time
|
||||
|
||||
for msg in track:
|
||||
current_time += msg.time
|
||||
|
||||
if msg.type == 'note_on' and msg.velocity > 0:
|
||||
active_notes[msg.note] = current_time
|
||||
elif msg.type == 'note_off' or (msg.type == 'note_on' and msg.velocity == 0):
|
||||
if msg.note in active_notes:
|
||||
start_time = active_notes.pop(msg.note)
|
||||
duration = current_time - start_time
|
||||
|
||||
notes.append({
|
||||
'pitch': msg.note,
|
||||
'start_time': start_time,
|
||||
'duration': duration,
|
||||
'velocity': getattr(msg, 'velocity', 64)
|
||||
})
|
||||
|
||||
# 按开始时间排序
|
||||
return sorted(notes, key=lambda x: x['start_time'])
|
||||
|
||||
def _extract_melody_features(self, notes: List[Dict], midi_file: mido.MidiFile) -> MelodyFeatures:
|
||||
"""深度旋律特征提取"""
|
||||
ticks_per_beat = midi_file.ticks_per_beat
|
||||
|
||||
# 基本信息
|
||||
pitches = [note['pitch'] for note in notes]
|
||||
durations = [note['duration'] for note in notes]
|
||||
|
||||
# 节奏分析
|
||||
rhythm_analysis = self._analyze_rhythm_patterns(durations, ticks_per_beat)
|
||||
|
||||
# 音程分析
|
||||
interval_analysis = self._analyze_intervals(pitches)
|
||||
|
||||
# 调式分析
|
||||
key_analysis = self._analyze_key_and_mode(pitches)
|
||||
|
||||
# 旋律轮廓
|
||||
contour = self._extract_melody_contour(pitches)
|
||||
|
||||
# 乐句结构
|
||||
phrases = self._identify_phrases(notes, ticks_per_beat)
|
||||
|
||||
return MelodyFeatures(
|
||||
total_notes=len(notes),
|
||||
note_range=(min(pitches), max(pitches)),
|
||||
duration_beats=sum(durations) / ticks_per_beat,
|
||||
rhythm_complexity=rhythm_analysis['complexity'],
|
||||
rhythm_patterns=rhythm_analysis['patterns'],
|
||||
syncopation_level=rhythm_analysis['syncopation'],
|
||||
interval_distribution=interval_analysis['distribution'],
|
||||
stepwise_ratio=interval_analysis['stepwise_ratio'],
|
||||
leap_ratio=interval_analysis['leap_ratio'],
|
||||
key_signature=key_analysis['key'],
|
||||
mode_analysis=key_analysis['modes'],
|
||||
scale_notes=key_analysis['scale_notes'],
|
||||
contour_vector=contour,
|
||||
phrase_structure=phrases
|
||||
)
|
||||
|
||||
def _analyze_rhythm_patterns(self, durations: List[int], ticks_per_beat: int) -> Dict[str, Any]:
|
||||
"""分析节奏型模式"""
|
||||
if not durations:
|
||||
return {'complexity': 0, 'patterns': {}, 'syncopation': 0}
|
||||
|
||||
# 标准化时值到节拍单位
|
||||
beat_durations = [d / ticks_per_beat for d in durations]
|
||||
|
||||
# 计算节奏模式分布
|
||||
patterns = {
|
||||
'whole': 0, # 全音符
|
||||
'half': 0, # 二分音符
|
||||
'quarter': 0, # 四分音符
|
||||
'eighth': 0, # 八分音符
|
||||
'sixteenth': 0, # 十六分音符
|
||||
'dotted': 0, # 附点节奏
|
||||
'triplet': 0 # 三连音
|
||||
}
|
||||
|
||||
for duration in beat_durations:
|
||||
if abs(duration - 4.0) < 0.1:
|
||||
patterns['whole'] += 1
|
||||
elif abs(duration - 2.0) < 0.1:
|
||||
patterns['half'] += 1
|
||||
elif abs(duration - 1.0) < 0.1:
|
||||
patterns['quarter'] += 1
|
||||
elif abs(duration - 0.5) < 0.1:
|
||||
patterns['eighth'] += 1
|
||||
elif abs(duration - 0.25) < 0.1:
|
||||
patterns['sixteenth'] += 1
|
||||
elif abs(duration - 1.5) < 0.1:
|
||||
patterns['dotted'] += 1
|
||||
elif abs(duration - 0.33) < 0.1:
|
||||
patterns['triplet'] += 1
|
||||
|
||||
total = len(durations)
|
||||
pattern_ratios = {k: v/total for k, v in patterns.items()} if total > 0 else patterns
|
||||
|
||||
# 计算节奏复杂度
|
||||
complexity = len([v for v in pattern_ratios.values() if v > 0.05]) # 超过5%的模式
|
||||
|
||||
# 简单的切分检测
|
||||
syncopation = sum(1 for d in beat_durations if 0.3 < d < 0.7 or 1.3 < d < 1.7) / total if total > 0 else 0
|
||||
|
||||
return {
|
||||
'complexity': complexity,
|
||||
'patterns': pattern_ratios,
|
||||
'syncopation': syncopation
|
||||
}
|
||||
|
||||
def _analyze_intervals(self, pitches: List[int]) -> Dict[str, Any]:
|
||||
"""分析音程分布"""
|
||||
if len(pitches) < 2:
|
||||
return {'distribution': {}, 'stepwise_ratio': 0, 'leap_ratio': 0}
|
||||
|
||||
intervals = [pitches[i+1] - pitches[i] for i in range(len(pitches)-1)]
|
||||
|
||||
# 音程分类
|
||||
interval_types = {
|
||||
'unison': 0, # 同度 (0)
|
||||
'step': 0, # 级进 (1-2)
|
||||
'small_leap': 0, # 小跳 (3-4)
|
||||
'large_leap': 0, # 大跳 (5+)
|
||||
'octave': 0 # 八度 (12)
|
||||
}
|
||||
|
||||
for interval in intervals:
|
||||
abs_interval = abs(interval)
|
||||
if abs_interval == 0:
|
||||
interval_types['unison'] += 1
|
||||
elif abs_interval <= 2:
|
||||
interval_types['step'] += 1
|
||||
elif abs_interval <= 4:
|
||||
interval_types['small_leap'] += 1
|
||||
elif abs_interval == 12:
|
||||
interval_types['octave'] += 1
|
||||
else:
|
||||
interval_types['large_leap'] += 1
|
||||
|
||||
total = len(intervals)
|
||||
distribution = {k: v/total for k, v in interval_types.items()} if total > 0 else interval_types
|
||||
|
||||
return {
|
||||
'distribution': distribution,
|
||||
'stepwise_ratio': distribution['step'],
|
||||
'leap_ratio': distribution['small_leap'] + distribution['large_leap']
|
||||
}
|
||||
|
||||
def _analyze_key_and_mode(self, pitches: List[int]) -> Dict[str, Any]:
|
||||
"""分析调性和调式"""
|
||||
if not pitches:
|
||||
return {'key': 'Unknown', 'modes': {}, 'scale_notes': []}
|
||||
|
||||
# 统计音高类别
|
||||
pitch_classes = [p % 12 for p in pitches]
|
||||
pc_counts = {}
|
||||
for pc in pitch_classes:
|
||||
pc_counts[pc] = pc_counts.get(pc, 0) + 1
|
||||
|
||||
# 尝试匹配五声音阶
|
||||
best_key = 'C'
|
||||
best_score = 0
|
||||
|
||||
for key, scale in self.pentatonic_scales.items():
|
||||
score = sum(pc_counts.get(pc, 0) for pc in scale)
|
||||
if score > best_score:
|
||||
best_score = score
|
||||
best_key = key
|
||||
|
||||
# 生成调式信息
|
||||
note_names = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
|
||||
scale_notes = [note_names[pc] for pc in self.pentatonic_scales[best_key]]
|
||||
|
||||
# 简化的调式检测
|
||||
modes = {
|
||||
'pentatonic': best_score / len(pitches) if pitches else 0,
|
||||
'major': 0.5, # 占位符
|
||||
'minor': 0.3 # 占位符
|
||||
}
|
||||
|
||||
return {
|
||||
'key': best_key,
|
||||
'modes': modes,
|
||||
'scale_notes': scale_notes
|
||||
}
|
||||
|
||||
def _extract_melody_contour(self, pitches: List[int]) -> List[int]:
|
||||
"""提取旋律轮廓"""
|
||||
if len(pitches) < 2:
|
||||
return []
|
||||
|
||||
contour = []
|
||||
for i in range(1, len(pitches)):
|
||||
diff = pitches[i] - pitches[i-1]
|
||||
if diff > 0:
|
||||
contour.append(1) # 上行
|
||||
elif diff < 0:
|
||||
contour.append(-1) # 下行
|
||||
else:
|
||||
contour.append(0) # 平行
|
||||
|
||||
return contour
|
||||
|
||||
def _identify_phrases(self, notes: List[Dict], ticks_per_beat: int) -> List[Tuple[int, int]]:
|
||||
"""识别乐句结构"""
|
||||
if not notes:
|
||||
return []
|
||||
|
||||
# 简单的乐句分割:基于较长的休止或时间间隔
|
||||
phrases = []
|
||||
phrase_start = 0
|
||||
|
||||
for i in range(1, len(notes)):
|
||||
# 检测乐句间隔(如果两个音符间隔超过一拍)
|
||||
gap = notes[i]['start_time'] - (notes[i-1]['start_time'] + notes[i-1]['duration'])
|
||||
if gap > ticks_per_beat: # 超过一拍的间隔
|
||||
phrases.append((phrase_start, i-1))
|
||||
phrase_start = i
|
||||
|
||||
# 添加最后一个乐句
|
||||
phrases.append((phrase_start, len(notes)-1))
|
||||
|
||||
return phrases
|
||||
|
||||
def _calculate_range_overlap(self, range1: Tuple[int, int], range2: Tuple[int, int]) -> float:
|
||||
"""计算两个音域的重叠度"""
|
||||
overlap_start = max(range1[0], range2[0])
|
||||
overlap_end = min(range1[1], range2[1])
|
||||
|
||||
if overlap_start >= overlap_end:
|
||||
return 0.0
|
||||
|
||||
overlap_size = overlap_end - overlap_start
|
||||
range1_size = range1[1] - range1[0]
|
||||
|
||||
return overlap_size / range1_size if range1_size > 0 else 0.0
|
||||
|
||||
def _calculate_interval_variety(self, notes: List[Dict]) -> float:
|
||||
"""计算音程变化丰富度"""
|
||||
if len(notes) < 2:
|
||||
return 0.0
|
||||
|
||||
pitches = [note['pitch'] for note in notes]
|
||||
intervals = [abs(pitches[i+1] - pitches[i]) for i in range(len(pitches)-1)]
|
||||
unique_intervals = len(set(intervals))
|
||||
|
||||
return unique_intervals / len(intervals) if intervals else 0.0
|
||||
|
||||
def calculate_complexity(self, melody_features: MelodyFeatures, lyrics_info: Dict = None) -> float:
|
||||
"""计算旋律复杂度(0-100分)"""
|
||||
try:
|
||||
# 节奏复杂度 (0-40分)
|
||||
rhythm_score = 0
|
||||
if hasattr(melody_features, 'rhythm_patterns'):
|
||||
syncopation = melody_features.rhythm_patterns.get('syncopation', 0)
|
||||
sixteenth = melody_features.rhythm_patterns.get('sixteenth', 0)
|
||||
rhythm_score = min(40, (syncopation + sixteenth) * 0.4)
|
||||
|
||||
# 音程复杂度 (0-30分)
|
||||
interval_score = 0
|
||||
if hasattr(melody_features, 'interval_distribution'):
|
||||
large_leap = melody_features.interval_distribution.get('large_leap', 0)
|
||||
interval_score = min(30, large_leap * 0.3)
|
||||
|
||||
# 调式不确定性 (0-30分)
|
||||
modal_score = 0
|
||||
if hasattr(melody_features, 'mode_analysis'):
|
||||
# 如果调式分析有置信度信息
|
||||
max_confidence = max(melody_features.mode_analysis.values()) if melody_features.mode_analysis else 0
|
||||
modal_uncertainty = 1 - max_confidence
|
||||
modal_score = modal_uncertainty * 30
|
||||
|
||||
total_complexity = rhythm_score + interval_score + modal_score
|
||||
return min(100, total_complexity)
|
||||
|
||||
except Exception:
|
||||
return 30.0 # 默认中等复杂度
|
||||
|
||||
def recommend_creation_mode(self, melody_features: MelodyFeatures, lyrics_info: Dict = None) -> Dict[str, Any]:
|
||||
"""基于旋律特征推荐创作模式"""
|
||||
try:
|
||||
# 计算整体复杂度
|
||||
complexity = self.calculate_complexity(melody_features, lyrics_info)
|
||||
|
||||
# 段落数量(从歌词信息获取)
|
||||
section_count = 0
|
||||
if lyrics_info and 'structure' in lyrics_info:
|
||||
sections = lyrics_info['structure'].get('sections', [])
|
||||
section_count = len(sections)
|
||||
|
||||
# 推荐逻辑
|
||||
if complexity >= 60:
|
||||
recommended = "expert"
|
||||
reason = f"旋律复杂度高 ({complexity:.1f}/100),建议使用专家模式进行精细控制"
|
||||
elif complexity <= 25:
|
||||
recommended = "express"
|
||||
reason = f"旋律相对简单 ({complexity:.1f}/100),适合快速模式自动生成"
|
||||
elif section_count >= 4:
|
||||
recommended = "coach"
|
||||
reason = f"歌曲结构复杂 ({section_count}个段落),建议教练模式逐步创作"
|
||||
else:
|
||||
recommended = "professional"
|
||||
reason = f"旋律复杂度适中 ({complexity:.1f}/100),推荐专业模式平衡效率与质量"
|
||||
|
||||
# 备选方案
|
||||
alternatives = []
|
||||
if recommended != "express":
|
||||
alternatives.append({"mode": "express", "reason": "需要快速原型或demo时使用"})
|
||||
if recommended != "professional":
|
||||
alternatives.append({"mode": "professional", "reason": "平衡创作质量与效率的通用选择"})
|
||||
if recommended != "coach":
|
||||
alternatives.append({"mode": "coach", "reason": "学习创作技巧或深度个性化表达时使用"})
|
||||
if recommended != "expert":
|
||||
alternatives.append({"mode": "expert", "reason": "需要完全控制创作过程的专业制作"})
|
||||
|
||||
return {
|
||||
"recommended": recommended,
|
||||
"complexity_score": complexity,
|
||||
"reasoning": reason,
|
||||
"section_count": section_count,
|
||||
"alternatives": alternatives
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
# 错误时返回默认推荐
|
||||
return {
|
||||
"recommended": "professional",
|
||||
"complexity_score": 50.0,
|
||||
"reasoning": "分析过程中出现问题,推荐使用通用的专业模式",
|
||||
"section_count": 0,
|
||||
"alternatives": [],
|
||||
"error": f"推荐逻辑错误: {str(e)}"
|
||||
}
|
||||
|
||||
def _create_error_result(self, error_type: str, message: str, details: Dict = None) -> Dict[str, Any]:
|
||||
"""创建错误结果"""
|
||||
result = {
|
||||
"status": "error",
|
||||
"error_type": error_type,
|
||||
"message": message,
|
||||
"timestamp": __import__('datetime').datetime.now().isoformat()
|
||||
}
|
||||
|
||||
if details:
|
||||
result["details"] = details
|
||||
|
||||
return result
|
||||
|
||||
def main():
|
||||
"""命令行入口"""
|
||||
parser = argparse.ArgumentParser(description="专业级 MIDI 音乐分析器")
|
||||
parser.add_argument("midi_file", help="MIDI 文件路径")
|
||||
parser.add_argument("--lyrics", help="歌词文件路径(可选)")
|
||||
parser.add_argument("--output", help="输出 JSON 文件路径(可选)")
|
||||
parser.add_argument("--pretty", action="store_true", help="格式化 JSON 输出")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# 创建分析器
|
||||
analyzer = ProfessionalMidiAnalyzer()
|
||||
|
||||
# 执行分析
|
||||
result = analyzer.analyze_midi_file(args.midi_file, args.lyrics)
|
||||
|
||||
# 输出结果
|
||||
if args.pretty:
|
||||
output = json.dumps(result, ensure_ascii=False, indent=2)
|
||||
else:
|
||||
output = json.dumps(result, ensure_ascii=False)
|
||||
|
||||
if args.output:
|
||||
with open(args.output, 'w', encoding='utf-8') as f:
|
||||
f.write(output)
|
||||
print(f"分析结果已保存到: {args.output}")
|
||||
else:
|
||||
print(output)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user