可以用了(?)

This commit is contained in:
EillesWan 2024-01-14 22:05:55 +08:00
parent fc138f1dbf
commit 41883f7798
7 changed files with 845 additions and 220 deletions

View File

@ -41,6 +41,8 @@ DEFAULT_PROGRESSBAR_STYLE = (
默认的进度条样式组 默认的进度条样式组
""" """
# Midi用对照表
MIDI_PITCH_NAME_TABLE: Dict[int, str] = { MIDI_PITCH_NAME_TABLE: Dict[int, str] = {
0: "C", 0: "C",
1: "C#", 1: "C#",
@ -171,12 +173,468 @@ MIDI_PITCH_NAME_TABLE: Dict[int, str] = {
126: "F#", 126: "F#",
127: "G", 127: "G",
} }
"""Midi音高名称对照表"""
MIDI_PITCHED_NOTE_NAME_GROUP: Dict[int, Tuple[str, str]] = {
1: ("钢琴", "Piano"),
9: ("半音阶打击乐器", "Chromatic Percussion"),
17: ("风琴", "Organ"),
25: ("吉他", "Guitar"),
33: ("贝斯", "Bass"),
41: ("弦乐器", "Strings"),
49: ("合奏乐器", "Ensemble"),
57: ("铜管乐器", "Brass"),
65: ("簧乐器", "Reed"),
73: ("吹管乐器", "Pipe"),
81: ("合成主旋律", "Synth Lead"),
89: ("合成和弦", "Synth Pad"),
97: ("合成声效", "Synth Effects"),
105: ("民族乐器", "Ethnic"),
113: ("打击乐器", "Percussive"),
121: ("特殊音效", "Sound Effects"),
}
"""Midi乐音乐器分组名称对照表"""
MIDI_PITCHED_NOTE_NAME_TABLE: Dict[int, Tuple[str, str]] = {
1: ("原声平台钢琴", "Acoustic Grand Piano"),
2: ("亮音原声钢琴", "Bright Acoustic Piano"),
3: ("数码电钢琴", "Electric Grand Piano"),
4: ("酒吧钢琴", "Honky-tonk Piano"),
5: ("电气电钢琴", "Electric Piano 1(Rhodes Piano)"),
6: ("合唱效果电钢琴", "Electric Piano 2(Chorused Piano)"),
7: ("拨弦古钢琴(羽管键琴)", "Harpsichord"),
8: ("古钢琴", "Clavi"),
9: ("钢片琴", "Celesta"),
10: ("钟琴", "Glockenspiel"),
11: ("八音盒", "Music box"),
12: ("颤音琴", "Vibraphone"),
13: ("马林巴琴", "Marimba"),
14: ("木琴", "Xylophone"),
15: ("管钟", "Tubular Bells"),
16: ("扬琴", "Dulcimer"),
17: ("音栓风琴(击杆风琴)", "Drawbar Organ (Hammond Organ)"),
18: ("打击风琴", "Percussive Organ"),
19: ("摇滚管风琴", "Rock Organ"),
20: ("教堂管风琴", "Church Organ"),
21: ("簧风琴", "Reed Organ"),
22: ("手风琴", "Accordion"),
23: ("口琴", "Harmonica"),
24: ("探戈手风琴", "Tango Accordion"),
25: ("尼龙弦吉他", "Acoustic Guitar (nylon)"),
26: ("钢弦吉他", "Acoustic Guitar (steel)"),
27: ("爵士电吉他", "Electric Guitar (jazz)"),
28: ("清音电吉他", "Electric Guitar (clean)"),
29: ("弱音电吉他", "Electric Guitar (muted)"),
30: ("过驱电吉他", "Overdriven Guitar"),
31: ("失真电吉他", "Distortion Guitar"),
32: ("吉他泛音", "Guitar harmonics"),
33: ("原声贝斯", "Acoustic Bass"),
34: ("指奏电贝斯", "Electric Bass (finger)"),
35: ("拨奏电贝斯", "Electric Bass (pick)"),
36: ("无品贝斯", "Fretless Bass"),
37: ("击弦贝斯 1", "Slap Bass 1"),
38: ("击弦贝斯 2", "Slap Bass 2"),
39: ("合成贝斯 1", "Synth Bass 1"),
40: ("合成贝斯 2", "Synth Bass 2"),
41: ("小提琴", "Violin"),
42: ("中提琴", "Viola"),
43: ("大提琴", "Cello"),
44: ("低音提琴", "Contrabass"),
45: ("颤弓弦乐(弦乐震音)", "Tremolo Strings"),
46: ("弹拨弦乐(弦乐拨奏)", "Pizzicato Strings"),
47: ("竖琴", "Orchestral Harp"),
48: ("定音鼓", "Timpani"),
49: ("弦乐合奏 1", "String Ensemble 1"),
50: ("弦乐合奏 2", "String Ensemble 2"),
51: ("合成弦乐 1", "Synth Strings 1"),
52: ("合成弦乐 2", "Synth Strings 2"),
53: ("合唱“啊”音", "Choir Aahs"),
54: ("人声“嘟”音", "Voice Oohs"),
55: ("合成人声", "Synth Voice"),
56: ("交响打击乐", "Orchestra Hit"),
57: ("小号", "Trumpet"),
58: ("长号", "Trombone"),
59: ("大号", "Tuba"),
60: ("弱音小号", "Muted Trumpet"),
61: ("圆号(法国号)", "French Horn"),
62: ("铜管乐组", "Brass Section"),
63: ("合成铜管 1", "Synth Brass 1"),
64: ("合成铜管 2", "Synth Brass 2"),
65: ("高音萨克斯风", "Soprano Sax"),
66: ("中音萨克斯风", "Alto Sax"),
67: ("次中音萨克斯风", "Tenor Sax"),
68: ("上低音萨克斯风", "Baritone Sax"),
69: ("双簧管", "Oboe"),
70: ("英国管", "English Horn"),
71: ("大管(巴松管)", "Bassoon"),
72: ("单簧管(黑管)", "Clarinet"),
73: ("短笛", "Piccolo"),
74: ("长笛", "Flute"),
75: ("竖笛", "Recorder"),
76: ("排笛", "Pan Flute"),
77: ("瓶笛", "Blown Bottle"),
78: ("尺八", "Shakuhachi"),
79: ("哨子", "Whistle"),
80: ("陶笛", "Ocarina"),
81: ("方波", "Lead 1 (square)"),
82: ("锯齿波", "Lead 2 (sawtooth)"),
83: ("汽笛风琴", "Lead 3 (calliope)"),
84: ("合成吹管", "Lead 4 (chiff)"),
85: ("合成电吉他", "Lead 5 (charang)"),
86: ("人声键盘", "Lead 6 (voice)"),
87: ("五度音", "Lead 7 (fifths)"),
88: ("低音+主音", "Lead 8 (bass+lead)"),
89: ("新纪元", "Pad 1 (new age)"),
90: ("暖温", "Pad 2 (warm)"),
91: ("复合成音", "Pad 3 (polysynth)"),
92: ("人声合唱", "Pad 4 (choir)"),
93: ("弓弦", "Pad 5 (bowed)"),
94: ("银铃", "Pad 6 (metallic)"),
95: ("荣光", "Pad 7 (halo)"),
96: ("轻扫", "Pad 8 (sweep)"),
97: ("夏雨", "FX 1 (rain)"),
98: ("音轨", "FX 2 (soundtrack)"),
99: ("水晶", "FX 3 (crystal)"),
100: ("大气", "FX 4 (atmosphere)"),
101: ("轻曼", "FX 5 (light)"),
102: ("魅影", "FX 6 (goblins)"),
103: ("回响", "FX 7 (echoes)"),
104: ("科幻", "FX 8 (sci-fi)"),
105: ("西塔琴", "Sitar"),
106: ("五弦琴(班卓琴)", "Banjo"),
107: ("三味线", "Shamisen"),
108: ("日本筝", "Koto"),
109: ("卡林巴铁片琴", "Kalimba"),
110: ("苏格兰风笛", "Bagpipe"),
111: ("古提琴", "Fiddle"),
112: ("唢呐", "Shanai"),
113: ("铃铛", "Tinkle Bell"),
114: ("拉丁打铃", "Agogo"),
115: ("钢鼓", "Steel Drums"),
116: ("木块", "Woodblock"),
117: ("太鼓", "Taiko Drum"),
118: ("古式高音鼓", "Melodic Tom"),
119: ("合成鼓", "Synth Drum"),
120: ("铜钹", "Reverse Cymbal"),
121: ("吉他品格杂音", "Guitar Fret Noise"),
122: ("呼吸杂音", "Breath Noise"),
123: ("浪潮", "Seashore"),
124: ("鸟鸣", "Bird Tweet"),
125: ("电话", "Telephone"),
126: ("直升机", "Helicopter"),
127: ("鼓掌", "Applause"),
128: ("射击", "Gunshot"),
}
"""Midi乐音乐器名称对照表"""
MIDI_PERCUSSION_NOTE_NAME_TABLE: Dict[int, Tuple[str, str]] = {
35: ("原声大鼓", "Acoustic Bass Drum"),
36: ("大鼓", "Bass Drum 1"),
37: ("小鼓鼓边", "Side Stick"),
38: ("原声小军鼓", "Acoustic Snare"),
39: ("拍手", "Hand Clap"),
40: ("电子小军鼓", "Electric Snare"),
41: ("低音落地桶鼓", "Low Floor Tom"),
42: ("闭镲", "Closed Hi-Hat"),
43: ("高音落地桶鼓", "High Floor Tom"),
44: ("脚踏踩镲", "Pedal Hi-Hat"),
45: ("低桶鼓", "Low Tom"),
46: ("开镲", "Open Hi-Hat"),
47: ("低音中桶鼓", "Low-Mid Tom"),
48: ("高音中桶鼓", "Hi Mid Tom 2"),
49: ("强音钹 1", "Crash Cymbal 1"),
50: ("高桶鼓", "High Tom"),
51: ("打点钹 1", "Ride Cymbal 1"),
52: ("", "Chinese Cymbal"),
53: ("圆铃", "Ride Bell"),
54: ("铃鼓", "Tambourine"),
55: ("小钹铜钹", "Splash Cymbal"),
56: ("牛铃", "Cowbell"),
57: ("强音钹 2", "Crash Cymbal 2"),
58: ("颤音器", "Vibra-Slap"),
59: ("打点钹 2", "Ride Cymbal 2"),
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"),
}
"""Midi打击乐器名称对照表"""
# Minecraft用对照表
MC_PERCUSSION_INSTRUMENT_LIST: List[str] = [
"note.snare",
"note.bd",
"note.hat",
"note.basedrum",
"firework.blast",
"firework.twinkle",
"fire.ignite",
"mob.zombie.wood",
]
"""打击乐器列表"""
MC_INSTRUMENT_BLOCKS_TABLE: Dict[str, Tuple[str, ...]] = {
"note.bass": ("planks",),
"note.snare": ("sand",),
"note.hat": ("glass",),
"note.bd": ("stone",),
"note.basedrum": ("stone",),
"note.bell": ("gold_block",),
"note.flute": ("clay",),
"note.chime": ("packed_ice",),
"note.guitar": ("wool",),
"note.xylobone": ("bone_block",),
"note.iron_xylophone": ("iron_block",),
"note.cow_bell": ("soul_sand",),
"note.didgeridoo": ("pumpkin",),
"note.bit": ("emerald_block",),
"note.banjo": ("hay_block",),
"note.pling": ("glowstone",),
"note.bassattack": ("stone",), # 无法找到此音效
"note.harp": ("dirt",),
# 呃……
"firework.blast": ("sandstone",),
"firework.twinkle": ("red_sandstone",),
"fire.ignite": ("concrete_powder",),
"mob.zombie.wood": ("sand",),
}
"""MC乐器对音符盒下垫方块对照表"""
# Midi对MC通用对照表
MM_INSTRUMENT_DEVIATION_TABLE: Dict[str, int] = {
"note.harp": 6,
"note.pling": 6,
"note.guitar": 7,
"note.iron_xylophone": 6,
"note.bell": 4,
"note.xylophone": 4,
"note.chime": 4,
"note.banjo": 6,
"note.flute": 5,
"note.bass": 8,
"note.snare": -1,
"note.didgeridoo": 8,
"mob.zombie.wood": -1,
"note.bit": 6,
"note.hat": -1,
"note.bd": -1,
"firework.blast": -1,
"firework.twinkle": -1,
"fire.ignite": -1,
"note.share": -1,
"note.cow_bell": 5,
}
"""不同乐器的音调偏离对照表"""
# Midi乐器对MC乐器对照表
MM_CLASSIC_PITCHED_INSTRUMENT_TABLE: Dict[int, Tuple[str, int]] = {
0: ("note.harp", 6),
1: ("note.harp", 6),
2: ("note.pling", 6),
3: ("note.harp", 6),
4: ("note.pling", 6),
5: ("note.pling", 6),
6: ("note.harp", 6),
7: ("note.harp", 6),
8: ("note.share", -1), # 打击乐器无音域
9: ("note.harp", 6),
10: ("note.didgeridoo", 8),
11: ("note.harp", 6),
12: ("note.xylophone", 4),
13: ("note.chime", 4),
14: ("note.harp", 6),
15: ("note.harp", 6),
16: ("note.bass", 8),
17: ("note.harp", 6),
18: ("note.harp", 6),
19: ("note.harp", 6),
20: ("note.harp", 6),
21: ("note.harp", 6),
22: ("note.harp", 6),
23: ("note.guitar", 7),
24: ("note.guitar", 7),
25: ("note.guitar", 7),
26: ("note.guitar", 7),
27: ("note.guitar", 7),
28: ("note.guitar", 7),
29: ("note.guitar", 7),
30: ("note.guitar", 7),
31: ("note.bass", 8),
32: ("note.bass", 8),
33: ("note.bass", 8),
34: ("note.bass", 8),
35: ("note.bass", 8),
36: ("note.bass", 8),
37: ("note.bass", 8),
38: ("note.bass", 8),
39: ("note.bass", 8),
40: ("note.harp", 6),
41: ("note.harp", 6),
42: ("note.harp", 6),
43: ("note.harp", 6),
44: ("note.iron_xylophone", 6),
45: ("note.guitar", 7),
46: ("note.harp", 6),
47: ("note.harp", 6),
48: ("note.guitar", 7),
49: ("note.guitar", 7),
50: ("note.bit", 6),
51: ("note.bit", 6),
52: ("note.harp", 6),
53: ("note.harp", 6),
54: ("note.bit", 6),
55: ("note.flute", 5),
56: ("note.flute", 5),
57: ("note.flute", 5),
58: ("note.flute", 5),
59: ("note.flute", 5),
60: ("note.flute", 5),
61: ("note.flute", 5),
62: ("note.flute", 5),
63: ("note.flute", 5),
64: ("note.bit", 6),
65: ("note.bit", 6),
66: ("note.bit", 6),
67: ("note.bit", 6),
68: ("note.flute", 5),
69: ("note.harp", 6),
70: ("note.harp", 6),
71: ("note.flute", 5),
72: ("note.flute", 5),
73: ("note.flute", 5),
74: ("note.harp", 6),
75: ("note.flute", 5),
76: ("note.harp", 6),
77: ("note.harp", 6),
78: ("note.harp", 6),
79: ("note.harp", 6),
80: ("note.bit", 6),
81: ("note.bit", 6),
82: ("note.bit", 6),
83: ("note.bit", 6),
84: ("note.bit", 6),
85: ("note.bit", 6),
86: ("note.bit", 6),
87: ("note.bit", 6),
88: ("note.bit", 6),
89: ("note.bit", 6),
90: ("note.bit", 6),
91: ("note.bit", 6),
92: ("note.bit", 6),
93: ("note.bit", 6),
94: ("note.bit", 6),
95: ("note.bit", 6),
96: ("note.bit", 6),
97: ("note.bit", 6),
98: ("note.bit", 6),
99: ("note.bit", 6),
100: ("note.bit", 6),
101: ("note.bit", 6),
102: ("note.bit", 6),
103: ("note.bit", 6),
104: ("note.harp", 6),
105: ("note.banjo", 6),
106: ("note.harp", 6),
107: ("note.harp", 6),
108: ("note.harp", 6),
109: ("note.harp", 6),
110: ("note.harp", 6),
111: ("note.guitar", 7),
112: ("note.harp", 6),
113: ("note.bell", 4),
114: ("note.harp", 6),
115: ("note.cow_bell", 5),
116: ("note.bd", -1), # 打击乐器无音域
117: ("note.bass", 8),
118: ("note.bit", 6),
119: ("note.bd", -1), # 打击乐器无音域
120: ("note.guitar", 7),
121: ("note.harp", 6),
122: ("note.harp", 6),
123: ("note.harp", 6),
124: ("note.harp", 6),
125: ("note.hat", -1), # 打击乐器无音域
126: ("note.bd", -1), # 打击乐器无音域
127: ("note.snare", -1), # 打击乐器无音域
}
"""“经典”乐音乐器对照表"""
MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE: Dict[int, Tuple[str, int]] = {
34: ("note.bd", -1),
35: ("note.bd", -1),
36: ("note.hat", -1),
37: ("note.snare", -1),
38: ("note.snare", -1),
39: ("note.snare", -1),
40: ("note.hat", -1),
41: ("note.snare", -1),
42: ("note.hat", -1),
43: ("note.snare", -1),
44: ("note.snare", -1),
45: ("note.bell", 4),
46: ("note.snare", -1),
47: ("note.snare", -1),
48: ("note.bell", 4),
49: ("note.hat", -1),
50: ("note.bell", 4),
51: ("note.bell", 4),
52: ("note.bell", 4),
53: ("note.bell", 4),
54: ("note.bell", 4),
55: ("note.bell", 4),
56: ("note.snare", -1),
57: ("note.hat", -1),
58: ("note.chime", 4),
59: ("note.iron_xylophone", 6),
60: ("note.bd", -1),
61: ("note.bd", -1),
62: ("note.xylophone", 4),
63: ("note.xylophone", 4),
64: ("note.xylophone", 4),
65: ("note.hat", -1),
66: ("note.bell", 4),
67: ("note.bell", 4),
68: ("note.hat", -1),
69: ("note.hat", -1),
70: ("note.flute", 5),
71: ("note.flute", 5),
72: ("note.hat", -1),
73: ("note.hat", -1),
74: ("note.xylophone", 4),
75: ("note.hat", -1),
76: ("note.hat", -1),
77: ("note.xylophone", 4),
78: ("note.xylophone", 4),
79: ("note.bell", 4),
80: ("note.bell", 4),
}
"""“经典”打击乐器对照表"""
# 以下是由 Touch “偷吃” 带来的高准确率音效对照表 # 以下是由 Touch “偷吃” 带来的高准确率音效对照表
# 包括乐音乐器对照和打击乐器对照 # 包括乐音乐器对照和打击乐器对照
PITCHED_INSTRUMENT_TABLE: Dict[int, Tuple[str, int]] = { MM_TOUCH_PITCHED_INSTRUMENT_TABLE: Dict[int, Tuple[str, int]] = {
0: ("note.harp", 6), 0: ("note.harp", 6),
1: ("note.harp", 6), 1: ("note.harp", 6),
2: ("note.pling", 6), 2: ("note.pling", 6),
@ -224,7 +682,7 @@ PITCHED_INSTRUMENT_TABLE: Dict[int, Tuple[str, int]] = {
44: ("note.flute", 5), 44: ("note.flute", 5),
45: ("note.iron_xylophone", 6), 45: ("note.iron_xylophone", 6),
46: ("note.harp", 6), 46: ("note.harp", 6),
47: ("note.snare", 7), 47: ("note.snare", -1),
48: ("note.flute", 5), 48: ("note.flute", 5),
49: ("note.flute", 5), 49: ("note.flute", 5),
50: ("note.flute", 5), 50: ("note.flute", 5),
@ -232,7 +690,7 @@ PITCHED_INSTRUMENT_TABLE: Dict[int, Tuple[str, int]] = {
52: ("note.didgeridoo", 5), 52: ("note.didgeridoo", 5),
53: ("note.flute", 5), # 合唱“啊”音 53: ("note.flute", 5), # 合唱“啊”音
54: ("note.flute", 5), # 人声“嘟”音 54: ("note.flute", 5), # 人声“嘟”音
55: ("mob.zombie.wood", 7), # 合成人声 55: ("mob.zombie.wood", -1), # 合成人声
56: ("note.flute", 5), 56: ("note.flute", 5),
57: ("note.flute", 5), 57: ("note.flute", 5),
58: ("note.flute", 5), 58: ("note.flute", 5),
@ -292,136 +750,100 @@ PITCHED_INSTRUMENT_TABLE: Dict[int, Tuple[str, int]] = {
112: ("note.bell", 4), 112: ("note.bell", 4),
113: ("note.xylophone", 4), 113: ("note.xylophone", 4),
114: ("note.flute", 5), 114: ("note.flute", 5),
115: ("note.hat", 7), # 打击乐器无音域 115: ("note.hat", -1), # 打击乐器无音域
116: ("note.snare", 7), # 打击乐器无音域 116: ("note.snare", -1), # 打击乐器无音域
117: ("note.snare", 7), # 打击乐器无音域 117: ("note.snare", -1), # 打击乐器无音域
118: ("note.bd", 7), # 打击乐器无音域 118: ("note.bd", -1), # 打击乐器无音域
119: ("firework.blast", 7), # 打击乐器无音域 119: ("firework.blast", -1), # 打击乐器无音域
120: ("note.guitar", 7), # 吉他还把杂音 120: ("note.guitar", 7), # 吉他还把杂音
121: ("note.harp", 6), # 呼吸声 121: ("note.harp", 6), # 呼吸声
122: ("note.harp", 6), # 海浪声 122: ("note.harp", 6), # 海浪声
123: ("note.harp", 6), # 鸟鸣 123: ("note.harp", 6), # 鸟鸣
124: ("note.bit", 6), 124: ("note.bit", 6),
125: ("note.hat", 7), # 直升机 125: ("note.hat", -1), # 直升机
126: ("firework.twinkle", 7), # 打击乐器无音域 126: ("firework.twinkle", -1), # 打击乐器无音域
127: ("mob.zombie.wood", 7), # 打击乐器无音域 127: ("mob.zombie.wood", -1), # 打击乐器无音域
} }
"""“偷吃”乐音乐器对照表"""
PERCUSSION_INSTRUMENT_TABLE: Dict[int, Tuple[str, int]] = { MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE: Dict[int, Tuple[str, int]] = {
34: ("note.hat", 7), 34: ("note.hat", -1),
35: ("note.bd", 7), 35: ("note.bd", -1),
36: ("note.bd", 7), 36: ("note.bd", -1),
37: ("note.snare", 7), 37: ("note.snare", -1),
38: ("note.snare", 7), 38: ("note.snare", -1),
39: ("fire.ignite", 7), 39: ("fire.ignite", 7),
40: ("note.snare", 7), 40: ("note.snare", -1),
41: ("note.hat", 7), 41: ("note.hat", -1),
42: ("note.hat", 7), 42: ("note.hat", -1),
43: ("firework.blast", 7), 43: ("firework.blast", -1),
44: ("note.hat", 7), 44: ("note.hat", -1),
45: ("note.snare", 4), 45: ("note.snare", -1),
46: ("note.snare", 7), 46: ("note.snare", -1),
47: ("note.snare", 7), 47: ("note.snare", -1),
48: ("note.bell", 4), 48: ("note.bell", 4),
49: ("note.hat", 7), 49: ("note.hat", -1),
50: ("note.bell", 4), 50: ("note.bell", 4),
51: ("note.bell", 4), 51: ("note.bell", 4),
52: ("note.bell", 4), 52: ("note.bell", 4),
53: ("note.bell", 4), 53: ("note.bell", 4),
54: ("note.bell", 4), 54: ("note.bell", 4),
55: ("note.bell", 4), 55: ("note.bell", 4),
56: ("note.snare", 7), 56: ("note.snare", -1),
57: ("note.hat", 7), 57: ("note.hat", -1),
58: ("note.chime", 4), 58: ("note.chime", 4),
59: ("note.iron_xylophone", 6), 59: ("note.iron_xylophone", 6),
60: ("note.bd", 7), 60: ("note.bd", -1),
61: ("note.bd", 7), 61: ("note.bd", -1),
62: ("note.xylophone", 4), 62: ("note.xylophone", 4),
63: ("note.xylophone", 4), 63: ("note.xylophone", 4),
64: ("note.xylophone", 4), 64: ("note.xylophone", 4),
65: ("note.hat", 7), 65: ("note.hat", -1),
66: ("note.bell", 4), 66: ("note.bell", 4),
67: ("note.bell", 4), 67: ("note.bell", 4),
68: ("note.hat", 7), 68: ("note.hat", -1),
69: ("note.hat", 7), 69: ("note.hat", -1),
70: ("note.flute", 5), 70: ("note.flute", 5),
71: ("note.flute", 5), 71: ("note.flute", 5),
72: ("note.hat", 7), 72: ("note.hat", -1),
73: ("note.hat", 7), 73: ("note.hat", -1),
74: ("note.xylophone", 4), 74: ("note.xylophone", 4),
75: ("note.hat", 7), 75: ("note.hat", -1),
76: ("note.hat", 7), 76: ("note.hat", -1),
77: ("note.xylophone", 4), 77: ("note.xylophone", 4),
78: ("note.xylophone", 4), 78: ("note.xylophone", 4),
79: ("note.bell", 4), 79: ("note.bell", 4),
80: ("note.bell", 4), 80: ("note.bell", 4),
} }
"""“偷吃”打击乐器对照表"""
PERCUSSION_INSTRUMENT_LIST: List[str] = [
"note.snare",
"note.bd",
"note.hat",
"note.basedrum",
"firework.blast",
"firework.twinkle",
"fire.ignite",
"mob.zombie.wood",
]
INSTRUMENT_BLOCKS_TABLE: Dict[str, Tuple[str, ...]] = {
"note.bass": ("planks",),
"note.snare": ("sand",),
"note.hat": ("glass",),
"note.bd": ("stone",),
"note.basedrum": ("stone",),
"note.bell": ("gold_block",),
"note.flute": ("clay",),
"note.chime": ("packed_ice",),
"note.guitar": ("wool",),
"note.xylobone": ("bone_block",),
"note.iron_xylophone": ("iron_block",),
"note.cow_bell": ("soul_sand",),
"note.didgeridoo": ("pumpkin",),
"note.bit": ("emerald_block",),
"note.banjo": ("hay_block",),
"note.pling": ("glowstone",),
"note.bassattack": ("command_block",), # 无法找到此音效
"note.harp": ("dirt",),
# 呃……
"firework.blast": ("sandstone",),
"firework.twinkle": ("red_sandstone",),
"fire.ignite": ("concrete_powder",),
"mob.zombie.wood": ("sand",),
}
# 即将启用 # 即将启用
height2note = { # height2note = {
0.5: 0, # 0.5: 0,
0.53: 1, # 0.53: 1,
0.56: 2, # 0.56: 2,
0.6: 3, # 0.6: 3,
0.63: 4, # 0.63: 4,
0.67: 5, # 0.67: 5,
0.7: 6, # 0.7: 6,
0.75: 7, # 0.75: 7,
0.8: 8, # 0.8: 8,
0.84: 9, # 0.84: 9,
0.9: 10, # 0.9: 10,
0.94: 11, # 0.94: 11,
1.0: 12, # 1.0: 12,
1.05: 13, # 1.05: 13,
1.12: 14, # 1.12: 14,
1.2: 15, # 1.2: 15,
1.25: 16, # 1.25: 16,
1.33: 17, # 1.33: 17,
1.4: 18, # 1.4: 18,
1.5: 19, # 1.5: 19,
1.6: 20, # 1.6: 20,
1.7: 21, # 1.7: 21,
1.8: 22, # 1.8: 22,
1.9: 23, # 1.9: 23,
2.0: 24, # 2.0: 24,
} # }
"""音高对照表\n # """音高对照表\n
MC音高:音符盒音调""" # MC音高:音符盒音调"""

View File

@ -16,14 +16,12 @@ Terms & Conditions: License.md in the root directory
# Email TriM-Organization@hotmail.com # Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md # 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
import random
from .constants import INSTRUMENT_BLOCKS_TABLE
from .exceptions import * from .exceptions import *
from .main import MidiConvert
from .subclass import * from .subclass import *
from .utils import * from .utils import *
from .types import Tuple, List, Dict from .main import MidiConvert, MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE, MM_CLASSIC_PITCHED_INSTRUMENT_TABLE
from .types import Tuple, List, Dict, ChannelType
class FutureMidiConvertRSNB(MidiConvert): class FutureMidiConvertRSNB(MidiConvert):
@ -34,30 +32,6 @@ class FutureMidiConvertRSNB(MidiConvert):
music_command_list: Dict[int, SingleNoteBox] music_command_list: Dict[int, SingleNoteBox]
"""音乐指令列表""" """音乐指令列表"""
@staticmethod
def soundID_to_block(sound_id: str, random_select: bool = False) -> str:
"""
将我的世界乐器名改作音符盒所需的对应方块名称
Parameters
----------
sound_id: str
将我的世界乐器名
random_select: bool
是否随机选取对应方块
Returns
-------
str方块名称
"""
try:
if random_select:
return random.choice(INSTRUMENT_BLOCKS_TABLE[sound_id])
else:
return INSTRUMENT_BLOCKS_TABLE[sound_id][0]
except KeyError:
return "air"
class FutureMidiConvertM4(MidiConvert): class FutureMidiConvertM4(MidiConvert):
""" """
@ -101,6 +75,7 @@ class FutureMidiConvertM4(MidiConvert):
lastime=int(_note.duration / totalCount), lastime=int(_note.duration / totalCount),
track_number=_note.track_no, track_number=_note.track_no,
is_percussion=_note.percussive, is_percussion=_note.percussive,
extra_information=_note.extra_info
) )
# ( # (
# _note.start_time + _i * _apply_time_division, # _note.start_time + _i * _apply_time_division,
@ -145,8 +120,11 @@ class FutureMidiConvertM4(MidiConvert):
# 此处 我们把通道视为音轨 # 此处 我们把通道视为音轨
for channel in self.to_music_note_channels().values(): for channel in self.to_music_note_channels().values():
for note in channel: for note in channel:
note.set_info(note_to_command_parameters(note,self.percussion_note_referrence_table if note.percussive else self.pitched_note_reference_table, (max_volume) if note.track_no == 0 else (max_volume * 0.9),self.volume_processing_function,))
if not note.percussive: if not note.percussive:
notes_list.extend(self._linear_note(note, note.get_mc_pitch * 500)) notes_list.extend(self._linear_note(note, note.extra_info[3] * 500))
else: else:
notes_list.append(note) notes_list.append(note)
@ -166,12 +144,12 @@ class FutureMidiConvertM4(MidiConvert):
self.music_command_list.append( self.music_command_list.append(
SingleCommand( SingleCommand(
self.execute_cmd_head.format(player_selector) self.execute_cmd_head.format(player_selector)
+ note.to_command(max_volume), + r"playsound {} @s ^ ^ ^{} {} {}".format(*note.extra_info),
tick_delay=tickdelay, tick_delay=tickdelay,
annotation="{}播放{}%{}".format( annotation="{}播放{}%{}".format(
mctick2timestr(delaytime_now), mctick2timestr(delaytime_now),
max_volume * 100, max_volume * 100,
"{}:{}".format(note.mc_sound_ID, note.mc_pitch), "{}:{}".format(note.extra_info[0], note.extra_info[3]),
), ),
) )
) )
@ -186,6 +164,82 @@ class FutureMidiConvertM5(MidiConvert):
加入同刻偏移算法优化音感 加入同刻偏移算法优化音感
""" """
def to_music_channels(
self,
) -> ChannelType:
"""
使用金羿的转换思路将midi解析并转换为频道信息字典
Returns
-------
以频道作为分割的Midi信息字典:
Dict[int,Dict[int,List[Union[Tuple[Literal["PgmC"], int, int],Tuple[Literal["NoteS"], int, int, int],Tuple[Literal["NoteE"], int, int],]],],]
"""
if self.midi is None:
raise MidiUnboundError(
"你是否正在使用的是一个由 copy_important 生成的MidiConvert对象这是不可复用的。"
)
# 一个midi中仅有16个通道 我们通过通道来识别而不是音轨
midi_channels: ChannelType = empty_midi_channels()
tempo = 500000
# 我们来用通道统计音乐信息
# 但是是用分轨的思路的
for track_no, track in enumerate(self.midi.tracks):
microseconds = 0
if not track:
continue
note_queue = empty_midi_channels(staff=[])
for msg in track:
if msg.time != 0:
microseconds += msg.time * tempo / self.midi.ticks_per_beat / 1000
if msg.is_meta:
if msg.type == "set_tempo":
tempo = msg.tempo
else:
try:
if not track_no in midi_channels[msg.channel].keys():
midi_channels[msg.channel][track_no] = []
except AttributeError as E:
print(msg, E)
if msg.type == "program_change":
midi_channels[msg.channel][track_no].append(
("PgmC", msg.program, microseconds)
)
elif msg.type == "note_on" and msg.velocity != 0:
midi_channels[msg.channel][track_no].append(
("NoteS", msg.note, msg.velocity, microseconds)
)
elif (msg.type == "note_on" and msg.velocity == 0) or (
msg.type == "note_off"
):
midi_channels[msg.channel][track_no].append(
("NoteE", msg.note, microseconds)
)
"""整合后的音乐通道格式
每个通道包括若干消息元素其中逃不过这三种
1 切换乐器消息
("PgmC", 切换后的乐器ID: int, 距离演奏开始的毫秒)
2 音符开始消息
("NoteS", 开始的音符ID, 力度响度, 距离演奏开始的毫秒)
3 音符结束消息
("NoteE", 结束的音符ID, 距离演奏开始的毫秒)"""
del tempo, self.channels
self.channels: ChannelType = midi_channels
# [print([print(no,tno,sum([True if i[0] == 'NoteS' else False for i in track])) for tno,track in cna.items()]) if cna else False for no,cna in midi_channels.items()]
return midi_channels
# 神奇的偏移音 # 神奇的偏移音
def to_command_list_in_delay( def to_command_list_in_delay(
self, self,
@ -237,9 +291,9 @@ class FutureMidiConvertM5(MidiConvert):
elif msg[0] == "NoteS": elif msg[0] == "NoteS":
soundID, _X = ( soundID, _X = (
self.perc_inst_to_soundID_withX(msg[1]) inst_to_sould_with_deviation(msg[1],MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE)
if SpecialBits if SpecialBits
else self.inst_to_souldID_withX(InstID) else inst_to_sould_with_deviation(InstID,MM_CLASSIC_PITCHED_INSTRUMENT_TABLE)
) )
score_now = round(msg[-1] / float(speed) / 50) score_now = round(msg[-1] / float(speed) / 50)

View File

@ -77,6 +77,15 @@ class MidiConvert:
midi: VoidMido midi: VoidMido
"""MidiFile对象""" """MidiFile对象"""
pitched_note_reference_table: Dict[int, Tuple[str, int]]
"""乐音乐器Midi-MC对照表"""
percussion_note_referrence_table: Dict[int, Tuple[str, int]]
"""打击乐器Midi-MC对照表"""
volume_processing_function: Callable[[float], float]
"""音量处理函数"""
midi_music_name: str midi_music_name: str
"""Midi乐曲名""" """Midi乐曲名"""
@ -103,6 +112,13 @@ class MidiConvert:
midi_obj: VoidMido, midi_obj: VoidMido,
midi_name: str, midi_name: str,
enable_old_exe_format: bool = False, enable_old_exe_format: bool = False,
pitched_note_rtable: Dict[
int, Tuple[str, int]
] = MM_TOUCH_PITCHED_INSTRUMENT_TABLE,
percussion_note_rtable: Dict[
int, Tuple[str, int]
] = MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE,
vol_processing_function: Callable[[float], float] = natural_curve,
): ):
""" """
简单的midi转换类将midi对象转换为我的世界结构或者包 简单的midi转换类将midi对象转换为我的世界结构或者包
@ -115,6 +131,10 @@ class MidiConvert:
此音乐之名 此音乐之名
enable_old_exe_format: bool enable_old_exe_format: bool
是否启用旧版(1.19)指令格式默认为否 是否启用旧版(1.19)指令格式默认为否
pitched_note_rtable: Dict[int, Tuple[str, int]]
乐音乐器Midi-MC对照表
percussion_note_rtable: Dict[int, Tuple[str, int]]
打击乐器Midi-MC对照表
""" """
self.midi: VoidMido = midi_obj self.midi: VoidMido = midi_obj
@ -129,6 +149,10 @@ class MidiConvert:
else "execute as {} at @s positioned ~ ~ ~ run " else "execute as {} at @s positioned ~ ~ ~ run "
) )
self.pitched_note_reference_table = pitched_note_rtable
self.percussion_note_referrence_table = percussion_note_rtable
self.volume_processing_function = vol_processing_function
self.progress_bar_command = self.music_command_list = [] self.progress_bar_command = self.music_command_list = []
self.channels = {} self.channels = {}
self.music_tick_num = 0 self.music_tick_num = 0
@ -138,6 +162,13 @@ class MidiConvert:
cls, cls,
midi_file_path: str, midi_file_path: str,
old_exe_format: bool = False, old_exe_format: bool = False,
pitched_note_table: Dict[
int, Tuple[str, int]
] = MM_TOUCH_PITCHED_INSTRUMENT_TABLE,
percussion_note_table: Dict[
int, Tuple[str, int]
] = MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE,
vol_processing_func: Callable[[float], float] = natural_curve,
): ):
""" """
直接输入文件地址将midi文件读入 直接输入文件地址将midi文件读入
@ -148,6 +179,10 @@ class MidiConvert:
midi文件地址 midi文件地址
enable_old_exe_format: bool enable_old_exe_format: bool
是否启用旧版(1.19)指令格式默认为否 是否启用旧版(1.19)指令格式默认为否
pitched_note_table: Dict[int, Tuple[str, int]]
乐音乐器Midi-MC对照表
percussion_note_table: Dict[int, Tuple[str, int]]
打击乐器Midi-MC对照表
""" """
midi_music_name = os.path.splitext(os.path.basename(midi_file_path))[0].replace( midi_music_name = os.path.splitext(os.path.basename(midi_file_path))[0].replace(
@ -160,6 +195,9 @@ class MidiConvert:
mido.MidiFile(midi_file_path, clip=True), mido.MidiFile(midi_file_path, clip=True),
midi_music_name, midi_music_name,
old_exe_format, old_exe_format,
pitched_note_table,
percussion_note_table,
vol_processing_func,
) )
except (ValueError, TypeError) as E: except (ValueError, TypeError) as E:
raise MidiDestroyedError(f"文件{midi_file_path}损坏:{E}") raise MidiDestroyedError(f"文件{midi_file_path}损坏:{E}")
@ -447,6 +485,7 @@ class MidiConvert:
def to_music_note_channels( def to_music_note_channels(
self, self,
default_tempo_value: int = mido.midifiles.midifiles.DEFAULT_TEMPO,
ignore_mismatch_error: bool = True, ignore_mismatch_error: bool = True,
) -> NoteChannelType: ) -> NoteChannelType:
""" """
@ -465,7 +504,7 @@ class MidiConvert:
# 一个midi中仅有16个通道 我们通过通道来识别而不是音轨 # 一个midi中仅有16个通道 我们通过通道来识别而不是音轨
midi_channels: NoteChannelType = empty_midi_channels(staff=[]) midi_channels: NoteChannelType = empty_midi_channels(staff=[])
tempo = mido.midifiles.midifiles.DEFAULT_TEMPO tempo = default_tempo_value
# 我们来用通道统计音乐信息 # 我们来用通道统计音乐信息
# 但是是用分轨的思路的 # 但是是用分轨的思路的
@ -624,6 +663,20 @@ class MidiConvert:
score_now = round(note.start_time / float(speed) / 50) score_now = round(note.start_time / float(speed) / 50)
max_score = max(max_score, score_now) max_score = max(max_score, score_now)
(
mc_sound_ID,
mc_distance_volume,
volume_percentage,
mc_pitch,
) = note_to_command_parameters(
note,
self.percussion_note_referrence_table
if note.percussive
else self.pitched_note_reference_table,
(max_volume) if note.track_no == 0 else (max_volume * 0.9),
self.volume_processing_function,
)
this_channel.append( this_channel.append(
SingleCommand( SingleCommand(
self.execute_cmd_head.format( self.execute_cmd_head.format(
@ -631,13 +684,13 @@ class MidiConvert:
.replace("(", r"{") .replace("(", r"{")
.replace(")", r"}") .replace(")", r"}")
) )
+ note.to_command( + r"playsound {} @s ^ ^ ^{} {} {}".format(
(max_volume) if note.track_no == 0 else (max_volume * 0.9) mc_sound_ID, mc_distance_volume, volume_percentage, mc_pitch
), ),
annotation="{}播放{}%{}".format( annotation="{}播放{}%{}".format(
mctick2timestr(score_now), mctick2timestr(score_now),
max_volume * 100, max_volume * 100,
"{}:{}".format(note.mc_sound_ID, note.mc_pitch), "{}:{:.2f}".format(mc_sound_ID, mc_pitch),
), ),
), ),
) )
@ -697,17 +750,35 @@ class MidiConvert:
else: else:
max_multi = max(max_multi, multi) max_multi = max(max_multi, multi)
multi = 0 multi = 0
(
mc_sound_ID,
mc_distance_volume,
volume_percentage,
mc_pitch,
) = note_to_command_parameters(
note,
self.percussion_note_referrence_table
if note.percussive
else self.pitched_note_reference_table,
(max_volume) if note.track_no == 0 else (max_volume * 0.9),
self.volume_processing_function,
)
self.music_command_list.append( self.music_command_list.append(
SingleCommand( SingleCommand(
self.execute_cmd_head.format(player_selector) self.execute_cmd_head.format(player_selector)
+ note.to_command( + r"playsound {} @s ^ ^ ^{} {} {}".format(
(max_volume) if note.track_no == 0 else (max_volume * 0.9) mc_sound_ID,
mc_distance_volume,
volume_percentage,
mc_pitch,
), ),
tick_delay=tickdelay, tick_delay=tickdelay,
annotation="{}播放{}%{}".format( annotation="{}播放{}%{}".format(
mctick2timestr(delaytime_now), mctick2timestr(delaytime_now),
max_volume * 100, max_volume * 100,
"{}:{}".format(note.mc_sound_ID, note.mc_pitch), "{}:{:.2f}".format(mc_sound_ID, mc_pitch),
), ),
) )
) )

