code-to-musicSkill code-to-music

这是一个利用代码创作音乐的技能,提供工具和模式生成具有真实乐器声音的.mp3文件。用户可以根据请求创作自定义音乐作品,但不能复制现有歌曲或旋律。此技能不适用于声乐音乐、音频混音/母带处理、实时MIDI播放或专业录音室录制质量的音乐。

AIGC 0 次安装 0 次浏览 更新于 3/3/2026

name: code-to-music description: 用于通过代码创作音乐的工具、模式和实用程序。输出为带有真实乐器声音的.mp3文件。编写自定义作品,通过音乐将创造力变为现实。此技能应用于用户要求创作音乐时。绝不用于复制歌曲、节奏、旋律或其他敏感作品。此技能不适用于声乐/歌词音乐、音频混音/母带处理(混响、均衡、压缩)、实时MIDI播放或专业录音室录制质量。

此技能提供工具和模式用于音乐创作,而不是预制解决方案。应使用智能和music21库根据用户请求动态创作音乐。

核心原则:编写自定义代码以算法方式创作音乐,而不是调用带有硬编码旋律的函数。

安装与设置

快速安装

运行自动化安装程序进行完整设置:install.sh。这将安装所有系统依赖项、Python包并验证安装。

注意:安装脚本最后可能显示“错误:外部管理环境”消息。这些是预期的,可以安全忽略 - 依赖项已经安装。如果出现这些消息,安装成功。

可用SoundFonts

传统管道(管弦乐/原声):

  • /usr/share/sounds/sf2/FluidR3_GM.sf2(141MB,通用MIDI声音字体 - 用于高质量的管弦乐/原声样本)
  • /usr/share/sounds/sf2/default.sf2(指向最佳可用的symlink)
  • ⚠️ 不要使用TimGM6mb.sf2 - 质量较差,吉他听起来电子/类似钢琴

电子管道:

  • 使用与传统音乐相同的FluidR3_GM.sf2声音字体
  • 不同之处在于你选择的GM程序(合成器程序38-39, 80-95而不是管弦乐)

关键概念

  • 始终创建可下载的MP3文件(而不是HTML播放器)
  • 可以使用music21.instrument类以方便:instrument.Violin(), instrument.Violoncello(), instrument.Piano(), instrument.Trumpet()等。
  • 关键:始终使用mido设置MIDI程序编号后导出 - music21的instrument类不可靠地导出program_change消息。见下面的mido工作流程。
  • 程序性生成音符 - 避免硬编码序列

选择您的音乐生成管道

此技能支持两种针对不同音乐风格的优化渲染管道。仔细阅读用户请求并根据读取正确的下一个文件选择正确的管道。

决策过程

从用户请求中识别:

  • 流派关键词(house, techno, classical, orchestral, reggae)
  • 乐器参考(合成器与原声乐器)
  • 音乐风格描述(电子/DJ与传统/原声)
  • 艺术家提及(DJs与古典作曲家)

电子管道

当请求包括时使用electronic-music-pipeline.md

  • 流派:House, techno, trance, EDM, electronic dance music, ambient electronic, acid house, deep house, club music, DJ sets
  • 乐器:Synthesizers, synth bass/pads/leads, 808 drums, electronic drums, supersaw leads, sub-bass
  • 上下文:提到DJ(Keinemusik, Black Coffee, Avicii, Swedish House Mafia), BPM 120-140, “for a club”, “for dancing”
  • 声音描述:“Fat synth sound”, “buzzy leads”, “electronic”, “synth-heavy”

工作原理:

  • 使用实时合成(无声音字体)
  • 实时合成鼓,低音,垫子,引导DSP
  • 流派预设优化合成参数(deep_house, techno, trance, ambient, acid_house)
  • 频率感知混音自动平衡低/中/高频率
  • 最适合:正宗电子声音,现代EDM制作

