import tkinter as tk
import pygame.midi
import time
import threading
import random
初始化 pygame.midi
pygame.midi.init()
获取 MIDI 输出设备
midi_out = pygame.midi.Output(0)
乐器名称映射
instrument_names = {
0: “大钢琴(声学钢琴)”,
1: “明亮的钢琴”,
2: “电钢琴”,
3: “酒吧钢琴”,
4: “柔和的电钢琴”,
5: “加合唱效果的电钢琴”,
6: “羽管键琴(拨弦古钢琴)”,
7: “科拉维科特琴(击弦古钢琴)”,
8: “钢片琴”,
9: “钟琴”,
10: “八音盒”,
11: “颤音琴”,
12: “马林巴”,
13: “木琴”,
14: “管钟”,
15: “大扬琴”,
16: “击杆风琴”,
17: “打击式风琴”,
18: “摇滚风琴”,
19: “教堂风琴”,
20: “簧管风琴”,
21: “手风琴”,
22: “口琴”,
23: “探戈手风琴”,
24: “尼龙弦吉他”,
25: “钢弦吉他”,
26: “爵士电吉他”,
27: “清音电吉他”,
28: “闷音电吉他”,
29: “加驱动效果的电吉他”,
30: “加失真效果的电吉他”,
31: “吉他和音”,
32: “大贝司(声学贝司)”,
33: “电贝司(指弹)”,
34: “电贝司(拨片)”,
35: “无品贝司”,
36: “掌击贝司”,
37: “掌击贝司”,
38: “电子合成贝司”,
39: “电子合成贝司”,
40: “小提琴”,
41: “中提琴”,
42: “大提琴”,
43: “低音大提琴”,
44: “弦乐群颤音音色”,
45: “弦乐群拨弦音色”,
46: “竖琴”,
47: “定音鼓”,
48: “弦乐合奏音色”,
49: “弦乐合奏音色”,
50: “合成弦乐合奏音色”,
51: “合成弦乐合奏音色”,
52: “人声合唱啊”,
53: “人声嘟”,
54: “合成人声”,
55: “管弦乐敲击齐奏”,
56: “小号”,
57: “长号”,
58: “大号”,
59: “加弱音器小号”,
60: “法国号(圆号)”,
61: “铜管组(铜管乐器合奏音色)”,
62: “合成铜管音色”,
63: “合成铜管音色”,
64: “高音萨克斯风”,
65: “次中音萨克斯风”,
66: “中音萨克斯风”,
67: “低音萨克斯风”,
68: “双簧管”,
69: “英国管”,
70: “巴松(大管)”,
71: “单簧管(黑管)”,
72: “短笛”,
73: “长笛”,
74: “竖笛”,
75: “排箫”,
76: “吹瓶声”,
77: “日本尺八”,
78: “口哨声”,
79: “奥卡雷那”,
80: “合成主音(方波)”,
81: “合成主音(锯齿波)”,
82: “合成主音”,
83: “合成主音”,
84: “合成主音”,
85: “合成主音(人声)”,
86: “合成主音(平行五度)”,
87: “合成主音(贝司加主音)”,
88: “合成音色(新世纪)”,
89: “合成音色(温暖)”,
90: “合成音色”,
91: “合成音色(合唱)”,
92: “合成音色”,
93: “合成音色(金属声)”,
94: “合成音色(光环)”,
95: “合成音色”,
96: “合成效果雨声”,
97: “合成效果音轨”,
98: “合成效果水晶”,
99: “合成效果大气”,
100: “合成效果明亮”,
101: “合成效果鬼怪”,
102: “合成效果回声”,
103: “合成效果科幻”,
104: “西塔尔(印度)”,
105: “班卓琴(美洲)”,
106: “三昧线(日本)”,
107: “十三弦筝(日本)”,
108: “卡林巴”,
109: “风笛”,
110: “民族提琴”,
111: “唢呐”,
112: “叮当铃”,
113: “阿哥哥鼓”,
114: “钢鼓”,
115: “木鱼”,
116: “太鼓”,
117: “古高音鼓”,
118: “合成鼓”,
119: “铜钹”,
120: “磨弦”,
121: “呼吸声”,
122: “海浪声”,
123: “鸟鸣”,
124: “电话铃”,
125: “直升机”,
126: “鼓掌声”,
127: “枪声”
}
def play_note(note_number, duration, instrument):
midi_out.set_instrument(instrument)
midi_out.note_on(note_number, 125)
pygame.time.wait(duration)
midi_out.note_off(note_number, 125)
root = tk.Tk()
root.title(“钢琴简谱播放器”)
设置窗口大小
root.geometry(“800x600”)
创建主旋律文本框
entry_main = tk.Text(root, wrap=“word”, height=5)
entry_main.pack(pady=10)
entry_main.place(x=10, y=120, width=500, height=100)
entry_main.insert(tk.END, “e5d1d1d1/,d3d2d1d2/,d3d1/,d1d3d5d6/,d6d5d3d3/,d1d2d1d2/,d3d1c6c6c5d1/,/,d6d5/,d3d3/,d1d2d1d2/,/,d6d5d3d3d5d6/,/,e1d5d3d3/,d1d2d1d2/,d3d1c6c6c5d1/,/,/,”)
创建伴奏文本框
entry_accompaniment = tk.Text(root, wrap=“word”, height=5)
entry_accompaniment.pack(pady=10)
entry_accompaniment.place(x=10, y=300, width=500, height=100)
entry_accompaniment.insert(tk.END, “e5d1d1d1/,d3d2d1d2/,d3d1/,d1d3d5d6/,d6d5d3d3/,d1d2d1d2/,d3d1c6c6c5d1/,/,d6d5/,d3d3/,d1d2d1d2/,/,d6d5d3d3d5d6/,/,e1d5d3d3/,d1d2d1d2/,d3d1c6c6c5d1/,/,/,”)
为主旋律选择乐器的下拉菜单
main_instrument_var = tk.StringVar(root)
default_main_instrument = 73
main_instrument_var.set(f"{default_main_instrument} - {instrument_names.get(default_main_instrument, ‘Unknown’)}“)
main_instrument_menu = tk.OptionMenu(root, main_instrument_var, *[f”{i} - {instrument_names.get(i, ‘Unknown’)}" for i in range(128)])
main_instrument_menu.pack(pady=10)
main_instrument_menu.place(x=20, y=60, width=150, height=50)
为伴奏选择乐器的下拉菜单
accompaniment_instrument_var = tk.StringVar(root)
default_accompaniment_instrument = 116
accompaniment_instrument_var.set(f"{default_accompaniment_instrument} - {instrument_names.get(default_accompaniment_instrument, ‘Unknown’)}“)
accompaniment_instrument_menu = tk.OptionMenu(root, accompaniment_instrument_var, *[f”{i} - {instrument_names.get(i, ‘Unknown’)}" for i in range(128)])
accompaniment_instrument_menu.pack(pady=10)
accompaniment_instrument_menu.place(x=20, y=250, width=150, height=50)
为主旋律选择调式的下拉菜单
main_tune_var = tk.StringVar(root)
default_main_tune = “G 大调”
main_tune_var.set(default_main_tune)
main_tune_menu = tk.OptionMenu(root, main_tune_var, “C 大调”, “D 大调”, “E 大调”, “F 大调”, “G 大调”, “A 大调”, “B 大调”)
main_tune_menu.pack(pady=10)
main_tune_menu.place(x=200, y=60, width=100, height=50)
为伴奏选择调式的下拉菜单
accompaniment_tune_var = tk.StringVar(root)
default_accompaniment_tune = “D 大调”
accompaniment_tune_var.set(default_accompaniment_tune)
accompaniment_tune_menu = tk.OptionMenu(root, accompaniment_tune_var, “C 大调”, “D 大调”, “E 大调”, “F 大调”, “G 大调”, “A 大调”, “B 大调”)
accompaniment_tune_menu.pack(pady=10)
accompaniment_tune_menu.place(x=200, y=250, width=100, height=50)
创建文本框的右键菜单
def show_textbox_menu(event):
menu = tk.Menu(root, tearoff=0)
menu.add_command(label=“剪切”, command=lambda: event.widget.event_generate(“<>”))
menu.add_command(label=“复制”, command=lambda: event.widget.event_generate(“<>”))
menu.add_command(label=“粘贴”, command=lambda: event.widget.event_generate(“<>”))
menu.add_separator()
menu.add_command(label=“全选”, command=lambda: event.widget.event_generate(“<>”))
menu.post(event.x_root, event.y_root)
entry_main.bind(“”, show_textbox_menu)
entry_accompaniment.bind(“”, show_textbox_menu)
def play_main_music():
main_music_notes = entry_main.get(“1.0”, “end-1c”)
base_duration = 300 # 基础音符时长
main_note_index = 0
main_notes_playing = []
pause_duration = 0.5 # 初始暂停时长
while main_note_index < len(main_music_notes):
main_note_char = main_music_notes[main_note_index:main_note_index + 2] if main_note_index < len(main_music_notes) else None
if main_note_char == '/,':
time.sleep(pause_duration)
main_note_index += 1
continue
main_note_number = convert_note(main_note_char)
if main_note_number is not None:
main_tune = main_tune_var.get()
main_note_number = convert_tune(main_note_number, main_tune)
main_duration = base_duration
play_note(main_note_number, main_duration, int(main_instrument_var.get().split(" - ")[0]))
main_note_index += 1
def play_accompaniment_music():
accompaniment_music_notes = entry_accompaniment.get(“1.0”, “end-1c”)
base_duration = 300 # 基础音符时长
accompaniment_note_index = 0
accompaniment_notes_playing = []
pause_duration = 0.5 # 初始暂停时长
while accompaniment_note_index < len(accompaniment_music_notes):
accompaniment_note_char = accompaniment_music_notes[accompaniment_note_index:accompaniment_note_index + 2]
if accompaniment_note_char == '/,':
time.sleep(pause_duration)
accompaniment_note_index += 1
continue
accompaniment_note_number = convert_note(accompaniment_note_char)
if accompaniment_note_number is not None:
accompaniment_tune = accompaniment_tune_var.get()
accompaniment_note_number = convert_tune(accompaniment_note_number, accompaniment_tune)
accompaniment_duration = base_duration
play_note(accompaniment_note_number, accompaniment_duration, int(accompaniment_instrument_var.get().split(" - ")[0]))
accompaniment_note_index += 1
def convert_note(note_char):
note_mapping = {‘c1’: 53, ‘c2’: 54, ‘c3’: 55, ‘c4’: 56, ‘c5’: 57, ‘c6’: 58, ‘c7’: 59,
‘d1’: 60, ‘d2’: 61, ‘d3’: 62, ‘d4’: 63, ‘d5’: 64, ‘d6’: 65, ‘d7’: 66,
‘e1’: 67, ‘e2’: 68, ‘e3’: 69, ‘e4’: 70, ‘e5’: 71, ‘e6’: 72, ‘e7’: 73,
‘f1’: 74, ‘f2’: 75, ‘f3’: 76, ‘f4’: 77, ‘f5’: 78, ‘f6’: 79, ‘f7’: 80,
‘g1’: 81, ‘g2’: 82, ‘g3’: 83, ‘g4’: 84, ‘g5’: 85, ‘g6’: 86, ‘g7’: 87,
‘a1’: 39, ‘a2’: 40, ‘a3’: 41, ‘a4’: 42, ‘a5’: 43, ‘a6’: 44, ‘a7’: 45,
‘b1’: 46, ‘b2’: 47, ‘b3’: 48, ‘b4’: 49, ‘b5’: 50, ‘b6’: 51, ‘b7’: 52}
return note_mapping.get(note_char)
def convert_tune(note_number, tune):
if tune == “D 大调”:
return note_number
elif tune == “E 大调”:
return note_number + 7
elif tune == “F 大调”:
return note_number + 14
elif tune == “G 大调”:
return note_number + 21
elif tune == “A 大调”:
return note_number - 21
elif tune == “B 大调”:
return note_number - 14
elif tune == “C 大调”:
return note_number - 7
创建播放按钮按钮
play_button = tk.Button(root, text=“播放”, command=lambda: [threading.Thread(target=play_main_music).start(), threading.Thread(target=play_accompaniment_music).start()])
play_button.pack(pady=20)
play_button.place(x=530, y=210, width=100, height=50)
定义音符列表
z = [“/,”,“a1”,“a2”,“a3”,“a4”,“a5”,“a6”,“a7”,“b1”,“b2”,“b3”,“b4”,“b5”,“b6”,“b7”,“c1”,“c2”,“c3”,“c4”,“c5”,“c6”,“c7”,“d1”,“d2”,“d3”,“d4”,“d5”,“d6”,“d7”,“e1”,“e2”,“e3”,“e4”,“e5”,“e6”,“e7”,“f1”,“f2”,“f3”,“f4”,“f5”,“f6”,“f7”,“g1”,“g2”,“g3”,“g4”,“g5”,“g6”,“g7”]
定义音符列表
x = [“/,”,“a1”,“a2”,“a3”,“a4”,“a5”,“a6”,“a7”,“b1”,“b2”,“b3”,“b4”,“b5”,“b6”,“b7”,“c1”,“c2”,“c3”,“c4”,“c5”,“c6”,“c7”,“d1”,“d2”,“d3”,“d4”,“d5”,“d6”,“d7”,“e1”,“e2”,“e3”,“e4”,“e5”,“e6”,“e7”,“f1”,“f2”,“f3”,“f4”,“f5”,“f6”,“f7”,“g1”,“g2”,“g3”,“g4”,“g5”,“g6”,“g7”]
定义生成随机音符的函数
def generate_random_notes():
random_notes = []
for _ in range(30):
random_note = random.choice(z)
random_notes.append(random_note)
entry_main.delete(“1.0”, tk.END) # 清空文本框内容
entry_main.insert(tk.END, “”.join(random_notes)) # 将随机音符插入文本框
定义生成随机音符的函数
def g_random_notes():
random_notes = []
for _ in range(30):
random_note = random.choice(x)
random_notes.append(random_note)
entry_accompaniment.delete(“1.0”, tk.END) # 清空文本框内容
entry_accompaniment.insert(tk.END, “”.join(random_notes)) # 将随机音符插入文本框
创建生成随机音符的按钮
generate_button = tk.Button(root, text=“谱曲1”, command=generate_random_notes)
generate_button.pack(pady=20)
generate_button.place(x=300, y=70, width=80, height=30)
创建生成随机音符的按钮
g_button = tk.Button(root, text=“谱曲2”, command=g_random_notes)
g_button.pack(pady=20)
g_button.place(x=300, y=260, width=80, height=30)
定义生成随机音符的函数
def q_random_notes():
entry_main.delete(“1.0”, tk.END) # 清空文本框内容
entry_accompaniment.delete(“1.0”, tk.END) # 清空文本框内容
创建生成随机音符的按钮
q_button = tk.Button(root, text=“清空”, command=q_random_notes)
q_button.pack(pady=20)
q_button.place(x=530, y=260, width=100, height=50)
root.mainloop()
关闭 MIDI 输出设备
midi_out.close()
pygame.midi.quit()