View File

@ -19,7 +19,7 @@ Terms & Conditions: License.md in the root directory
from ..exceptions import NotDefineProgramError, ZeroSpeedError from ..exceptions import NotDefineProgramError, ZeroSpeedError
from ..main import MidiConvert from ..main import MidiConvert
from ..subclass import SingleCommand from ..subclass import SingleCommand
from ..utils import inst_to_souldID_withX, perc_inst_to_soundID_withX from ..utils import inst_to_sould_with_deviation, perc_inst_to_soundID_withX
# 你以为写完了吗?其实并没有 # 你以为写完了吗?其实并没有
@ -71,13 +71,13 @@ def to_note_list(
soundID, _X = ( soundID, _X = (
perc_inst_to_soundID_withX(InstID) perc_inst_to_soundID_withX(InstID)
if SpecialBits if SpecialBits
else inst_to_souldID_withX(InstID) else inst_to_sould_with_deviation(InstID)
) )
except UnboundLocalError as E: except UnboundLocalError as E:
soundID, _X = ( soundID, _X = (
perc_inst_to_soundID_withX(-1) perc_inst_to_soundID_withX(-1)
if SpecialBits if SpecialBits
else inst_to_souldID_withX(-1) else inst_to_sould_with_deviation(-1)
) )
score_now = round(msg[-1] / float(speed) / 50) score_now = round(msg[-1] / float(speed) / 50)
# print(score_now) # print(score_now)

View File

@ -20,6 +20,7 @@ from .main import MidiConvert, mido
from .subclass import * from .subclass import *
from .types import ChannelType from .types import ChannelType
from .utils import * from .utils import *
from .constants import *
class ObsoleteMidiConvert(MidiConvert): class ObsoleteMidiConvert(MidiConvert):
@ -153,9 +154,9 @@ class ObsoleteMidiConvert(MidiConvert):
) )
maxscore = max(maxscore, nowscore) maxscore = max(maxscore, nowscore)
if msg.channel == 9: if msg.channel == 9:
soundID, _X = perc_inst_to_soundID_withX(instrumentID) soundID, _X = inst_to_sould_with_deviation(instrumentID,MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE)
else: else:
soundID, _X = inst_to_souldID_withX(instrumentID) soundID, _X = inst_to_sould_with_deviation(instrumentID,MM_CLASSIC_PITCHED_INSTRUMENT_TABLE)
singleTrack.append( singleTrack.append(
"execute @a[scores={" "execute @a[scores={"
@ -212,7 +213,10 @@ class ObsoleteMidiConvert(MidiConvert):
(ticks * tempo) / ((self.midi.ticks_per_beat * float(speed)) * 50000) # type: ignore (ticks * tempo) / ((self.midi.ticks_per_beat * float(speed)) * 50000) # type: ignore
) )
maxscore = max(maxscore, nowscore) maxscore = max(maxscore, nowscore)
soundID, _X = inst_to_souldID_withX(instrumentID) if msg.channel == 9:
soundID, _X = inst_to_sould_with_deviation(instrumentID,MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE)
else:
soundID, _X = inst_to_sould_with_deviation(instrumentID,MM_CLASSIC_PITCHED_INSTRUMENT_TABLE)
singleTrack.append( singleTrack.append(
"execute @a[scores={" "execute @a[scores={"
+ str(scoreboardname) + str(scoreboardname)
@ -273,9 +277,9 @@ class ObsoleteMidiConvert(MidiConvert):
elif msg[0] == "NoteS": elif msg[0] == "NoteS":
soundID, _X = ( soundID, _X = (
perc_inst_to_soundID_withX(msg[1]) inst_to_sould_with_deviation(msg[1],MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE)
if SpecialBits if SpecialBits
else inst_to_souldID_withX(InstID) else inst_to_sould_with_deviation(InstID,MM_CLASSIC_PITCHED_INSTRUMENT_TABLE)
) )
score_now = round(msg[-1] / float(speed) / 50) score_now = round(msg[-1] / float(speed) / 50)
maxScore = max(maxScore, score_now) maxScore = max(maxScore, score_now)
@ -339,7 +343,11 @@ class ObsoleteMidiConvert(MidiConvert):
(ticks * tempo) (ticks * tempo)
/ ((self.midi.ticks_per_beat * float(speed)) * 50000) / ((self.midi.ticks_per_beat * float(speed)) * 50000)
) )
soundID, _X = inst_to_souldID_withX(instrumentID)
if msg.channel == 9:
soundID, _X = inst_to_sould_with_deviation(instrumentID,MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE)
else:
soundID, _X = inst_to_sould_with_deviation(instrumentID,MM_CLASSIC_PITCHED_INSTRUMENT_TABLE)
try: try:
tracks[now_tick].append( tracks[now_tick].append(
self.execute_cmd_head.format(player) self.execute_cmd_head.format(player)
@ -413,9 +421,9 @@ class ObsoleteMidiConvert(MidiConvert):
elif msg[0] == "NoteS": elif msg[0] == "NoteS":
soundID, _X = ( soundID, _X = (
perc_inst_to_soundID_withX(msg[1]) inst_to_sould_with_deviation(msg[1],MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE)
if SpecialBits if SpecialBits
else inst_to_souldID_withX(InstID) else inst_to_sould_with_deviation(InstID,MM_CLASSIC_PITCHED_INSTRUMENT_TABLE)
) )
score_now = round(msg[-1] / float(speed) / 50) score_now = round(msg[-1] / float(speed) / 50)

View File

@ -18,10 +18,9 @@ Terms & Conditions: License.md in the root directory
from dataclasses import dataclass from dataclasses import dataclass
from typing import Optional from typing import Optional, Any
from .constants import PERCUSSION_INSTRUMENT_LIST from .constants import MC_PERCUSSION_INSTRUMENT_LIST
from .utils import inst_to_souldID_withX, perc_inst_to_soundID_withX, volume2distance
@dataclass(init=False) @dataclass(init=False)
@ -49,6 +48,9 @@ class SingleNote:
percussive: bool percussive: bool
"""是否为打击乐器""" """是否为打击乐器"""
extra_info: Any
"""你觉得放什么好?"""
def __init__( def __init__(
self, self,
instrument: int, instrument: int,
@ -58,6 +60,7 @@ class SingleNote:
lastime: int, lastime: int,
track_number: int = 0, track_number: int = 0,
is_percussion: Optional[bool] = None, is_percussion: Optional[bool] = None,
extra_information: Any = None,
): ):
"""用于存储单个音符的类 """用于存储单个音符的类
:param instrument 乐器编号 :param instrument 乐器编号
@ -80,12 +83,14 @@ class SingleNote:
"""音符所处的音轨""" """音符所处的音轨"""
self.percussive = ( self.percussive = (
(is_percussion in PERCUSSION_INSTRUMENT_LIST) (is_percussion in MC_PERCUSSION_INSTRUMENT_LIST)
if (is_percussion is None) if (is_percussion is None)
else is_percussion else is_percussion
) )
"""是否为打击乐器""" """是否为打击乐器"""
self.extra_info = extra_information
@property @property
def inst(self) -> int: def inst(self) -> int:
"""乐器编号""" """乐器编号"""
@ -100,14 +105,14 @@ class SingleNote:
"""音符编号""" """音符编号"""
return self.note return self.note
@property # @property
def get_mc_pitch(self) -> float: # def get_mc_pitch(self,table: Dict[int, Tuple[str, int]]) -> float:
self.mc_sound_ID, _X = ( # self.mc_sound_ID, _X = inst_to_sould_with_deviation(self.inst,table,"note.bd" if self.percussive else "note.flute",)
perc_inst_to_soundID_withX(self.inst) # return -1 if self.percussive else 2 ** ((self.note - 60 - _X) / 12)
if self.percussive
else inst_to_souldID_withX(self.inst) def set_info(self, sth: Any):
) """设置附加信息"""
return -1 if self.percussive else 2 ** ((self.note - 60 - _X) / 12) self.extra_info = sth
def __str__(self, is_track: bool = False): def __str__(self, is_track: bool = False):
return "{}Note(Instrument = {}, {}Velocity = {}, StartTime = {}, Duration = {}{})".format( return "{}Note(Instrument = {}, {}Velocity = {}, StartTime = {}, Duration = {}{})".format(
@ -168,31 +173,6 @@ class SingleNote:
return False return False
return self.__str__() == other.__str__() return self.__str__() == other.__str__()
def to_command(self, volume_percentage: float = 1) -> str:
"""
将音符转为播放的指令
:param volume_percentage:int 音量占比(0,1]
:return str指令
"""
self.mc_sound_ID, _X = (
perc_inst_to_soundID_withX(self.inst)
if self.percussive
else inst_to_souldID_withX(self.inst)
)
# delaytime_now = round(self.start_time / float(speed) / 50)
self.mc_pitch = "" if self.percussive else 2 ** ((self.note - 60 - _X) / 12)
self.mc_distance_volume = volume2distance(self.velocity * volume_percentage)
return "playsound {} @s ^ ^ ^{} {} {}".format(
self.mc_sound_ID,
self.mc_distance_volume,
volume_percentage,
self.mc_pitch,
)
@dataclass(init=False) @dataclass(init=False)
class SingleCommand: class SingleCommand:
@ -304,7 +284,7 @@ class SingleNoteBox:
self.annotation_text = annotation self.annotation_text = annotation
"""音符注释""" """音符注释"""
if percussion is None: if percussion is None:
self.is_percussion = percussion in PERCUSSION_INSTRUMENT_LIST self.is_percussion = percussion in MC_PERCUSSION_INSTRUMENT_LIST
else: else:
self.is_percussion = percussion self.is_percussion = percussion

View File

@ -16,9 +16,12 @@ Terms & Conditions: License.md in the root directory
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md # 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
import math import math
import random
from .constants import PERCUSSION_INSTRUMENT_TABLE, PITCHED_INSTRUMENT_TABLE from .constants import MM_INSTRUMENT_DEVIATION_TABLE, MC_INSTRUMENT_BLOCKS_TABLE
from typing import Any, Dict, Tuple from .subclass import SingleNote
from typing import Any, Dict, Tuple, Optional, Callable, Literal, Union
def mctick2timestr(mc_tick: int) -> str: def mctick2timestr(mc_tick: int) -> str:
@ -42,8 +45,11 @@ def empty_midi_channels(channel_count: int = 17, staff: Any = {}) -> Dict[int, A
) )
def inst_to_souldID_withX( def inst_to_sould_with_deviation(
instrumentID: int, instrumentID: int,
reference_table: Dict[int, Tuple[str, int]],
default_instrument: str = "note.flute",
default_deviation: Optional[int] = 5,
) -> Tuple[str, int]: ) -> Tuple[str, int]:
""" """
返回midi的乐器ID对应的我的世界乐器名对于音域转换算法如下 返回midi的乐器ID对应的我的世界乐器名对于音域转换算法如下
@ -60,40 +66,30 @@ def inst_to_souldID_withX(
---------- ----------
instrumentID: int instrumentID: int
midi的乐器ID midi的乐器ID
reference_table: Dict[int, Tuple[str, int]]
转换乐器参照表
Returns Returns
------- -------
tuple(str我的世界乐器名, int转换算法中的X) tuple(str我的世界乐器名, int转换算法中的X)
""" """
try: return reference_table.get(
return PITCHED_INSTRUMENT_TABLE[instrumentID] instrumentID,
except KeyError: (
return "note.flute", 5 default_instrument,
default_deviation
if default_deviation
def perc_inst_to_soundID_withX(instrumentID: int) -> Tuple[str, int]: else MM_INSTRUMENT_DEVIATION_TABLE.get(default_instrument, -1),
""" ),
对于Midi第10通道所对应的打击乐器返回我的世界乐器名 )
Parameters
----------
instrumentID: int
midi的乐器ID
Returns
-------
tuple(str我的世界乐器名, int转换算法中的X)
"""
try:
return PERCUSSION_INSTRUMENT_TABLE[instrumentID]
except KeyError:
return "note.bd", 7
# 明明已经走了 # 明明已经走了
# 凭什么还要在我心里留下缠绵缱绻 # 凭什么还要在我心里留下缠绵缱绻
def volume2distance(vol: float) -> float: def natural_curve(
vol: float,
) -> float:
""" """
midi力度值拟合成的距离函数 midi力度值拟合成的距离函数
@ -117,3 +113,97 @@ def volume2distance(vol: float) -> float:
+ -6.313841334963396 * (vol + 2592.272889454798) + -6.313841334963396 * (vol + 2592.272889454798)
+ 4558.496367823575 + 4558.496367823575
) )
def straight_line(vol: float) -> float:
"""
midi力度值拟合成的距离函数
Parameters
----------
vol: int
midi音符力度值
Returns
-------
float播放中心到玩家的距离
"""
return vol / -8 + 16
def note_to_command_parameters(
note_: SingleNote,
reference_table: Dict[int, Tuple[str, int]],
volume_percentage: float = 1,
volume_processing_method: Callable[[float], float] = natural_curve,
) -> Tuple[str, float, float, Union[float, Literal[None]],]:
"""
将音符转为播放的指令
:param note_:int 音符对象
:param reference_table:Dict[int, Tuple[str, int]] 转换对照表
:param volume_percentage:int 音量占比(0,1]
:param volume_proccessing_method:Callable[[float], float]: 音量处理函数
:return str[我的世界音符ID], float[播放距离], float[指令音量参数], float[指令音调参数]
"""
mc_sound_ID, deviation = inst_to_sould_with_deviation(
note_.inst,
reference_table,
"note.bd" if note_.percussive else "note.flute",
)
# delaytime_now = round(self.start_time / float(speed) / 50)
mc_pitch = None if note_.percussive else 2 ** ((note_.note - 60 - deviation) / 12)
mc_distance_volume = volume_processing_method(note_.velocity * volume_percentage)
return mc_sound_ID, mc_distance_volume, volume_percentage, mc_pitch
def from_single_note(
note_: SingleNote, random_select: bool = False, default_block: str = "air"
):
"""
将我的世界乐器名改作音符盒所需的对应方块名称
Parameters
----------
note_: SingleNote
音符类
random_select: bool
是否随机选取对应方块
default_block: str
查表查不到怎么办默认一个
Returns
-------
str方块名称
"""
pass
# return SingleNoteBox() # TO-DO
@staticmethod
def soundID_to_blockID(
sound_id: str, random_select: bool = False, default_block: str = "air"
) -> str:
"""
将我的世界乐器名改作音符盒所需的对应方块名称
Parameters
----------
sound_id: str
将我的世界乐器名
random_select: bool
是否随机选取对应方块
default_block: str
查表查不到怎么办默认一个
Returns
-------
str方块名称
"""
if random_select:
return random.choice(MC_INSTRUMENT_BLOCKS_TABLE.get(sound_id, (default_block,)))
else:
return MC_INSTRUMENT_BLOCKS_TABLE.get(sound_id, (default_block,))[0]