→ 见electronic-music-pipeline.md了解详细说明


传统管道

当请求包括时使用traditional-music-pipeline.md

  • 流派:Classical, orchestral, jazz, blues, rock, country, folk, reggae, ska, symphonic, chamber music
  • 乐器:Violin, cello, trumpet, flute, piano, acoustic guitar, acoustic bass, brass ensembles, string quartets, organ (reggae/gospel)
  • 上下文:提到作曲家(Mozart, Beethoven, Bach), 古典时期(Baroque, Romantic), “unplugged”, “acoustic version”
  • 声音描述:“Traditional”, “acoustic”, “orchestral”

工作原理:

  • 使用预录音的管弦乐样本(声音字体)
  • FluidR3_GM.sf2声音字体与128种通用MIDI乐器
  • 适用于逼真的管弦乐/原声乐器
  • 最适合:古典,爵士,雷鬼,摇滚,传统音乐

→ 见traditional-music-pipeline.md了解详细说明


如果不清楚

  • 默认为TRADITIONAL用于混合请求或模糊流派
  • 如果请求可以两者兼而有之,请向用户询问澄清

为什么这很重要

  • 使用错误的管道 = 音频质量差(技术上可行,听起来不好)
  • 电子管道:实时合成以获得正宗的电子声音
  • 传统管道:预录音样本以获得逼真的管弦乐/原声

可用脚本

所有脚本位于./scripts

传统渲染:

  • midi_inventory.py - 从任何MIDI文件中提取完整结构到JSON格式
  • midi_render.py - 使用FluidSynth和动态范围压缩将JSON音乐结构渲染为MP3
  • midi_utils.py - MIDI实用程序函数(提取鼓,获取BPM等)

实用工具:

  • audio_validate.py - 验证音频文件质量和格式

注意:电子和传统音乐都使用相同的渲染管道(FluidSynth + FluidR3_GM.sf2)。不同之处在于你选择的GM程序。

音乐理论参考

完整的通用MIDI乐器地图(程序0-127)

关键:music21不可靠地导出程序更改消息。即使使用instrument.TenorSaxophone()或instrument.AcousticGuitar()等乐器类,也必须始终使用mido在导出后设置程序编号。没有这一步,所有曲目将默认为钢琴(程序0)。

合成乐器分类: 当创作电子音乐时,根据其声音特征对乐器进行分类,以进行适当的合成:

  • 吉他(24-31):弹拨攻击,明亮的音色,中等持续时间 - 需要与垫子不同的合成
  • 低音(32-39):低频基频,次低音能量,短攻击
  • 弦乐(40-47):持续的弓法,丰富的和声,平滑的连奏
  • 铜管(56-63):明亮的攻击,持续的音色,强大的投射
  • 簧片/木管(64-79):呼吸攻击,有机的音色,表现力强的动态
  • 合成主音(80-87):明亮,切割,激进 - 专为旋律而设计
  • 合成垫(88-95):软攻击,长持续时间,大气 - 专为背景而设计
  • 民族/打击乐(104-119):具有独特音色的弹拨或敲击声音
# 钢琴(0-7)
0: "Acoustic Grand Piano"
1: "Bright Acoustic Piano"
2: "Electric Grand Piano"
3: "Honky-tonk Piano"
4: "Electric Piano 1"
5: "Electric Piano 2"
6: "Harpsichord"
7: "Clavinet"

# 色彩打击乐(8-15)
8: "Celesta"
9: "Glockenspiel"
10: "Music Box"
11: "Vibraphone"
12: "Marimba"
13: "Xylophone"
14: "Tubular Bells"
15: "Dulcimer"

# 风琴(16-23)
16: "Drawbar Organ"
17: "Percussive Organ"
18: "Rock Organ"
19: "Church Organ"
20: "Reed Organ"
21: "Accordion"
22: "Harmonica"
23: "Tango Accordion"

