9 Commits

Author SHA1 Message Date
EillesWan
041c64ff65 优化example结构,支持mcstructure的计分板播放 2024-02-03 16:54:43 +08:00
EillesWan
b0bdb7b445 修复了乐音乐器的execute前缀缺失的问题 2024-02-02 20:50:35 +08:00
EillesWan
99a7564648 修复了打击乐器转换时,注释部分format代码报错的问题 2024-02-02 18:12:29 +08:00
EillesWan
dbb3f4c83f 修复了一个小兼容性bug 2024-01-23 18:36:25 +08:00
EillesWan
edd40c078f 加个copy方法 2024-01-23 18:17:15 +08:00
EillesWan
d3b637a0c8 修复类型定义的重复问题-2 2024-01-23 18:14:41 +08:00
EillesWan
d7e3c62deb 修复类型定义的重复问题 2024-01-23 17:01:42 +08:00
EillesWan
7b319268fe 改个版本号 2024-01-14 22:08:27 +08:00
EillesWan
41883f7798 可以用了(?) 2024-01-14 22:05:55 +08:00
40 changed files with 1612 additions and 533 deletions

3
.gitignore vendored
View File

@@ -18,6 +18,9 @@
/utils /utils
test.py test.py
RES.txt RES.txt
/MSCT_Packer.py
/Packer/*.MPK
/Packer/checksum.txt
# Byte-compiled / optimized # Byte-compiled / optimized
__pycache__/ __pycache__/

View File

@@ -5,8 +5,8 @@
Musicreater(音·创) Musicreater(音·创)
A free open source library used for convert midi file into formats that is suitable for **Minecraft**. A free open source library used for convert midi file into formats that is suitable for **Minecraft**.
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory
@@ -17,8 +17,8 @@ Terms & Conditions: License.md in the root directory
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md # 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
__version__ = "1.6.2" __version__ = "1.7.3"
__vername__ = "新的转换算法测试,更好的声音适配" __vername__ = "功能结构化"
__author__ = ( __author__ = (
("金羿", "Eilles Wan"), ("金羿", "Eilles Wan"),
("诸葛亮与八卦阵", "bgArray"), ("诸葛亮与八卦阵", "bgArray"),
@@ -31,7 +31,15 @@ __all__ = [
# 附加类 # 附加类
"SingleNote", "SingleNote",
"SingleCommand", "SingleCommand",
"SingleNoteBox",
# "TimeStamp", 未来功能 # "TimeStamp", 未来功能
# 默认值
"DEFAULT_PROGRESSBAR_STYLE",
"MM_INSTRUMENT_DEVIATION_TABLE",
"MM_CLASSIC_PITCHED_INSTRUMENT_TABLE",
"MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE",
"MM_TOUCH_PITCHED_INSTRUMENT_TABLE",
"MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE",
] ]
from .main import * from .main import *

View File

@@ -5,8 +5,8 @@
""" """
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory
@@ -16,7 +16,7 @@ Terms & Conditions: License.md in the root directory
# Email TriM-Organization@hotmail.com # Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md # 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
from typing import Dict, List, Tuple from .types import Dict, List, Tuple, MidiInstrumentTableType, MidiNoteNameTableType
x = "x" x = "x"
""" """
@@ -33,13 +33,8 @@ z = "z"
z z
""" """
DEFAULT_PROGRESSBAR_STYLE = (
r"%%N [ %%s/%^s %%% __________ %%t|%^t ]", # Midi用对照表
("§e=§r", "§7=§r"),
)
"""
默认的进度条样式组
"""
MIDI_PITCH_NAME_TABLE: Dict[int, str] = { MIDI_PITCH_NAME_TABLE: Dict[int, str] = {
0: "C", 0: "C",
@@ -171,12 +166,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 +675,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 +683,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 +743,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

@@ -5,8 +5,8 @@
""" """
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory

View File

@@ -5,8 +5,8 @@
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory
@@ -16,14 +16,16 @@ 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 +36,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 +79,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 +124,21 @@ 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 +158,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 +178,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 +305,13 @@ 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

@@ -22,24 +22,24 @@
Musicreater (音·创) Musicreater (音·创)
A free open source library used for convert midi file into formats that is suitable for **Minecraft**. A free open source library used for convert midi file into formats that is suitable for **Minecraft**.
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 ../License.md 开源相关声明请见 ../License.md
Terms & Conditions: ../License.md Terms & Conditions: ../License.md
""" """
# ============================ # ============================
import mido import mido
class NoteMessage: class NoteMessage:
def __init__(self, channel, pitch, velocity, startT, lastT, midi, now_bpm, change_bpm=None): def __init__(
self, channel, pitch, velocity, startT, lastT, midi, now_bpm, change_bpm=None
):
self.channel = channel self.channel = channel
self.note = pitch self.note = pitch
self.velocity = velocity self.velocity = velocity
@@ -49,19 +49,39 @@ class NoteMessage:
def mt2gt(mt, tpb_a, bpm_a): def mt2gt(mt, tpb_a, bpm_a):
return mt / tpb_a / bpm_a * 60 return mt / tpb_a / bpm_a * 60
self.startTrueTime = mt2gt(self.startTime, midi.ticks_per_beat, self.tempo) # / 20
self.startTrueTime = mt2gt(
self.startTime, midi.ticks_per_beat, self.tempo
) # / 20
# delete_extra_zero(round_up()) # delete_extra_zero(round_up())
if change_bpm is not None: if change_bpm is not None:
self.lastTrueTime = mt2gt(self.lastTime, midi.ticks_per_beat, change_bpm) # / 20 self.lastTrueTime = mt2gt(
self.lastTime, midi.ticks_per_beat, change_bpm
) # / 20
else: else:
self.lastTrueTime = mt2gt(self.lastTime, midi.ticks_per_beat, self.tempo) # / 20 self.lastTrueTime = mt2gt(
self.lastTime, midi.ticks_per_beat, self.tempo
) # / 20
# delete_extra_zero(round_up()) # delete_extra_zero(round_up())
print((self.startTime * self.tempo) / (midi.ticks_per_beat * 50000)) print((self.startTime * self.tempo) / (midi.ticks_per_beat * 50000))
def __str__(self): def __str__(self):
return "noteMessage channel=" + str(self.channel) + " note=" + str(self.note) + " velocity=" + \ return (
str(self.velocity) + " startTime=" + str(self.startTime) + " lastTime=" + str(self.lastTime) + \ "noteMessage channel="
" startTrueTime=" + str(self.startTrueTime) + " lastTrueTime=" + str(self.lastTrueTime) + str(self.channel)
+ " note="
+ str(self.note)
+ " velocity="
+ str(self.velocity)
+ " startTime="
+ str(self.startTime)
+ " lastTime="
+ str(self.lastTime)
+ " startTrueTime="
+ str(self.startTrueTime)
+ " lastTrueTime="
+ str(self.lastTrueTime)
)
def load(mid: mido.MidiFile): def load(mid: mido.MidiFile):
@@ -75,7 +95,7 @@ def load(mid: mido.MidiFile):
for msg in track: for msg in track:
# print(msg) # print(msg)
if msg.is_meta is not True: if msg.is_meta is not True:
if msg.type == 'note_on' and msg.velocity == 0: if msg.type == "note_on" and msg.velocity == 0:
type_[1] = True type_[1] = True
elif msg.type == "note_off": elif msg.type == "note_off":
type_[0] = True type_[0] = True
@@ -105,13 +125,13 @@ def load(mid: mido.MidiFile):
print(ticks) print(ticks)
if msg.is_meta is True and msg.type == "set_tempo": if msg.is_meta is True and msg.type == "set_tempo":
recent_change_bpm = bpm recent_change_bpm = bpm
bpm = 60000000 / msg.tempo bpm = 60000000 / msg.tempo
is_change_bpm = True is_change_bpm = True
if msg.type == 'note_on' and msg.velocity != 0: if msg.type == "note_on" and msg.velocity != 0:
noteOn.append([msg, msg.note, ticks]) noteOn.append([msg, msg.note, ticks])
if type_[1] is True: if type_[1] is True:
if msg.type == 'note_on' and msg.velocity == 0: if msg.type == "note_on" and msg.velocity == 0:
for u in noteOn: for u in noteOn:
index = 0 index = 0
if u[1] == msg.note: if u[1] == msg.note:
@@ -121,13 +141,31 @@ def load(mid: mido.MidiFile):
index += 1 index += 1
print(lastTick) print(lastTick)
if is_change_bpm and recent_change_bpm != 0: if is_change_bpm and recent_change_bpm != 0:
trackS.append(NoteMessage(msg.channel, msg.note, lastMessage.velocity, lastTick, ticks - lastTick, trackS.append(
mid, recent_change_bpm, bpm)) NoteMessage(
msg.channel,
msg.note,
lastMessage.velocity,
lastTick,
ticks - lastTick,
mid,
recent_change_bpm,
bpm,
)
)
is_change_bpm = False is_change_bpm = False
else: else:
trackS.append( trackS.append(
NoteMessage(msg.channel, msg.note, lastMessage.velocity, lastTick, ticks - lastTick, NoteMessage(
mid, bpm)) msg.channel,
msg.note,
lastMessage.velocity,
lastTick,
ticks - lastTick,
mid,
bpm,
)
)
# print(noteOn) # print(noteOn)
# print(index) # print(index)
try: try:
@@ -139,20 +177,19 @@ def load(mid: mido.MidiFile):
print(j) print(j)
if __name__ == '__main__': if __name__ == "__main__":
load(mido.MidiFile("test.mid")) load(mido.MidiFile("test.mid"))
# ============================ # ============================
from typing import Literal from typing import Literal
from ..constants import x,y,z from ..constants import x, y, z
# 不要用 没写完 # 不要用 没写完
def delay_to_note_blocks( def delay_to_note_blocks(
baseblock: str = "stone", baseblock: str = "stone",
position_forward: Literal['x','y','z'] = z, position_forward: Literal["x", "y", "z"] = z,
): ):
"""传入音符,生成以音符盒存储的红石音乐 """传入音符,生成以音符盒存储的红石音乐
:param: :param:
@@ -169,8 +206,7 @@ def delay_to_note_blocks(
log = print log = print
startpos = [0,0,0] startpos = [0, 0, 0]
# 1拍 x 2.5 rt # 1拍 x 2.5 rt
for i in notes: for i in notes:
@@ -180,7 +216,10 @@ def delay_to_note_blocks(
[startpos[0], startpos[1] + 1, startpos[2]], [startpos[0], startpos[1] + 1, startpos[2]],
form_note_block_in_NBT_struct(height2note[i[0]], instrument), form_note_block_in_NBT_struct(height2note[i[0]], instrument),
) )
struct.set_block(startpos, Block("universal_minecraft", instuments[i[0]][1]),) struct.set_block(
startpos,
Block("universal_minecraft", instuments[i[0]][1]),
)
error = False error = False
except ValueError: except ValueError:
log("无法放置音符:" + str(i) + "" + str(startpos)) log("无法放置音符:" + str(i) + "" + str(startpos))

View File

@@ -7,8 +7,8 @@
Musicreater (音·创) Musicreater (音·创)
A free open source library used for convert midi file into formats that is suitable for **Minecraft**. A free open source library used for convert midi file into formats that is suitable for **Minecraft**.
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory
@@ -28,6 +28,8 @@ Terms & Conditions: License.md in the root directory
import math import math
import os import os
import mido
from .constants import * from .constants import *
from .exceptions import * from .exceptions import *
from .subclass import * from .subclass import *
@@ -68,6 +70,12 @@ tick * tempo / 1000000.0 / ticks_per_beat * 一秒多少游戏刻
""" """
VoidMido = Union[mido.MidiFile, None] # void mido
"""
空Midi类类型
"""
@dataclass(init=False) @dataclass(init=False)
class MidiConvert: class MidiConvert:
""" """
@@ -77,6 +85,15 @@ class MidiConvert:
midi: VoidMido midi: VoidMido
"""MidiFile对象""" """MidiFile对象"""
pitched_note_reference_table: MidiInstrumentTableType
"""乐音乐器Midi-MC对照表"""
percussion_note_referrence_table: MidiInstrumentTableType
"""打击乐器Midi-MC对照表"""
volume_processing_function: FittingFunctionType
"""音量处理函数"""
midi_music_name: str midi_music_name: str
"""Midi乐曲名""" """Midi乐曲名"""
@@ -103,6 +120,9 @@ 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: MidiInstrumentTableType = MM_TOUCH_PITCHED_INSTRUMENT_TABLE,
percussion_note_rtable: MidiInstrumentTableType = MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE,
vol_processing_function: FittingFunctionType = natural_curve,
): ):
""" """
简单的midi转换类将midi对象转换为我的世界结构或者包 简单的midi转换类将midi对象转换为我的世界结构或者包
@@ -115,6 +135,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 +153,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 +166,9 @@ 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: MidiInstrumentTableType = MM_TOUCH_PITCHED_INSTRUMENT_TABLE,
percussion_note_table: MidiInstrumentTableType = MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE,
vol_processing_func: FittingFunctionType = 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}")
@@ -173,7 +211,7 @@ class MidiConvert:
self, self,
max_score: int, max_score: int,
scoreboard_name: str, scoreboard_name: str,
progressbar_style: tuple = DEFAULT_PROGRESSBAR_STYLE, progressbar_style: ProgressBarStyle = DEFAULT_PROGRESSBAR_STYLE,
) -> List[SingleCommand]: ) -> List[SingleCommand]:
""" """
生成进度条 生成进度条
@@ -193,7 +231,7 @@ class MidiConvert:
------- -------
list[SingleCommand,] list[SingleCommand,]
""" """
pgs_style = progressbar_style[0] pgs_style = progressbar_style.base_style
"""用于被替换的进度条原始样式""" """用于被替换的进度条原始样式"""
""" """
@@ -222,8 +260,10 @@ class MidiConvert:
if r"%%%" in pgs_style: if r"%%%" in pgs_style:
result.append( result.append(
SingleCommand( SingleCommand(
'scoreboard objectives add {}PercT dummy "百分比计算"'.format(sbn_pc), 'scoreboard objectives add {}PercT dummy "百分比计算"'.format(
annotation="新增临时计算用计分板(百分比)", sbn_pc
),
annotation="新增临时百分比变量",
) )
) )
result.append( result.append(
@@ -234,7 +274,7 @@ class MidiConvert:
+ "scoreboard players set MaxScore {} {}".format( + "scoreboard players set MaxScore {} {}".format(
scoreboard_name, max_score scoreboard_name, max_score
), ),
annotation="设定音乐最大计分", annotation="设定音乐最大延迟分数",
) )
) )
result.append( result.append(
@@ -254,7 +294,7 @@ class MidiConvert:
+ "scoreboard players operation @s {} = @s {}".format( + "scoreboard players operation @s {} = @s {}".format(
sbn_pc + "PercT", scoreboard_name sbn_pc + "PercT", scoreboard_name
), ),
annotation="为临时变量赋值", annotation="赋值临时百分比",
) )
) )
result.append( result.append(
@@ -265,7 +305,7 @@ class MidiConvert:
+ "scoreboard players operation @s {} *= n100 {}".format( + "scoreboard players operation @s {} *= n100 {}".format(
sbn_pc + "PercT", scoreboard_name sbn_pc + "PercT", scoreboard_name
), ),
annotation="改变临时变量的单位为百分比(扩大精度)", annotation="转换临时百分比之单位至%(扩大精度)",
) )
) )
result.append( result.append(
@@ -276,7 +316,7 @@ class MidiConvert:
+ "scoreboard players operation @s {} /= MaxScore {}".format( + "scoreboard players operation @s {} /= MaxScore {}".format(
sbn_pc + "PercT", scoreboard_name sbn_pc + "PercT", scoreboard_name
), ),
annotation="使用临时变量计算百分比", annotation="计算百分比",
) )
) )
@@ -287,14 +327,18 @@ class MidiConvert:
if r"%%t" in pgs_style: if r"%%t" in pgs_style:
result.append( result.append(
SingleCommand( SingleCommand(
'scoreboard objectives add {}TMinT dummy "时间计算:分"'.format(sbn_pc), 'scoreboard objectives add {}TMinT dummy "时间计算:分"'.format(
annotation="新增临时计算计分板(分)", sbn_pc
),
annotation="新增临时分变量",
) )
) )
result.append( result.append(
SingleCommand( SingleCommand(
'scoreboard objectives add {}TSecT dummy "时间计算:秒"'.format(sbn_pc), 'scoreboard objectives add {}TSecT dummy "时间计算:秒"'.format(
annotation="新增临时计算计分板(秒)", sbn_pc
),
annotation="新增临时秒变量",
) )
) )
result.append( result.append(
@@ -324,7 +368,7 @@ class MidiConvert:
+ "scoreboard players operation @s {} = @s {}".format( + "scoreboard players operation @s {} = @s {}".format(
sbn_pc + "TMinT", scoreboard_name sbn_pc + "TMinT", scoreboard_name
), ),
annotation="为临时变量(分)赋值", annotation="赋值临时分",
) )
) )
result.append( result.append(
@@ -335,7 +379,7 @@ class MidiConvert:
+ "scoreboard players operation @s {} /= n20 {}".format( + "scoreboard players operation @s {} /= n20 {}".format(
sbn_pc + "TMinT", scoreboard_name sbn_pc + "TMinT", scoreboard_name
), ),
annotation="将临时变量转换单位为秒(缩减精度)", annotation="转换临时分之单位为秒(缩减精度)",
) )
) )
result.append( result.append(
@@ -346,7 +390,7 @@ class MidiConvert:
+ "scoreboard players operation @s {} = @s {}".format( + "scoreboard players operation @s {} = @s {}".format(
sbn_pc + "TSecT", sbn_pc + "TMinT" sbn_pc + "TSecT", sbn_pc + "TMinT"
), ),
annotation="为临时变量(秒)赋值", annotation="赋值临时秒",
) )
) )
@@ -358,7 +402,7 @@ class MidiConvert:
+ "scoreboard players operation @s {} /= n60 {}".format( + "scoreboard players operation @s {} /= n60 {}".format(
sbn_pc + "TMinT", scoreboard_name sbn_pc + "TMinT", scoreboard_name
), ),
annotation="将临时变量(分)转换单位为分(缩减精度)", annotation="转换临时分之单位为分(缩减精度)",
) )
) )
@@ -370,42 +414,35 @@ class MidiConvert:
+ "scoreboard players operation @s {} %= n60 {}".format( + "scoreboard players operation @s {} %= n60 {}".format(
sbn_pc + "TSecT", scoreboard_name sbn_pc + "TSecT", scoreboard_name
), ),
annotation="将临时变量(秒)确定下来(框定精度区间)", annotation="确定临时秒(框定精度区间)",
) )
) )
for i in range(pgs_style.count("_")): for i in range(pgs_style.count("_")):
npg_stl = ( npg_stl = (
pgs_style.replace("_", progressbar_style[1][0], i + 1) pgs_style.replace("_", progressbar_style.played_style, i + 1)
.replace("_", progressbar_style[1][1]) .replace("_", progressbar_style.to_play_style)
.replace(r"%%N", self.midi_music_name) .replace(r"%%N", self.midi_music_name)
if r"%%N" in pgs_style .replace(
else pgs_style.replace("_", progressbar_style[1][0], i + 1).replace(
"_", progressbar_style[1][1]
)
)
if r"%%s" in npg_stl:
npg_stl = npg_stl.replace(
r"%%s", r"%%s",
'"},{"score":{"name":"*","objective":"' '"},{"score":{"name":"*","objective":"'
+ scoreboard_name + scoreboard_name
+ '"}},{"text":"', + '"}},{"text":"',
) )
if r"%%%" in npg_stl: .replace(
npg_stl = npg_stl.replace(
r"%%%", r"%%%",
r'"},{"score":{"name":"*","objective":"' r'"},{"score":{"name":"*","objective":"'
+ sbn_pc + sbn_pc
+ r'PercT"}},{"text":"%', + r'PercT"}},{"text":"%',
) )
if r"%%t" in npg_stl: .replace(
npg_stl = npg_stl.replace(
r"%%t", r"%%t",
r'"},{"score":{"name":"*","objective":"{-}TMinT"}},{"text":":"},' r'"},{"score":{"name":"*","objective":"{-}TMinT"}},{"text":":"},'
r'{"score":{"name":"*","objective":"{-}TSecT"}},{"text":"'.replace( r'{"score":{"name":"*","objective":"{-}TSecT"}},{"text":"'.replace(
r"{-}", sbn_pc r"{-}", sbn_pc
), ),
) )
)
result.append( result.append(
SingleCommand( SingleCommand(
self.execute_cmd_head.format( self.execute_cmd_head.format(
@@ -425,20 +462,20 @@ class MidiConvert:
result.append( result.append(
SingleCommand( SingleCommand(
"scoreboard objectives remove {}PercT".format(sbn_pc), "scoreboard objectives remove {}PercT".format(sbn_pc),
annotation="移除临时计算计分板(百分比", annotation="移除临时百分比变量",
) )
) )
if r"%%t" in pgs_style: if r"%%t" in pgs_style:
result.append( result.append(
SingleCommand( SingleCommand(
"scoreboard objectives remove {}TMinT".format(sbn_pc), "scoreboard objectives remove {}TMinT".format(sbn_pc),
annotation="移除临时计算计分板(分)", annotation="移除临时分变量",
) )
) )
result.append( result.append(
SingleCommand( SingleCommand(
"scoreboard objectives remove {}TSecT".format(sbn_pc), "scoreboard objectives remove {}TSecT".format(sbn_pc),
annotation="移除临时计算计分板(秒)", annotation="移除临时秒变量",
) )
) )
@@ -447,6 +484,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 +503,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
# 我们来用通道统计音乐信息 # 我们来用通道统计音乐信息
# 但是是用分轨的思路的 # 但是是用分轨的思路的
@@ -557,7 +595,9 @@ class MidiConvert:
) )
else: else:
raise NoteOnOffMismatchError( raise NoteOnOffMismatchError(
"当前的MIDI很可能有损坏之嫌……", msg, "无法在上文中找到与之匹配的音符开音消息。" "当前的MIDI很可能有损坏之嫌……",
msg,
"无法在上文中找到与之匹配的音符开音消息。",
) )
"""整合后的音乐通道格式 """整合后的音乐通道格式
@@ -624,20 +664,55 @@ 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( (
"@a[scores=({}={})]".format(scoreboard_name, score_now) self.execute_cmd_head.format(
.replace("(", r"{") "@a[scores=({}={})]".format(scoreboard_name, score_now)
.replace(")", r"}") .replace("(", r"{")
) .replace(")", r"}")
+ note.to_command( )
(max_volume) if note.track_no == 0 else (max_volume * 0.9) + (
r"playsound {} @s ^ ^ ^{} {}".format(
mc_sound_ID, mc_distance_volume, volume_percentage
)
if note.percussive
else r"playsound {} @s ^ ^ ^{} {} {}".format(
mc_sound_ID,
mc_distance_volume,
volume_percentage,
mc_pitch,
)
)
), ),
annotation="{}播放{}%{}".format( annotation=(
mctick2timestr(score_now), "{}播放{}%{}噪音".format(
max_volume * 100, mctick2timestr(score_now),
"{}:{}".format(note.mc_sound_ID, note.mc_pitch), max_volume * 100,
mc_sound_ID,
)
if note.percussive
else "{}播放{}%{}乐音".format(
mctick2timestr(score_now),
max_volume * 100,
"{}:{:.2f}".format(mc_sound_ID, mc_pitch),
)
), ),
), ),
) )
@@ -649,7 +724,7 @@ class MidiConvert:
command_channels.append(this_channel) command_channels.append(this_channel)
self.music_tick_num = max_score self.music_tick_num = max_score
return (command_channels, command_amount, max_score) return command_channels, command_amount, max_score
def to_command_list_in_delay( def to_command_list_in_delay(
self, self,
@@ -697,19 +772,55 @@ 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) command=(
+ note.to_command( self.execute_cmd_head.format(player_selector)
(max_volume) if note.track_no == 0 else (max_volume * 0.9) + (
r"playsound {} @s ^ ^ ^{} {}".format(
mc_sound_ID, mc_distance_volume, volume_percentage
)
if note.percussive
else r"playsound {} @s ^ ^ ^{} {} {}".format(
mc_sound_ID,
mc_distance_volume,
volume_percentage,
mc_pitch,
)
)
),
annotation=(
"{}播放{}%{}噪音".format(
mctick2timestr(delaytime_now),
max_volume * 100,
mc_sound_ID,
)
if note.percussive
else "{}播放{}%{}乐音".format(
mctick2timestr(delaytime_now),
max_volume * 100,
"{}:{:.2f}".format(mc_sound_ID, mc_pitch),
)
), ),
tick_delay=tickdelay, tick_delay=tickdelay,
annotation="{}播放{}%{}".format( ),
mctick2timestr(delaytime_now),
max_volume * 100,
"{}:{}".format(note.mc_sound_ID, note.mc_pitch),
),
)
) )
delaytime_previous = delaytime_now delaytime_previous = delaytime_now

View File

@@ -2,8 +2,8 @@
""" """
存放非音·创本体的附加内容(插件?) 存放非音·创本体的附加内容(插件?)
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory
@@ -15,8 +15,57 @@ Terms & Conditions: License.md in the root directory
__all__ = [ __all__ = [
# 通用
"ConvertConfig", "ConvertConfig",
"bottem_side_length_of_smallest_square_bottom_box",
# 打包
"compress_zipfile",
"behavior_mcpack_manifest",
# MCSTRUCTURE 函数
"antiaxis",
"forward_IER",
"command_statevalue",
"form_note_block_in_NBT_struct",
"form_repeater_in_NBT_struct",
"form_command_block_in_NBT_struct",
"commands_to_structure",
"commands_to_redstone_delay_structure",
# MCSTRUCTURE 常量
"AXIS_PARTICULAR_VALUE",
"COMPABILITY_VERSION_117",
"COMPABILITY_VERSION_119",
# BDX 函数
"bdx_move",
"form_command_block_in_BDX_bytes",
"commands_to_BDX_bytes",
# BDX 常量
"BDX_MOVE_KEY",
] ]
__author__ = (("金羿", "Eilles Wan"), ("诸葛亮与八卦阵", "bgArray")) __author__ = (("金羿", "Eilles Wan"), ("诸葛亮与八卦阵", "bgArray"))
from .main import * from .main import ConvertConfig
from .archive import compress_zipfile, behavior_mcpack_manifest
from .bdx import (
BDX_MOVE_KEY,
bdx_move,
form_command_block_in_BDX_bytes,
commands_to_BDX_bytes,
)
from .common import bottem_side_length_of_smallest_square_bottom_box
from .mcstructure import (
antiaxis,
forward_IER,
AXIS_PARTICULAR_VALUE,
COMPABILITY_VERSION_119,
COMPABILITY_VERSION_117,
command_statevalue,
form_note_block_in_NBT_struct,
form_repeater_in_NBT_struct,
form_command_block_in_NBT_struct,
commands_to_structure,
commands_to_redstone_delay_structure,
)

View File

@@ -2,8 +2,8 @@
""" """
用以生成附加包的附加功能 用以生成附加包的附加功能
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory
@@ -102,15 +102,17 @@ def to_addon_pack_in_score(
+ scoreboard_name + scoreboard_name
+ " 1\n", + " 1\n",
( (
"scoreboard players reset @a[scores={" (
+ scoreboard_name "scoreboard players reset @a[scores={"
+ "=" + scoreboard_name
+ str(maxscore + 20) + "="
+ "..}]" + str(maxscore + 20)
+ f" {scoreboard_name}\n" + "..}]"
) + f" {scoreboard_name}\n"
if auto_reset )
else "", if auto_reset
else ""
),
f"function mscplay/progressShow\n" if data_cfg.progressbar_style else "", f"function mscplay/progressShow\n" if data_cfg.progressbar_style else "",
) )
) )

View File

@@ -5,8 +5,8 @@
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory

View File

@@ -4,8 +4,8 @@
""" """
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory
@@ -21,7 +21,7 @@ from ..constants import x, y, z
from ..subclass import SingleCommand from ..subclass import SingleCommand
from .common import bottem_side_length_of_smallest_square_bottom_box from .common import bottem_side_length_of_smallest_square_bottom_box
bdx_key = { BDX_MOVE_KEY = {
"x": [b"\x0f", b"\x0e", b"\x1c", b"\x14", b"\x15"], "x": [b"\x0f", b"\x0e", b"\x1c", b"\x14", b"\x15"],
"y": [b"\x11", b"\x10", b"\x1d", b"\x16", b"\x17"], "y": [b"\x11", b"\x10", b"\x1d", b"\x16", b"\x17"],
"z": [b"\x13", b"\x12", b"\x1e", b"\x18", b"\x19"], "z": [b"\x13", b"\x12", b"\x1e", b"\x18", b"\x19"],
@@ -34,21 +34,18 @@ def bdx_move(axis: str, value: int):
if value == 0: if value == 0:
return b"" return b""
if abs(value) == 1: if abs(value) == 1:
return bdx_key[axis][0 if value == -1 else 1] return BDX_MOVE_KEY[axis][0 if value == -1 else 1]
pointer = sum( pointer = sum(
[ [
1 if i else 0 value != -1,
for i in ( value < -1 or value > 1,
value != -1, value < -128 or value > 127,
value < -1 or value > 1, value < -32768 or value > 32767,
value < -128 or value > 127,
value < -32768 or value > 32767,
)
] ]
) )
return bdx_key[axis][pointer] + value.to_bytes( return BDX_MOVE_KEY[axis][pointer] + value.to_bytes(
2 ** (pointer - 2), "big", signed=True 2 ** (pointer - 2), "big", signed=True
) )
@@ -150,18 +147,20 @@ def commands_to_BDX_bytes(
for command in commands_list: for command in commands_list:
_bytes += form_command_block_in_BDX_bytes( _bytes += form_command_block_in_BDX_bytes(
command.command_text, command.command_text,
(1 if y_forward else 0) (
if ( (1 if y_forward else 0)
((now_y != 0) and (not y_forward))
or (y_forward and (now_y != (max_height - 1)))
)
else (
(3 if z_forward else 2)
if ( if (
((now_z != 0) and (not z_forward)) ((now_y != 0) and (not y_forward))
or (z_forward and (now_z != _sideLength - 1)) or (y_forward and (now_y != (max_height - 1)))
)
else (
(3 if z_forward else 2)
if (
((now_z != 0) and (not z_forward))
or (z_forward and (now_z != _sideLength - 1))
)
else 5
) )
else 5
), ),
impluse=2, impluse=2,
condition=command.conditional, condition=command.conditional,
@@ -196,13 +195,13 @@ def commands_to_BDX_bytes(
): ):
now_z -= 1 if z_forward else -1 now_z -= 1 if z_forward else -1
z_forward = not z_forward z_forward = not z_forward
_bytes += bdx_key[x][1] _bytes += BDX_MOVE_KEY[x][1]
now_x += 1 now_x += 1
else: else:
_bytes += bdx_key[z][int(z_forward)] _bytes += BDX_MOVE_KEY[z][int(z_forward)]
else: else:
_bytes += bdx_key[y][int(y_forward)] _bytes += BDX_MOVE_KEY[y][int(y_forward)]
return ( return (
_bytes, _bytes,

View File

@@ -2,8 +2,8 @@
""" """
用以生成BDX结构文件的附加功能 用以生成BDX结构文件的附加功能
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory

View File

@@ -4,8 +4,8 @@
""" """
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory

View File

@@ -4,8 +4,8 @@
""" """
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory
@@ -19,7 +19,7 @@ Terms & Conditions: License.md in the root directory
from dataclasses import dataclass from dataclasses import dataclass
from typing import Literal, Tuple, Union from typing import Literal, Tuple, Union
from ..constants import DEFAULT_PROGRESSBAR_STYLE from ..subclass import DEFAULT_PROGRESSBAR_STYLE, ProgressBarStyle
@dataclass(init=False) @dataclass(init=False)
@@ -34,8 +34,8 @@ class ConvertConfig:
speed_multiplier: float speed_multiplier: float
"""速度倍率""" """速度倍率"""
progressbar_style: Union[Tuple[str, Tuple[str, str]], Literal[None]] progressbar_style: Union[ProgressBarStyle, None]
"""进度条样式""" """进度条样式"""
dist_path: str dist_path: str
"""输出目录""" """输出目录"""
@@ -45,7 +45,8 @@ class ConvertConfig:
output_path: str, output_path: str,
volume: float = 1.0, volume: float = 1.0,
speed: float = 1.0, speed: float = 1.0,
progressbar: Union[bool, Tuple[str, Tuple[str, str]]] = True, progressbar: Union[bool, Tuple[str, Tuple[str, str]], ProgressBarStyle] = True,
ignore_progressbar_param_error: bool = False,
): ):
""" """
将已经转换好的数据内容指令载入MC可读格式 将已经转换好的数据内容指令载入MC可读格式
@@ -77,10 +78,29 @@ class ConvertConfig:
# 改这一段没🐎 # 改这一段没🐎
if progressbar is True: if progressbar is True:
self.progressbar_style = DEFAULT_PROGRESSBAR_STYLE self.progressbar_style = DEFAULT_PROGRESSBAR_STYLE
"""进度条样式""" """进度条样式"""
else: return
elif isinstance(progressbar, ProgressBarStyle):
self.progressbar_style = progressbar self.progressbar_style = progressbar
"""进度条样式""" """进度条样式"""
else: return
self.progressbar_style = None elif isinstance(progressbar, tuple):
"""进度条样式组""" if isinstance(progressbar[0], str) and isinstance(
progressbar[1], tuple
):
if isinstance(progressbar[1][0], str) and isinstance(
progressbar[1][1], str
):
self.progressbar_style = ProgressBarStyle(
progressbar[0], progressbar[1][0], progressbar[1][1]
)
return
if not ignore_progressbar_param_error:
raise TypeError(
"参数 {} 的类型 {} 与所需类型 Union[bool, Tuple[str, Tuple[str, str]], ProgressBarStyle] 不符。".format(
progressbar, type(progressbar)
)
)
self.progressbar_style = None
"""进度条样式组"""

View File

@@ -2,8 +2,8 @@
""" """
用以生成单个mcstructure文件的附加功能 用以生成单个mcstructure文件的附加功能
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory
@@ -17,7 +17,8 @@ Terms & Conditions: License.md in the root directory
__all__ = [ __all__ = [
"to_mcstructure_file_in_delay", "to_mcstructure_file_in_delay",
"to_mcstructure_file_in_repeater", "to_mcstructure_file_in_repeater",
"to_mcstructure_file_in_score",
] ]
__author__ = (("金羿", "Eilles Wan"),) __author__ = (("金羿", "Eilles Wan"),)
from .main import to_mcstructure_file_in_delay, to_mcstructure_file_in_repeater from .main import to_mcstructure_file_in_delay, to_mcstructure_file_in_repeater, to_mcstructure_file_in_score

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory
@@ -14,9 +14,10 @@ Terms & Conditions: License.md in the root directory
import os import os
from typing import Literal from typing import Literal
from ...exceptions import CommandFormatError # from ...exceptions import CommandFormatError
from ...main import MidiConvert from ...main import MidiConvert
from ..main import ConvertConfig from ..main import ConvertConfig
from ...subclass import SingleCommand
from ..mcstructure import ( from ..mcstructure import (
COMPABILITY_VERSION_117, COMPABILITY_VERSION_117,
COMPABILITY_VERSION_119, COMPABILITY_VERSION_119,
@@ -47,7 +48,7 @@ def to_mcstructure_file_in_delay(
Returns Returns
------- -------
tuple[tuple[int,]结构大小, int音乐总延迟] tuple[tuple[int,int,int]结构大小, int音乐总延迟]
""" """
compability_ver = ( compability_ver = (
@@ -80,6 +81,78 @@ def to_mcstructure_file_in_delay(
return size, max_delay return size, max_delay
def to_mcstructure_file_in_score(
midi_cvt: MidiConvert,
data_cfg: ConvertConfig,
scoreboard_name: str = "mscplay",
auto_reset: bool = False,
max_height: int = 64,
):
"""
将midi以延迟播放器形式转换为mcstructure结构文件
Parameters
----------
midi_cvt: MidiConvert 对象
用于转换的MidiConvert对象
data_cfg: ConvertConfig 对象
部分转换通用参数
scoreboard_name: str
我的世界的计分板名称
auto_reset: bool
是否自动重置计分板
max_height: int
生成结构最大高度
Returns
-------
tuple[tuple[int,int,int]结构大小, int音乐总延迟, int指令数量
"""
compability_ver = (
COMPABILITY_VERSION_117
if midi_cvt.enable_old_exe_format
else COMPABILITY_VERSION_119
)
cmd_list, cmd_count, max_delay = midi_cvt.to_command_list_in_score(
scoreboard_name,
data_cfg.volume_ratio,
data_cfg.speed_multiplier,
)
if not os.path.exists(data_cfg.dist_path):
os.makedirs(data_cfg.dist_path)
struct, size, end_pos = commands_to_structure(
midi_cvt.music_command_list+(
[
SingleCommand(
command="scoreboard players reset @a[scores={"
+ scoreboard_name
+ "="
+ str(max_delay + 20)
+ "}] "
+ scoreboard_name,
annotation="自动重置计分板",
)
]
if auto_reset
else []
), max_height - 1, compability_version_=compability_ver
)
with open(
os.path.abspath(
os.path.join(data_cfg.dist_path, f"{midi_cvt.midi_music_name}.mcstructure")
),
"wb+",
) as f:
struct.dump(f)
return size, max_delay, cmd_count
def to_mcstructure_file_in_repeater( def to_mcstructure_file_in_repeater(
midi_cvt: MidiConvert, midi_cvt: MidiConvert,
data_cfg: ConvertConfig, data_cfg: ConvertConfig,
@@ -105,7 +178,7 @@ def to_mcstructure_file_in_repeater(
Returns Returns
------- -------
tuple[tuple[int,]结构大小, int音乐总延迟] tuple[tuple[int,int,int]结构大小, int音乐总延迟]
""" """
compability_ver = ( compability_ver = (

View File

@@ -4,8 +4,8 @@
""" """
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory
@@ -189,9 +189,11 @@ def form_command_block_in_NBT_struct(
return Block( return Block(
"minecraft", "minecraft",
"command_block" (
if impluse == 0 "command_block"
else ("repeating_command_block" if impluse == 1 else "chain_command_block"), if impluse == 0
else ("repeating_command_block" if impluse == 1 else "chain_command_block")
),
states={"conditional_bit": condition, "facing_direction": particularValue}, states={"conditional_bit": condition, "facing_direction": particularValue},
extra_data={ extra_data={
"block_entity_data": { "block_entity_data": {
@@ -257,18 +259,20 @@ def commands_to_structure(
form_command_block_in_NBT_struct( form_command_block_in_NBT_struct(
command=command.command_text, command=command.command_text,
coordinate=coordinate, coordinate=coordinate,
particularValue=(1 if y_forward else 0) particularValue=(
if ( (1 if y_forward else 0)
((now_y != 0) and (not y_forward))
or (y_forward and (now_y != (max_height - 1)))
)
else (
(3 if z_forward else 2)
if ( if (
((now_z != 0) and (not z_forward)) ((now_y != 0) and (not y_forward))
or (z_forward and (now_z != _sideLength - 1)) or (y_forward and (now_y != (max_height - 1)))
)
else (
(3 if z_forward else 2)
if (
((now_z != 0) and (not z_forward))
or (z_forward and (now_z != _sideLength - 1))
)
else 5
) )
else 5
), ),
impluse=2, impluse=2,
condition=False, condition=False,
@@ -357,20 +361,16 @@ def commands_to_redstone_delay_structure(
for cmd in commands: for cmd in commands:
# print("\r 正在进行处理:",end="") # print("\r 正在进行处理:",end="")
if cmd.delay > 2: if cmd.delay > 2:
a_max = max(a,a_max) a_max = max(a, a_max)
total_cmd += (a := 1) total_cmd += (a := 1)
else: else:
a += 1 a += 1
struct = Structure( struct = Structure(
size=( size=(
round(delay_length / 2 + total_cmd) round(delay_length / 2 + total_cmd) if extensioon_direction == x else a_max,
if extensioon_direction == x
else a_max,
3, 3,
round(delay_length / 2 + total_cmd) round(delay_length / 2 + total_cmd) if extensioon_direction == z else a_max,
if extensioon_direction == z
else a_max,
), ),
fill=Block("minecraft", "air", compability_version=compability_version_), fill=Block("minecraft", "air", compability_version=compability_version_),
compability_version=compability_version_, compability_version=compability_version_,

View File

@@ -4,8 +4,8 @@
""" """
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory
@@ -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

@@ -4,8 +4,8 @@
""" """
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory

View File

@@ -2,8 +2,8 @@
""" """
用以生成Schematic结构的附加功能 用以生成Schematic结构的附加功能
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory

View File

@@ -4,8 +4,8 @@
""" """
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory

View File

@@ -2,8 +2,8 @@
""" """
用以启动WebSocket服务器播放的附加功能 用以启动WebSocket服务器播放的附加功能
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory

View File

@@ -4,8 +4,8 @@
""" """
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory
@@ -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,13 @@ 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 +217,14 @@ 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 +285,13 @@ 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 +355,15 @@ 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 +437,13 @@ 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

@@ -5,8 +5,8 @@
""" """
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory
@@ -18,10 +18,10 @@ Terms & Conditions: License.md in the root directory
from dataclasses import dataclass from dataclasses import dataclass
from typing import Optional from typing import Any
from .types import Optional, Any, List, Mapping
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 +49,9 @@ class SingleNote:
percussive: bool percussive: bool
"""是否为打击乐器""" """是否为打击乐器"""
extra_info: Any
"""你觉得放什么好?"""
def __init__( def __init__(
self, self,
instrument: int, instrument: int,
@@ -58,6 +61,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 +84,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 +106,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 +174,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 +285,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
@@ -359,3 +340,62 @@ class SingleNoteBox:
if not isinstance(other, self.__class__): if not isinstance(other, self.__class__):
return False return False
return self.__str__() == other.__str__() return self.__str__() == other.__str__()
@dataclass(init=False)
class ProgressBarStyle:
"""进度条样式类"""
base_style: str
"""基础样式"""
to_play_style: str
"""未播放之样式"""
played_style: str
"""已播放之样式"""
def __init__(self, base_s: str, to_play_s: str, played_s: str):
"""用于存储进度条样式的类
:param base_s 基础样式,用以定义进度条整体
:param to_play_s 进度条样式:尚未播放的样子
:param played_s 已经播放的样子"""
self.base_style = base_s
self.to_play_style = to_play_s
self.played_style = played_s
def set_base_style(self, value: str):
"""设置基础样式"""
self.base_style = value
def set_to_play_style(self, value: str):
"""设置未播放之样式"""
self.to_play_style = value
def set_played_style(self, value: str):
"""设置已播放之样式"""
self.played_style = value
def copy(self):
dst = ProgressBarStyle(self.base_style, self.to_play_style, self.played_style)
return dst
DEFAULT_PROGRESSBAR_STYLE = ProgressBarStyle(
r"%%N [ %%s/%^s %%% __________ %%t|%^t ]",
r"§e=§r",
r"§7=§r",
)
"""
默认的进度条样式
"""
NoteChannelType = Mapping[
int,
List[SingleNote,],
]
"""
频道信息类型
Dict[int,Dict[int,List[SingleNote,],],]
"""

View File

@@ -5,8 +5,8 @@
""" """
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory
@@ -16,32 +16,32 @@ Terms & Conditions: License.md in the root directory
# Email TriM-Organization@hotmail.com # Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md # 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
from typing import Any, Dict, List, Literal, Optional, Tuple, Union from typing import (
Any,
Dict,
List,
Literal,
Optional,
Tuple,
Union,
Iterable,
Sequence,
Mapping,
Callable,
)
import mido
from .subclass import SingleNote MidiNoteNameTableType = Mapping[int, Tuple[str, ...]]
ProgressStyle = Tuple[str, Tuple[str, str]]
""" """
进度条样式类型 Midi音符名称对照表类型
""" """
VoidMido = Union[mido.MidiFile, None] # void mido MidiInstrumentTableType = Mapping[int, Tuple[str, int]]
""" """
Midi类型 Midi乐器对照表类型
""" """
FittingFunctionType = Callable[[float], float]
NoteChannelType = Dict[
int,
List[SingleNote,],
]
"""
频道信息类型
Dict[int,Dict[int,List[SingleNote,],],]
"""
ChannelType = Dict[ ChannelType = Dict[

View File

@@ -4,8 +4,8 @@
""" """
""" """
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 仓库根目录下的 License.md 开源相关声明请见 仓库根目录下的 License.md
Terms & Conditions: License.md in the root directory Terms & Conditions: License.md in the root directory
@@ -16,9 +16,21 @@ 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 .types import (
Any,
Dict,
Tuple,
Optional,
Callable,
Literal,
Union,
MidiInstrumentTableType,
)
def mctick2timestr(mc_tick: int) -> str: def mctick2timestr(mc_tick: int) -> str:
@@ -42,8 +54,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: MidiInstrumentTableType,
default_instrument: str = "note.flute",
default_deviation: Optional[int] = 5,
) -> Tuple[str, int]: ) -> Tuple[str, int]:
""" """
返回midi的乐器ID对应的我的世界乐器名对于音域转换算法如下 返回midi的乐器ID对应的我的世界乐器名对于音域转换算法如下
@@ -60,40 +75,32 @@ 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
def perc_inst_to_soundID_withX(instrumentID: int) -> Tuple[str, int]: if default_deviation
""" 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 +124,102 @@ 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: MidiInstrumentTableType,
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]

70
Packer/MSCT_Packer.py Normal file
View File

@@ -0,0 +1,70 @@
import Musicreater
import Musicreater.experiment
import Musicreater.previous
import Musicreater.plugin
from Musicreater.plugin.addonpack import (
to_addon_pack_in_delay,
to_addon_pack_in_repeater,
to_addon_pack_in_score,
)
from Musicreater.plugin.mcstructfile import (
to_mcstructure_file_in_delay,
to_mcstructure_file_in_repeater,
to_mcstructure_file_in_score,
)
from Musicreater.plugin.bdxfile import to_BDX_file_in_delay, to_BDX_file_in_score
MSCT_MAIN = (
Musicreater,
Musicreater.experiment,
Musicreater.previous,
)
MSCT_PLUGIN = (Musicreater.plugin,)
MSCT_PLUGIN_FUNCTION = (
to_addon_pack_in_delay,
to_addon_pack_in_repeater,
to_addon_pack_in_score,
to_mcstructure_file_in_delay,
to_mcstructure_file_in_repeater,
to_mcstructure_file_in_score,
to_BDX_file_in_delay,
to_BDX_file_in_score,
)
import hashlib
import dill
import brotli
def enpack_llc_pack(sth, to_dist: str):
packing_bytes = brotli.compress(
dill.dumps(
sth,
)
)
with open(
to_dist,
"wb",
) as f:
f.write(packing_bytes)
return hashlib.sha256(packing_bytes)
with open("./Packer/checksum.txt", "w", encoding="utf-8") as f:
f.write("MSCT_MAIN:\n")
f.write(enpack_llc_pack(MSCT_MAIN, "./Packer/MSCT_MAIN.MPK").hexdigest())
f.write("\nMSCT_PLUGIN:\n")
f.write(enpack_llc_pack(MSCT_PLUGIN, "./Packer/MSCT_PLUGIN.MPK").hexdigest())
f.write("\nMSCT_PLUGIN_FUNCTION:\n")
f.write(
enpack_llc_pack(
MSCT_PLUGIN_FUNCTION, "./Packer/MSCT_PLUGIN_FUNCTION.MPK"
).hexdigest()
)

View File

@@ -50,7 +50,7 @@
pip install --upgrade -i https://pypi.python.org/simple Musicreater pip install --upgrade -i https://pypi.python.org/simple Musicreater
``` ```
- 克隆仓库并安装**不推荐** - 克隆仓库并安装最新版本但**不推荐**
```bash ```bash
git clone https://gitee.com/TriM-Organization/Musicreater.git git clone https://gitee.com/TriM-Organization/Musicreater.git
cd Musicreater cd Musicreater

View File

@@ -49,7 +49,7 @@ Welcome to join our QQ group: [861684859](https://jq.qq.com/?_wv=1027&k=hpeRxrYr
pip install -i https://pypi.python.org/simple Musicreater --upgrade pip install -i https://pypi.python.org/simple Musicreater --upgrade
``` ```
- Clone repo and Install (**NOT RECOMMANDED**): - Clone repo and Install (Latest but **NOT RECOMMANDED**):
```bash ```bash
git clone https://github.com/TriM-Organization/Musicreater.git git clone https://github.com/TriM-Organization/Musicreater.git
cd Musicreater cd Musicreater
@@ -75,7 +75,7 @@ Commands such as `python`、`pip` could be changed to some like `python3` or `pi
**Touch (偷吃不是Touch)**: A man who is used to use command(s) in _Minecraft: Bedrock Edition_, who supported us of debugging and testing program and algorithm **Touch (偷吃不是Touch)**: A man who is used to use command(s) in _Minecraft: Bedrock Edition_, who supported us of debugging and testing program and algorithm
## Thanks 🙏 ## Acknowledgements 🙏
This list is not in any order. This list is not in any order.

View File

@@ -173,7 +173,7 @@
|`InstID`|声音效果ID|不同的声音ID可以对应不同的乐器详见转换[乐器对照表](./%E8%BD%AC%E6%8D%A2%E4%B9%90%E5%99%A8%E5%AF%B9%E7%85%A7%E8%A1%A8.md)| |`InstID`|声音效果ID|不同的声音ID可以对应不同的乐器详见转换[乐器对照表](./%E8%BD%AC%E6%8D%A2%E4%B9%90%E5%99%A8%E5%AF%B9%E7%85%A7%E8%A1%A8.md)|
|`Ht`|播放点对玩家的距离|通过距离来表达声音的响度 $S$ 表示此参数`Ht`以Vol表示音量百分比则计算公式为 $S = \frac{1}{Vol}-1$ | |`Ht`|播放点对玩家的距离|通过距离来表达声音的响度 $S$ 表示此参数`Ht`以Vol表示音量百分比则计算公式为 $S = \frac{1}{Vol}-1$ |
|`Vlct`|原生我的世界中规定的播放力度|这个参数是一个谜一样的存在似乎它的值毫不重要因为无论这个值是多少我们听起来都差不多当此音符所在MIDI通道为第一通道则这个值为 $0.7$ 倍MIDI指定力度其他则为 $0.9$ | |`Vlct`|原生我的世界中规定的播放力度|这个参数是一个谜一样的存在似乎它的值毫不重要因为无论这个值是多少我们听起来都差不多当此音符所在MIDI通道为第一通道则这个值为 $0.7$ 倍MIDI指定力度其他则为 $0.9$ |
|`Ptc`|音符的音高|这是决定音调的参数 $P$ 表示此参数 $n$ 表示其在MIDI中的编号 $x$ 表示一定的音调偏移则计算公式为 $P = 2^\frac{n-60-x}{12}$之所以存在音调偏移是因为在我的世界不同的[乐器存在不同的音域](https://minecraft.fandom.com/zh/wiki/%E9%9F%B3%E7%AC%A6%E7%9B%92#%E4%B9%90%E5%99%A8),我们通过音调偏移来进行调整。| |`Ptc`|音符的音高|这是决定音调的参数 $P$ 表示此参数 $n$ 表示其在MIDI中的编号 $x$ 表示一定的音调偏移则计算公式为 $P = 2^\frac{n-60-x}{12}$之所以存在音调偏移是因为在我的世界不同的[乐器存在不同的音域](https://zh.minecraft.wiki/wiki/%E9%9F%B3%E7%AC%A6%E7%9B%92#%E4%B9%90%E5%99%A8),我们通过音调偏移来进行调整。|
### 播放器内容 ### 播放器内容
@@ -285,23 +285,31 @@
表示进度条占位的 `_` 是用来标识你的进度条的也就是可变部分的唯一的图形部分 表示进度条占位的 `_` 是用来标识你的进度条的也就是可变部分的唯一的图形部分
**样式定义字符串**的样例如下这也是默认进度条的样式 **样式定义字符串基础样式**的样例如下这也是默认进度条的基础样式
` %%N [ %%s/%^s %%% __________ %%t|%^t]` ``` %%N [ %%s/%^s %%% __________ %%t|%^t]```
这是单独一行的进度条当然你也可以制作多行的如果是一行的输出时所使用的指令便是 `title`而如果是多行的话输出就会用 `titleraw` 作为进度条字幕 这是单独一行的进度条当然你也可以制作多行的如果是一行的输出时所使用的指令便是 `title`而如果是多行的话输出就会用 `titleraw` 作为进度条字幕
哦对了上面的只不过是样式定义同时还需要定义的是可变图形的部分也就是进度条上那个真正的 哦对了上面的只不过是样式定义同时还需要定义的是可变图形的部分也就是进度条上那个真正的
对于这个我们就采用了固定参数的方法对于一个进度条无非就是已经播放过的没播放过的两种形态所以使用一个元组来传入这两个参数就是最简单的了元组的格式也很简单`(str: 播放过的部分长啥样, str: 没播放过的部分长啥样)` 例如我们默认的进度的定义是这样的 对于这个我们就采用了固定参数的方法对于一个进度条无非就是已经播放过的没播放过的两种形态例如我们默认的进度**可变样式**的定义是这样的
`('§e=§r', '§7=§r')` **可变样式甲已播放样式**`'§e=§r'`
综合起来把这些参数传给函数需要一个参数整合你猜用的啥啊对对对我用的还是元组 **可变样式乙未播放样式**`'§7=§r'`
综合起来把这些参数传给函数需要一个参数整合使用位于 `Musicreater/subclass.py` 下的 `ProgressBarStyle` 类进行定义
我们的默认定义参数如下 我们的默认定义参数如下
`(r'%%N [ %%s/%^s %%% __________ %%t|%^t]',('§e=§r', '§7=§r'))` ```python
DEFAULT_PROGRESSBAR_STYLE = ProgressBarStyle(
r"%%N [ %%s/%^s %%% __________ %%t|%^t ]",
r"§e=§r",
r"§7=§r",
)
```
*为了避免生成错误请尽量避免使用标识符作为定义样式字符串的其他部分* *为了避免生成错误请尽量避免使用标识符作为定义样式字符串的其他部分*

View File

@@ -12,8 +12,8 @@
**_使用时请遵循协议规定_** **_使用时请遵循协议规定_**
- 版权所有 © 2023 · 开发者 - 版权所有 © 2024 · 开发者
- Copyright © 2023 all the developers of Musicreater - Copyright © 2024 all the developers of Musicreater
* 开源相关声明请见 仓库根目录下的 License.md * 开源相关声明请见 仓库根目录下的 License.md
* Terms & Conditions: License.md in the root directory * Terms & Conditions: License.md in the root directory

View File

@@ -9,8 +9,8 @@
Musicreater (音·创) Musicreater (音·创)
A free open source library used for convert midi file into formats that is suitable for **Minecraft**. A free open source library used for convert midi file into formats that is suitable for **Minecraft**.
版权所有 © 2023 音·创 开发者 版权所有 © 2024 音·创 开发者
Copyright © 2023 all the developers of Musicreater Copyright © 2024 all the developers of Musicreater
开源相关声明请见 ./License.md 开源相关声明请见 ./License.md
Terms & Conditions: ./License.md Terms & Conditions: ./License.md
@@ -25,6 +25,12 @@ from Musicreater.plugin.addonpack import (
to_addon_pack_in_repeater, to_addon_pack_in_repeater,
to_addon_pack_in_score, to_addon_pack_in_score,
) )
from Musicreater.plugin.mcstructfile import (
to_mcstructure_file_in_delay,
to_mcstructure_file_in_repeater,
to_mcstructure_file_in_score,
)
from Musicreater.plugin.bdxfile import to_BDX_file_in_delay, to_BDX_file_in_score from Musicreater.plugin.bdxfile import to_BDX_file_in_delay, to_BDX_file_in_score
# 获取midi列表 # 获取midi列表
@@ -36,7 +42,9 @@ out_path = input(f"请输入输出路径:")
# 选择输出格式 # 选择输出格式
fileFormat = int(input(f"请输入输出格式[BDX(1) 或 MCPACK(0)]").lower()) fileFormat = int(
input(f"请输入输出格式[MCSTRUCTURE(2) 或 BDX(1) 或 MCPACK(0)]").lower()
)
playerFormat = int(input(f"请选择播放方式[红石(2) 或 计分板(1) 或 延迟(0)]").lower()) playerFormat = int(input(f"请选择播放方式[红石(2) 或 计分板(1) 或 延迟(0)]").lower())
@@ -50,7 +58,17 @@ def bool_str(sth: str):
elif str(sth).lower() in ("false", "", "", "f", "n"): elif str(sth).lower() in ("false", "", "", "f", "n"):
return False return False
else: else:
raise ValueError("布尔字符串啊?") raise ValueError("非法逻辑字串")
def isin(sth: str, range_list: dict):
sth = sth.lower()
for bool_value, res_list in range_list.items():
if sth in res_list:
return bool_value
raise ValueError(
"不在可选范围内:{}".format([j for i in range_list.values() for j in i])
)
if os.path.exists("./demo_config.json"): if os.path.exists("./demo_config.json"):
@@ -74,31 +92,63 @@ else:
bool_str, bool_str,
), ),
( (
f"计分板名称:", (
str, f"计分板名称:",
) str,
if playerFormat == 1 )
else ( if playerFormat == 1
f"玩家选择器:", else (
str, f"玩家选择器:",
str,
)
), ),
( (
f"是否自动重置计分板:", (
bool_str, f"是否自动重置计分板:",
) bool_str,
if playerFormat == 1 )
else (), if playerFormat == 1
else ()
),
( (
f"作者名称:", (
str, f"BDX作者署名",
) str,
if fileFormat == 1 )
else (), if fileFormat == 1
() else (
if playerFormat == 1 (
else ( (
f"最大结构高度", "结构延展方向",
int, lambda a: isin(
a,
{
"z+": ["z+", "Z+"],
"x+": ["X+", "x+"],
"z-": ["Z-", "z-"],
"x-": ["x-", "X-"],
},
),
)
if (playerFormat == 2 and fileFormat == 2)
else ()
),
)
),
(
()
if playerFormat == 1
else (
(
"基础空白方块:",
str,
)
if (playerFormat == 2 and fileFormat == 2)
else (
f"最大结构高度:",
int,
)
)
), ),
]: ]:
if args: if args:
@@ -109,12 +159,20 @@ print(f"正在处理 {midi_path} ")
cvt_mid = Musicreater.MidiConvert.from_midi_file(midi_path, old_exe_format=False) cvt_mid = Musicreater.MidiConvert.from_midi_file(midi_path, old_exe_format=False)
cvt_cfg = ConvertConfig(out_path, *prompts[:3]) cvt_cfg = ConvertConfig(out_path, *prompts[:3])
if playerFormat == 1: if fileFormat == 0:
cvt_method = to_addon_pack_in_score if playerFormat == 1:
elif playerFormat == 0: cvt_method = to_addon_pack_in_score
cvt_method = to_addon_pack_in_delay elif playerFormat == 0:
elif playerFormat == 2: cvt_method = to_addon_pack_in_delay
cvt_method = to_addon_pack_in_repeater elif playerFormat == 2:
cvt_method = to_addon_pack_in_repeater
elif fileFormat == 2:
if playerFormat == 1:
cvt_method = to_mcstructure_file_in_score
elif playerFormat == 0:
cvt_method = to_mcstructure_file_in_delay
elif playerFormat == 2:
cvt_method = to_mcstructure_file_in_repeater
print( print(
@@ -122,11 +180,21 @@ print(
*(cvt_method(cvt_mid, cvt_cfg, *prompts[3:])) # type: ignore *(cvt_method(cvt_mid, cvt_cfg, *prompts[3:])) # type: ignore
) )
if fileFormat == 0 if fileFormat == 0
else " 指令总长:{},最高延迟:{},结构大小{},终点坐标{}".format( else (
*( " 指令总长:{},最高延迟:{},结构大小{},终点坐标{}".format(
to_BDX_file_in_score(cvt_mid, cvt_cfg, *prompts[3:]) *(
if playerFormat == 1 to_BDX_file_in_score(cvt_mid, cvt_cfg, *prompts[3:])
else to_BDX_file_in_delay(cvt_mid, cvt_cfg, *prompts[3:]) if playerFormat == 1
else to_BDX_file_in_delay(cvt_mid, cvt_cfg, *prompts[3:])
)
)
if fileFormat == 1
else (" 结构大小:{},延迟总数:{},指令数量:{}".format(
*(cvt_method(cvt_mid, cvt_cfg, *prompts[3:])) # type: ignore
) if playerFormat == 2 else
" 结构大小:{},延迟总数:{}".format(
*(cvt_method(cvt_mid, cvt_cfg, *prompts[3:])) # type: ignore
)
) )
) )
) )

View File

@@ -1,11 +0,0 @@
import Musicreater
import Musicreater.plugin
import Musicreater.plugin.mcstructfile
print(
Musicreater.plugin.mcstructfile.to_mcstructure_file_in_delay(
Musicreater.MidiConvert.from_midi_file(input("midi路径:"), old_exe_format=False),
Musicreater.plugin.ConvertConfig(input("输出路径:"), volume=1),
max_height=32,
)
)

View File

@@ -1,10 +0,0 @@
import Musicreater
import Musicreater.plugin
import Musicreater.plugin.mcstructfile
print(
Musicreater.plugin.mcstructfile.to_mcstructure_file_in_repeater(
Musicreater.MidiConvert.from_midi_file(input("midi路径:"), old_exe_format=False),
Musicreater.plugin.ConvertConfig(input("输出路径:"), volume=1),
)
)

View File

@@ -1,12 +0,0 @@
import Musicreater.experiment
import Musicreater.plugin
import Musicreater.plugin.mcstructfile
print(
Musicreater.plugin.mcstructfile.to_mcstructure_file_in_repeater(
Musicreater.experiment.FutureMidiConvertM4.from_midi_file(
input("midi路径:"), old_exe_format=False
),
Musicreater.plugin.ConvertConfig(input("输出路径:"), volume=1),
)
)

View File

@@ -11,4 +11,4 @@
不得用于商业用途 不得用于商业用途
若 音·创 库被用于商业用途,应当将其剔除 若 音·创 库被用于商业用途,应当将其剔除
版权所有 © 2023 诸葛亮与八卦阵 版权所有 © 2024 诸葛亮与八卦阵