from mido import Message, MidiFile, MidiTrack, MetaMessage
# 简谱音符到 MIDI 音符的映射,包含低音、中音和高音
note_mapping = {
# 低2音区
"1..": 34, # 低2八度的do
"2..": 36, # 低2八度的re
"3..": 38, # 低2八度的mi
"4..": 40, # 低2八度的fa
"5..": 42, # 低2八度的sol
"6..": 44, # 低2八度的la
"7..": 46, # 低2八度的si
# 低音区
"1.": 48, # 低八度的do
"2.": 50, # 低八度的re
"3.": 52, # 低八度的mi
"4.": 53, # 低八度的fa
"5.": 55, # 低八度的sol
"6.": 57, # 低八度的la
"7.": 59, # 低八度的si
# 中音区
"1": 60, # do
"2": 62, # re
"3": 64, # mi
"4": 65, # fa
"5": 67, # sol
"6": 69, # la
"7": 71, # si
# 高音区
"1'": 72, # 高八度的do
"2'": 74, # 高八度的re
"3'": 76, # 高八度的mi
"4'": 77, # 高八度的fa
"5'": 79, # 高八度的sol
"6'": 81, # 高八度的la
"7'": 83, # 高八度的si
# 高2音区
"1''": 72, # 高2八度的do
"2''": 74, # 高2八度的re
"3''": 76, # 高2八度的mi
"4''": 77, # 高2八度的fa
"5''": 79, # 高2八度的sol
"6''": 81, # 高2八度的la
"7''": 83, # 高2八度的si
"0": 0 # 表示休止符之类的,这里简单处理
}
# 以字符串形式输入的第一个简谱,音符数字之间没有空格
simple_score_str1 = "00006'6'7'7'1''1''7'7'6'6'3'3'1'1'665'5'4'4'3'4'5'4'4'000004'4'5'5'6'6'7'7'5'5'2'2'4'4'3'3'2'3'4'3'000003'61'3'2'3'61'3'2'3'61'4'3'4'61'4'3'4'4'3'4'4'5'5'6'5'6'3'000003''6'1''3''2''3''6'1''3''2''3''6'1''4''3''4''6'1''4''3''4''4''3''4''4''5''5''6''5''6''3''00001''3'3'4'4'2'2'7'7'2'2'3'3'1'1'6'5'6'1'1'2'2'73'2'3'000001''01''1''2''2''1''7'6'5'5'6'5'3'0000001''1''1''1''2''2''1''7'6'5'5'6'5'6'0000000"
# 以字符串形式输入的第二个简谱,音符数字之间没有空格
simple_score_str2 = "6..3.013.013.0103.00006..0300103.0103.0103.002.06.00406.0406.005..02.007.02.007.02.007.001.005.003003.006..003.0013.0103006..003.0012.06040006.0406.005..02.007.001.17.006..003.0013.0103006..003.0012.06040006.0406.005..02.007.001.17.006..003.0012.0604005..02.007.01.001.005.007..006..03.17..0006..03.17..4.02000"
# 处理第一个简谱字符串,将其转换为音符和时长的列表
simple_score1 = []
i = 0
while i < len(simple_score_str1):
if simple_score_str1[i].isdigit():
if i + 1 < len(simple_score_str1) and simple_score_str1[i + 1] in [".", "'"]:
note = simple_score_str1[i:i + 2]
i += 2
else:
note = simple_score_str1[i]
i += 1
simple_score1.append((note, 1)) # 每个音符默认占一拍
else:
i += 1
# 处理第二个简谱字符串,将其转换为音符和时长的列表
simple_score2 = []
i = 0
while i < len(simple_score_str2):
if simple_score_str2[i].isdigit():
if i + 1 < len(simple_score_str2) and simple_score_str2[i + 1] in [".", "'"]:
note = simple_score_str2[i:i + 2]
i += 2
else:
note = simple_score_str2[i]
i += 1
simple_score2.append((note, 1)) # 每个音符默认占一拍
else:
i += 1
mid = MidiFile()
# 第一个音轨
track1 = MidiTrack()
mid.tracks.append(track1)
# 设置第一个音轨的速度为 120 BPM (500000 us per beat)
tempo = 200000
track1.append(MetaMessage('set_tempo', tempo=tempo, time=0))
# 设置第一个音轨的乐器(例如,钢琴,program=0)
track1.append(Message('program_change', program=0, time=0))
# 时间变量,用于计算第一个音轨 MIDI 消息之间的时间间隔
current_time1 = 50
# 遍历第一个简谱,将其转换为 MIDI 消息
for note, duration in simple_score1:
if note in note_mapping:
midi_note = note_mapping[note]
# 音符开启消息
track1.append(Message('note_on', note=midi_note, velocity=64, time=current_time1))
current_time1 = 0
# 音符关闭消息
track1.append(Message('note_off', note=midi_note, velocity=127, time=duration * 480))
else:
print(f"不支持的音符: {note}")
# 第二个音轨
track2 = MidiTrack()
mid.tracks.append(track2)
# 设置第二个音轨的速度为 120 BPM (500000 us per beat)
track2.append(MetaMessage('set_tempo', tempo=tempo, time=0))
# 设置第二个音轨的乐器(例如,吉他,program=24)
track2.append(Message('program_change', program=24, time=0))
# 时间变量,用于计算第二个音轨 MIDI 消息之间的时间间隔
current_time2 = 50
# 遍历第二个简谱,将其转换为 MIDI 消息
for note, duration in simple_score2:
if note in note_mapping:
midi_note = note_mapping[note]
# 音符开启消息
track2.append(Message('note_on', note=midi_note, velocity=64, time=current_time2))
current_time2 = 0
# 音符关闭消息
track2.append(Message('note_off', note=midi_note, velocity=127, time=duration * 480))
else:
print(f"不支持的音符: {note}")
mid.save('梦中的婚礼.mid')
Python双音轨简谱生成mid音频文件程序代码
于 2025-04-22 07:17:51 首次发布
1833

被折叠的 条评论
为什么被折叠?