# 吉他(24-31)
24: "Acoustic Guitar (nylon)"
25: "Acoustic Guitar (steel)"
26: "Electric Guitar (jazz)"
27: "Electric Guitar (clean)"
28: "Electric Guitar (muted)"
29: "Overdriven Guitar"
30: "Distortion Guitar"
31: "Guitar Harmonics"

# 低音(32-39)
32: "Acoustic Bass"
33: "Electric Bass (finger)"
34: "Electric Bass (pick)"
35: "Fretless Bass"
36: "Slap Bass 1"
37: "Slap Bass 2"
38: "Synth Bass 1"
39: "Synth Bass 2"

# 弦乐(40-47)
40: "Violin"
41: "Viola"
42: "Cello"
43: "Contrabass"
44: "Tremolo Strings"
45: "Pizzicato Strings"
46: "Orchestral Harp"
47: "Timpani"

# 合奏(48-55)
48: "String Ensemble 1"
49: "String Ensemble 2"
50: "Synth Strings 1"
51: "Synth Strings 2"
52: "Choir Aahs"
53: "Voice Oohs"
54: "Synth Voice"
55: "Orchestra Hit"

# 铜管(56-63)
56: "Trumpet"
57: "Trombone"
58: "Tuba"
59: "Muted Trumpet"
60: "French Horn"
61: "Brass Section"
62: "Synth Brass 1"
63: "Synth Brass 2"

# 簧片(64-71)
64: "Soprano Sax"
65: "Alto Sax"
66: "Tenor Sax"
67: "Baritone Sax"
68: "Oboe"
69: "English Horn"
70: "Bassoon"
71: "Clarinet"

# 管乐(72-79)
72: "Piccolo"
73: "Flute"
74: "Recorder"
75: "Pan Flute"
76: "Blown Bottle"
77: "Shakuhachi"
78: "Whistle"
79: "Ocarina"

# 合成主音(80-87)
80: "Lead 1 (square)"
81: "Lead 2 (sawtooth)"
82: "Lead 3 (calliope)"
83: "Lead 4 (chiff)"
84: "Lead 5 (charang)"
85: "Lead 6 (voice)"
86: "Lead 7 (fifths)"
87: "Lead 8 (bass + lead)"

# 合成垫(88-95)
88: "Pad 1 (new age)"
89: "Pad 2 (warm)"
90: "Pad 3 (polysynth)"
91: "Pad 4 (choir)"
92: "Pad 5 (bowed)"
93: "Pad 6 (metallic)"
94: "Pad 7 (halo)"
95: "Pad 8 (sweep)"

# 合成效果(96-103)
96: "FX 1 (rain)"
97: "FX 2 (soundtrack)"
98: "FX 3 (crystal)"
99: "FX 4 (atmosphere)"
100: "FX 5 (brightness)"
101: "FX 6 (goblins)"
102: "FX 7 (echoes)"
103: "FX 8 (sci-fi)"

# 民族(104-111)
104: "Sitar"
105: "Banjo"
106: "Shamisen"
107: "Koto"
108: "Kalimba"
109: "Bag pipe"
110: "Fiddle"
111: "Shanai"

# 打击乐(112-119)
112: "Tinkle Bell"
113: "Agogo"
114: "Steel Drums"
115: "Woodblock"
116: "Taiko Drum"
117: "Melodic Tom"
118: "Synth Drum"
119: "Reverse Cymbal"

# 音效(120-127)
120: "Guitar Fret Noise"
121: "Breath Noise"
122: "Seashore"
123: "Bird Tweet"
124: "Telephone Ring"
125: "Helicopter"
126: "Applause"
127: "Gunshot"

完整的鼓映射(MIDI通道10,音符35-81)

鼓使用音符编号表示不同的声音,而不是音高。必须在通道10(0索引为9)上。

# 低音鼓
35: "Acoustic Bass Drum"
36: "Bass Drum 1"  # 最常见的低音鼓

