import tkinter as tk
import pygame.midi
初始化 pygame.midi
pygame.midi.init()
获取 MIDI 输出设备
midi_out = pygame.midi.Output(0)
创建 tkinter 的主窗口
root = tk.Tk()
设置主窗口标题
root.title(“小钢琴”)
设置窗口大小
root.geometry(“1000x500”)
音符对应的 MIDI 编号
notes = [50, 52, 54, 55, 57, 59, 61, 62, 64, 66, 67, 69, 71, 73, 74, 76, 78, 79, 81, 83, 85]
乐器名称映射
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: “枪声”
}
设置音量为 125
def play_note(note_number):
midi_out.note_on(note_number, 125)
def stop_note(note_number):
midi_out.note_off(note_number, 125)
class PianoKey(tk.Button):
def init(self, master, note_number, is_black=False):
# 根据 MIDI 编号获取音符名称
note_names = {
50: ‘C3’,
51: ‘C#3’,
52: ‘D3’,
53: ‘D#3’,
54: ‘E3’,
55: ‘F3’,
56: ‘F#3’,
57: ‘G3’,
58: ‘G#3’,
59: ‘A3’,
60: ‘A#3’,
61: ‘B3’,
62: ‘C4’,
63: ‘C#4’,
64: ‘D4’,
65: ‘D#4’,
66: ‘E4’,
67: ‘F4’,
68: ‘F#4’,
69: ‘G4’,
70: ‘G#4’,
71: ‘A4’,
72: ‘A#4’,
73: ‘B4’,
74: ‘C5’,
75: ‘C#5’,
76: ‘D5’,
77: ‘D#5’,
78: ‘E5’,
79: ‘F5’,
80: ‘F#4’,
81: ‘G5’,
82: ‘G#5’,
83: ‘A5’,
84: ‘A#5’,
85: ‘B5’
}
note_name = note_names.get(note_number, ‘Unknown’)
bg_color = “black” if is_black else “white”
active_bg_color = “gray” if is_black else “lightgray”
super().init(master, bg=bg_color, activebackground=active_bg_color, command=self.on_click, text=note_name)
self.note_number = note_number
self.is_black = is_black
# 设置音符文本颜色
if is_black:
self.config(fg="white")
else:
self.config(fg="black")
def on_click(self):
play_note(self.note_number)
定义一个函数来处理乐器选择变化
def change_instrument(instrument_value):
instrument_number = int(instrument_value.split(" - ")[0])
midi_out.set_instrument(instrument_number)
设置钢琴白键
white_key_width = 40
white_key_height = 250
white_key_x_offset = 45
for note_number in notes:
key = PianoKey(root, note_number)
key.place(x=white_key_x_offset, y=160, width=white_key_width, height=white_key_height)
white_key_x_offset += white_key_width
设置单独的黑键并设置颜色
black_keys = [
{‘note_number’: 51, ‘x’: 75, ‘y’: 160, ‘width’: 20, ‘height’: 150, ‘color’: ‘black’, ‘text’: ‘C#3’},
{‘note_number’: 53, ‘x’: 115, ‘y’: 160, ‘width’: 20, ‘height’: 150, ‘color’: ‘black’, ‘text’: ‘D#3’},
{‘note_number’: 56, ‘x’: 195, ‘y’: 160, ‘width’: 20, ‘height’: 150, ‘color’: ‘black’, ‘text’: ‘F#3’},
{‘note_number’: 58, ‘x’: 235, ‘y’: 160, ‘width’: 20, ‘height’: 150, ‘color’: ‘black’, ‘text’: ‘G#3’},
{‘note_number’: 60, ‘x’: 275, ‘y’: 160, ‘width’: 20, ‘height’: 150, ‘color’: ‘black’, ‘text’: ‘A#3’},
{'note_number': 63, 'x': 355, 'y': 160, 'width': 20, 'height': 150, 'color': 'black', 'text': 'C#4'},
{'note_number': 65, 'x': 395, 'y': 160, 'width': 20, 'height': 150, 'color': 'black', 'text': 'D#4'},
{'note_number': 68, 'x': 475, 'y': 160, 'width': 20, 'height': 150, 'color': 'black', 'text': 'F#4'},
{'note_number': 70, 'x': 515, 'y': 160, 'width': 20, 'height': 150, 'color': 'black', 'text': 'G#4'},
{'note_number': 72, 'x': 555, 'y': 160, 'width': 20, 'height': 150, 'color': 'black', 'text': 'A#4'},
{'note_number': 75, 'x': 635, 'y': 160, 'width': 20, 'height': 150, 'color': 'black', 'text': 'C#5'},
{'note_number': 77, 'x': 675, 'y': 160, 'width': 20, 'height': 150, 'color': 'black', 'text': 'D#5'},
{'note_number': 80, 'x': 755, 'y': 160, 'width': 20, 'height': 150, 'color': 'black', 'text': 'F#5'},
{'note_number': 82, 'x': 795, 'y': 160, 'width': 20, 'height': 150, 'color': 'black', 'text': 'G#5'},
{'note_number': 84, 'x': 835, 'y': 160, 'width': 20, 'height': 150, 'color': 'black', 'text': 'A#5'}
]
for key_info in black_keys:
black_key = PianoKey(root, key_info[‘note_number’], is_black=True)
black_key.config(bg=key_info[‘color’])
black_key.place(x=key_info[‘x’], y=key_info[‘y’], width=key_info[‘width’], height=key_info[‘height’])
选择乐器的下拉菜单
midi_out_var = tk.StringVar(root)
default_main_instrument = 2
midi_out_var.set(f"{default_main_instrument} - {instrument_names.get(default_main_instrument, ‘Unknown’)}")
main_instrument_menu = tk.OptionMenu(root, midi_out_var,
*[f"{i} - {instrument_names.get(i, ‘Unknown’)}" for i in range(128)],
command=change_instrument)
main_instrument_menu.place(x=10, y=10, width=200, height=50)
root.mainloop()
关闭 MIDI 输出设备
midi_out.close()
pygame.midi.quit()