# 军鼓
38: "Acoustic Snare"  # 标准军鼓
40: "Electric Snare"

# 通鼓
41: "Low Floor Tom"
43: "High Floor Tom"
45: "Low Tom"
47: "Low-Mid Tom"
48: "Hi-Mid Tom"
50: "High Tom"

# 踩镲
42: "Closed Hi-Hat"  # 最常用
44: "Pedal Hi-Hat"
46: "Open Hi-Hat"

# 钹
49: "Crash Cymbal 1"
51: "Ride Cymbal 1"
52: "Chinese Cymbal"
53: "Ride Bell"
55: "Splash Cymbal"
57: "Crash Cymbal 2"
59: "Ride Cymbal 2"

# 打击乐
37: "Side Stick"
39: "Hand Clap"
54: "Tambourine"
56: "Cowbell"
58: "Vibraslap"
60: "Hi Bongo"
61: "Low Bongo"
62: "Mute Hi Conga"
63: "Open Hi Conga"
64: "Low Conga"
65: "High Timbale"
66: "Low Timbale"
67: "High Agogo"
68: "Low Agogo"
69: "Cabasa"
70: "Maracas"
71: "Short Whistle"
72: "Long Whistle"
73: "Short Guiro"
74: "Long Guiro"
75: "Claves"
76: "Hi Wood Block"
77: "Low Wood Block"
78: "Mute Cuica"
79: "Open Cuica"
80: "Mute Triangle"
81: "Open Triangle"

如何使用任何乐器(mido工作流程)

关键规则:music21不可靠地导出program_change消息,即使使用instrument.TenorSaxophone()或instrument.AcousticGuitar()等乐器类。导出到MIDI后,必须始终使用mido手动插入程序更改消息。没有这一步,所有曲目听起来都会像钢琴(程序0)。

常见错误:假设sax_part.insert(0, instrument.TenorSaxophone())会自动使曲目听起来像萨克斯。它不会!仍然必须使用mido设置程序编号。

设置乐器的辅助函数

from mido import Message
def set_track_instrument(track, program):
    """在MIDI轨道的开头插入程序更改消息。"""
    # 查找所有元消息之后的位置(track_name等)
    insert_pos = 0
    for j, msg in enumerate(track):
        if not msg.is_meta:  # 在第一个非元消息之前插入
            insert_pos = j
            break
    else:
        # 如果所有消息都是元消息,则在末尾插入
        insert_pos = len(track)
    track.insert(insert_pos, Message('program_change', program=program, time=0))

# 使用mido加载MIDI后的用法:
# set_track_instrument(mid.tracks[2], 33)  # 将第二轨设置为电贝斯

第1步:使用music21进行创作(使用占位符或跳过乐器)

from music21 import stream, note, chord, tempo

score = stream.Score()

# 创建部分 - 现在不用担心乐器分配
synth_lead = stream.Part()
synth_pad = stream.Part()
bass = stream.Part()

# 使用.insert()添加你的音符/和弦,使用显式定时
# 关键:始终使用.insert(offset, note)而不是.append(note)
offset = 0.0
synth_lead.insert(offset, note.Note('E5', quarterLength=1.0))
offset += 1.0
synth_lead.insert(offset, note.Note('G5', quarterLength=1.0))
# ... 使用.insert()创作你的音乐

score.append(synth_lead)
score.append(synth_pad)
score.append(bass)

# 导出到MIDI
midi_path = # 定义一个输出路径
score.write('midi', fp=midi_path)

第2步:检查MIDI结构并使用mido分配乐器

from mido import MidiFile, Message

mid = MidiFile(midi_path)

# 关键:不要假设轨道号码!首先检查MIDI文件。
# 打印轨道结构,看看存在哪些轨道
print(f"总轨道数:{len(mid.tracks)}")
for i, track in enumerate(mid.tracks):
    note_count = sum(1 for msg in track if msg.type == 'note_on' and msg.velocity > 0)
    print(f"轨道 {i}: {note_count} 音符")

# 辅助函数设置乐器def set_track_instrument(track, program):
    """在MIDI轨道的开头插入程序更改消息。"""
    insert_pos = 0
    for j, msg in enumerate(track):
        if not msg.is_meta:
            insert_pos = j
            break
    else:
        insert_pos = len(track)
    track.insert(insert_pos, Message('program_change', program=program, time=0))

# 根据检查,为正确的轨道分配乐器
# 示例:如果[鼓,低音,吉他]被追加,检查显示轨道1, 2, 3有音符:
set_track_instrument(mid.tracks[1], 80)  # 第一部分 - 正方形主音
set_track_instrument(mid.tracks[2], 88)  # 第二部分 - 垫子
set_track_instrument(mid.tracks[3], 38)  # 第三部分 - 低音

mid.save(midi_path)

第3步:对于鼓,还要将通道设置为9(通道10)

# 如果轨道是鼓,将所有消息设置为通道9
for i, track in enumerate(mid.tracks):
    if i == 1:  # 这是鼓轨道
        for msg in track:
            if hasattr(msg, 'channel'):
                msg.channel = 9  # 1索引中的通道10

第4步:渲染为音频

from midi2audio import FluidSynth
from pydub import AudioSegment

fs = FluidSynth('/usr/share/sounds/sf2/FluidR3_GM.sf2')
wav_path = # 定义一个路径
fs.midi_to_audio(midi_path, wav_path)

audio = AudioSegment.from_wav(wav_path)
mp3_path = # 定义一个路径
audio.export(mp3_path, format='mp3', bitrate='192k')

常见和弦进程与风格

# 标准进程(罗马数字)
"pop": ["I", "V", "vi", "IV"]           # C-G-Am-F (Journey, Adele)
"epic": ["i", "VI", "III", "VII"]       # Am-F-C-G (Epic trailer music)
"sad": ["i", "VI", "iv", "V"]           # Am-F-Dm-E (Melancholic)
"jazz": ["ii", "V", "I", "vi"]          # Dm-G-C-Am (Jazz standard)
"classical": ["I", "IV", "V", "I"]      # C-F-G-C (Classical cadence)
"blues": ["I", "I", "I", "I", "IV", "IV", "I", "I", "V", "IV", "I", "I"]  # 12-bar blues
"house": ["i", "VI", "III", "VII"]      # _minor house progression
"reggae": ["I", "V", "vi", "IV"]        # Offbeat rhythm style
"country": ["I", "IV", "V", "I"]        # Simple and direct
"rock": ["I", "bVII", "IV", "I"]        # Power chord style
"r&b": ["I", "V", "vi", "iii", "IV", "I", "IV", "V"]  # Complex R&B

# 流派特定特征
STYLES = {
    "house": {
        "bpm": 120-128,
        "time_signature": "4/4",
        "drum_pattern": "4-on-floor kick, offbeat hats",
        "bass": "Synth bass with groove",
        "common_instruments": [38, 80, 88, 4]  # Synth bass, lead, pad, e-piano
    },
    "jazz": {
        "bpm": 100-180,
        "time_signature": "4/4 or 3/4",
        "chords": "Extended (7th, 9th, 11th, 13th)",
        "common_instruments": [0, 32, 64, 56, 73]  # Piano, bass, sax, trumpet, drums
    },
    "orchestral": {
        "bpm": 60-140,
        "sections": ["strings", "woodwinds", "brass", "percussion"],
        "common_instruments": [40, 41, 42, 56, 73, 47]  # Violin, viola, cello, trumpet, flute, timpani
    },
    "rock": {
        "bpm": 100-140,
        "time_signature": "4/4",
        "guitars": "Distorted (30) or clean (27)",
        "common_instruments": [30, 33, 0, 128]  # Distortion guitar, bass, piano, drums
    },
    "ambient": {
        "bpm": 60-90,
        "characteristics": "Long sustained notes, atmospheric pads",
        "common_instruments": [88, 89, 90, 91, 52]  # Various pads, choir
    },
    "trap": {
        "bpm": 130-170,
        "drums": "Tight snare rolls, 808 bass kicks",
        "hi_hats": "Fast hi-hat patterns (1/16 or 1/32 notes)",
        "common_instruments": [38, 128]  # Synth bass, drums
    }
}

music21乐器类

from music21 import instrument

# 弦乐
instrument.Violin()
instrument.Viola()
instrument.Violoncello()  # 注意:不是Cello()
instrument.Contrabass()
instrument.Harp()

# 钢琴
instrument.Piano()
instrument.Harpsichord()

# 铜管
instrument.Trumpet()
instrument.Trombone()
instrument.Tuba()
instrument.Horn()  # 法国号

# 木管
instrument.Flute()
instrument.Clarinet()
instrument.Oboe()
instrument.Bassoon()
instrument.SopranoSaxophone()
instrument.AltoSaxophone()
instrument.TenorSaxophone()  # 最常用于爵士乐
instrument.BaritoneSaxophone()

# 其他
instrument.AcousticGuitar()
instrument.ElectricGuitar()
instrument.Bass()
instrument.Timpani()

# 关键:music21对电子乐器和鼓的支持有限
# 对于合成器,鼓和电子声音,必须采取以下步骤:
# 1. 创建一个没有乐器的部分(或使用占位符如Piano())
# 2. 使用mido库在导出后插入程序更改消息
# 3. 将鼓设置为MIDI通道10(0索引为9)否则它们不会听起来像鼓
#
# 常见错误:
# - instrument.Cello()不存在 - 使用Violoncello()
# - instrument.FrenchHorn()不存在 - 使用Horn()
# - 设置part.partName不会改变声音 - 必须使用mido设置MIDI程序
# - 鼓在通道0上将播放为有音高音符,而不是鼓声

音符持续时间(四分音符=1.0)

  • 整音符:4.0
  • 半音符:2.0
  • 四分音符:1.0
  • 八分音符:0.5
  • 十六分音符:0.25
  • 点四分音符:1.5
  • 三连音四分音符:0.667

mido快速参考

对于电子音乐和鼓,使用mido在music21导出后设置MIDI程序:

from mido import MidiFile, Message

mid = MidiFile(midi_path)

# 定义辅助函数def set_track_instrument(track, program):
    """在MIDI轨道的开头插入程序更改消息。"""
    insert_pos = 0
    for j, msg in enumerate(track):
        if not msg.is_meta:
            insert_pos = j
            break
    else:
        insert_pos = len(track)
    track.insert(insert_pos, Message('program_change', program=program, time=0))

# 插入程序更改消息
for i, track in enumerate(mid.tracks):
    if i == 1:  # 你的轨道(轨道从1开始,不是0)
        set_track_instrument(track, 38)  # 合成贝斯1

# 对于鼓:将通道设置为9(1索引中的通道10)
for i, track in enumerate(mid.tracks):
    if i == 1:  # 鼓轨道
        for msg in track:
            if hasattr(msg, 'channel'):
                msg.channel = 9

mid.save(midi_path)

常见MIDI程序:

  • 38:合成贝斯1
  • 80:正方形主音
  • 81:锯形主音
  • 88:垫1(新时代)
  • 25:吉他(钢弦) - 响亮,穿透力强
  • 33:原声贝斯

常见技巧

鼓编程(4-on-floor house节奏)

关键:music21的.append()添加音符顺序(一个接一个),不是同时。对于需要叠加的鼓,其中kick,snare和hats同时播放,.insert(offset, note)必须与显式定时一起使用。

始终对部分使用.insert()添加音符:

由于几乎所有优秀的音乐创作都需要叠加,对于所有轨道 - 鼓,低音,吉他,pads等,必须始终使用part.insert(offset, note)。这可以防止定时错误,并确保正确同步。

从不混合.insert()和.append()向部分添加音符 - 如果对鼓使用.insert(),对其他乐器使用.append(),music21会错误地计算轨道长度,创建比预期长5-10倍的轨道(8分钟而不是1.5分钟),其中只有前20-25%包含实际声音。

正确模式:

# 对:对音符使用.insert(),对部分使用.append()
 drum_part = stream.Part()
 bass_part = stream.Part()

 offset = 0.0
 for beat in range(16):
    # 同时(叠加)的kick和hi-hat
    drum_part.insert(offset, note.Note(36, quarterLength=0.5))  # Kick
    drum_part.insert(offset, note.Note(42, quarterLength=0.5))  # Hi-hat

    # 低音音符
    bass_part.insert(offset, note.Note('A2', quarterLength=0.5))

    offset += 0.5  # 提升时间

# 将部分添加到得分(这个.append()可以)
score.append(drum_part)
score.append(bass_part)

确保完整的小节覆盖

关键:在循环创作时,确保你的音符完全填满每个小节,没有间隙。一个常见错误是放置音符没有跨越整个小节的持续时间,留下静音间隙。

问题模式(创建间隙):

bar_length = 1.5  # 6/8时间签名
 offset = 0.0

 for bar in range(8):
    # 只填充了第一个1.0四分之一长度,留下了0.5的静音!
    guitar_part.insert(offset, note.Note('D3', quarterLength=0.5))
    guitar_part.insert(offset + 0.5, chord.Chord(['D3', 'F#3', 'A3'], quarterLength=0.5))
    # 缺少:offset + 1.0到offset + 1.5

    offset += bar_length  # 推进到下一个小节,但间隙仍然存在

# 结果:吉他播放了10秒钟,然后剩余时间是静音

解决方案模式(完全覆盖):

bar_length = 1.5  # 6/8时间签名
 offset = 0.0

 for bar in range(8):
    # 用音符填满整个小节
    guitar_part.insert(offset, note.Note('D3', quarterLength=0.5))           # 0.0到0.5
    guitar_part.insert(offset + 0.5, chord.Chord(['D3', 'F#3', 'A3'], quarterLength=0.5))  # 0.5到1.0
    guitar_part.insert(offset + 1.0, note.Note('D3', quarterLength=0.5))     # 1.0到1.5 ✓ 完整!

    offset += bar_length

# 结果:吉他在整个作品中持续播放

最佳实践:在提升offset += bar_length之前,验证你的最后一个音符是否恰好在offset + bar_length结束。例如:

  • 如果bar_length = 1.5,你的最后一个音符应该在offset + 1.0开始,quarterLength=0.5到达offset + 1.5
  • 如果bar_length = 2.0,你的最后一个音符应该在offset + 1.5开始,quarterLength=0.5到达offset + 2.0

最佳实践

作曲质量

  • 生成多样性:不要为整个作品重复相同的4个小节
  • 使用音乐理论:真正的和弦进程,适当的声音引导
  • 尊重乐器范围:小提琴(G3-E7),大提琴(C2-C6),小号(E3-C6)
  • 添加动态:使用p, mp, mf, f, ff标记和渐强
  • 结构:引言 → 发展 → 高潮 → 解决
  • 添加人性化:变化时间和速度,避免机器人声音
    import random
    n = note.Note('C5', quarterLength=1.0 + random.uniform(-0.05, 0.05))
    n.volume.velocity = 80 + random.randint(-5, 5)
    

技术质量

  • 声音字体:使用FluidR3_GM.sf2获得最佳质量
  • 比特率:最低192kbps,高质量320kbps
  • 限制:通过audio.compress_dynamic_range()防止剪辑
  • 定时精度:仔细使用quarterLength值
  • 清理:在MP3转换后删除临时MIDI/WAV文件

常见陷阱

  • 关键:绝不假设轨道号码 - 不要盲目使用if i == 3用于吉他。始终首先使用音符计数验证哪个轨道是哪个
  • 关键:始终对部分使用part.insert(offset, note)添加音符 - 永远不要使用part.append(note)或混合使用.insert().append()。这会导致定时错误,其中轨道比预期长5-10倍,只有20-25%包含声音。见“鼓编程”部分详情
  • 关键:插入程序更改消息 - 使用track.insert(pos, Message('program_change', ...))而不是msg.program = X。见mido快速参考
  • 关键:设置速度 - 主音90-105,背景50-65。见“混合和平衡”部分
  • 关键:低音八度 - 使用A1-A2(55-110 Hz),绝不使用A0-G0(在大多数系统上听不见)
  • **instrument.Cello()**不存在 - 使用Violoncello()
  • 忘记节奏 - 在第一部分添加tempo.MetronomeMark()
  • 鼓听起来不像鼓 - 使用mido将通道设置为9(见mido快速参考)

混合和平衡

关键:仅设置MIDI程序编号是不够的。没有显式速度控制,一些乐器将完全听不见

设置速度

music21对所有音符使用默认速度64,导致混合不良。使用mido在MIDI导出后设置速度:

from mido import MidiFile
def set_track_velocity(track, velocity):
    """为轨道中的所有note_on消息设置速度。"""
    for msg in track:
        if msg.type == 'note_on' and msg.velocity > 0:
            msg.velocity = velocity

mid = MidiFile(midi_path)
for i, track in enumerate(mid.tracks):
    if i == 1:  # 鼓
        set_track_velocity(track, 75)
    elif i == 2:  # 低音
        set_track_velocity(track, 80)
    elif i == 3:  # 主乐器(萨克斯,吉他,小号)
        set_track_velocity(track, 95)
    elif i == 4:  # 背景(风琴,垫子)
        set_track_velocity(track, 55)
mid.save(midi_path)

速度指南

按角色:

  • 主乐器(旋律,独奏):90-105
  • 节奏乐器(吉他弹奏,伴奏):85-100
  • 低音:75-85
  • 鼓:70-90
  • 背景(垫子,风琴):50-65

按频率范围:

  • 低(20-250 Hz):低音,kick - 只有一个在75-85处占主导
  • 中(250-2000 Hz):最拥挤 - 使用速度分离(主音90+,背景50-65)
  • 高(2000+ Hz):Hi-hats, cymbals - 70-85清晰而不刺耳

声音字体级别问题

FluidR3_GM乐器以不同级别录制。即使速度正确,一些乐器可能听不见:

安静程序(避免用于主音/节奏):

  • 程序27(电吉他 - 干净)- 非常安静
  • 程序24(吉他 - 尼龙弦)
  • 程序73(长笛)

更好的选择

  • 程序25(吉他 - 钢弦)- 8-10dB更响亮,穿透力强
  • 程序28(电吉他 - 闷音)- 打击乐
  • 程序30(失真吉他)- 激进

额外修复

  • 增加音符持续时间(0.4 quarterLength最低vs 0.25)
  • 使用八度分隔(将竞争乐器移动到不同的八度)
  • 极端速度对比(安静乐器110,响亮40)

混合检查表

在渲染之前:

  • ✅ 主音在速度90-105
  • ✅ 背景在速度50-65
  • ✅ 低音在速度75-85
  • ✅ 检查安静乐器(程序24, 27, 73)并使用替代品
  • ✅ 节奏乐器的最低0.4 quarterLength

资源

限制

  • 仅限器乐 - 无歌词/声乐
  • 基于MIDI的合成 - 不是录音室质量录音
  • 无实时播放 - 文件必须在播放前渲染